Fix SDMMC v2 and add H7 example

This commit is contained in:
chemicstry 2022-03-16 20:20:39 +02:00
parent 48fc48ea7d
commit 8a8e5c4b73
4 changed files with 120 additions and 41 deletions

View File

@ -12,7 +12,7 @@ use embassy_hal_common::unborrow;
use futures::future::poll_fn; use futures::future::poll_fn;
use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; 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::sealed::AFType;
use crate::gpio::{Pull, Speed}; use crate::gpio::{Pull, Speed};
use crate::interrupt::Interrupt; use crate::interrupt::Interrupt;
@ -191,26 +191,23 @@ pub struct Sdmmc<'d, T: Instance, P: Pins<T>, Dma = NoDma> {
card: Option<Card>, card: Option<Card>,
} }
#[cfg(sdmmc_v1)]
impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> { impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> {
/// # Safety pub fn new(
///
/// Futures that borrow this type can't be leaked
#[inline(always)]
pub unsafe fn new(
_peripheral: impl Unborrow<Target = T> + 'd, _peripheral: impl Unborrow<Target = T> + 'd,
pins: impl Unborrow<Target = P> + 'd, pins: impl Unborrow<Target = P> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd, irq: impl Unborrow<Target = T::Interrupt> + 'd,
config: Config, config: Config,
dma: Dma, dma: impl Unborrow<Target = Dma> + 'd,
) -> Self { ) -> Self {
unborrow!(irq, pins); unborrow!(irq, pins, dma);
pins.configure(); pins.configure();
T::enable(); T::enable();
T::reset(); T::reset();
let inner = T::inner(); 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.set_handler(Self::on_interrupt);
irq.unpend(); irq.unpend();
@ -227,7 +224,45 @@ impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> {
card: None, card: None,
} }
} }
}
#[cfg(sdmmc_v2)]
impl<'d, T: Instance, P: Pins<T>> Sdmmc<'d, T, P, NoDma> {
pub fn new(
_peripheral: impl Unborrow<Target = T> + 'd,
pins: impl Unborrow<Target = P> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + '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<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> {
#[inline(always)] #[inline(always)]
pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> { pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> Result<(), Error> {
let inner = T::inner(); let inner = T::inner();
@ -687,7 +722,7 @@ impl SdmmcInner {
length_bytes: u32, length_bytes: u32,
block_size: u8, block_size: u8,
data_transfer_timeout: u32, data_transfer_timeout: u32,
dma: &mut Dma, #[allow(unused_variables)] dma: &mut Dma,
) { ) {
assert!(block_size <= 14, "Block size up to 2^14 bytes"); assert!(block_size <= 14, "Block size up to 2^14 bytes");
let regs = self.0; let regs = self.0;
@ -705,13 +740,13 @@ impl SdmmcInner {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(sdmmc_v1)] { if #[cfg(sdmmc_v1)] {
let request = dma.request(); 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, pburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral, flow_ctrl: crate::dma::FlowControl::Peripheral,
..Default::default() ..Default::default()
}); });
} else if #[cfg(sdmmc_v2)] { } 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)); regs.idmactrlr().modify(|w| w.set_idmaen(true));
} }
} }
@ -736,7 +771,7 @@ impl SdmmcInner {
length_bytes: u32, length_bytes: u32,
block_size: u8, block_size: u8,
data_transfer_timeout: u32, data_transfer_timeout: u32,
dma: &mut Dma, #[allow(unused_variables)] dma: &mut Dma,
) { ) {
assert!(block_size <= 14, "Block size up to 2^14 bytes"); assert!(block_size <= 14, "Block size up to 2^14 bytes");
let regs = self.0; let regs = self.0;
@ -754,13 +789,13 @@ impl SdmmcInner {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(sdmmc_v1)] { if #[cfg(sdmmc_v1)] {
let request = dma.request(); 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, pburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral, flow_ctrl: crate::dma::FlowControl::Peripheral,
..Default::default() ..Default::default()
}); });
} else if #[cfg(sdmmc_v2)] { } 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)); regs.idmactrlr().modify(|w| w.set_idmaen(true));
} }
} }
@ -1104,7 +1139,7 @@ impl SdmmcInner {
while self.cmd_active() {} while self.cmd_active() {}
// Command arg // 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 // Command index and start CP State Machine
regs.cmdr().write(|w| { regs.cmdr().write(|w| {
@ -1113,14 +1148,13 @@ impl SdmmcInner {
w.set_cmdindex(cmd.cmd); w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true); w.set_cpsmen(true);
cfg_if::cfg_if! { #[cfg(sdmmc_v2)]
if #[cfg(sdmmc_v2)] { {
// Special mode in CP State Machine // Special mode in CP State Machine
// CMD12: Stop Transmission // CMD12: Stop Transmission
let cpsm_stop_transmission = cmd.cmd == 12; let cpsm_stop_transmission = cmd.cmd == 12;
w.set_cmdstop(cpsm_stop_transmission); w.set_cmdstop(cpsm_stop_transmission);
w.set_cmdtrans(data); w.set_cmdtrans(data);
}
} }
}); });
@ -1160,7 +1194,7 @@ impl SdmmcInner {
while self.cmd_active() {} while self.cmd_active() {}
// Command arg // 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 // Command index and start CP State Machine
regs.cmdr().write(|w| { regs.cmdr().write(|w| {
@ -1300,7 +1334,15 @@ pin_trait!(D5Pin, Instance);
pin_trait!(D6Pin, Instance); pin_trait!(D6Pin, Instance);
pin_trait!(D7Pin, 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<T: Instance> {}
impl<T: Instance> SdioDma<T> for NoDma {}
}
}
pub trait Pins<T: Instance>: sealed::Pins<T> + 'static { pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
const BUSWIDTH: BusWidth; const BUSWIDTH: BusWidth;

View File

@ -13,28 +13,23 @@ use example_common::*;
fn config() -> Config { fn config() -> Config {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.hse = Some(8.mhz().into()); config.rcc.sys_ck = Some(48.mhz().into());
config.rcc.hclk = Some(48.mhz().into());
config.rcc.pclk2 = Some(48.mhz().into());
config.rcc.pll48 = true;
config config
} }
#[embassy::main(config = "config()")] #[embassy::main(config = "config()")]
async fn main(_spawner: Spawner, p: Peripherals) -> ! { async fn main(_spawner: Spawner, p: Peripherals) -> ! {
info!("Hello World, dude!"); info!("Hello World!");
let irq = interrupt::take!(SDIO); let irq = interrupt::take!(SDIO);
let mut sdmmc = unsafe { let mut sdmmc = Sdmmc::new(
Sdmmc::new( p.SDIO,
p.SDIO, (p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11),
(p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11), irq,
irq, Default::default(),
Default::default(), p.DMA2_CH3,
p.DMA2_CH3, );
)
};
info!("Configured clock: {}", sdmmc.clock.0); info!("Configured clock: {}", sdmmc.clock.0);

View File

@ -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 {}
}

@ -1 +1 @@
Subproject commit 2b8eb83c7aa01200f8215248793da2489209116f Subproject commit 938770167164faa46970af4f6096ec7c8b195914