scaffold eMMC support

This commit is contained in:
Anton Lazarev 2025-03-25 06:29:16 -07:00
parent 14bb4ee9e4
commit 5325f1d911
No known key found for this signature in database
GPG Key ID: FBD20243E0CD9104

View File

@ -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<EMMC>,
/// Relative Card Address
pub rca: u16,
/// Card ID
pub cid: CID<EMMC>,
/// Card Specific Data
pub csd: CSD<EMMC>,
/// 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>,
card: Option<SdmmcPeripheral>,
/// 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<Signalling, Error> {
// 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::<T>::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<CardStatus<SD>, Error> {
fn read_status<Ext>(&self, card: &SdmmcPeripheral) -> Result<CardStatus<Ext>, Error>
where
CardStatus<Ext>: From<u32>,
{
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::<T>::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<u16>) -> 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::<T>::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<R: Resp>(cmd: Cmd<R>, 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::<T>::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::<T>::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::<EMMC>(card)?.ready_for_data(),
SdmmcPeripheral::SdCard(_) => self.read_status::<SD>(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::<SD>(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<Signalling, Error> {
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::<T>::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::<T>::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::<T>::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
}
}