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