cancel
Showing results for 
Search instead for 
Did you mean: 

FreeRTOS+FatFs+SD+DMA

GreenGuy
Senior III
Posted on March 23, 2018 at 03:40

Still having issues with tracking down how this is supposed to work using F746G-Discovery board, F7V1.11.0 CubeMX, with the board configured to use FreeRTOS, FatFs, SDMMC, and DMA.  Everything is fine up to f_close, after which the system times out and the close fails.

Reading some other examples of DMA+FreeRTOS, I see that the callbacks are registered using   HAL_DMA_RegisterCallback which is missing in the initialization.  I also notice that the callbacks are not being executed which is why the timeout.  Is this something that needs to be entered as User code?  If so, with respect to the discovery board noted, what would that look like?

5 REPLIES 5
Rick Sladkey
Associate II
Posted on March 23, 2018 at 04:44

With F7V1.0 CubeMX, this is what I had to do to get FreeRTOS+FatFs+SD+DMA working, YMMV.

Add callbacks in user block in sd_diskio.c, which I think you already noticed:

// N.B. Workarounds for broken SD card with CubeMX + FreeRTOS:// https://community.st.com/0D50X00009bMM8bSAGhttps://community.st.com/0D50X00009XkWyLSAV(void);void BSP_SD_ReadCpltCallback(void);void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd){ BSP_SD_WriteCpltCallback();}void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd){ BSP_SD_ReadCpltCallback();}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Fix SD_status in user block in sd_diskio.c, which is not safe when used with tasks:

// Workaround for non-thread-safe version of SD_status implemented below.// FatFs calls SD_status (via disk_status in ff.c) BEFORE it locks the// file pointer. As a result, SD_status must be reentrant. For our purposes,// FatFs only checks for STA_NOINIT and this cannot change after successful// initialization unless the media is removed.// See: https://community.st.com/external-link.jspa?url=http%3A%2F%2Felm-chan.org%2Ffsw%2Fff%2Fdoc%2Fdstat.html// Reported here: https://community.st.com/0D50X00009XkWmPSAV(BYTE lun){ return Stat;}#define SD_status SD_status_not_thread_safe�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Make sure you have configured DMA for byte-aligned reads and writes in sdmmc.c, because it is very hard to ensure word-aligned writes with FatFs:

 /* SDMMC1 DMA Init */ /* SDMMC1_RX Init */... hdma_sdmmc1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;... /* SDMMC1_TX Init */... hdma_sdmmc1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;�?�?�?�?�?�?�?�?�?

Don't change this in the file, go back to CubeMX to change the DMA configuration and regenerated the code.

If you havecache enabled (and if you have F7, you should), be sure to enable to SD DMA cache management in sd_diskio.c:

#define ENABLE_SD_DMA_CACHE_MAINTENANCE 1�?�?�?�?

Finally, make sure all SD reads are 32-byte aligned, otherwise you WILL eventually get corrupted FatFs data structures (see the linked post for how to make sure FatFs read buffers are 32-byte aligned):

#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)// Workaround: Enforce 32-byte alignment for sector reads:// https://community.st.com/0D50X00009XkWmRSAV SD_read_generated(BYTE lun, BYTE *buff, DWORD sector, UINT count);DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count){ if ((uint32_t)buff % 32 != 0) { Error_Handler(); } return SD_read_generated(lun, buff, sector, count);}#define SD_read SD_read_generated�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Your only other option with this version of the firmware libraries is to disable the cache.

GreenGuy
Senior III
Posted on March 23, 2018 at 21:35

The callbacks are there in stm32746g_discovery_sd.c lines 548-561.  They call to the appropriate __weak void BSP_SD_...Callback in lines 576-588 and this assuming that your looking at F7V1.11.0.  Those __weak defines are redefined in sd_diskio.c at lines 375-405 and both send the appropriate osMessagePut to notify of the completion of the write or read DMA process.  I do not know if you have tried this with or without the BSP files for STM32746G_Discovery added to the CubeMX generation, but in my case I am using the BSP files for the board.  And for completeness I am also excluding from the build the bsp_driver_sd.c that CubeMX generates and places in the Src folder as it doubles on some of the defines in stm3274g_discovery_sd.c.  This being the case, it looks like the first work around block you show is not needed. 

