cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 L476RG: DMA + SDMMC: SDMMC Timeout after Write

Benjamin Richard
Associate
Posted on September 04, 2017 at 12:58

I'm trying to get the DMA + SDMMC to write to an SD Card using the HAL_SD_WriteBlocks_DMA() function. 

After I call the function, the HAL_DMA_GetState() function never returns HAL_DMA_STATE_READY, and the same is true for HAL_SD_GetState(), meaning all subsequent calls to the SDMMC fail.

I attached Data, Clock and Cmd to an Oscilloscope (the wires from the board to SD card), and I don't register any activity on the Data and Cmd lines in the above case. 

So no data is written.

Firmware: Using Cube, 1.8.1, SDMMC is clocked at 48Mhz, the DMA at 80Mhz. Transfer using 1 Data line. Interrupts are set for both TX, RX and there is a global SDMMC interrupt with a higher priority than TX and RX.

DMA: TX uses DMA2 Channel 4, RX uses DMA2 Channel 5. 

HAL_SD_ReadBlocks_DMA, HAL_SD_ReadBlocks, and HAL_SD_WriteBlocks all work. 

I modified the 

BSP_SD_WriteBlocks_DMA function to wait for the DMA and SDMMC to finish before returning. 

https://pastebin.com/Eavqk902

 

This is my test code (nothing important here): 

https://pastebin.com/tfXy2mW9

 

In the ERRATA Datasheet I found a note saying the WAITRESP register doesn't work correctly when no response is expected. I don't think this applies here; But I tried it anyway by setting sdmmc_cmdinit.Response         = SDMMC_RESPONSE_NO; in the function SDMMC_CmdWriteMultiBlock(). Errorstate will be bad after I do that.

http://www.st.com/content/ccc/resource/technical/document/errata_sheet/65/dd/2c/78/59/b0/4c/68/DM00111498.pdf/files/DM00111498.pdf/jcr:content/translations/en.DM00111498.pdf

 

----

EDIT1: 

I recompiled the project using MXCube and switched the DMA2 Channels for RX and TX, now RX is on Channel 4, TX is on Channel 5. 

Now Writing is working without issues, but reading hangs. 

I changing the priority of one channel over the other doesn't change anything either.

----

EDIT2: 

So as a workaround, I just don't use the DMA to write for now. 

Now I have a new issue: 

The SDMMC doesn't go back to HAL_SD_STATE_READY if I call the DMA to fast. 

If I put a delay between the write commands they work without issue. 

EDIT2.2: Tipp: The SDMMC and the DMA each throw an interrupt! Make sure you use the correct one, as the DMA can be finished before the SDMMC is. Doesn't solve this problem though.  

-

--

EDIT3: 

ST Support suggested following solution: 

https://pastebin.com/yCxq9E6q

 

I didn't verify it because I migrated to firmware 1.9 by now, but maybe it helps someone else. 

#cube-mx #sdmmc-dma-stm32l4 #sdmmc #dma #l476rg #stm32-l4
8 REPLIES 8
Zt Liu
Senior III
Posted on February 07, 2018 at 07:24

Hi, Ben.

Using CubeL4 1.10, I've never succeed in applying DMA2_Channel4 for 

HAL_SD_WriteBlocks_DMA()

  nor for HAL_SD_ReadBlocks_DMA().

However, DMA_Channel5 is working properly, either for read or write.

I'm using Nucleo 64 stm32L476 with an uSD adapter. (with all pins pulled out).

Really want to know is there anyone successfully using DMA2_Channel4 for SDMMC DMA.

.Zt

pw yzh
Associate
Posted on March 08, 2018 at 04:41

I get the same problem with you.Have you solve it NOW?DMA2_Channel4

for 

HAL_SD_WriteBlocks_DMA()

 is unuseful?

Nikolay Brinken
Associate III
Posted on March 31, 2018 at 21:46

after multiblocks transaction you should wait for SD card is no busy:

while(!LL_GPIO_IsInputPinSet(GPIOC, LL_GPIO_PIN_8)){};

where port C pin 8 - SD card data0 pin

Benjamin Richard
Associate
Posted on May 17, 2018 at 23:27

Hey, thanks for all your replies! 

