SD Card corruption after f_write with STM32H7 + SDMMC/FATFS + FREERTOS
I'm seeing a filesystem corruption issue on an STM32H7 when using FatFs with SDMMC DMA.
Hardware / Software
-
STM32H7
-
SDMMC1
-
DMA (and MDMA support enabled)
-
FatFs generated by CubeMX
-
D-Cache enabled
-
8 GB Swissbit industrial SD card
-
Generated
sd_diskio.cbased on:/* Note: code generation based on sd_diskio_dma_rtos_template_bspv1.c v2.1.4 */
Problems
The SD card works normally while mounted:
-
Files can be created
-
Data can be written
-
Data can be read back
-
f_write(),f_sync(), andf_close()all return success
However, after:
-
Removing and reinserting the SD card, or
-
Power cycling the system
the SD card is detected by Windows as:
RAW / Unformatted
and must be reformatted before it can be used again.
Important observation
If I only perform read operations:
Mount card
Read files
Power cycle / reinsert card
the filesystem remains valid. The corruption only occurs after write operations.
Initial investigation
Because the STM32H7 uses D-Cache, I initially suspected cache coherency issues.
I created a dedicated non-cacheable MPU region:
0x24000000 - 0x2401FFFF (128 KB)
and placed my application DMA buffers in that region using:
__attribute__((section(".RAM_D1_NCACHE")))
__attribute__((aligned(32)))
I also verified via the linker map and debugger that the buffers were actually located inside the non-cacheable region.
Despite this, the filesystem corruption remained.
Investigation of sd_diskio.c
The generated driver contains a scratch buffer path used when the user buffer is not suitably aligned.
I noticed the following code:
#if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
#endif
for (i = 0; i < count; i++)
{
memcpy((void *)scratch, buff, BLOCKSIZE);
buff += BLOCKSIZE;
ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch,
(uint32_t)sector++,
1);
}
The sequence is:
-
Invalidate cache for scratch buffer
-
Copy data into scratch buffer using CPU (
memcpy) -
Start DMA transfer from scratch buffer
-
No cache clean after the copy
This looked suspicious because the CPU modifies the scratch buffer immediately before the DMA transfer.
Additional test
I moved the scratch buffer from the sd_diskio.c into my non-cacheable MPU region:
__attribute__((section(".RAM_D1_NCACHE")))
__attribute__((aligned(32)))
static uint8_t scratch[BLOCKSIZE];
Result:
Filesystem corruption disappeared.
DMA operation continues to work correctly and the SD card remains valid after reinsertion and power cycling.
Has anyone else observed similar behaviour with the STM32H7 FatFs SD driver, SDMMC DMA, or the generated scratch-buffer path?
If so:
- What was the root cause?
- Did you use a similar workaround?
- Is there a recommended fix that keeps the scratch buffer in normal cacheable RAM?
