Merge branch 'master' into usb_msc

This commit is contained in:
chemicstry
2023-02-27 01:19:52 +02:00
142 changed files with 3965 additions and 1165 deletions

View File

@ -17,7 +17,7 @@ flavors = [
{ regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
{ regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" },
{ regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32f42.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" },
@ -58,7 +58,7 @@ cortex-m = "0.7.6"
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand_core = "0.6.3"
sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/thalesfragoso/embedded-sdmmc-rs", branch = "async", optional = true }
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "46d1b1c2ff13e31e282ec1e352421721694f126a", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] }
@ -77,7 +77,6 @@ stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features
[features]
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
sdmmc-rs = ["embedded-sdmmc"]
memory-x = ["stm32-metapac/memory-x"]
subghz = []
exti = []

View File

@ -192,6 +192,7 @@ mod low_level_api {
options.flow_ctrl == crate::dma::FlowControl::Dma,
"Peripheral flow control not supported"
);
assert!(options.fifo_threshold.is_none(), "FIFO mode not supported");
let ch = dma.ch(channel_number as _);

View File

@ -4,7 +4,7 @@ use core::task::Waker;
use embassy_cortex_m::interrupt::Priority;
use embassy_sync::waitqueue::AtomicWaker;
use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
use super::{Burst, FifoThreshold, FlowControl, Request, TransferOptions, Word, WordSize};
use crate::_generated::DMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac::dma::{regs, vals};
@ -40,6 +40,17 @@ impl From<FlowControl> for vals::Pfctrl {
}
}
impl From<FifoThreshold> for vals::Fth {
fn from(value: FifoThreshold) -> Self {
match value {
FifoThreshold::Quarter => vals::Fth::QUARTER,
FifoThreshold::Half => vals::Fth::HALF,
FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS,
FifoThreshold::Full => vals::Fth::FULL,
}
}
}
struct ChannelState {
waker: AtomicWaker,
}
@ -236,6 +247,16 @@ mod low_level_api {
ch.par().write_value(peri_addr as u32);
ch.m0ar().write_value(mem_addr as u32);
ch.ndtr().write_value(regs::Ndtr(mem_len as _));
ch.fcr().write(|w| {
if let Some(fth) = options.fifo_threshold {
// FIFO mode
w.set_dmdis(vals::Dmdis::DISABLED);
w.set_fth(fth.into());
} else {
// Direct mode
w.set_dmdis(vals::Dmdis::ENABLED);
}
});
ch.cr().write(|w| {
w.set_dir(dir);
w.set_msize(data_size);
@ -411,12 +432,8 @@ mod low_level_api {
}
if isr.tcif(channel_num % 4) && cr.read().tcie() {
if cr.read().dbm() == vals::Dbm::DISABLED {
cr.write(|_| ()); // Disable channel with the default value.
} else {
// for double buffered mode, clear TCIF flag but do not stop the transfer
dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
}
/* acknowledge transfer complete interrupt */
dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
STATE.channels[state_index].waker.wake();
}
}

View File

@ -176,8 +176,16 @@ mod low_level_api {
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
_options: TransferOptions,
options: TransferOptions,
) {
assert!(options.mburst == crate::dma::Burst::Single, "Burst mode not supported");
assert!(options.pburst == crate::dma::Burst::Single, "Burst mode not supported");
assert!(
options.flow_ctrl == crate::dma::FlowControl::Dma,
"Peripheral flow control not supported"
);
assert!(options.fifo_threshold.is_none(), "FIFO mode not supported");
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::SeqCst);

View File

@ -186,6 +186,19 @@ pub enum FlowControl {
Peripheral,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FifoThreshold {
/// 1/4 full FIFO
Quarter,
/// 1/2 full FIFO
Half,
/// 3/4 full FIFO
ThreeQuarters,
/// Full FIFO
Full,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TransferOptions {
@ -195,6 +208,8 @@ pub struct TransferOptions {
pub mburst: Burst,
/// Flow control configuration
pub flow_ctrl: FlowControl,
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
pub fifo_threshold: Option<FifoThreshold>,
}
impl Default for TransferOptions {
@ -203,6 +218,7 @@ impl Default for TransferOptions {
pburst: Burst::Single,
mburst: Burst::Single,
flow_ctrl: FlowControl::Dma,
fifo_threshold: None,
}
}
}
@ -257,6 +273,7 @@ mod transfers {
Transfer::new(channel)
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct Transfer<'a, C: Channel> {
channel: PeripheralRef<'a, C>,
}

View File

@ -198,6 +198,7 @@ mod eha {
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct ExtiInputFuture<'a> {
pin: u8,
phantom: PhantomData<&'a mut AnyPin>,

View File

@ -6,9 +6,6 @@ use crate::gpio::sealed::AFType;
use crate::gpio::{Pull, Speed};
use crate::Peripheral;
mod pins;
pub use pins::*;
pub struct Fmc<'d, T: Instance> {
peri: PhantomData<&'d mut T>,
}
@ -19,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
where
T: Instance,
{
const REGISTERS: *const () = crate::pac::FMC.0 as *const _;
const REGISTERS: *const () = T::REGS.0 as *const _;
fn enable(&mut self) {
<T as crate::rcc::sealed::RccPeripheral>::enable();
@ -27,9 +24,13 @@ where
}
fn memory_controller_enable(&mut self) {
// The FMCEN bit of the FMC_BCR2..4 registers is dont
// care. It is only enabled through the FMC_BCR1 register.
unsafe { T::regs().bcr1().modify(|r| r.set_fmcen(true)) };
// fmc v1 and v2 does not have the fmcen bit
// fsmc v1, v2 and v3 does not have the fmcen bit
// This is a "not" because it is expected that all future versions have this bit
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
unsafe {
T::REGS.bcr1().modify(|r| r.set_fmcen(true))
};
}
fn source_clock_hz(&self) -> u32 {
@ -107,6 +108,24 @@ impl<'d, T: Instance> Fmc<'d, T> {
]
));
fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank2: (
bank: stm32_fmc::SdramTargetBank::Bank2,
addr: [
(a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin)
],
ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
d: [
(d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
(d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
],
nbl: [
(nbl0: NBL0Pin), (nbl1: NBL1Pin)
],
ctrl: [
(sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
]
));
fmc_sdram_constructor!(sdram_a12bits_d32bits_4banks_bank2: (
bank: stm32_fmc::SdramTargetBank::Bank2,
addr: [
@ -128,13 +147,130 @@ impl<'d, T: Instance> Fmc<'d, T> {
));
}
pub(crate) mod sealed {
pub trait Instance: crate::rcc::sealed::RccPeripheral {
const REGS: crate::pac::fmc::Fmc;
}
}
pub trait Instance: sealed::Instance + 'static {}
foreach_peripheral!(
(fmc, $inst:ident) => {
impl crate::fmc::sealed::Instance for crate::peripherals::$inst {
fn regs() -> stm32_metapac::fmc::Fmc {
crate::pac::$inst
}
const REGS: crate::pac::fmc::Fmc = crate::pac::$inst;
}
impl crate::fmc::Instance for crate::peripherals::$inst {}
};
);
pin_trait!(SDNWEPin, Instance);
pin_trait!(SDNCASPin, Instance);
pin_trait!(SDNRASPin, Instance);
pin_trait!(SDNE0Pin, Instance);
pin_trait!(SDNE1Pin, Instance);
pin_trait!(SDCKE0Pin, Instance);
pin_trait!(SDCKE1Pin, Instance);
pin_trait!(SDCLKPin, Instance);
pin_trait!(NBL0Pin, Instance);
pin_trait!(NBL1Pin, Instance);
pin_trait!(NBL2Pin, Instance);
pin_trait!(NBL3Pin, Instance);
pin_trait!(INTPin, Instance);
pin_trait!(NLPin, Instance);
pin_trait!(NWaitPin, Instance);
pin_trait!(NE1Pin, Instance);
pin_trait!(NE2Pin, Instance);
pin_trait!(NE3Pin, Instance);
pin_trait!(NE4Pin, Instance);
pin_trait!(NCEPin, Instance);
pin_trait!(NOEPin, Instance);
pin_trait!(NWEPin, Instance);
pin_trait!(ClkPin, Instance);
pin_trait!(BA0Pin, Instance);
pin_trait!(BA1Pin, Instance);
pin_trait!(D0Pin, Instance);
pin_trait!(D1Pin, Instance);
pin_trait!(D2Pin, Instance);
pin_trait!(D3Pin, Instance);
pin_trait!(D4Pin, Instance);
pin_trait!(D5Pin, Instance);
pin_trait!(D6Pin, Instance);
pin_trait!(D7Pin, Instance);
pin_trait!(D8Pin, Instance);
pin_trait!(D9Pin, Instance);
pin_trait!(D10Pin, Instance);
pin_trait!(D11Pin, Instance);
pin_trait!(D12Pin, Instance);
pin_trait!(D13Pin, Instance);
pin_trait!(D14Pin, Instance);
pin_trait!(D15Pin, Instance);
pin_trait!(D16Pin, Instance);
pin_trait!(D17Pin, Instance);
pin_trait!(D18Pin, Instance);
pin_trait!(D19Pin, Instance);
pin_trait!(D20Pin, Instance);
pin_trait!(D21Pin, Instance);
pin_trait!(D22Pin, Instance);
pin_trait!(D23Pin, Instance);
pin_trait!(D24Pin, Instance);
pin_trait!(D25Pin, Instance);
pin_trait!(D26Pin, Instance);
pin_trait!(D27Pin, Instance);
pin_trait!(D28Pin, Instance);
pin_trait!(D29Pin, Instance);
pin_trait!(D30Pin, Instance);
pin_trait!(D31Pin, Instance);
pin_trait!(DA0Pin, Instance);
pin_trait!(DA1Pin, Instance);
pin_trait!(DA2Pin, Instance);
pin_trait!(DA3Pin, Instance);
pin_trait!(DA4Pin, Instance);
pin_trait!(DA5Pin, Instance);
pin_trait!(DA6Pin, Instance);
pin_trait!(DA7Pin, Instance);
pin_trait!(DA8Pin, Instance);
pin_trait!(DA9Pin, Instance);
pin_trait!(DA10Pin, Instance);
pin_trait!(DA11Pin, Instance);
pin_trait!(DA12Pin, Instance);
pin_trait!(DA13Pin, Instance);
pin_trait!(DA14Pin, Instance);
pin_trait!(DA15Pin, Instance);
pin_trait!(A0Pin, Instance);
pin_trait!(A1Pin, Instance);
pin_trait!(A2Pin, Instance);
pin_trait!(A3Pin, Instance);
pin_trait!(A4Pin, Instance);
pin_trait!(A5Pin, Instance);
pin_trait!(A6Pin, Instance);
pin_trait!(A7Pin, Instance);
pin_trait!(A8Pin, Instance);
pin_trait!(A9Pin, Instance);
pin_trait!(A10Pin, Instance);
pin_trait!(A11Pin, Instance);
pin_trait!(A12Pin, Instance);
pin_trait!(A13Pin, Instance);
pin_trait!(A14Pin, Instance);
pin_trait!(A15Pin, Instance);
pin_trait!(A16Pin, Instance);
pin_trait!(A17Pin, Instance);
pin_trait!(A18Pin, Instance);
pin_trait!(A19Pin, Instance);
pin_trait!(A20Pin, Instance);
pin_trait!(A21Pin, Instance);
pin_trait!(A22Pin, Instance);
pin_trait!(A23Pin, Instance);
pin_trait!(A24Pin, Instance);
pin_trait!(A25Pin, Instance);

View File

@ -1,118 +0,0 @@
pub(crate) mod sealed {
pub trait Instance: crate::rcc::sealed::RccPeripheral {
fn regs() -> crate::pac::fmc::Fmc;
}
}
pub trait Instance: sealed::Instance + 'static {}
pin_trait!(SDNWEPin, Instance);
pin_trait!(SDNCASPin, Instance);
pin_trait!(SDNRASPin, Instance);
pin_trait!(SDNE0Pin, Instance);
pin_trait!(SDNE1Pin, Instance);
pin_trait!(SDCKE0Pin, Instance);
pin_trait!(SDCKE1Pin, Instance);
pin_trait!(SDCLKPin, Instance);
pin_trait!(NBL0Pin, Instance);
pin_trait!(NBL1Pin, Instance);
pin_trait!(NBL2Pin, Instance);
pin_trait!(NBL3Pin, Instance);
pin_trait!(INTPin, Instance);
pin_trait!(NLPin, Instance);
pin_trait!(NWaitPin, Instance);
pin_trait!(NE1Pin, Instance);
pin_trait!(NE2Pin, Instance);
pin_trait!(NE3Pin, Instance);
pin_trait!(NE4Pin, Instance);
pin_trait!(NCEPin, Instance);
pin_trait!(NOEPin, Instance);
pin_trait!(NWEPin, Instance);
pin_trait!(ClkPin, Instance);
pin_trait!(BA0Pin, Instance);
pin_trait!(BA1Pin, Instance);
pin_trait!(D0Pin, Instance);
pin_trait!(D1Pin, Instance);
pin_trait!(D2Pin, Instance);
pin_trait!(D3Pin, Instance);
pin_trait!(D4Pin, Instance);
pin_trait!(D5Pin, Instance);
pin_trait!(D6Pin, Instance);
pin_trait!(D7Pin, Instance);
pin_trait!(D8Pin, Instance);
pin_trait!(D9Pin, Instance);
pin_trait!(D10Pin, Instance);
pin_trait!(D11Pin, Instance);
pin_trait!(D12Pin, Instance);
pin_trait!(D13Pin, Instance);
pin_trait!(D14Pin, Instance);
pin_trait!(D15Pin, Instance);
pin_trait!(D16Pin, Instance);
pin_trait!(D17Pin, Instance);
pin_trait!(D18Pin, Instance);
pin_trait!(D19Pin, Instance);
pin_trait!(D20Pin, Instance);
pin_trait!(D21Pin, Instance);
pin_trait!(D22Pin, Instance);
pin_trait!(D23Pin, Instance);
pin_trait!(D24Pin, Instance);
pin_trait!(D25Pin, Instance);
pin_trait!(D26Pin, Instance);
pin_trait!(D27Pin, Instance);
pin_trait!(D28Pin, Instance);
pin_trait!(D29Pin, Instance);
pin_trait!(D30Pin, Instance);
pin_trait!(D31Pin, Instance);
pin_trait!(DA0Pin, Instance);
pin_trait!(DA1Pin, Instance);
pin_trait!(DA2Pin, Instance);
pin_trait!(DA3Pin, Instance);
pin_trait!(DA4Pin, Instance);
pin_trait!(DA5Pin, Instance);
pin_trait!(DA6Pin, Instance);
pin_trait!(DA7Pin, Instance);
pin_trait!(DA8Pin, Instance);
pin_trait!(DA9Pin, Instance);
pin_trait!(DA10Pin, Instance);
pin_trait!(DA11Pin, Instance);
pin_trait!(DA12Pin, Instance);
pin_trait!(DA13Pin, Instance);
pin_trait!(DA14Pin, Instance);
pin_trait!(DA15Pin, Instance);
pin_trait!(A0Pin, Instance);
pin_trait!(A1Pin, Instance);
pin_trait!(A2Pin, Instance);
pin_trait!(A3Pin, Instance);
pin_trait!(A4Pin, Instance);
pin_trait!(A5Pin, Instance);
pin_trait!(A6Pin, Instance);
pin_trait!(A7Pin, Instance);
pin_trait!(A8Pin, Instance);
pin_trait!(A9Pin, Instance);
pin_trait!(A10Pin, Instance);
pin_trait!(A11Pin, Instance);
pin_trait!(A12Pin, Instance);
pin_trait!(A13Pin, Instance);
pin_trait!(A14Pin, Instance);
pin_trait!(A15Pin, Instance);
pin_trait!(A16Pin, Instance);
pin_trait!(A17Pin, Instance);
pin_trait!(A18Pin, Instance);
pin_trait!(A19Pin, Instance);
pin_trait!(A20Pin, Instance);
pin_trait!(A21Pin, Instance);
pin_trait!(A22Pin, Instance);
pin_trait!(A23Pin, Instance);
pin_trait!(A24Pin, Instance);
pin_trait!(A25Pin, Instance);

View File

@ -28,6 +28,21 @@ impl<'d, T: Pin> Flex<'d, T> {
Self { pin }
}
#[inline]
pub fn degrade(mut self) -> Flex<'d, AnyPin> {
// Safety: We are about to drop the other copy of this pin, so
// this clone is safe.
let pin = unsafe { self.pin.clone_unchecked() };
// We don't want to run the destructor here, because that would
// deconfigure the pin.
core::mem::forget(self);
Flex {
pin: pin.map_into::<AnyPin>(),
}
}
/// Put the pin into input mode.
#[inline]
pub fn set_as_input(&mut self, pull: Pull) {
@ -286,6 +301,13 @@ impl<'d, T: Pin> Input<'d, T> {
Self { pin }
}
#[inline]
pub fn degrade(self) -> Input<'d, AnyPin> {
Input {
pin: self.pin.degrade(),
}
}
#[inline]
pub fn is_high(&self) -> bool {
self.pin.is_high()
@ -345,6 +367,13 @@ impl<'d, T: Pin> Output<'d, T> {
Self { pin }
}
#[inline]
pub fn degrade(self) -> Output<'d, AnyPin> {
Output {
pin: self.pin.degrade(),
}
}
/// Set the output as high.
#[inline]
pub fn set_high(&mut self) {
@ -407,6 +436,13 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
Self { pin }
}
#[inline]
pub fn degrade(self) -> Output<'d, AnyPin> {
Output {
pin: self.pin.degrade(),
}
}
#[inline]
pub fn is_high(&self) -> bool {
!self.pin.is_low()

View File

@ -64,7 +64,7 @@ impl Into<u8> for APBPrescaler {
impl Into<u8> for AHBPrescaler {
fn into(self) -> u8 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::NotDivided => 0x0,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div3 => 0x01,
AHBPrescaler::Div4 => 0x09,

View File

@ -158,7 +158,7 @@ impl Into<u8> for APBPrescaler {
impl Into<u8> for AHBPrescaler {
fn into(self) -> u8 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::NotDivided => 0x0,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div3 => 0x01,
AHBPrescaler::Div4 => 0x09,

View File

@ -32,6 +32,11 @@ impl<'d, T: Instance> Rng<'d, T> {
}
pub fn reset(&mut self) {
// rng_v2 locks up on seed error, needs reset
#[cfg(rng_v2)]
if unsafe { T::regs().sr().read().seis() } {
T::reset();
}
unsafe {
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
@ -90,8 +95,10 @@ impl<'d, T: Instance> Rng<'d, T> {
impl<'d, T: Instance> RngCore for Rng<'d, T> {
fn next_u32(&mut self) -> u32 {
loop {
let bits = unsafe { T::regs().sr().read() };
if bits.drdy() {
let sr = unsafe { T::regs().sr().read() };
if sr.seis() | sr.ceis() {
self.reset();
} else if sr.drdy() {
return unsafe { T::regs().dr().read() };
}
}

View File

@ -2,6 +2,7 @@
use core::default::Default;
use core::future::poll_fn;
use core::ops::{Deref, DerefMut};
use core::task::Poll;
use embassy_hal_common::drop::OnDrop;
@ -40,7 +41,23 @@ impl Default for Signalling {
}
#[repr(align(4))]
pub struct DataBlock([u8; 512]);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DataBlock(pub [u8; 512]);
impl Deref for DataBlock {
type Target = [u8; 512];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for DataBlock {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// Errors
#[non_exhaustive]
@ -123,10 +140,21 @@ cfg_if::cfg_if! {
/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
/// `sdmmc_ck` in Hertz.
///
/// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
/// value and `clk_f` is the resulting new clock frequency.
fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u8, Hertz), Error> {
let clk_div = match ker_ck.0 / sdmmc_ck {
/// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1),
/// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency.
fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u8, Hertz), Error> {
// sdmmc_v1 maximum clock is 50 MHz
if sdmmc_ck > 50_000_000 {
return Err(Error::BadClock);
}
// bypass divisor
if ker_ck.0 <= sdmmc_ck {
return Ok((true, 0, ker_ck));
}
// `ker_ck / sdmmc_ck` rounded up
let clk_div = match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
0 | 1 => Ok(0),
x @ 2..=258 => {
Ok((x - 2) as u8)
@ -136,22 +164,24 @@ cfg_if::cfg_if! {
// SDIO_CK frequency = SDIOCLK / [CLKDIV + 2]
let clk_f = Hertz(ker_ck.0 / (clk_div as u32 + 2));
Ok((clk_div, clk_f))
Ok((false, clk_div, clk_f))
}
} else if #[cfg(sdmmc_v2)] {
/// Calculate clock divisor. Returns a SDMMC_CK less than or equal to
/// `sdmmc_ck` in Hertz.
///
/// Returns `(clk_div, clk_f)`, where `clk_div` is the divisor register
/// value and `clk_f` is the resulting new clock frequency.
fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(u16, Hertz), Error> {
/// Returns `(bypass, clk_div, clk_f)`, where `bypass` enables clock divisor bypass (only sdmmc_v1),
/// `clk_div` is the divisor register value and `clk_f` is the resulting new clock frequency.
fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> {
// `ker_ck / sdmmc_ck` rounded up
match (ker_ck.0 + sdmmc_ck - 1) / sdmmc_ck {
0 | 1 => Ok((0, ker_ck)),
0 | 1 => Ok((false, 0, ker_ck)),
x @ 2..=2046 => {
// SDMMC_CK frequency = SDMMCCLK / [CLKDIV + 2]
let clk_div = ((x + 1) / 2) as u16;
let clk = Hertz(ker_ck.0 / (clk_div as u32 * 2));
Ok((clk_div, clk))
Ok((false, clk_div, clk))
}
_ => Err(Error::BadClock),
}
@ -461,7 +491,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
bus_width,
&mut self.card,
&mut self.signalling,
T::frequency(),
T::kernel_clk(),
&mut self.clock,
T::state(),
self.config.data_transfer_timeout,
@ -570,6 +600,12 @@ impl SdmmcInner {
regs.clkcr().write(|w| {
w.set_pwrsav(false);
w.set_negedge(false);
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
// See chip erratas for more details.
#[cfg(sdmmc_v1)]
w.set_hwfc_en(false);
#[cfg(sdmmc_v2)]
w.set_hwfc_en(true);
#[cfg(sdmmc_v1)]
@ -602,7 +638,7 @@ impl SdmmcInner {
unsafe {
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be no more than 400 kHz.
let (clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
*clock = init_clock;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
@ -611,6 +647,8 @@ impl SdmmcInner {
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
@ -807,10 +845,16 @@ impl SdmmcInner {
let regs = self.0;
let on_drop = OnDrop::new(|| unsafe { self.on_drop() });
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
#[cfg(sdmmc_v1)]
self.cmd(Cmd::write_single_block(address), true)?;
unsafe {
self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9, data_transfer_timeout, dma);
self.data_interrupts(true);
}
#[cfg(sdmmc_v2)]
self.cmd(Cmd::write_single_block(address), true)?;
let res = poll_fn(|cx| {
@ -922,7 +966,9 @@ impl SdmmcInner {
let request = dma.request();
dma.start_read(request, regs.fifor().ptr() as *const u32, buffer, crate::dma::TransferOptions {
pburst: crate::dma::Burst::Incr4,
mburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral,
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
..Default::default()
});
} else if #[cfg(sdmmc_v2)] {
@ -970,7 +1016,9 @@ impl SdmmcInner {
let request = dma.request();
dma.start_write(request, buffer, regs.fifor().ptr() as *mut u32, crate::dma::TransferOptions {
pburst: crate::dma::Burst::Incr4,
mburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral,
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
..Default::default()
});
} else if #[cfg(sdmmc_v2)] {
@ -982,6 +1030,11 @@ impl SdmmcInner {
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(false);
#[cfg(sdmmc_v1)]
{
w.set_dmaen(true);
w.set_dten(true);
}
});
}
@ -1014,7 +1067,8 @@ impl SdmmcInner {
_ => panic!("Invalid Bus Width"),
};
let (clkdiv, new_clock) = clk_div(ker_ck, freq)?;
let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?;
// Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
// Section 55.5.8
let sdmmc_bus_bandwidth = new_clock.0 * width_u32;
@ -1025,7 +1079,11 @@ impl SdmmcInner {
unsafe {
// CPSMACT and DPSMACT must be 0 to set CLKDIV
self.wait_idle();
regs.clkcr().modify(|w| w.set_clkdiv(clkdiv));
regs.clkcr().modify(|w| {
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
}
Ok(())
@ -1114,7 +1172,6 @@ impl SdmmcInner {
}
/// Query the card status (CMD13, returns R1)
///
fn read_status(&self, card: &Card) -> Result<CardStatus, Error> {
let regs = self.0;
let rca = card.rca;
@ -1485,6 +1542,7 @@ pub(crate) mod sealed {
fn inner() -> SdmmcInner;
fn state() -> &'static AtomicWaker;
fn kernel_clk() -> Hertz;
}
pub trait Pins<T: Instance> {}
@ -1512,6 +1570,61 @@ cfg_if::cfg_if! {
}
}
cfg_if::cfg_if! {
// TODO, these could not be implemented, because required clocks are not exposed in RCC:
// - H7 uses pll1_q_ck or pll2_r_ck depending on SDMMCSEL
// - L1 uses pll48
// - L4 uses clk48(pll48)
// - L4+, L5, U5 uses clk48(pll48) or PLLSAI3CLK(PLLP) depending on SDMMCSEL
if #[cfg(stm32f1)] {
// F1 uses AHB1(HCLK), which is correct in PAC
macro_rules! kernel_clk {
($inst:ident) => {
<peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
}
}
} else if #[cfg(any(stm32f2, stm32f4))] {
// F2, F4 always use pll48
macro_rules! kernel_clk {
($inst:ident) => {
critical_section::with(|_| unsafe {
crate::rcc::get_freqs().pll48
}).expect("PLL48 is required for SDIO")
}
}
} else if #[cfg(stm32f7)] {
macro_rules! kernel_clk {
(SDMMC1) => {
critical_section::with(|_| unsafe {
let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc1sel();
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
crate::rcc::get_freqs().sys
} else {
crate::rcc::get_freqs().pll48.expect("PLL48 is required for SDMMC")
}
})
};
(SDMMC2) => {
critical_section::with(|_| unsafe {
let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc2sel();
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYSCLK {
crate::rcc::get_freqs().sys
} else {
crate::rcc::get_freqs().pll48.expect("PLL48 is required for SDMMC")
}
})
};
}
} else {
// Use default peripheral clock and hope it works
macro_rules! kernel_clk {
($inst:ident) => {
<peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
}
}
}
}
foreach_peripheral!(
(sdmmc, $inst:ident) => {
impl sealed::Instance for peripherals::$inst {
@ -1526,13 +1639,17 @@ foreach_peripheral!(
static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
&WAKER
}
fn kernel_clk() -> Hertz {
kernel_clk!($inst)
}
}
impl Instance for peripherals::$inst {}
};
);
#[cfg(feature = "sdmmc-rs")]
#[cfg(feature = "embedded-sdmmc")]
mod sdmmc_rs {
use core::future::Future;
@ -1540,7 +1657,7 @@ mod sdmmc_rs {
use super::*;
impl<'d, T: Instance, P: Pins<T>> BlockDevice for Sdmmc<'d, T, P> {
impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> {
type Error = Error;
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
@ -1558,19 +1675,14 @@ mod sdmmc_rs {
_reason: &str,
) -> Self::ReadFuture<'a> {
async move {
let card_capacity = self.card()?.card_type;
let inner = T::inner();
let state = T::state();
let mut address = start_block_idx.0;
for block in blocks.iter_mut() {
let block: &mut [u8; 512] = &mut block.contents;
// NOTE(unsafe) Block uses align(4)
let buf = unsafe { &mut *(block as *mut [u8; 512] as *mut [u32; 128]) };
inner
.read_block(address, buf, card_capacity, state, self.config.data_transfer_timeout)
.await?;
let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) };
self.read_block(address, block).await?;
address += 1;
}
Ok(())
@ -1579,19 +1691,14 @@ mod sdmmc_rs {
fn write<'a>(&'a mut self, blocks: &'a [Block], start_block_idx: BlockIdx) -> Self::WriteFuture<'a> {
async move {
let card = self.card.as_mut().ok_or(Error::NoCard)?;
let inner = T::inner();
let state = T::state();
let mut address = start_block_idx.0;
for block in blocks.iter() {
let block: &[u8; 512] = &block.contents;
// NOTE(unsafe) DataBlock uses align 4
let buf = unsafe { &*(block as *const [u8; 512] as *const [u32; 128]) };
inner
.write_block(address, buf, card, state, self.config.data_transfer_timeout)
.await?;
let block = unsafe { &*(block as *const _ as *const DataBlock) };
self.write_block(address, block).await?;
address += 1;
}
Ok(())

View File

@ -10,7 +10,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
use self::sealed::WordSize;
use crate::dma::{slice_ptr_parts, Transfer};
use crate::gpio::sealed::{AFType, Pin as _};
use crate::gpio::AnyPin;
use crate::gpio::{AnyPin, Pull};
use crate::pac::spi::{regs, vals, Spi as Regs};
use crate::rcc::RccPeripheral;
use crate::time::Hertz;
@ -93,8 +93,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
config: Config,
) -> Self {
into_ref!(peri, sck, mosi, miso);
let sck_pull_mode = match config.mode.polarity {
Polarity::IdleLow => Pull::Down,
Polarity::IdleHigh => Pull::Up,
};
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
mosi.set_speed(crate::gpio::Speed::VeryHigh);

View File

@ -770,7 +770,14 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable
unsafe {
r.brr().write_value(regs::Brr(div));
r.cr2().write(|_w| {});
r.cr2().write(|w| {
w.set_stop(match config.stop_bits {
StopBits::STOP0P5 => vals::Stop::STOP0P5,
StopBits::STOP1 => vals::Stop::STOP1,
StopBits::STOP1P5 => vals::Stop::STOP1P5,
StopBits::STOP2 => vals::Stop::STOP2,
});
});
r.cr1().write(|w| {
// enable uart
w.set_ue(true);
@ -1148,7 +1155,7 @@ macro_rules! impl_lpuart {
foreach_interrupt!(
($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => {
impl_lpuart!($inst, $irq, 255);
impl_lpuart!($inst, $irq, 256);
};
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {

View File

@ -268,13 +268,13 @@ impl<'d, T: Instance> Driver<'d, T> {
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Endpoint<'d, T, D>, driver::EndpointAllocError> {
trace!(
"allocating type={:?} mps={:?} interval={}, dir={:?}",
"allocating type={:?} mps={:?} interval_ms={}, dir={:?}",
ep_type,
max_packet_size,
interval,
interval_ms,
D::dir()
);
@ -345,7 +345,7 @@ impl<'d, T: Instance> Driver<'d, T> {
addr: EndpointAddress::from_parts(index, D::dir()),
ep_type,
max_packet_size,
interval,
interval_ms,
},
buf,
})
@ -362,18 +362,18 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
self.alloc_endpoint(ep_type, max_packet_size, interval)
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
}
fn alloc_endpoint_out(
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
self.alloc_endpoint(ep_type, max_packet_size, interval)
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
}
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {

View File

@ -217,13 +217,13 @@ impl<'d, T: Instance> Driver<'d, T> {
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Endpoint<'d, T, D>, EndpointAllocError> {
trace!(
"allocating type={:?} mps={:?} interval={}, dir={:?}",
"allocating type={:?} mps={:?} interval_ms={}, dir={:?}",
ep_type,
max_packet_size,
interval,
interval_ms,
D::dir()
);
@ -292,7 +292,7 @@ impl<'d, T: Instance> Driver<'d, T> {
addr: EndpointAddress::from_parts(index, D::dir()),
ep_type,
max_packet_size,
interval,
interval_ms,
},
})
}
@ -308,18 +308,18 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Self::EndpointIn, EndpointAllocError> {
self.alloc_endpoint(ep_type, max_packet_size, interval)
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
}
fn alloc_endpoint_out(
&mut self,
ep_type: EndpointType,
max_packet_size: u16,
interval: u8,
interval_ms: u8,
) -> Result<Self::EndpointOut, EndpointAllocError> {
self.alloc_endpoint(ep_type, max_packet_size, interval)
self.alloc_endpoint(ep_type, max_packet_size, interval_ms)
}
fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {