2025-07-20 10:29 AM
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.