Rebase on master

This commit is contained in:
Mathias
2023-02-13 14:55:15 +01:00
410 changed files with 25743 additions and 7098 deletions

View File

@ -17,8 +17,9 @@ 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" },
{ regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
@ -39,12 +40,12 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9", optional = true}
embedded-hal-async = { version = "=0.1.0-alpha.2", optional = true}
embedded-hal-async = { version = "=0.2.0-alpha.0", optional = true}
embedded-hal-nb = { version = "=1.0.0-alpha.1", optional = true}
embedded-storage = "0.3.0"
@ -57,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"] }
@ -67,7 +68,7 @@ nb = "1.0.0"
stm32-fmc = "0.2.4"
seq-macro = "0.3.0"
cfg-if = "1.0.0"
embedded-io = { version = "0.3.0", features = ["async"], optional = true }
embedded-io = { version = "0.4.0", features = ["async"], optional = true }
chrono = { version = "^0.4", default-features = false, optional = true}
[build-dependencies]
@ -76,16 +77,17 @@ quote = "1.0.15"
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
[features]
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt"]
sdmmc-rs = ["embedded-sdmmc"]
net = ["embassy-net" ]
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"]
memory-x = ["stm32-metapac/memory-x"]
subghz = []
exti = []
# Enables additional driver features that depend on embassy-time
time = ["dep:embassy-time"]
# Features starting with `_` are for internal use only. They're not intended
# to be enabled by other crates, and are not covered by semver guarantees.
_time-driver = ["dep:embassy-time"]
_time-driver = ["time"]
time-driver-any = ["_time-driver"]
time-driver-tim2 = ["_time-driver"]
time-driver-tim3 = ["_time-driver"]
@ -109,6 +111,19 @@ unstable-traits = ["embedded-hal-1", "dep:embedded-hal-nb"]
# BEGIN GENERATED FEATURES
# Generated by stm32-gen-features. DO NOT EDIT.
stm32c011d6 = [ "stm32-metapac/stm32c011d6" ]
stm32c011f4 = [ "stm32-metapac/stm32c011f4" ]
stm32c011f6 = [ "stm32-metapac/stm32c011f6" ]
stm32c011j4 = [ "stm32-metapac/stm32c011j4" ]
stm32c011j6 = [ "stm32-metapac/stm32c011j6" ]
stm32c031c4 = [ "stm32-metapac/stm32c031c4" ]
stm32c031c6 = [ "stm32-metapac/stm32c031c6" ]
stm32c031f4 = [ "stm32-metapac/stm32c031f4" ]
stm32c031f6 = [ "stm32-metapac/stm32c031f6" ]
stm32c031g4 = [ "stm32-metapac/stm32c031g4" ]
stm32c031g6 = [ "stm32-metapac/stm32c031g6" ]
stm32c031k4 = [ "stm32-metapac/stm32c031k4" ]
stm32c031k6 = [ "stm32-metapac/stm32c031k6" ]
stm32f030c6 = [ "stm32-metapac/stm32f030c6" ]
stm32f030c8 = [ "stm32-metapac/stm32f030c8" ]
stm32f030cc = [ "stm32-metapac/stm32f030cc" ]
@ -1317,11 +1332,9 @@ stm32u575zi = [ "stm32-metapac/stm32u575zi" ]
stm32u585ai = [ "stm32-metapac/stm32u585ai" ]
stm32u585ci = [ "stm32-metapac/stm32u585ci" ]
stm32u585oi = [ "stm32-metapac/stm32u585oi" ]
stm32u585qe = [ "stm32-metapac/stm32u585qe" ]
stm32u585qi = [ "stm32-metapac/stm32u585qi" ]
stm32u585ri = [ "stm32-metapac/stm32u585ri" ]
stm32u585vi = [ "stm32-metapac/stm32u585vi" ]
stm32u585ze = [ "stm32-metapac/stm32u585ze" ]
stm32u585zi = [ "stm32-metapac/stm32u585zi" ]
stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
@ -1339,7 +1352,6 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ]
stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ]
stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ]
stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ]
stm32wb5mmg = [ "stm32-metapac/stm32wb5mmg" ]
stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ]
stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ]
stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ]
@ -1348,8 +1360,6 @@ stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4" ]
stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p" ]
stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4" ]
stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p" ]
stm32wl55uc-cm4 = [ "stm32-metapac/stm32wl55uc-cm4" ]
stm32wl55uc-cm0p = [ "stm32-metapac/stm32wl55uc-cm0p" ]
stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ]
stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ]
stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ]
@ -1362,6 +1372,4 @@ stm32wle5cc = [ "stm32-metapac/stm32wle5cc" ]
stm32wle5j8 = [ "stm32-metapac/stm32wle5j8" ]
stm32wle5jb = [ "stm32-metapac/stm32wle5jb" ]
stm32wle5jc = [ "stm32-metapac/stm32wle5jc" ]
stm32wle5u8 = [ "stm32-metapac/stm32wle5u8" ]
stm32wle5ub = [ "stm32-metapac/stm32wle5ub" ]
# END GENERATED FEATURES

View File

@ -244,11 +244,13 @@ fn main() {
(("usart", "CTS"), quote!(crate::usart::CtsPin)),
(("usart", "RTS"), quote!(crate::usart::RtsPin)),
(("usart", "CK"), quote!(crate::usart::CkPin)),
(("usart", "DE"), quote!(crate::usart::DePin)),
(("lpuart", "TX"), quote!(crate::usart::TxPin)),
(("lpuart", "RX"), quote!(crate::usart::RxPin)),
(("lpuart", "CTS"), quote!(crate::usart::CtsPin)),
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
(("lpuart", "DE"), quote!(crate::usart::DePin)),
(("spi", "SCK"), quote!(crate::spi::SckPin)),
(("spi", "MOSI"), quote!(crate::spi::MosiPin)),
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
@ -275,22 +277,20 @@ fn main() {
(("dcmi", "PIXCLK"), quote!(crate::dcmi::PixClkPin)),
(("usb", "DP"), quote!(crate::usb::DpPin)),
(("usb", "DM"), quote!(crate::usb::DmPin)),
(("otgfs", "DP"), quote!(crate::usb_otg::DpPin)),
(("otgfs", "DM"), quote!(crate::usb_otg::DmPin)),
(("otghs", "DP"), quote!(crate::usb_otg::DpPin)),
(("otghs", "DM"), quote!(crate::usb_otg::DmPin)),
(("otghs", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)),
(("otghs", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)),
(("otghs", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)),
(("otghs", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)),
(("otghs", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)),
(("otghs", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)),
(("otghs", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)),
(("otghs", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)),
(("otghs", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)),
(("otghs", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)),
(("otghs", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)),
(("otghs", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)),
(("otg", "DP"), quote!(crate::usb_otg::DpPin)),
(("otg", "DM"), quote!(crate::usb_otg::DmPin)),
(("otg", "ULPI_CK"), quote!(crate::usb_otg::UlpiClkPin)),
(("otg", "ULPI_DIR"), quote!(crate::usb_otg::UlpiDirPin)),
(("otg", "ULPI_NXT"), quote!(crate::usb_otg::UlpiNxtPin)),
(("otg", "ULPI_STP"), quote!(crate::usb_otg::UlpiStpPin)),
(("otg", "ULPI_D0"), quote!(crate::usb_otg::UlpiD0Pin)),
(("otg", "ULPI_D1"), quote!(crate::usb_otg::UlpiD1Pin)),
(("otg", "ULPI_D2"), quote!(crate::usb_otg::UlpiD2Pin)),
(("otg", "ULPI_D3"), quote!(crate::usb_otg::UlpiD3Pin)),
(("otg", "ULPI_D4"), quote!(crate::usb_otg::UlpiD4Pin)),
(("otg", "ULPI_D5"), quote!(crate::usb_otg::UlpiD5Pin)),
(("otg", "ULPI_D6"), quote!(crate::usb_otg::UlpiD6Pin)),
(("otg", "ULPI_D7"), quote!(crate::usb_otg::UlpiD7Pin)),
(("can", "TX"), quote!(crate::can::TxPin)),
(("can", "RX"), quote!(crate::can::RxPin)),
(("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),

View File

@ -1,9 +1,7 @@
use core::marker::PhantomData;
use embassy_hal_common::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use crate::adc::{AdcPin, Instance};
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
use crate::rcc::get_freqs;
use crate::time::Hertz;
use crate::Peripheral;
@ -29,70 +27,9 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
}
}
mod sample_time {
/// ADC sample time
///
/// The default setting is 1.5 ADC clock cycles.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
/// 1.5 ADC clock cycles
Cycles1_5 = 0b000,
/// 7.5 ADC clock cycles
Cycles7_5 = 0b001,
/// 13.5 ADC clock cycles
Cycles13_5 = 0b010,
/// 28.5 ADC clock cycles
Cycles28_5 = 0b011,
/// 41.5 ADC clock cycles
Cycles41_5 = 0b100,
/// 55.5 ADC clock cycles
Cycles55_5 = 0b101,
/// 71.5 ADC clock cycles
Cycles71_5 = 0b110,
/// 239.5 ADC clock cycles
Cycles239_5 = 0b111,
}
impl SampleTime {
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
match self {
SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
SampleTime::Cycles13_5 => crate::pac::adc::vals::SampleTime::CYCLES13_5,
SampleTime::Cycles28_5 => crate::pac::adc::vals::SampleTime::CYCLES28_5,
SampleTime::Cycles41_5 => crate::pac::adc::vals::SampleTime::CYCLES41_5,
SampleTime::Cycles55_5 => crate::pac::adc::vals::SampleTime::CYCLES55_5,
SampleTime::Cycles71_5 => crate::pac::adc::vals::SampleTime::CYCLES71_5,
SampleTime::Cycles239_5 => crate::pac::adc::vals::SampleTime::CYCLES239_5,
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::Cycles28_5
}
}
}
pub use sample_time::SampleTime;
pub struct Adc<'d, T: Instance> {
sample_time: SampleTime,
calibrated_vdda: u32,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(_peri);
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc);
T::enable();
T::reset();
unsafe {
@ -121,9 +58,8 @@ impl<'d, T: Instance> Adc<'d, T> {
delay.delay_us((1_000_000) / Self::freq().0 + 1);
Self {
adc,
sample_time: Default::default(),
calibrated_vdda: VDDA_CALIB_MV,
phantom: PhantomData,
}
}
@ -162,29 +98,10 @@ impl<'d, T: Instance> Adc<'d, T> {
Temperature {}
}
/// Calculates the system VDDA by sampling the internal VREF channel and comparing
/// to the expected value. If the chip's VDDA is not stable, run this before each ADC
/// conversion.
pub fn calibrate(&mut self, vref: &mut Vref) -> u32 {
let old_sample_time = self.sample_time;
self.sample_time = SampleTime::Cycles239_5;
let vref_samp = self.read(vref);
self.sample_time = old_sample_time;
self.calibrated_vdda = (ADC_MAX * VREF_INT) / u32::from(vref_samp);
self.calibrated_vdda
}
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
self.sample_time = sample_time;
}
/// Convert a measurement to millivolts
pub fn to_millivolts(&self, sample: u16) -> u16 {
((u32::from(sample) * self.calibrated_vdda) / ADC_MAX) as u16
}
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
unsafe {
@ -222,14 +139,11 @@ impl<'d, T: Instance> Adc<'d, T> {
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs()
.smpr2()
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs()
.smpr1()
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
}
}

View File

