mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
stm32/sdmmc: misc improvements
This commit is contained in:
parent
3127e1c50b
commit
c8a4a49958
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user