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 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<T>, Dma = NoDma> {
card: Option<Card>,
}
#[cfg(sdmmc_v1)]
impl<'d, T: Instance, P: Pins<T>, Dma: SdioDma<T>> 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<Target = T> + 'd,
pins: impl Unborrow<Target = P> + 'd,
irq: impl Unborrow<Target = T::Interrupt> + 'd,
config: Config,
dma: Dma,
dma: impl Unborrow<Target = Dma> + '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<T>, Dma: SdioDma<T>> Sdmmc<'d, T, P, Dma> {
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)]
pub async fn init_card(&mut self, freq: impl Into<Hertz>) -> 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,15 +1148,14 @@ impl SdmmcInner {
w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true);
cfg_if::cfg_if! {
if #[cfg(sdmmc_v2)] {
#[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);
}
}
});
let mut status;
@ -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);
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 {
const BUSWIDTH: BusWidth;

View file

@ -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(
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);

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