cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746G‑DISCO | SDMMC + DMA + D‑Cache – hangs at state 5, FR_DISK_ERR / empty files → root‑cause & minimal fixes

anejati
Visitor

Subject: STM32F746G‑DISCO | SDMMC + DMA + D‑Cache – hangs at state 5, FR_DISK_ERR / empty files → root‑cause & minimal fixes


Cube / HAL versions

  • 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)


1 – Read path: card never leaves RECEIVING (0x5)

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.


2 – Write path: f_sync() returns FR_DISK_ERR / file size stays 0

2.1 Cache coherency

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().

2.2 Card busy after DMA

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;

2.3 Timeout

Raise SD_DATATIMEOUT to a realistic value (≥ 500 ms; I used 5000 ms) to cover worst‑case card program times.


3 – FatFs log example (byte‑oriented write)

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.


Result

  • 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.

2 REPLIES 2
anejati
Visitor

My github is https://github.com/anj1 if you'd like to ask me more details about this fix.

On the F7 the DTCMRAM can be used to avoid cache coherency issues.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..