From 8a8e5c4b736adf1d83f6849d7f86c26dabf73675 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Wed, 16 Mar 2022 20:20:39 +0200 Subject: [PATCH] Fix SDMMC v2 and add H7 example --- embassy-stm32/src/sdmmc/mod.rs | 94 ++++++++++++++++++++++--------- examples/stm32f4/src/bin/sdmmc.rs | 23 +++----- examples/stm32h7/src/bin/sdmmc.rs | 42 ++++++++++++++ stm32-data | 2 +- 4 files changed, 120 insertions(+), 41 deletions(-) create mode 100644 examples/stm32h7/src/bin/sdmmc.rs diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 18e53ce10..60060c79e 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -12,7 +12,7 @@ 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, TransferOptions}; +use crate::dma::NoDma; use crate::gpio::sealed::AFType; use crate::gpio::{Pull, Speed}; use crate::interrupt::Interrupt; @@ -191,26 +191,23 @@ pub struct Sdmmc<'d, T: Instance, P: Pins, Dma = NoDma> { card: Option, } +#[cfg(sdmmc_v1)] impl<'d, T: Instance, P: Pins, Dma: SdioDma> Sdmmc<'d, T, P, Dma> { - /// # Safety - /// - /// Futures that borrow this type can't be leaked - #[inline(always)] - pub unsafe fn new( + pub fn new( _peripheral: impl Unborrow + 'd, pins: impl Unborrow + 'd, irq: impl Unborrow + 'd, config: Config, - dma: Dma, + dma: impl Unborrow + 'd, ) -> Self { - unborrow!(irq, pins); + unborrow!(irq, pins, dma); pins.configure(); T::enable(); T::reset(); let inner = T::inner(); - let clock = inner.new_inner(T::frequency()); + let clock = unsafe { inner.new_inner(T::frequency()) }; irq.set_handler(Self::on_interrupt); irq.unpend(); @@ -227,7 +224,45 @@ impl<'d, T: Instance, P: Pins, Dma: SdioDma> Sdmmc<'d, T, P, Dma> { card: None, } } +} +#[cfg(sdmmc_v2)] +impl<'d, T: Instance, P: Pins> Sdmmc<'d, T, P, NoDma> { + pub fn new( + _peripheral: impl Unborrow + 'd, + pins: impl Unborrow + 'd, + irq: impl Unborrow + 'd, + config: Config, + ) -> Self { + unborrow!(irq, pins); + pins.configure(); + + T::enable(); + T::reset(); + + info!("Freq: {}", T::frequency().0); + + let inner = T::inner(); + let clock = unsafe { inner.new_inner(T::frequency()) }; + + irq.set_handler(Self::on_interrupt); + irq.unpend(); + irq.enable(); + + Self { + sdmmc: PhantomData, + pins, + irq, + config, + dma: NoDma, + clock, + signalling: Default::default(), + card: None, + } + } +} + +impl<'d, T: Instance, P: Pins, Dma: SdioDma> Sdmmc<'d, T, P, Dma> { #[inline(always)] pub async fn init_card(&mut self, freq: impl Into) -> Result<(), Error> { let inner = T::inner(); @@ -687,7 +722,7 @@ impl SdmmcInner { length_bytes: u32, block_size: u8, data_transfer_timeout: u32, - dma: &mut Dma, + #[allow(unused_variables)] dma: &mut Dma, ) { assert!(block_size <= 14, "Block size up to 2^14 bytes"); let regs = self.0; @@ -705,13 +740,13 @@ impl SdmmcInner { cfg_if::cfg_if! { if #[cfg(sdmmc_v1)] { let request = dma.request(); - dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, TransferOptions { + dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::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.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32)); regs.idmactrlr().modify(|w| w.set_idmaen(true)); } } @@ -736,7 +771,7 @@ impl SdmmcInner { length_bytes: u32, block_size: u8, data_transfer_timeout: u32, - dma: &mut Dma, + #[allow(unused_variables)] dma: &mut Dma, ) { assert!(block_size <= 14, "Block size up to 2^14 bytes"); let regs = self.0; @@ -754,13 +789,13 @@ impl SdmmcInner { cfg_if::cfg_if! { if #[cfg(sdmmc_v1)] { let request = dma.request(); - dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, TransferOptions { + dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::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.idmabase0r().write(|w| w.set_idmabase0(buffer as *const u32 as u32)); regs.idmactrlr().modify(|w| w.set_idmaen(true)); } } @@ -1104,7 +1139,7 @@ impl SdmmcInner { while self.cmd_active() {} // Command arg - regs.argr().write(|w| w.set_cmdargr(cmd.arg)); + regs.argr().write(|w| w.set_cmdarg(cmd.arg)); // Command index and start CP State Machine regs.cmdr().write(|w| { @@ -1113,14 +1148,13 @@ impl SdmmcInner { w.set_cmdindex(cmd.cmd); w.set_cpsmen(true); - cfg_if::cfg_if! { - if #[cfg(sdmmc_v2)] { - // Special mode in CP State Machine - // CMD12: Stop Transmission - let cpsm_stop_transmission = cmd.cmd == 12; - w.set_cmdstop(cpsm_stop_transmission); - w.set_cmdtrans(data); - } + #[cfg(sdmmc_v2)] + { + // Special mode in CP State Machine + // CMD12: Stop Transmission + let cpsm_stop_transmission = cmd.cmd == 12; + w.set_cmdstop(cpsm_stop_transmission); + w.set_cmdtrans(data); } }); @@ -1160,7 +1194,7 @@ impl SdmmcInner { while self.cmd_active() {} // Command arg - regs.argr().write(|w| w.set_cmdargr(0)); + regs.argr().write(|w| w.set_cmdarg(0)); // Command index and start CP State Machine regs.cmdr().write(|w| { @@ -1300,7 +1334,15 @@ pin_trait!(D5Pin, Instance); pin_trait!(D6Pin, Instance); pin_trait!(D7Pin, Instance); -dma_trait!(SdioDma, Instance); +cfg_if::cfg_if! { + if #[cfg(sdmmc_v1)] { + dma_trait!(SdioDma, Instance); + } else if #[cfg(sdmmc_v2)] { + // SDMMCv2 uses internal DMA + pub trait SdioDma {} + impl SdioDma for NoDma {} + } +} pub trait Pins: sealed::Pins + 'static { const BUSWIDTH: BusWidth; diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 46ac44500..301d7dda0 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -13,28 +13,23 @@ 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.rcc.sys_ck = Some(48.mhz().into()); config } #[embassy::main(config = "config()")] async fn main(_spawner: Spawner, p: Peripherals) -> ! { - info!("Hello World, dude!"); + info!("Hello World!"); let irq = interrupt::take!(SDIO); - let mut sdmmc = unsafe { - Sdmmc::new( - p.SDIO, - (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), - irq, - Default::default(), - p.DMA2_CH3, - ) - }; + let mut sdmmc = Sdmmc::new( + p.SDIO, + (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), + irq, + Default::default(), + p.DMA2_CH3, + ); info!("Configured clock: {}", sdmmc.clock.0); diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs new file mode 100644 index 000000000..255c5568f --- /dev/null +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy_stm32::sdmmc::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.sys_ck = Some(200.mhz().into()); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, p: Peripherals) -> ! { + info!("Hello World!"); + + let irq = interrupt::take!(SDMMC1); + + let mut sdmmc = Sdmmc::new( + p.SDMMC1, + (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), + irq, + Default::default(), + ); + + 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 2b8eb83c7..938770167 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 2b8eb83c7aa01200f8215248793da2489209116f +Subproject commit 938770167164faa46970af4f6096ec7c8b195914