cancel
Showing results for 
Search instead for 
Did you mean: 

Seems like a bug in HAL DMA driver

BillR
Associate III

I am transferring 307200 bytes (640x480 gray) from DCMI to AXI SRAM using DMA1. When I do single transfer mode to do snapshot captures the DMA driver state never changes back from BUSY to READY so I can't start another.

I did 'fix' it with a hack in the HAL code for now but the problem seems in part from the fact that circular mode is forced by hardware when using double buffer mode. Double buffer mode is required when the transfer is larger than 64KWords and two transfers are required for the 307KB I need. Therefore then ending condition is never met because the driver checks that circular mode is off or on to know if the single transfer was complete and driver state should be changed back to READY.

This is in HAL_DMA_IRQHandler() from stm32h7xx_hal_dma.c from STM32Cube_FW_H7_V1.5.0
 
//
// ME: Here it checks if double buffer mode. If so, it starts the second half transfer
//
 if(((((DMA_Stream_TypeDef   *)hdma->Instance)->CR) & (uint32_t)(DMA_SxCR_DBM)) != 0U)
        {
          /* Current memory buffer used is Memory 0 */
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CT) == 0U)
          {
            if(hdma->XferM1CpltCallback != NULL)
            {
              /* Transfer complete Callback for memory1 */
            	hdma->XferM1CpltCallback(hdma);
            }
          }
          /* Current memory buffer used is Memory 1 */
          else
          {
            if(hdma->XferCpltCallback != NULL)
            {
              /* Transfer complete Callback for memory0 */
              hdma->XferCpltCallback(hdma);
            }
          }
        }
    else  
        {
        // ME: problem - circular is forced on when using double    
        // buffered so this never hits to go back to READY state:
          if((((DMA_Stream_TypeDef   *)hdma->Instance)->CR & DMA_SxCR_CIRC) == 0U)
          {
            /* Disable the transfer complete interrupt */
            ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  &= ~(DMA_IT_TC);
 
            /* Process Unlocked */
            __HAL_UNLOCK(hdma);
 
            /* Change the DMA state */
            hdma->State = HAL_DMA_STATE_READY;
          }
 
          if(hdma->XferCpltCallback != NULL)
          {
            /* Transfer complete callback */
            hdma->XferCpltCallback(hdma);
          }
        }

4 REPLIES 4

DMA's NDTR is 16 bit, so it's limited to 65535 transfers. This well documented in the RM, and if it's not documented for Cube/HAL, that's then the only bug.

> Double buffer mode is required when the transfer is larger than 64KWords

Circular, thus double-buffer, is unsuitable for memory-to-memory transfer - you can't stop it precisely.

Simply perform as many DMA transfer cycles as needed, if you need more than 64k transfers.

JW

BillR
Associate III

Thanks for the response.

Its not a mem-to-mem transfer, its peripheral DCMI fifo to memory.

It just appears that the HAL driver does not correctly handle what is described in an app note, on how to transfer > 64Kwords sizes from DCMI snapshot. After this single snapshot the DMA driver state never goes back to READY. I can deal with it, but I thought I'd let people know about this issue.

0690X00000At9U5QAJ.png

Ah, I see. Sorry, I misread your initial post.

I'd say this is a usage mode which was not envisaged in Cube/HAL. Any "library" inevitably implements only a fraction of what the actual hardware allows to achieve, so whenever you get outside what's "usual", you are on your own.

The quoted text above is quite simple-minded, as the double-buffer mode allows you to change the address of the inactive buffer's memory pointer in respective DMA_SxMyAR register "on the fly", doing so in the transfer-complete interrupt of given DMA stream will then allow you an unlimited frame size (well, limited by the available memory, of course).

I don't Cube (in case it was not obvious =) )

JW

BillR
Associate III

Still don't really know what Cube means anyway.

I also have to do a custom linked list mode DMA transfer into JPEG encoder (8x8 blocks) and I will probably not bother to try to use the HAL, just write by hand.