stm32/sdmmc: misc improvements

This commit is contained in:
Dario Nieuwenhuis 2025-07-04 00:25:00 +02:00
parent 3127e1c50b
commit c8a4a49958

View File

@ -32,25 +32,48 @@ pub struct InterruptHandler<T: Instance> {
}
impl<T: Instance> InterruptHandler<T> {
fn data_interrupts(enable: bool) {
fn enable_interrupts() {
let regs = T::regs();
regs.maskr().write(|w| {
w.set_dcrcfailie(enable);
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
w.set_dcrcfailie(true);
w.set_dtimeoutie(true);
w.set_dataendie(true);
w.set_dbckendie(true);
#[cfg(sdmmc_v1)]
w.set_stbiterre(enable);
w.set_stbiterre(true);
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
w.set_dabortie(true);
});
}
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
Self::data_interrupts(false);
T::state().wake();
let status = T::regs().star().read();
T::regs().maskr().modify(|w| {
if status.dcrcfail() {
w.set_dcrcfailie(false)
}
if status.dtimeout() {
w.set_dtimeoutie(false)
}
if status.dataend() {
w.set_dataendie(false)
}
if status.dbckend() {
w.set_dbckendie(false)
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
w.set_stbiterre(false)
}
#[cfg(sdmmc_v2)]
if status.dabort() {
w.set_dabortie(false)
}
});
}
}
@ -1002,14 +1025,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
// Wait for the abort
while Self::data_active() {}
}
InterruptHandler::<T>::data_interrupts(false);
regs.maskr().write(|_| ()); // disable irqs
Self::clear_interrupt_flags();
Self::stop_datapath();
}
/// Wait for a previously started datapath transfer to complete from an interrupt.
#[inline]
async fn complete_datapath_transfer() -> Result<(), Error> {
async fn complete_datapath_transfer(block: bool) -> Result<(), Error> {
let regs = T::regs();
let res = poll_fn(|cx| {
@ -1029,7 +1052,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
let done = match block {
true => status.dbckend(),
false => status.dataend(),
};
if done {
return Poll::Ready(Ok(()));
}
Poll::Pending
@ -1067,10 +1094,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
512,
9,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(common_cmd::read_single_block(address), true)?;
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
if res.is_ok() {
on_drop.defuse();
@ -1100,7 +1127,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
};
Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = Self::prepare_datapath_read(
@ -1111,30 +1137,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
512 * blocks.len() as u32,
9,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(common_cmd::read_multiple_blocks(address), true)?;
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
})
.await;
let res = Self::complete_datapath_transfer(false).await;
Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
Self::clear_interrupt_flags();
@ -1169,12 +1176,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
Self::cmd(common_cmd::write_single_block(address), true)?;
let transfer = self.prepare_datapath_write(buffer, 512, 9);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
#[cfg(sdmmc_v2)]
Self::cmd(common_cmd::write_single_block(address), true)?;
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
match res {
Ok(_) => {
@ -1225,7 +1232,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
let block_count = blocks.len();
let regs = T::regs();
let on_drop = OnDrop::new(|| Self::on_drop());
#[cfg(sdmmc_v1)]
@ -1233,36 +1239,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
// Setup write command
let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
#[cfg(sdmmc_v2)]
Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
}
if status.dtimeout() {
return Poll::Ready(Err(Error::Timeout));
}
if status.txunderr() {
return Poll::Ready(Err(Error::Underrun));
}
#[cfg(sdmmc_v1)]
if status.stbiterr() {
return Poll::Ready(Err(Error::StBitErr));
}
if status.dataend() {
return Poll::Ready(Ok(()));
}
Poll::Pending
})
.await;
let res = Self::complete_datapath_transfer(false).await;
Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12
Self::clear_interrupt_flags();
@ -1597,10 +1579,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
64,
6,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
// Host is allowed to use the new functions at least 8
// clocks after the end of the switch command
@ -1657,10 +1639,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
8,
3,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(sd_cmd::send_scr(), true)?;
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
if res.is_ok() {
on_drop.defuse();
@ -1703,10 +1685,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
64,
6,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(sd_cmd::sd_status(), true)?;
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
if res.is_ok() {
on_drop.defuse();
@ -1753,10 +1735,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
512,
9,
);
InterruptHandler::<T>::data_interrupts(true);
InterruptHandler::<T>::enable_interrupts();
Self::cmd(emmc_cmd::send_ext_csd(), true)?;
let res = Self::complete_datapath_transfer().await;
let res = Self::complete_datapath_transfer(true).await;
if res.is_ok() {
on_drop.defuse();