I only got Channel 5 to work as well. 

I can just give one more tip regarding the SDMMC unit and SD Cards: 

When the SD Card recives a packet to write, it actually takes some time for the SD Card to be ready again for the next packet. There are 2 ways to find out if that is the case: 

1. You poll the SD Card using the appropriate command, it needs to be in Transfer State if I remember correctly. 

2. You can actually generate an SDMMC interrupt when the SD Card is ready to write. This is because the SD Card will pull DAT1 up (in 4 Bit mode) when it is ready to get the next block. You can configure the SDMMC to register that and throw an interrupt. 

3. And this is what Nikolay is refering to, you can check manually if DAT1 is up or not. 

Be aware that you need to keep providing the SD Card with a clock signal, otherwise it won't pull DAT1 up when it's done.
Imen.D
ST Employee
Posted on May 24, 2018 at 18:03

Hello All,

The problem occurs when using DMA2_Channel4 for one path and DMA2_Channel5 for the other path. 

This is due to the fact that two channels are configured for SDMMC1 request.

The SDMMC DMA request is not dependent to a direction (it is SDMMC1 and not SDMMC1_TX or SDMMC1_RX).

When using DMA2_Channel4 for TX and RX paths, there is no issue.

As workaround, we suggest to use one of these solutions:

  • 1st solution : 

    Use same DMA channel for both Rx and Tx paths.

  • 2nd solution : Clear the request of the other path before to perform a DMA transfer;

=> This can be done by using the function LL_DMA_SetPeriphRequest().

Hope this helps you.

Best Regards,

Imen.

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on May 25, 2018 at 10:17

Hello  Imen!

I tested DMA2_Channel4 Tx and Rx. The problem was not solved. The wait for GPIOC_PIN_8 hi-level (SD card is not busy) works successfully.

Nikolay.

>�?§�?µÑ‚�?²�?µÑ€�?³, 24 �?¼�?°Ñ� 2018, 19:04 +03:00 �?¾Ñ‚ Imen D <st-microelectronics@jiveon.com>:

>STMicroelectronics Community

>Re: STM32 L476RG: DMA + SDMMC: SDMMC Timeout after Write

>reply from Imen D in STM32 MCUs Forum - View the full discussion

I am running into this issue on the STM32L496 and I am going to try the 2nd solution. I had no issue with the STM32F405 in this regard and it used different DMA channels for both TX and RX.

Tried 2nd solution...does not work...

/* USER CODE BEGIN BeforeReadDMABlocksSection */

/* can be used to modify previous code / undefine following code / add code */

/* USER CODE END BeforeReadDMABlocksSection */

/**

 * @brief Reads block(s) from a specified address in an SD card, in DMA mode.

 * @param pData: Pointer to the buffer that will contain the data to transmit

 * @param ReadAddr: Address from where data is to be read

 * @param NumOfBlocks: Number of SD blocks to read 

 * @retval SD status

 */

uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)

{

 uint8_t sd_state = MSD_OK;

  

 LL_DMA_SetPeriphRequest(hsd1.hdmatx->DmaBaseAddress, hsd1.hdmatx->ChannelIndex, hsd1.hdmatx->Init.Request);

 /* Read block(s) in DMA transfer mode */

 if (HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK)

 {

  sd_state = MSD_ERROR;

 }

  

 return sd_state; 

}

/* USER CODE BEGIN BeforeWriteDMABlocksSection */

/* can be used to modify previous code / undefine following code / add code */

/* USER CODE END BeforeWriteDMABlocksSection */

/**

 * @brief Writes block(s) to a specified address in an SD card, in DMA mode.

 * @param pData: Pointer to the buffer that will contain the data to transmit

 * @param WriteAddr: Address from where data is to be written

 * @param NumOfBlocks: Number of SD blocks to write 

 * @retval SD status

 */

uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)

{

 uint8_t sd_state = MSD_OK;

  

 LL_DMA_SetPeriphRequest(hsd1.hdmarx->DmaBaseAddress, hsd1.hdmarx->ChannelIndex, hsd1.hdmarx->Init.Request);

 /* Write block(s) in DMA transfer mode */

 if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK)

 {

  sd_state = MSD_ERROR;

 }

  

 return sd_state; 

}