mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 14:44:32 +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> {
|
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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user