8 years, 11 months ago.

How to use spi with DMA in STM32F401RE NUCLEO?

Hi. I want to use DMA for spi in STM32F401RE NUCLEO board.

I tried as follows. SPISlave spi_slave(SPI_MOSI, SPI_MISO, SPI_SCK, NC);

It is slow to transmit and receive by using SPISlave class, so i want to use HAL Drivers.

I tried as follows, but it is not generated SPI CLK signal.

/*############################### SPI1 #######################################*/

#define NUCLEO_SPIx                                     SPI1
#define NUCLEO_SPIx_CLK_ENABLE()                        __SPI1_CLK_ENABLE()

#define NUCLEO_SPIx_SCK_AF                              GPIO_AF5_SPI1
#define NUCLEO_SPIx_SCK_GPIO_PORT                       GPIOA
#define NUCLEO_SPIx_SCK_PIN                             GPIO_PIN_5
#define NUCLEO_SPIx_SCK_GPIO_CLK_ENABLE()               __GPIOA_CLK_ENABLE()
#define NUCLEO_SPIx_SCK_GPIO_CLK_DISABLE()              __GPIOA_CLK_DISABLE()

#define NUCLEO_SPIx_MISO_MOSI_AF                        GPIO_AF5_SPI1
#define NUCLEO_SPIx_MISO_MOSI_GPIO_PORT                 GPIOA
#define NUCLEO_SPIx_MISO_MOSI_GPIO_CLK_ENABLE()         __GPIOA_CLK_ENABLE()
#define NUCLEO_SPIx_MISO_MOSI_GPIO_CLK_DISABLE()        __GPIOA_CLK_DISABLE()
#define NUCLEO_SPIx_MISO_PIN                            GPIO_PIN_6
#define NUCLEO_SPIx_MOSI_PIN                            GPIO_PIN_7
#endif
/** @defgroup STM32F4XX_NUCLEO_LOW_LEVEL_Private_FunctionPrototypes
  * @{
  */
static void       SPIx_Init(void);
static void       SPIx_Write_DMA(uint8_t Value);
static uint32_t   SPIx_Read_DMA(void);
static void       SPIx_Error_DMA(void);

static void       SPIx_MspInit(SPI_HandleTypeDef *hspi);
static void       DMA_MspInit(SPI_HandleTypeDef *hspi);

/******************************************************************************
                            BUS OPERATIONS
*******************************************************************************/

#define NUCLEO_DMAx_CLK_ENABLE()                __HAL_RCC_DMA1_CLK_ENABLE()

/* Definition for SPIx's DMA */
#define NUCLEO_SPIx_TX_DMA_CHANNEL              DMA_CHANNEL_0 
#define NUCLEO_SPIx_TX_DMA_STREAM               DMA1_Stream4	
#define NUCLEO_SPIx_RX_DMA_CHANNEL              DMA_CHANNEL_0
#define NUCLEO_SPIx_RX_DMA_STREAM               DMA1_Stream3	

/* Definition for SPIx's NVIC */
#define NUCLEO_SPIx_DMA_TX_IRQn                 DMA1_Stream4_IRQn	
#define NUCLEO_SPIx_DMA_RX_IRQn                 DMA1_Stream3_IRQn	
#define NUCLEO_SPIx_DMA_TX_IRQHandler           DMA1_Stream4_IRQHandler
#define NUCLEO_SPIx_DMA_RX_IRQHandler           DMA1_Stream3_IRQHandler

#define NUCLEO_SPIx_FORCE_RESET()               __HAL_RCC_SPI1_FORCE_RESET()
#define NUCLEO_SPIx_RELEASE_RESET()             __HAL_RCC_SPI1_RELEASE_RESET()

#endif

/**
  * @brief SPI MSP Initialization 
  *        This function configures the hardware resources used in this example: 
  *           - Peripheral's clock enable
  *           - Peripheral's GPIO Configuration  
  *           - DMA configuration for transmission request by peripheral 
  *           - NVIC configuration for DMA interrupt request enable
  * @param hspi: SPI handle pointer
  * @retval None
  */
