DBCKEND flag not set on STM32H753, causing init_sd_card to hang
I'm encountering an issue when using SDMMC on STM32H753 with Embassy.
- When calling
init_sd_card, the function hangs. - After investigation, I found that it gets stuck in
complete_datapath_transfer, waiting for the DBCKEND flag. - However, checking the registers showed that the DBCKEND flag is never set.
According to the STM32H753 reference manual, the DBCKEND flag should be set in this situation, but in my experiments it never happens.
I have a hypothesis (not fully confident): when using IDMA, the DBCKEND flag might not be set at all. This could potentially be an erratum.
As a workaround, I tried calling complete_datapath_transfer(false), and then everything worked correctly.
I also found this related commit: https://github.com/embassy-rs/embassy/commit/c8a4a4995844be1b61d1a1479a6009eeb69b1117
From this commit, I can see that the code was intentionally changed to wait for DBCKEND instead of DATAEND. It seems to reflect a deliberate design choice, but I couldn’t find any documentation or reasoning behind this change.
Could you explain the rationale for preferring DBCKEND over DATAEND here? Also, has anyone observed similar behavior with IDMA and DBCKEND on STM32H7?
@Dirbaio I'd like to understand the background behind this change. Could you explain a bit? https://github.com/embassy-rs/embassy/commit/c8a4a4995844be1b61d1a1479a6009eeb69b1117
I'm experiencing the same issue with init_sd_card hanging on STM32L5, although I can't confirm if its related to the above DBCKEND change.
Edit: seeing same issue on STM32U5 as well.
I just worked my way through my pile of Nucleo board and discovered that all the sdmmc_v2 boards that I tried (L5, U5, H7) experienced this issue, the sdmmc_v1 board (F4) worked fine. Like mentioned above setting complete_datapath_transfer(false) resolves the issue.
Looking at the reference manual there are some possible preconditions for the DBCKEND flag to fire, I'm not sure how to verify if these are being set.
I pushed my local fix to #4809 if anyone else needs a potential workaround.
Unfortunately my fix above I don't think will work, as I just tried running in --release mode and I get nothing but CRC errors. But at least it doesn't hang anymore, so I guess its a step in the right direction.
I was experiencing the same issue, so I tried your fix on weact board with stm32h723 and it doesn't hang anymore in init_sd_card but for some strange reason following code doesn't print anything at all for me
let card = sdmmc.card().unwrap();
info!("{:#?}", Debug2Format(&card));
However I'm not getting any error both in debug and release mode, also it says that the sdmmc bus clock changes correctly
I spent a bunch of time in the reference manual today working on the fix for this. I believe the original hypothesis is correct in that DBCKEND is only used when IDMAEN=0, and DTHOLD/RWSTART are used. In other words, DBCKEND will only be set if you aren't using IDMA and are manually handling the filling/reading of transfer buffers. If using IDMA (which we are), then DATAENDis sufficient.
Hi, I had the same hanging problem with the init_sd_card function. I’ve updated the embassy crates to ff42c61dc6c0f870b4022aca52f3c45d992ae735 and it doesn’t hang anymore, but it always returns a Crc error (both in debug and release mode).
I’m quite new to firmware development so it might be something I’m doing wrong, but I’ve tried a bit everything I could find (fiddling with the clocks, reducing the distance between MCU and MicroSD board notably) and nothing seems to work (well, when I put the init frequency under 118kHz I get BadClock errors, but…I guess that’s expected?).
Is there something I can do to help diagnose the issue? In case it’s pertinent, I have a Nucleo-H753ZI (NUH753ZI$AT3).
There is however something weird. This is (part of) my initialization code:
pub async fn init(&mut self) -> Result<(), SdmmcError> {
info!("Initializing SD card");
Timer::after_secs(1).await;
debug!(
"SDMMC1 interrupt enabled: {}",
embassy_stm32::interrupt::SDMMC1.is_enabled()
);
debug!("Configured clock: {}", self.pins.sdmmc.clock().0);
trace!("init sd card hardware");
match self
.pins
.sdmmc
.init_sd_card(embassy_stm32::time::khz(400))
.await
{
Ok(_) => trace!("SD card hardware init succeeded"),
Err(e) => {
error!("SD card init failed: {:?}", defmt::Debug2Format(&e));
match self.pins.sdmmc.card() {
Ok(card) => warn!(
"still managed to get the card: {:?}",
defmt::Debug2Format(card)
),
Err(err) => warn!(
"couldn’t get the card either: {:?}",
defmt::Debug2Format(&err)
),
}
debug!("Configured clock: {}", self.pins.sdmmc.clock().0);
return Err(e);
}
}
todo!() // some other stuff
}
The init_sd_card always returns a Crc error, but…
[INFO ] Initializing SD card (firmware src/storage/sd_card.rs:34)
[DEBUG] SDMMC1 interrupt enabled: true (firmware src/storage/sd_card.rs:37)
[DEBUG] Configured clock: 400000 (firmware src/storage/sd_card.rs:41)
[TRACE] init sd card hardware (firmware src/storage/sd_card.rs:43)
[ERROR] SD card init failed: "Crc" (firmware src/storage/sd_card.rs:52)
[WARN ] still managed to get the card: "SdCard(Card { card_type: HighCapacity, ocr: OCR: Operation Conditions Register { Voltage Window (mV): (2700, 3600), S18A (UHS-I only): true, Over 2TB flag (SDUC only): false, UHS-II Card: false, Card Capacity Status (CSS): \"SDHC/SDXC/SDUC\", Busy: false }, rca: 43690, cid: CID: Card Identification { Manufacturer ID: 3, OEM ID: \"SD\", Product Name: \"SA32G\", Product Revision: 128, Product Serial Number: 3074332934, Manufacturing Date: (3, 2025) }, csd: CSD: Card Specific Data { Transfer Rate: 50, Block Count: 62333952, Card Size (bytes): 31914983424, Read I (@min VDD): 35 mA, Write I (@min VDD): 35 mA, Read I (@max VDD): 80 mA, Write I (@max VDD): 10 mA, Erase Size (Blocks): 1 }, scr: SCR: SD CARD Configuration Register { Version: Unknown, 1-bit width: false, 4-bit width: true }, status: SD Status { Bus Width: One, Secured Mode: false, SD Memory Card Type: 0, Protected Area Size (B): 0, Speed Class: 0, Video Speed Class: 0, Application Performance Class: 0, Move Performance (MB/s): 0, AU Size: 0, Erase Size (units of AU): 0, Erase Timeout (s): 0, Discard Support: false } })" (firmware src/storage/sd_card.rs:54)
[DEBUG] Configured clock: 396825 (firmware src/storage/sd_card.rs:63)
The clock changes but more importantly, I’m able to retrieve the information on the card, which would mean that it was in fact initialized? I’m a bit confused…
In fact, it seems that if I ignore the Crc error returned by init_sd_card…read and writes work fine?
In fact, it seems that if I ignore the Crc error returned by init_sd_card…read and writes work fine?
That has been my experience as well, there is definitely some race condition and/or compiler optimization that is incorrectly happening. If you get lucky in the rolling of the dice on the compiler output (currently release works for me, but debug is a wildcard), then the crc error bit will never get set and everything works as expected. But when the crc error bit is set, it seems to be done by mistake, as everything is definitely working correctly.
If I add enough defmt log lines in the correct locations I normally can get it to work 100% of the time. But unfortunately that's not the correct solution to this problem.