From 7087ad7d45396e139fcbd710084db0d9dac7ecb8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 9 Dec 2025 09:34:50 -0600 Subject: type-erase sdmmc --- embassy-stm32/src/sdmmc/mod.rs | 394 ++++++++++++++++++++++------------------- 1 file changed, 212 insertions(+), 182 deletions(-) (limited to 'embassy-stm32') diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 37ef7099f..74a6f13fa 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -9,6 +9,7 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; +use embassy_sync::mutex::Mutex; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::common_cmd::{self, Resp, ResponseLen}; use sdio_host::emmc::{EMMC, ExtCSD}; @@ -22,7 +23,7 @@ use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::pac::sdmmc::Sdmmc as RegBlock; -use crate::rcc::{self, RccPeripheral}; +use crate::rcc::{self, RccInfo, RccPeripheral, SealedRccPeripheral}; use crate::time::Hertz; use crate::{interrupt, peripherals}; @@ -31,28 +32,11 @@ pub struct InterruptHandler { _phantom: PhantomData, } -impl InterruptHandler { - fn enable_interrupts() { - let regs = T::regs(); - regs.maskr().write(|w| { - w.set_dcrcfailie(true); - w.set_dtimeoutie(true); - w.set_dataendie(true); - w.set_dbckendie(true); - - #[cfg(sdmmc_v1)] - w.set_stbiterre(true); - #[cfg(sdmmc_v2)] - w.set_dabortie(true); - }); - } -} - impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - T::state().wake(); - let status = T::regs().star().read(); - T::regs().maskr().modify(|w| { + T::state().waker.wake(); + let status = T::info().regs.star().read(); + T::info().regs.maskr().modify(|w| { if status.dcrcfail() { w.set_dcrcfailie(false) } @@ -379,8 +363,10 @@ impl SdmmcPeripheral { } /// Sdmmc device -pub struct Sdmmc<'d, T: Instance> { - _peri: Peri<'d, T>, +pub struct Sdmmc<'d> { + info: &'static Info, + state: &'static State, + ker_clk: Hertz, #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, @@ -416,9 +402,9 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh const DATA_AF: AfType = CMD_AF; #[cfg(sdmmc_v1)] -impl<'d, T: Instance> Sdmmc<'d, T> { +impl<'d> Sdmmc<'d> { /// Create a new SDMMC driver, with 1 data lane. - pub fn new_1bit( + pub fn new_1bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, dma: Peri<'d, impl SdmmcDma>, @@ -451,7 +437,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } /// Create a new SDMMC driver, with 4 data lanes. - pub fn new_4bit( + pub fn new_4bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, dma: Peri<'d, impl SdmmcDma>, @@ -491,9 +477,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } #[cfg(sdmmc_v1)] -impl<'d, T: Instance> Sdmmc<'d, T> { +impl<'d> Sdmmc<'d> { /// Create a new SDMMC driver, with 8 data lanes. - pub fn new_8bit( + pub fn new_8bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, dma: Peri<'d, impl SdmmcDma>, @@ -541,9 +527,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } #[cfg(sdmmc_v2)] -impl<'d, T: Instance> Sdmmc<'d, T> { +impl<'d> Sdmmc<'d> { /// Create a new SDMMC driver, with 1 data lane. - pub fn new_1bit( + pub fn new_1bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, clk: Peri<'d, impl CkPin>, @@ -574,7 +560,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } /// Create a new SDMMC driver, with 4 data lanes. - pub fn new_4bit( + pub fn new_4bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, clk: Peri<'d, impl CkPin>, @@ -612,9 +598,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } #[cfg(sdmmc_v2)] -impl<'d, T: Instance> Sdmmc<'d, T> { +impl<'d> Sdmmc<'d> { /// Create a new SDMMC driver, with 8 data lanes. - pub fn new_8bit( + pub fn new_8bit( sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, clk: Peri<'d, impl CkPin>, @@ -659,9 +645,24 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } } -impl<'d, T: Instance> Sdmmc<'d, T> { - fn new_inner( - sdmmc: Peri<'d, T>, +impl<'d> Sdmmc<'d> { + fn enable_interrupts(&self) { + let regs = self.info.regs; + regs.maskr().write(|w| { + w.set_dcrcfailie(true); + w.set_dtimeoutie(true); + w.set_dataendie(true); + w.set_dbckendie(true); + + #[cfg(sdmmc_v1)] + w.set_stbiterre(true); + #[cfg(sdmmc_v2)] + w.set_dabortie(true); + }); + } + + fn new_inner( + _sdmmc: Peri<'d, T>, #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, clk: Peri<'d, AnyPin>, cmd: Peri<'d, AnyPin>, @@ -680,8 +681,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - let regs = T::regs(); - regs.clkcr().write(|w| { + let info = T::info(); + let state = T::state(); + let ker_clk = T::frequency(); + + info.regs.clkcr().write(|w| { w.set_pwrsav(false); w.set_negedge(false); @@ -698,10 +702,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Power off, writen 00: Clock to the card is stopped; // D[7:0], CMD, and CK are driven high. - regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); + info.regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); Self { - _peri: sdmmc, + info, + state, + ker_clk, #[cfg(sdmmc_v1)] dma, @@ -726,8 +732,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Data transfer is in progress #[inline] - fn data_active() -> bool { - let regs = T::regs(); + fn data_active(&self) -> bool { + let regs = self.info.regs; let status = regs.star().read(); #[cfg(sdmmc_v1)] @@ -738,8 +744,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Coammand transfer is in progress #[inline] - fn cmd_active() -> bool { - let regs = T::regs(); + fn cmd_active(&self) -> bool { + let regs = self.info.regs; let status = regs.star().read(); #[cfg(sdmmc_v1)] @@ -750,8 +756,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) #[inline] - fn wait_idle() { - while Self::data_active() || Self::cmd_active() {} + fn wait_idle(&self) { + while self.data_active() || self.cmd_active() {} } /// # Safety @@ -759,6 +765,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// `buffer` must be valid for the whole transfer and word aligned #[allow(unused_variables)] fn prepare_datapath_read<'a>( + &self, config: &Config, #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, buffer: &'a mut [u32], @@ -766,11 +773,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { block_size: u8, ) -> Transfer<'a> { assert!(block_size <= 14, "Block size up to 2^14 bytes"); - let regs = T::regs(); + let regs = self.info.regs; // Command AND Data state machines must be idle - Self::wait_idle(); - Self::clear_interrupt_flags(); + self.wait_idle(); + self.clear_interrupt_flags(); regs.dlenr().write(|w| w.set_datalength(length_bytes)); @@ -801,13 +808,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// # Safety /// /// `buffer` must be valid for the whole transfer and word aligned - fn prepare_datapath_write<'a>(&'a mut self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { + fn prepare_datapath_write<'a>(&self, buffer: &'a [u32], length_bytes: u32, block_size: u8) -> Transfer<'a> { assert!(block_size <= 14, "Block size up to 2^14 bytes"); - let regs = T::regs(); + let regs = self.info.regs; // Command AND Data state machines must be idle - Self::wait_idle(); - Self::clear_interrupt_flags(); + self.wait_idle(); + self.clear_interrupt_flags(); regs.dlenr().write(|w| w.set_datalength(length_bytes)); @@ -839,8 +846,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } /// Stops the DMA datapath - fn stop_datapath() { - let regs = T::regs(); + fn stop_datapath(&self) { + let regs = self.info.regs; #[cfg(sdmmc_v1)] regs.dctrl().modify(|w| { @@ -853,7 +860,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Sets the CLKDIV field in CLKCR. Updates clock field in self fn clkcr_set_clkdiv(&mut self, freq: u32, width: BusWidth) -> Result<(), Error> { - let regs = T::regs(); + let regs = self.info.regs; let width_u32 = match width { BusWidth::One => 1u32, @@ -862,17 +869,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { _ => panic!("Invalid Bus Width"), }; - let ker_ck = T::frequency(); - let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?; + let (_bypass, clkdiv, new_clock) = clk_div(self.ker_clk, freq)?; // Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7 // Section 55.5.8 let sdmmc_bus_bandwidth = new_clock.0 * width_u32; - assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32); + assert!(self.ker_clk.0 > 3 * sdmmc_bus_bandwidth / 32); self.clock = new_clock; // CPSMACT and DPSMACT must be 0 to set CLKDIV - Self::wait_idle(); + self.wait_idle(); regs.clkcr().modify(|w| { w.set_clkdiv(clkdiv); #[cfg(sdmmc_v1)] @@ -887,10 +893,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { where CardStatus: From, { - let regs = T::regs(); + let regs = self.info.regs; let rca = card.get_address(); - Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 + self.cmd(common_cmd::card_status(rca, false), false)?; // CMD13 let r1 = regs.respr(0).read().cardstatus(); Ok(r1.into()) @@ -904,7 +910,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Determine Relative Card Address (RCA) of given card let rca = rca.unwrap_or(0); - let r = Self::cmd(common_cmd::select_card(rca), false); + let r = self.cmd(common_cmd::select_card(rca), false); match (r, rca) { (Err(Error::Timeout), 0) => Ok(()), _ => r, @@ -913,8 +919,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Clear flags in interrupt clear register #[inline] - fn clear_interrupt_flags() { - let regs = T::regs(); + fn clear_interrupt_flags(&self) { + let regs = self.info.regs; regs.icr().write(|w| { w.set_ccrcfailc(true); w.set_dcrcfailc(true); @@ -947,12 +953,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Send command to card #[allow(unused_variables)] - fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { - let regs = T::regs(); + fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { + let regs = self.info.regs; - Self::clear_interrupt_flags(); + self.clear_interrupt_flags(); // CP state machine must be idle - while Self::cmd_active() {} + while self.cmd_active() {} // Command arg regs.argr().write(|w| w.set_cmdarg(cmd.arg)); @@ -997,13 +1003,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(()) } - fn on_drop() { - let regs = T::regs(); - if Self::data_active() { - Self::clear_interrupt_flags(); + fn on_drop(&self) { + let regs = self.info.regs; + if self.data_active() { + self.clear_interrupt_flags(); // Send abort // CP state machine must be idle - while Self::cmd_active() {} + while self.cmd_active() {} // Command arg regs.argr().write(|w| w.set_cmdarg(0)); @@ -1023,22 +1029,22 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); // Wait for the abort - while Self::data_active() {} + while self.data_active() {} } regs.maskr().write(|_| ()); // disable irqs - Self::clear_interrupt_flags(); - Self::stop_datapath(); + self.clear_interrupt_flags(); + self.stop_datapath(); } /// Wait for a previously started datapath transfer to complete from an interrupt. #[inline] #[allow(unused)] - async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { + async fn complete_datapath_transfer(&self, block: bool) -> Result<(), Error> { let res = poll_fn(|cx| { // Compiler might not be sufficiently constrained here // https://github.com/embassy-rs/embassy/issues/4723 - T::state().register(cx.waker()); - let status = T::regs().star().read(); + self.state.waker.register(cx.waker()); + let status = self.info.regs.star().read(); if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -1067,7 +1073,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }) .await; - Self::clear_interrupt_flags(); + self.clear_interrupt_flags(); res } @@ -1075,7 +1081,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Read a data block. #[inline] pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); let card_capacity = self.card()?.get_capacity(); // NOTE(unsafe) DataBlock uses align 4 @@ -1087,11 +1093,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 - 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( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1099,14 +1105,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 512, 9, ); - InterruptHandler::::enable_interrupts(); - Self::cmd(common_cmd::read_single_block(address), true)?; + self.enable_interrupts(); + self.cmd(common_cmd::read_single_block(address), true)?; - let res = Self::complete_datapath_transfer(true).await; + let res = self.complete_datapath_transfer(true).await; if res.is_ok() { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); } res @@ -1115,7 +1121,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Read multiple data blocks. #[inline] pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); let card_capacity = self.card()?.get_capacity(); // NOTE(unsafe) reinterpret buffer as &mut [u32] @@ -1131,11 +1137,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 - 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( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1143,18 +1149,18 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 512 * blocks.len() as u32, 9, ); - InterruptHandler::::enable_interrupts(); + self.enable_interrupts(); - Self::cmd(common_cmd::read_multiple_blocks(address), true)?; + self.cmd(common_cmd::read_multiple_blocks(address), true)?; - let res = Self::complete_datapath_transfer(false).await; + let res = self.complete_datapath_transfer(false).await; - Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 - Self::clear_interrupt_flags(); + self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 + self.clear_interrupt_flags(); if res.is_ok() { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); } res @@ -1162,7 +1168,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); let card = self.card.as_mut().ok_or(Error::NoCard)?; // NOTE(unsafe) DataBlock uses align 4 @@ -1174,26 +1180,26 @@ impl<'d, T: Instance> Sdmmc<'d, T> { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 - let on_drop = OnDrop::new(|| Self::on_drop()); + 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)?; + self.cmd(common_cmd::write_single_block(address), true)?; let transfer = self.prepare_datapath_write(buffer, 512, 9); - InterruptHandler::::enable_interrupts(); + self.enable_interrupts(); #[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(true).await; + let res = self.complete_datapath_transfer(true).await; match res { Ok(_) => { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); // TODO: Make this configurable @@ -1219,7 +1225,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Write multiple data blocks. pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); let card = self.card.as_mut().ok_or(Error::NoCard)?; // NOTE(unsafe) reinterpret buffer as &[u32] @@ -1236,31 +1242,31 @@ impl<'d, T: Instance> Sdmmc<'d, T> { _ => block_idx, }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + self.cmd(common_cmd::set_block_length(512), false)?; // CMD16 let block_count = blocks.len(); - let on_drop = OnDrop::new(|| Self::on_drop()); + let on_drop = OnDrop::new(|| self.on_drop()); #[cfg(sdmmc_v1)] - Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 + self.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 // Setup write command let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); - InterruptHandler::::enable_interrupts(); + self.enable_interrupts(); #[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 = Self::complete_datapath_transfer(false).await; + let res = self.complete_datapath_transfer(false).await; - Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 - Self::clear_interrupt_flags(); + self.cmd(common_cmd::stop_transmission(), false)?; // CMD12 + self.clear_interrupt_flags(); match res { Ok(_) => { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); // TODO: Make this configurable @@ -1306,8 +1312,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { - let regs = T::regs(); - let ker_ck = T::frequency(); + let regs = self.info.regs; let bus_width = match (self.d3.is_some(), self.d7.is_some()) { (true, true) => { @@ -1322,11 +1327,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // 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)); + let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(self.ker_clk, SD_INIT_FREQ.0)); self.clock = init_clock; // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); + self.wait_idle(); regs.clkcr().modify(|w| { w.set_widbus(0); @@ -1338,12 +1343,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { .write(|w| w.set_datatime(self.config.data_transfer_timeout)); regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); - Self::cmd(common_cmd::idle(), false)?; + 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)?; + self.cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; let cic = CIC::from(regs.respr(0).read().cardstatus()); if cic.pattern() != 0xAA { @@ -1356,12 +1361,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let ocr = loop { // Signal that next command is a app command - Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 + 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) { + match self.cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { // ACMD41 Ok(_) => (), Err(Error::Crc) => (), @@ -1388,7 +1393,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 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) { + match self.cmd(emmc_cmd::send_op_cond(op_cond), false) { Ok(_) => (), Err(Error::Crc) => (), Err(err) => return Err(err), @@ -1410,7 +1415,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } } - Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 + 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; @@ -1421,7 +1426,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { SdmmcPeripheral::SdCard(ref mut card) => { card.cid = cid.into(); - Self::cmd(sd_cmd::send_relative_address(), false)?; + self.cmd(sd_cmd::send_relative_address(), false)?; let rca = RCA::::from(regs.respr(0).read().cardstatus()); card.rca = rca.address(); } @@ -1429,11 +1434,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { emmc.cid = cid.into(); emmc.rca = 1u16.into(); - Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; + self.cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; } } - Self::cmd(common_cmd::send_csd(card.get_address()), 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; @@ -1475,12 +1480,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 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)?; + 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( + self.cmd( emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), false, )?; @@ -1497,7 +1502,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); + self.wait_idle(); regs.clkcr().modify(|w| w.set_widbus(widbus)); @@ -1546,7 +1551,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// /// SD only. pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await } @@ -1579,9 +1584,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }; // Arm `OnDrop` after the buffer, so it will be dropped first - 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( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1589,10 +1594,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 64, 6, ); - InterruptHandler::::enable_interrupts(); - Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 + self.enable_interrupts(); + self.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 - let res = Self::complete_datapath_transfer(true).await; + let res = self.complete_datapath_transfer(true).await; // Host is allowed to use the new functions at least 8 // clocks after the end of the switch command @@ -1605,7 +1610,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { match res { Ok(_) => { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); // Function Selection of Function Group 1 @@ -1629,8 +1634,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// 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)?; + 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, @@ -1639,9 +1644,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 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 on_drop = OnDrop::new(|| self.on_drop()); - let transfer = Self::prepare_datapath_read( + let transfer = self.prepare_datapath_read( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1649,14 +1654,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 8, 3, ); - InterruptHandler::::enable_interrupts(); - Self::cmd(sd_cmd::send_scr(), true)?; + self.enable_interrupts(); + self.cmd(sd_cmd::send_scr(), true)?; - let res = Self::complete_datapath_transfer(true).await; + let res = self.complete_datapath_transfer(true).await; if res.is_ok() { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); unsafe { @@ -1679,15 +1684,15 @@ impl<'d, T: Instance> Sdmmc<'d, T> { None => &mut CmdBlock::new(), }; - Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 - Self::cmd(common_cmd::app_cmd(rca), false)?; // APP + 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 on_drop = OnDrop::new(|| self.on_drop()); - let transfer = Self::prepare_datapath_read( + let transfer = self.prepare_datapath_read( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1695,14 +1700,14 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 64, 6, ); - InterruptHandler::::enable_interrupts(); - Self::cmd(sd_cmd::sd_status(), true)?; + self.enable_interrupts(); + self.cmd(sd_cmd::sd_status(), true)?; - let res = Self::complete_datapath_transfer(true).await; + let res = self.complete_datapath_transfer(true).await; if res.is_ok() { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); for byte in status.iter_mut() { @@ -1717,7 +1722,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// /// eMMC only. pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await } @@ -1726,7 +1731,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// /// eMMC only. async fn read_ext_csd(&mut self) -> Result<(), Error> { - let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc(); + let mut card = self.card.take().ok_or(Error::NoCard)?; + let emmc = card.get_emmc(); // Note: cmd_block can't be used because ExtCSD is too long to fit. let mut data_block = DataBlock([0u8; 512]); @@ -1734,12 +1740,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // 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 + 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( + let transfer = self.prepare_datapath_read( &self.config, #[cfg(sdmmc_v1)] &mut self.dma, @@ -1747,26 +1750,30 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 512, 9, ); - InterruptHandler::::enable_interrupts(); - Self::cmd(emmc_cmd::send_ext_csd(), true)?; + self.enable_interrupts(); + self.cmd(emmc_cmd::send_ext_csd(), true)?; - let res = Self::complete_datapath_transfer(true).await; + // Arm `OnDrop` after the buffer, so it will be dropped first + let on_drop = OnDrop::new(|| self.on_drop()); + + let res = self.complete_datapath_transfer(true).await; if res.is_ok() { on_drop.defuse(); - Self::stop_datapath(); + self.stop_datapath(); drop(transfer); - card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); + emmc.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); } + res } } -impl<'d, T: Instance> Drop for Sdmmc<'d, T> { +impl<'d> Drop for Sdmmc<'d> { fn drop(&mut self) { - T::Interrupt::disable(); - Self::on_drop(); + // T::Interrupt::disable(); + self.on_drop(); critical_section::with(|_| { self.clk.set_as_disconnected(); @@ -1799,9 +1806,28 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { ////////////////////////////////////////////////////// +type Regs = RegBlock; + +struct Info { + regs: Regs, + rcc: RccInfo, +} + +struct State { + waker: AtomicWaker, +} + +impl State { + const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } +} + trait SealedInstance { - fn regs() -> RegBlock; - fn state() -> &'static AtomicWaker; + fn info() -> &'static Info; + fn state() -> &'static State; } /// SDMMC instance trait. @@ -1828,13 +1854,17 @@ dma_trait!(SdmmcDma, Instance); foreach_peripheral!( (sdmmc, $inst:ident) => { impl SealedInstance for peripherals::$inst { - fn regs() -> RegBlock { - crate::pac::$inst + fn info() -> &'static Info { + static INFO: Info = Info { + regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }, + rcc: crate::peripherals::$inst::RCC_INFO, + }; + &INFO } - fn state() -> &'static ::embassy_sync::waitqueue::AtomicWaker { - static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new(); - &WAKER + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE } } @@ -1844,7 +1874,7 @@ foreach_peripheral!( }; ); -impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { +impl<'d> block_device_driver::BlockDevice<512> for Sdmmc<'d> { type Error = Error; type Align = aligned::A4; @@ -1853,7 +1883,7 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { block_address: u32, buf: &mut [aligned::Aligned], ) -> Result<(), Self::Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); // TODO: I think block_address needs to be adjusted by the partition start offset if buf.len() == 1 { let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; @@ -1871,7 +1901,7 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { block_address: u32, buf: &[aligned::Aligned], ) -> Result<(), Self::Error> { - let _scoped_block_stop = T::RCC_INFO.block_stop(); + let _scoped_block_stop = self.info.rcc.block_stop(); // TODO: I think block_address needs to be adjusted by the partition start offset if buf.len() == 1 { let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; -- cgit