void DMA_MspInit(SPI_HandleTypeDef *hspi)
{
  static DMA_HandleTypeDef hdma_tx;
  static DMA_HandleTypeDef hdma_rx;
  
	NUCLEO_DMAx_CLK_ENABLE();
	
  /*##-3- Configure the DMA streams ##########################################*/
  /* Configure the DMA handler for Transmission process */
  hdma_tx.Instance                 = NUCLEO_SPIx_TX_DMA_STREAM;
  
  hdma_tx.Init.Channel             = NUCLEO_SPIx_TX_DMA_CHANNEL;
  hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  hdma_tx.Init.Mode                = DMA_NORMAL;
  hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
  hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;         
  hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
  hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;
  
  HAL_DMA_Init(&hdma_tx);   
  
  /* Associate the initialized DMA handle to the the SPI handle */
  __HAL_LINKDMA(hspi, hdmatx, hdma_tx);
    
  /* Configure the DMA handler for Transmission process */
  hdma_rx.Instance                 = NUCLEO_SPIx_RX_DMA_STREAM;
  
  hdma_rx.Init.Channel             = NUCLEO_SPIx_RX_DMA_CHANNEL;
  hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  hdma_rx.Init.Mode                = DMA_NORMAL;
  hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
  hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;         
  hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;
  hdma_rx.Init.PeriphBurst         = DMA_PBURST_INC4; 

  HAL_DMA_Init(&hdma_rx);
    
  /* Associate the initialized DMA handle to the the SPI handle */
  __HAL_LINKDMA(hspi, hdmarx, hdma_rx);
    
  /*##-4- Configure the NVIC for DMA #########################################*/ 
  /* NVIC configuration for DMA transfer complete interrupt (SPI3_TX) */
  HAL_NVIC_SetPriority(NUCLEO_SPIx_DMA_TX_IRQn, 0, 1);
  HAL_NVIC_EnableIRQ(NUCLEO_SPIx_DMA_TX_IRQn);
    
  /* NVIC configuration for DMA transfer complete interrupt (SPI3_RX) */
  HAL_NVIC_SetPriority(NUCLEO_SPIx_DMA_RX_IRQn, 0, 0);   
  HAL_NVIC_EnableIRQ(NUCLEO_SPIx_DMA_RX_IRQn);
	
	NUCLEO_DMAx_CLK_ENABLE();
}

/**
  * @brief SPI MSP De-Initialization 
  *        This function frees the hardware resources used in this example:
  *          - Disable the Peripheral's clock
  *          - Revert GPIO, DMA and NVIC configuration to their default state
  * @param hspi: SPI handle pointer
  * @retval None
  */
void DMA_MspDeInit(SPI_HandleTypeDef *hspi)
{
  
  static DMA_HandleTypeDef hdma_tx;
  static DMA_HandleTypeDef hdma_rx;
	 
  /*##-3- Disable the DMA Streams ############################################*/
  /* De-Initialize the DMA Stream associate to transmission process */
  HAL_DMA_DeInit(&hdma_tx); 
  /* De-Initialize the DMA Stream associate to reception process */
  HAL_DMA_DeInit(&hdma_rx);
  
  /*##-4- Disable the NVIC for DMA ###########################################*/
  HAL_NVIC_DisableIRQ(NUCLEO_SPIx_DMA_TX_IRQn);
  HAL_NVIC_DisableIRQ(NUCLEO_SPIx_DMA_RX_IRQn);
}

//////////////////////////////////////////////////////////////////////////////
/**
  * @brief  Initializes SPI MSP.
  * @param  None
  * @retval None
  */
