AnsweredAssumed Answered

SDIO DMA initialization order

Question asked by reynolds.mike on Jun 19, 2014
Latest reply on May 18, 2017 by dueringandreas
What is the proper order of the DMA setup when using SDIO to perform block transfers?

An older version of ST's STM32_EVAL library sets up the DMA at the end of each block transfer function, but a newer version sets it up at the beginning. I've come to the conclusion that this is incorrect, and should be setup before the CPSM and DPSM state machines are configured.

The following example is taken from the STM3240_41_G_EVAL software (see attachments for source code):
Old Version v1.0.0 2011_09_30     vs     Newer v1.1.2 2013_09_19
                         SD_ReadBlock()
Setup for single block read             Setup DMA
Setup DMA                               Setup for single block read

                       SD_ReadMultiBlocks()
Setup for multiple block read           Setup DMA
Setup DMA                               Setup for multiple block read

                         SD_WriteBlock()
Setup for single block write            Setup DMA
Setup DMA                               Setup for single block write

                     SD_WriteMultiBlocks()
Setup for multiple block write          Setup DMA
Setup DMA                               Setup for multiple block write

There was a blurb in the V1.1.0 release notes for which says:

"Transmit and receive functions: swap the order of state machine and DMA configuration, to fix marginal limitation where the card sent data to the SDIO interface while the DMA is not ready to transfer them"

Besides these obvious changes, there is also a set of subtle changes within the setting up of the DMA.

The SD_ReadMultiBlocks() and SD_WriteMultiBlocks() functions changed the order:
SD_ReadMultiBlocks()
OLD v1.0.0 2011_09_30
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
    SDIO_DMACmd(ENABLE);
    SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * BlockSize));

NEW v1.1.2 2013_09_19
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
    SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, (NumberOfBlocks * BlockSize));
    SDIO_DMACmd(ENABLE);
 
SD_WriteMultiBlocks()
OLD v1.0.0 2011_09_30
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
    SDIO_DMACmd(ENABLE);
    SD_LowLevel_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * BlockSize));

NEW v1.1.2 2013_09_19
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
    SD_LowLevel_DMA_TxConfig((uint32_t *)writebuff, (NumberOfBlocks * BlockSize));
    SDIO_DMACmd(ENABLE);
    
Note the last two functions are swapped.
SD_ReadBlock() and SD_WriteBlock() both have the same DMA setup orders between the two versions:

SD_ReadBlock()
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
    SDIO_DMACmd(ENABLE);
    SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, BlockSize);

SD_WriteBlock()
    SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);
  SD_LowLevel_DMA_TxConfig((uint32_t *)writebuff, BlockSize);
  SDIO_DMACmd(ENABLE);
 

To summarize:
SD_ReadBlock(): both versions: ITConfig, DMACmd(EN), LL_DMA_RX
SD_ReadMultiBlocks(): was ITConfig, DMACmd(EN), LL_DMA_RX, but is now ITConfig, LL_DMA_RX, DMACmd(EN)
SD_WriteBlock(): both versions: ITConfig, LL_DMA_TX, DMACmd(EN)
SD_WriteMultiBlocks(): was ITConfig, DMACmd(EN), LL_DMA_TX, but is now ITConfig, LL_DMA_TX, DMACmd(EN)

Why aren't the initialization sequences consistent, such as [1] IT_Config(...), [2] SDIO_DMACmd(ENABLE);, [3] SD_LowLevel_DMA_{Rx/Tx}Config(...), or [1] IT_Config(...), [2] SD_LowLevel_DMA_{Rx/Tx}Config(...), [3] SDIO_DMACmd(ENABLE);  regardless of the transfer quantity and type to be performed?? The newest CubeMX HAL driver has the same order whether or not a single or multi-block transfer is to take place:

HAL_SD_ReadBlocks_DMA():
/* Enable transfer interrupts */
  __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\
                                SDIO_IT_DTIMEOUT |\
                                SDIO_IT_DATAEND  |\
                                SDIO_IT_RXOVERR  |\
                                SDIO_IT_STBITERR));
 
  /* Enable SDIO DMA transfer */
  __HAL_SD_SDIO_DMA_ENABLE();
 
...
 
  /* Enable the DMA Stream */
  HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)SDIO_FIFO_ADDRESS, (uint32_t)pReadBuffer, (uint32_t)(BlockSize * NumberOfBlocks));
 

HAL_SD_WriteBlocks_DMA():
/* Enable transfer interrupts */
  __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\
                                SDIO_IT_DTIMEOUT |\
                                SDIO_IT_DATAEND  |\
                                SDIO_IT_TXUNDERR |\
                                SDIO_IT_STBITERR));
 
...
 
  /* Enable the DMA Stream */
  HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pWriteBuffer, (uint32_t)SDIO_FIFO_ADDRESS, (uint32_t)(BlockSize * NumberOfBlocks));

  /* Enable SDIO DMA transfer */
  __HAL_SD_SDIO_DMA_ENABLE();


So according to the CubeMX sequence, the proper order appears to be:
ITConfig, DMACmd(EN), LL_DMA_RX     for RX
and
ITConfig, LL_DMA_TX, DMACmd(EN)     for TX
which is almost consistent with the v1.1.2 2013_09_19 code, except the multi-block RX (SD_ReadMultiBlocks()) has the ITConfig, LL_DMA_RX, DMACmd(EN) order instead of ITConfig, DMACmd(EN), LL_DMA_RX.

Is this correct?

Thanks!

Attachments

Outcomes