From 6d547b1143950197e5558803104c08d546885560 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Wed, 16 Mar 2022 18:52:27 +0200 Subject: [PATCH] SDIO working on stm32f4 --- embassy-stm32/build.rs | 23 +-- embassy-stm32/src/sdmmc/mod.rs | 294 +++++++++++++++++++----------- embassy-stm32/src/spi/mod.rs | 20 +- examples/stm32f4/Cargo.toml | 3 + examples/stm32f4/src/bin/sdmmc.rs | 52 ++++++ stm32-data | 2 +- 6 files changed, 269 insertions(+), 125 deletions(-) create mode 100644 examples/stm32f4/src/bin/sdmmc.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8b64aaaa..a8e89c84 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -407,17 +407,17 @@ fn main() { (("timer", "BKIN2"), (quote!(crate::pwm::BreakInput2Pin), quote!())), (("timer", "BKIN2_COMP1"), (quote!(crate::pwm::BreakInput2Comparator1Pin), quote!())), (("timer", "BKIN2_COMP2"), (quote!(crate::pwm::BreakInput2Comparator2Pin), quote!())), - (("sdmmc", "CK"), (quote!(crate::sdmmc::CkPin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "CMD"), (quote!(crate::sdmmc::CmdPin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D0"), (quote!(crate::sdmmc::D0Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D1"), (quote!(crate::sdmmc::D1Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D2"), (quote!(crate::sdmmc::D2Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D3"), (quote!(crate::sdmmc::D3Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D4"), (quote!(crate::sdmmc::D4Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D5"), (quote!(crate::sdmmc::D5Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D6"), (quote!(crate::sdmmc::D6Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D6"), (quote!(crate::sdmmc::D7Pin), quote!(#[cfg(feature="sdmmc-rs")]))), - (("sdmmc", "D8"), (quote!(crate::sdmmc::D8Pin), quote!(#[cfg(feature="sdmmc-rs")]))), + (("sdmmc", "CK"), (quote!(crate::sdmmc::CkPin), quote!())), + (("sdmmc", "CMD"), (quote!(crate::sdmmc::CmdPin), quote!())), + (("sdmmc", "D0"), (quote!(crate::sdmmc::D0Pin), quote!())), + (("sdmmc", "D1"), (quote!(crate::sdmmc::D1Pin), quote!())), + (("sdmmc", "D2"), (quote!(crate::sdmmc::D2Pin), quote!())), + (("sdmmc", "D3"), (quote!(crate::sdmmc::D3Pin), quote!())), + (("sdmmc", "D4"), (quote!(crate::sdmmc::D4Pin), quote!())), + (("sdmmc", "D5"), (quote!(crate::sdmmc::D5Pin), quote!())), + (("sdmmc", "D6"), (quote!(crate::sdmmc::D6Pin), quote!())), + (("sdmmc", "D6"), (quote!(crate::sdmmc::D7Pin), quote!())), + (("sdmmc", "D8"), (quote!(crate::sdmmc::D8Pin), quote!())), ].into(); for p in METADATA.peripherals { @@ -483,6 +483,7 @@ fn main() { (("i2c", "TX"), quote!(crate::i2c::TxDma)), (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)), (("dcmi", "PSSI"), quote!(crate::dcmi::FrameDma)), + (("sdmmc", "SDIO"), quote!(crate::sdmmc::SdioDma)), ] .into(); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 7bd80981..7548b799 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -12,12 +12,13 @@ use embassy_hal_common::unborrow; use futures::future::poll_fn; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; -use crate::dma::NoDma; +use crate::dma::{NoDma, TransferOptions}; use crate::gpio::sealed::AFType; use crate::gpio::{Pull, Speed}; use crate::interrupt::Interrupt; use crate::pac::sdmmc::Sdmmc as RegBlock; use crate::peripherals; +use crate::rcc::RccPeripheral; use crate::time::Hertz; /// The signalling scheme used on the SDMMC bus @@ -92,12 +93,6 @@ impl Card { } } -/// Indicates transfer direction -enum Dir { - CardToHost, - HostToCard, -} - #[repr(u8)] enum PowerCtrl { Off = 0b00, @@ -196,16 +191,16 @@ pub struct Sdmmc<'d, T: Instance, P: Pins, Dma = NoDma> { pins: P, irq: T::Interrupt, config: Config, + dma: Dma, /// Current clock to card - clock: Hertz, + pub clock: Hertz, /// Current signalling scheme to card signalling: Signalling, /// Card card: Option, - dma: Dma, } -impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { +impl<'d, T: Instance, P: Pins, Dma: SdioDma> Sdmmc<'d, T, P, Dma> { /// # Safety /// /// Futures that borrow this type can't be leaked @@ -220,6 +215,9 @@ impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { unborrow!(irq, pins); pins.configure(); + T::enable(); + T::reset(); + let inner = T::inner(); let clock = inner.new_inner(config.kernel_clk); @@ -232,10 +230,10 @@ impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { pins, irq, config, + dma, clock, signalling: Default::default(), card: None, - dma, } } @@ -255,6 +253,7 @@ impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { &mut self.clock, T::state(), self.config.data_transfer_timeout, + &mut self.dma, ) .await } @@ -278,6 +277,7 @@ impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { card_capacity, state, self.config.data_transfer_timeout, + &mut self.dma, ) .await } @@ -296,6 +296,7 @@ impl<'d, T: Instance, P: Pins, Dma> Sdmmc<'d, T, P, Dma> { card, state, self.config.data_transfer_timeout, + &mut self.dma, ) .await } @@ -349,6 +350,9 @@ impl SdmmcInner { w.set_pwrsav(false); w.set_negedge(false); w.set_hwfc_en(true); + + #[cfg(sdmmc_v1)] + w.set_clken(true); }); // Power off, writen 00: Clock to the card is stopped; @@ -361,7 +365,7 @@ impl SdmmcInner { /// Initializes card (if present) and sets the bus at the /// specified frequency. #[allow(clippy::too_many_arguments)] - async fn init_card( + async fn init_card>( &self, freq: Hertz, bus_width: BusWidth, @@ -372,6 +376,7 @@ impl SdmmcInner { clock: &mut Hertz, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result<(), Error> { let regs = self.0; @@ -382,7 +387,7 @@ impl SdmmcInner { // Check if cards supports CMD8 (with pattern) self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; - let r1 = regs.resp(0).read().cardstatus(); + let r1 = regs.respr(0).read().cardstatus(); let mut card = if r1 == 0x1AA { // Card echoed back the pattern. Must be at least v2 @@ -406,7 +411,7 @@ impl SdmmcInner { Err(Error::Crc) => (), Err(err) => return Err(err), } - let ocr: OCR = regs.resp(0).read().cardstatus().into(); + let ocr: OCR = regs.respr(0).read().cardstatus().into(); if !ocr.is_busy() { // Power up done break ocr; @@ -422,26 +427,27 @@ impl SdmmcInner { card.ocr = ocr; self.cmd(Cmd::all_send_cid(), false)?; // CMD2 - let cid0 = regs.resp(0).read().cardstatus() as u128; - let cid1 = regs.resp(1).read().cardstatus() as u128; - let cid2 = regs.resp(2).read().cardstatus() as u128; - let cid3 = regs.resp(3).read().cardstatus() as u128; + 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.resp(0).read().cardstatus() >> 16; + card.rca = regs.respr(0).read().cardstatus() >> 16; self.cmd(Cmd::send_csd(card.rca << 16), false)?; - let csd0 = regs.resp(0).read().cardstatus() as u128; - let csd1 = regs.resp(1).read().cardstatus() as u128; - let csd2 = regs.resp(2).read().cardstatus() as u128; - let csd3 = regs.resp(3).read().cardstatus() as u128; + 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, waker_reg, data_transfer_timeout) + + self.get_scr(&mut card, waker_reg, data_transfer_timeout, dma) .await?; // Set bus width @@ -475,13 +481,18 @@ impl SdmmcInner { } // Read status - self.read_sd_status(&mut card, waker_reg, data_transfer_timeout) + self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma) .await?; if freq.0 > 25_000_000 { // Switch to SDR25 *signalling = self - .switch_signalling_mode(Signalling::SDR25, waker_reg, data_transfer_timeout) + .switch_signalling_mode( + Signalling::SDR25, + waker_reg, + data_transfer_timeout, + dma, + ) .await?; if *signalling == Signalling::SDR25 { @@ -494,7 +505,7 @@ impl SdmmcInner { } } // Read status after signalling change - self.read_sd_status(&mut card, waker_reg, data_transfer_timeout) + self.read_sd_status(&mut card, waker_reg, data_transfer_timeout, dma) .await?; old_card.replace(card); } @@ -502,13 +513,14 @@ impl SdmmcInner { Ok(()) } - async fn read_block( + async fn read_block>( &self, block_idx: u32, buffer: &mut [u32; 128], capacity: CardCapacity, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result<(), Error> { // Always read 1 block of 512 bytes // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes @@ -521,14 +533,13 @@ impl SdmmcInner { let regs = self.0; let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); - let buf_addr = buffer as *mut [u32; 128] as u32; unsafe { - self.prepare_datapath_transfer( - buf_addr, + self.prepare_datapath_read( + buffer as *mut [u32; 128], 512, 9, - Dir::CardToHost, data_transfer_timeout, + dma, ); self.data_interrupts(true); } @@ -536,7 +547,7 @@ impl SdmmcInner { let res = poll_fn(|cx| { waker_reg.register(cx.waker()); - let status = unsafe { regs.sta().read() }; + let status = unsafe { regs.star().read() }; if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -552,20 +563,19 @@ impl SdmmcInner { if res.is_ok() { on_drop.defuse(); - unsafe { - regs.idmactrlr().modify(|w| w.set_idmaen(false)); - } + self.stop_datapath(); } res } - async fn write_block( + async fn write_block>( &self, block_idx: u32, buffer: &[u32; 128], card: &mut Card, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result<(), Error> { // Always read 1 block of 512 bytes // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes @@ -578,14 +588,13 @@ impl SdmmcInner { let regs = self.0; let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); - let buf_addr = buffer as *const [u32; 128] as u32; unsafe { - self.prepare_datapath_transfer( - buf_addr, + self.prepare_datapath_write( + buffer as *const [u32; 128], 512, 9, - Dir::HostToCard, data_transfer_timeout, + dma, ); self.data_interrupts(true); } @@ -593,7 +602,7 @@ impl SdmmcInner { let res = poll_fn(|cx| { waker_reg.register(cx.waker()); - let status = unsafe { regs.sta().read() }; + let status = unsafe { regs.star().read() }; if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -610,16 +619,15 @@ impl SdmmcInner { match res { Ok(_) => { on_drop.defuse(); - unsafe { - regs.idmactrlr().modify(|w| w.set_idmaen(false)); - } + self.stop_datapath(); + // TODO: Make this configurable let mut timeout: u32 = 0x00FF_FFFF; // Try to read card status (ACMD13) while timeout > 0 { match self - .read_sd_status(card, waker_reg, data_transfer_timeout) + .read_sd_status(card, waker_reg, data_transfer_timeout, dma) .await { Ok(_) => return Ok(()), @@ -646,7 +654,7 @@ impl SdmmcInner { // NOTE(unsafe) Atomic read with no side-effects unsafe { - let status = regs.sta().read(); + let status = regs.star().read(); cfg_if::cfg_if! { if #[cfg(sdmmc_v1)] { status.rxact() || status.txact() @@ -664,7 +672,7 @@ impl SdmmcInner { // NOTE(unsafe) Atomic read with no side-effects unsafe { - let status = regs.sta().read(); + let status = regs.star().read(); cfg_if::cfg_if! { if #[cfg(sdmmc_v1)] { status.cmdact() @@ -683,23 +691,18 @@ impl SdmmcInner { /// # Safety /// - /// `buffer_addr` must be valid for the whole transfer and word aligned - unsafe fn prepare_datapath_transfer( + /// `buffer` must be valid for the whole transfer and word aligned + unsafe fn prepare_datapath_read>( &self, - buffer_addr: u32, + buffer: *mut [u32], length_bytes: u32, block_size: u8, - direction: Dir, data_transfer_timeout: u32, + dma: &mut Dma, ) { assert!(block_size <= 14, "Block size up to 2^14 bytes"); let regs = self.0; - let dtdir = match direction { - Dir::CardToHost => true, - Dir::HostToCard => false, - }; - // Command AND Data state machines must be idle self.wait_idle(); self.clear_interrupt_flags(); @@ -708,16 +711,94 @@ impl SdmmcInner { regs.dtimer() .write(|w| w.set_datatime(data_transfer_timeout)); - regs.dlen().write(|w| w.set_datalength(length_bytes)); + regs.dlenr().write(|w| w.set_datalength(length_bytes)); + + cfg_if::cfg_if! { + if #[cfg(sdmmc_v1)] { + let request = dma.request(); + dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, TransferOptions { + pburst: crate::dma::Burst::Incr4, + flow_ctrl: crate::dma::FlowControl::Peripheral, + ..Default::default() + }); + } else if #[cfg(sdmmc_v2)] { + regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr)); + regs.idmactrlr().modify(|w| w.set_idmaen(true)); + } + } - regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr)); - regs.idmactrlr().modify(|w| w.set_idmaen(true)); regs.dctrl().modify(|w| { w.set_dblocksize(block_size); - w.set_dtdir(dtdir); + w.set_dtdir(true); + #[cfg(sdmmc_v1)] + { + w.set_dmaen(true); + w.set_dten(true); + } }); } + /// # Safety + /// + /// `buffer` must be valid for the whole transfer and word aligned + unsafe fn prepare_datapath_write>( + &self, + buffer: *const [u32], + length_bytes: u32, + block_size: u8, + data_transfer_timeout: u32, + dma: &mut Dma, + ) { + assert!(block_size <= 14, "Block size up to 2^14 bytes"); + let regs = self.0; + + // Command AND Data state machines must be idle + self.wait_idle(); + self.clear_interrupt_flags(); + + // NOTE(unsafe) We have exclusive access to the regisers + + regs.dtimer() + .write(|w| w.set_datatime(data_transfer_timeout)); + regs.dlenr().write(|w| w.set_datalength(length_bytes)); + + cfg_if::cfg_if! { + if #[cfg(sdmmc_v1)] { + let request = dma.request(); + dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, TransferOptions { + pburst: crate::dma::Burst::Incr4, + flow_ctrl: crate::dma::FlowControl::Peripheral, + ..Default::default() + }); + } else if #[cfg(sdmmc_v2)] { + regs.idmabase0r().write(|w| w.set_idmabase0(buffer_addr)); + regs.idmactrlr().modify(|w| w.set_idmaen(true)); + } + } + + regs.dctrl().modify(|w| { + w.set_dblocksize(block_size); + w.set_dtdir(false); + }); + } + + fn stop_datapath(&self) { + let regs = self.0; + + unsafe { + cfg_if::cfg_if! { + if #[cfg(sdmmc_v1)] { + regs.dctrl().modify(|w| { + w.set_dmaen(false); + w.set_dten(false); + }); + } else if #[cfg(sdmmc_v2)] { + regs.idmactrlr().modify(|w| w.set_idmaen(false)); + } + } + } + } + /// Sets the CLKDIV field in CLKCR. Updates clock field in self fn clkcr_set_clkdiv( &self, @@ -751,11 +832,12 @@ impl SdmmcInner { /// 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( + async fn switch_signalling_mode>( &self, signalling: Signalling, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result { // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not // necessary" @@ -771,19 +853,18 @@ impl SdmmcInner { }; let mut status = [0u32; 16]; - let status_addr = &mut status as *mut [u32; 16] as u32; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = self.0; let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); unsafe { - self.prepare_datapath_transfer( - status_addr, + self.prepare_datapath_read( + &mut status as *mut [u32; 16], 64, 6, - Dir::CardToHost, data_transfer_timeout, + dma, ); self.data_interrupts(true); } @@ -791,7 +872,7 @@ impl SdmmcInner { let res = poll_fn(|cx| { waker_reg.register(cx.waker()); - let status = unsafe { regs.sta().read() }; + let status = unsafe { regs.star().read() }; if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -816,9 +897,8 @@ impl SdmmcInner { match res { Ok(_) => { on_drop.defuse(); - unsafe { - regs.idmactrlr().modify(|w| w.set_idmaen(false)); - } + self.stop_datapath(); + // Function Selection of Function Group 1 let selection = (u32::from_be(status[4]) >> 24) & 0xF; @@ -844,35 +924,35 @@ impl SdmmcInner { self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13 // NOTE(unsafe) Atomic read with no side-effects - let r1 = unsafe { regs.resp(0).read().cardstatus() }; + let r1 = unsafe { regs.respr(0).read().cardstatus() }; Ok(r1.into()) } /// Reads the SD Status (ACMD13) - async fn read_sd_status( + async fn read_sd_status>( &self, card: &mut Card, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result<(), Error> { let rca = card.rca; self.cmd(Cmd::set_block_length(64), false)?; // CMD16 self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP let mut status = [0u32; 16]; - let status_addr = &mut status as *mut [u32; 16] as u32; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = self.0; let on_drop = OnDrop::new(|| unsafe { self.on_drop() }); unsafe { - self.prepare_datapath_transfer( - status_addr, + self.prepare_datapath_read( + &mut status as *mut [u32; 16], 64, 6, - Dir::CardToHost, data_transfer_timeout, + dma, ); self.data_interrupts(true); } @@ -880,7 +960,7 @@ impl SdmmcInner { let res = poll_fn(|cx| { waker_reg.register(cx.waker()); - let status = unsafe { regs.sta().read() }; + let status = unsafe { regs.star().read() }; if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -896,9 +976,8 @@ impl SdmmcInner { if res.is_ok() { on_drop.defuse(); - unsafe { - regs.idmactrlr().modify(|w| w.set_idmaen(false)); - } + self.stop_datapath(); + for byte in status.iter_mut() { *byte = u32::from_be(*byte); } @@ -941,21 +1020,17 @@ impl SdmmcInner { w.set_dbckendc(true); w.set_sdioitc(true); - cfg_if::cfg_if! { - if #[cfg(sdmmc_v1)] { - w.set_stbiterrc(true); - w.set_ceataendc(true); - } else if #[cfg(sdmmc_v2)] { - w.set_dholdc(true); - w.set_dabortc(true); - w.set_busyd0endc(true); - w.set_ackfailc(true); - w.set_acktimeoutc(true); - w.set_vswendc(true); - w.set_ckstopc(true); - w.set_idmatec(true); - w.set_idmabtcc(true); - } + #[cfg(sdmmc_v2)] + { + w.set_dholdc(true); + w.set_dabortc(true); + w.set_busyd0endc(true); + w.set_ackfailc(true); + w.set_acktimeoutc(true); + w.set_vswendc(true); + w.set_ckstopc(true); + w.set_idmatec(true); + w.set_idmabtcc(true); } }); } @@ -967,7 +1042,7 @@ impl SdmmcInner { let regs = self.0; // NOTE(unsafe) Atomic write unsafe { - regs.mask().write(|w| { + regs.maskr().write(|w| { w.set_dcrcfailie(enable); w.set_dtimeoutie(enable); w.set_dataendie(enable); @@ -978,32 +1053,32 @@ impl SdmmcInner { } } - async fn get_scr( + async fn get_scr>( &self, card: &mut Card, waker_reg: &AtomicWaker, data_transfer_timeout: u32, + dma: &mut Dma, ) -> Result<(), Error> { // Read the the 64-bit SCR register self.cmd(Cmd::set_block_length(8), false)?; // CMD16 self.cmd(Cmd::app_cmd(card.rca << 16), false)?; let mut scr = [0u32; 2]; - let scr_addr = &mut scr as *mut u32 as u32; // Arm `OnDrop` after the buffer, so it will be dropped first let regs = self.0; let on_drop = OnDrop::new(move || unsafe { self.on_drop() }); unsafe { - self.prepare_datapath_transfer(scr_addr, 8, 3, Dir::CardToHost, data_transfer_timeout); + self.prepare_datapath_read(&mut scr as *mut [u32], 8, 3, data_transfer_timeout, dma); self.data_interrupts(true); } self.cmd(Cmd::cmd51(), true)?; let res = poll_fn(|cx| { waker_reg.register(cx.waker()); - let status = unsafe { regs.sta().read() }; + let status = unsafe { regs.star().read() }; if status.dcrcfail() { return Poll::Ready(Err(Error::Crc)); @@ -1019,9 +1094,9 @@ impl SdmmcInner { if res.is_ok() { on_drop.defuse(); + self.stop_datapath(); unsafe { - regs.idmactrlr().modify(|w| w.set_idmaen(false)); let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); card.scr = SCR(u64::from_be_bytes(*scr_bytes)); } @@ -1030,6 +1105,7 @@ impl SdmmcInner { } /// Send command to card + #[allow(unused_variables)] fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> { let regs = self.0; @@ -1040,10 +1116,10 @@ impl SdmmcInner { while self.cmd_active() {} // Command arg - regs.arg().write(|w| w.set_cmdarg(cmd.arg)); + regs.argr().write(|w| w.set_cmdargr(cmd.arg)); // Command index and start CP State Machine - regs.cmd().write(|w| { + regs.cmdr().write(|w| { w.set_waitint(false); w.set_waitresp(cmd.resp as u8); w.set_cmdindex(cmd.cmd); @@ -1064,13 +1140,13 @@ impl SdmmcInner { if cmd.resp == Response::None { // Wait for CMDSENT or a timeout while { - status = regs.sta().read(); + status = regs.star().read(); !(status.ctimeout() || status.cmdsent()) } {} } else { // Wait for CMDREND or CCRCFAIL or a timeout while { - status = regs.sta().read(); + status = regs.star().read(); !(status.ctimeout() || status.cmdrend() || status.ccrcfail()) } {} } @@ -1096,10 +1172,10 @@ impl SdmmcInner { while self.cmd_active() {} // Command arg - regs.arg().write(|w| w.set_cmdarg(0)); + regs.argr().write(|w| w.set_cmdargr(0)); // Command index and start CP State Machine - regs.cmd().write(|w| { + regs.cmdr().write(|w| { w.set_waitint(false); w.set_waitresp(Response::Short as u8); w.set_cmdindex(12); @@ -1118,7 +1194,7 @@ impl SdmmcInner { } self.data_interrupts(false); self.clear_interrupt_flags(); - regs.idmactrlr().modify(|w| w.set_idmaen(false)); + self.stop_datapath(); } } @@ -1224,7 +1300,7 @@ pub(crate) mod sealed { pub trait Pins {} } -pub trait Instance: sealed::Instance + 'static {} +pub trait Instance: sealed::Instance + RccPeripheral + 'static {} pin_trait!(CkPin, Instance); pin_trait!(CmdPin, Instance); pin_trait!(D0Pin, Instance); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 764a967c..ea0c496d 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -424,7 +424,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { let tx_request = self.txdma.request(); let tx_dst = T::REGS.tx_ptr(); - unsafe { self.txdma.start_write(tx_request, data, tx_dst) } + unsafe { + self.txdma + .start_write(tx_request, data, tx_dst, Default::default()) + } let tx_f = Transfer::new(&mut self.txdma); unsafe { @@ -470,7 +473,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { let rx_request = self.rxdma.request(); let rx_src = T::REGS.rx_ptr(); - unsafe { self.rxdma.start_read(rx_request, rx_src, data) }; + unsafe { + self.rxdma + .start_read(rx_request, rx_src, data, Default::default()) + }; let rx_f = Transfer::new(&mut self.rxdma); let tx_request = self.txdma.request(); @@ -532,12 +538,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { let rx_request = self.rxdma.request(); let rx_src = T::REGS.rx_ptr(); - unsafe { self.rxdma.start_read(rx_request, rx_src, read) }; + unsafe { + self.rxdma + .start_read(rx_request, rx_src, read, Default::default()) + }; let rx_f = Transfer::new(&mut self.rxdma); let tx_request = self.txdma.request(); let tx_dst = T::REGS.tx_ptr(); - unsafe { self.txdma.start_write(tx_request, write, tx_dst) } + unsafe { + self.txdma + .start_write(tx_request, write, tx_dst, Default::default()) + } let tx_f = Transfer::new(&mut self.txdma); unsafe { diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index c53f04e1..0efc751f 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -23,3 +23,6 @@ nb = "1.0.0" usb-device = "0.2" usbd-serial = "0.1.1" + +[profile.release] +debug = 2 \ No newline at end of file diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs new file mode 100644 index 00000000..d941584b --- /dev/null +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -0,0 +1,52 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy_stm32::sdmmc::{self, Sdmmc}; +use embassy_stm32::time::U32Ext; +use embassy_stm32::{interrupt, Config, Peripherals}; +use example_common::*; + +fn config() -> Config { + let mut config = Config::default(); + config.rcc.hse = Some(8.mhz().into()); + config.rcc.hclk = Some(48.mhz().into()); + config.rcc.pclk2 = Some(48.mhz().into()); + config.rcc.pll48 = true; + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) -> ! { + info!("Hello World, dude!"); + + let irq = interrupt::take!(SDIO); + + let mut config = sdmmc::Config::default(); + config.hclk = 48.mhz().into(); + config.kernel_clk = 48.mhz().into(); + + let mut sdmmc = unsafe { + Sdmmc::new( + p.SDIO, + (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), + irq, + config, + p.DMA2_CH3, + ) + }; + + info!("Configured clock: {}", sdmmc.clock.0); + + unwrap!(sdmmc.init_card(25.mhz()).await); + + let card = unwrap!(sdmmc.card()); + + info!("Card: {:#?}", Debug2Format(card)); + + loop {} +} diff --git a/stm32-data b/stm32-data index 9a23a90c..2b8eb83c 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 9a23a90cc038ce657611770d919c26e89719d1f3 +Subproject commit 2b8eb83c7aa01200f8215248793da2489209116f