cancel
Showing results for 
Search instead for 
Did you mean: 

Bug in GPDMA with 2D addressing (I think)

FA1234
Associate III

I believe there's a bug in the stm32h7rsxx_hal_dma code for dealing with repeated blocks in interrupt mode. This bug probably exists in other STM32H7 devices as well.

With a typical repeating transfer, in *NON* interrupt mode, the DMA transfer completes successfully, and the DMA state ends up in HAL_DMA_STATE_READY, ready for another request. All is well.

However, in interrupt mode, the DMA transfer completes successfully (all data is correctly transferred), but querying the DMA state in the DMA Transfer Complete callback, you'll get HAL_DMA_STATE_BUSY. In fact, it will remain in this state forever.

Looking at the stm32h7rsxx_hal_dma.c code, the block starting at 1154 ("Transfer Complete Interrupt management"). There are really only two cases where the HAL_DMA_STATE_READY can be set:
1) LinkedList mode (not relevant to us)
2) "Normal transfer" where CBR1 == 0. (i.e. not a repeating block transfer) In a repeating transfer, CBR1 contains the repeating config, and is generally not 0 (it's called the "Alternate Block Register 1").

So, a repeating block transfer can seemingly never get back to HAL_DMA_STATE_READY with a repeating transfer.

You can reproduce this problem starting with the DMA_RepeatedBlock demo incremented gather operation. 

I'm not entirely sure of the fix here. Perhaps it's checking if we're in a repeating block transfer and assuming that's also a "normal transfer"?

2 REPLIES 2
Saket_Om
ST Employee

Hello @FA1234 

Thank you for bringing this issue to our attention.

I reported this internally.

Internal ticket number: 196498 (This is an internal tracking number and is not accessible or usable by customers).

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar
FA1234
Associate III

Some additional information of interest that maybe should be fixed as part of this issue (or at least documented).

The HAL_DMAEx_ConfigRepeatBlock() call that is added to the MX_HPDMA1_Init()/MX_GPDMA1_Init() function is *NOT* sticky. Meaning, you need to call this function before *every* DMA_Start_IT (and possibly DMA_Start) call. This is because the BNDT/BRC (meaning the repeat count and other config info) is decremented by the CPU as the block runs, eventually ending with it = 0. So, calling DMA_Start_IT() after that point is equivalent to starting with a non-repeating block request.

It seems possible that messing with the _CxLLR register could cause a situation where the CxBR1.BNDT/BRC will automatically reload with their programmed values, but it's not obvious which or even if this is possible.

So, my current hacked up solution is in the DMA transfer complete callback:

 

if (HAL_DMA_GetState(ptr) == HAL_DMA_STATE_BUSY) {
  ptr->State = HAL_DMA_STATE_READY; // Fix repeating DMA stuck in BUSY
  HAL_DMAEx_ConfigRepeatBlock(ptr, &repeatConfig); // Reset for next repeating DMA
}