AnsweredAssumed Answered

Solution to fix STM32F4xxx STMCubeMX Firmware V1.18 SDIO FATFS DMA not working issue

Question asked by Bardeen Lai on Jan 2, 2018
Latest reply on May 2, 2018 by vagni

Hi all,

 

Recently I use STM32CubeMX Ver 4.23.0 (STMCube V1.0), firmware V1.18 to generate codes for STM32F407 by using SDIO 4-bit bus to access SD card via DMA or standard IO. The generated codes could not function probably.

 

In order to make it work, you have to modify three files generated by STM32CubeMX:

1. bsp_driver_sd.c

2. sd_diskio.c

3. fatfs.c

 

Here are the procedures:

1. bsp_driver_sd.c

Modify the BSP_SD_WriteBlocks() and BSP_SD_ReadBlocks_DMA() to support DMA or standard I/O:

// A flag indicating if to use DMA for read/write
uint8_t BSP_SD_Ext_UseDMA = 1;
/*==========================================================================
Description
DMA or polling mode of Reads block(s) from a specified address in an SD card
* @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
* @param Timeout: Timeout for read operation
* @retval SD status
---------------------------------------------------------------------------*/

uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout)
{
    HAL_SD_StateTypeDef state_return;
    uint32_t timeout = 0;

    if (BSP_SD_Ext_UseDMA == 0) {
        if (HAL_SD_ReadBlocks(&hsd, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK)
            return MSD_ERROR;
    } else {
          // Read block(s) in DMA transfer mode
        if (HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*) pData, ReadAddr, NumOfBlocks) != HAL_OK)
            return MSD_ERROR;
          
        // Wait until the SDIO/SDMMC and DMA finish the read/write
        timeout = 0;
        do {
            state_return = HAL_SD_GetState(&hsd);
            timeout++;
        } while((state_return == HAL_SD_STATE_BUSY) && (timeout < SD_DATATIMEOUT));

        if (HAL_SD_STATE_READY != state_return)
            return MSD_ERROR;
    }
    return MSD_OK;
}
/*==========================================================================
Description
DMA or polling mode of Write block(s) to a specified address in an SD card
* @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
* @param Timeout: Timeout for write operation
* @retval SD status
---------------------------------------------------------------------------*/

uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout)
{
    HAL_SD_StateTypeDef state_return;
    uint32_t timeout = 0;

    if(BSP_SD_Ext_UseDMA == 0) {
        if (HAL_SD_WriteBlocks(&hsd, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK)
            return MSD_ERROR;
    } else {
          // Read block(s) in DMA transfer mode
        if (HAL_SD_WriteBlocks_DMA(&hsd, (uint8_t*) pData, WriteAddr, NumOfBlocks) != HAL_OK)
            return MSD_ERROR;

        // Wait until the SDIO/SDMMC and DMA finish the read/write
          timeout = 0;
        do {
            state_return = HAL_SD_GetState(&hsd);
            timeout++;
        }
        while((state_return == HAL_SD_STATE_BUSY) && (timeout < SD_DATATIMEOUT));

          if (HAL_SD_STATE_READY != state_return)
            return MSD_ERROR;
    }
    return MSD_OK;
}

 

2. sd_diskio.c

i) fix the missing initialization code for SDIO

Original generated code:

 

DSTATUS SD_initialize(BYTE lun)
{
  return SD_CheckStatus(lun);
}

Shoud be modified (I have no idea why BSP_SD_Init() was missing!):

DSTATUS SD_initialize(BYTE lun)
{
    Stat = STA_NOINIT;

    if (BSP_SD_Init() == MSD_OK)
        Stat = SD_CheckStatus(lun);

    return Stat;
}

Otherwise, it could not initialize the SDIO via HAL_SD_Init()!

ii) modify SD_read() and SD_write:

DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
    DRESULT res = RES_ERROR;

    if (BSP_SD_ReadBlocks((uint32_t*)buff,
                          (uint32_t) (sector),
                          count,
                          SDMMC_DATATIMEOUT) == MSD_OK) {

        // wait until the read operation is finished
        while (BSP_SD_GetCardState()!= MSD_OK);
        res = RES_OK;
    }

    return res;
}

DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
    DRESULT res = RES_ERROR;

    if (BSP_SD_WriteBlocks((uint32_t*)buff,
                           (uint32_t)(sector),
                            count,
                            SDMMC_DATATIMEOUT) == MSD_OK) {
        // wait until the Write operation is finished
        while (BSP_SD_GetCardState() != MSD_OK);
        res = RES_OK;
    }
    return res;
}

3. fatfs.c

Add a mounting procedure to mount the file system of SD card

Original generated code:

void MX_FATFS_Init(void) 
{
  /*## FatFS: Link the SD driver ###########################*/
  retSD = FATFS_LinkDriver(&SD_Driver, SDPath);

  /* USER CODE BEGIN Init */
  /* additional user code for init */    

  /* USER CODE END Init */
}

Modified code:

void MX_FATFS_Init(void) 
{
  /*## FatFS: Link the SD driver ###########################*/
  retSD = FATFS_LinkDriver(&SD_Driver, SDPath);

  /* USER CODE BEGIN Init */
  /* additional user code for init */    
    if (retSD != 0)
        Error_Handler();

    if (f_mount(&SDFatFS, (TCHAR const*)SDPath, 0) != FR_OK)
        Error_Handler();

  /* USER CODE END Init */
}

 

Finally, we could write codes to test the FATFS :

void SDFileTest(void)
{
    FIL MyFile;
    FRESULT res;                               /* FatFs function common result code */
    uint32_t byteswritten, bytesread;          /* File write/read counts */
    uint8_t wtext[] = "Hello, STM32F4 FatFs!"; /* File write buffer */
    uint8_t rtext[100];                        /* File read buffer */

    printf("SD File create\n");
    // Create file test
    if (f_open(&MyFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
          Error_Handler();

    res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);

    if ((byteswritten == 0) || (res != FR_OK))
       Error_Handler();

    f_close(&MyFile);
    printf("done!\n");

    printf("SD File open\n");
    // Read file test
    if (f_open(&MyFile, "STM32.TXT", FA_READ) != FR_OK)
        Error_Handler();

    res = f_read(&MyFile, rtext, sizeof(rtext), (UINT*)&bytesread);
             
    if ((bytesread == 0) || (res != FR_OK))
        Error_Handler();

    f_close(&MyFile);
               
    if ((bytesread != byteswritten))
        Error_Handler();

    printf("done!\n");
}

int main(void)
{
.
.
  MX_DMA_Init();
  .
  .
  MX_SDIO_SD_Init();
  .
  .
  MX_FATFS_Init();
  .
  .
  SDFileTest();
  while (1);
}

It works and note that I have reported this kind of issue to ST on-line support team.

 

Best regards

Outcomes