Fix SDMMC v2 and add H7 example
This commit is contained in:
parent
48fc48ea7d
commit
8a8e5c4b73
@ -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,15 +1148,14 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut status;
|
let mut status;
|
||||||
@ -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);
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(sdmmc_v1)] {
|
||||||
dma_trait!(SdioDma, Instance);
|
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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
42
examples/stm32h7/src/bin/sdmmc.rs
Normal file
42
examples/stm32h7/src/bin/sdmmc.rs
Normal 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
|
Loading…
Reference in New Issue
Block a user