cancel
Showing results for 
Search instead for 
Did you mean: 

how to use "HAL SPI receive DMA"register in stm32f407 correctly ?

CLi H.1
Associate II

Hello , i would like to receive data via SPI . i tried to use getting data from AD7606 via HAL_SPI_Receive_dma , but i always failed. i do not know which step i miss or wrong . Could you give me hint or solution? Thanks for very much .

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();
  MX_SPI2_Init();
  MX_TIM7_Init();
  MX_USART2_UART_Init();
 
  /* Init scheduler */
  osKernelInitialize();
 
 /*handle */
  SendTaskHandle = osThreadNew(SendTaskFun, NULL, &SendTask_attributes);
  ReceiveTaskHandle = osThreadNew(ReceiveTaskFun, NULL, &ReceiveTask_attributes);
 
  osKernelStart();
  while (1) {
  }
}
 
 
static void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
  __HAL_RCC_DMA2_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  /* DMA2_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
 
}
** Note 
DMA2_Stream0 - > SPI1 Receive
DMA2_Stream3 - > SPI1 Transmit
DMA1_Stream4 - > SPI2 Transmit
 
void ReceiveTaskFun(void *argument)
{
 uint8_t receive_buffer[256] ;
  for (;;) {
         //-- Enable CS
	 HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 0); //-- cs=0   active low  
 
         //- -  SPI2_DMA_receive
         ...... (Here is for receive data from AD7606 )
	 HAL_SPI_Receive_DMA(&hspi1, receive_buffer, 8);
}
 
 
// From stm32f4XX_it.c
void DMA2_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
	
  /* USER CODE END DMA2_Stream0_IRQn 0 */
 
  HAL_DMA_IRQHandler(&hdma_spi1_rx);
 
  /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
  DMA2->LISR |= 1<< 26;
  /* USER CODE END DMA2_Stream0_IRQn 1 */
}
 
 
//From main.c function 
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
   if (hspi->Instance == SPI1){
      HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 1); //-- cs=1  deactive 
   }
}
 
 
 
 
 
 
 

​There is my code , I abbreviated the code. If some important codes that i did not paste on it , please tell me .

i refer DMA controller manual and stm32 f407 reference manual

  1. 4.2 DMA flag management before enabling a new transfer Before enabling a new transfer, the user must ensure that the Transfer Complete Interrupt Flag (TCIF) in DMA_LISR or DMA_HISR is cleared. As a general recommendation, it is advised to clear all flags in the DMA_LIFCR and DMA_HIFCR registers before starting a new transfer.
  2. 0693W000008xEzrQAE.png

Then , I set TCIF3(bit 27 ) to 1 after HAL_SPI_RxCpltCallback . But It worked only one time, the second dma receive did not perform. Did i miss any information about SPI_DMA? :\

3 REPLIES 3

IMO Cube/HAL clears the DMA flags for you.

> void ReceiveTaskFun(void *argument)

> {

> uint8_t receive_buffer[256] ;

You can't DMA into a local variable.

JW

CLi H.1
Associate II

Thanks your suggestion . i changed receive_buffer[256] to global variable . Then i fixed my code ,and dma work!

But there are some problems that I always received same data . As if i didn't receive any new data.

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */
 
  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();
 
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI1 DMA Init */
    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA2_Stream0;
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
 
    /* SPI1_TX Init */
    hdma_spi1_tx.Instance = DMA2_Stream3;
    hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);
 
    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(SPI1_IRQn);
  /* USER CODE BEGIN SPI1_MspInit 1 */
 
  /* USER CODE END SPI1_MspInit 1 */
  }
}
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();
  MX_SPI2_Init();
  MX_TIM7_Init();
  MX_USART2_UART_Init();
  uint8_t receive_buffer[256] ;
  /* Init scheduler */
  osKernelInitialize();
 
 /*handle */
  SendTaskHandle = osThreadNew(SendTaskFun, NULL, &SendTask_attributes);
  ReceiveTaskHandle = osThreadNew(ReceiveTaskFun, NULL, &ReceiveTask_attributes);
 
  osKernelStart();
  while (1) {
  }
}
 
 
static void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
  __HAL_RCC_DMA2_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  /* DMA2_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
 
}
** Note 
DMA2_Stream0 - > SPI1 Receive
DMA2_Stream3 - > SPI1 Transmit
DMA1_Stream4 - > SPI2 Transmit
 
void ReceiveTaskFun(void *argument)
{
  for (;;) {
     //-- SPI1 callback 
    HAL_SPI_RxCpltCallback(&hspi1);	
    HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 1); //-- cs=1    deactive 
}
 
 
// From stm32f4XX_it.c
void DMA2_Stream0_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
 
void DMA2_Stream3_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
 
//From main.c function 
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
   if (hspi->Instance == SPI1){
         //-- Enable CS
      	 HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 0); //-- cs=0   active low  
         //- -  SPI2_DMA_receive
         ...... (Here is for receive data from AD7606 )
	 HAL_SPI_Receive_DMA(&hspi1, receive_buffer, 8);
   }
}

I don't use Cube/HAL so can't help directly.

Try to clear the buffer between successive reception sessions, that would reveal if it really does not work.

Try to read out the SPI and DMA registers content before the "working" and "non-working" session and compare.

JW