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 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,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<T: Instance> {}
|
||||
impl<T: Instance> SdioDma<T> for NoDma {}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Pins<T: Instance>: sealed::Pins<T> + 'static {
|
||||
const BUSWIDTH: BusWidth;
|
||||
|
@ -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);
|
||||
|
||||
|
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