text: /*
   * File      : drv_spi.c
   * This file is part of RT-Thread RTOS
   * COPYRIGHT (C) 2017 RT-Thread Develop Team
   *
   * The license and distribution terms for this file may be
   * found in the file LICENSE in this distribution or at
   * http://www.rt-thread.org/license/LICENSE
   *
   * Change Logs:
   * Date           Author       Notes
   * 2017-06-05     tanek        first implementation.
   */
   
  #include "drv_spi.h"
  
  #include <board.h>
  #include <finsh.h>
  
  //#define DEBUG
  
  #ifdef DEBUG
  #define DEBUG_PRINTF(...)   rt_kprintf(__VA_ARGS__)
  #else
  #define DEBUG_PRINTF(...)   
  #endif
  
  /* private rt-thread spi ops function */
  static rt_err_t configure(struct rt_spi_device* device, struct rt_spi_configuration* configuration);
  static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message);
  
  static struct rt_spi_ops stm32_spi_ops =
  {
      configure,
      xfer
  };
  
  #ifdef SPI_USE_DMA
  static uint8_t dummy = 0xFF;
  static void DMA_RxConfiguration(struct rt_spi_bus * spi_bus,
                                  struct rt_spi_message* message)
  {
      struct stm32f4_spi *f4_spi = (struct stm32f4_spi *)spi_bus->parent.user_data;
      
      DMA_HandleTypeDef * hdma_tx = &f4_spi->hdma_tx;
      DMA_HandleTypeDef * hdma_rx = &f4_spi->hdma_rx;
       
      HAL_DMA_DeInit(hdma_tx);
      HAL_DMA_DeInit(hdma_rx);
          
      /* Check if the DMA Stream is disabled before enabling it.
         Note that this step is useful when the same Stream is used multiple times:
         enabled, then disabled then re-enabled... In this case, the DMA Stream disable
         will be effective only at the end of the ongoing data transfer and it will
         not be possible to re-configure it before making sure that the Enable bit
         has been cleared by hardware. If the Stream is used only once, this step might
         be bypassed. */    
      while (hdma_tx->Instance->CR & DMA_SxCR_EN);
      while (hdma_rx->Instance->CR & DMA_SxCR_EN);
  
      if(message->recv_buf != RT_NULL)
      {
          hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
      }
      else
      {
          message->recv_buf = &dummy;
          hdma_rx->Init.MemInc = DMA_MINC_DISABLE;
      }
      HAL_DMA_Init(hdma_rx);
      
      __HAL_LINKDMA(&f4_spi->spi_handle, hdmarx, f4_spi->hdma_rx);
          
      if(message->send_buf != RT_NULL)
      {
          hdma_tx->Init.MemInc = DMA_MINC_ENABLE;
      }
      else
      {
          dummy = 0xFF;
          message->send_buf = &dummy;
          hdma_tx->Init.MemInc = DMA_MINC_DISABLE;
      }
      HAL_DMA_Init(hdma_tx);
      
      __HAL_LINKDMA(&f4_spi->spi_handle, hdmatx, f4_spi->hdma_tx);
      
      /* NVIC configuration for DMA transfer complete interrupt*/
      HAL_NVIC_SetPriority(f4_spi->hdma_tx_irq, 0, 1);
      HAL_NVIC_EnableIRQ(f4_spi->hdma_tx_irq);
  
      /* NVIC configuration for DMA transfer complete interrupt*/
      HAL_NVIC_SetPriority(f4_spi->hdma_rx_irq, 0, 0);   
      HAL_NVIC_EnableIRQ(f4_spi->hdma_rx_irq);
      
  }
  #endif
  
  static rt_err_t configure(struct rt_spi_device* device,
                            struct rt_spi_configuration* configuration)
  {
      struct rt_spi_bus * spi_bus = (struct rt_spi_bus *)device->bus;	
      struct stm32f4_spi *f4_spi = (struct stm32f4_spi *)spi_bus->parent.user_data;
  	SPI_HandleTypeDef * SpiHandle = &f4_spi->spi_handle;
  
  	RT_ASSERT(device != RT_NULL);
  	RT_ASSERT(configuration != RT_NULL);
  
      /* data_width */
      if(configuration->data_width <= 8)
      {
          SpiHandle->Init.DataSize = SPI_DATASIZE_8BIT;
      }
      else if(configuration->data_width <= 16)
      {
          SpiHandle->Init.DataSize = SPI_DATASIZE_16BIT;
      }
      else
      {
          return RT_EIO;
      }
  
      /* baudrate */
      {
          uint32_t SPI_APB_CLOCK;
          uint32_t max_hz;
  
          max_hz = configuration->max_hz;
  
          DEBUG_PRINTF("sys   freq: %d\n", HAL_RCC_GetSysClockFreq());
          DEBUG_PRINTF("pclk2 freq: %d\n", HAL_RCC_GetPCLK2Freq());
  
          SPI_APB_CLOCK = HAL_RCC_GetPCLK2Freq();
  
          if(max_hz >= SPI_APB_CLOCK/2)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
          }
          else if(max_hz >= SPI_APB_CLOCK/4)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
          }
          else if(max_hz >= SPI_APB_CLOCK/8)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
          }
          else if(max_hz >= SPI_APB_CLOCK/16)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
          }
          else if(max_hz >= SPI_APB_CLOCK/32)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
          }
          else if(max_hz >= SPI_APB_CLOCK/64)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
          }
          else if(max_hz >= SPI_APB_CLOCK/128)
          {
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
          }
          else
          {
              /*  min prescaler 256 */
              SpiHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
          }
      } /* baudrate */
  
      /* CPOL */
      if(configuration->mode & RT_SPI_CPOL)
      {
          SpiHandle->Init.CLKPolarity = SPI_POLARITY_HIGH;
      }
      else
      {
          SpiHandle->Init.CLKPolarity = SPI_POLARITY_LOW;
      }
      /* CPHA */
      if(configuration->mode & RT_SPI_CPHA)
      {
  		SpiHandle->Init.CLKPhase = SPI_PHASE_2EDGE;
      }
      else
      {
  		SpiHandle->Init.CLKPhase = SPI_PHASE_1EDGE;
      }
      /* MSB or LSB */
      if(configuration->mode & RT_SPI_MSB)
      {
          SpiHandle->Init.FirstBit = SPI_FIRSTBIT_MSB;
      }
      else
      {
          SpiHandle->Init.FirstBit = SPI_FIRSTBIT_LSB;
      }
      SpiHandle->Init.Direction = SPI_DIRECTION_2LINES;
      SpiHandle->Init.Mode = SPI_MODE_MASTER;
      SpiHandle->Init.NSS  = SPI_NSS_SOFT;
  	SpiHandle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  	SpiHandle->Init.TIMode = SPI_TIMODE_DISABLE;
  
      /* init SPI */
      if (HAL_SPI_Init(SpiHandle) != HAL_OK)
  	{
  		return RT_ERROR;
  	}
      /* Enable SPI_MASTER */
  	__HAL_SPI_ENABLE(SpiHandle);
      
      DEBUG_PRINTF("spi configuration\n");
  
      return RT_EOK;
  };
  
  static rt_uint32_t xfer(struct rt_spi_device* device, struct rt_spi_message* message)
  {
      struct rt_spi_bus * stm32_spi_bus = (struct rt_spi_bus *)device->bus;
      struct stm32f4_spi *f4_spi = (struct stm32f4_spi *)stm32_spi_bus->parent.user_data;
      struct rt_spi_configuration * config = &device->config;
      SPI_TypeDef * SPI = f4_spi->spi_handle.Instance;
      struct stm32_spi_cs * stm32_spi_cs = device->parent.user_data;
      rt_uint32_t size = message->length;
  
  	RT_ASSERT(device != NULL);
  	RT_ASSERT(message != NULL);
  	
      /* take CS */
      if(message->cs_take)
      {
          HAL_GPIO_WritePin(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin, GPIO_PIN_RESET);
      }
  
  #ifdef SPI_USE_DMA
      if(message->length > 32)
      {
          if(config->data_width <= 8)
          {
              HAL_StatusTypeDef state; 
              DEBUG_PRINTF("spi dma transfer start\n");
              DMA_RxConfiguration(stm32_spi_bus, message);
              DEBUG_PRINTF("dma configuration finish , send buf %X, rec buf %X, length: %d\n", 
                      (uint32_t)message->send_buf, (uint32_t)message->recv_buf, message->length);
              
              state = HAL_SPI_TransmitReceive_DMA(&f4_spi->spi_handle, 
                                                  (uint8_t*)message->send_buf, 
                                                  (uint8_t*)message->recv_buf, 
                                                  message->length);
              if (state != HAL_OK) 
              {
                  DEBUG_PRINTF("spi flash configuration error : %d\n", state);
                  message->length = 0;
                  //while(1);
              }
              else
              {
                  DEBUG_PRINTF("spi dma transfer finish\n");            
              }
              
              while (HAL_SPI_GetState(&f4_spi->spi_handle) != HAL_SPI_STATE_READY);
              DEBUG_PRINTF("spi get state finish\n");
          }
          else
          {
              // Todo 
          }
      }
      else
  #endif
      {
          if(config->data_width <= 8)
          {
              const rt_uint8_t * send_ptr = message->send_buf;
              rt_uint8_t * recv_ptr = message->recv_buf;
  
              while(size--)
              {
                  rt_uint8_t data = 0xFF;
  
                  if(send_ptr != RT_NULL)
                  {
                      data = *send_ptr++;
                  }
                  
                  // Todo: replace register read/write by stm32f4 lib
                  //Wait until the transmit buffer is empty
                  while ((SPI->SR & SPI_FLAG_TXE) == RESET);
                  // Send the byte
  				SPI->DR = data;
  
                  //Wait until a data is received
                  while ((SPI->SR & SPI_FLAG_RXNE) == RESET);
                  // Get the received data
                  data = SPI->DR;
  
                  if(recv_ptr != RT_NULL)
                  {
                      *recv_ptr++ = data;
                  }
              }
          }
          else if(config->data_width <= 16)
          {
              const rt_uint16_t * send_ptr = message->send_buf;
              rt_uint16_t * recv_ptr = message->recv_buf;
  
              while(size--)
              {
                  rt_uint16_t data = 0xFF;
  
                  if(send_ptr != RT_NULL)
                  {
                      data = *send_ptr++;
                  }
  
                  //Wait until the transmit buffer is empty
                  while ((SPI->SR & SPI_FLAG_TXE) == RESET);
                  // Send the byte
                  SPI->DR = data;
  
                  //Wait until a data is received
                  while ((SPI->SR & SPI_FLAG_RXNE) == RESET);
                  // Get the received data
                  data = SPI->DR;
  
                  if(recv_ptr != RT_NULL)
                  {
                      *recv_ptr++ = data;
                  }
              }
          }
      }
  
      /* release CS */
      if(message->cs_release)
      {
          //GPIO_SetBits(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin);
  		HAL_GPIO_WritePin(stm32_spi_cs->GPIOx, stm32_spi_cs->GPIO_Pin, GPIO_PIN_SET);
      }
  
      return message->length;
  };
  
  
  
  
  
  #ifdef RT_USING_SPI1
  
  static struct stm32f4_spi stm32f4_spi1 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI1,
      },
      /* .hdma_rx = */ {   
          DMA2_Stream2,
          DMA_CHANNEL_3,
      },
      /* .hdma_rx_irq = */ DMA2_Stream2_IRQn,
  
      /* .hdma_tx = */{
          DMA2_Stream3,
          DMA_CHANNEL_3,
      },
      /* .hdma_tx_irq = */ DMA2_Stream3_IRQn,
  };
  
  static struct rt_spi_bus spi1_bus;
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA2_Stream2_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi1.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA2_Stream3_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi1.spi_handle.hdmatx);
  }
  
  #endif
  
  #ifdef RT_USING_SPI2
  
  struct stm32f4_spi stm32f4_spi2 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI2,
      },
      /* .hdma_rx = */ {   
          DMA1_Stream3,
          DMA_CHANNEL_0,
      },
      /* .hdma_rx_irq = */ DMA1_Stream3_IRQn,
  
      /* .hdma_tx = */{
          DMA1_Stream4,
          DMA_CHANNEL_0,
      },
      /* .hdma_tx_irq = */ DMA1_Stream4_IRQn,
  };
  
  static struct rt_spi_bus spi2_bus;
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA1_Stream3_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi2.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA1_Stream4_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi2.spi_handle.hdmatx);
  }
  
  #endif
  
  #ifdef RT_USING_SPI3
  
  struct stm32f4_spi stm32f4_spi3 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI3,
      },
      /* .hdma_rx = */ {   
          DMA1_Stream0,
          DMA_CHANNEL_0,
      },
      /* .hdma_rx_irq = */ DMA1_Stream0_IRQn,
  
      /* .hdma_tx = */{
          DMA1_Stream2,
          DMA_CHANNEL_0,
      },
      /* .hdma_tx_irq = */ DMA1_Stream2_IRQn,
  };
  
  static struct rt_spi_bus spi3_bus;
  
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA1_Stream0_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi3.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA1_Stream2_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi3.spi_handle.hdmatx);
  }
  
  #endif
  
  #ifdef RT_USING_SPI4
  
  struct stm32f4_spi stm32f4_spi4 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI4,
      },
      /* .hdma_rx = */ {   
          DMA2_Stream0,
          DMA_CHANNEL_4,
      },
      /* .hdma_rx_irq = */ DMA2_Stream0_IRQn,
  
      /* .hdma_tx = */{
          DMA2_Stream1,
          DMA_CHANNEL_4,
      },
      /* .hdma_tx_irq = */ DMA2_Stream1_IRQn,
  };
  
  static struct rt_spi_bus spi4_bus;
  
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA2_Stream0_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi4.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA2_Stream1_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi4.spi_handle.hdmatx);
  }
  
  #endif
  
  #ifdef RT_USING_SPI5
  
  struct stm32f4_spi stm32f4_spi5 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI5,
      },
  #ifdef SPI_USE_DMA
      /* .hdma_rx = */ {   
          DMA2_Stream3,
          DMA_CHANNEL_2,
      },
      /* .hdma_rx_irq = */ DMA2_Stream3_IRQn,
  
      /* .hdma_tx = */{
          DMA2_Stream4,
          DMA_CHANNEL_2,
      },
      /* .hdma_tx_irq = */ DMA2_Stream4_IRQn,
  #endif /* SPI_USE_DMA */
  };
  
  static struct rt_spi_bus spi5_bus;
  
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA2_Stream3_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi5.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA2_Stream4_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi5.spi_handle.hdmatx);
  }
  
  #endif
  
  #ifdef RT_USING_SPI6
  
  struct stm32f4_spi stm32f4_spi6 = 
  {
      /* .spi_handle = */{
          /* .Instance = */ SPI5,
      },
      /* .hdma_rx = */ {   
          DMA2_Stream6,
          DMA_CHANNEL_2,
      },
      /* .hdma_rx_irq = */ DMA2_Stream6_IRQn,
  
      /* .hdma_tx = */{
          DMA2_Stream5,
          DMA_CHANNEL_2,
      },
      /* .hdma_tx_irq = */ DMA2_Stream5_IRQn,
  };
  
  static struct rt_spi_bus spi6_bus;
  
  
  /**
    * @brief  This function handles DMA Rx interrupt request.
    * @param  None
    * @retval None  
    */
  void DMA2_Stream6_IRQHandler(void)
  {
    HAL_DMA_IRQHandler(stm32f4_spi6.spi_handle.hdmarx);
  }    
  /**
    * @brief  This function handles DMA Tx interrupt request.  
    * @param  None
    * @retval None    
    */
  void DMA2_Stream5_IRQHandler(void)
  {
      HAL_DMA_IRQHandler(stm32f4_spi6.spi_handle.hdmatx);
  }
  
  #endif
  
  /** \brief init and register stm32 spi bus.
   *
   * \param SPI: STM32 SPI, e.g: SPI1,SPI2,SPI3.
   * \param spi_bus_name: spi bus name, e.g: "spi1"
   * \return
   *
   */
  rt_err_t stm32_spi_bus_register(SPI_TypeDef * SPI,
                              //struct stm32_spi_bus * stm32_spi,
                              const char * spi_bus_name)
  {
      struct stm32f4_spi * p_spi_bus;
      struct rt_spi_bus *  spi_bus;
      
      RT_ASSERT(SPI != RT_NULL);
      //RT_ASSERT(stm32_spi != RT_NULL);
      RT_ASSERT(spi_bus_name != RT_NULL);
          
  #ifdef RT_USING_SPI1
      if(SPI == SPI1)
      {
      #ifdef SPI_USE_DMA
          __HAL_RCC_DMA2_CLK_ENABLE();
          p_spi_bus = &stm32f4_spi1;
      #endif
          __HAL_RCC_SPI1_CLK_ENABLE();
          spi_bus = &spi1_bus;
      }
  #endif
      
  #ifdef RT_USING_SPI2
      if(SPI == SPI2)
      {
      #ifdef SPI_USE_DMA
          __HAL_RCC_DMA1_CLK_ENABLE();
          p_spi_bus = &stm32f4_spi2;
      #endif
          __HAL_RCC_SPI2_CLK_ENABLE();
          spi_bus = &spi2_bus;
      }
  #endif
  
  #ifdef RT_USING_SPI3
      if(SPI == SPI3)
      {
      	//stm32_spi->spi_handle.Instance = SPI3;
      #ifdef SPI_USE_DMA
          __HAL_RCC_DMA1_CLK_ENABLE();
          p_spi_bus = &stm32f4_spi3;
      #endif
  		__HAL_RCC_SPI3_CLK_ENABLE();
          spi_bus = &spi3_bus;
      }
  #endif
      
  #ifdef RT_USING_SPI4
      if(SPI == SPI4)
      {
  #ifdef SPI_USE_DMA
          __HAL_RCC_DMA2_CLK_ENABLE();
  #endif
  		__HAL_RCC_SPI4_CLK_ENABLE();
          spi_bus = &spi4_bus;
      }
  #endif
  
  #ifdef RT_USING_SPI5
      if(SPI == SPI5)
      {
      #ifdef SPI_USE_DMA
          __HAL_RCC_DMA2_CLK_ENABLE();
          p_spi_bus = &stm32f4_spi5;		
      #endif
  		__HAL_RCC_SPI5_CLK_ENABLE();
          spi_bus = &spi5_bus;
      }
  #endif
   
  #ifdef RT_USING_SPI6
      if(SPI == SPI6)
      {
      #ifdef SPI_USE_DMA
          __HAL_RCC_DMA2_CLK_ENABLE();
          p_spi_bus = &stm32f4_spi5;
      #endif
  		__HAL_RCC_SPI6_CLK_ENABLE();
          spi_bus = &spi6_bus;
      }
  #endif
  
      if (    (SPI != SPI1) && (SPI != SPI2) && (SPI != SPI3)
          &&  (SPI != SPI4) && (SPI != SPI5) && (SPI != SPI6))
      {
          return RT_ENOSYS;
      }
      
  #ifdef SPI_USE_DMA
      /* Configure the DMA handler for Transmission process */
      p_spi_bus->hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
      p_spi_bus->hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
      //p_spi_bus->hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
      p_spi_bus->hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
      p_spi_bus->hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
      p_spi_bus->hdma_tx.Init.Mode                = DMA_NORMAL;
      p_spi_bus->hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
      p_spi_bus->hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;         
      p_spi_bus->hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
      p_spi_bus->hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
      p_spi_bus->hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;
      
      p_spi_bus->hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
      p_spi_bus->hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
      //p_spi_bus->hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
      p_spi_bus->hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
      p_spi_bus->hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
      p_spi_bus->hdma_rx.Init.Mode                = DMA_NORMAL;
      p_spi_bus->hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
      p_spi_bus->hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;         
      p_spi_bus->hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
      p_spi_bus->hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;
      p_spi_bus->hdma_rx.Init.PeriphBurst         = DMA_PBURST_INC4;
  #endif /* SPI_USE_DMA */
  
      spi_bus->parent.user_data = &stm32f4_spi5;
      
      return rt_spi_bus_register(spi_bus, spi_bus_name, &stm32_spi_ops);
  }
  