Skip to main content
Senior
July 21, 2024
Solved

How to know the when the DMA transfer done?

  • July 21, 2024
  • 5 replies
  • 3393 views

Hi.

I use a trigger source to trigger  SPI tx/rx linked-list DMA (not circular). But have no clues how to jude if the tx/rx DMA is done. I traced the IRQ handler, it calls, the code below: 

 

 

 

/**
 * @brief DMA SPI transmit receive process complete callback.
 * hdma: pointer to a DMA_HandleTypeDef structure that contains
 * the configuration information for the specified DMA module.
 * @retval None
 */
static void SPI_DMATransmitReceiveCplt(DMA_HandleTypeDef *hdma)
{
 SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

 if (hspi->State != HAL_SPI_STATE_ABORT)
 {
 if ((hspi->hdmarx->Mode == DMA_LINKEDLIST_CIRCULAR) &&
 (hspi->hdmatx->Mode == DMA_LINKEDLIST_CIRCULAR))
 {
#if (USE_HAL_SPI_REGISTER_CALLBACKS == 1UL)
 hspi->TxRxCpltCallback(hspi);
#else
 HAL_SPI_TxRxCpltCallback(hspi);
#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */
 }
 else
 {
 /* Enable EOT interrupt */
 __HAL_SPI_ENABLE_IT(hspi, SPI_IT_EOT);
 }
 }
}

 

 

It seems only when the DMA is configured as 'DMA_LINKEDLIST_CIRCULAR', the 'HAL_SPI_TxRxCpltCallback()' get called.

But in other situation, it only enable the EOT interrupt and simply return.

 

This topic has been closed for replies.
Best answer by BarryWhit

Now that the caffeine has flushed out of my system (an event I promptly celebrated with recaffeination), I've looked at this again and I think you were looking at the wrong place.

 

You need to look at the IRQ handler for the DMA channel, not the SPI transfer. i.e. HAL_DMA_IRQHandler

which includes this conditional:

 

 if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_TC) != 0U))
 {
 /* Check if interrupt source is enabled */
 if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != 0U)
 {
 // [...]
 /* Check transfer complete callback */
 if (hdma->XferCpltCallback != NULL)
 {
 /* Channel Transfer Complete callback */
 hdma->XferCpltCallback(hdma);
 }
 }
 }

 

So, you need to put your TC handler in hdma->XferCpltCallback. Which you can do cleanly using HAL_DMA_RegisterCallback

5 replies

BarryWhit
Lead
July 21, 2024

Yeah, this looks strange to me as well. Especially since

 

#define DMA_LINKEDLIST_NORMAL DMA_LINKEDLIST /*!< Linear linked-list DMA channel transfer */
#define DMA_LINKEDLIST_CIRCULAR (DMA_LINKEDLIST | (0x01U)) /*!< Circular linked-list DMA channel transfer */

HAL_SPI_TransmitReceive_DMA() {
 if ((hspi->hdmarx->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST) {
 HAL_DMAEx_List_Start_IT() -> {
 /* Enable common interrupts: Transfer Complete and Transfer Errors ITs */
 __HAL_DMA_ENABLE_IT(hdma, (DMA_IT_TC | DMA_IT_DTE | DMA_IT_ULE | DMA_IT_USE | DMA_IT_TO)); 
 } 
 }
}

 

So, the TC event is enabled whether mode is  Circular or Linear.

 

For now, you can use CubeMX/ProjectManager/Advanced Settings to enable "Register Callback" For SPI,

[Wrong]

"- If someone's post helped resolve your issue, please thank them by clicking ""Accept as Solution"".- Please post an update with details once you've solved your issue. Your experience may help others."
divergerAuthor
Senior
July 21, 2024

Hi,

Though I can register my own callback, the callback will be called only in linked-circular mode. :)

It seems the code intends to pass the event handling to the EOT handler,  then which handler callback should I use?

BarryWhit
Lead
July 21, 2024

You're right of course. Too much coffee. Or maybe not enough.

"- If someone's post helped resolve your issue, please thank them by clicking ""Accept as Solution"".- Please post an update with details once you've solved your issue. Your experience may help others."
divergerAuthor
Senior
July 22, 2024

Hi,

I think my guess is right. After the EOT interrupt enabled, it will fire the SPI EOT IRQ, and the SPI IRQ handler will be called, then the same TxRx complete interrupt callback will be called. So, the strategy is mask the SPI's EOT interrupt, and let DMA engine to handle burst events, and finally enable the EOT of the last burst which hands the flow back to SPI, 

Thanks.

BarryWhit
BarryWhitBest answer
Lead
July 22, 2024

Now that the caffeine has flushed out of my system (an event I promptly celebrated with recaffeination), I've looked at this again and I think you were looking at the wrong place.

 

You need to look at the IRQ handler for the DMA channel, not the SPI transfer. i.e. HAL_DMA_IRQHandler

which includes this conditional:

 

 if ((__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_TC) != 0U))
 {
 /* Check if interrupt source is enabled */
 if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != 0U)
 {
 // [...]
 /* Check transfer complete callback */
 if (hdma->XferCpltCallback != NULL)
 {
 /* Channel Transfer Complete callback */
 hdma->XferCpltCallback(hdma);
 }
 }
 }

 

So, you need to put your TC handler in hdma->XferCpltCallback. Which you can do cleanly using HAL_DMA_RegisterCallback

"- If someone's post helped resolve your issue, please thank them by clicking ""Accept as Solution"".- Please post an update with details once you've solved your issue. Your experience may help others."