The fix for SD_Status I have implemented, but I would like to know what is the #define for after the code?  I do not see anywhere it is used later.

As for the byte alignment I find this very confusing for the following reasons:

1. There is no sdmmc.c in the CubeMX built project.  There is stm32746g_discovery that contains a section to configure the DMA Rx and Tx parameters which code is not updated by CubeMX.

2. There is a file stm32f7xx_hal_msp.c that contains DAM Rx and Tx parameters for SDMMC1 DMA Init as you point out which are controlled by CubeMX.

So this raises a few questions, since none of the changes have worked to this point.

1) Do the memory Data Widths need to match for Rx and Tx DMA streams?

2) Does it matter that the only selection for the periphery is Word?

3) Should the assignments in stm32f7xx_ahl_msp.c for SDMMC1 DMA Init generated by CubeMX match with the BSP file stm32746g_discovery_sd.c assignments for  DMA parameters in lines 395-433. (F7V1.11.0)?

Posted on March 24, 2018 at 00:12

The cache issues can be entirely avoided by using the DTCM RAM

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 24, 2018 at 04:10

As I said, your mileage might vary!

I am definitely using 1.0, but the weak callbacks in my generated code are defined in Drivers\STM32F7xx_HAL_Driver\Src\stm32f7xx_hal_sd.c and look like this:

/**
 * @brief Tx Transfer completed callbacks
 * @param hsd Pointer to SD handle
 * @retval None
 */
 __weak void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
 /* Prevent unused argument(s) compilation warning */
 UNUSED(hsd);
 /* NOTE : This function should not be modified, when the callback is needed,
 the HAL_SD_TxCpltCallback can be implemented in the user file
 */
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?

In my user block, the define after the SD_status definition is designed to prevent the subsequent generated SD_status function from being used (and to prevent it from being multiply defined).

In my CubeMX project, sdmmc.c is definitely present and generated:

/**
 ******************************************************************************
 * File Name : SDMMC.c
 * Description : This file provides code for the configuration
 * of the SDMMC instances.
 ******************************************************************************
...
 */�?�?�?�?�?�?�?�?

Since you are using

stm32746g_discovery, presumably the code generation differs and is using a predefined BSP.

The point is, the DMASDMMC1_RXMemDataAlignment must match the alignment of all buffers passed to SD_read andSDMMC1_TX

MemDataAlignmentmust match the alignment of all buffers passed to SD_write. There is no sanity checking and if you pass a misaligned buffer to SD_read or SD_write, the data will be corrupted. This is why I recommended byte-alignment (which is maybe 10% slower than word-alignment).

Your code generation is clearly different than mine as in my case CubeMX there is no code related to SDMMC instm32f7xx_hal_msp.c.

Summary:

  • Add callbacks if needed
  • Ensure SD_status is thread-safe
  • Ensure SD DMA RX alignment matches what you are prepared to align all SD_read buff pointers to (byte is safest)
  • Ensure SD DMA TX alignment matches what you are prepared to align all SD_write buff pointers to (byte is safest)
  • Either:
    • use

      DTCM

      RAM (128k at0x2000 0000 on my board) as suggested by Clive (awkward) or

    • disable data cache (slow) or

    • align all SD_write buff pointers to 32-byte boundaries (hard with FatFs)

Posted on March 24, 2018 at 04:16

Perhaps it seems incredible, but I have been programming my STM32F765IGKx for several months without realizing that the first 128k of my 512k of RAM is DTCM RAM. Nothing in CubeMX, the HAL libraries or the generated linker script makes this distinction clear.

Thanks for the insight!