2025-07-20 10:29 AM - last edited on 2025-07-21 3:50 AM by Andrew Neil
Subject: STM32F746G‑DISCO | SDMMC + DMA + D‑Cache – hangs at state 5, FR_DISK_ERR / empty files → root‑cause & minimal fixes
CubeF7: v1.28.0
CubeMX: 6.11
Board: STM32F746G‑DISCO
Middleware: FatFs R0.14, _USE_LFN = 3, _MAX_SS = 512
Cache: I‑ & D‑cache enabled (default)
Symptom
HAL_SD_GetCardState() polled after HAL_SD_ReadBlocks_DMA() stays at 0x05 → loop never exits.
Root cause
SD_DMAReceiveCplt() does not re‑enable the DATAEND interrupt, so the SDMMC ISR never runs and HAL state is never cleared.
Fix (HAL driver)
File: stm32f7xx_hal_sd.c
/* inside SD_DMAReceiveCplt() */ __HAL_SD_ENABLE_IT(hsd, SDMMC_IT_DATAEND); /* <- add this line */
After this patch the DATAEND IRQ fires, HAL_SD_IRQHandler() sends CMD12, sets hsd->State = READY, and the read loop exits.
Before starting a DMA write, the sector buffer FatFs passes to disk_write() must be cleaned; after a DMA read it must be invalidated.
Both address and length must be cache‑line aligned (32 B on F7).
static inline void cache_clean(const void *buf, uint32_t len) { uint32_t a = (uint32_t)buf & ~31U; len += (uint32_t)buf - a; len = (len + 31U) & ~31U; SCB_CleanDCache_by_Addr((uint32_t*)a, len); } static inline void cache_invalidate(void *buf, uint32_t len) { … }
Call cache_clean() in every disk_write() (or inside your BSP write routine) and cache_invalidate() in every successful disk_read().
After the DMA completes the card enters PROGRAMMING (0x07) until its internal erase/program sequence finishes.
The driver must keep polling CMD13 until the card returns TRANSFER (0x04).
/* BSP_SD_WriteBlocks_DMA() – after hsd1.State == READY */ HAL_SD_CardStateTypeDef cs; uint32_t t1 = HAL_GetTick(); do { cs = HAL_SD_GetCardState(&hsd1); if ((HAL_GetTick() - t1) >= SD_DATATIMEOUT) /* e.g. 5000 ms */ { HAL_SD_Abort(&hsd1); return MSD_ERROR; } } while (cs == HAL_SD_CARD_PROGRAMMING || cs == HAL_SD_CARD_RECEIVING || cs == HAL_SD_CARD_SENDING); return (cs == HAL_SD_CARD_TRANSFER) ? MSD_OK : MSD_ERROR;
Raise SD_DATATIMEOUT to a realistic value (≥ 500 ms; I used 5000 ms) to cover worst‑case card program times.
UINT bw; size_t len = strlen(msg); if (f_write(&logFile, msg, len, &bw) != FR_OK || bw != len) goto err; if (f_write(&logFile, "\r\n", 2, &bw) != FR_OK) goto err; if (f_sync(&logFile) != FR_OK) goto err;
No f_printf() → avoids the UTF‑16 %s pitfall when _USE_LFN != 0.
Read loop exits correctly.
f_sync() always returns FR_OK.
Log file grows and is readable on a PC after every reset / power loss.
These patches are small (3 driver lines + BSP cache helpers + PROGRAMMING poll) and can be upstreamed to stm32f7xx_hal_sd.c & CubeMX templates.
Hope this saves someone else half a day of head‑scratching.
2025-07-20 10:30 AM
My github is https://github.com/anj1 if you'd like to ask me more details about this fix.
2025-07-20 12:34 PM
On the F7 the DTCMRAM can be used to avoid cache coherency issues.
2025-07-20 2:17 PM
Thanks Tesla. To be clear, cache coherency is only part of the issue, an equal issue is not respecting the period in which the card is in the PROGRAMMING (0x7) state.
2025-07-21 3:33 AM
Hello @anejati
Could you please specifie how to reproduce the issue?
2025-07-21 8:25 PM
Issue is reproduced on a STM32F746G-Discovery board with the cubemx/library versions I mentioned in the post. Writing to a FAT formatted UHS-I sd card fails, however it likely fails with other sd cards as well.
2025-07-28 1:30 AM
Hello @anejati
There is two examples FATFS on STM32F746G-Discovery board, please check them.