AnsweredAssumed Answered

Timing, DMA & SDIO "Bug" in Standards Peripherals Examples V3.5.0

Question asked by mueller.moritz on Mar 2, 2012
Latest reply on Jun 1, 2012 by mueller.moritz
Hi,

I just spent plenty of days to get the SDIO example (esp. stm32_eval_sdio_sd.c) working with freeRTOS, FatFS and DMA Transfer.

There is a problem in the code in 
SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize)
and in SD_WriteBlock, too.

The problem is, that in the code  the read or write_block command is sent first and afterwards the DMA2 is configured and enabled (i skipped the polling mode stuff).
01./*!< Send CMD17 READ_SINGLE_BLOCK */
02.  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
03.  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
04.  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
05.  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
06.  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
07.  SDIO_SendCommand(&SDIO_CmdInitStructure);
08.  
09.  errorstatus = CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);
10.  
11.  if (errorstatus != SD_OK)
12.  {
13.    return(errorstatus);
14.  }
15.  
16.#if defined (SD_POLLING_MODE)
17. /* long polling mode stuff is long */
18.#elif defined (SD_DMA_MODE)
19.    SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
20.    SDIO_DMACmd(ENABLE);
21.    SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, BlockSize);
22.#endif

In the manual on page 555 the following  steps are written to transfer data between SDIO and memory:
1. Do the card identification process
2. Increase the SDIO_CK frequency
3. Select the card by sending CMD7
4. Configure the DMA2 as follows ...
5. Send CMD24 (WRITE_BLOCK) as follows ...

In the example the steps 4 and 5 are inverted. That works well in the example, but when there is a small delay line 09 and 21 like
1.uint16_t nTime = 0x0000;
2.for(nTime = 0; nTime <0xFFF; nTime++){}

or a delay be waiting for semaphores, the program will fail (the transfer will stop somewhere, when there are bytes in the FIFO left).

The solution for my problem was to put the DMA-stuff before sending the command like stated in the manual, like so:

01.#if defined (SD_DMA_MODE)
02.  SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
03.  SDIO_DMACmd(ENABLE);
04.  SD_LowLevel_DMA_RxConfig((uint32_t *)readbuff, BlockSize);
05.#endif
06.  
07.  /*!< Send CMD17 READ_SINGLE_BLOCK */
08.  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
09.  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;
10.  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
11.  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
12.  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
13.  SDIO_SendCommand(&SDIO_CmdInitStructure);
14.  
15.  errorstatus = CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);

and disabling the DMA2 in case of error.

Hope, that helps anybody ;-)
Moritz

Outcomes