diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index a28fd51e8..6dbb524b7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -10,11 +10,10 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use sdio_host::{ - common_cmd::{self, Resp, ResponseLen}, - sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}, - sd_cmd, Cmd, -}; +use sdio_host::common_cmd::{self, Resp, ResponseLen}; +use sdio_host::emmc::{ExtCSD, EMMC}; +use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; +use sdio_host::{sd_cmd, Cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -174,12 +173,21 @@ pub struct Card { pub status: SDStatus, } -impl Card { - /// Size in bytes - pub fn size(&self) -> u64 { - // SDHC / SDXC / SDUC - u64::from(self.csd.block_count()) * 512 - } +#[derive(Clone, Copy, Debug, Default)] +/// eMMC storage +pub struct Emmc { + /// The capacity of this card + pub capacity: CardCapacity, + /// Operation Conditions Register + pub ocr: OCR, + /// Relative Card Address + pub rca: u16, + /// Card ID + pub cid: CID, + /// Card Specific Data + pub csd: CSD, + /// Extended Card Specific Data + pub ext_csd: ExtCSD, } #[repr(u8)] @@ -290,6 +298,61 @@ impl Default for Config { } } +/// Peripheral that can be operated over SDMMC +#[derive(Clone, Copy, Debug)] +pub enum SdmmcPeripheral { + /// SD Card + SdCard(Card), + /// eMMC memory + Emmc(Emmc), +} + +impl SdmmcPeripheral { + /// Get this peripheral's address on the SDMMC bus + fn get_address(&self) -> u16 { + match self { + Self::SdCard(c) => c.rca, + Self::Emmc(e) => e.rca, + } + } + /// Is this a standard or high capacity peripheral? + fn get_capacity(&self) -> CardCapacity { + match self { + Self::SdCard(c) => c.card_type, + Self::Emmc(e) => e.capacity, + } + } + /// Size in bytes + fn size(&self) -> u64 { + match self { + // SDHC / SDXC / SDUC + Self::SdCard(c) => u64::from(c.csd.block_count()) * 512, + // capacity > 2GB + Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512, + } + } + + /// Get a mutable reference to the SD Card. + /// + /// Panics if there is another peripheral instead. + fn get_sd_card(&mut self) -> &mut Card { + match *self { + Self::SdCard(ref mut c) => c, + _ => unreachable!("SD only"), + } + } + + /// Get a mutable reference to the eMMC. + /// + /// Panics if there is another peripheral instead. + fn get_emmc(&mut self) -> &mut Emmc { + match *self { + Self::Emmc(ref mut e) => e, + _ => unreachable!("eMMC only"), + } + } +} + /// Sdmmc device pub struct Sdmmc<'d, T: Instance> { _peri: Peri<'d, T>, @@ -309,7 +372,7 @@ pub struct Sdmmc<'d, T: Instance> { /// Current signalling scheme to card signalling: Signalling, /// Card - card: Option, + card: Option, /// An optional buffer to be used for commands /// This should be used if there are special memory location requirements for dma @@ -662,101 +725,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(()) } - /// Switch mode using CMD6. - /// - /// Attempt to set a new signalling mode. The selected - /// signalling mode is returned. Expects the current clock - /// frequency to be > 12.5MHz. - async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { - // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not - // necessary" - - let set_function = 0x8000_0000 - | match signalling { - // See PLSS v7_10 Table 4-11 - Signalling::DDR50 => 0xFF_FF04, - Signalling::SDR104 => 0xFF_1F03, - Signalling::SDR50 => 0xFF_1F02, - Signalling::SDR25 => 0xFF_FF01, - Signalling::SDR12 => 0xFF_FF00, - }; - - let status = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - status.as_mut(), - 64, - 6, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 - - 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; - Self::clear_interrupt_flags(); - - // Host is allowed to use the new functions at least 8 - // clocks after the end of the switch command - // transaction. We know the current clock period is < 80ns, - // so a total delay of 640ns is required here - for _ in 0..300 { - cortex_m::asm::nop(); - } - - match res { - Ok(_) => { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - // Function Selection of Function Group 1 - let selection = (u32::from_be(status[4]) >> 24) & 0xF; - - match selection { - 0 => Ok(Signalling::SDR12), - 1 => Ok(Signalling::SDR25), - 2 => Ok(Signalling::SDR50), - 3 => Ok(Signalling::SDR104), - 4 => Ok(Signalling::DDR50), - _ => Err(Error::UnsupportedCardType), - } - } - Err(e) => Err(e), - } - } - /// Query the card status (CMD13, returns R1) - fn read_status(&self, card: &Card) -> Result, Error> { + fn read_status(&self, card: &SdmmcPeripheral) -> Result, Error> + where + CardStatus: From, + { let regs = T::regs(); - let rca = card.rca; + let rca = card.get_address(); Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 @@ -764,78 +739,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(r1.into()) } - /// Reads the SD Status (ACMD13) - async fn read_sd_status(&mut self) -> Result<(), Error> { - let card = self.card.as_mut().ok_or(Error::NoCard)?; - let rca = card.rca; - - let cmd_block = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - - Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 - Self::cmd(common_cmd::app_cmd(rca), false)?; // APP - - let status = cmd_block; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - status.as_mut(), - 64, - 6, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::sd_status(), 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; - Self::clear_interrupt_flags(); - - if res.is_ok() { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - for byte in status.iter_mut() { - *byte = u32::from_be(*byte); - } - self.card.as_mut().unwrap().status = status.0.into(); - } - res - } - /// Select one card and place it into the _Tranfer State_ /// /// If `None` is specifed for `card`, all cards are put back into /// _Stand-by State_ - fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { + fn select_card(&self, rca: Option) -> Result<(), Error> { // Determine Relative Card Address (RCA) of given card - let rca = card.map(|c| c.rca).unwrap_or(0); + let rca = rca.unwrap_or(0); let r = Self::cmd(common_cmd::select_card(rca), false); match (r, rca) { @@ -878,67 +788,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); } - async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { - // Read the 64-bit SCR register - Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 - Self::cmd(common_cmd::app_cmd(card.rca), false)?; - - let cmd_block = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - let scr = &mut cmd_block.0[..2]; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - scr, - 8, - 3, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::send_scr(), 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; - Self::clear_interrupt_flags(); - - if res.is_ok() { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - unsafe { - let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); - card.scr = SCR(u64::from_be_bytes(*scr_bytes)); - } - } - res - } - /// Send command to card #[allow(unused_variables)] fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { @@ -1024,6 +873,170 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::stop_datapath(); } + /// Read a data block. + #[inline] + pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { + let card_capacity = self.card()?.get_capacity(); + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card_capacity { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + 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( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(common_cmd::read_single_block(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; + Self::clear_interrupt_flags(); + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + } + res + } + + /// Write a data block. + pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?; + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card.get_capacity() { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + // sdmmc_v1 uses different cmd/dma order than v2, but only for writes + #[cfg(sdmmc_v1)] + Self::cmd(common_cmd::write_single_block(address), true)?; + + let transfer = self.prepare_datapath_write(buffer, 512, 9); + InterruptHandler::::data_interrupts(true); + + #[cfg(sdmmc_v2)] + Self::cmd(common_cmd::write_single_block(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; + Self::clear_interrupt_flags(); + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // TODO: Make this configurable + let mut timeout: u32 = 0x00FF_FFFF; + + let card = self.card.as_ref().unwrap(); + while timeout > 0 { + let ready_for_data = match card { + SdmmcPeripheral::Emmc(_) => self.read_status::(card)?.ready_for_data(), + SdmmcPeripheral::SdCard(_) => self.read_status::(card)?.ready_for_data(), + }; + + if ready_for_data { + return Ok(()); + } + timeout -= 1; + } + Err(Error::SoftwareTimeout) + } + Err(e) => Err(e), + } + } + + /// Get a reference to the initialized card + /// + /// # Errors + /// + /// Returns Error::NoCard if [`init_card`](#method.init_card) + /// has not previously succeeded + #[inline] + pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { + self.card.as_ref().ok_or(Error::NoCard) + } + + /// Get the current SDMMC bus clock + pub fn clock(&self) -> Hertz { + self.clock + } + + /// Set a specific cmd buffer rather than using the default stack allocated one. + /// This is required if stack RAM cannot be used with DMA and usually manifests + /// itself as an indefinite wait on a dma transfer because the dma peripheral + /// cannot access the memory. + pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { + self.cmd_block = Some(cmd_block) + } +} + +/// SD only +impl<'d, T: Instance> Sdmmc<'d, T> { /// Initializes card (if present) and sets the bus at the specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { let regs = T::regs(); @@ -1114,7 +1127,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); card.csd = csd.into(); - self.select_card(Some(&card))?; + self.select_card(Some(card.rca))?; self.get_scr(&mut card).await?; @@ -1148,7 +1161,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { self.clkcr_set_clkdiv(25_000_000, width)?; } - self.card = Some(card); + self.card = Some(SdmmcPeripheral::SdCard(card)); // Read status self.read_sd_status().await?; @@ -1161,7 +1174,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Set final clock frequency self.clkcr_set_clkdiv(freq.0, width)?; - if self.read_status(&card)?.state() != CurrentState::Transfer { + if self.read_status::(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { return Err(Error::SignalingSwitchFailed); } } @@ -1173,22 +1186,34 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(()) } - /// Read a data block. - #[inline] - pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { - let card_capacity = self.card()?.card_type; + /// Switch mode using CMD6. + /// + /// Attempt to set a new signalling mode. The selected + /// signalling mode is returned. Expects the current clock + /// frequency to be > 12.5MHz. + /// + /// SD only. + async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { + let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); + // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not + // necessary" - // NOTE(unsafe) DataBlock uses align 4 - let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; + let set_function = 0x8000_0000 + | match signalling { + // See PLSS v7_10 Table 4-11 + Signalling::DDR50 => 0xFF_FF04, + Signalling::SDR104 => 0xFF_1F03, + Signalling::SDR50 => 0xFF_1F02, + Signalling::SDR25 => 0xFF_FF01, + Signalling::SDR12 => 0xFF_FF00, + }; - // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes - let address = match card_capacity { - CardCapacity::StandardCapacity => block_idx * 512, - _ => block_idx, + let status = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); @@ -1196,12 +1221,93 @@ impl<'d, T: Instance> Sdmmc<'d, T> { &self.config, #[cfg(sdmmc_v1)] &mut self.dma, - buffer, - 512, - 9, + status.as_mut(), + 64, + 6, ); InterruptHandler::::data_interrupts(true); - Self::cmd(common_cmd::read_single_block(address), true)?; + Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 + + 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; + Self::clear_interrupt_flags(); + + // Host is allowed to use the new functions at least 8 + // clocks after the end of the switch command + // transaction. We know the current clock period is < 80ns, + // so a total delay of 640ns is required here + for _ in 0..300 { + cortex_m::asm::nop(); + } + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // Function Selection of Function Group 1 + let selection = (u32::from_be(status[4]) >> 24) & 0xF; + + match selection { + 0 => Ok(Signalling::SDR12), + 1 => Ok(Signalling::SDR25), + 2 => Ok(Signalling::SDR50), + 3 => Ok(Signalling::SDR104), + 4 => Ok(Signalling::DDR50), + _ => Err(Error::UnsupportedCardType), + } + } + Err(e) => Err(e), + } + } + + /// Reads the SCR register. + /// + /// SD only. + async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { + // Read the 64-bit SCR register + Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(card.rca), false)?; + + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), + }; + let scr = &mut cmd_block.0[..2]; + + // Arm `OnDrop` after the buffer, so it will be dropped first + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + scr, + 8, + 3, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(sd_cmd::send_scr(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1229,37 +1335,46 @@ impl<'d, T: Instance> Sdmmc<'d, T> { on_drop.defuse(); Self::stop_datapath(); drop(transfer); + + unsafe { + let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); + card.scr = SCR(u64::from_be_bytes(*scr_bytes)); + } } res } - /// Write a data block. - pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { - let card = self.card.as_mut().ok_or(Error::NoCard)?; + /// Reads the SD Status (ACMD13) + /// + /// SD only. + async fn read_sd_status(&mut self) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); + let rca = card.rca; - // NOTE(unsafe) DataBlock uses align 4 - let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; - - // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes - let address = match card.card_type { - CardCapacity::StandardCapacity => block_idx * 512, - _ => block_idx, + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(rca), false)?; // APP + + let status = cmd_block; + + // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - // sdmmc_v1 uses different cmd/dma order than v2, but only for writes - #[cfg(sdmmc_v1)] - Self::cmd(common_cmd::write_single_block(address), true)?; - - let transfer = self.prepare_datapath_write(buffer, 512, 9); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); - - #[cfg(sdmmc_v2)] - Self::cmd(common_cmd::write_single_block(address), true)?; + Self::cmd(sd_cmd::sd_status(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1283,52 +1398,17 @@ impl<'d, T: Instance> Sdmmc<'d, T> { .await; Self::clear_interrupt_flags(); - match res { - Ok(_) => { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); - // TODO: Make this configurable - let mut timeout: u32 = 0x00FF_FFFF; - - let card = self.card.as_ref().unwrap(); - while timeout > 0 { - let status = self.read_status(card)?; - - if status.ready_for_data() { - return Ok(()); - } - timeout -= 1; - } - Err(Error::SoftwareTimeout) + for byte in status.iter_mut() { + *byte = u32::from_be(*byte); } - Err(e) => Err(e), + card.status = status.0.into(); } - } - - /// Get a reference to the initialized card - /// - /// # Errors - /// - /// Returns Error::NoCard if [`init_card`](#method.init_card) - /// has not previously succeeded - #[inline] - pub fn card(&self) -> Result<&Card, Error> { - self.card.as_ref().ok_or(Error::NoCard) - } - - /// Get the current SDMMC bus clock - pub fn clock(&self) -> Hertz { - self.clock - } - - /// Set a specific cmd buffer rather than using the default stack allocated one. - /// This is required if stack RAM cannot be used with DMA and usually manifests - /// itself as an indefinite wait on a dma transfer because the dma peripheral - /// cannot access the memory. - pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { - self.cmd_block = Some(cmd_block) + res } }