@ -1,28 +1,38 @@
#![macro_use]
#[cfg_attr(adc_v4, path = "v4.rs")]
#[cfg_attr(adc_v3, path = "v3.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(adc_g0, path = "v3.rs")]
#[cfg_attr(adc_f1, path = "f1.rs")]
#[cfg_attr(adc_v1, path = "v1.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0), path = "v3.rs")]
#[cfg_attr(adc_v4, path = "v4.rs")]
mod _version;
#[cfg(not(any(adc_f1, adc_v1)))]
mod resolution;
#[cfg(not(adc_v1))]
mod sample_time;
#[allow(unused)]
pub use _version::*;
#[cfg(not(any(adc_f1, adc_v1)))]
pub use resolution::Resolution;
#[cfg(not(adc_v1))]
pub use sample_time::SampleTime;
use crate::peripherals;
#[cfg(not(adc_v1))]
pub struct Adc<'d, T: Instance> {
#[allow(unused)]
adc: crate::PeripheralRef<'d, T>,
sample_time: SampleTime,
}
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> &'static crate::pac::adc::Adc;
fn regs() -> crate::pac::adc::Adc;
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon;
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
pub trait Common {
fn regs() -> &'static crate::pac::adccommon::AdcCommon;
fn common_regs() -> crate::pac::adccommon::AdcCommon;
}
pub trait AdcPin<T: Instance> {
@ -34,12 +44,11 @@ pub(crate) mod sealed {
}
}
#[cfg(not(any(adc_f1, adc_v2)))]
pub trait Instance: sealed::Instance + 'static {}
#[cfg(any(adc_f1, adc_v2))]
pub trait Instance: sealed::Instance + crate::rcc::RccPeripheral + 'static {}
#[cfg(all(not(adc_f1), not(adc_v1)))]
pub trait Common: sealed::Common + 'static {}
#[cfg(not(any(adc_f1, adc_v2, adc_v4)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
#[cfg(any(adc_f1, adc_v2, adc_v4))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
@ -47,14 +56,14 @@ pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
foreach_peripheral!(
(adc, $inst:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {
fn regs() -> &'static crate::pac::adc::Adc {
&crate::pac::$inst
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, $common_inst:ident) => {
return &crate::pac::$common_inst
return crate::pac::$common_inst
};
}
}
@ -68,14 +77,14 @@ foreach_peripheral!(
foreach_peripheral!(
(adc, ADC3) => {
impl crate::adc::sealed::Instance for peripherals::ADC3 {
fn regs() -> &'static crate::pac::adc::Adc {
&crate::pac::ADC3
fn regs() -> crate::pac::adc::Adc {
crate::pac::ADC3
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, ADC3_COMMON) => {
return &crate::pac::ADC3_COMMON
return crate::pac::ADC3_COMMON
};
}
}
@ -85,14 +94,14 @@ foreach_peripheral!(
};
(adc, $inst:ident) => {
impl crate::adc::sealed::Instance for peripherals::$inst {
fn regs() -> &'static crate::pac::adc::Adc {
&crate::pac::$inst
fn regs() -> crate::pac::adc::Adc {
crate::pac::$inst
}
#[cfg(all(not(adc_f1), not(adc_v1)))]
fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
fn common_regs() -> crate::pac::adccommon::AdcCommon {
foreach_peripheral!{
(adccommon, ADC_COMMON) => {
return &crate::pac::ADC_COMMON
return crate::pac::ADC_COMMON
};
}
}
@ -102,19 +111,6 @@ foreach_peripheral!(
};
);
#[cfg(all(not(adc_f1), not(adc_v1)))]
foreach_peripheral!(
(adccommon, $inst:ident) => {
impl sealed::Common for peripherals::$inst {
fn regs() -> &'static crate::pac::adccommon::AdcCommon {
&crate::pac::$inst
}
}
impl crate::adc::Common for peripherals::$inst {}
};
);
macro_rules! impl_adc_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}

View File

@ -0,0 +1,63 @@
#[cfg(any(adc_v2, adc_v3, adc_g0))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Resolution {
TwelveBit,
TenBit,
EightBit,
SixBit,
}
#[cfg(adc_v4)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Resolution {
SixteenBit,
FourteenBit,
TwelveBit,
TenBit,
EightBit,
}
impl Default for Resolution {
fn default() -> Self {
#[cfg(any(adc_v2, adc_v3, adc_g0))]
{
Self::TwelveBit
}
#[cfg(adc_v4)]
{
Self::SixteenBit
}
}
}
impl From<Resolution> for crate::pac::adc::vals::Res {
fn from(res: Resolution) -> crate::pac::adc::vals::Res {
match res {
#[cfg(adc_v4)]
Resolution::SixteenBit => crate::pac::adc::vals::Res::SIXTEENBIT,
#[cfg(adc_v4)]
Resolution::FourteenBit => crate::pac::adc::vals::Res::FOURTEENBITV,
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
#[cfg(any(adc_v2, adc_v3, adc_g0))]
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
}
impl Resolution {
pub fn to_max_count(&self) -> u32 {
match self {
#[cfg(adc_v4)]
Resolution::SixteenBit => (1 << 16) - 1,
#[cfg(adc_v4)]
Resolution::FourteenBit => (1 << 14) - 1,
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
#[cfg(any(adc_v2, adc_v3, adc_g0))]
Resolution::SixBit => (1 << 6) - 1,
}
}
}

View File

@ -0,0 +1,111 @@
macro_rules! impl_sample_time {
($default_doc:expr, $default:ident, $pac:ty, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => {
#[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
$(
#[doc = concat!($doc, " ADC clock cycles.")]
$variant,
)*
}
impl From<SampleTime> for $pac {
fn from(sample_time: SampleTime) -> $pac {
match sample_time {
$(SampleTime::$variant => <$pac>::$pac_variant),*
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::$default
}
}
};
}
#[cfg(adc_f1)]
impl_sample_time!(
"1.5",
Cycles1_5,
crate::pac::adc::vals::SampleTime,
(
("1.5", Cycles1_5, CYCLES1_5),
("7.5", Cycles7_5, CYCLES7_5),
("13.5", Cycles13_5, CYCLES13_5),
("28.5", Cycles28_5, CYCLES28_5),
("41.5", Cycles41_5, CYCLES41_5),
("55.5", Cycles55_5, CYCLES55_5),
("71.5", Cycles71_5, CYCLES71_5),
("239.5", Cycles239_5, CYCLES239_5)
)
);
#[cfg(adc_v2)]
impl_sample_time!(
"3",
Cycles3,
crate::pac::adc::vals::Smp,
(
("3", Cycles3, CYCLES3),
("15", Cycles15, CYCLES15),
("28", Cycles28, CYCLES28),
("56", Cycles56, CYCLES56),
("84", Cycles84, CYCLES84),
("112", Cycles112, CYCLES112),
("144", Cycles144, CYCLES144),
("480", Cycles480, CYCLES480)
)
);
#[cfg(adc_v3)]
impl_sample_time!(
"2.5",
Cycles2_5,
crate::pac::adc::vals::SampleTime,
(
("2.5", Cycles2_5, CYCLES2_5),
("6.5", Cycles6_5, CYCLES6_5),
("12.5", Cycles12_5, CYCLES12_5),
("24.5", Cycles24_5, CYCLES24_5),
("47.5", Cycles47_5, CYCLES47_5),
("92.5", Cycles92_5, CYCLES92_5),
("247.5", Cycles247_5, CYCLES247_5),
("640.5", Cycles640_5, CYCLES640_5)
)
);
#[cfg(adc_g0)]
impl_sample_time!(
"1.5",
Cycles1_5,
crate::pac::adc::vals::SampleTime,
(
("1.5", Cycles1_5, CYCLES1_5),
("3.5", Cycles3_5, CYCLES3_5),
("7.5", Cycles7_5, CYCLES7_5),
("12.5", Cycles12_5, CYCLES12_5),
("19.5", Cycles19_5, CYCLES19_5),
("39.5", Cycles39_5, CYCLES39_5),
("79.5", Cycles79_5, CYCLES79_5),
("160.5", Cycles160_5, CYCLES160_5)
)
);
#[cfg(adc_v4)]
impl_sample_time!(
"1.5",
Cycles1_5,
crate::pac::adc::vals::Smp,
(
("1.5", Cycles1_5, CYCLES1_5),
("2.5", Cycles2_5, CYCLES2_5),
("8.5", Cycles8_5, CYCLES8_5),
("16.5", Cycles16_5, CYCLES16_5),
("32.5", Cycles32_5, CYCLES32_5),
("64.5", Cycles64_5, CYCLES64_5),
("387.5", Cycles387_5, CYCLES387_5),
("810.5", Cycles810_5, CYCLES810_5)
)
);

View File

@ -1,10 +1,8 @@
use core::marker::PhantomData;
use embassy_hal_common::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use super::InternalChannel;
use crate::adc::{AdcPin, Instance};
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::peripherals::ADC1;
use crate::time::Hertz;
use crate::Peripheral;
@ -17,39 +15,6 @@ pub const VREF_CALIB_MV: u32 = 3300;
/// ADC turn-on time
pub const ADC_POWERUP_TIME_US: u32 = 3;
pub enum Resolution {
TwelveBit,
TenBit,
EightBit,
SixBit,
}
impl Default for Resolution {
fn default() -> Self {
Self::TwelveBit
}
}
impl Resolution {
fn res(&self) -> crate::pac::adc::vals::Res {
match self {
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
pub fn to_max_count(&self) -> u32 {
match self {
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
Resolution::SixBit => (1 << 6) - 1,
}
}
}
pub struct VrefInt;
impl InternalChannel<ADC1> for VrefInt {}
impl super::sealed::InternalChannel<ADC1> for VrefInt {
@ -80,15 +45,6 @@ impl super::sealed::InternalChannel<ADC1> for Temperature {
}
impl Temperature {
/// Converts temperature sensor reading in millivolts to degrees celcius
pub fn to_celcius(sample_mv: u16) -> f32 {
// From 6.3.22 Temperature sensor characteristics
const V25: i32 = 760; // mV
const AVG_SLOPE: f32 = 2.5; // mV/C
(sample_mv as i32 - V25) as f32 / AVG_SLOPE + 25.0
}
/// Time needed for temperature sensor readings to stabilize
pub fn start_time_us() -> u32 {
10
@ -103,42 +59,6 @@ impl super::sealed::InternalChannel<ADC1> for Vbat {
}
}
/// ADC sample time
///
/// The default setting is 3 ADC clock cycles.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
Cycles3 = 0b000,
Cycles15 = 0b001,
Cycles28 = 0b010,
Cycles56 = 0b011,
Cycles85 = 0b100,
Cycles112 = 0b101,
Cycles144 = 0b110,
Cycles480 = 0b111,
}
impl SampleTime {
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::Smp {
match self {
SampleTime::Cycles3 => crate::pac::adc::vals::Smp::CYCLES3,
SampleTime::Cycles15 => crate::pac::adc::vals::Smp::CYCLES15,
SampleTime::Cycles28 => crate::pac::adc::vals::Smp::CYCLES28,
SampleTime::Cycles56 => crate::pac::adc::vals::Smp::CYCLES56,
SampleTime::Cycles85 => crate::pac::adc::vals::Smp::CYCLES84,
SampleTime::Cycles112 => crate::pac::adc::vals::Smp::CYCLES112,
SampleTime::Cycles144 => crate::pac::adc::vals::Smp::CYCLES144,
SampleTime::Cycles480 => crate::pac::adc::vals::Smp::CYCLES480,
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::Cycles3
}
}
enum Prescaler {
Div2,
Div4,
@ -170,19 +90,12 @@ impl Prescaler {
}
}
pub struct Adc<'d, T: Instance> {
sample_time: SampleTime,
vref_mv: u32,
resolution: Resolution,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T> Adc<'d, T>
where
T: Instance,
{
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(_peri);
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc);
T::enable();
T::reset();
@ -198,10 +111,8 @@ where
delay.delay_us(ADC_POWERUP_TIME_US);
Self {
adc,
sample_time: Default::default(),
resolution: Resolution::default(),
vref_mv: VREF_DEFAULT_MV,
phantom: PhantomData,
}
}
@ -210,19 +121,9 @@ where
}
pub fn set_resolution(&mut self, resolution: Resolution) {
self.resolution = resolution;
}
/// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
///
/// Use this if you have a known precise VREF (VDDA) pin reference voltage.
pub fn set_vref_mv(&mut self, vref_mv: u32) {
self.vref_mv = vref_mv;
}
/// Convert a measurement to millivolts
pub fn to_millivolts(&self, sample: u16) -> u16 {
((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
unsafe {
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
}
}
/// Enables internal voltage reference and returns [VrefInt], which can be used in
@ -306,7 +207,6 @@ where
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
// Configure ADC
T::regs().cr1().modify(|reg| reg.set_res(self.resolution.res()));
// Select channel
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
@ -320,14 +220,11 @@ where
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs()
.smpr2()
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs()
.smpr1()
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
}
}

View File

@ -1,9 +1,7 @@
use core::marker::PhantomData;
use embassy_hal_common::into_ref;
use embedded_hal_02::blocking::delay::DelayUs;
use crate::adc::{AdcPin, Instance};
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::Peripheral;
/// Default VREF voltage used for sample conversion to millivolts.
@ -24,39 +22,6 @@ fn enable() {
});
}
pub enum Resolution {
TwelveBit,
TenBit,
EightBit,
SixBit,
}
impl Default for Resolution {
fn default() -> Self {
Self::TwelveBit
}
}
impl Resolution {
fn res(&self) -> crate::pac::adc::vals::Res {
match self {
Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
}
}
pub fn to_max_count(&self) -> u32 {
match self {
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
Resolution::SixBit => (1 << 6) - 1,
}
}
}
pub struct VrefInt;
impl<T: Instance> AdcPin<T> for VrefInt {}
impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
@ -93,126 +58,9 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
}
}
#[cfg(not(adc_g0))]
mod sample_time {
/// ADC sample time
///
/// The default setting is 2.5 ADC clock cycles.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
/// 2.5 ADC clock cycles
Cycles2_5 = 0b000,
/// 6.5 ADC clock cycles
Cycles6_5 = 0b001,
/// 12.5 ADC clock cycles
Cycles12_5 = 0b010,
/// 24.5 ADC clock cycles
Cycles24_5 = 0b011,
/// 47.5 ADC clock cycles
Cycles47_5 = 0b100,
/// 92.5 ADC clock cycles
Cycles92_5 = 0b101,
/// 247.5 ADC clock cycles
Cycles247_5 = 0b110,
/// 640.5 ADC clock cycles
Cycles640_5 = 0b111,
}
impl SampleTime {
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
match self {
SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5,
SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5,
SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5,
SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5,
SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5,
SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5,
SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5,
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::Cycles2_5
}
}
}
#[cfg(adc_g0)]
mod sample_time {
/// ADC sample time
///
/// The default setting is 1.5 ADC clock cycles.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
/// 1.5 ADC clock cycles
Cycles1_5 = 0b000,
/// 3.5 ADC clock cycles
Cycles3_5 = 0b001,
/// 7.5 ADC clock cycles
Cycles7_5 = 0b010,
/// 12.5 ADC clock cycles
Cycles12_5 = 0b011,
/// 19.5 ADC clock cycles
Cycles19_5 = 0b100,
/// 39.5 ADC clock cycles
Cycles39_5 = 0b101,
/// 79.5 ADC clock cycles
Cycles79_5 = 0b110,
/// 160.5 ADC clock cycles
Cycles160_5 = 0b111,
}
impl SampleTime {
pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
match self {
SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5,
SampleTime::Cycles3_5 => crate::pac::adc::vals::SampleTime::CYCLES3_5,
SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5,
SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
SampleTime::Cycles19_5 => crate::pac::adc::vals::SampleTime::CYCLES19_5,
SampleTime::Cycles39_5 => crate::pac::adc::vals::SampleTime::CYCLES39_5,
SampleTime::Cycles79_5 => crate::pac::adc::vals::SampleTime::CYCLES79_5,
SampleTime::Cycles160_5 => crate::pac::adc::vals::SampleTime::CYCLES160_5,
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::Cycles1_5
}
}
}
pub use sample_time::SampleTime;
pub struct Adc<'d, T: Instance> {
sample_time: SampleTime,
vref_mv: u32,
resolution: Resolution,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(_peri);
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc);
enable();
unsafe {
T::regs().cr().modify(|reg| {
@ -223,7 +71,7 @@ impl<'d, T: Instance> Adc<'d, T> {
#[cfg(adc_g0)]
T::regs().cfgr1().modify(|reg| {
reg.set_chselrmod(true);
reg.set_chselrmod(false);
});
}
@ -242,10 +90,8 @@ impl<'d, T: Instance> Adc<'d, T> {
delay.delay_us(1);
Self {
adc,
sample_time: Default::default(),
resolution: Resolution::default(),
vref_mv: VREF_DEFAULT_MV,
phantom: PhantomData,
}
}
@ -285,49 +131,17 @@ impl<'d, T: Instance> Adc<'d, T> {
Vbat {}
}
/// Calculates the system VDDA by sampling the internal VREFINT channel and comparing
/// the result with the value stored at the factory. If the chip's VDDA is not stable, run
/// this before each ADC conversion.
#[cfg(not(stm32g0))] // TODO is this supposed to be public?
#[allow(unused)] // TODO is this supposed to be public?
fn calibrate(&mut self, vrefint: &mut VrefInt) {
#[cfg(stm32l5)]
let vrefint_cal: u32 = todo!();
#[cfg(not(stm32l5))]
let vrefint_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() };
let old_sample_time = self.sample_time;
// "Table 24. Embedded internal voltage reference" states that the sample time needs to be
// at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving
// some headroom.
self.sample_time = SampleTime::Cycles640_5;
// This can't actually fail, it's just in a result to satisfy hal trait
let vrefint_samp = self.read(vrefint);
self.sample_time = old_sample_time;
self.vref_mv = (VREF_CALIB_MV * u32::from(vrefint_cal)) / u32::from(vrefint_samp);
}
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
self.sample_time = sample_time;
}
pub fn set_resolution(&mut self, resolution: Resolution) {
self.resolution = resolution;
}
/// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
///
/// Use this if you have a known precise VREF (VDDA) pin reference voltage.
pub fn set_vref_mv(&mut self, vref_mv: u32) {
self.vref_mv = vref_mv;
}
/// Convert a measurement to millivolts
pub fn to_millivolts(&self, sample: u16) -> u16 {
((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
unsafe {
#[cfg(not(stm32g0))]
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
#[cfg(stm32g0)]
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
}
/*
@ -379,12 +193,6 @@ impl<'d, T: Instance> Adc<'d, T> {
// spin
}
// Configure ADC
#[cfg(not(stm32g0))]
T::regs().cfgr().modify(|reg| reg.set_res(self.resolution.res()));
#[cfg(stm32g0)]
T::regs().cfgr1().modify(|reg| reg.set_res(self.resolution.res()));
// Configure channel
Self::set_channel_sample_time(pin.channel(), self.sample_time);
@ -392,7 +200,7 @@ impl<'d, T: Instance> Adc<'d, T> {
#[cfg(not(stm32g0))]
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
#[cfg(stm32g0)]
T::regs().chselr().write(|reg| reg.set_chsel(pin.channel() as u32));
T::regs().chselr().write(|reg| reg.set_chsel(1 << pin.channel()));
// Some models are affected by an erratum:
// If we perform conversions slower than 1 kHz, the first read ADC value can be
@ -413,19 +221,16 @@ impl<'d, T: Instance> Adc<'d, T> {
#[cfg(stm32g0)]
unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.sample_time()));
T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
}
#[cfg(not(stm32g0))]
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs()
.smpr1()
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs()
.smpr2()
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
}
}

View File

@ -1,11 +1,10 @@
use core::marker::PhantomData;
use core::sync::atomic::{AtomicU8, Ordering};
use atomic_polyfill::{AtomicU8, Ordering};
use embedded_hal_02::blocking::delay::DelayUs;
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
use pac::adccommon::vals::Presc;
use super::{AdcPin, Instance, InternalChannel};
use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
use crate::time::Hertz;
use crate::{pac, Peripheral};
@ -14,42 +13,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3300;
pub enum Resolution {
SixteenBit,
FourteenBit,
TwelveBit,
TenBit,
EightBit,
}
impl Default for Resolution {
fn default() -> Self {
Self::SixteenBit
}
}
impl Resolution {
fn res(&self) -> pac::adc::vals::Res {
match self {
Resolution::SixteenBit => pac::adc::vals::Res::SIXTEENBIT,
Resolution::FourteenBit => pac::adc::vals::Res::FOURTEENBITV,
Resolution::TwelveBit => pac::adc::vals::Res::TWELVEBITV,
Resolution::TenBit => pac::adc::vals::Res::TENBIT,
Resolution::EightBit => pac::adc::vals::Res::EIGHTBIT,
}
}
pub fn to_max_count(&self) -> u32 {
match self {
Resolution::SixteenBit => (1 << 16) - 1,
Resolution::FourteenBit => (1 << 14) - 1,
Resolution::TwelveBit => (1 << 12) - 1,
Resolution::TenBit => (1 << 10) - 1,
Resolution::EightBit => (1 << 8) - 1,
}
}
}
// NOTE: Vrefint/Temperature/Vbat are only available on ADC3 on H7, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
pub struct VrefInt;
impl<T: Instance> InternalChannel<T> for VrefInt {}
@ -193,57 +156,6 @@ foreach_peripheral!(
};
);
/// ADC sample time
///
/// The default setting is 2.5 ADC clock cycles.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum SampleTime {
/// 1.5 ADC clock cycles
Cycles1_5,
/// 2.5 ADC clock cycles
Cycles2_5,
/// 8.5 ADC clock cycles
Cycles8_5,
/// 16.5 ADC clock cycles
Cycles16_5,
/// 32.5 ADC clock cycles
Cycles32_5,
/// 64.5 ADC clock cycles
Cycles64_5,
/// 387.5 ADC clock cycles
Cycles387_5,
/// 810.5 ADC clock cycles
Cycles810_5,
}
impl SampleTime {
pub(crate) fn sample_time(&self) -> pac::adc::vals::Smp {
match self {
SampleTime::Cycles1_5 => pac::adc::vals::Smp::CYCLES1_5,
SampleTime::Cycles2_5 => pac::adc::vals::Smp::CYCLES2_5,
SampleTime::Cycles8_5 => pac::adc::vals::Smp::CYCLES8_5,
SampleTime::Cycles16_5 => pac::adc::vals::Smp::CYCLES16_5,
SampleTime::Cycles32_5 => pac::adc::vals::Smp::CYCLES32_5,
SampleTime::Cycles64_5 => pac::adc::vals::Smp::CYCLES64_5,
SampleTime::Cycles387_5 => pac::adc::vals::Smp::CYCLES387_5,
SampleTime::Cycles810_5 => pac::adc::vals::Smp::CYCLES810_5,
}
}
}
impl Default for SampleTime {
fn default() -> Self {
Self::Cycles1_5
}
}
// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
#[allow(unused)]
@ -312,16 +224,9 @@ impl Prescaler {
}
}
pub struct Adc<'d, T: Instance> {
sample_time: SampleTime,
vref_mv: u32,
resolution: Resolution,
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
pub fn new(_peri: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
embassy_hal_common::into_ref!(_peri);
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
embassy_hal_common::into_ref!(adc);
T::enable();
T::reset();
@ -351,10 +256,8 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
}
let mut s = Self {
adc,
sample_time: Default::default(),
vref_mv: VREF_DEFAULT_MV,
resolution: Resolution::default(),
phantom: PhantomData,
};
s.power_up(delay);
s.configure_differential_inputs();
@ -456,19 +359,9 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
}
pub fn set_resolution(&mut self, resolution: Resolution) {
self.resolution = resolution;
}
/// Set VREF value in millivolts. This value is used for [to_millivolts()] sample conversion.
///
/// Use this if you have a known precise VREF (VDDA) pin reference voltage.
pub fn set_vref_mv(&mut self, vref_mv: u32) {
self.vref_mv = vref_mv;
}
/// Convert a measurement to millivolts
pub fn to_millivolts(&self, sample: u16) -> u16 {
((u32::from(sample) * self.vref_mv) / self.resolution.to_max_count()) as u16
unsafe {
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
}
}
/// Perform a single conversion.
@ -509,9 +402,6 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
}
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
// Configure ADC
T::regs().cfgr().modify(|reg| reg.set_res(self.resolution.res()));
// Configure channel
Self::set_channel_sample_time(channel, self.sample_time);
@ -528,14 +418,11 @@ impl<'d, T: Instance + crate::rcc::RccPeripheral> Adc<'d, T> {
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
if ch <= 9 {
T::regs()
.smpr(0)
.modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
} else {
T::regs()
.smpr(1)
.modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
}
}
}

View File

@ -3,6 +3,7 @@
use core::sync::atomic::{fence, Ordering};
use core::task::Waker;
use embassy_cortex_m::interrupt::Priority;
use embassy_sync::waitqueue::AtomicWaker;
use super::{TransferOptions, Word, WordSize};
@ -38,10 +39,12 @@ impl State {
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init() {
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::$irq::steal().enable();
let irq = crate::interrupt::$irq::steal();
irq.set_priority(irq_priority);
irq.enable();
};
}
crate::_generated::init_bdma();
@ -75,8 +78,7 @@ foreach_dma_channel! {
);
}
unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
let buf = [repeated];
unsafe fn start_write_repeated<W: Word>(&mut self, _request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) {
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
@ -84,7 +86,7 @@ foreach_dma_channel! {
_request,
vals::Dir::FROMMEMORY,
reg_addr as *const u32,
buf.as_ptr() as *mut u32,
repeated as *mut u32,
count,
false,
vals::Size::from(W::bits()),

View File

@ -1,6 +1,7 @@
use core::sync::atomic::{fence, Ordering};
use core::task::Waker;
use embassy_cortex_m::interrupt::Priority;
use embassy_sync::waitqueue::AtomicWaker;
use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
@ -67,10 +68,12 @@ impl State {
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init() {
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
interrupt::$irq::steal().enable();
let irq = interrupt::$irq::steal();
irq.set_priority(irq_priority);
irq.enable();
};
}
crate::_generated::init_dma();
@ -99,15 +102,14 @@ foreach_dma_channel! {
)
}
unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
let buf = [repeated];
unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) {
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
request,
vals::Dir::MEMORYTOPERIPHERAL,
reg_addr as *const u32,
buf.as_ptr() as *mut u32,
repeated as *mut u32,
count,
false,
vals::Size::from(W::bits()),

View File

@ -75,15 +75,14 @@ foreach_dma_channel! {
)
}
unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) {
let buf = [repeated];
unsafe fn start_write_repeated<W: Word>(&mut self, request: Request, repeated: *const W, count: usize, reg_addr: *mut W, options: TransferOptions) {
low_level_api::start_transfer(
pac::$dma_peri,
$channel_num,
request,
low_level_api::Dir::MemoryToPeripheral,
reg_addr as *const u32,
buf.as_ptr() as *mut u32,
repeated as *mut u32,
count,
false,
W::bits(),

View File

@ -12,6 +12,8 @@ use core::mem;
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
#[cfg(any(dma, bdma))]
use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{impl_peripheral, into_ref};
#[cfg(dmamux)]
@ -57,7 +59,7 @@ pub(crate) mod sealed {
unsafe fn start_write_repeated<W: super::Word>(
&mut self,
request: Request,
repeated: W,
repeated: *const W,
count: usize,
reg_addr: *mut W,
options: TransferOptions,
@ -244,7 +246,7 @@ mod transfers {
pub fn write_repeated<'a, W: Word>(
channel: impl Peripheral<P = impl Channel> + 'a,
request: Request,
repeated: W,
repeated: *const W,
count: usize,
reg_addr: *mut W,
) -> impl Future<Output = ()> + 'a {
@ -294,11 +296,11 @@ pub struct NoDma;
impl_peripheral!(NoDma);
// safety: must be called only once at startup
pub(crate) unsafe fn init() {
pub(crate) unsafe fn init(#[cfg(bdma)] bdma_priority: Priority, #[cfg(dma)] dma_priority: Priority) {
#[cfg(bdma)]
bdma::init();
bdma::init(bdma_priority);
#[cfg(dma)]
dma::init();
dma::init(dma_priority);
#[cfg(dmamux)]
dmamux::init();
#[cfg(gpdma)]

View File

@ -1,13 +1,125 @@
#![macro_use]
#[cfg(feature = "net")]
#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
#[cfg_attr(eth_v2, path = "v2/mod.rs")]
mod _version;
pub mod generic_smi;
#[cfg(feature = "net")]
pub use _version::*;
use core::task::Context;
use embassy_net_driver::{Capabilities, LinkState};
use embassy_sync::waitqueue::AtomicWaker;
pub use self::_version::*;
#[allow(unused)]
const MTU: usize = 1514;
const TX_BUFFER_SIZE: usize = 1514;
const RX_BUFFER_SIZE: usize = 1536;
#[repr(C, align(8))]
#[derive(Copy, Clone)]
pub(crate) struct Packet<const N: usize>([u8; N]);
pub struct PacketQueue<const TX: usize, const RX: usize> {
tx_desc: [TDes; TX],
rx_desc: [RDes; RX],
tx_buf: [Packet<TX_BUFFER_SIZE>; TX],
rx_buf: [Packet<RX_BUFFER_SIZE>; RX],
}
impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
pub const fn new() -> Self {
const NEW_TDES: TDes = TDes::new();
const NEW_RDES: RDes = RDes::new();
Self {
tx_desc: [NEW_TDES; TX],
rx_desc: [NEW_RDES; RX],
tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX],
rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX],
}
}
}
static WAKER: AtomicWaker = AtomicWaker::new();
impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> {
type RxToken<'a> = RxToken<'a, 'd> where Self: 'a;
type TxToken<'a> = TxToken<'a, 'd> where Self: 'a;
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
WAKER.register(cx.waker());
if self.rx.available().is_some() && self.tx.available().is_some() {
Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx }))
} else {
None
}
}
fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> {
WAKER.register(cx.waker());
if self.tx.available().is_some() {
Some(TxToken { tx: &mut self.tx })
} else {
None
}
}
fn capabilities(&self) -> Capabilities {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(self.tx.len());
caps
}
fn link_state(&mut self, cx: &mut Context) -> LinkState {
// TODO: wake cx.waker on link state change
cx.waker().wake_by_ref();
if P::poll_link(self) {
LinkState::Up
} else {
LinkState::Down
}
}
fn ethernet_address(&self) -> [u8; 6] {
self.mac_addr
}
}
pub struct RxToken<'a, 'd> {
rx: &'a mut RDesRing<'d>,
}
impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
let pkt = unwrap!(self.rx.available());
let r = f(pkt);
self.rx.pop_packet();
r
}
}
pub struct TxToken<'a, 'd> {
tx: &'a mut TDesRing<'d>,
}
impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
let pkt = unwrap!(self.tx.available());
let r = f(&mut pkt[..len]);
self.tx.transmit(len);
r
}
}
/// Station Management Interface (SMI) on an ethernet PHY
///

View File

@ -1,21 +0,0 @@
use crate::eth::_version::rx_desc::RDesRing;
use crate::eth::_version::tx_desc::TDesRing;
pub struct DescriptorRing<const T: usize, const R: usize> {
pub(crate) tx: TDesRing<T>,
pub(crate) rx: RDesRing<R>,
}
impl<const T: usize, const R: usize> DescriptorRing<T, R> {
pub const fn new() -> Self {
Self {
tx: TDesRing::new(),
rx: RDesRing::new(),
}
}
pub fn init(&mut self) {
self.tx.init();
self.rx.init();
}
}

View File

@ -1,16 +1,19 @@
// The v1c ethernet driver was ported to embassy from the awesome stm32-eth project (https://github.com/stm32-rs/stm32-eth).
use core::marker::PhantomData;
mod rx_desc;
mod tx_desc;
use core::sync::atomic::{fence, Ordering};
use core::task::Waker;
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
use embassy_cortex_m::interrupt::InterruptExt;
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
use embassy_sync::waitqueue::AtomicWaker;
use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
pub(crate) use self::rx_desc::{RDes, RDesRing};
pub(crate) use self::tx_desc::{TDes, TDesRing};
use super::*;
use crate::gpio::sealed::{AFType, Pin as __GpioPin};
use crate::gpio::{AnyPin, Speed};
use crate::gpio::AnyPin;
#[cfg(eth_v1a)]
use crate::pac::AFIO;
#[cfg(any(eth_v1b, eth_v1c))]
@ -18,29 +21,16 @@ use crate::pac::SYSCFG;
use crate::pac::{ETH, RCC};
use crate::Peripheral;
mod descriptors;
mod rx_desc;
mod tx_desc;
pub struct Ethernet<'d, T: Instance, P: PHY> {
_peri: PeripheralRef<'d, T>,
pub(crate) tx: TDesRing<'d>,
pub(crate) rx: RDesRing<'d>,
use descriptors::DescriptorRing;
use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
use super::*;
pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>);
impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> {
pub const fn new() -> Self {
Self(StateStorage::new())
}
}
pub struct Ethernet<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> {
state: PeripheralMutex<'d, Inner<'d, T, TX, RX>>,
pins: [PeripheralRef<'d, AnyPin>; 9],
_phy: P,
clock_range: Cr,
phy_addr: u8,
mac_addr: [u8; 6],
pub(crate) mac_addr: [u8; 6],
}
#[cfg(eth_v1a)]
@ -76,16 +66,16 @@ macro_rules! config_pins {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
$pin.set_speed(Speed::VeryHigh);
$pin.set_speed(crate::gpio::Speed::VeryHigh);
)*
})
};
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, P, TX, RX> {
impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
/// safety: the returned instance is not leak-safe
pub unsafe fn new(
state: &'d mut State<'d, T, TX, RX>,
pub fn new<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>,
peri: impl Peripheral<P = T> + 'd,
interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd,
ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
@ -101,134 +91,131 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
mac_addr: [u8; 6],
phy_addr: u8,
) -> Self {
into_ref!(interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// Enable the necessary Clocks
// NOTE(unsafe) We have exclusive access to the registers
#[cfg(eth_v1a)]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_afioen(true));
unsafe {
// Enable the necessary Clocks
// NOTE(unsafe) We have exclusive access to the registers
#[cfg(eth_v1a)]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_afioen(true));
// Select RMII (Reduced Media Independent Interface)
// Must be done prior to enabling peripheral clock
AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
// Select RMII (Reduced Media Independent Interface)
// Must be done prior to enabling peripheral clock
AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true));
RCC.ahbenr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
});
#[cfg(any(eth_v1b, eth_v1c))]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
RCC.ahbenr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
});
// RMII (Reduced Media Independent Interface)
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
});
#[cfg(any(eth_v1b, eth_v1c))]
critical_section::with(|_| {
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
#[cfg(eth_v1a)]
{
config_in_pins!(ref_clk, rx_d0, rx_d1);
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
}
// RMII (Reduced Media Independent Interface)
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
});
#[cfg(any(eth_v1b, eth_v1c))]
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// NOTE(unsafe) We are ourselves not leak-safe.
let state = PeripheralMutex::new(interrupt, &mut state.0, || Inner::new(peri));
// NOTE(unsafe) We have exclusive access to the registers
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
// Reset and wait
dma.dmabmr().modify(|w| w.set_sr(true));
while dma.dmabmr().read().sr() {}
mac.maccr().modify(|w| {
w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
w.set_fes(Fes::FES100); // fast ethernet speed
w.set_dm(Dm::FULLDUPLEX); // full duplex
// TODO: Carrier sense ? ECRSFD
});
// Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
// so the LR write must happen after the HR write.
mac.maca0hr()
.modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
mac.maca0lr().write(|w| {
w.set_maca0l(
u32::from(mac_addr[0])
| (u32::from(mac_addr[1]) << 8)
| (u32::from(mac_addr[2]) << 16)
| (u32::from(mac_addr[3]) << 24),
)
});
// pause time
mac.macfcr().modify(|w| w.set_pt(0x100));
// Transfer and Forward, Receive and Forward
dma.dmaomr().modify(|w| {
w.set_tsf(Tsf::STOREFORWARD);
w.set_rsf(Rsf::STOREFORWARD);
});
dma.dmabmr().modify(|w| {
w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ?
});
// TODO MTU size setting not found for v1 ethernet, check if correct
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = crate::rcc::get_freqs().ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
let clock_range = match hclk_mhz {
0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
25..=34 => Cr::CR_20_35, // Divide by 16
35..=59 => Cr::CR_35_60, // Divide by 26
60..=99 => Cr::CR_60_100, // Divide by 42
100..=149 => Cr::CR_100_150, // Divide by 62
150..=216 => Cr::CR_150_168, // Divide by 102
_ => {
panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
#[cfg(eth_v1a)]
{
config_in_pins!(ref_clk, rx_d0, rx_d1);
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
}
};
let pins = [
ref_clk.map_into(),
mdio.map_into(),
mdc.map_into(),
crs.map_into(),
rx_d0.map_into(),
rx_d1.map_into(),
tx_d0.map_into(),
tx_d1.map_into(),
tx_en.map_into(),
];
#[cfg(any(eth_v1b, eth_v1c))]
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
let mut this = Self {
state,
pins,
_phy: phy,
clock_range,
phy_addr,
mac_addr,
};
// NOTE(unsafe) We have exclusive access to the registers
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
this.state.with(|s| {
s.desc_ring.init();
// Reset and wait
dma.dmabmr().modify(|w| w.set_sr(true));
while dma.dmabmr().read().sr() {}
mac.maccr().modify(|w| {
w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times
w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
w.set_fes(Fes::FES100); // fast ethernet speed
w.set_dm(Dm::FULLDUPLEX); // full duplex
// TODO: Carrier sense ? ECRSFD
});
// Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
// so the LR write must happen after the HR write.
mac.maca0hr()
.modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
mac.maca0lr().write(|w| {
w.set_maca0l(
u32::from(mac_addr[0])
| (u32::from(mac_addr[1]) << 8)
| (u32::from(mac_addr[2]) << 16)
| (u32::from(mac_addr[3]) << 24),
)
});
// pause time
mac.macfcr().modify(|w| w.set_pt(0x100));
// Transfer and Forward, Receive and Forward
dma.dmaomr().modify(|w| {
w.set_tsf(Tsf::STOREFORWARD);
w.set_rsf(Rsf::STOREFORWARD);
});
dma.dmabmr().modify(|w| {
w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ?
});
// TODO MTU size setting not found for v1 ethernet, check if correct
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = crate::rcc::get_freqs().ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
let clock_range = match hclk_mhz {
0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
25..=34 => Cr::CR_20_35, // Divide by 16
35..=59 => Cr::CR_35_60, // Divide by 26
60..=99 => Cr::CR_60_100, // Divide by 42
100..=149 => Cr::CR_100_150, // Divide by 62
150..=216 => Cr::CR_150_168, // Divide by 102
_ => {
panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
}
};
let pins = [
ref_clk.map_into(),
mdio.map_into(),
mdc.map_into(),
crs.map_into(),
rx_d0.map_into(),
rx_d1.map_into(),
tx_d0.map_into(),
tx_d1.map_into(),
tx_en.map_into(),
];
let mut this = Self {
_peri: peri,
pins,
_phy: phy,
clock_range,
phy_addr,
mac_addr,
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
};
fence(Ordering::SeqCst);
@ -245,23 +232,45 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
w.set_sr(DmaomrSr::STARTED); // start receiving channel
});
this.rx.demand_poll();
// Enable interrupts
dma.dmaier().modify(|w| {
w.set_nise(true);
w.set_rie(true);
w.set_tie(true);
});
});
P::phy_reset(&mut this);
P::phy_init(&mut this);
this
P::phy_reset(&mut this);
P::phy_init(&mut this);
interrupt.set_handler(Self::on_interrupt);
interrupt.enable();
this
}
}
fn on_interrupt(_cx: *mut ()) {
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
dma.dmasr().modify(|w| {
w.set_ts(true);
w.set_rs(true);
w.set_nis(true);
});
// Delay two peripheral's clock
dma.dmasr().read();
dma.dmasr().read();
}
}
}
unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationManagement
for Ethernet<'d, T, P, TX, RX>
{
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
fn smi_read(&mut self, reg: u8) -> u16 {
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
unsafe {
@ -297,44 +306,7 @@ unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationMa
}
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, T, P, TX, RX> {
fn is_transmit_ready(&mut self) -> bool {
self.state.with(|s| s.desc_ring.tx.available())
}
fn transmit(&mut self, pkt: PacketBuf) {
self.state.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt)));
}
fn receive(&mut self) -> Option<PacketBuf> {
self.state.with(|s| s.desc_ring.rx.pop_packet())
}
fn register_waker(&mut self, waker: &Waker) {
WAKER.register(waker);
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(TX.min(RX));
caps
}
fn link_state(&mut self) -> LinkState {
if P::poll_link(self) {
LinkState::Up
} else {
LinkState::Down
}
}
fn ethernet_address(&self) -> [u8; 6] {
self.mac_addr
}
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Ethernet<'d, T, P, TX, RX> {
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
fn drop(&mut self) {
// NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers
unsafe {
@ -361,46 +333,3 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Etherne
})
}
}
//----------------------------------------------------------------------
struct Inner<'d, T: Instance, const TX: usize, const RX: usize> {
_peri: PhantomData<&'d mut T>,
desc_ring: DescriptorRing<TX, RX>,
}
impl<'d, T: Instance, const TX: usize, const RX: usize> Inner<'d, T, TX, RX> {
pub fn new(_peri: impl Peripheral<P = T> + 'd) -> Self {
Self {
_peri: PhantomData,
desc_ring: DescriptorRing::new(),
}
}
}
impl<'d, T: Instance, const TX: usize, const RX: usize> PeripheralState for Inner<'d, T, TX, RX> {
type Interrupt = crate::interrupt::ETH;
fn on_interrupt(&mut self) {
unwrap!(self.desc_ring.tx.on_interrupt());
self.desc_ring.rx.on_interrupt();
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
dma.dmasr().modify(|w| {
w.set_ts(true);
w.set_rs(true);
w.set_nis(true);
});
// Delay two peripheral's clock
dma.dmasr().read();
dma.dmasr().read();
}
}
}
static WAKER: AtomicWaker = AtomicWaker::new();

View File

@ -1,9 +1,9 @@
use core::sync::atomic::{compiler_fence, fence, Ordering};
use embassy_net::{Packet, PacketBox, PacketBoxExt, PacketBuf};
use stm32_metapac::eth::vals::{DmaomrSr, Rpd, Rps};
use stm32_metapac::eth::vals::{Rpd, Rps};
use vcell::VolatileCell;
use crate::eth::RX_BUFFER_SIZE;
use crate::pac::ETH;
mod rx_consts {
@ -28,6 +28,8 @@ mod rx_consts {
use rx_consts::*;
use super::Packet;
/// Receive Descriptor representation
///
/// * rdes0: OWN and Status
@ -35,7 +37,7 @@ use rx_consts::*;
/// * rdes2: data buffer address
/// * rdes3: next descriptor address
#[repr(C)]
struct RDes {
pub(crate) struct RDes {
rdes0: VolatileCell<u32>,
rdes1: VolatileCell<u32>,
rdes2: VolatileCell<u32>,
@ -54,7 +56,7 @@ impl RDes {
/// Return true if this RDes is acceptable to us
#[inline(always)]
pub fn valid(&self) -> bool {
fn valid(&self) -> bool {
// Write-back descriptor is valid if:
//
// Contains first buffer of packet AND contains last buf of
@ -64,15 +66,16 @@ impl RDes {
/// Return true if this RDes is not currently owned by the DMA
#[inline(always)]
pub fn available(&self) -> bool {
fn available(&self) -> bool {
self.rdes0.get() & RXDESC_0_OWN == 0 // Owned by us
}
/// Configures the reception buffer address and length and passed descriptor ownership to the DMA
#[inline(always)]
pub fn set_ready(&mut self, buf_addr: u32, buf_len: usize) {
self.rdes1.set(self.rdes1.get() | (buf_len as u32) & RXDESC_1_RBS_MASK);
self.rdes2.set(buf_addr);
fn set_ready(&self, buf: *mut u8) {
self.rdes1
.set(self.rdes1.get() | (RX_BUFFER_SIZE as u32) & RXDESC_1_RBS_MASK);
self.rdes2.set(buf as u32);
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
@ -88,12 +91,12 @@ impl RDes {
// points to next descriptor (RCH)
#[inline(always)]
fn set_buffer2(&mut self, buffer: *const u8) {
fn set_buffer2(&self, buffer: *const u8) {
self.rdes3.set(buffer as u32);
}
#[inline(always)]
fn set_end_of_ring(&mut self) {
fn set_end_of_ring(&self) {
self.rdes1.set(self.rdes1.get() | RXDESC_1_RER);
}
@ -102,7 +105,7 @@ impl RDes {
((self.rdes0.get() >> RXDESC_0_FL_SHIFT) & RXDESC_0_FL_MASK) as usize
}
pub fn setup(&mut self, next: Option<&Self>) {
fn setup(&self, next: Option<&Self>, buf: *mut u8) {
// Defer this initialization to this function, so we can have `RingEntry` on bss.
self.rdes1.set(self.rdes1.get() | RXDESC_1_RCH);
@ -113,8 +116,11 @@ impl RDes {
self.set_end_of_ring();
}
}
self.set_ready(buf);
}
}
/// Running state of the `RxRing`
#[derive(PartialEq, Eq, Debug)]
pub enum RunningState {
@ -123,116 +129,42 @@ pub enum RunningState {
Running,
}
impl RunningState {
/// whether self equals to `RunningState::Running`
pub fn is_running(&self) -> bool {
*self == RunningState::Running
}
}
/// Rx ring of descriptors and packets
///
/// This ring has three major locations that work in lock-step. The DMA will never write to the tail
/// index, so the `read_index` must never pass the tail index. The `next_tail_index` is always 1
/// slot ahead of the real tail index, and it must never pass the `read_index` or it could overwrite
/// a packet still to be passed to the application.
///
/// nt can't pass r (no alloc)
/// +---+---+---+---+ Read ok +---+---+---+---+ No Read +---+---+---+---+
/// | | | | | ------------> | | | | | ------------> | | | | |
/// +---+---+---+---+ Allocation ok +---+---+---+---+ +---+---+---+---+
/// ^ ^t ^t ^ ^t ^
/// |r |r |r
/// |nt |nt |nt
///
///
/// +---+---+---+---+ Read ok +---+---+---+---+ Can't read +---+---+---+---+
/// | | | | | ------------> | | | | | ------------> | | | | |
/// +---+---+---+---+ Allocation fail +---+---+---+---+ Allocation ok +---+---+---+---+
/// ^ ^t ^ ^t ^ ^ ^ ^t
/// |r | |r | | |r
/// |nt |nt |nt
///
pub(crate) struct RDesRing<const N: usize> {
descriptors: [RDes; N],
buffers: [Option<PacketBox>; N],
read_index: usize,
next_tail_index: usize,
pub(crate) struct RDesRing<'a> {
descriptors: &'a mut [RDes],
buffers: &'a mut [Packet<RX_BUFFER_SIZE>],
index: usize,
}
impl<const N: usize> RDesRing<N> {
pub const fn new() -> Self {
const RDES: RDes = RDes::new();
const BUFFERS: Option<PacketBox> = None;
impl<'a> RDesRing<'a> {
pub(crate) fn new(descriptors: &'a mut [RDes], buffers: &'a mut [Packet<RX_BUFFER_SIZE>]) -> Self {
assert!(descriptors.len() > 1);
assert!(descriptors.len() == buffers.len());
Self {
descriptors: [RDES; N],
buffers: [BUFFERS; N],
read_index: 0,
next_tail_index: 0,
}
}
pub(crate) fn init(&mut self) {
assert!(N > 1);
let mut last_index = 0;
for (index, buf) in self.buffers.iter_mut().enumerate() {
let pkt = match PacketBox::new(Packet::new()) {
Some(p) => p,
None => {
if index == 0 {
panic!("Could not allocate at least one buffer for Ethernet receiving");
} else {
break;
}
}
};
self.descriptors[index].set_ready(pkt.as_ptr() as u32, pkt.len());
*buf = Some(pkt);
last_index = index;
}
self.next_tail_index = (last_index + 1) % N;
// not sure if this is supposed to span all of the descriptor or just those that contain buffers
{
let mut previous: Option<&mut RDes> = None;
for entry in self.descriptors.iter_mut() {
if let Some(prev) = &mut previous {
prev.setup(Some(entry));
}
previous = Some(entry);
}
if let Some(entry) = &mut previous {
entry.setup(None);
}
for (i, entry) in descriptors.iter().enumerate() {
entry.setup(descriptors.get(i + 1), buffers[i].0.as_mut_ptr());
}
// Register txdescriptor start
// Register rx descriptor start
// NOTE (unsafe) Used for atomic writes
unsafe {
ETH.ethernet_dma()
.dmardlar()
.write(|w| w.0 = &self.descriptors as *const _ as u32);
.write(|w| w.0 = descriptors.as_ptr() as u32);
};
// We already have fences in `set_owned`, which is called in `setup`
// Start receive
unsafe { ETH.ethernet_dma().dmaomr().modify(|w| w.set_sr(DmaomrSr::STARTED)) };
self.demand_poll();
Self {
descriptors,
buffers,
index: 0,
}
}
fn demand_poll(&self) {
pub(crate) fn demand_poll(&self) {
unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) };
}
pub(crate) fn on_interrupt(&mut self) {
// XXX: Do we need to do anything here ? Maybe we should try to advance the tail ptr, but it
// would soon hit the read ptr anyway, and we will wake smoltcp's stack on the interrupt
// which should try to pop a packet...
}
/// Get current `RunningState`
fn running_state(&self) -> RunningState {
match unsafe { ETH.ethernet_dma().dmasr().read().rps() } {
@ -252,52 +184,52 @@ impl<const N: usize> RDesRing<N> {
}
}
pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> {
if !self.running_state().is_running() {
/// Get a received packet if any, or None.
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
if self.running_state() != RunningState::Running {
self.demand_poll();
}
// Not sure if the contents of the write buffer on the M7 can affects reads, so we are using
// a DMB here just in case, it also serves as a hint to the compiler that we're syncing the
// buffer (I think .-.)
fence(Ordering::SeqCst);
let read_available = self.descriptors[self.read_index].available();
let tail_index = (self.next_tail_index + N - 1) % N;
let pkt = if read_available && self.read_index != tail_index {
let pkt = self.buffers[self.read_index].take();
let len = self.descriptors[self.read_index].packet_len();
assert!(pkt.is_some());
let valid = self.descriptors[self.read_index].valid();
self.read_index = (self.read_index + 1) % N;
if valid {
pkt.map(|p| p.slice(0..len))
} else {
None
// We might have to process many packets, in case some have been rx'd but are invalid.
loop {
let descriptor = &mut self.descriptors[self.index];
if !descriptor.available() {
return None;
}
} else {
None
};
// Try to advance the tail_index
if self.next_tail_index != self.read_index {
match PacketBox::new(Packet::new()) {
Some(b) => {
let addr = b.as_ptr() as u32;
let buffer_len = b.len();
self.buffers[self.next_tail_index].replace(b);
self.descriptors[self.next_tail_index].set_ready(addr, buffer_len);
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
self.next_tail_index = (self.next_tail_index + 1) % N;
}
None => {}
// If packet is invalid, pop it and try again.
if !descriptor.valid() {
warn!("invalid packet: {:08x}", descriptor.rdes0.get());
self.pop_packet();
continue;
}
break;
}
let descriptor = &mut self.descriptors[self.index];
let len = descriptor.packet_len();
return Some(&mut self.buffers[self.index].0[..len]);
}
/// Pop the packet previously returned by `available`.
pub(crate) fn pop_packet(&mut self) {
let descriptor = &mut self.descriptors[self.index];
assert!(descriptor.available());
self.descriptors[self.index].set_ready(self.buffers[self.index].0.as_mut_ptr());
self.demand_poll();
// Increment index.
self.index += 1;
if self.index == self.descriptors.len() {
self.index = 0
}
pkt
}
}

View File

@ -1,20 +1,10 @@
use core::sync::atomic::{compiler_fence, fence, Ordering};
use embassy_net::PacketBuf;
use stm32_metapac::eth::vals::St;
use vcell::VolatileCell;
use crate::eth::TX_BUFFER_SIZE;
use crate::pac::ETH;
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
NoBufferAvailable,
// TODO: Break down this error into several others
TransmissionError,
}
/// Transmit and Receive Descriptor fields
#[allow(dead_code)]
mod tx_consts {
@ -37,6 +27,8 @@ mod tx_consts {
}
use tx_consts::*;
use super::Packet;
/// Transmit Descriptor representation
///
/// * tdes0: control
@ -44,7 +36,7 @@ use tx_consts::*;
/// * tdes2: data buffer address
/// * tdes3: next descriptor address
#[repr(C)]
struct TDes {
pub(crate) struct TDes {
tdes0: VolatileCell<u32>,
tdes1: VolatileCell<u32>,
tdes2: VolatileCell<u32>,
@ -62,7 +54,7 @@ impl TDes {
}
/// Return true if this TDes is not currently owned by the DMA
pub fn available(&self) -> bool {
fn available(&self) -> bool {
(self.tdes0.get() & TXDESC_0_OWN) == 0
}
@ -79,26 +71,26 @@ impl TDes {
fence(Ordering::SeqCst);
}
fn set_buffer1(&mut self, buffer: *const u8) {
fn set_buffer1(&self, buffer: *const u8) {
self.tdes2.set(buffer as u32);
}
fn set_buffer1_len(&mut self, len: usize) {
fn set_buffer1_len(&self, len: usize) {
self.tdes1
.set((self.tdes1.get() & !TXDESC_1_TBS_MASK) | ((len as u32) << TXDESC_1_TBS_SHIFT));
}
// points to next descriptor (RCH)
fn set_buffer2(&mut self, buffer: *const u8) {
fn set_buffer2(&self, buffer: *const u8) {
self.tdes3.set(buffer as u32);
}
fn set_end_of_ring(&mut self) {
fn set_end_of_ring(&self) {
self.tdes0.set(self.tdes0.get() | TXDESC_0_TER);
}
// set up as a part fo the ring buffer - configures the tdes
pub fn setup(&mut self, next: Option<&Self>) {
fn setup(&self, next: Option<&Self>) {
// Defer this initialization to this function, so we can have `RingEntry` on bss.
self.tdes0.set(TXDESC_0_TCH | TXDESC_0_IOC | TXDESC_0_FS | TXDESC_0_LS);
match next {
@ -111,85 +103,58 @@ impl TDes {
}
}
pub(crate) struct TDesRing<const N: usize> {
descriptors: [TDes; N],
buffers: [Option<PacketBuf>; N],
next_entry: usize,
pub(crate) struct TDesRing<'a> {
descriptors: &'a mut [TDes],
buffers: &'a mut [Packet<TX_BUFFER_SIZE>],
index: usize,
}
impl<const N: usize> TDesRing<N> {
pub const fn new() -> Self {
const TDES: TDes = TDes::new();
const BUFFERS: Option<PacketBuf> = None;
Self {
descriptors: [TDES; N],
buffers: [BUFFERS; N],
next_entry: 0,
}
}
impl<'a> TDesRing<'a> {
/// Initialise this TDesRing. Assume TDesRing is corrupt
///
/// The current memory address of the buffers inside this TDesRing
/// will be stored in the descriptors, so ensure the TDesRing is
/// not moved after initialisation.
pub(crate) fn init(&mut self) {
assert!(N > 0);
pub(crate) fn new(descriptors: &'a mut [TDes], buffers: &'a mut [Packet<TX_BUFFER_SIZE>]) -> Self {
assert!(descriptors.len() > 0);
assert!(descriptors.len() == buffers.len());
{
let mut previous: Option<&mut TDes> = None;
for entry in self.descriptors.iter_mut() {
if let Some(prev) = &mut previous {
prev.setup(Some(entry));
}
previous = Some(entry);
}
if let Some(entry) = &mut previous {
entry.setup(None);
}
for (i, entry) in descriptors.iter().enumerate() {
entry.setup(descriptors.get(i + 1));
}
self.next_entry = 0;
// Register txdescriptor start
// NOTE (unsafe) Used for atomic writes
unsafe {
ETH.ethernet_dma()
.dmatdlar()
.write(|w| w.0 = &self.descriptors as *const _ as u32);
.write(|w| w.0 = descriptors.as_ptr() as u32);
}
// "Preceding reads and writes cannot be moved past subsequent writes."
#[cfg(feature = "fence")]
fence(Ordering::Release);
// We don't need a compiler fence here because all interactions with `Descriptor` are
// volatiles
// Start transmission
unsafe { ETH.ethernet_dma().dmaomr().modify(|w| w.set_st(St::STARTED)) };
}
/// Return true if a TDes is available for use
pub(crate) fn available(&self) -> bool {
self.descriptors[self.next_entry].available()
}
pub(crate) fn transmit(&mut self, pkt: PacketBuf) -> Result<(), Error> {
if !self.available() {
return Err(Error::NoBufferAvailable);
Self {
descriptors,
buffers,
index: 0,
}
}
let descriptor = &mut self.descriptors[self.next_entry];
pub(crate) fn len(&self) -> usize {
self.descriptors.len()
}
let pkt_len = pkt.len();
let address = pkt.as_ptr() as *const u8;
/// Return the next available packet buffer for transmitting, or None
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
let descriptor = &mut self.descriptors[self.index];
if descriptor.available() {
Some(&mut self.buffers[self.index].0)
} else {
None
}
}
descriptor.set_buffer1(address);
descriptor.set_buffer1_len(pkt_len);
/// Transmit the packet written in a buffer returned by `available`.
pub(crate) fn transmit(&mut self, len: usize) {
let descriptor = &mut self.descriptors[self.index];
assert!(descriptor.available());
self.buffers[self.next_entry].replace(pkt);
descriptor.set_buffer1(self.buffers[self.index].0.as_ptr());
descriptor.set_buffer1_len(len);
descriptor.set_owned();
@ -198,36 +163,12 @@ impl<const N: usize> TDesRing<N> {
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
// Move the tail pointer (TPR) to the next descriptor
self.next_entry = (self.next_entry + 1) % N;
// Move the index to the next descriptor
self.index += 1;
if self.index == self.descriptors.len() {
self.index = 0
}
// Request the DMA engine to poll the latest tx descriptor
unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) }
Ok(())
}
pub(crate) fn on_interrupt(&mut self) -> Result<(), Error> {
let previous = (self.next_entry + N - 1) % N;
let td = &self.descriptors[previous];
// DMB to ensure that we are reading an updated value, probably not needed at the hardware
// level, but this is also a hint to the compiler that we're syncing on the buffer.
fence(Ordering::SeqCst);
let tdes0 = td.tdes0.get();
if tdes0 & TXDESC_0_OWN != 0 {
// Transmission isn't done yet, probably a receive interrupt that fired this
return Ok(());
}
// Release the buffer
self.buffers[previous].take();
if tdes0 & TXDESC_0_ES != 0 {
Err(Error::TransmissionError)
} else {
Ok(())
}
}
}

View File

@ -1,19 +1,10 @@
use core::sync::atomic::{fence, Ordering};
use embassy_net::{Packet, PacketBox, PacketBoxExt, PacketBuf};
use vcell::VolatileCell;
use crate::eth::{Packet, RX_BUFFER_SIZE, TX_BUFFER_SIZE};
use crate::pac::ETH;
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
NoBufferAvailable,
// TODO: Break down this error into several others
TransmissionError,
}
/// Transmit and Receive Descriptor fields
#[allow(dead_code)]
mod emac_consts {
@ -41,7 +32,7 @@ use emac_consts::*;
/// * tdes2: buffer lengths
/// * tdes3: control and payload/frame length
#[repr(C)]
struct TDes {
pub(crate) struct TDes {
tdes0: VolatileCell<u32>,
tdes1: VolatileCell<u32>,
tdes2: VolatileCell<u32>,
@ -59,41 +50,26 @@ impl TDes {
}
/// Return true if this TDes is not currently owned by the DMA
pub fn available(&self) -> bool {
fn available(&self) -> bool {
self.tdes3.get() & EMAC_DES3_OWN == 0
}
}
pub(crate) struct TDesRing<const N: usize> {
td: [TDes; N],
buffers: [Option<PacketBuf>; N],
tdidx: usize,
pub(crate) struct TDesRing<'a> {
descriptors: &'a mut [TDes],
buffers: &'a mut [Packet<TX_BUFFER_SIZE>],
index: usize,
}
impl<const N: usize> TDesRing<N> {
pub const fn new() -> Self {
const TDES: TDes = TDes::new();
const BUFFERS: Option<PacketBuf> = None;
impl<'a> TDesRing<'a> {
/// Initialise this TDesRing. Assume TDesRing is corrupt.
pub fn new(descriptors: &'a mut [TDes], buffers: &'a mut [Packet<TX_BUFFER_SIZE>]) -> Self {
assert!(descriptors.len() > 0);
assert!(descriptors.len() == buffers.len());
Self {
td: [TDES; N],
buffers: [BUFFERS; N],
tdidx: 0,
}
}
/// Initialise this TDesRing. Assume TDesRing is corrupt
///
/// The current memory address of the buffers inside this TDesRing
/// will be stored in the descriptors, so ensure the TDesRing is
/// not moved after initialisation.
pub(crate) fn init(&mut self) {
assert!(N > 0);
for td in self.td.iter_mut() {
for td in descriptors.iter_mut() {
*td = TDes::new();
}
self.tdidx = 0;
// Initialize the pointers in the DMA engine. (There will be a memory barrier later
// before the DMA engine is enabled.)
@ -101,80 +77,60 @@ impl<const N: usize> TDesRing<N> {
unsafe {
let dma = ETH.ethernet_dma();
dma.dmactx_dlar().write(|w| w.0 = &self.td as *const _ as u32);
dma.dmactx_rlr().write(|w| w.set_tdrl((N as u16) - 1));
dma.dmactx_dtpr().write(|w| w.0 = &self.td[0] as *const _ as u32);
dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
dma.dmactx_dtpr().write(|w| w.0 = 0);
}
Self {
descriptors,
buffers,
index: 0,
}
}
/// Return true if a TDes is available for use
pub(crate) fn available(&self) -> bool {
self.td[self.tdidx].available()
pub(crate) fn len(&self) -> usize {
self.descriptors.len()
}
pub(crate) fn transmit(&mut self, pkt: PacketBuf) -> Result<(), Error> {
if !self.available() {
return Err(Error::NoBufferAvailable);
/// Return the next available packet buffer for transmitting, or None
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
let d = &mut self.descriptors[self.index];
if d.available() {
Some(&mut self.buffers[self.index].0)
} else {
None
}
let x = self.tdidx;
let td = &mut self.td[x];
}
let pkt_len = pkt.len();
assert!(pkt_len as u32 <= EMAC_TDES2_B1L);
let address = pkt.as_ptr() as u32;
/// Transmit the packet written in a buffer returned by `available`.
pub(crate) fn transmit(&mut self, len: usize) {
let td = &mut self.descriptors[self.index];
assert!(td.available());
assert!(len as u32 <= EMAC_TDES2_B1L);
// Read format
td.tdes0.set(address);
td.tdes2.set(pkt_len as u32 & EMAC_TDES2_B1L | EMAC_TDES2_IOC);
td.tdes0.set(self.buffers[self.index].0.as_ptr() as u32);
td.tdes2.set(len as u32 & EMAC_TDES2_B1L | EMAC_TDES2_IOC);
// FD: Contains first buffer of packet
// LD: Contains last buffer of packet
// Give the DMA engine ownership
td.tdes3.set(EMAC_DES3_FD | EMAC_DES3_LD | EMAC_DES3_OWN);
self.buffers[x].replace(pkt);
// Ensure changes to the descriptor are committed before DMA engine sees tail pointer store.
// This will generate an DMB instruction.
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
// Move the tail pointer (TPR) to the next descriptor
let x = (x + 1) % N;
self.index = self.index + 1;
if self.index == self.descriptors.len() {
self.index = 0;
}
// signal DMA it can try again.
// NOTE(unsafe) Atomic write
unsafe {
ETH.ethernet_dma()
.dmactx_dtpr()
.write(|w| w.0 = &self.td[x] as *const _ as u32);
}
self.tdidx = x;
Ok(())
}
pub(crate) fn on_interrupt(&mut self) -> Result<(), Error> {
let previous = (self.tdidx + N - 1) % N;
let td = &self.td[previous];
// DMB to ensure that we are reading an updated value, probably not needed at the hardware
// level, but this is also a hint to the compiler that we're syncing on the buffer.
fence(Ordering::SeqCst);
let tdes3 = td.tdes3.get();
if tdes3 & EMAC_DES3_OWN != 0 {
// Transmission isn't done yet, probably a receive interrupt that fired this
return Ok(());
}
assert!(tdes3 & EMAC_DES3_CTXT == 0);
// Release the buffer
self.buffers[previous].take();
if tdes3 & EMAC_DES3_ES != 0 {
Err(Error::TransmissionError)
} else {
Ok(())
}
unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
}
}
@ -185,7 +141,7 @@ impl<const N: usize> TDesRing<N> {
/// * rdes2:
/// * rdes3: OWN and Status
#[repr(C)]
struct RDes {
pub(crate) struct RDes {
rdes0: VolatileCell<u32>,
rdes1: VolatileCell<u32>,
rdes2: VolatileCell<u32>,
@ -204,7 +160,7 @@ impl RDes {
/// Return true if this RDes is acceptable to us
#[inline(always)]
pub fn valid(&self) -> bool {
fn valid(&self) -> bool {
// Write-back descriptor is valid if:
//
// Contains first buffer of packet AND contains last buf of
@ -215,177 +171,96 @@ impl RDes {
/// Return true if this RDes is not currently owned by the DMA
#[inline(always)]
pub fn available(&self) -> bool {
fn available(&self) -> bool {
self.rdes3.get() & EMAC_DES3_OWN == 0 // Owned by us
}
#[inline(always)]
pub fn set_ready(&mut self, buf_addr: u32) {
self.rdes0.set(buf_addr);
fn set_ready(&mut self, buf: *mut u8) {
self.rdes0.set(buf as u32);
self.rdes3.set(EMAC_RDES3_BUF1V | EMAC_RDES3_IOC | EMAC_DES3_OWN);
}
}
/// Rx ring of descriptors and packets
///
/// This ring has three major locations that work in lock-step. The DMA will never write to the tail
/// index, so the `read_index` must never pass the tail index. The `next_tail_index` is always 1
/// slot ahead of the real tail index, and it must never pass the `read_index` or it could overwrite
/// a packet still to be passed to the application.
///
/// nt can't pass r (no alloc)
/// +---+---+---+---+ Read ok +---+---+---+---+ No Read +---+---+---+---+
/// | | | | | ------------> | | | | | ------------> | | | | |
/// +---+---+---+---+ Allocation ok +---+---+---+---+ +---+---+---+---+
/// ^ ^t ^t ^ ^t ^
/// |r |r |r
/// |nt |nt |nt
///
///
/// +---+---+---+---+ Read ok +---+---+---+---+ Can't read +---+---+---+---+
/// | | | | | ------------> | | | | | ------------> | | | | |
/// +---+---+---+---+ Allocation fail +---+---+---+---+ Allocation ok +---+---+---+---+
/// ^ ^t ^ ^t ^ ^ ^ ^t
/// |r | |r | | |r
/// |nt |nt |nt
///
pub(crate) struct RDesRing<const N: usize> {
rd: [RDes; N],
buffers: [Option<PacketBox>; N],
read_idx: usize,
next_tail_idx: usize,
pub(crate) struct RDesRing<'a> {
descriptors: &'a mut [RDes],
buffers: &'a mut [Packet<RX_BUFFER_SIZE>],
index: usize,
}
impl<const N: usize> RDesRing<N> {
pub const fn new() -> Self {
const RDES: RDes = RDes::new();
const BUFFERS: Option<PacketBox> = None;
impl<'a> RDesRing<'a> {
pub(crate) fn new(descriptors: &'a mut [RDes], buffers: &'a mut [Packet<RX_BUFFER_SIZE>]) -> Self {
assert!(descriptors.len() > 1);
assert!(descriptors.len() == buffers.len());
Self {
rd: [RDES; N],
buffers: [BUFFERS; N],
read_idx: 0,
next_tail_idx: 0,
}
}
pub(crate) fn init(&mut self) {
assert!(N > 1);
for desc in self.rd.iter_mut() {
for (i, desc) in descriptors.iter_mut().enumerate() {
*desc = RDes::new();
desc.set_ready(buffers[i].0.as_mut_ptr());
}
let mut last_index = 0;
for (index, buf) in self.buffers.iter_mut().enumerate() {
let pkt = match PacketBox::new(Packet::new()) {
Some(p) => p,
None => {
if index == 0 {
panic!("Could not allocate at least one buffer for Ethernet receiving");
} else {
break;
}
}
};
let addr = pkt.as_ptr() as u32;
*buf = Some(pkt);
self.rd[index].set_ready(addr);
last_index = index;
}
self.next_tail_idx = (last_index + 1) % N;
unsafe {
let dma = ETH.ethernet_dma();
dma.dmacrx_dlar().write(|w| w.0 = self.rd.as_ptr() as u32);
dma.dmacrx_rlr().write(|w| w.set_rdrl((N as u16) - 1));
dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
dma.dmacrx_dtpr().write(|w| w.0 = 0);
}
// We manage to allocate all buffers, set the index to the last one, that means
// that the DMA won't consider the last one as ready, because it (unfortunately)
// stops at the tail ptr and wraps at the end of the ring, which means that we
// can't tell it to stop after the last buffer.
let tail_ptr = &self.rd[last_index] as *const _ as u32;
fence(Ordering::Release);
dma.dmacrx_dtpr().write(|w| w.0 = tail_ptr);
Self {
descriptors,
buffers,
index: 0,
}
}
pub(crate) fn on_interrupt(&mut self) {
// XXX: Do we need to do anything here ? Maybe we should try to advance the tail ptr, but it
// would soon hit the read ptr anyway, and we will wake smoltcp's stack on the interrupt
// which should try to pop a packet...
}
pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> {
/// Get a received packet if any, or None.
pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
// Not sure if the contents of the write buffer on the M7 can affects reads, so we are using
// a DMB here just in case, it also serves as a hint to the compiler that we're syncing the
// buffer (I think .-.)
fence(Ordering::SeqCst);
let read_available = self.rd[self.read_idx].available();
let tail_index = (self.next_tail_idx + N - 1) % N;
let pkt = if read_available && self.read_idx != tail_index {
let pkt = self.buffers[self.read_idx].take();
let len = (self.rd[self.read_idx].rdes3.get() & EMAC_RDES3_PKTLEN) as usize;
assert!(pkt.is_some());
let valid = self.rd[self.read_idx].valid();
self.read_idx = (self.read_idx + 1) % N;
if valid {
pkt.map(|p| p.slice(0..len))
} else {
None
// We might have to process many packets, in case some have been rx'd but are invalid.
loop {
let descriptor = &mut self.descriptors[self.index];
if !descriptor.available() {
return None;
}
} else {
None
};
// Try to advance the tail_idx
if self.next_tail_idx != self.read_idx {
match PacketBox::new(Packet::new()) {
Some(b) => {
let addr = b.as_ptr() as u32;
self.buffers[self.next_tail_idx].replace(b);
self.rd[self.next_tail_idx].set_ready(addr);
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
// NOTE(unsafe) atomic write
unsafe {
ETH.ethernet_dma()
.dmacrx_dtpr()
.write(|w| w.0 = &self.rd[self.next_tail_idx] as *const _ as u32);
}
self.next_tail_idx = (self.next_tail_idx + 1) % N;
}
None => {}
// If packet is invalid, pop it and try again.
if !descriptor.valid() {
warn!("invalid packet: {:08x}", descriptor.rdes0.get());
self.pop_packet();
continue;
}
break;
}
pkt
let descriptor = &mut self.descriptors[self.index];
let len = (descriptor.rdes3.get() & EMAC_RDES3_PKTLEN) as usize;
return Some(&mut self.buffers[self.index].0[..len]);
}
}
pub struct DescriptorRing<const T: usize, const R: usize> {
pub(crate) tx: TDesRing<T>,
pub(crate) rx: RDesRing<R>,
}
/// Pop the packet previously returned by `available`.
pub(crate) fn pop_packet(&mut self) {
let descriptor = &mut self.descriptors[self.index];
assert!(descriptor.available());
impl<const T: usize, const R: usize> DescriptorRing<T, R> {
pub const fn new() -> Self {
Self {
tx: TDesRing::new(),
rx: RDesRing::new(),
self.descriptors[self.index].set_ready(self.buffers[self.index].0.as_mut_ptr());
// "Preceding reads and writes cannot be moved past subsequent writes."
fence(Ordering::Release);
// signal DMA it can try again.
// NOTE(unsafe) Atomic write
unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
// Increment index.
self.index += 1;
if self.index == self.descriptors.len() {
self.index = 0
}
}
pub fn init(&mut self) {
self.tx.init();
self.rx.init();
}
}

View File

@ -1,35 +1,28 @@
use core::marker::PhantomData;
mod descriptors;
use core::sync::atomic::{fence, Ordering};
use core::task::Waker;
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
use embassy_cortex_m::interrupt::InterruptExt;
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
use embassy_sync::waitqueue::AtomicWaker;
pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
use super::*;
use crate::gpio::sealed::{AFType, Pin as _};
use crate::gpio::{AnyPin, Speed};
use crate::pac::{ETH, RCC, SYSCFG};
use crate::Peripheral;
mod descriptors;
use descriptors::DescriptorRing;
const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
use super::*;
pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>);
impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> {
pub const fn new() -> Self {
Self(StateStorage::new())
}
}
pub struct Ethernet<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> {
state: PeripheralMutex<'d, Inner<'d, T, TX, RX>>,
pub struct Ethernet<'d, T: Instance, P: PHY> {
_peri: PeripheralRef<'d, T>,
pub(crate) tx: TDesRing<'d>,
pub(crate) rx: RDesRing<'d>,
pins: [PeripheralRef<'d, AnyPin>; 9],
_phy: P,
clock_range: u8,
phy_addr: u8,
mac_addr: [u8; 6],
pub(crate) mac_addr: [u8; 6],
}
macro_rules! config_pins {
@ -44,10 +37,9 @@ macro_rules! config_pins {
};
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, P, TX, RX> {
/// safety: the returned instance is not leak-safe
pub unsafe fn new(
state: &'d mut State<'d, T, TX, RX>,
impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
pub fn new<const TX: usize, const RX: usize>(
queue: &'d mut PacketQueue<TX, RX>,
peri: impl Peripheral<P = T> + 'd,
interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd,
ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
@ -63,108 +55,123 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
mac_addr: [u8; 6],
phy_addr: u8,
) -> Self {
into_ref!(interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// Enable the necessary Clocks
// NOTE(unsafe) We have exclusive access to the registers
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
RCC.ahb1enr().modify(|w| {
w.set_eth1macen(true);
w.set_eth1txen(true);
w.set_eth1rxen(true);
unsafe {
// Enable the necessary Clocks
// NOTE(unsafe) We have exclusive access to the registers
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
RCC.ahb1enr().modify(|w| {
w.set_eth1macen(true);
w.set_eth1txen(true);
w.set_eth1rxen(true);
});
// RMII
SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
});
// RMII
SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
});
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// NOTE(unsafe) We have exclusive access to the registers
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
// NOTE(unsafe) We are ourselves not leak-safe.
let state = PeripheralMutex::new(interrupt, &mut state.0, || Inner::new(peri));
// Reset and wait
dma.dmamr().modify(|w| w.set_swr(true));
while dma.dmamr().read().swr() {}
// NOTE(unsafe) We have exclusive access to the registers
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
mac.maccr().modify(|w| {
w.set_ipg(0b000); // 96 bit times
w.set_acs(true);
w.set_fes(true);
w.set_dm(true);
// TODO: Carrier sense ? ECRSFD
});
// Reset and wait
dma.dmamr().modify(|w| w.set_swr(true));
while dma.dmamr().read().swr() {}
// Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
// so the LR write must happen after the HR write.
mac.maca0hr()
.modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
mac.maca0lr().write(|w| {
w.set_addrlo(
u32::from(mac_addr[0])
| (u32::from(mac_addr[1]) << 8)
| (u32::from(mac_addr[2]) << 16)
| (u32::from(mac_addr[3]) << 24),
)
});
mac.maccr().modify(|w| {
w.set_ipg(0b000); // 96 bit times
w.set_acs(true);
w.set_fes(true);
w.set_dm(true);
// TODO: Carrier sense ? ECRSFD
});
mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
// Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
// so the LR write must happen after the HR write.
mac.maca0hr()
.modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
mac.maca0lr().write(|w| {
w.set_addrlo(
u32::from(mac_addr[0])
| (u32::from(mac_addr[1]) << 8)
| (u32::from(mac_addr[2]) << 16)
| (u32::from(mac_addr[3]) << 24),
)
});
// disable all MMC RX interrupts
mac.mmc_rx_interrupt_mask().write(|w| {
w.set_rxcrcerpim(true);
w.set_rxalgnerpim(true);
w.set_rxucgpim(true);
w.set_rxlpiuscim(true);
w.set_rxlpitrcim(true)
});
mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
// disable all MMC TX interrupts
mac.mmc_tx_interrupt_mask().write(|w| {
w.set_txscolgpim(true);
w.set_txmcolgpim(true);
w.set_txgpktim(true);
w.set_txlpiuscim(true);
w.set_txlpitrcim(true);
});
mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
dma.dmacrx_cr().modify(|w| {
w.set_rxpbl(1); // 32 ?
w.set_rbsz(MTU as u16);
});
dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
dma.dmacrx_cr().modify(|w| {
w.set_rxpbl(1); // 32 ?
w.set_rbsz(MTU as u16);
});
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = crate::rcc::get_freqs().ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = crate::rcc::get_freqs().ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
let clock_range = match hclk_mhz {
0..=34 => 2, // Divide by 16
35..=59 => 3, // Divide by 26
60..=99 => 0, // Divide by 42
100..=149 => 1, // Divide by 62
150..=249 => 4, // Divide by 102
250..=310 => 5, // Divide by 124
_ => {
panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
}
};
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
let clock_range = match hclk_mhz {
0..=34 => 2, // Divide by 16
35..=59 => 3, // Divide by 26
60..=99 => 0, // Divide by 42
100..=149 => 1, // Divide by 62
150..=249 => 4, // Divide by 102
250..=310 => 5, // Divide by 124
_ => {
panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
}
};
let pins = [
ref_clk.map_into(),
mdio.map_into(),
mdc.map_into(),
crs.map_into(),
rx_d0.map_into(),
rx_d1.map_into(),
tx_d0.map_into(),
tx_d1.map_into(),
tx_en.map_into(),
];
let pins = [
ref_clk.map_into(),
mdio.map_into(),
mdc.map_into(),
crs.map_into(),
rx_d0.map_into(),
rx_d1.map_into(),
tx_d0.map_into(),
tx_d1.map_into(),
tx_en.map_into(),
];
let mut this = Self {
state,
pins,
_phy: phy,
clock_range,
phy_addr,
mac_addr,
};
this.state.with(|s| {
s.desc_ring.init();
let mut this = Self {
_peri: peri,
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
pins,
_phy: phy,
clock_range,
phy_addr,
mac_addr,
};
fence(Ordering::SeqCst);
@ -187,17 +194,37 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
w.set_rie(true);
w.set_tie(true);
});
});
P::phy_reset(&mut this);
P::phy_init(&mut this);
this
P::phy_reset(&mut this);
P::phy_init(&mut this);
interrupt.set_handler(Self::on_interrupt);
interrupt.enable();
this
}
}
fn on_interrupt(_cx: *mut ()) {
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
dma.dmacsr().modify(|w| {
w.set_ti(true);
w.set_ri(true);
w.set_nis(true);
});
// Delay two peripheral's clock
dma.dmacsr().read();
dma.dmacsr().read();
}
}
}
unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationManagement
for Ethernet<'d, T, P, TX, RX>
{
unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
fn smi_read(&mut self, reg: u8) -> u16 {
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
unsafe {
@ -233,44 +260,7 @@ unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationMa
}
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, T, P, TX, RX> {
fn is_transmit_ready(&mut self) -> bool {
self.state.with(|s| s.desc_ring.tx.available())
}
fn transmit(&mut self, pkt: PacketBuf) {
self.state.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt)));
}
fn receive(&mut self) -> Option<PacketBuf> {
self.state.with(|s| s.desc_ring.rx.pop_packet())
}
fn register_waker(&mut self, waker: &Waker) {
WAKER.register(waker);
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = MTU;
caps.max_burst_size = Some(TX.min(RX));
caps
}
fn link_state(&mut self) -> LinkState {
if P::poll_link(self) {
LinkState::Up
} else {
LinkState::Down
}
}
fn ethernet_address(&self) -> [u8; 6] {
self.mac_addr
}
}
impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Ethernet<'d, T, P, TX, RX> {
impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
fn drop(&mut self) {
// NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers
unsafe {
@ -307,46 +297,3 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Etherne
})
}
}
//----------------------------------------------------------------------
struct Inner<'d, T: Instance, const TX: usize, const RX: usize> {
_peri: PhantomData<&'d mut T>,
desc_ring: DescriptorRing<TX, RX>,
}
impl<'d, T: Instance, const TX: usize, const RX: usize> Inner<'d, T, TX, RX> {
pub fn new(_peri: impl Peripheral<P = T> + 'd) -> Self {
Self {
_peri: PhantomData,
desc_ring: DescriptorRing::new(),
}
}
}
impl<'d, T: Instance, const TX: usize, const RX: usize> PeripheralState for Inner<'d, T, TX, RX> {
type Interrupt = crate::interrupt::ETH;
fn on_interrupt(&mut self) {
unwrap!(self.desc_ring.tx.on_interrupt());
self.desc_ring.rx.on_interrupt();
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
dma.dmacsr().modify(|w| {
w.set_ti(true);
w.set_ri(true);
w.set_nis(true);
});
// Delay two peripheral's clock
dma.dmacsr().read();
dma.dmacsr().read();
}
}
}
static WAKER: AtomicWaker = AtomicWaker::new();

View File

@ -25,11 +25,11 @@ fn cpu_regs() -> pac::exti::Exti {
EXTI
}
#[cfg(not(any(exti_g0, exti_l5, gpio_v1, exti_u5)))]
#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5)))]
fn exticr_regs() -> pac::syscfg::Syscfg {
pac::SYSCFG
}
#[cfg(any(exti_g0, exti_l5, exti_u5))]
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))]
fn exticr_regs() -> pac::exti::Exti {
EXTI
}
@ -39,9 +39,9 @@ fn exticr_regs() -> pac::afio::Afio {
}
pub unsafe fn on_irq() {
#[cfg(not(any(exti_g0, exti_l5, exti_u5)))]
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))]
let bits = EXTI.pr(0).read().0;
#[cfg(any(exti_g0, exti_l5, exti_u5))]
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))]
let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
// Mask all the channels that fired.
@ -53,9 +53,9 @@ pub unsafe fn on_irq() {
}
// Clear pending
#[cfg(not(any(exti_g0, exti_l5, exti_u5)))]
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))]
EXTI.pr(0).write_value(Lines(bits));
#[cfg(any(exti_g0, exti_l5, exti_u5))]
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))]
{
EXTI.rpr(0).write_value(Lines(bits));
EXTI.fpr(0).write_value(Lines(bits));
@ -167,39 +167,33 @@ mod eh1 {
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use futures::FutureExt;
use super::*;
impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for ExtiInput<'d, T> {
type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> {
self.wait_for_high().map(Ok)
async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
self.wait_for_high().await;
Ok(())
}
type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> {
self.wait_for_low().map(Ok)
async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
self.wait_for_low().await;
Ok(())
}
type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> {
self.wait_for_rising_edge().map(Ok)
async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
self.wait_for_rising_edge().await;
Ok(())
}
type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> {
self.wait_for_falling_edge().map(Ok)
async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
self.wait_for_falling_edge().await;
Ok(())
}
type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> {
self.wait_for_any_edge().map(Ok)
async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
self.wait_for_any_edge().await;
Ok(())
}
}
}
@ -218,9 +212,9 @@ impl<'a> ExtiInputFuture<'a> {
EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
// clear pending bit
#[cfg(not(any(exti_g0, exti_l5, exti_u5)))]
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5)))]
EXTI.pr(0).write(|w| w.set_line(pin, true));
#[cfg(any(exti_g0, exti_l5, exti_u5))]
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5))]
{
EXTI.rpr(0).write(|w| w.set_line(pin, true));
EXTI.fpr(0).write(|w| w.set_line(pin, true));

View File

@ -1,7 +1,6 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use super::{ERASE_SIZE, FLASH_BASE, FLASH_SIZE};
use crate::flash::Error;

View File

@ -1,7 +1,6 @@
use core::convert::TryInto;
use core::ptr::write_volatile;
use atomic_polyfill::{fence, Ordering};
use core::sync::atomic::{fence, Ordering};
use crate::flash::Error;
use crate::pac;

View File

@ -39,6 +39,10 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error
w.set_psize(2); // 32 bits at once
});
cortex_m::asm::isb();
cortex_m::asm::dsb();
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
let ret = {
let mut ret: Result<(), Error> = Ok(());
let mut offset = offset;
@ -64,6 +68,10 @@ pub(crate) unsafe fn blocking_write(offset: u32, buf: &[u8]) -> Result<(), Error
bank.cr().write(|w| w.set_pg(false));
cortex_m::asm::isb();
cortex_m::asm::dsb();
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
ret
}
@ -71,24 +79,19 @@ pub(crate) unsafe fn blocking_erase(from: u32, to: u32) -> Result<(), Error> {
let from = from - super::FLASH_BASE as u32;
let to = to - super::FLASH_BASE as u32;
let bank_size = (super::FLASH_SIZE / 2) as u32;
let (bank, start, end) = if to <= bank_size {
let (start, end) = if to <= super::FLASH_SIZE as u32 {
let start_sector = from / super::ERASE_SIZE as u32;
let end_sector = to / super::ERASE_SIZE as u32;
(0, start_sector, end_sector)
} else if from >= SECOND_BANK_OFFSET as u32 && to <= (SECOND_BANK_OFFSET as u32 + bank_size) {
let start_sector = (from - SECOND_BANK_OFFSET as u32) / super::ERASE_SIZE as u32;
let end_sector = (to - SECOND_BANK_OFFSET as u32) / super::ERASE_SIZE as u32;
(1, start_sector, end_sector)
(start_sector, end_sector)
} else {
error!("Attempting to write outside of defined sectors");
error!("Attempting to write outside of defined sectors {:x} {:x}", from, to);
return Err(Error::Unaligned);
};
trace!("Erasing bank {}, sectors from {} to {}", bank, start, end);
trace!("Erasing sectors from {} to {}", start, end);
for sector in start..end {
let ret = erase_sector(pac::FLASH.bank(bank), sector as u8);
let bank = if sector >= 8 { 1 } else { 0 };
let ret = erase_sector(pac::FLASH.bank(bank), (sector % 8) as u8);
if ret.is_err() {
return ret;
}

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

@ -7,6 +7,11 @@ use crate::interrupt::Interrupt;
mod _version;
pub use _version::*;
#[cfg(feature = "time")]
mod timeout;
#[cfg(feature = "time")]
pub use timeout::*;
use crate::peripherals;
#[derive(Debug)]

View File

@ -0,0 +1,142 @@
use embassy_time::{Duration, Instant};
use super::{Error, I2c, Instance};
/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
///
/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
/// A regular [I2c] would freeze until condition is removed.
pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> {
i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>,
timeout: Duration,
}
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
let deadline = Instant::now() + timeout;
move || {
if Instant::now() > deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
}
impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> {
pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
Self { i2c, timeout }
}
/// Blocking read with a custom timeout
pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> {
self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout))
}
/// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, buffer, self.timeout)
}
/// Blocking write with a custom timeout
pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> {
self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout))
}
/// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(addr, bytes, self.timeout)
}
/// Blocking write-read with a custom timeout
pub fn blocking_write_read_timeout(
&mut self,
addr: u8,
bytes: &[u8],
buffer: &mut [u8],
timeout: Duration,
) -> Result<(), Error> {
self.i2c
.blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout))
}
/// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout)
}
}
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> {
type Error = Error;
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(addr, buffer)
}
}
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> {
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(addr, bytes)
}
}
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> {
type Error = Error;
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(addr, bytes, buffer)
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> {
type Error = Error;
}
impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> {
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, buffer)
}
fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, buffer)
}
fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
todo!();
}
fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
todo!();
}
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, wr_buffer, rd_buffer)
}
fn transaction<'a>(
&mut self,
_address: u8,
_operations: &mut [embedded_hal_1::i2c::Operation<'a>],
) -> Result<(), Self::Error> {
todo!();
}
fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error>
where
O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>,
{
todo!();
}
}
}

View File

@ -1,8 +1,9 @@
use core::marker::PhantomData;
use embassy_embedded_hal::SetConfig;
use embassy_hal_common::into_ref;
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::dma::NoDma;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
@ -34,19 +35,26 @@ impl State {
}
}
pub struct I2c<'d, T: Instance> {
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
phantom: PhantomData<&'d mut T>,
#[allow(dead_code)]
tx_dma: PeripheralRef<'d, TXDMA>,
#[allow(dead_code)]
rx_dma: PeripheralRef<'d, RXDMA>,
}
impl<'d, T: Instance> I2c<'d, T> {
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(scl, sda);
into_ref!(scl, sda, tx_dma, rx_dma);
T::enable();
T::reset();
@ -99,7 +107,11 @@ impl<'d, T: Instance> I2c<'d, T> {
});
}
Self { phantom: PhantomData }
Self {
phantom: PhantomData,
tx_dma,
rx_dma,
}
}
unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
@ -141,7 +153,12 @@ impl<'d, T: Instance> I2c<'d, T> {
Ok(sr1)
}
unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
unsafe fn write_bytes(
&mut self,
addr: u8,
bytes: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
// Send a START condition
T::regs().cr1().modify(|reg| {
@ -149,7 +166,9 @@ impl<'d, T: Instance> I2c<'d, T> {
});
// Wait until START condition was generated
while !self.check_and_clear_error_flags()?.start() {}
while !self.check_and_clear_error_flags()?.start() {
check_timeout()?;
}
// Also wait until signalled we're master and everything is waiting for us
while {
@ -157,7 +176,9 @@ impl<'d, T: Instance> I2c<'d, T> {
let sr2 = T::regs().sr2().read();
!sr2.msl() && !sr2.busy()
} {}
} {
check_timeout()?;
}
// Set up current address, we're trying to talk to
T::regs().dr().write(|reg| reg.set_dr(addr << 1));
@ -165,26 +186,30 @@ impl<'d, T: Instance> I2c<'d, T> {
// Wait until address was sent
// Wait for the address to be acknowledged
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
while !self.check_and_clear_error_flags()?.addr() {}
while !self.check_and_clear_error_flags()?.addr() {
check_timeout()?;
}
// Clear condition by reading SR2
let _ = T::regs().sr2().read();
// Send bytes
for c in bytes {
self.send_byte(*c)?;
self.send_byte(*c, &check_timeout)?;
}
// Fallthrough is success
Ok(())
}
unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> {
unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
// Wait until we're ready for sending
while {
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
!self.check_and_clear_error_flags()?.txe()
} {}
} {
check_timeout()?;
}
// Push out a byte of data
T::regs().dr().write(|reg| reg.set_dr(byte));
@ -193,24 +218,33 @@ impl<'d, T: Instance> I2c<'d, T> {
while {
// Check for any potential error conditions.
!self.check_and_clear_error_flags()?.btf()
} {}
} {
check_timeout()?;
}
Ok(())
}
unsafe fn recv_byte(&self) -> Result<u8, Error> {
unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
while {
// Check for any potential error conditions.
self.check_and_clear_error_flags()?;
!T::regs().sr1().read().rxne()
} {}
} {
check_timeout()?;
}
let value = T::regs().dr().read().dr();
Ok(value)
}
pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
pub fn blocking_read_timeout(
&mut self,
addr: u8,
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
if let Some((last, buffer)) = buffer.split_last_mut() {
// Send a START condition and set ACK bit
unsafe {
@ -221,27 +255,33 @@ impl<'d, T: Instance> I2c<'d, T> {
}
// Wait until START condition was generated
while unsafe { !T::regs().sr1().read().start() } {}
while unsafe { !self.check_and_clear_error_flags()?.start() } {
check_timeout()?;
}
// Also wait until signalled we're master and everything is waiting for us
while {
let sr2 = unsafe { T::regs().sr2().read() };
!sr2.msl() && !sr2.busy()
} {}
} {
check_timeout()?;
}
// Set up current address, we're trying to talk to
unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) }
// Wait until address was sent
// Wait for the address to be acknowledged
while unsafe { !self.check_and_clear_error_flags()?.addr() } {}
while unsafe { !self.check_and_clear_error_flags()?.addr() } {
check_timeout()?;
}
// Clear condition by reading SR2
let _ = unsafe { T::regs().sr2().read() };
// Receive bytes into buffer
for c in buffer {
*c = unsafe { self.recv_byte()? };
*c = unsafe { self.recv_byte(&check_timeout)? };
}
// Prepare to send NACK then STOP after next byte
@ -253,10 +293,12 @@ impl<'d, T: Instance> I2c<'d, T> {
}
// Receive last byte
*last = unsafe { self.recv_byte()? };
*last = unsafe { self.recv_byte(&check_timeout)? };
// Wait for the STOP to be sent.
while unsafe { T::regs().cr1().read().stop() } {}
while unsafe { T::regs().cr1().read().stop() } {
check_timeout()?;
}
// Fallthrough is success
Ok(())
@ -265,25 +307,50 @@ impl<'d, T: Instance> I2c<'d, T> {
}
}
pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, buffer, || Ok(()))
}
pub fn blocking_write_timeout(
&mut self,
addr: u8,
bytes: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
unsafe {
self.write_bytes(addr, bytes)?;
self.write_bytes(addr, bytes, &check_timeout)?;
// Send a STOP condition
T::regs().cr1().modify(|reg| reg.set_stop(true));
// Wait for STOP condition to transmit.
while T::regs().cr1().read().stop() {}
while T::regs().cr1().read().stop() {
check_timeout()?;
}
};
// Fallthrough is success
Ok(())
}
pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
unsafe { self.write_bytes(addr, bytes)? };
self.blocking_read(addr, buffer)?;
pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(addr, bytes, || Ok(()))
}
pub fn blocking_write_read_timeout(
&mut self,
addr: u8,
bytes: &[u8],
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
unsafe { self.write_bytes(addr, bytes, &check_timeout)? };
self.blocking_read_timeout(addr, buffer, &check_timeout)?;
Ok(())
}
pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(()))
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> {

View File

@ -1,8 +1,8 @@
use core::cmp;
use core::future::poll_fn;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::task::Poll;
use atomic_polyfill::{AtomicUsize, Ordering};
use embassy_embedded_hal::SetConfig;
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef};
@ -131,7 +131,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if isr.tcr() || isr.tc() {
let state = T::state();
state.chunks_transferred.fetch_add(1, Ordering::Relaxed);
let transferred = state.chunks_transferred.load(Ordering::Relaxed);
state.chunks_transferred.store(transferred + 1, Ordering::Relaxed);
state.waker.wake();
}
// The flag can only be cleared by writting to nbytes, we won't do that here, so disable
@ -147,14 +148,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) {
unsafe fn master_read(
address: u8,
length: usize,
stop: Stop,
reload: bool,
restart: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
assert!(length < 256);
if !restart {
// Wait for any previous address sequence to end
// automatically. This could be up to 50% of a bus
// cycle (ie. up to 0.5/freq)
while T::regs().cr2().read().start() {}
while T::regs().cr2().read().start() {
check_timeout()?;
}
}
// Set START and prepare to receive bytes into
@ -176,15 +186,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
w.set_autoend(stop.autoend());
w.set_reload(reload);
});
Ok(())
}
unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) {
unsafe fn master_write(
address: u8,
length: usize,
stop: Stop,
reload: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
assert!(length < 256);
// Wait for any previous address sequence to end
// automatically. This could be up to 50% of a bus
// cycle (ie. up to 0.5/freq)
while T::regs().cr2().read().start() {}
while T::regs().cr2().read().start() {
check_timeout()?;
}
let reload = if reload {
i2c::vals::Reload::NOTCOMPLETED
@ -204,12 +224,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
w.set_autoend(stop.autoend());
w.set_reload(reload);
});
Ok(())
}
unsafe fn master_continue(length: usize, reload: bool) {
unsafe fn master_continue(
length: usize,
reload: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
assert!(length < 256 && length > 0);
while !T::regs().isr().read().tcr() {}
while !T::regs().isr().read().tcr() {
check_timeout()?;
}
let reload = if reload {
i2c::vals::Reload::NOTCOMPLETED
@ -221,6 +249,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
w.set_nbytes(length as u8);
w.set_reload(reload);
});
Ok(())
}
fn flush_txdr(&self) {
@ -243,7 +273,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
//}
}
fn wait_txe(&self) -> Result<(), Error> {
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
@ -261,10 +291,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack);
}
}
check_timeout()?;
}
}
fn wait_rxne(&self) -> Result<(), Error> {
fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
@ -282,10 +314,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack);
}
}
check_timeout()?;
}
}
fn wait_tc(&self) -> Result<(), Error> {
fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
@ -303,10 +337,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack);
}
}
check_timeout()?;
}
}
fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> {
fn read_internal(
&mut self,
address: u8,
buffer: &mut [u8],
restart: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
let completed_chunks = buffer.len() / 255;
let total_chunks = if completed_chunks * 255 == buffer.len() {
completed_chunks
@ -322,20 +364,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Stop::Automatic,
last_chunk_idx != 0,
restart,
);
&check_timeout,
)?;
}
for (number, chunk) in buffer.chunks_mut(255).enumerate() {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(chunk.len(), number != last_chunk_idx);
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
}
for byte in chunk {
// Wait until we have received something
self.wait_rxne()?;
self.wait_rxne(&check_timeout)?;
unsafe {
*byte = T::regs().rxdr().read().rxdata();
@ -345,7 +388,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
fn write_internal(
&mut self,
address: u8,
bytes: &[u8],
send_stop: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
let completed_chunks = bytes.len() / 255;
let total_chunks = if completed_chunks * 255 == bytes.len() {
completed_chunks
@ -359,14 +408,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// ST SAD+W
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0);
Self::master_write(
address,
bytes.len().min(255),
Stop::Software,
last_chunk_idx != 0,
&check_timeout,
)?;
}
for (number, chunk) in bytes.chunks(255).enumerate() {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(chunk.len(), number != last_chunk_idx);
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
}
@ -374,7 +429,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until we are allowed to send data
// (START has been ACKed or last byte when
// through)
self.wait_txe()?;
self.wait_txe(&check_timeout)?;
unsafe {
T::regs().txdr().write(|w| w.set_txdata(*byte));
@ -382,7 +437,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
// Wait until the write finishes
self.wait_tc()?;
self.wait_tc(&check_timeout)?;
if send_stop {
self.master_stop();
@ -396,6 +451,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
bytes: &[u8],
first_slice: bool,
last_slice: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
@ -427,7 +483,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
state.chunks_transferred.store(0, Ordering::Relaxed);
let mut remaining_len = total_len;
let _on_drop = OnDrop::new(|| {
let on_drop = OnDrop::new(|| {
let regs = T::regs();
unsafe {
regs.cr1().modify(|w| {
@ -447,11 +503,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
total_len.min(255),
Stop::Software,
(total_chunks != 1) || !last_slice,
);
&check_timeout,
)?;
}
} else {
unsafe {
Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice);
Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?;
T::regs().cr1().modify(|w| w.set_tcie(true));
}
}
@ -461,32 +518,43 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
if chunks_transferred == total_chunks {
return Poll::Ready(());
return Poll::Ready(Ok(()));
} else if chunks_transferred != 0 {
remaining_len = remaining_len.saturating_sub(255);
let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice;
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
unsafe {
Self::master_continue(remaining_len.min(255), !last_piece);
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
return Poll::Ready(Err(e));
}
T::regs().cr1().modify(|w| w.set_tcie(true));
}
}
Poll::Pending
})
.await;
.await?;
dma_transfer.await;
if last_slice {
// This should be done already
self.wait_tc()?;
self.wait_tc(&check_timeout)?;
self.master_stop();
}
drop(on_drop);
Ok(())
}
async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error>
async fn read_dma_internal(
&mut self,
address: u8,
buffer: &mut [u8],
restart: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
RXDMA: crate::i2c::RxDma<T>,
{
@ -515,7 +583,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
state.chunks_transferred.store(0, Ordering::Relaxed);
let mut remaining_len = total_len;
let _on_drop = OnDrop::new(|| {
let on_drop = OnDrop::new(|| {
let regs = T::regs();
unsafe {
regs.cr1().modify(|w| {
@ -527,7 +595,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
unsafe {
Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart);
Self::master_read(
address,
total_len.min(255),
Stop::Software,
total_chunks != 1,
restart,
&check_timeout,
)?;
}
poll_fn(|cx| {
@ -535,26 +610,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed);
if chunks_transferred == total_chunks {
return Poll::Ready(());
return Poll::Ready(Ok(()));
} else if chunks_transferred != 0 {
remaining_len = remaining_len.saturating_sub(255);
let last_piece = chunks_transferred + 1 == total_chunks;
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
unsafe {
Self::master_continue(remaining_len.min(255), !last_piece);
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) {
return Poll::Ready(Err(e));
}
T::regs().cr1().modify(|w| w.set_tcie(true));
}
}
Poll::Pending
})
.await;
.await?;
dma_transfer.await;
// This should be done already
self.wait_tc()?;
self.wait_tc(&check_timeout)?;
self.master_stop();
drop(on_drop);
Ok(())
}
@ -566,9 +646,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
TXDMA: crate::i2c::TxDma<T>,
{
if bytes.is_empty() {
self.write_internal(address, bytes, true)
self.write_internal(address, bytes, true, || Ok(()))
} else {
self.write_dma_internal(address, bytes, true, true).await
self.write_dma_internal(address, bytes, true, true, || Ok(())).await
}
}
@ -587,7 +667,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let next = iter.next();
let is_last = next.is_none();
self.write_dma_internal(address, c, first, is_last).await?;
self.write_dma_internal(address, c, first, is_last, || Ok(())).await?;
first = false;
current = next;
}
@ -599,9 +679,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
RXDMA: crate::i2c::RxDma<T>,
{
if buffer.is_empty() {
self.read_internal(address, buffer, false)
self.read_internal(address, buffer, false, || Ok(()))
} else {
self.read_dma_internal(address, buffer, false).await
self.read_dma_internal(address, buffer, false, || Ok(())).await
}
}
@ -611,15 +691,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
RXDMA: super::RxDma<T>,
{
if bytes.is_empty() {
self.write_internal(address, bytes, false)?;
self.write_internal(address, bytes, false, || Ok(()))?;
} else {
self.write_dma_internal(address, bytes, true, true).await?;
self.write_dma_internal(address, bytes, true, true, || Ok(())).await?;
}
if buffer.is_empty() {
self.read_internal(address, buffer, true)?;
self.read_internal(address, buffer, true, || Ok(()))?;
} else {
self.read_dma_internal(address, buffer, true).await?;
self.read_dma_internal(address, buffer, true, || Ok(())).await?;
}
Ok(())
@ -628,22 +708,55 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// =========================
// Blocking public API
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.read_internal(address, buffer, false)
pub fn blocking_read_timeout(
&mut self,
address: u8,
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.read_internal(address, buffer, false, &check_timeout)
// Automatic Stop
}
pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(address, buffer, || Ok(()))
}
pub fn blocking_write_timeout(
&mut self,
address: u8,
bytes: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.write_internal(address, bytes, true, &check_timeout)
}
pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
self.write_internal(address, bytes, true)
self.blocking_write_timeout(address, bytes, || Ok(()))
}
pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.write_internal(address, bytes, false)?;
self.read_internal(address, buffer, true)
pub fn blocking_write_read_timeout(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.write_internal(address, bytes, false, &check_timeout)?;
self.read_internal(address, buffer, true, &check_timeout)
// Automatic Stop
}
pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(address, bytes, buffer, || Ok(()))
}
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
bytes: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
if bytes.is_empty() {
return Err(Error::ZeroLengthTransfer);
}
@ -657,7 +770,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
first_length.min(255),
Stop::Software,
(first_length > 255) || (last_slice_index != 0),
);
&check_timeout,
)?;
}
for (idx, slice) in bytes.iter().enumerate() {
@ -673,7 +787,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if idx != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255));
Self::master_continue(
slice_len.min(255),
(idx != last_slice_index) || (slice_len > 255),
&check_timeout,
)?;
}
}
@ -681,7 +799,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index));
Self::master_continue(
chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index),
&check_timeout,
)?;
}
}
@ -689,7 +811,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until we are allowed to send data
// (START has been ACKed or last byte when
// through)
self.wait_txe()?;
self.wait_txe(&check_timeout)?;
// Put byte on the wire
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
@ -700,11 +822,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
// Wait until the write finishes
self.wait_tc()?;
self.wait_tc(&check_timeout)?;
self.master_stop();
Ok(())
}
pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> {
self.blocking_write_vectored_timeout(address, bytes, || Ok(()))
}
}
mod eh02 {
@ -929,43 +1055,35 @@ mod eh1 {
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use core::future::Future;
use super::super::{RxDma, TxDma};
use super::*;
impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c::I2c for I2c<'d, T, TXDMA, RXDMA> {
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.read(address, buffer)
async fn read<'a>(&'a mut self, address: u8, read: &'a mut [u8]) -> Result<(), Self::Error> {
self.read(address, read).await
}
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> {
self.write(address, bytes)
async fn write<'a>(&'a mut self, address: u8, write: &'a [u8]) -> Result<(), Self::Error> {
self.write(address, write).await
}
type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn write_read<'a>(
async fn write_read<'a>(
&'a mut self,
address: u8,
bytes: &'a [u8],
buffer: &'a mut [u8],
) -> Self::WriteReadFuture<'a> {
self.write_read(address, bytes, buffer)
write: &'a [u8],
read: &'a mut [u8],
) -> Result<(), Self::Error> {
self.write_read(address, write, read).await
}
type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a;
fn transaction<'a, 'b>(
async fn transaction<'a, 'b>(
&'a mut self,
address: u8,
operations: &'a mut [embedded_hal_async::i2c::Operation<'b>],
) -> Self::TransactionFuture<'a, 'b> {
operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
) -> Result<(), Self::Error> {
let _ = address;
let _ = operations;
async move { todo!() }
todo!()
}
}
}

View File

@ -1,5 +1,9 @@
#![no_std]
#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
#![cfg_attr(
feature = "nightly",
feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
)]
#![cfg_attr(feature = "nightly", allow(incomplete_features))]
// This must go FIRST so that all the other modules see its macros.
pub mod fmt;
@ -54,9 +58,9 @@ pub mod sdmmc;
pub mod spi;
#[cfg(usart)]
pub mod usart;
#[cfg(usb)]
#[cfg(all(usb, feature = "time"))]
pub mod usb;
#[cfg(any(otgfs, otghs))]
#[cfg(otg)]
pub mod usb_otg;
#[cfg(iwdg)]
@ -77,6 +81,8 @@ pub(crate) mod _generated {
// Reexports
pub use _generated::{peripherals, Peripherals};
pub use embassy_cortex_m::executor;
#[cfg(any(dma, bdma))]
use embassy_cortex_m::interrupt::Priority;
pub use embassy_cortex_m::interrupt::_export::interrupt;
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
#[cfg(feature = "unstable-pac")]
@ -89,6 +95,10 @@ pub struct Config {
pub rcc: rcc::Config,
#[cfg(dbgmcu)]
pub enable_debug_during_sleep: bool,
#[cfg(bdma)]
pub bdma_interrupt_priority: Priority,
#[cfg(dma)]
pub dma_interrupt_priority: Priority,
}
impl Default for Config {
@ -97,6 +107,10 @@ impl Default for Config {
rcc: Default::default(),
#[cfg(dbgmcu)]
enable_debug_during_sleep: true,
#[cfg(bdma)]
bdma_interrupt_priority: Priority::P0,
#[cfg(dma)]
dma_interrupt_priority: Priority::P0,
}
}
}
@ -109,7 +123,7 @@ pub fn init(config: Config) -> Peripherals {
#[cfg(dbgmcu)]
if config.enable_debug_during_sleep {
crate::pac::DBGMCU.cr().modify(|cr| {
#[cfg(any(dbgmcu_f0, dbgmcu_g0, dbgmcu_u5))]
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
{
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
@ -135,7 +149,12 @@ pub fn init(config: Config) -> Peripherals {
}
gpio::init();
dma::init();
dma::init(
#[cfg(bdma)]
config.bdma_interrupt_priority,
#[cfg(dma)]
config.dma_interrupt_priority,
);
#[cfg(feature = "exti")]
exti::init();

233
embassy-stm32/src/rcc/c0.rs Normal file
View File

@ -0,0 +1,233 @@
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Hpre, Hsidiv, Ppre, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI(HSIPrescaler),
LSI,
}
#[derive(Clone, Copy)]
pub enum HSIPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSIPrescaler {
fn into(self) -> Hsidiv {
match self {
HSIPrescaler::NotDivided => Hsidiv::DIV1,
HSIPrescaler::Div2 => Hsidiv::DIV2,
HSIPrescaler::Div4 => Hsidiv::DIV4,
HSIPrescaler::Div8 => Hsidiv::DIV8,
HSIPrescaler::Div16 => Hsidiv::DIV16,
HSIPrescaler::Div32 => Hsidiv::DIV32,
HSIPrescaler::Div64 => Hsidiv::DIV64,
HSIPrescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// AHB prescaler
#[derive(Clone, Copy, PartialEq)]
pub enum AHBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div64,
Div128,
Div256,
Div512,
}
/// APB prescaler
#[derive(Clone, Copy)]
pub enum APBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
}
impl Into<Ppre> for APBPrescaler {
fn into(self) -> Ppre {
match self {
APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
impl Into<Hpre> for AHBPrescaler {
fn into(self) -> Hpre {
match self {
AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
ahb_pre: AHBPrescaler::NotDivided,
apb_pre: APBPrescaler::NotDivided,
}
}
}
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux {
ClockSrc::HSI(div) => {
// Enable HSI
let div: Hsidiv = div.into();
RCC.cr().write(|w| {
w.set_hsidiv(div);
w.set_hsion(true)
});
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.0, Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE)
}
ClockSrc::LSI => {
// Enable LSI
RCC.csr2().write(|w| w.set_lsion(true));
while !RCC.csr2().read().lsirdy() {}
(LSI_FREQ.0, Sw::LSI)
}
};
// Determine the flash latency implied by the target clock speed
// RM0454 § 3.3.4:
let target_flash_latency = if sys_clk <= 24_000_000 {
Latency::WS0
} else {
Latency::WS1
};
// Increase the number of cycles we wait for flash if the new value is higher
// There's no harm in waiting a little too much before the clock change, but we'll
// crash immediately if we don't wait enough after the clock change
let mut set_flash_latency_after = false;
FLASH.acr().modify(|w| {
// Is the current flash latency less than what we need at the new SYSCLK?
if w.latency().0 <= target_flash_latency.0 {
// We must increase the number of wait states now
w.set_latency(target_flash_latency)
} else {
// We may decrease the number of wait states later
set_flash_latency_after = true;
}
// RM0490 § 3.3.4:
// > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register
// > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the
// > Flash memory.
//
// Enable flash prefetching if we have at least one wait state, and disable it otherwise.
w.set_prften(target_flash_latency.0 > 0);
});
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into());
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(hpre);
w.set_ppre(ppre);
});
if set_flash_latency_after {
// We can make the flash require fewer wait states
// Spin until the SYSCLK changes have taken effect
loop {
let cfgr = RCC.cfgr().read();
if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
break;
}
}
// Set the flash latency to require fewer wait states
FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
}
let ahb_div = match config.ahb_pre {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 2,
AHBPrescaler::Div4 => 4,
AHBPrescaler::Div8 => 8,
AHBPrescaler::Div16 => 16,
AHBPrescaler::Div64 => 64,
AHBPrescaler::Div128 => 128,
AHBPrescaler::Div256 => 256,
AHBPrescaler::Div512 => 512,
};
let ahb_freq = sys_clk / ahb_div;
let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),
apb1: Hertz(apb_freq),
apb1_tim: Hertz(apb_tim_freq),
});
}

View File

@ -10,6 +10,7 @@ use crate::time::Hertz;
#[cfg_attr(rcc_f3, path = "f3.rs")]
#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
#[cfg_attr(rcc_f7, path = "f7.rs")]
#[cfg_attr(rcc_c0, path = "c0.rs")]
#[cfg_attr(rcc_g0, path = "g0.rs")]
#[cfg_attr(rcc_g4, path = "g4.rs")]
#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
@ -23,16 +24,17 @@ use crate::time::Hertz;
mod _version;
pub use _version::*;
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Clocks {
pub sys: Hertz,
// APB
pub apb1: Hertz,
pub apb1_tim: Hertz,
#[cfg(not(rcc_g0))]
#[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2: Hertz,
#[cfg(not(rcc_g0))]
#[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2_tim: Hertz,
#[cfg(any(rcc_wl5, rcc_wle, rcc_u5))]
pub apb3: Hertz,
@ -71,6 +73,7 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
///
/// Safety: Sets a mutable global.
pub(crate) unsafe fn set_freqs(freqs: Clocks) {
debug!("rcc: {:?}", freqs);
CLOCK_FREQS.as_mut_ptr().write(freqs);
}

View File

@ -295,6 +295,7 @@ pub struct Config {
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
pub hsi48: bool,
}
impl Default for Config {
@ -305,6 +306,7 @@ impl Default for Config {
apb1_pre: Default::default(),
apb2_pre: Default::default(),
apb3_pre: Default::default(),
hsi48: false,
}
}
}
@ -320,7 +322,6 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| {
w.set_msipllen(false);
w.set_msison(true);
w.set_msison(true);
});
while !RCC.cr().read().msisrdy() {}
@ -340,9 +341,20 @@ pub(crate) unsafe fn init(config: Config) {
}
ClockSrc::PLL1R(src, m, n, div) => {
let freq = match src {
PllSrc::MSI(_) => MSIRange::default().into(),
PllSrc::HSE(hertz) => hertz.0,
PllSrc::HSI16 => HSI_FREQ.0,
PllSrc::MSI(_) => {
// TODO: enable MSI
MSIRange::default().into()
}
PllSrc::HSE(hertz) => {
// TODO: enable HSE
hertz.0
}
PllSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0
}
};
// disable
@ -355,6 +367,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.pll1cfgr().write(|w| {
w.set_pllm(m.into());
w.set_pllsrc(src.into());
w.set_pllren(true);
});
RCC.pll1divr().modify(|w| {
@ -365,15 +378,16 @@ pub(crate) unsafe fn init(config: Config) {
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(0, true));
while !RCC.cr().read().pllrdy(0) {}
RCC.pll1cfgr().modify(|w| w.set_pllren(true));
RCC.cr().write(|w| w.set_pllon(0, true));
while !RCC.cr().read().pllrdy(0) {}
pll_ck
}
};
if config.hsi48 {
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48rdy() {}
}
// TODO make configurable
let power_vos = VoltageScale::Range4;

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

@ -18,6 +18,9 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// Frequency used for SD Card initialization. Must be no higher than 400 kHz.
const SD_INIT_FREQ: Hertz = Hertz(400_000);
/// The signalling scheme used on the SDMMC bus
#[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -295,7 +298,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
T::reset();
let inner = T::inner();
let clock = unsafe { inner.new_inner(T::frequency()) };
unsafe { inner.new_inner() };
irq.set_handler(Self::on_interrupt);
irq.unpend();
@ -314,7 +317,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
d3,
config,
clock,
clock: SD_INIT_FREQ,
signalling: Default::default(),
card: None,
}
@ -415,7 +418,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
T::reset();
let inner = T::inner();
let clock = unsafe { inner.new_inner(T::frequency()) };
unsafe { inner.new_inner() };
irq.set_handler(Self::on_interrupt);
irq.unpend();
@ -434,7 +437,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
d3,
config,
clock,
clock: SD_INIT_FREQ,
signalling: Default::default(),
card: None,
}
@ -561,16 +564,10 @@ impl SdmmcInner {
/// # Safety
///
/// Access to `regs` registers should be exclusive
unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz {
unsafe fn new_inner(&self) {
let regs = self.0;
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be less than 400 kHz.
let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
regs.clkcr().write(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
w.set_pwrsav(false);
w.set_negedge(false);
w.set_hwfc_en(true);
@ -582,8 +579,6 @@ impl SdmmcInner {
// Power off, writen 00: Clock to the card is stopped;
// D[7:0], CMD, and CK are driven high.
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
clock
}
/// Initializes card (if present) and sets the bus at the
@ -605,6 +600,19 @@ impl SdmmcInner {
// NOTE(unsafe) We have exclusive access to the peripheral
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));
*clock = init_clock;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
self.wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
self.cmd(Cmd::idle(), false)?;
@ -1524,7 +1532,7 @@ foreach_peripheral!(
};
);
#[cfg(feature = "sdmmc-rs")]
#[cfg(feature = "embedded-sdmmc")]
mod sdmmc_rs {
use core::future::Future;
@ -1532,16 +1540,16 @@ 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>
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + 'a;
type WriteFuture<'a>
Self: 'a;
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
where
Self: 'a,
= impl Future<Output = Result<(), Self::Error>> + 'a;
Self: 'a;
fn read<'a>(
&'a mut self,
@ -1550,19 +1558,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(())
@ -1571,19 +1574,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

@ -8,9 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef};
pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
use self::sealed::WordSize;
use crate::dma::{slice_ptr_parts, NoDma, Transfer};
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,15 +93,18 @@ 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);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
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);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
mosi.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -129,10 +132,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
into_ref!(sck, miso);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
sck.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -160,10 +161,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
into_ref!(sck, mosi);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
#[cfg(any(spi_v2, spi_v3, spi_v4))]
mosi.set_speed(crate::gpio::Speed::VeryHigh);
}
@ -474,7 +473,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
let tx_request = self.txdma.request();
let tx_dst = T::REGS.tx_ptr();
let clock_byte = 0x00u8;
let tx_f = crate::dma::write_repeated(&mut self.txdma, tx_request, clock_byte, clock_byte_count, tx_dst);
let tx_f = crate::dma::write_repeated(&mut self.txdma, tx_request, &clock_byte, clock_byte_count, tx_dst);
unsafe {
set_txdmaen(T::REGS, true);
@ -772,10 +771,13 @@ fn finish_dma(regs: Regs) {
#[cfg(not(any(spi_v3, spi_v4)))]
while regs.sr().read().bsy() {}
// Disable the spi peripheral
regs.cr1().modify(|w| {
w.set_spe(false);
});
// The peripheral automatically disables the DMA stream on completion without error,
// but it does not clear the RXDMAEN/TXDMAEN flag in CR2.
#[cfg(not(any(spi_v3, spi_v4)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(false);
@ -812,7 +814,7 @@ mod eh02 {
// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
macro_rules! impl_blocking {
($w:ident) => {
impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, NoDma, NoDma> {
impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, T, Tx, Rx> {
type Error = Error;
fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@ -820,7 +822,7 @@ mod eh02 {
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, NoDma, NoDma> {
impl<'d, T: Instance, Tx, Rx> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, T, Tx, Rx> {
type Error = Error;
fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@ -849,19 +851,19 @@ mod eh1 {
}
}
impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, NoDma, NoDma> {
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusRead<W> for Spi<'d, T, Tx, Rx> {
fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.blocking_read(words)
}
}
impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, NoDma, NoDma> {
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
self.blocking_write(words)
}
}
impl<'d, T: Instance, W: Word> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, NoDma, NoDma> {
impl<'d, T: Instance, W: Word, Tx, Rx> embedded_hal_1::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error> {
self.blocking_transfer(read, write)
}
@ -885,46 +887,34 @@ mod eh1 {
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use core::future::Future;
use super::*;
impl<'d, T: Instance, Tx, Rx> embedded_hal_async::spi::SpiBusFlush for Spi<'d, T, Tx, Rx> {
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
async { Ok(()) }
async fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx, W: Word> embedded_hal_async::spi::SpiBusWrite<W> for Spi<'d, T, Tx, Rx> {
type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn write<'a>(&'a mut self, data: &'a [W]) -> Self::WriteFuture<'a> {
self.write(data)
async fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
self.write(words).await
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBusRead<W>
for Spi<'d, T, Tx, Rx>
{
type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn read<'a>(&'a mut self, data: &'a mut [W]) -> Self::ReadFuture<'a> {
self.read(data)
async fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.read(words).await
}
}
impl<'d, T: Instance, Tx: TxDma<T>, Rx: RxDma<T>, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, T, Tx, Rx> {
type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn transfer<'a>(&'a mut self, rx: &'a mut [W], tx: &'a [W]) -> Self::TransferFuture<'a> {
self.transfer(rx, tx)
async fn transfer<'a>(&'a mut self, read: &'a mut [W], write: &'a [W]) -> Result<(), Self::Error> {
self.transfer(read, write).await
}
type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Self::TransferInPlaceFuture<'a> {
self.transfer_in_place(words)
async fn transfer_in_place<'a>(&'a mut self, words: &'a mut [W]) -> Result<(), Self::Error> {
self.transfer_in_place(words).await
}
}
}

View File

@ -439,6 +439,7 @@ impl From<Timeout> for [u8; 3] {
}
}
#[cfg(feature = "time")]
impl From<Timeout> for embassy_time::Duration {
fn from(to: Timeout) -> Self {
embassy_time::Duration::from_micros(to.as_micros().into())

View File

@ -44,6 +44,7 @@ impl From<RampTime> for core::time::Duration {
}
}
#[cfg(feature = "time")]
impl From<RampTime> for embassy_time::Duration {
fn from(rt: RampTime) -> Self {
match rt {

View File

@ -2,6 +2,7 @@
/// Hertz
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Hertz(pub u32);
impl Hertz {

View File

@ -292,19 +292,23 @@ impl Driver for RtcDriver {
})
}
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) {
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
critical_section::with(|cs| {
let r = T::regs_gp16();
let n = alarm.id() as _;
let n = alarm.id() as usize;
let alarm = self.get_alarm(cs, alarm);
alarm.timestamp.set(timestamp);
let t = self.now();
if timestamp <= t {
// If alarm timestamp has passed the alarm will not fire.
// Disarm the alarm and return `false` to indicate that.
unsafe { r.dier().modify(|w| w.set_ccie(n + 1, false)) };
self.trigger_alarm(n, cs);
return;
alarm.timestamp.set(u64::MAX);
return false;
}
let safe_timestamp = timestamp.max(t + 3);
@ -317,6 +321,8 @@ impl Driver for RtcDriver {
let diff = timestamp - t;
// NOTE(unsafe) We're in a critical section
unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
true
})
}
}

View File

@ -1,8 +1,8 @@
use core::cell::RefCell;
use core::future::{poll_fn, Future};
use core::future::poll_fn;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use atomic_polyfill::{compiler_fence, Ordering};
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
use embassy_hal_common::ring_buffer::RingBuffer;
use embassy_sync::waitqueue::WakerRegistration;
@ -46,16 +46,102 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {}
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
pub fn new(
state: &'d mut State<'d, T>,
_uart: Uart<'d, T, NoDma, NoDma>,
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
into_ref!(irq);
T::enable();
T::reset();
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
}
pub fn new_with_rtscts(
state: &'d mut State<'d, T>,
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
into_ref!(cts, rts);
T::enable();
T::reset();
unsafe {
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_rtse(true);
w.set_ctse(true);
});
}
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
}
#[cfg(not(usart_v1))]
pub fn new_with_de(
state: &'d mut State<'d, T>,
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
into_ref!(de);
T::enable();
T::reset();
unsafe {
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
}
Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config)
}
fn new_inner(
state: &'d mut State<'d, T>,
_peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
) -> BufferedUart<'d, T> {
into_ref!(_peri, rx, tx, irq);
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
unsafe {
r.cr1().modify(|w| {
#[cfg(lpuart_v2)]
w.set_fifoen(true);
w.set_rxneie(true);
w.set_idleie(true);
});
@ -283,32 +369,20 @@ impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> {
}
impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.inner_read(buf)
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.inner_read(buf).await
}
}
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> {
type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
self.inner.inner_read(buf)
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.inner.inner_read(buf).await
}
}
impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
where
Self: 'a;
fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
self.inner_fill_buf()
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
self.inner_fill_buf().await
}
fn consume(&mut self, amt: usize) {
@ -317,12 +391,8 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T>
}
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> {
type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
where
Self: 'a;
fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
self.inner.inner_fill_buf()
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
self.inner.inner_fill_buf().await
}
fn consume(&mut self, amt: usize) {
@ -331,37 +401,21 @@ impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'
}
impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.inner_write(buf)
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.inner_write(buf).await
}
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
where
Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
self.inner_flush()
async fn flush(&mut self) -> Result<(), Self::Error> {
self.inner_flush().await
}
}
impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> {
type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
where
Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.inner.inner_write(buf)
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.inner.inner_write(buf).await
}
type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
where
Self: 'a;
fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
self.inner.inner_flush()
async fn flush(&mut self) -> Result<(), Self::Error> {
self.inner.inner_flush().await
}
}

View File

@ -1,7 +1,13 @@
#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_cortex_m::interrupt::InterruptExt;
use embassy_futures::select::{select, Either};
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::dma::NoDma;
@ -10,6 +16,7 @@ use crate::gpio::sealed::AFType;
use crate::pac::lpuart::{regs, vals, Lpuart as Regs};
#[cfg(not(any(lpuart_v1, lpuart_v2)))]
use crate::pac::usart::{regs, vals, Usart as Regs};
use crate::time::Hertz;
use crate::{peripherals, Peripheral};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@ -44,6 +51,10 @@ pub struct Config {
pub data_bits: DataBits,
pub stop_bits: StopBits,
pub parity: Parity,
/// if true, on read-like method, if there is a latent error pending,
/// read will abort, the error reported and cleared
/// if false, the error is ignored and cleared
pub detect_previous_overrun: bool,
}
impl Default for Config {
@ -53,6 +64,8 @@ impl Default for Config {
data_bits: DataBits::DataBits8,
stop_bits: StopBits::STOP1,
parity: Parity::ParityNone,
// historical behavior
detect_previous_overrun: false,
}
}
}
@ -70,10 +83,18 @@ pub enum Error {
Overrun,
/// Parity check error
Parity,
/// Buffer too large for DMA
BufferTooLong,
}
enum ReadCompletionEvent {
// DMA Read transfer completed first
DmaCompleted,
// Idle line detected first
Idle,
}
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
phantom: PhantomData<&'d mut T>,
tx: UartTx<'d, T, TxDma>,
rx: UartRx<'d, T, RxDma>,
}
@ -84,12 +105,65 @@ pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
}
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
phantom: PhantomData<&'d mut T>,
_peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>,
detect_previous_overrun: bool,
}
impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
fn new(tx_dma: PeripheralRef<'d, TxDma>) -> Self {
/// usefull if you only want Uart Tx. It saves 1 pin and consumes a little less power
pub fn new(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
T::enable();
T::reset();
Self::new_inner(peri, tx, tx_dma, config)
}
pub fn new_with_cts(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
into_ref!(cts);
T::enable();
T::reset();
unsafe {
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_ctse(true);
});
}
Self::new_inner(peri, tx, tx_dma, config)
}
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Self {
into_ref!(_peri, tx, tx_dma);
let r = T::regs();
unsafe {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
configure(r, &config, T::frequency(), T::MULTIPLIER, false, true);
// create state once!
let _s = T::state();
Self {
tx_dma,
phantom: PhantomData,
@ -135,10 +209,120 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
}
impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
fn new(rx_dma: PeripheralRef<'d, RxDma>) -> Self {
/// usefull if you only want Uart Rx. It saves 1 pin and consumes a little less power
pub fn new(
peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
T::enable();
T::reset();
Self::new_inner(peri, irq, rx, rx_dma, config)
}
pub fn new_with_rts(
peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(rts);
T::enable();
T::reset();
unsafe {
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_rtse(true);
});
}
Self::new_inner(peri, irq, rx, rx_dma, config)
}
fn new_inner(
peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(peri, irq, rx, rx_dma);
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
}
configure(r, &config, T::frequency(), T::MULTIPLIER, true, false);
irq.set_handler(Self::on_interrupt);
irq.unpend();
irq.enable();
// create state once!
let _s = T::state();
Self {
_peri: peri,
rx_dma,
phantom: PhantomData,
detect_previous_overrun: config.detect_previous_overrun,
}
}
fn on_interrupt(_: *mut ()) {
let r = T::regs();
let s = T::state();
let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
if has_errors {
// clear all interrupts and DMA Rx Request
unsafe {
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// disable parity interrupt
w.set_peie(false);
// disable idle line interrupt
w.set_idleie(false);
});
r.cr3().modify(|w| {
// disable Error Interrupt: (Frame error, Noise error, Overrun error)
w.set_eie(false);
// disable DMA Rx Request
w.set_dmar(false);
});
}
compiler_fence(Ordering::SeqCst);
s.rx_waker.wake();
} else if cr1.idleie() && sr.idle() {
// IDLE detected: no more data will come
unsafe {
r.cr1().modify(|w| {
// disable idle line detection
w.set_idleie(false);
});
r.cr3().modify(|w| {
// disable DMA Rx Request
w.set_dmar(false);
});
}
compiler_fence(Ordering::SeqCst);
s.rx_waker.wake();
}
}
@ -146,17 +330,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
where
RxDma: crate::usart::RxDma<T>,
{
let ch = &mut self.rx_dma;
let request = ch.request();
unsafe {
T::regs().cr3().modify(|reg| {
reg.set_dmar(true);
});
}
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer);
transfer.await;
self.inner_read(buffer, false).await?;
Ok(())
}
@ -211,57 +386,332 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
}
Ok(())
}
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.inner_read(buffer, true).await
}
async fn inner_read_run(
&mut self,
buffer: &mut [u8],
enable_idle_line_detection: bool,
) -> Result<ReadCompletionEvent, Error>
where
RxDma: crate::usart::RxDma<T>,
{
let r = T::regs();
// make sure USART state is restored to neutral state when this future is dropped
let on_drop = OnDrop::new(move || {
// defmt::trace!("Clear all USART interrupts and DMA Read Request");
// clear all interrupts and DMA Rx Request
// SAFETY: only clears Rx related flags
unsafe {
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// disable parity interrupt
w.set_peie(false);
// disable idle line interrupt
w.set_idleie(false);
});
r.cr3().modify(|w| {
// disable Error Interrupt: (Frame error, Noise error, Overrun error)
w.set_eie(false);
// disable DMA Rx Request
w.set_dmar(false);
});
}
});
let ch = &mut self.rx_dma;
let request = ch.request();
// Start USART DMA
// will not do anything yet because DMAR is not yet set
// future which will complete when DMA Read request completes
let transfer = crate::dma::read(ch, request, rdr(T::regs()), buffer);
// SAFETY: The only way we might have a problem is using split rx and tx
// here we only modify or read Rx related flags, interrupts and DMA channel
unsafe {
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
if !self.detect_previous_overrun {
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
rdr(r).read_volatile();
clear_interrupt_flags(r, sr);
}
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// enable parity interrupt if not ParityNone
w.set_peie(w.pce());
});
r.cr3().modify(|w| {
// enable Error Interrupt: (Frame error, Noise error, Overrun error)
w.set_eie(true);
// enable DMA Rx Request
w.set_dmar(true);
});
compiler_fence(Ordering::SeqCst);
// In case of errors already pending when reception started, interrupts may have already been raised
// and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
// have been disabled in interrupt handler and DMA Rx Request has been disabled.
let cr3 = r.cr3().read();
if !cr3.dmar() {
// something went wrong
// because the only way to get this flag cleared is to have an interrupt
// DMA will be stopped when transfer is dropped
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
rdr(r).read_volatile();
clear_interrupt_flags(r, sr);
if sr.pe() {
return Err(Error::Parity);
}
if sr.fe() {
return Err(Error::Framing);
}
if sr.ne() {
return Err(Error::Noise);
}
if sr.ore() {
return Err(Error::Overrun);
}
unreachable!();
}
if !enable_idle_line_detection {
transfer.await;
return Ok(ReadCompletionEvent::DmaCompleted);
}
// clear idle flag
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
rdr(r).read_volatile();
clear_interrupt_flags(r, sr);
// enable idle interrupt
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
// future which completes when idle line is detected
let idle = poll_fn(move |cx| {
let s = T::state();
s.rx_waker.register(cx.waker());
// SAFETY: read only and we only use Rx related flags
let sr = unsafe { sr(r).read() };
// SAFETY: only clears Rx related flags
unsafe {
// This read also clears the error and idle interrupt flags on v1.
rdr(r).read_volatile();
clear_interrupt_flags(r, sr);
}
compiler_fence(Ordering::SeqCst);
let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
if has_errors {
// all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler
if sr.pe() {
return Poll::Ready(Err(Error::Parity));
}
if sr.fe() {
return Poll::Ready(Err(Error::Framing));
}
if sr.ne() {
return Poll::Ready(Err(Error::Noise));
}
if sr.ore() {
return Poll::Ready(Err(Error::Overrun));
}
}
if sr.idle() {
// Idle line detected
return Poll::Ready(Ok(()));
}
Poll::Pending
});
// wait for the first of DMA request or idle line detected to completes
// select consumes its arguments
// when transfer is dropped, it will stop the DMA request
let r = match select(transfer, idle).await {
// DMA transfer completed first
Either::First(()) => Ok(ReadCompletionEvent::DmaCompleted),
// Idle line detected first
Either::Second(Ok(())) => Ok(ReadCompletionEvent::Idle),
// error occurred
Either::Second(Err(e)) => Err(e),
};
drop(on_drop);
r
}
async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
{
if buffer.is_empty() {
return Ok(0);
} else if buffer.len() > 0xFFFF {
return Err(Error::BufferTooLong);
}
let buffer_len = buffer.len();
// wait for DMA to complete or IDLE line detection if requested
let res = self.inner_read_run(buffer, enable_idle_line_detection).await;
let ch = &mut self.rx_dma;
match res {
Ok(ReadCompletionEvent::DmaCompleted) => Ok(buffer_len),
Ok(ReadCompletionEvent::Idle) => {
let n = buffer_len - (ch.remaining_transfers() as usize);
Ok(n)
}
Err(e) => Err(e),
}
}
}
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
pub fn new(
_inner: impl Peripheral<P = T> + 'd,
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(_inner, rx, tx, tx_dma, rx_dma);
T::enable();
T::reset();
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
}
pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(cts, rts);
T::enable();
T::reset();
let pclk_freq = T::frequency();
// TODO: better calculation, including error checking and OVER8 if possible.
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * T::MULTIPLIER;
unsafe {
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_rtse(true);
w.set_ctse(true);
});
}
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
}
#[cfg(not(usart_v1))]
pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(de);
T::enable();
T::reset();
unsafe {
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
}
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
}
fn new_inner(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Self {
into_ref!(peri, rx, tx, irq, tx_dma, rx_dma);
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
r.cr2().write(|_w| {});
r.cr3().write(|_w| {});
r.brr().write_value(regs::Brr(div));
r.cr1().write(|w| {
w.set_ue(true);
w.set_te(true);
w.set_re(true);
w.set_m0(if config.parity != Parity::ParityNone {
vals::M0::BIT9
} else {
vals::M0::BIT8
});
w.set_pce(config.parity != Parity::ParityNone);
w.set_ps(match config.parity {
Parity::ParityOdd => vals::Ps::ODD,
Parity::ParityEven => vals::Ps::EVEN,
_ => vals::Ps::EVEN,
});
});
}
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true);
irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
irq.unpend();
irq.enable();
// create state once!
let _s = T::state();
Self {
tx: UartTx::new(tx_dma),
rx: UartRx::new(rx_dma),
phantom: PhantomData {},
tx: UartTx {
tx_dma,
phantom: PhantomData,
},
rx: UartRx {
_peri: peri,
rx_dma,
detect_previous_overrun: config.detect_previous_overrun,
},
}
}
@ -295,6 +745,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.rx.blocking_read(buffer)
}
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.rx.read_until_idle(buffer).await
}
/// Split the Uart into a transmitter and receiver, which is
/// particuarly useful when having two tasks correlating to
/// transmitting and receiving.
@ -303,6 +760,48 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
}
}
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) {
if !enable_rx && !enable_tx {
panic!("USART: At least one of RX or TX should be enabled");
}
// TODO: better calculation, including error checking and OVER8 if possible.
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier;
unsafe {
r.brr().write_value(regs::Brr(div));
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);
// enable transceiver
w.set_te(enable_tx);
// enable receiver
w.set_re(enable_rx);
// configure word size
w.set_m0(if config.parity != Parity::ParityNone {
vals::M0::BIT9
} else {
vals::M0::BIT8
});
// configure parity
w.set_pce(config.parity != Parity::ParityNone);
w.set_ps(match config.parity {
Parity::ParityOdd => vals::Ps::ODD,
Parity::ParityEven => vals::Ps::EVEN,
_ => vals::Ps::EVEN,
});
});
}
}
mod eh02 {
use super::*;
@ -352,6 +851,7 @@ mod eh1 {
Self::Noise => embedded_hal_1::serial::ErrorKind::Noise,
Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun,
Self::Parity => embedded_hal_1::serial::ErrorKind::Parity,
Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other,
}
}
}
@ -421,6 +921,58 @@ mod eh1 {
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eio {
use embedded_io::asynch::Write;
use embedded_io::Io;
use super::*;
impl<T, TxDma, RxDma> Io for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma, RxDma> Write for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
TxDma: super::TxDma<T>,
{
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<T, TxDma> Io for UartTx<'_, T, TxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma> Write for UartTx<'_, T, TxDma>
where
T: BasicInstance,
TxDma: super::TxDma<T>,
{
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
}
#[cfg(all(
feature = "unstable-traits",
feature = "nightly",
@ -536,13 +1088,30 @@ unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
}
pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker;
use super::*;
pub struct State {
pub rx_waker: AtomicWaker,
pub tx_waker: AtomicWaker,
}
impl State {
pub const fn new() -> Self {
Self {
rx_waker: AtomicWaker::new(),
tx_waker: AtomicWaker::new(),
}
}
}
pub trait BasicInstance: crate::rcc::RccPeripheral {
const MULTIPLIER: u32;
type Interrupt: crate::interrupt::Interrupt;
fn regs() -> Regs;
fn state() -> &'static State;
}
pub trait FullInstance: BasicInstance {
@ -550,7 +1119,7 @@ pub(crate) mod sealed {
}
}
pub trait BasicInstance: sealed::BasicInstance {}
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
pub trait FullInstance: sealed::FullInstance {}
@ -559,6 +1128,7 @@ pin_trait!(TxPin, BasicInstance);
pin_trait!(CtsPin, BasicInstance);
pin_trait!(RtsPin, BasicInstance);
pin_trait!(CkPin, BasicInstance);
pin_trait!(DePin, BasicInstance);
dma_trait!(TxDma, BasicInstance);
dma_trait!(RxDma, BasicInstance);
@ -572,6 +1142,11 @@ macro_rules! impl_lpuart {
fn regs() -> Regs {
Regs(crate::pac::$inst.0)
}
fn state() -> &'static crate::usart::sealed::State {
static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new();
&STATE
}
}
impl BasicInstance for peripherals::$inst {}
@ -580,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

@ -1,11 +1,10 @@
#![macro_use]
use core::future::{poll_fn, Future};
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::Ordering;
use core::sync::atomic::{AtomicBool, Ordering};
use core::task::Poll;
use atomic_polyfill::{AtomicBool, AtomicU8};
use embassy_hal_common::into_ref;
use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::{block_for, Duration};
@ -35,10 +34,9 @@ static BUS_WAKER: AtomicWaker = NEW_AW;
static EP0_SETUP: AtomicBool = AtomicBool::new(false);
static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
static IRQ_FLAGS: AtomicU8 = AtomicU8::new(0);
const IRQ_FLAG_RESET: u8 = 0x01;
const IRQ_FLAG_SUSPEND: u8 = 0x02;
const IRQ_FLAG_RESUME: u8 = 0x04;
static IRQ_RESET: AtomicBool = AtomicBool::new(false);
static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
fn convert_type(t: EndpointType) -> EpType {
match t {
@ -156,6 +154,7 @@ impl<'d, T: Instance> Driver<'d, T> {
block_for(Duration::from_millis(100));
#[cfg(not(usb_v4))]
regs.btable().write(|w| w.set_btable(0));
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
@ -184,47 +183,51 @@ impl<'d, T: Instance> Driver<'d, T> {
let istr = regs.istr().read();
let mut flags: u8 = 0;
if istr.susp() {
//trace!("USB IRQ: susp");
flags |= IRQ_FLAG_SUSPEND;
IRQ_SUSPEND.store(true, Ordering::Relaxed);
regs.cntr().modify(|w| {
w.set_fsusp(true);
w.set_lpmode(true);
})
});
// Write 0 to clear.
let mut clear = regs::Istr(!0);
clear.set_susp(false);
regs.istr().write_value(clear);
// Wake main thread.
BUS_WAKER.wake();
}
if istr.wkup() {
//trace!("USB IRQ: wkup");
flags |= IRQ_FLAG_RESUME;
IRQ_RESUME.store(true, Ordering::Relaxed);
regs.cntr().modify(|w| {
w.set_fsusp(false);
w.set_lpmode(false);
})
});
// Write 0 to clear.
let mut clear = regs::Istr(!0);
clear.set_wkup(false);
regs.istr().write_value(clear);
// Wake main thread.
BUS_WAKER.wake();
}
if istr.reset() {
//trace!("USB IRQ: reset");
flags |= IRQ_FLAG_RESET;
IRQ_RESET.store(true, Ordering::Relaxed);
// Write 0 to clear.
let mut clear = regs::Istr(!0);
clear.set_reset(false);
regs.istr().write_value(clear);
}
if flags != 0 {
// Send irqs to main thread.
IRQ_FLAGS.fetch_or(flags, Ordering::AcqRel);
// Wake main thread.
BUS_WAKER.wake();
// Clear them
let mut mask = regs::Istr(0);
mask.set_wkup(true);
mask.set_susp(true);
mask.set_reset(true);
regs.istr().write_value(regs::Istr(!(istr.0 & mask.0)));
}
if istr.ctr() {
@ -265,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()
);
@ -342,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,
})
@ -359,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) {
@ -429,26 +432,22 @@ pub struct Bus<'d, T: Instance> {
}
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a;
fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| unsafe {
BUS_WAKER.register(cx.waker());
if self.inited {
let regs = T::regs();
let flags = IRQ_FLAGS.load(Ordering::Acquire);
if flags & IRQ_FLAG_RESUME != 0 {
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
if IRQ_RESUME.load(Ordering::Acquire) {
IRQ_RESUME.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Resume);
}
if flags & IRQ_FLAG_RESET != 0 {
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel);
if IRQ_RESET.load(Ordering::Acquire) {
IRQ_RESET.store(false, Ordering::Relaxed);
trace!("RESET REGS WRITINGINGING");
trace!("RESET");
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(0);
@ -477,8 +476,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
return Poll::Ready(Event::Reset);
}
if flags & IRQ_FLAG_SUSPEND != 0 {
IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel);
if IRQ_SUSPEND.load(Ordering::Acquire) {
IRQ_SUSPEND.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Suspend);
}
@ -488,18 +487,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
return Poll::Ready(Event::PowerDetected);
}
})
}
#[inline]
fn set_address(&mut self, addr: u8) {
let regs = T::regs();
trace!("setting addr: {}", addr);
unsafe {
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(addr);
})
}
.await
}
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
@ -598,22 +586,11 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
trace!("EPR after: {:04x}", unsafe { reg.read() }.0);
}
type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
async fn enable(&mut self) {}
async fn disable(&mut self) {}
fn enable(&mut self) -> Self::EnableFuture<'_> {
async move {}
}
type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
fn disable(&mut self) -> Self::DisableFuture<'_> {
async move {}
}
type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a;
fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> {
async move { Err(Unsupported) }
async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
Err(Unsupported)
}
}
@ -676,24 +653,20 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
&self.info
}
type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> {
async move {
trace!("wait_enabled OUT WAITING");
let index = self.info.addr.index();
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
}
})
.await;
trace!("wait_enabled OUT OK");
}
async fn wait_enabled(&mut self) {
trace!("wait_enabled OUT WAITING");
let index = self.info.addr.index();
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
}
})
.await;
trace!("wait_enabled OUT OK");
}
}
@ -702,116 +675,104 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
&self.info
}
type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> {
async move {
trace!("wait_enabled OUT WAITING");
let index = self.info.addr.index();
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
}
})
.await;
trace!("wait_enabled OUT OK");
}
async fn wait_enabled(&mut self) {
trace!("wait_enabled OUT WAITING");
let index = self.info.addr.index();
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
}
})
.await;
trace!("wait_enabled OUT OK");
}
}
impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
async move {
trace!("READ WAITING, buf.len() = {}", buf.len());
let index = self.info.addr.index();
let stat = poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
let stat = unsafe { regs.epr(index).read() }.stat_rx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
Poll::Pending
}
})
.await;
if stat == Stat::DISABLED {
return Err(EndpointError::Disabled);
}
let rx_len = self.read_data(buf)?;
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
trace!("READ WAITING, buf.len() = {}", buf.len());
let index = self.info.addr.index();
let stat = poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
unsafe {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_tx(Stat(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
trace!("READ OK, rx_len = {}", rx_len);
let stat = unsafe { regs.epr(index).read() }.stat_rx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
Poll::Pending
}
})
.await;
Ok(rx_len)
if stat == Stat::DISABLED {
return Err(EndpointError::Disabled);
}
let rx_len = self.read_data(buf)?;
let regs = T::regs();
unsafe {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_tx(Stat(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
trace!("READ OK, rx_len = {}", rx_len);
Ok(rx_len)
}
}
impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
async move {
if buf.len() > self.info.max_packet_size as usize {
return Err(EndpointError::BufferOverflow);
}
let index = self.info.addr.index();
trace!("WRITE WAITING");
let stat = poll_fn(|cx| {
EP_IN_WAKERS[index].register(cx.waker());
let regs = T::regs();
let stat = unsafe { regs.epr(index).read() }.stat_tx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
Poll::Pending
}
})
.await;
if stat == Stat::DISABLED {
return Err(EndpointError::Disabled);
}
self.write_data(buf);
let regs = T::regs();
unsafe {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_rx(Stat(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
trace!("WRITE OK");
Ok(())
async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
if buf.len() > self.info.max_packet_size as usize {
return Err(EndpointError::BufferOverflow);
}
let index = self.info.addr.index();
trace!("WRITE WAITING");
let stat = poll_fn(|cx| {
EP_IN_WAKERS[index].register(cx.waker());
let regs = T::regs();
let stat = unsafe { regs.epr(index).read() }.stat_tx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
Poll::Pending
}
})
.await;
if stat == Stat::DISABLED {
return Err(EndpointError::Disabled);
}
self.write_data(buf);
let regs = T::regs();
unsafe {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_rx(Stat(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
trace!("WRITE OK");
Ok(())
}
}
@ -823,84 +784,16 @@ pub struct ControlPipe<'d, T: Instance> {
}
impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a;
type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a;
type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a;
type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
fn max_packet_size(&self) -> usize {
usize::from(self.max_packet_size)
}
fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> {
async move {
loop {
trace!("SETUP read waiting");
poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker());
if EP0_SETUP.load(Ordering::Relaxed) {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
let mut buf = [0; 8];
let rx_len = self.ep_out.read_data(&mut buf);
if rx_len != Ok(8) {
trace!("SETUP read failed: {:?}", rx_len);
continue;
}
EP0_SETUP.store(false, Ordering::Relaxed);
trace!("SETUP read ok");
return buf;
}
}
}
fn data_out<'a>(&'a mut self, buf: &'a mut [u8], first: bool, last: bool) -> Self::DataOutFuture<'a> {
async move {
let regs = T::regs();
// When a SETUP is received, Stat/Stat is set to NAK.
// On first transfer, we must set Stat=VALID, to get the OUT data stage.
// We want Stat=STALL so that the host gets a STALL if it switches to the status
// stage too soon, except in the last transfer we set Stat=NAK so that it waits
// for the status stage, which we will ACK or STALL later.
if first || last {
let mut stat_rx = 0;
let mut stat_tx = 0;
if first {
// change NAK -> VALID
stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
}
if last {
// change STALL -> VALID
stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
}
// Note: if this is the first AND last transfer, the above effectively
// changes stat_tx like NAK -> NAK, so noop.
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(stat_rx));
w.set_stat_tx(Stat(stat_tx));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
}
}
trace!("data_out WAITING, buf.len() = {}", buf.len());
async fn setup(&mut self) -> [u8; 8] {
loop {
trace!("SETUP read waiting");
poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK {
if EP0_SETUP.load(Ordering::Relaxed) {
Poll::Ready(())
} else {
Poll::Pending
@ -908,157 +801,222 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
})
.await;
if EP0_SETUP.load(Ordering::Relaxed) {
trace!("received another SETUP, aborting data_out.");
return Err(EndpointError::Disabled);
let mut buf = [0; 8];
let rx_len = self.ep_out.read_data(&mut buf);
if rx_len != Ok(8) {
trace!("SETUP read failed: {:?}", rx_len);
continue;
}
let rx_len = self.ep_out.read_data(buf)?;
EP0_SETUP.store(false, Ordering::Relaxed);
trace!("SETUP read ok");
return buf;
}
}
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
let regs = T::regs();
// When a SETUP is received, Stat/Stat is set to NAK.
// On first transfer, we must set Stat=VALID, to get the OUT data stage.
// We want Stat=STALL so that the host gets a STALL if it switches to the status
// stage too soon, except in the last transfer we set Stat=NAK so that it waits
// for the status stage, which we will ACK or STALL later.
if first || last {
let mut stat_rx = 0;
let mut stat_tx = 0;
if first {
// change NAK -> VALID
stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
}
if last {
// change STALL -> VALID
stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
}
// Note: if this is the first AND last transfer, the above effectively
// changes stat_tx like NAK -> NAK, so noop.
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(match last {
// If last, set STAT_RX=STALL.
true => Stat::NAK.0 ^ Stat::STALL.0,
// Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
false => Stat::NAK.0 ^ Stat::VALID.0,
}));
w.set_stat_rx(Stat(stat_rx));
w.set_stat_tx(Stat(stat_tx));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
Ok(rx_len)
}
}
trace!("data_out WAITING, buf.len() = {}", buf.len());
poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_rx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
if EP0_SETUP.load(Ordering::Relaxed) {
trace!("received another SETUP, aborting data_out.");
return Err(EndpointError::Disabled);
}
let rx_len = self.ep_out.read_data(buf)?;
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(match last {
// If last, set STAT_RX=STALL.
true => Stat::NAK.0 ^ Stat::STALL.0,
// Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
false => Stat::NAK.0 ^ Stat::VALID.0,
}));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
Ok(rx_len)
}
fn data_in<'a>(&'a mut self, buf: &'a [u8], first: bool, last: bool) -> Self::DataInFuture<'a> {
async move {
trace!("control: data_in");
async fn data_in(&mut self, data: &[u8], first: bool, last: bool) -> Result<(), EndpointError> {
trace!("control: data_in");
if buf.len() > self.ep_in.info.max_packet_size as usize {
return Err(EndpointError::BufferOverflow);
if data.len() > self.ep_in.info.max_packet_size as usize {
return Err(EndpointError::BufferOverflow);
}
let regs = T::regs();
// When a SETUP is received, Stat is set to NAK.
// We want it to be STALL in non-last transfers.
// We want it to be VALID in last transfer, so the HW does the status stage.
if first || last {
let mut stat_rx = 0;
if first {
// change NAK -> STALL
stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
}
let regs = T::regs();
// When a SETUP is received, Stat is set to NAK.
// We want it to be STALL in non-last transfers.
// We want it to be VALID in last transfer, so the HW does the status stage.
if first || last {
let mut stat_rx = 0;
if first {
// change NAK -> STALL
stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
}
if last {
// change STALL -> VALID
stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
}
// Note: if this is the first AND last transfer, the above effectively
// does a change of NAK -> VALID.
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(stat_rx));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
}
if last {
// change STALL -> VALID
stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
}
trace!("WRITE WAITING");
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
if EP0_SETUP.load(Ordering::Relaxed) {
trace!("received another SETUP, aborting data_in.");
return Err(EndpointError::Disabled);
}
self.ep_in.write_data(buf);
let regs = T::regs();
// Note: if this is the first AND last transfer, the above effectively
// does a change of NAK -> VALID.
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_stat_rx(Stat(stat_rx));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
};
trace!("WRITE OK");
Ok(())
}
}
fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> {
async move {
let regs = T::regs();
trace!("control: accept");
self.ep_in.write_data(&[]);
// Set OUT=stall, IN=accept
unsafe {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
}
trace!("control: accept WAITING");
}
// Wait is needed, so that we don't set the address too soon, breaking the status stage.
// (embassy-usb sets the address after accept() returns)
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
}
trace!("WRITE WAITING");
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
if EP0_SETUP.load(Ordering::Relaxed) {
trace!("received another SETUP, aborting data_in.");
return Err(EndpointError::Disabled);
}
self.ep_in.write_data(data);
let regs = T::regs();
unsafe {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
})
.await;
};
trace!("control: accept OK");
trace!("WRITE OK");
Ok(())
}
async fn accept(&mut self) {
let regs = T::regs();
trace!("control: accept");
self.ep_in.write_data(&[]);
// Set OUT=stall, IN=accept
unsafe {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
}
trace!("control: accept WAITING");
// Wait is needed, so that we don't set the address too soon, breaking the status stage.
// (embassy-usb sets the address after accept() returns)
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
trace!("control: accept OK");
}
async fn reject(&mut self) {
let regs = T::regs();
trace!("control: reject");
// Set IN+OUT to stall
unsafe {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
}
}
fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> {
async move {
let regs = T::regs();
trace!("control: reject");
async fn accept_set_address(&mut self, addr: u8) {
self.accept().await;
// Set IN+OUT to stall
unsafe {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
}
let regs = T::regs();
trace!("setting addr: {}", addr);
unsafe {
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(addr);
})
}
}
}

View File

@ -1,213 +0,0 @@
use core::marker::PhantomData;
use embassy_hal_common::into_ref;
use crate::gpio::sealed::AFType;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
macro_rules! config_ulpi_pins {
($($pin:ident),*) => {
into_ref!($($pin),*);
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| unsafe {
$(
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
#[cfg(gpio_v2)]
$pin.set_speed(crate::gpio::Speed::VeryHigh);
)*
})
};
}
/// USB PHY type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PhyType {
/// Internal Full-Speed PHY
///
/// Available on most High-Speed peripherals.
InternalFullSpeed,
/// Internal High-Speed PHY
///
/// Available on a few STM32 chips.
InternalHighSpeed,
/// External ULPI High-Speed PHY
ExternalHighSpeed,
}
pub struct UsbOtg<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
_phy_type: PhyType,
}
impl<'d, T: Instance> UsbOtg<'d, T> {
/// Initializes USB OTG peripheral with internal Full-Speed PHY
pub fn new_fs(
_peri: impl Peripheral<P = T> + 'd,
dp: impl Peripheral<P = impl DpPin<T>> + 'd,
dm: impl Peripheral<P = impl DmPin<T>> + 'd,
) -> Self {
into_ref!(dp, dm);
unsafe {
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
}
Self {
phantom: PhantomData,
_phy_type: PhyType::InternalFullSpeed,
}
}
/// Initializes USB OTG peripheral with external High-Speed PHY
pub fn new_hs_ulpi(
_peri: impl Peripheral<P = T> + 'd,
ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
ulpi_stp: impl Peripheral<P = impl UlpiStpPin<T>> + 'd,
ulpi_d0: impl Peripheral<P = impl UlpiD0Pin<T>> + 'd,
ulpi_d1: impl Peripheral<P = impl UlpiD1Pin<T>> + 'd,
ulpi_d2: impl Peripheral<P = impl UlpiD2Pin<T>> + 'd,
ulpi_d3: impl Peripheral<P = impl UlpiD3Pin<T>> + 'd,
ulpi_d4: impl Peripheral<P = impl UlpiD4Pin<T>> + 'd,
ulpi_d5: impl Peripheral<P = impl UlpiD5Pin<T>> + 'd,
ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
) -> Self {
config_ulpi_pins!(
ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6,
ulpi_d7
);
Self {
phantom: PhantomData,
_phy_type: PhyType::ExternalHighSpeed,
}
}
}
impl<'d, T: Instance> Drop for UsbOtg<'d, T> {
fn drop(&mut self) {
T::reset();
T::disable();
}
}
pub(crate) mod sealed {
pub trait Instance {
const REGISTERS: *const ();
const HIGH_SPEED: bool;
const FIFO_DEPTH_WORDS: usize;
const ENDPOINT_COUNT: usize;
}
}
pub trait Instance: sealed::Instance + RccPeripheral {}
// Internal PHY pins
pin_trait!(DpPin, Instance);
pin_trait!(DmPin, Instance);
// External PHY pins
pin_trait!(UlpiClkPin, Instance);
pin_trait!(UlpiDirPin, Instance);
pin_trait!(UlpiNxtPin, Instance);
pin_trait!(UlpiStpPin, Instance);
pin_trait!(UlpiD0Pin, Instance);
pin_trait!(UlpiD1Pin, Instance);
pin_trait!(UlpiD2Pin, Instance);
pin_trait!(UlpiD3Pin, Instance);
pin_trait!(UlpiD4Pin, Instance);
pin_trait!(UlpiD5Pin, Instance);
pin_trait!(UlpiD6Pin, Instance);
pin_trait!(UlpiD7Pin, Instance);
foreach_peripheral!(
(otgfs, $inst:ident) => {
impl sealed::Instance for peripherals::$inst {
const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
const HIGH_SPEED: bool = false;
cfg_if::cfg_if! {
if #[cfg(stm32f1)] {
const FIFO_DEPTH_WORDS: usize = 128;
const ENDPOINT_COUNT: usize = 8;
} else if #[cfg(any(
stm32f2,
stm32f401,
stm32f405,
stm32f407,
stm32f411,
stm32f415,
stm32f417,
stm32f427,
stm32f429,
stm32f437,
stm32f439,
))] {
const FIFO_DEPTH_WORDS: usize = 320;
const ENDPOINT_COUNT: usize = 4;
} else if #[cfg(any(
stm32f412,
stm32f413,
stm32f423,
stm32f446,
stm32f469,
stm32f479,
stm32f7,
stm32l4,
stm32u5,
))] {
const FIFO_DEPTH_WORDS: usize = 320;
const ENDPOINT_COUNT: usize = 6;
} else if #[cfg(stm32g0x1)] {
const FIFO_DEPTH_WORDS: usize = 512;
const ENDPOINT_COUNT: usize = 8;
} else {
compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
}
}
}
impl Instance for peripherals::$inst {}
};
(otghs, $inst:ident) => {
impl sealed::Instance for peripherals::$inst {
const REGISTERS: *const () = crate::pac::$inst.0 as *const ();
const HIGH_SPEED: bool = true;
cfg_if::cfg_if! {
if #[cfg(any(
stm32f2,
stm32f405,
stm32f407,
stm32f415,
stm32f417,
stm32f427,
stm32f429,
stm32f437,
stm32f439,
))] {
const FIFO_DEPTH_WORDS: usize = 1024;
const ENDPOINT_COUNT: usize = 6;
} else if #[cfg(any(
stm32f446,
stm32f469,
stm32f479,
stm32f7,
stm32h7,
))] {
const FIFO_DEPTH_WORDS: usize = 1024;
const ENDPOINT_COUNT: usize = 9;
} else {
compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
}
}
}
impl Instance for peripherals::$inst {}
};
);

View File

@ -0,0 +1,161 @@
use embassy_cortex_m::interrupt::Interrupt;
use crate::peripherals;
use crate::rcc::RccPeripheral;
#[cfg(feature = "nightly")]
mod usb;
#[cfg(feature = "nightly")]
pub use usb::*;
// Using Instance::ENDPOINT_COUNT requires feature(const_generic_expr) so just define maximum eps
#[cfg(feature = "nightly")]
const MAX_EP_COUNT: usize = 9;
pub(crate) mod sealed {
pub trait Instance {
const HIGH_SPEED: bool;
const FIFO_DEPTH_WORDS: u16;
const ENDPOINT_COUNT: usize;
fn regs() -> crate::pac::otg::Otg;
#[cfg(feature = "nightly")]
fn state() -> &'static super::State<{ super::MAX_EP_COUNT }>;
}
}
pub trait Instance: sealed::Instance + RccPeripheral {
type Interrupt: Interrupt;
}
// Internal PHY pins
pin_trait!(DpPin, Instance);
pin_trait!(DmPin, Instance);
// External PHY pins
pin_trait!(UlpiClkPin, Instance);
pin_trait!(UlpiDirPin, Instance);
pin_trait!(UlpiNxtPin, Instance);
pin_trait!(UlpiStpPin, Instance);
pin_trait!(UlpiD0Pin, Instance);
pin_trait!(UlpiD1Pin, Instance);
pin_trait!(UlpiD2Pin, Instance);
pin_trait!(UlpiD3Pin, Instance);
pin_trait!(UlpiD4Pin, Instance);
pin_trait!(UlpiD5Pin, Instance);
pin_trait!(UlpiD6Pin, Instance);
pin_trait!(UlpiD7Pin, Instance);
foreach_interrupt!(
(USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
impl sealed::Instance for peripherals::USB_OTG_FS {
const HIGH_SPEED: bool = false;
cfg_if::cfg_if! {
if #[cfg(stm32f1)] {
const FIFO_DEPTH_WORDS: u16 = 128;
const ENDPOINT_COUNT: usize = 8;
} else if #[cfg(any(
stm32f2,
stm32f401,
stm32f405,
stm32f407,
stm32f411,
stm32f415,
stm32f417,
stm32f427,
stm32f429,
stm32f437,
stm32f439,
))] {
const FIFO_DEPTH_WORDS: u16 = 320;
const ENDPOINT_COUNT: usize = 4;
} else if #[cfg(any(
stm32f412,
stm32f413,
stm32f423,
stm32f446,
stm32f469,
stm32f479,
stm32f7,
stm32l4,
stm32u5,
))] {
const FIFO_DEPTH_WORDS: u16 = 320;
const ENDPOINT_COUNT: usize = 6;
} else if #[cfg(stm32g0x1)] {
const FIFO_DEPTH_WORDS: u16 = 512;
const ENDPOINT_COUNT: usize = 8;
} else if #[cfg(stm32h7)] {
const FIFO_DEPTH_WORDS: u16 = 1024;
const ENDPOINT_COUNT: usize = 9;
} else {
compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
}
}
fn regs() -> crate::pac::otg::Otg {
crate::pac::USB_OTG_FS
}
#[cfg(feature = "nightly")]
fn state() -> &'static State<MAX_EP_COUNT> {
static STATE: State<MAX_EP_COUNT> = State::new();
&STATE
}
}
impl Instance for peripherals::USB_OTG_FS {
type Interrupt = crate::interrupt::$irq;
}
};
(USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
impl sealed::Instance for peripherals::USB_OTG_HS {
const HIGH_SPEED: bool = true;
cfg_if::cfg_if! {
if #[cfg(any(
stm32f2,
stm32f405,
stm32f407,
stm32f415,
stm32f417,
stm32f427,
stm32f429,
stm32f437,
stm32f439,
))] {
const FIFO_DEPTH_WORDS: u16 = 1024;
const ENDPOINT_COUNT: usize = 6;
} else if #[cfg(any(
stm32f446,
stm32f469,
stm32f479,
stm32f7,
stm32h7,
))] {
const FIFO_DEPTH_WORDS: u16 = 1024;
const ENDPOINT_COUNT: usize = 9;
} else {
compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
}
}
fn regs() -> crate::pac::otg::Otg {
// OTG HS registers are a superset of FS registers
crate::pac::otg::Otg(crate::pac::USB_OTG_HS.0)
}
#[cfg(feature = "nightly")]
fn state() -> &'static State<MAX_EP_COUNT> {
static STATE: State<MAX_EP_COUNT> = State::new();
&STATE
}
}
impl Instance for peripherals::USB_OTG_HS {
type Interrupt = crate::interrupt::$irq;
}
};
);

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,12 @@ pub struct IndependentWatchdog<'d, T: Instance> {
const MAX_RL: u16 = 0xFFF;
/// Calculates maximum watchdog timeout in us (RL = 0xFFF) for a given prescaler
const fn max_timeout(prescaler: u8) -> u32 {
const fn max_timeout(prescaler: u16) -> u32 {
1_000_000 * MAX_RL as u32 / (LSI_FREQ.0 / prescaler as u32)
}
/// Calculates watchdog reload value for the given prescaler and desired timeout
const fn reload_value(prescaler: u8, timeout_us: u32) -> u16 {
const fn reload_value(prescaler: u16, timeout_us: u32) -> u16 {
(timeout_us / prescaler as u32 * LSI_FREQ.0 / 1_000_000) as u16
}
@ -33,12 +33,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
// Find lowest prescaler value, which makes watchdog period longer or equal to timeout.
// This iterates from 4 (2^2) to 256 (2^8).
let psc_power = unwrap!((2..=8).find(|psc_power| {
let psc = 2u8.pow(*psc_power);
let psc = 2u16.pow(*psc_power);
timeout_us <= max_timeout(psc)
}));
// Prescaler value
let psc = 2u8.pow(psc_power);
let psc = 2u16.pow(psc_power);
// Convert prescaler power to PR register value
let pr = psc_power as u8 - 2;