static void SPIx_MspInit(SPI_HandleTypeDef *hspi)
{
  GPIO_InitTypeDef  GPIO_InitStruct;  
  
  /*** Configure the GPIOs ***/  
  /* Enable GPIO clock */
  NUCLEO_SPIx_SCK_GPIO_CLK_ENABLE();
  NUCLEO_SPIx_MISO_MOSI_GPIO_CLK_ENABLE();
  
  /* Configure SPI SCK */
  GPIO_InitStruct.Pin = NUCLEO_SPIx_SCK_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Alternate = NUCLEO_SPIx_SCK_AF;
  HAL_GPIO_Init(NUCLEO_SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);

  /* Configure SPI MISO and MOSI */ 
  GPIO_InitStruct.Pin = NUCLEO_SPIx_MOSI_PIN;
  GPIO_InitStruct.Alternate = NUCLEO_SPIx_MISO_MOSI_AF;
  GPIO_InitStruct.Pull  = GPIO_PULLDOWN;
  HAL_GPIO_Init(NUCLEO_SPIx_MISO_MOSI_GPIO_PORT, &GPIO_InitStruct);
  
  GPIO_InitStruct.Pin = NUCLEO_SPIx_MISO_PIN;
  HAL_GPIO_Init(NUCLEO_SPIx_MISO_MOSI_GPIO_PORT, &GPIO_InitStruct);

  /*** Configure the SPI peripheral ***/ 
  /* Enable SPI clock */
  NUCLEO_SPIx_CLK_ENABLE();
}

/**
  * @brief  Initializes SPI HAL.
  * @param  None
  * @retval None
  */
static void SPIx_Init(void)
{
  if(HAL_SPI_GetState(&hnucleo_Spi) == HAL_SPI_STATE_RESET)
  {
    /* SPI Config */
    hnucleo_Spi.Instance = NUCLEO_SPIx;
      /* SPI baudrate is set to 12,5 MHz maximum (PCLK2/SPI_BaudRatePrescaler = 100/8 = 12,5 MHz) 
       to verify these constraints:
          - ST7735 LCD SPI interface max baudrate is 15MHz for write and 6.66MHz for read
            Since the provided driver doesn't use read capability from LCD, only constraint 
            on write baudrate is considered.
          - SD card SPI interface max baudrate is 25MHz for write/read
          - PCLK2 max frequency is 100 MHz 
       */ 
    hnucleo_Spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hnucleo_Spi.Init.Direction = SPI_DIRECTION_2LINES;
    hnucleo_Spi.Init.CLKPhase = SPI_PHASE_2EDGE;
    hnucleo_Spi.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hnucleo_Spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
    hnucleo_Spi.Init.CRCPolynomial = 7;
    hnucleo_Spi.Init.DataSize = SPI_DATASIZE_8BIT;
    hnucleo_Spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hnucleo_Spi.Init.NSS = SPI_NSS_SOFT;
    hnucleo_Spi.Init.TIMode = SPI_TIMODE_DISABLED;
    hnucleo_Spi.Init.Mode = SPI_MODE_MASTER;

    SPIx_MspInit(&hnucleo_Spi);		
    HAL_SPI_Init(&hnucleo_Spi);
    DMA_MspInit(&hnucleo_Spi);
  }
}

void main(void)
{
                uint8_t Value = 0xFF;
                int status ;

  		SPIx_Init();

		while((status = HAL_SPI_GetState(&hnucleo_Spi)) != HAL_SPI_STATE_READY)
		{
			printf("\n\r status = 0x%x \n\r", status);
		}
					
		status = HAL_SPI_Transmit_DMA(&hnucleo_Spi, (uint8_t*) &Value, 1);
			
		/* Check the communication status */
		if(status == HAL_OK)
		{
			/* Execute user timeout callback */
				printf("\n\r HAL_OK \n\r");
		//  SPIx_Error_DMA();
		}
		
		while ((status = HAL_SPI_GetState(&hnucleo_Spi)) != HAL_SPI_STATE_READY)
		{			
			printf("\n\r status = 0x%x \n\r", status);		
		} 
}

Please help me. Thank you.

Is it possible to speed up to 20MHz for SPISlave class as spi slave?

posted by Tian CR 09 Dec 2015

I have the same problem.

posted by 王 秀杰 25 Mar 2016
Be the first to answer this question.

Assigned to Tian CR 8 years, 11 months ago.

This means that the question has been accepted and is being worked on.