diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4d0555d4a..d15ac4823 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,7 @@ cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } rand_core = "0.6.3" -sdio-host = "0.5.0" +sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b4e61878c..d965d8732 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1056,7 +1056,7 @@ fn main() { (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), - (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), + (("sdmmc", "D7"), quote!(crate::sdmmc::D7Pin)), (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 8f3c45f50..63868e5ae 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -10,7 +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::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; +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::{emmc_cmd, sd_cmd, Cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -136,10 +139,14 @@ pub enum Error { UnsupportedCardVersion, /// Unsupported card type. UnsupportedCardType, + /// Unsupported voltage. + UnsupportedVoltage, /// CRC error. Crc, /// No card inserted. NoCard, + /// 8-lane buses are not supported for SD cards. + BusWidth, /// Bad clock supplied to the SDMMC peripheral. BadClock, /// Signaling switch failed. @@ -149,38 +156,40 @@ pub enum Error { StBitErr, } -/// A SD command -struct Cmd { - cmd: u8, - arg: u32, - resp: Response, -} - #[derive(Clone, Copy, Debug, Default)] /// SD Card pub struct Card { /// The type of this card pub card_type: CardCapacity, /// Operation Conditions Register - pub ocr: OCR, + pub ocr: OCR, /// Relative Card Address - pub rca: u32, + pub rca: u16, /// Card ID - pub cid: CID, + pub cid: CID, /// Card Specific Data - pub csd: CSD, + pub csd: CSD, /// SD CARD Configuration Register pub scr: SCR, /// SD Status 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)] @@ -189,22 +198,12 @@ enum PowerCtrl { On = 0b11, } -#[repr(u32)] -#[allow(dead_code)] -#[allow(non_camel_case_types)] -enum CmdAppOper { - VOLTAGE_WINDOW_SD = 0x8010_0000, - HIGH_CAPACITY = 0x4000_0000, - SDMMC_STD_CAPACITY = 0x0000_0000, - SDMMC_CHECK_PATTERN = 0x0000_01AA, - SD_SWITCH_1_8V_CAPACITY = 0x0100_0000, -} - -#[derive(Eq, PartialEq, Copy, Clone)] -enum Response { - None = 0, - Short = 1, - Long = 3, +fn get_waitresp_val(rlen: ResponseLen) -> u8 { + match rlen { + common_cmd::ResponseLen::Zero => 0, + common_cmd::ResponseLen::R48 => 1, + common_cmd::ResponseLen::R136 => 3, + } } /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to @@ -301,6 +300,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>, @@ -313,6 +367,10 @@ pub struct Sdmmc<'d, T: Instance> { d1: Option>, d2: Option>, d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, config: Config, /// Current clock to card @@ -320,7 +378,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 @@ -361,6 +419,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { None, None, None, + None, + None, + None, + None, config, ) } @@ -396,6 +458,60 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Some(d1.into()), Some(d2.into()), Some(d3.into()), + None, + None, + None, + None, + config, + ) + } +} + +#[cfg(sdmmc_v1)] +impl<'d, T: Instance> Sdmmc<'d, T> { + /// Create a new SDMMC driver, with 8 data lanes. + pub fn new_8bit( + sdmmc: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + dma: Peri<'d, impl SdmmcDma>, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + config: Config, + ) -> Self { + critical_section::with(|_| { + clk.set_as_af(clk.af_num(), CLK_AF); + cmd.set_as_af(cmd.af_num(), CMD_AF); + d0.set_as_af(d0.af_num(), DATA_AF); + d1.set_as_af(d1.af_num(), DATA_AF); + d2.set_as_af(d2.af_num(), DATA_AF); + d3.set_as_af(d3.af_num(), DATA_AF); + d4.set_as_af(d4.af_num(), DATA_AF); + d5.set_as_af(d5.af_num(), DATA_AF); + d6.set_as_af(d6.af_num(), DATA_AF); + d7.set_as_af(d7.af_num(), DATA_AF); + }); + + Self::new_inner( + sdmmc, + new_dma_nonopt!(dma), + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), + Some(d4.into()), + Some(d5.into()), + Some(d6.into()), + Some(d7.into()), config, ) } @@ -418,7 +534,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d0.set_as_af(d0.af_num(), DATA_AF); }); - Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config) + Self::new_inner( + sdmmc, + clk.into(), + cmd.into(), + d0.into(), + None, + None, + None, + None, + None, + None, + None, + config, + ) } /// Create a new SDMMC driver, with 4 data lanes. @@ -450,6 +579,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Some(d1.into()), Some(d2.into()), Some(d3.into()), + None, + None, + None, + None, + config, + ) + } +} + +#[cfg(sdmmc_v2)] +impl<'d, T: Instance> Sdmmc<'d, T> { + /// Create a new SDMMC driver, with 8 data lanes. + pub fn new_8bit( + sdmmc: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + config: Config, + ) -> Self { + critical_section::with(|_| { + clk.set_as_af(clk.af_num(), CLK_AF); + cmd.set_as_af(cmd.af_num(), CMD_AF); + d0.set_as_af(d0.af_num(), DATA_AF); + d1.set_as_af(d1.af_num(), DATA_AF); + d2.set_as_af(d2.af_num(), DATA_AF); + d3.set_as_af(d3.af_num(), DATA_AF); + d4.set_as_af(d4.af_num(), DATA_AF); + d5.set_as_af(d5.af_num(), DATA_AF); + d6.set_as_af(d6.af_num(), DATA_AF); + d7.set_as_af(d7.af_num(), DATA_AF); + }); + + Self::new_inner( + sdmmc, + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), + Some(d4.into()), + Some(d5.into()), + Some(d6.into()), + Some(d7.into()), config, ) } @@ -465,6 +646,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d1: Option>, d2: Option>, d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, config: Config, ) -> Self { rcc::enable_and_reset::(); @@ -503,6 +688,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d1, d2, d3, + d4, + d5, + d6, + d7, config, clock: SD_INIT_FREQ, @@ -673,182 +862,29 @@ 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(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 { + 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(Cmd::card_status(rca << 16), false)?; // CMD13 + Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 let r1 = regs.respr(0).read().cardstatus(); 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(Cmd::set_block_length(64), false)?; // CMD16 - Self::cmd(Cmd::app_cmd(rca << 16), 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(Cmd::card_status(0), 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 << 16).unwrap_or(0); + let rca = rca.unwrap_or(0); - let r = Self::cmd(Cmd::sel_desel_card(rca), false); + let r = Self::cmd(common_cmd::select_card(rca), false); match (r, rca) { (Err(Error::Timeout), 0) => Ok(()), _ => r, @@ -889,70 +925,9 @@ 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(Cmd::set_block_length(8), false)?; // CMD16 - Self::cmd(Cmd::app_cmd(card.rca << 16), 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(Cmd::cmd51(), 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> { + fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { let regs = T::regs(); Self::clear_interrupt_flags(); @@ -965,7 +940,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Command index and start CP State Machine regs.cmdr().write(|w| { w.set_waitint(false); - w.set_waitresp(cmd.resp as u8); + w.set_waitresp(get_waitresp_val(cmd.response_len())); w.set_cmdindex(cmd.cmd); w.set_cpsmen(true); @@ -980,7 +955,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); let mut status; - if cmd.resp == Response::None { + if cmd.response_len() == ResponseLen::Zero { // Wait for CMDSENT or a timeout while { status = regs.star().read(); @@ -1016,7 +991,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Command index and start CP State Machine regs.cmdr().write(|w| { w.set_waitint(false); - w.set_waitresp(Response::Short as u8); + w.set_waitresp(get_waitresp_val(ResponseLen::R48)); w.set_cmdindex(12); w.set_cpsmen(true); @@ -1035,182 +1010,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::stop_datapath(); } - /// 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(); - let ker_ck = T::frequency(); - - let bus_width = match self.d3.is_some() { - true => BusWidth::Four, - false => BusWidth::One, - }; - - // While the SD/SDIO card or eMMC is in identification mode, - // the SDMMC_CK frequency must be no more than 400 kHz. - let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); - self.clock = init_clock; - - // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); - - regs.clkcr().modify(|w| { - w.set_widbus(0); - w.set_clkdiv(clkdiv); - #[cfg(sdmmc_v1)] - w.set_bypass(_bypass); - }); - - regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); - Self::cmd(Cmd::idle(), false)?; - - // Check if cards supports CMD8 (with pattern) - Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; - let r1 = regs.respr(0).read().cardstatus(); - - let mut card = if r1 == 0x1AA { - // Card echoed back the pattern. Must be at least v2 - Card::default() - } else { - return Err(Error::UnsupportedCardVersion); - }; - - let ocr = loop { - // Signal that next command is a app command - Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 - - let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 - | CmdAppOper::HIGH_CAPACITY as u32 - | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; - - // Initialize card - match Self::cmd(Cmd::app_op_cmd(arg), false) { - // ACMD41 - Ok(_) => (), - Err(Error::Crc) => (), - Err(err) => return Err(err), - } - let ocr: OCR = regs.respr(0).read().cardstatus().into(); - if !ocr.is_busy() { - // Power up done - break ocr; - } - }; - - if ocr.high_capacity() { - // Card is SDHC or SDXC or SDUC - card.card_type = CardCapacity::SDHC; - } else { - card.card_type = CardCapacity::SDSC; - } - card.ocr = ocr; - - Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 - let cid0 = regs.respr(0).read().cardstatus() as u128; - let cid1 = regs.respr(1).read().cardstatus() as u128; - let cid2 = regs.respr(2).read().cardstatus() as u128; - let cid3 = regs.respr(3).read().cardstatus() as u128; - let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); - card.cid = cid.into(); - - Self::cmd(Cmd::send_rel_addr(), false)?; - card.rca = regs.respr(0).read().cardstatus() >> 16; - - Self::cmd(Cmd::send_csd(card.rca << 16), false)?; - let csd0 = regs.respr(0).read().cardstatus() as u128; - let csd1 = regs.respr(1).read().cardstatus() as u128; - let csd2 = regs.respr(2).read().cardstatus() as u128; - let csd3 = regs.respr(3).read().cardstatus() as u128; - let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); - card.csd = csd.into(); - - self.select_card(Some(&card))?; - - self.get_scr(&mut card).await?; - - // Set bus width - let (width, acmd_arg) = match bus_width { - BusWidth::Eight => unimplemented!(), - BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), - _ => (BusWidth::One, 0), - }; - Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; - Self::cmd(Cmd::cmd6(acmd_arg), false)?; - - // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); - - regs.clkcr().modify(|w| { - w.set_widbus(match width { - BusWidth::One => 0, - BusWidth::Four => 1, - BusWidth::Eight => 2, - _ => panic!("Invalid Bus Width"), - }) - }); - - // Set Clock - if freq.0 <= 25_000_000 { - // Final clock frequency - self.clkcr_set_clkdiv(freq.0, width)?; - } else { - // Switch to max clock for SDR12 - self.clkcr_set_clkdiv(25_000_000, width)?; - } - - self.card = Some(card); - - // Read status - self.read_sd_status().await?; - - if freq.0 > 25_000_000 { - // Switch to SDR25 - self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; - - if self.signalling == Signalling::SDR25 { - // Set final clock frequency - self.clkcr_set_clkdiv(freq.0, width)?; - - if self.read_status(&card)?.state() != CurrentState::Transfer { - return Err(Error::SignalingSwitchFailed); - } - } - } - - // Read status after signalling change - self.read_sd_status().await?; - - Ok(()) - } - - /// Read a data block. + /// Wait for a previously started datapath transfer to complete from an interrupt. #[inline] - pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { - let card_capacity = self.card()?.card_type; - - // 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::SDSC => block_idx * 512, - _ => block_idx, - }; - Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 - + async fn complete_datapath_transfer() -> Result<(), Error> { 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(Cmd::read_single_block(address), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1232,8 +1035,43 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Poll::Pending }) .await; + Self::clear_interrupt_flags(); + res + } + + /// 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 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 = Self::complete_datapath_transfer().await; + if res.is_ok() { on_drop.defuse(); Self::stop_datapath(); @@ -1251,46 +1089,25 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // 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::SDSC => block_idx * 512, + let address = match card.get_capacity() { + CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(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()); // sdmmc_v1 uses different cmd/dma order than v2, but only for writes #[cfg(sdmmc_v1)] - Self::cmd(Cmd::write_single_block(address), true)?; + 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(Cmd::write_single_block(address), true)?; + 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(); + let res = Self::complete_datapath_transfer().await; match res { Ok(_) => { @@ -1301,12 +1118,15 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // TODO: Make this configurable let mut timeout: u32 = 0x00FF_FFFF; - // Try to read card status (ACMD13) + let card = self.card.as_ref().unwrap(); while timeout > 0 { - match self.read_sd_status().await { - Ok(_) => return Ok(()), - Err(Error::Timeout) => (), // Try again - Err(e) => return Err(e), + 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; } @@ -1320,10 +1140,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// /// # Errors /// - /// Returns Error::NoCard if [`init_card`](#method.init_card) - /// has not previously succeeded + /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or + /// [`init_emmc`](#method.init_emmc) has not previously succeeded #[inline] - pub fn card(&self) -> Result<&Card, Error> { + pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { self.card.as_ref().ok_or(Error::NoCard) } @@ -1339,6 +1159,457 @@ impl<'d, T: Instance> Sdmmc<'d, T> { pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { self.cmd_block = Some(cmd_block) } + + async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { + let regs = T::regs(); + let ker_ck = T::frequency(); + + let bus_width = match (self.d3.is_some(), self.d7.is_some()) { + (true, true) => { + if matches!(card, SdmmcPeripheral::SdCard(_)) { + return Err(Error::BusWidth); + } + BusWidth::Eight + } + (true, false) => BusWidth::Four, + _ => BusWidth::One, + }; + + // While the SD/SDIO card or eMMC is in identification mode, + // the SDMMC_CK frequency must be no more than 400 kHz. + let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); + self.clock = init_clock; + + // CPSMACT and DPSMACT must be 0 to set WIDBUS + Self::wait_idle(); + + regs.clkcr().modify(|w| { + w.set_widbus(0); + w.set_clkdiv(clkdiv); + #[cfg(sdmmc_v1)] + w.set_bypass(_bypass); + }); + + regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); + Self::cmd(common_cmd::idle(), false)?; + + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + // Check if cards supports CMD8 (with pattern) + Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; + let cic = CIC::from(regs.respr(0).read().cardstatus()); + + if cic.pattern() != 0xAA { + return Err(Error::UnsupportedCardVersion); + } + + if cic.voltage_accepted() & 1 == 0 { + return Err(Error::UnsupportedVoltage); + } + + let ocr = loop { + // Signal that next command is a app command + Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 + + // 3.2-3.3V + let voltage_window = 1 << 5; + // Initialize card + match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { + // ACMD41 + Ok(_) => (), + Err(Error::Crc) => (), + Err(err) => return Err(err), + } + let ocr: OCR = regs.respr(0).read().cardstatus().into(); + if !ocr.is_busy() { + // Power up done + break ocr; + } + }; + + if ocr.high_capacity() { + // Card is SDHC or SDXC or SDUC + card.card_type = CardCapacity::HighCapacity; + } else { + card.card_type = CardCapacity::StandardCapacity; + } + card.ocr = ocr; + } + SdmmcPeripheral::Emmc(ref mut emmc) => { + let ocr = loop { + let high_voltage = 0b0 << 7; + let access_mode = 0b10 << 29; + let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; + // Initialize card + match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { + Ok(_) => (), + Err(Error::Crc) => (), + Err(err) => return Err(err), + } + let ocr: OCR = regs.respr(0).read().cardstatus().into(); + if !ocr.is_busy() { + // Power up done + break ocr; + } + }; + + emmc.capacity = if ocr.access_mode() == 0b10 { + // Card is SDHC or SDXC or SDUC + CardCapacity::HighCapacity + } else { + CardCapacity::StandardCapacity + }; + emmc.ocr = ocr; + } + } + + Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 + let cid0 = regs.respr(0).read().cardstatus() as u128; + let cid1 = regs.respr(1).read().cardstatus() as u128; + let cid2 = regs.respr(2).read().cardstatus() as u128; + let cid3 = regs.respr(3).read().cardstatus() as u128; + let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); + + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + card.cid = cid.into(); + + Self::cmd(sd_cmd::send_relative_address(), false)?; + let rca = RCA::::from(regs.respr(0).read().cardstatus()); + card.rca = rca.address(); + } + SdmmcPeripheral::Emmc(ref mut emmc) => { + emmc.cid = cid.into(); + + emmc.rca = 1u16.into(); + Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; + } + } + + Self::cmd(common_cmd::send_csd(card.get_address()), false)?; + let csd0 = regs.respr(0).read().cardstatus() as u128; + let csd1 = regs.respr(1).read().cardstatus() as u128; + let csd2 = regs.respr(2).read().cardstatus() as u128; + let csd3 = regs.respr(3).read().cardstatus() as u128; + let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); + + self.select_card(Some(card.get_address()))?; + + let bus_width = match card { + SdmmcPeripheral::SdCard(ref mut card) => { + card.csd = csd.into(); + + self.get_scr(card).await?; + + if !card.scr.bus_width_four() { + BusWidth::One + } else { + BusWidth::Four + } + } + SdmmcPeripheral::Emmc(ref mut emmc) => { + emmc.csd = csd.into(); + + bus_width + } + }; + + // Set bus width + let widbus = match bus_width { + BusWidth::Eight => 2, + BusWidth::Four => 1, + BusWidth::One => 0, + _ => unreachable!(), + }; + + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + let acmd_arg = match bus_width { + BusWidth::Four if card.scr.bus_width_four() => 2, + _ => 0, + }; + Self::cmd(common_cmd::app_cmd(card.rca), false)?; + Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; + } + SdmmcPeripheral::Emmc(_) => { + // Write bus width to ExtCSD byte 183 + Self::cmd( + emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), + false, + )?; + + // Wait for ready after R1b response + loop { + let status = self.read_status::(&card)?; + + if status.ready_for_data() { + break; + } + } + } + } + + // CPSMACT and DPSMACT must be 0 to set WIDBUS + Self::wait_idle(); + + regs.clkcr().modify(|w| w.set_widbus(widbus)); + + // Set Clock + if freq.0 <= 25_000_000 { + // Final clock frequency + self.clkcr_set_clkdiv(freq.0, bus_width)?; + } else { + // Switch to max clock for SDR12 + self.clkcr_set_clkdiv(25_000_000, bus_width)?; + } + + self.card = Some(card); + + match card { + SdmmcPeripheral::SdCard(_) => { + // Read status + self.read_sd_status().await?; + + if freq.0 > 25_000_000 { + // Switch to SDR25 + self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; + + if self.signalling == Signalling::SDR25 { + // Set final clock frequency + self.clkcr_set_clkdiv(freq.0, bus_width)?; + + if self.read_status::(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { + return Err(Error::SignalingSwitchFailed); + } + } + } + + // Read status after signalling change + self.read_sd_status().await?; + } + SdmmcPeripheral::Emmc(_) => { + self.read_ext_csd().await?; + } + } + + Ok(()) + } + + /// Initializes card (if present) and sets the bus at the specified frequency. + /// + /// SD only. + pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { + self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await + } + + /// 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" + + 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 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 = Self::complete_datapath_transfer().await; + + // 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 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 = Self::complete_datapath_transfer().await; + + 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 + } + + /// 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; + + 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 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 = Self::complete_datapath_transfer().await; + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + for byte in status.iter_mut() { + *byte = u32::from_be(*byte); + } + card.status = status.0.into(); + } + res + } + + /// Initializes eMMC and sets the bus at the specified frequency. + /// + /// eMMC only. + pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { + self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await + } + + /// Gets the EXT_CSD register. + /// + /// eMMC only. + async fn read_ext_csd(&mut self) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc(); + + // Note: cmd_block can't be used because ExtCSD is too long to fit. + let mut data_block = DataBlock([0u8; 512]); + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; + + Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 + + // Arm `OnDrop` after the buffer, so it will be dropped first + 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(emmc_cmd::send_ext_csd(), true)?; + + let res = Self::complete_datapath_transfer().await; + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); + } + res + } } impl<'d, T: Instance> Drop for Sdmmc<'d, T> { @@ -1359,97 +1630,22 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { if let Some(x) = &mut self.d3 { x.set_as_disconnected(); } + if let Some(x) = &mut self.d4 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d5 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d6 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d7 { + x.set_as_disconnected(); + } }); } } -/// SD card Commands -impl Cmd { - const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd { - Cmd { cmd, arg, resp } - } - - /// CMD0: Idle - const fn idle() -> Cmd { - Cmd::new(0, 0, Response::None) - } - - /// CMD2: Send CID - const fn all_send_cid() -> Cmd { - Cmd::new(2, 0, Response::Long) - } - - /// CMD3: Send Relative Address - const fn send_rel_addr() -> Cmd { - Cmd::new(3, 0, Response::Short) - } - - /// CMD6: Switch Function Command - /// ACMD6: Bus Width - const fn cmd6(arg: u32) -> Cmd { - Cmd::new(6, arg, Response::Short) - } - - /// CMD7: Select one card and put it into the _Tranfer State_ - const fn sel_desel_card(rca: u32) -> Cmd { - Cmd::new(7, rca, Response::Short) - } - - /// CMD8: - const fn hs_send_ext_csd(arg: u32) -> Cmd { - Cmd::new(8, arg, Response::Short) - } - - /// CMD9: - const fn send_csd(rca: u32) -> Cmd { - Cmd::new(9, rca, Response::Long) - } - - /// CMD12: - //const fn stop_transmission() -> Cmd { - // Cmd::new(12, 0, Response::Short) - //} - - /// CMD13: Ask card to send status register - /// ACMD13: SD Status - const fn card_status(rca: u32) -> Cmd { - Cmd::new(13, rca, Response::Short) - } - - /// CMD16: - const fn set_block_length(blocklen: u32) -> Cmd { - Cmd::new(16, blocklen, Response::Short) - } - - /// CMD17: Block Read - const fn read_single_block(addr: u32) -> Cmd { - Cmd::new(17, addr, Response::Short) - } - - /// CMD18: Multiple Block Read - //const fn read_multiple_blocks(addr: u32) -> Cmd { - // Cmd::new(18, addr, Response::Short) - //} - - /// CMD24: Block Write - const fn write_single_block(addr: u32) -> Cmd { - Cmd::new(24, addr, Response::Short) - } - - const fn app_op_cmd(arg: u32) -> Cmd { - Cmd::new(41, arg, Response::Short) - } - - const fn cmd51() -> Cmd { - Cmd::new(51, 0, Response::Short) - } - - /// App Command. Indicates that next command will be a app command - const fn app_cmd(rca: u32) -> Cmd { - Cmd::new(55, rca, Response::Short) - } -} - ////////////////////////////////////////////////////// trait SealedInstance { diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 66e4e527c..e97b63925 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match sdmmc.init_card(mhz(24)).await { + match sdmmc.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) { diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 6d36ef518..787bef25e 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_card(mhz(25)).await); + unwrap!(sdmmc.init_sd_card(mhz(25)).await); let card = unwrap!(sdmmc.card()); diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index abe2d4ba7..96840d8ff 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) -> ! { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_card(mhz(25)).await); + unwrap!(sdmmc.init_sd_card(mhz(25)).await); let card = unwrap!(sdmmc.card()); diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index 07f17b569..c1ed45588 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match s.init_card(mhz(24)).await { + match s.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) { @@ -100,7 +100,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match s.init_card(mhz(24)).await { + match s.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) {