STM32F427 SDIO write reports success at every layer but data never persists (DMA and polling both)
Part Number: STM32F427VIT6
Environment: Custom PCB (not an eval/dev board), native SDIO/SDMMC1 peripheral, 4-bit bus, FatFs (ChaN's ff.c) on top of ST's HAL (stm32f4xx_hal_sd.c). STM32CubeIDE 2.2.0, GNU Arm Embedded toolchain 14.3.rel1 (arm-none-eabi-gcc), STM32CubeProgrammer for flashing/SWD debug, bare-metal HAL (no RTOS). SDIO clock tested from 400kHz up to ~24MHz; same result throughout.
Schematics / hardware note: This is a custom PCB, so a board-level cause can't be fully excluded, a scope check on the 3.3V rail during a write burst is still pending, and I'm happy to attach the relevant SDMMC1/power schematic on request. That said, a pure PCB signal-integrity/trace defect looks unlikely specifically: DAT0-3 are bidirectional and reads over those same physical traces are 100% reliable, every write's CRC check passes cleanly, the failure is fully deterministic rather than marginal/intermittent, and it's unchanged across the full 400kHz-24MHz clock range tested, none of that fits a timing-margin/trace-length explanation. A power-delivery issue during the card's internal write-programming phase specifically (as opposed to the low-current handshake phase, which always succeeds) remains the leading untested hardware hypothesis.
Details / symptom: A write reports success at every single layer, FatFs FRESULT clean, BSP_SD_WriteBlocks()/_DMA() return MSD_OK, hsd.ErrorCode clean, SDIO->STA shows clean DBCKEND/DATAEND with no error flags, and a raw CMD13/SEND_STATUS immediately afterward decodes to 0x900 (READY_FOR_DATA=1, CURRENT_STATE=4/"tran", every error bit zero). But the data never lands: reading the same sector back, at the raw block level, bypassing FatFs entirely, returns the pre-existing stale content, not what was just written, not corrupted garbage.
Expected behavior: Reading back a sector immediately after writing it should return the data just written. Actual: it returns whatever was there before.
How to reproduce: BSP_SD_WriteBlocks() (or _DMA()) a known pattern to a sector, then immediately BSP_SD_ReadBlocks()/_DMA() the same sector and compare. Fails every time, regardless of sector location, write pattern, clock speed, or bus width.
Occurrence: Systematic, 100% reproducible, every single attempt, not intermittent.
Sanity checks already performed (with hardware evidence, not just config review):
- Not FatFs-specific: raw
BSP_SD_WriteBlocks()/_DMA()block writes fail identically. - Not sector-location-specific: tested at multiple sectors across the card.
- Not card-specific: reproduces identically across 3 different physical SD cards.
- Not a write-protect flag:
HAL_SD_GetCardCSD()showsPermWrProtect=0,TempWrProtect=0,WrProtectGrEnable=0. - Not bus-width-dependent: fails identically in 1-bit and 4-bit mode.
- Not clock-speed-dependent: fails identically from 400kHz to ~24MHz.
- Not DMA-specific: switching the write path to polling (
BSP_SD_WriteBlocks(), no DMA at all) produces the exact same symptom. - Not a stuck/stale software state:
hsd.Statereads back clean/READYimmediately after a fresh failed write. - Not a card-side volatile buffer: power-cycling the card (GPIO power switch) and re-initializing before the read-back doesn't recover the data.
- Not a busy-line/trailing-clock desync: direct GPIO read of the physical
DAT0line (bypassing the SDIO peripheral's own busy interpretation entirely) matches the software's ready/busy state exactly. - Not interference from other on-board peripherals: reproduces identically in a stripped-down boot with every other peripheral (UART/I2C/SPI/USB/other DMA/timers) left uninitialized, SDIO+DMA+FatFs running alone.
- Hardware flow control (
SDIO_HARDWARE_FLOW_CONTROL_ENABLE): no change either way.
One separate, real bug found and fixed along the way (not the cause of the above, but worth mentioning for anyone else on this thread): a DMA write's NDTR register doesn't reach zero in sync with SDIO->DCOUNT/FIFOCNT, same symptom class as this earlier thread on F427 SDIO+DMA writes. Worked around by moving writes to polling mode instead of DMA, but as noted above, the actual write-persistence bug reproduces identically either way, so that wasn't the root cause of this specific issue.
One more data point: the card's own busy/programming time after a write is consistently ~1ms, much shorter than a typical NAND program cycle, which suggests the card may not be attempting a real internal write at all rather than attempting one and failing partway through.
Question: Has anyone seen a write that the SDIO peripheral, the HAL, and the card's own CMD13 status all agree completed cleanly, but that silently doesn't persist? Is there any register-level state (beyond STA/DCOUNT/FIFOCNT/CMD13) that could show a write being accepted by the peripheral/card protocol layer without actually reaching flash? Any errata for the F427 SDMMC1 block worth checking that isn't in the standard STM32F4 errata sheet?
