This commit is contained in:
xoviat
2023-06-19 15:52:33 -05:00
253 changed files with 8629 additions and 8368 deletions

View File

@ -32,11 +32,9 @@ flavors = [
[dependencies]
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
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-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
@ -59,7 +57,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
stm32-metapac = "9"
stm32-metapac = "10"
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -76,11 +74,13 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { version = "9", default-features = false, features = ["metadata"]}
stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
[features]
default = ["stm32-metapac/rt"]
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"]
default = ["rt"]
rt = ["stm32-metapac/rt"]
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/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"]
exti = []
@ -99,7 +99,7 @@ time-driver-tim12 = ["_time-driver"]
time-driver-tim15 = ["_time-driver"]
# Enable nightly-only features
nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
# Reexport stm32-metapac at `embassy_stm32::pac`.
# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.

View File

@ -160,13 +160,11 @@ fn main() {
}
g.extend(quote! {
pub mod interrupt {
use crate::pac::Interrupt as InterruptEnum;
use embassy_cortex_m::interrupt::_export::declare;
embassy_hal_common::interrupt_mod!(
#(
declare!(#irqs);
#irqs,
)*
}
);
});
// ========
@ -297,6 +295,7 @@ fn main() {
let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
g.extend(quote! {
#[cfg(feature = "rt")]
#[crate::interrupt]
unsafe fn #irq () {
#(
@ -323,7 +322,7 @@ fn main() {
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
quote! {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
});
@ -354,13 +353,13 @@ fn main() {
})
}
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
#after_enable
})
}
fn disable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
})
}

View File

@ -32,26 +32,22 @@ impl<'d, T: Instance> Adc<'d, T> {
into_ref!(adc);
T::enable();
T::reset();
unsafe {
T::regs().cr2().modify(|reg| reg.set_adon(true));
}
T::regs().cr2().modify(|reg| reg.set_adon(true));
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = 1)
// for at least two ADC clock cycles
delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1);
unsafe {
// Reset calibration
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
while T::regs().cr2().read().rstcal() {
// spin
}
// Reset calibration
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
while T::regs().cr2().read().rstcal() {
// spin
}
// Calibrate
T::regs().cr2().modify(|reg| reg.set_cal(true));
while T::regs().cr2().read().cal() {
// spin
}
// Calibrate
T::regs().cr2().modify(|reg| reg.set_cal(true));
while T::regs().cr2().read().cal() {
// spin
}
// One cycle after calibration
@ -81,20 +77,16 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn enable_vref(&self, _delay: &mut impl DelayUs<u32>) -> Vref {
unsafe {
T::regs().cr2().modify(|reg| {
reg.set_tsvrefe(true);
})
}
T::regs().cr2().modify(|reg| {
reg.set_tsvrefe(true);
});
Vref {}
}
pub fn enable_temperature(&self) -> Temperature {
unsafe {
T::regs().cr2().modify(|reg| {
reg.set_tsvrefe(true);
})
}
T::regs().cr2().modify(|reg| {
reg.set_tsvrefe(true);
});
Temperature {}
}
@ -104,41 +96,37 @@ impl<'d, T: Instance> Adc<'d, T> {
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
unsafe {
T::regs().cr2().modify(|reg| {
reg.set_adon(true);
reg.set_swstart(true);
});
while T::regs().cr2().read().swstart() {}
while !T::regs().sr().read().eoc() {}
T::regs().cr2().modify(|reg| {
reg.set_adon(true);
reg.set_swstart(true);
});
while T::regs().cr2().read().swstart() {}
while !T::regs().sr().read().eoc() {}
T::regs().dr().read().0 as u16
}
T::regs().dr().read().0 as u16
}
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
unsafe {
Self::set_channel_sample_time(pin.channel(), self.sample_time);
T::regs().cr1().modify(|reg| {
reg.set_scan(false);
reg.set_discen(false);
});
T::regs().sqr1().modify(|reg| reg.set_l(0));
Self::set_channel_sample_time(pin.channel(), self.sample_time);
T::regs().cr1().modify(|reg| {
reg.set_scan(false);
reg.set_discen(false);
});
T::regs().sqr1().modify(|reg| reg.set_l(0));
T::regs().cr2().modify(|reg| {
reg.set_cont(false);
reg.set_exttrig(true);
reg.set_swstart(false);
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
});
}
T::regs().cr2().modify(|reg| {
reg.set_cont(false);
reg.set_exttrig(true);
reg.set_swstart(false);
reg.set_extsel(crate::pac::adc::vals::Extsel::SWSTART);
});
// Configure the channel to sample
unsafe { T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())) }
T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
self.convert()
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
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));

View File

@ -57,18 +57,14 @@ impl<'d, T: Instance> Adc<'d, T> {
//
// 6.3.20 Vbat monitoring characteristics
// ts_vbat ≥ 4μs
unsafe {
T::regs().ccr().modify(|reg| reg.set_vbaten(true));
}
T::regs().ccr().modify(|reg| reg.set_vbaten(true));
Vbat
}
pub fn enable_vref(&self, delay: &mut impl DelayUs<u32>) -> Vref {
// Table 28. Embedded internal reference voltage
// tstart = 10μs
unsafe {
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
}
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
delay.delay_us(10);
Vref
}
@ -79,27 +75,23 @@ impl<'d, T: Instance> Adc<'d, T> {
// 6.3.19 Temperature sensor characteristics
// tstart ≤ 10μs
// ts_temp ≥ 4μs
unsafe {
T::regs().ccr().modify(|reg| reg.set_tsen(true));
}
T::regs().ccr().modify(|reg| reg.set_tsen(true));
delay.delay_us(10);
Temperature
}
fn calibrate(&self) {
unsafe {
// A.7.1 ADC calibration code example
if T::regs().cr().read().aden() {
T::regs().cr().modify(|reg| reg.set_addis(true));
}
while T::regs().cr().read().aden() {
// spin
}
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true));
while T::regs().cr().read().adcal() {
// spin
}
// A.7.1 ADC calibration code example
if T::regs().cr().read().aden() {
T::regs().cr().modify(|reg| reg.set_addis(true));
}
while T::regs().cr().read().aden() {
// spin
}
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
T::regs().cr().modify(|reg| reg.set_adcal(true));
while T::regs().cr().read().adcal() {
// spin
}
}
@ -108,9 +100,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn set_resolution(&mut self, resolution: Resolution) {
unsafe {
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
}
pub fn read<P>(&mut self, pin: &mut P) -> u16
@ -118,18 +108,16 @@ impl<'d, T: Instance> Adc<'d, T> {
P: AdcPin<T> + crate::gpio::sealed::Pin,
{
let channel = pin.channel();
unsafe {
pin.set_as_analog();
self.read_channel(channel)
}
pin.set_as_analog();
self.read_channel(channel)
}
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
let channel = channel.channel();
unsafe { self.read_channel(channel) }
self.read_channel(channel)
}
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
fn read_channel(&mut self, channel: u8) -> u16 {
// A.7.2 ADC enable sequence code example
if T::regs().isr().read().adrdy() {
T::regs().isr().modify(|reg| reg.set_adrdy(true));

View File

@ -100,13 +100,10 @@ where
T::reset();
let presc = Prescaler::from_pclk2(T::frequency());
unsafe {
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
T::regs().cr2().modify(|reg| {
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
});
}
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
T::regs().cr2().modify(|reg| {
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
});
delay.delay_us(ADC_POWERUP_TIME_US);
@ -121,19 +118,15 @@ where
}
pub fn set_resolution(&mut self, resolution: Resolution) {
unsafe {
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
}
T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
}
/// Enables internal voltage reference and returns [VrefInt], which can be used in
/// [Adc::read_internal()] to perform conversion.
pub fn enable_vrefint(&self) -> VrefInt {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
});
VrefInt {}
}
@ -144,11 +137,9 @@ where
/// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled,
/// temperature sensor will return vbat value.
pub fn enable_temperature(&self) -> Temperature {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
});
Temperature {}
}
@ -156,37 +147,33 @@ where
/// Enables vbat input and returns [Vbat], which can be used in
/// [Adc::read_internal()] to perform conversion.
pub fn enable_vbat(&self) -> Vbat {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
});
Vbat {}
}
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
unsafe {
// clear end of conversion flag
T::regs().sr().modify(|reg| {
reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
});
// clear end of conversion flag
T::regs().sr().modify(|reg| {
reg.set_eoc(crate::pac::adc::vals::Eoc::NOTCOMPLETE);
});
// Start conversion
T::regs().cr2().modify(|reg| {
reg.set_swstart(true);
});
// Start conversion
T::regs().cr2().modify(|reg| {
reg.set_swstart(true);
});
while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED {
// spin //wait for actual start
}
while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
// spin //wait for finish
}
T::regs().dr().read().0 as u16
while T::regs().sr().read().strt() == crate::pac::adc::vals::Strt::NOTSTARTED {
// spin //wait for actual start
}
while T::regs().sr().read().eoc() == crate::pac::adc::vals::Eoc::NOTCOMPLETE {
// spin //wait for finish
}
T::regs().dr().read().0 as u16
}
pub fn read<P>(&mut self, pin: &mut P) -> u16
@ -194,18 +181,16 @@ where
P: AdcPin<T>,
P: crate::gpio::sealed::Pin,
{
unsafe {
pin.set_as_analog();
pin.set_as_analog();
self.read_channel(pin.channel())
}
self.read_channel(pin.channel())
}
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
unsafe { self.read_channel(channel.channel()) }
self.read_channel(channel.channel())
}
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
fn read_channel(&mut self, channel: u8) -> u16 {
// Configure ADC
// Select channel
@ -219,7 +204,7 @@ where
val
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
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));

View File

@ -12,7 +12,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
/// configuration.
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
#[cfg(stm32h7)]
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
#[cfg(stm32g0)]
@ -62,29 +62,25 @@ impl<'d, T: Instance> Adc<'d, T> {
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| {
#[cfg(not(adc_g0))]
reg.set_deeppwd(false);
reg.set_advregen(true);
});
T::regs().cr().modify(|reg| {
#[cfg(not(adc_g0))]
reg.set_deeppwd(false);
reg.set_advregen(true);
});
#[cfg(adc_g0)]
T::regs().cfgr1().modify(|reg| {
reg.set_chselrmod(false);
});
}
#[cfg(adc_g0)]
T::regs().cfgr1().modify(|reg| {
reg.set_chselrmod(false);
});
delay.delay_us(20);
unsafe {
T::regs().cr().modify(|reg| {
reg.set_adcal(true);
});
T::regs().cr().modify(|reg| {
reg.set_adcal(true);
});
while T::regs().cr().read().adcal() {
// spin
}
while T::regs().cr().read().adcal() {
// spin
}
delay.delay_us(1);
@ -96,11 +92,9 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn enable_vrefint(&self, delay: &mut impl DelayUs<u32>) -> VrefInt {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
// "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
// to stabilize the internal voltage reference, we wait a little more.
@ -112,21 +106,17 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn enable_temperature(&self) -> Temperature {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_ch17sel(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_ch17sel(true);
});
Temperature {}
}
pub fn enable_vbat(&self) -> Vbat {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_ch18sel(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_ch18sel(true);
});
Vbat {}
}
@ -136,12 +126,10 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn set_resolution(&mut self, resolution: Resolution) {
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()));
}
#[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()));
}
/*
@ -155,77 +143,73 @@ impl<'d, T: Instance> Adc<'d, T> {
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
unsafe {
T::regs().isr().modify(|reg| {
reg.set_eos(true);
reg.set_eoc(true);
});
T::regs().isr().modify(|reg| {
reg.set_eos(true);
reg.set_eoc(true);
});
// Start conversion
T::regs().cr().modify(|reg| {
reg.set_adstart(true);
});
// Start conversion
T::regs().cr().modify(|reg| {
reg.set_adstart(true);
});
while !T::regs().isr().read().eos() {
// spin
}
T::regs().dr().read().0 as u16
while !T::regs().isr().read().eos() {
// spin
}
T::regs().dr().read().0 as u16
}
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
unsafe {
// Make sure bits are off
while T::regs().cr().read().addis() {
// spin
}
// Enable ADC
T::regs().isr().modify(|reg| {
reg.set_adrdy(true);
});
T::regs().cr().modify(|reg| {
reg.set_aden(true);
});
while !T::regs().isr().read().adrdy() {
// spin
}
// Configure channel
Self::set_channel_sample_time(pin.channel(), self.sample_time);
// Select channel
#[cfg(not(stm32g0))]
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
#[cfg(stm32g0)]
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
// corrupted, so we discard it and measure again.
//
// STM32L471xx: Section 2.7.3
// STM32G4: Section 2.7.3
#[cfg(any(rcc_l4, rcc_g4))]
let _ = self.convert();
let val = self.convert();
T::regs().cr().modify(|reg| reg.set_addis(true));
val
// Make sure bits are off
while T::regs().cr().read().addis() {
// spin
}
// Enable ADC
T::regs().isr().modify(|reg| {
reg.set_adrdy(true);
});
T::regs().cr().modify(|reg| {
reg.set_aden(true);
});
while !T::regs().isr().read().adrdy() {
// spin
}
// Configure channel
Self::set_channel_sample_time(pin.channel(), self.sample_time);
// Select channel
#[cfg(not(stm32g0))]
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
#[cfg(stm32g0)]
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
// corrupted, so we discard it and measure again.
//
// STM32L471xx: Section 2.7.3
// STM32G4: Section 2.7.3
#[cfg(any(rcc_l4, rcc_g4))]
let _ = self.convert();
let val = self.convert();
T::regs().cr().modify(|reg| reg.set_addis(true));
val
}
#[cfg(stm32g0)]
unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
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) {
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));

View File

@ -46,8 +46,8 @@ foreach_peripheral!(
(adc, ADC1) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC1 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe {
match crate::rcc::get_freqs().adc {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
@ -55,7 +55,7 @@ foreach_peripheral!(
}
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@ -63,7 +63,7 @@ foreach_peripheral!(
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
@ -72,7 +72,7 @@ foreach_peripheral!(
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
@ -85,8 +85,8 @@ foreach_peripheral!(
(adc, ADC2) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC2 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe {
match crate::rcc::get_freqs().adc {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
@ -94,7 +94,7 @@ foreach_peripheral!(
}
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(true))
});
ADC12_ENABLE_COUNTER.fetch_add(1, Ordering::SeqCst);
@ -102,7 +102,7 @@ foreach_peripheral!(
fn disable() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| w.set_adc12en(false));
})
}
@ -111,7 +111,7 @@ foreach_peripheral!(
fn reset() {
if ADC12_ENABLE_COUNTER.load(Ordering::SeqCst) == 1 {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(true));
crate::pac::RCC.ahb1rstr().modify(|w| w.set_adc12rst(false));
});
@ -124,8 +124,8 @@ foreach_peripheral!(
(adc, ADC3) => {
impl crate::rcc::sealed::RccPeripheral for crate::peripherals::ADC3 {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe {
match crate::rcc::get_freqs().adc {
critical_section::with(|_| {
match unsafe { crate::rcc::get_freqs() }.adc {
Some(ck) => ck,
None => panic!("Invalid ADC clock configuration, AdcClockSource was likely not properly configured.")
}
@ -133,22 +133,22 @@ foreach_peripheral!(
}
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(true))
});
}
fn disable() {
critical_section::with(|_| unsafe {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
})
critical_section::with(|_| {
crate::pac::RCC.ahb4enr().modify(|w| w.set_adc3en(false));
})
}
fn reset() {
critical_section::with(|_| unsafe {
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
});
critical_section::with(|_| {
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(true));
crate::pac::RCC.ahb4rstr().modify(|w| w.set_adc3rst(false));
});
}
}
@ -232,9 +232,7 @@ impl<'d, T: Instance> Adc<'d, T> {
let prescaler = Prescaler::from_ker_ck(T::frequency());
unsafe {
T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
}
T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc()));
let frequency = Hertz(T::frequency().0 / prescaler.divisor());
info!("ADC frequency set to {} Hz", frequency.0);
@ -251,9 +249,7 @@ impl<'d, T: Instance> Adc<'d, T> {
} else {
Boost::LT50
};
unsafe {
T::regs().cr().modify(|w| w.set_boost(boost));
}
T::regs().cr().modify(|w| w.set_boost(boost));
let mut s = Self {
adc,
@ -272,84 +268,68 @@ impl<'d, T: Instance> Adc<'d, T> {
}
fn power_up(&mut self, delay: &mut impl DelayUs<u16>) {
unsafe {
T::regs().cr().modify(|reg| {
reg.set_deeppwd(false);
reg.set_advregen(true);
});
}
T::regs().cr().modify(|reg| {
reg.set_deeppwd(false);
reg.set_advregen(true);
});
delay.delay_us(10);
}
fn configure_differential_inputs(&mut self) {
unsafe {
T::regs().difsel().modify(|w| {
for n in 0..20 {
w.set_difsel(n, Difsel::SINGLEENDED);
}
})
};
T::regs().difsel().modify(|w| {
for n in 0..20 {
w.set_difsel(n, Difsel::SINGLEENDED);
}
});
}
fn calibrate(&mut self) {
unsafe {
T::regs().cr().modify(|w| {
w.set_adcaldif(Adcaldif::SINGLEENDED);
w.set_adcallin(true);
});
T::regs().cr().modify(|w| {
w.set_adcaldif(Adcaldif::SINGLEENDED);
w.set_adcallin(true);
});
T::regs().cr().modify(|w| w.set_adcal(true));
T::regs().cr().modify(|w| w.set_adcal(true));
while T::regs().cr().read().adcal() {}
}
while T::regs().cr().read().adcal() {}
}
fn enable(&mut self) {
unsafe {
T::regs().isr().write(|w| w.set_adrdy(true));
T::regs().cr().modify(|w| w.set_aden(true));
while !T::regs().isr().read().adrdy() {}
T::regs().isr().write(|w| w.set_adrdy(true));
}
T::regs().isr().write(|w| w.set_adrdy(true));
T::regs().cr().modify(|w| w.set_aden(true));
while !T::regs().isr().read().adrdy() {}
T::regs().isr().write(|w| w.set_adrdy(true));
}
fn configure(&mut self) {
// single conversion mode, software trigger
unsafe {
T::regs().cfgr().modify(|w| {
w.set_cont(false);
w.set_exten(Exten::DISABLED);
})
}
T::regs().cfgr().modify(|w| {
w.set_cont(false);
w.set_exten(Exten::DISABLED);
});
}
pub fn enable_vrefint(&self) -> VrefInt {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
});
VrefInt {}
}
pub fn enable_temperature(&self) -> Temperature {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_vsenseen(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_vsenseen(true);
});
Temperature {}
}
pub fn enable_vbat(&self) -> Vbat {
unsafe {
T::common_regs().ccr().modify(|reg| {
reg.set_vbaten(true);
});
}
T::common_regs().ccr().modify(|reg| {
reg.set_vbaten(true);
});
Vbat {}
}
@ -359,30 +339,26 @@ impl<'d, T: Instance> Adc<'d, T> {
}
pub fn set_resolution(&mut self, resolution: Resolution) {
unsafe {
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
}
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
}
/// Perform a single conversion.
fn convert(&mut self) -> u16 {
unsafe {
T::regs().isr().modify(|reg| {
reg.set_eos(true);
reg.set_eoc(true);
});
T::regs().isr().modify(|reg| {
reg.set_eos(true);
reg.set_eoc(true);
});
// Start conversion
T::regs().cr().modify(|reg| {
reg.set_adstart(true);
});
// Start conversion
T::regs().cr().modify(|reg| {
reg.set_adstart(true);
});
while !T::regs().isr().read().eos() {
// spin
}
T::regs().dr().read().0 as u16
while !T::regs().isr().read().eos() {
// spin
}
T::regs().dr().read().0 as u16
}
pub fn read<P>(&mut self, pin: &mut P) -> u16
@ -390,18 +366,16 @@ impl<'d, T: Instance> Adc<'d, T> {
P: AdcPin<T>,
P: crate::gpio::sealed::Pin,
{
unsafe {
pin.set_as_analog();
pin.set_as_analog();
self.read_channel(pin.channel())
}
self.read_channel(pin.channel())
}
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
unsafe { self.read_channel(channel.channel()) }
self.read_channel(channel.channel())
}
unsafe fn read_channel(&mut self, channel: u8) -> u16 {
fn read_channel(&mut self, channel: u8) -> u16 {
// Configure channel
Self::set_channel_sample_time(channel, self.sample_time);
@ -417,7 +391,7 @@ impl<'d, T: Instance> Adc<'d, T> {
self.convert()
}
unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
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));

View File

@ -105,10 +105,8 @@ impl<'d, T: Instance> Can<'d, T> {
) -> Self {
into_ref!(peri, rx, tx);
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
T::enable();
T::reset();
@ -146,6 +144,9 @@ impl<'d, T: Instance> Can<'d, T> {
T::SCEInterrupt::steal().enable();
}
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
Self { can }
}
@ -346,7 +347,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
fn drop(&mut self) {
// Cannot call `free()` because it moves the instance.
// Manually reset the peripheral.
unsafe { T::regs().mcr().write(|w| w.set_reset(true)) }
T::regs().mcr().write(|w| w.set_reset(true));
T::disable();
}
}
@ -422,7 +423,7 @@ unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
foreach_peripheral!(
(can, $inst:ident) => {
impl sealed::Instance for peripherals::$inst {
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _;
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
fn regs() -> &'static crate::pac::can::Can {
&crate::pac::$inst

View File

@ -27,26 +27,24 @@ impl<'d> Crc<'d> {
/// Resets the CRC unit to default value (0xFFFF_FFFF)
pub fn reset(&mut self) {
unsafe { PAC_CRC.cr().write(|w| w.set_reset(true)) };
PAC_CRC.cr().write(|w| w.set_reset(true));
}
/// Feeds a word to the peripheral and returns the current CRC value
pub fn feed_word(&mut self, word: u32) -> u32 {
// write a single byte to the device, and return the result
unsafe {
PAC_CRC.dr().write_value(word);
}
PAC_CRC.dr().write_value(word);
self.read()
}
/// Feed a slice of words to the peripheral and return the result.
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
for word in words {
unsafe { PAC_CRC.dr().write_value(*word) }
PAC_CRC.dr().write_value(*word);
}
self.read()
}
pub fn read(&self) -> u32 {
unsafe { PAC_CRC.dr().read() }
PAC_CRC.dr().read()
}
}

View File

@ -85,95 +85,79 @@ impl<'d> Crc<'d> {
}
pub fn reset(&mut self) {
unsafe {
PAC_CRC.cr().modify(|w| w.set_reset(true));
}
PAC_CRC.cr().modify(|w| w.set_reset(true));
}
/// Reconfigures the CRC peripheral. Doesn't reset.
fn reconfigure(&mut self) {
unsafe {
// Init CRC value
PAC_CRC.init().write_value(self._config.crc_init_value);
#[cfg(crc_v3)]
PAC_CRC.pol().write_value(self._config.crc_poly);
// Init CRC value
PAC_CRC.init().write_value(self._config.crc_init_value);
#[cfg(crc_v3)]
PAC_CRC.pol().write_value(self._config.crc_poly);
// configure CR components
// (reverse I/O, polysize, poly)
PAC_CRC.cr().write(|w| {
// configure reverse output
w.set_rev_out(match self._config.reverse_out {
true => vals::RevOut::REVERSED,
false => vals::RevOut::NORMAL,
});
// configure reverse input
w.set_rev_in(match self._config.reverse_in {
InputReverseConfig::None => vals::RevIn::NORMAL,
InputReverseConfig::Byte => vals::RevIn::BYTE,
InputReverseConfig::Halfword => vals::RevIn::HALFWORD,
InputReverseConfig::Word => vals::RevIn::WORD,
});
// configure the polynomial.
#[cfg(crc_v3)]
w.set_polysize(match self._config.poly_size {
PolySize::Width7 => vals::Polysize::POLYSIZE7,
PolySize::Width8 => vals::Polysize::POLYSIZE8,
PolySize::Width16 => vals::Polysize::POLYSIZE16,
PolySize::Width32 => vals::Polysize::POLYSIZE32,
});
})
}
// configure CR components
// (reverse I/O, polysize, poly)
PAC_CRC.cr().write(|w| {
// configure reverse output
w.set_rev_out(match self._config.reverse_out {
true => vals::RevOut::REVERSED,
false => vals::RevOut::NORMAL,
});
// configure reverse input
w.set_rev_in(match self._config.reverse_in {
InputReverseConfig::None => vals::RevIn::NORMAL,
InputReverseConfig::Byte => vals::RevIn::BYTE,
InputReverseConfig::Halfword => vals::RevIn::HALFWORD,
InputReverseConfig::Word => vals::RevIn::WORD,
});
// configure the polynomial.
#[cfg(crc_v3)]
w.set_polysize(match self._config.poly_size {
PolySize::Width7 => vals::Polysize::POLYSIZE7,
PolySize::Width8 => vals::Polysize::POLYSIZE8,
PolySize::Width16 => vals::Polysize::POLYSIZE16,
PolySize::Width32 => vals::Polysize::POLYSIZE32,
});
});
self.reset();
}
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
pub fn feed_byte(&mut self, byte: u8) -> u32 {
unsafe {
PAC_CRC.dr8().write_value(byte);
PAC_CRC.dr().read()
}
PAC_CRC.dr8().write_value(byte);
PAC_CRC.dr().read()
}
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
for byte in bytes {
unsafe {
PAC_CRC.dr8().write_value(*byte);
}
PAC_CRC.dr8().write_value(*byte);
}
unsafe { PAC_CRC.dr().read() }
PAC_CRC.dr().read()
}
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
unsafe {
PAC_CRC.dr16().write_value(halfword);
PAC_CRC.dr().read()
}
PAC_CRC.dr16().write_value(halfword);
PAC_CRC.dr().read()
}
/// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
for halfword in halfwords {
unsafe {
PAC_CRC.dr16().write_value(*halfword);
}
PAC_CRC.dr16().write_value(*halfword);
}
unsafe { PAC_CRC.dr().read() }
PAC_CRC.dr().read()
}
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
pub fn feed_word(&mut self, word: u32) -> u32 {
unsafe {
PAC_CRC.dr().write_value(word as u32);
PAC_CRC.dr().read()
}
PAC_CRC.dr().write_value(word as u32);
PAC_CRC.dr().read()
}
/// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
pub fn feed_words(&mut self, words: &[u32]) -> u32 {
for word in words {
unsafe {
PAC_CRC.dr().write_value(*word as u32);
}
PAC_CRC.dr().write_value(*word as u32);
}
unsafe { PAC_CRC.dr().read() }
PAC_CRC.dr().read()
}
}

View File

@ -121,13 +121,11 @@ impl<'d, T: Instance> Dac<'d, T> {
T::enable();
T::reset();
unsafe {
T::regs().cr().modify(|reg| {
for ch in 0..channels {
reg.set_en(ch as usize, true);
}
});
}
T::regs().cr().modify(|reg| {
for ch in 0..channels {
reg.set_en(ch as usize, true);
}
});
Self { channels, _peri: peri }
}
@ -143,11 +141,9 @@ impl<'d, T: Instance> Dac<'d, T> {
fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
self.check_channel_exists(ch)?;
unsafe {
T::regs().cr().modify(|reg| {
reg.set_en(ch.index(), on);
})
}
T::regs().cr().modify(|reg| {
reg.set_en(ch.index(), on);
});
Ok(())
}
@ -162,56 +158,42 @@ impl<'d, T: Instance> Dac<'d, T> {
pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch1)?;
unwrap!(self.disable_channel(Channel::Ch1));
unsafe {
T::regs().cr().modify(|reg| {
reg.set_tsel1(trigger.tsel());
})
}
T::regs().cr().modify(|reg| {
reg.set_tsel1(trigger.tsel());
});
Ok(())
}
pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch2)?;
unwrap!(self.disable_channel(Channel::Ch2));
unsafe {
T::regs().cr().modify(|reg| {
reg.set_tsel2(trigger.tsel());
})
}
T::regs().cr().modify(|reg| {
reg.set_tsel2(trigger.tsel());
});
Ok(())
}
pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
self.check_channel_exists(ch)?;
unsafe {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(ch.index(), true);
});
}
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(ch.index(), true);
});
Ok(())
}
pub fn trigger_all(&mut self) {
unsafe {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(Channel::Ch1.index(), true);
reg.set_swtrig(Channel::Ch2.index(), true);
})
}
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(Channel::Ch1.index(), true);
reg.set_swtrig(Channel::Ch2.index(), true);
});
}
pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
self.check_channel_exists(ch)?;
match value {
Value::Bit8(v) => unsafe {
T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v));
},
Value::Bit12(v, Alignment::Left) => unsafe {
T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v));
},
Value::Bit12(v, Alignment::Right) => unsafe {
T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v));
},
Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
@ -239,20 +221,20 @@ foreach_peripheral!(
}
fn reset() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
})
}
fn enable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
})
}
fn disable() {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
})
}

View File

@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::dma::Transfer;
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::{interrupt, Peripheral};
/// Interrupt handler.
@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let ris = crate::pac::DCMI.ris().read();
if ris.err_ris() {
@ -96,8 +96,7 @@ impl Default for Config {
macro_rules! config_pins {
($($pin:ident),*) => {
into_ref!($($pin),*);
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| unsafe {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AFType::Input);
$pin.set_speed(Speed::VeryHigh);
@ -119,7 +118,7 @@ where
pub fn new_8bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -143,7 +142,7 @@ where
pub fn new_10bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -169,7 +168,7 @@ where
pub fn new_12bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -197,7 +196,7 @@ where
pub fn new_14bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -227,7 +226,7 @@ where
pub fn new_es_8bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -249,7 +248,7 @@ where
pub fn new_es_10bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -273,7 +272,7 @@ where
pub fn new_es_12bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -299,7 +298,7 @@ where
pub fn new_es_14bit(
peri: impl Peripheral<P = T> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
@ -334,25 +333,23 @@ where
T::reset();
T::enable();
unsafe {
peri.regs().cr().modify(|r| {
r.set_cm(true); // disable continuous mode (snapshot mode)
r.set_ess(use_embedded_synchronization);
r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
r.set_fcrc(0x00); // capture every frame
r.set_edm(edm); // extended data mode
});
}
peri.regs().cr().modify(|r| {
r.set_cm(true); // disable continuous mode (snapshot mode)
r.set_ess(use_embedded_synchronization);
r.set_pckpol(config.pixclk_polarity == PixelClockPolarity::RisingEdge);
r.set_vspol(config.vsync_level == VSyncDataInvalidLevel::High);
r.set_hspol(config.hsync_level == HSyncDataInvalidLevel::High);
r.set_fcrc(0x00); // capture every frame
r.set_edm(edm); // extended data mode
});
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Self { inner: peri, dma }
}
unsafe fn toggle(enable: bool) {
fn toggle(enable: bool) {
crate::pac::DCMI.cr().modify(|r| {
r.set_enable(enable);
r.set_capture(enable);
@ -360,23 +357,19 @@ where
}
fn enable_irqs() {
unsafe {
crate::pac::DCMI.ier().modify(|r| {
r.set_err_ie(true);
r.set_ovr_ie(true);
r.set_frame_ie(true);
});
}
crate::pac::DCMI.ier().modify(|r| {
r.set_err_ie(true);
r.set_ovr_ie(true);
r.set_frame_ie(true);
});
}
fn clear_interrupt_flags() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_ovr_isc(true);
r.set_err_isc(true);
r.set_frame_isc(true);
})
}
crate::pac::DCMI.icr().write(|r| {
r.set_ovr_isc(true);
r.set_err_isc(true);
r.set_frame_isc(true);
})
}
/// This method starts the capture and finishes when both the dma transfer and DCMI finish the frame transfer.
@ -392,41 +385,30 @@ where
return self.capture_giant(buffer).await;
}
}
async fn capture_small(&mut self, buffer: &mut [u32]) -> Result<(), Error> {
let r = self.inner.regs();
let src = r.dr().ptr() as *mut u32;
let src = r.dr().as_ptr() as *mut u32;
let request = self.dma.request();
let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) };
Self::clear_interrupt_flags();
Self::enable_irqs();
unsafe { Self::toggle(true) };
Self::toggle(true);
let result = poll_fn(|cx| {
STATE.waker.register(cx.waker());
let ris = unsafe { crate::pac::DCMI.ris().read() };
let ris = crate::pac::DCMI.ris().read();
if ris.err_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_err_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
Poll::Ready(Err(Error::PeripheralError))
} else if ris.ovr_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_ovr_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
Poll::Ready(Err(Error::Overrun))
} else if ris.frame_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_frame_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
Poll::Ready(Ok(()))
} else {
Poll::Pending
@ -435,7 +417,7 @@ where
let (_, result) = embassy_futures::join::join(dma_read, result).await;
unsafe { Self::toggle(false) };
Self::toggle(false);
result
}
@ -468,7 +450,7 @@ where
let request = channel.request();
let r = self.inner.regs();
let src = r.dr().ptr() as *mut u32;
let src = r.dr().as_ptr() as *mut u32;
let mut transfer = unsafe {
crate::dma::DoubleBuffered::new_read(
@ -526,38 +508,26 @@ where
let result = poll_fn(|cx| {
STATE.waker.register(cx.waker());
let ris = unsafe { crate::pac::DCMI.ris().read() };
let ris = crate::pac::DCMI.ris().read();
if ris.err_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_err_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_err_isc(true));
Poll::Ready(Err(Error::PeripheralError))
} else if ris.ovr_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_ovr_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_ovr_isc(true));
Poll::Ready(Err(Error::Overrun))
} else if ris.frame_ris() {
unsafe {
crate::pac::DCMI.icr().write(|r| {
r.set_frame_isc(true);
})
};
crate::pac::DCMI.icr().write(|r| r.set_frame_isc(true));
Poll::Ready(Ok(()))
} else {
Poll::Pending
}
});
unsafe { Self::toggle(true) };
Self::toggle(true);
let (_, result) = embassy_futures::join::join(dma_result, result).await;
unsafe { Self::toggle(false) };
Self::toggle(false);
result
}
@ -570,7 +540,7 @@ mod sealed {
}
pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
}
pin_trait!(D0Pin, Instance);
@ -602,7 +572,7 @@ macro_rules! impl_peripheral {
}
impl Instance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}

View File

@ -6,7 +6,6 @@ use core::sync::atomic::{fence, Ordering};
use core::task::{Context, Poll, Waker};
use atomic_polyfill::AtomicUsize;
use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
@ -14,7 +13,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::BDMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::Priority;
use crate::pac;
use crate::pac::bdma::{regs, vals};
@ -70,9 +70,8 @@ static STATE: State = State::new();
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
let irq = crate::interrupt::$irq::steal();
irq.set_priority(irq_priority);
irq.enable();
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
crate::interrupt::typelevel::$irq::enable();
};
}
crate::_generated::init_bdma();
@ -108,7 +107,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
let cr = dma.ch(channel_num).cr();
if isr.teif(channel_num) {
panic!("DMA: error on BDMA@{:08x} channel {}", dma.0 as u32, channel_num);
panic!("DMA: error on BDMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
}
if isr.htif(channel_num) && cr.read().htie() {
@ -292,29 +291,25 @@ impl<'a, C: Channel> Transfer<'a, C> {
}
fn clear_irqs(&mut self) {
unsafe {
self.channel.regs().ifcr().write(|w| {
w.set_tcif(self.channel.num(), true);
w.set_teif(self.channel.num(), true);
})
}
self.channel.regs().ifcr().write(|w| {
w.set_tcif(self.channel.num(), true);
w.set_teif(self.channel.num(), true);
});
}
pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
})
}
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
});
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
let en = unsafe { ch.cr().read() }.en();
let en = ch.cr().read().en();
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
en && !tcif
}
@ -323,11 +318,12 @@ impl<'a, C: Channel> Transfer<'a, C> {
/// Note: this will be zero for transfers that completed without cancellation.
pub fn get_remaining_transfers(&self) -> u16 {
let ch = self.channel.regs().ch(self.channel.num());
unsafe { ch.ndtr().read() }.ndt()
ch.ndtr().read().ndt()
}
pub fn blocking_wait(mut self) {
while self.is_running() {}
self.request_stop();
// "Subsequent reads and writes cannot be moved ahead of preceding reads."
fence(Ordering::SeqCst);
@ -367,7 +363,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
fn get_remaining_transfers(&self) -> usize {
let ch = self.0.regs().ch(self.0.num());
unsafe { ch.ndtr().read() }.ndt() as usize
ch.ndtr().read().ndt() as usize
}
fn get_complete_count(&self) -> usize {
@ -443,7 +439,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
pub fn start(&mut self) {
let ch = self.channel.regs().ch(self.channel.num());
unsafe { ch.cr().write_value(self.cr) }
ch.cr().write_value(self.cr)
}
pub fn clear(&mut self) {
@ -470,31 +466,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
fn clear_irqs(&mut self) {
let dma = self.channel.regs();
unsafe {
dma.ifcr().write(|w| {
w.set_htif(self.channel.num(), true);
w.set_tcif(self.channel.num(), true);
w.set_teif(self.channel.num(), true);
})
}
dma.ifcr().write(|w| {
w.set_htif(self.channel.num(), true);
w.set_tcif(self.channel.num(), true);
w.set_teif(self.channel.num(), true);
});
}
pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
w.set_htie(true);
w.set_tcie(true);
})
}
ch.cr().write(|w| {
w.set_teie(true);
w.set_htie(true);
w.set_tcie(true);
});
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
unsafe { ch.cr().read() }.en()
ch.cr().read().en()
}
}

View File

@ -5,7 +5,6 @@ use core::sync::atomic::{fence, Ordering};
use core::task::{Context, Poll, Waker};
use atomic_polyfill::AtomicUsize;
use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
@ -13,7 +12,8 @@ use super::ringbuffer::{DmaCtrl, DmaRingBuffer, OverrunError};
use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::DMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::Priority;
use crate::pac::dma::{regs, vals};
use crate::{interrupt, pac};
@ -149,9 +149,8 @@ static STATE: State = State::new();
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
let irq = interrupt::$irq::steal();
irq.set_priority(irq_priority);
irq.enable();
interrupt::typelevel::$irq::set_priority(irq_priority);
interrupt::typelevel::$irq::enable();
};
}
crate::_generated::init_dma();
@ -184,7 +183,7 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
let isr = dma.isr(channel_num / 4).read();
if isr.teif(channel_num % 4) {
panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
panic!("DMA: error on DMA@{:08x} channel {}", dma.as_ptr() as u32, channel_num);
}
if isr.htif(channel_num % 4) && cr.read().htie() {
@ -388,36 +387,32 @@ impl<'a, C: Channel> Transfer<'a, C> {
let isrn = self.channel.num() / 4;
let isrbit = self.channel.num() % 4;
unsafe {
self.channel.regs().ifcr(isrn).write(|w| {
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
})
}
self.channel.regs().ifcr(isrn).write(|w| {
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
});
}
pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
})
}
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
});
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.cr().read() }.en()
ch.cr().read().en()
}
/// Gets the total remaining transfers for the channel
/// Note: this will be zero for transfers that completed without cancellation.
pub fn get_remaining_transfers(&self) -> u16 {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.ndtr().read() }.ndt()
ch.ndtr().read().ndt()
}
pub fn blocking_wait(mut self) {
@ -538,13 +533,11 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
let isrn = channel_number / 4;
let isrbit = channel_number % 4;
unsafe {
dma.ifcr(isrn).write(|w| {
w.set_htif(isrbit, true);
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
})
}
dma.ifcr(isrn).write(|w| {
w.set_htif(isrbit, true);
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
});
}
pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
@ -559,7 +552,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
pub fn is_buffer0_accessible(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.cr().read() }.ct() == vals::Ct::MEMORY1
ch.cr().read().ct() == vals::Ct::MEMORY1
}
pub fn set_waker(&mut self, waker: &Waker) {
@ -570,24 +563,22 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
let ch = self.channel.regs().st(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
})
}
ch.cr().write(|w| {
w.set_teie(true);
w.set_tcie(true);
});
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.cr().read() }.en()
ch.cr().read().en()
}
/// Gets the total remaining transfers for the channel
/// Note: this will be zero for transfers that completed without cancellation.
pub fn get_remaining_transfers(&self) -> u16 {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.ndtr().read() }.ndt()
ch.ndtr().read().ndt()
}
}
@ -608,7 +599,7 @@ struct DmaCtrlImpl<'a, C: Channel>(PeripheralRef<'a, C>);
impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
fn get_remaining_transfers(&self) -> usize {
let ch = self.0.regs().st(self.0.num());
unsafe { ch.ndtr().read() }.ndt() as usize
ch.ndtr().read().ndt() as usize
}
fn get_complete_count(&self) -> usize {
@ -699,7 +690,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
pub fn start(&mut self) {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.cr().write_value(self.cr) }
ch.cr().write_value(self.cr);
}
pub fn clear(&mut self) {
@ -730,31 +721,27 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
let isrn = channel_number / 4;
let isrbit = channel_number % 4;
unsafe {
dma.ifcr(isrn).write(|w| {
w.set_htif(isrbit, true);
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
})
}
dma.ifcr(isrn).write(|w| {
w.set_htif(isrbit, true);
w.set_tcif(isrbit, true);
w.set_teif(isrbit, true);
});
}
pub fn request_stop(&mut self) {
let ch = self.channel.regs().st(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
w.set_htie(true);
w.set_tcie(true);
})
}
ch.cr().write(|w| {
w.set_teie(true);
w.set_htie(true);
w.set_tcie(true);
});
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().st(self.channel.num());
unsafe { ch.cr().read() }.en()
ch.cr().read().en()
}
}

View File

@ -2,7 +2,7 @@
use crate::{pac, peripherals};
pub(crate) unsafe fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
pub(crate) fn configure_dmamux<M: MuxChannel>(channel: &mut M, request: u8) {
let ch_mux_regs = channel.mux_regs().ccr(channel.mux_num());
ch_mux_regs.write(|reg| {
reg.set_nbreq(0);

View File

@ -5,14 +5,14 @@ use core::pin::Pin;
use core::sync::atomic::{fence, Ordering};
use core::task::{Context, Poll};
use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use super::word::{Word, WordSize};
use super::Dir;
use crate::_generated::GPDMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::Priority;
use crate::pac;
use crate::pac::gpdma::vals;
@ -56,9 +56,8 @@ static STATE: State = State::new();
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
let irq = crate::interrupt::$irq::steal();
irq.set_priority(irq_priority);
irq.enable();
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
crate::interrupt::typelevel::$irq::enable();
};
}
crate::_generated::init_gpdma();
@ -93,13 +92,15 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
if sr.dtef() {
panic!(
"DMA: data transfer error on DMA@{:08x} channel {}",
dma.0 as u32, channel_num
dma.as_ptr() as u32,
channel_num
);
}
if sr.usef() {
panic!(
"DMA: user settings error on DMA@{:08x} channel {}",
dma.0 as u32, channel_num
dma.as_ptr() as u32,
channel_num
);
}
@ -299,26 +300,24 @@ impl<'a, C: Channel> Transfer<'a, C> {
let ch = self.channel.regs().ch(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
unsafe {
ch.cr().write(|w| {
w.set_tcie(true);
w.set_useie(true);
w.set_dteie(true);
w.set_suspie(true);
})
}
ch.cr().write(|w| {
w.set_tcie(true);
w.set_useie(true);
w.set_dteie(true);
w.set_suspie(true);
})
}
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
!unsafe { ch.sr().read() }.tcf()
!ch.sr().read().tcf()
}
/// Gets the total remaining transfers for the channel
/// Note: this will be zero for transfers that completed without cancellation.
pub fn get_remaining_transfers(&self) -> u16 {
let ch = self.channel.regs().ch(self.channel.num());
unsafe { ch.br1().read() }.bndt()
ch.br1().read().bndt()
}
pub fn blocking_wait(mut self) {

View File

@ -26,11 +26,11 @@ pub mod word;
use core::mem;
use embassy_cortex_m::interrupt::Priority;
use embassy_hal_common::impl_peripheral;
#[cfg(dmamux)]
pub use self::dmamux::*;
use crate::interrupt::Priority;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]

View File

@ -5,7 +5,6 @@ mod tx_desc;
use core::sync::atomic::{fence, Ordering};
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::{into_ref, PeripheralRef};
use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf};
@ -14,6 +13,7 @@ pub(crate) use self::tx_desc::{TDes, TDesRing};
use super::*;
use crate::gpio::sealed::{AFType, Pin as __GpioPin};
use crate::gpio::AnyPin;
use crate::interrupt::InterruptExt;
#[cfg(eth_v1a)]
use crate::pac::AFIO;
#[cfg(any(eth_v1b, eth_v1c))]
@ -24,23 +24,21 @@ use crate::{interrupt, Peripheral};
/// Interrupt handler.
pub struct InterruptHandler {}
impl interrupt::Handler<interrupt::ETH> for InterruptHandler {
impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
unsafe fn on_interrupt() {
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
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();
}
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();
}
}
@ -59,7 +57,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
#[cfg(eth_v1a)]
macro_rules! config_in_pins {
($($pin:ident),*) => {
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| {
$(
// TODO properly create a set_as_input function
@ -72,7 +69,6 @@ macro_rules! config_in_pins {
#[cfg(eth_v1a)]
macro_rules! config_af_pins {
($($pin:ident),*) => {
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| {
$(
// We are lucky here, this configures to max speed (50MHz)
@ -85,7 +81,6 @@ macro_rules! config_af_pins {
#[cfg(any(eth_v1b, eth_v1c))]
macro_rules! config_pins {
($($pin:ident),*) => {
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@ -100,7 +95,7 @@ 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,
_irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd,
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@ -116,222 +111,208 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
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));
// Enable the necessary Clocks
#[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);
});
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);
});
#[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);
});
// RMII (Reduced Media Independent Interface)
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
});
// RMII (Reduced Media Independent Interface)
SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true));
});
#[cfg(eth_v1a)]
{
config_in_pins!(ref_clk, rx_d0, rx_d1);
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
}
#[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 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")
}
};
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);
let mac = ETH.ethernet_mac();
let dma = ETH.ethernet_dma();
mac.maccr().modify(|w| {
w.set_re(true);
w.set_te(true);
});
dma.dmaomr().modify(|w| {
w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
w.set_st(St::STARTED); // start transmitting channel
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);
interrupt::ETH::steal().unpend();
interrupt::ETH::steal().enable();
this
#[cfg(eth_v1a)]
{
config_in_pins!(ref_clk, rx_d0, rx_d1);
config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en);
}
#[cfg(any(eth_v1b, eth_v1c))]
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
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 = unsafe { 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);
let mac = ETH.ethernet_mac();
let dma = ETH.ethernet_dma();
mac.maccr().modify(|w| {
w.set_re(true);
w.set_te(true);
});
dma.dmaomr().modify(|w| {
w.set_ftf(Ftf::FLUSH); // flush transmit fifo (queue)
w.set_st(St::STARTED); // start transmitting channel
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);
interrupt::ETH.unpend();
unsafe { interrupt::ETH.enable() };
this
}
}
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 {
let mac = ETH.ethernet_mac();
let mac = ETH.ethernet_mac();
mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_mr(reg);
w.set_mw(Mw::READ); // read operation
w.set_cr(self.clock_range);
w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
});
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
mac.macmiidr().read().md()
}
mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_mr(reg);
w.set_mw(Mw::READ); // read operation
w.set_cr(self.clock_range);
w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
});
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
mac.macmiidr().read().md()
}
fn smi_write(&mut self, reg: u8, val: u16) {
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
unsafe {
let mac = ETH.ethernet_mac();
let mac = ETH.ethernet_mac();
mac.macmiidr().write(|w| w.set_md(val));
mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_mr(reg);
w.set_mw(Mw::WRITE); // write
w.set_cr(self.clock_range);
w.set_mb(MbProgress::BUSY);
});
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
}
mac.macmiidr().write(|w| w.set_md(val));
mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_mr(reg);
w.set_mw(Mw::WRITE); // write
w.set_cr(self.clock_range);
w.set_mb(MbProgress::BUSY);
});
while mac.macmiiar().read().mb() == MbProgress::BUSY {}
}
}
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 {
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
// Disable the TX DMA and wait for any previous transmissions to be completed
dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
// Disable the TX DMA and wait for any previous transmissions to be completed
dma.dmaomr().modify(|w| w.set_st(St::STOPPED));
// Disable MAC transmitter and receiver
mac.maccr().modify(|w| {
w.set_re(false);
w.set_te(false);
});
// Disable MAC transmitter and receiver
mac.maccr().modify(|w| {
w.set_re(false);
w.set_te(false);
});
dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
}
dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED));
// NOTE(unsafe) Exclusive access to the regs
critical_section::with(|_| unsafe {
critical_section::with(|_| {
for pin in self.pins.iter_mut() {
pin.set_as_disconnected();
}

View File

@ -146,12 +146,9 @@ impl<'a> RDesRing<'a> {
}
// Register rx descriptor start
// NOTE (unsafe) Used for atomic writes
unsafe {
ETH.ethernet_dma()
.dmardlar()
.write(|w| w.0 = descriptors.as_ptr() as u32);
};
ETH.ethernet_dma()
.dmardlar()
.write(|w| w.0 = descriptors.as_ptr() as u32);
// We already have fences in `set_owned`, which is called in `setup`
Self {
@ -162,12 +159,12 @@ impl<'a> RDesRing<'a> {
}
pub(crate) fn demand_poll(&self) {
unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) };
ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL));
}
/// Get current `RunningState`
fn running_state(&self) -> RunningState {
match unsafe { ETH.ethernet_dma().dmasr().read().rps() } {
match ETH.ethernet_dma().dmasr().read().rps() {
// Reset or Stop Receive Command issued
Rps::STOPPED => RunningState::Stopped,
// Fetching receive transfer descriptor

View File

@ -120,12 +120,9 @@ impl<'a> TDesRing<'a> {
}
// Register txdescriptor start
// NOTE (unsafe) Used for atomic writes
unsafe {
ETH.ethernet_dma()
.dmatdlar()
.write(|w| w.0 = descriptors.as_ptr() as u32);
}
ETH.ethernet_dma()
.dmatdlar()
.write(|w| w.0 = descriptors.as_ptr() as u32);
Self {
descriptors,
@ -169,6 +166,6 @@ impl<'a> TDesRing<'a> {
self.index = 0
}
// Request the DMA engine to poll the latest tx descriptor
unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) }
ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1)
}
}

View File

@ -73,14 +73,10 @@ impl<'a> TDesRing<'a> {
// Initialize the pointers in the DMA engine. (There will be a memory barrier later
// before the DMA engine is enabled.)
// NOTE (unsafe) Used for atomic writes
unsafe {
let dma = ETH.ethernet_dma();
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);
}
let dma = ETH.ethernet_dma();
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,
@ -129,8 +125,7 @@ impl<'a> TDesRing<'a> {
}
// signal DMA it can try again.
// NOTE(unsafe) Atomic write
unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0)
}
}
@ -199,13 +194,10 @@ impl<'a> RDesRing<'a> {
desc.set_ready(buffers[i].0.as_mut_ptr());
}
unsafe {
let dma = ETH.ethernet_dma();
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);
}
let dma = ETH.ethernet_dma();
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);
Self {
descriptors,
@ -254,8 +246,7 @@ impl<'a> RDesRing<'a> {
fence(Ordering::Release);
// signal DMA it can try again.
// NOTE(unsafe) Atomic write
unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0);
// Increment index.
self.index += 1;

View File

@ -2,36 +2,34 @@ mod descriptors;
use core::sync::atomic::{fence, Ordering};
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::{into_ref, PeripheralRef};
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::interrupt::InterruptExt;
use crate::pac::ETH;
use crate::{interrupt, Peripheral};
/// Interrupt handler.
pub struct InterruptHandler {}
impl interrupt::Handler<interrupt::ETH> for InterruptHandler {
impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandler {
unsafe fn on_interrupt() {
WAKER.wake();
// TODO: Check and clear more flags
unsafe {
let dma = ETH.ethernet_dma();
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();
}
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();
}
}
@ -50,7 +48,6 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
macro_rules! config_pins {
($($pin:ident),*) => {
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
@ -64,7 +61,7 @@ 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,
_irq: impl interrupt::Binding<interrupt::ETH, InterruptHandler> + 'd,
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
@ -80,239 +77,225 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
unsafe {
// Enable the necessary Clocks
// NOTE(unsafe) We have exclusive access to the registers
#[cfg(not(rcc_h5))]
critical_section::with(|_| {
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
crate::pac::RCC.ahb1enr().modify(|w| {
w.set_eth1macen(true);
w.set_eth1txen(true);
w.set_eth1rxen(true);
});
// RMII
crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
// Enable the necessary Clocks
#[cfg(not(rcc_h5))]
critical_section::with(|_| {
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
crate::pac::RCC.ahb1enr().modify(|w| {
w.set_eth1macen(true);
w.set_eth1txen(true);
w.set_eth1rxen(true);
});
#[cfg(rcc_h5)]
critical_section::with(|_| {
crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
// RMII
crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
});
crate::pac::RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
#[cfg(rcc_h5)]
critical_section::with(|_| {
crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
// RMII
crate::pac::SBS
.pmcr()
.modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
crate::pac::RCC.ahb1enr().modify(|w| {
w.set_ethen(true);
w.set_ethtxen(true);
w.set_ethrxen(true);
});
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// RMII
crate::pac::SBS
.pmcr()
.modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
});
// NOTE(unsafe) We have exclusive access to the registers
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
// Reset and wait
dma.dmamr().modify(|w| w.set_swr(true));
while dma.dmamr().read().swr() {}
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);
});
// 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)
});
mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
// 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);
});
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);
});
mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
// 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;
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);
});
// 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")
}
};
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
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(),
];
// 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 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,
};
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(),
];
fence(Ordering::SeqCst);
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,
};
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
let dma = ETH.ethernet_dma();
fence(Ordering::SeqCst);
mac.maccr().modify(|w| {
w.set_re(true);
w.set_te(true);
});
mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
let dma = ETH.ethernet_dma();
dma.dmactx_cr().modify(|w| w.set_st(true));
dma.dmacrx_cr().modify(|w| w.set_sr(true));
mac.maccr().modify(|w| {
w.set_re(true);
w.set_te(true);
});
mtl.mtltx_qomr().modify(|w| w.set_ftq(true));
// Enable interrupts
dma.dmacier().modify(|w| {
w.set_nie(true);
w.set_rie(true);
w.set_tie(true);
});
dma.dmactx_cr().modify(|w| w.set_st(true));
dma.dmacrx_cr().modify(|w| w.set_sr(true));
P::phy_reset(&mut this);
P::phy_init(&mut this);
// Enable interrupts
dma.dmacier().modify(|w| {
w.set_nie(true);
w.set_rie(true);
w.set_tie(true);
});
interrupt::ETH::steal().unpend();
interrupt::ETH::steal().enable();
P::phy_reset(&mut this);
P::phy_init(&mut this);
this
}
interrupt::ETH.unpend();
unsafe { interrupt::ETH.enable() };
this
}
}
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 {
let mac = ETH.ethernet_mac();
let mac = ETH.ethernet_mac();
mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_rda(reg);
w.set_goc(0b11); // read
w.set_cr(self.clock_range);
w.set_mb(true);
});
while mac.macmdioar().read().mb() {}
mac.macmdiodr().read().md()
}
mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_rda(reg);
w.set_goc(0b11); // read
w.set_cr(self.clock_range);
w.set_mb(true);
});
while mac.macmdioar().read().mb() {}
mac.macmdiodr().read().md()
}
fn smi_write(&mut self, reg: u8, val: u16) {
// NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
unsafe {
let mac = ETH.ethernet_mac();
let mac = ETH.ethernet_mac();
mac.macmdiodr().write(|w| w.set_md(val));
mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_rda(reg);
w.set_goc(0b01); // write
w.set_cr(self.clock_range);
w.set_mb(true);
});
while mac.macmdioar().read().mb() {}
}
mac.macmdiodr().write(|w| w.set_md(val));
mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr);
w.set_rda(reg);
w.set_goc(0b01); // write
w.set_cr(self.clock_range);
w.set_mb(true);
});
while mac.macmdioar().read().mb() {}
}
}
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 {
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
let dma = ETH.ethernet_dma();
let mac = ETH.ethernet_mac();
let mtl = ETH.ethernet_mtl();
// Disable the TX DMA and wait for any previous transmissions to be completed
dma.dmactx_cr().modify(|w| w.set_st(false));
while {
let txqueue = mtl.mtltx_qdr().read();
txqueue.trcsts() == 0b01 || txqueue.txqsts()
} {}
// Disable the TX DMA and wait for any previous transmissions to be completed
dma.dmactx_cr().modify(|w| w.set_st(false));
while {
let txqueue = mtl.mtltx_qdr().read();
txqueue.trcsts() == 0b01 || txqueue.txqsts()
} {}
// Disable MAC transmitter and receiver
mac.maccr().modify(|w| {
w.set_re(false);
w.set_te(false);
});
// Disable MAC transmitter and receiver
mac.maccr().modify(|w| {
w.set_re(false);
w.set_te(false);
});
// Wait for previous receiver transfers to be completed and then disable the RX DMA
while {
let rxqueue = mtl.mtlrx_qdr().read();
rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
} {}
dma.dmacrx_cr().modify(|w| w.set_sr(false));
}
// Wait for previous receiver transfers to be completed and then disable the RX DMA
while {
let rxqueue = mtl.mtlrx_qdr().read();
rxqueue.rxqsts() != 0b00 || rxqueue.prxq() != 0
} {}
dma.dmacrx_cr().modify(|w| w.set_sr(false));
// NOTE(unsafe) Exclusive access to the regs
critical_section::with(|_| unsafe {
critical_section::with(|_| {
for pin in self.pins.iter_mut() {
pin.set_as_disconnected();
}

View File

@ -206,7 +206,7 @@ struct ExtiInputFuture<'a> {
impl<'a> ExtiInputFuture<'a> {
fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let pin = pin as usize;
exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
EXTI.rtsr(0).modify(|w| w.set_line(pin, rising));
@ -233,7 +233,7 @@ impl<'a> ExtiInputFuture<'a> {
impl<'a> Drop for ExtiInputFuture<'a> {
fn drop(&mut self) {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let pin = self.pin as _;
cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
});
@ -246,7 +246,7 @@ impl<'a> Future for ExtiInputFuture<'a> {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
EXTI_WAKERS[self.pin as usize].register(cx.waker());
let imr = unsafe { cpu_regs().imr(0).read() };
let imr = cpu_regs().imr(0).read();
if !imr.line(self.pin as _) {
Poll::Ready(())
} else {
@ -291,6 +291,7 @@ macro_rules! foreach_exti_irq {
macro_rules! impl_irq {
($e:ident) => {
#[cfg(feature = "rt")]
#[interrupt]
unsafe fn $e() {
on_irq()
@ -354,13 +355,13 @@ impl_exti!(EXTI15, 15);
macro_rules! enable_irq {
($e:ident) => {
crate::interrupt::$e::steal().enable();
crate::interrupt::typelevel::$e::enable();
};
}
/// safety: must be called only once
pub(crate) unsafe fn init() {
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
foreach_exti_irq!(enable_irq);

View File

@ -1,7 +1,6 @@
use core::marker::PhantomData;
use atomic_polyfill::{fence, Ordering};
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::into_ref;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
@ -11,6 +10,7 @@ use super::{
blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE,
WRITE_SIZE,
};
use crate::interrupt::InterruptExt;
use crate::peripherals::FLASH;
use crate::{interrupt, Peripheral};
@ -19,13 +19,12 @@ pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new
impl<'d> Flash<'d, Async> {
pub fn new(
p: impl Peripheral<P = FLASH> + 'd,
_irq: impl interrupt::Binding<crate::interrupt::FLASH, InterruptHandler> + 'd,
_irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
) -> Self {
into_ref!(p);
let flash_irq = unsafe { crate::interrupt::FLASH::steal() };
flash_irq.unpend();
flash_irq.enable();
crate::interrupt::FLASH.unpend();
unsafe { crate::interrupt::FLASH.enable() };
Self {
inner: p,
@ -50,7 +49,7 @@ impl<'d> Flash<'d, Async> {
/// Interrupt handler
pub struct InterruptHandler;
impl interrupt::Handler<crate::interrupt::FLASH> for InterruptHandler {
impl interrupt::typelevel::Handler<crate::interrupt::typelevel::FLASH> for InterruptHandler {
unsafe fn on_interrupt() {
family::on_interrupt();
}

View File

@ -192,7 +192,7 @@ impl FlashSector {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
pub(crate) fn is_default_layout() -> bool {
unsafe { !pac::FLASH.optcr().read().db1m() }
!pac::FLASH.optcr().read().db1m()
}
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))]
@ -336,7 +336,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
ret
}
pub(crate) unsafe fn clear_all_err() {
pub(crate) fn clear_all_err() {
pac::FLASH.sr().write(|w| {
w.set_pgserr(true);
w.set_pgperr(true);
@ -345,7 +345,7 @@ pub(crate) unsafe fn clear_all_err() {
});
}
pub(crate) async unsafe fn wait_ready() -> Result<(), Error> {
pub(crate) async fn wait_ready() -> Result<(), Error> {
use core::task::Poll;
use futures::future::poll_fn;
@ -391,10 +391,10 @@ fn save_data_cache_state() {
let dual_bank = get_flash_regions().last().unwrap().bank == FlashBank::Bank2;
if dual_bank {
// Disable data cache during write/erase if there are two banks, see errata 2.2.12
let dcen = unsafe { pac::FLASH.acr().read().dcen() };
let dcen = pac::FLASH.acr().read().dcen();
DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
if dcen {
unsafe { pac::FLASH.acr().modify(|w| w.set_dcen(false)) };
pac::FLASH.acr().modify(|w| w.set_dcen(false));
}
}
}
@ -405,12 +405,10 @@ fn restore_data_cache_state() {
// Restore data cache if it was enabled
let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
if dcen {
unsafe {
// Reset data cache before we enable it again
pac::FLASH.acr().modify(|w| w.set_dcrst(true));
pac::FLASH.acr().modify(|w| w.set_dcrst(false));
pac::FLASH.acr().modify(|w| w.set_dcen(true))
};
// Reset data cache before we enable it again
pac::FLASH.acr().modify(|w| w.set_dcrst(true));
pac::FLASH.acr().modify(|w| w.set_dcrst(false));
pac::FLASH.acr().modify(|w| w.set_dcen(true))
}
}
}
@ -445,7 +443,7 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
feature = "stm32f439vi",
feature = "stm32f439zi",
))]
if second_bank_read && unsafe { pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() } {
if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11");
}
@ -479,11 +477,9 @@ fn pa12_is_output_pull_low() -> bool {
use pac::gpio::vals;
use pac::GPIOA;
const PIN: usize = 12;
unsafe {
GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
&& GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
&& GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
}
GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
&& GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN
&& GPIOA.odr().read().odr(PIN) == vals::Odr::LOW
}
#[cfg(test)]

View File

@ -16,7 +16,7 @@ unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
where
T: Instance,
{
const REGISTERS: *const () = T::REGS.0 as *const _;
const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
fn enable(&mut self) {
<T as crate::rcc::sealed::RccPeripheral>::enable();
@ -28,9 +28,7 @@ where
// 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))
};
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
}
fn source_clock_hz(&self) -> u32 {
@ -67,7 +65,7 @@ macro_rules! fmc_sdram_constructor {
chip: CHIP
) -> stm32_fmc::Sdram<Fmc<'d, T>, CHIP> {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
config_pins!(
$($addr_pin_name),*,
$($ba_pin_name),*,

View File

@ -46,7 +46,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Put the pin into input mode.
#[inline]
pub fn set_as_input(&mut self, pull: Pull) {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let r = self.pin.block();
let n = self.pin.pin() as usize;
#[cfg(gpio_v1)]
@ -84,7 +84,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// at a specific level, call `set_high`/`set_low` on the pin first.
#[inline]
pub fn set_as_output(&mut self, speed: Speed) {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let r = self.pin.block();
let n = self.pin.pin() as usize;
#[cfg(gpio_v1)]
@ -116,7 +116,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// at a specific level, call `set_high`/`set_low` on the pin first.
#[inline]
pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let r = self.pin.block();
let n = self.pin.pin() as usize;
#[cfg(gpio_v1)]
@ -147,7 +147,7 @@ impl<'d, T: Pin> Flex<'d, T> {
#[inline]
pub fn is_low(&self) -> bool {
let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) };
let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
state == vals::Idr::LOW
}
@ -164,7 +164,7 @@ impl<'d, T: Pin> Flex<'d, T> {
/// Is the output pin set as low?
#[inline]
pub fn is_set_low(&self) -> bool {
let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) };
let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
state == vals::Odr::LOW
}
@ -207,7 +207,7 @@ impl<'d, T: Pin> Flex<'d, T> {
impl<'d, T: Pin> Drop for Flex<'d, T> {
#[inline]
fn drop(&mut self) {
critical_section::with(|_| unsafe {
critical_section::with(|_| {
let r = self.pin.block();
let n = self.pin.pin() as usize;
#[cfg(gpio_v1)]
@ -341,9 +341,9 @@ impl From<bool> for Level {
}
}
impl Into<bool> for Level {
fn into(self) -> bool {
match self {
impl From<Level> for bool {
fn from(level: Level) -> bool {
match level {
Level::Low => false,
Level::High => true,
}
@ -534,29 +534,25 @@ pub(crate) mod sealed {
/// Set the output as high.
#[inline]
fn set_high(&self) {
unsafe {
let n = self._pin() as _;
self.block().bsrr().write(|w| w.set_bs(n, true));
}
let n = self._pin() as _;
self.block().bsrr().write(|w| w.set_bs(n, true));
}
/// Set the output as low.
#[inline]
fn set_low(&self) {
unsafe {
let n = self._pin() as _;
self.block().bsrr().write(|w| w.set_br(n, true));
}
let n = self._pin() as _;
self.block().bsrr().write(|w| w.set_br(n, true));
}
#[inline]
unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) {
fn set_as_af(&self, af_num: u8, af_type: AFType) {
self.set_as_af_pull(af_num, af_type, Pull::None);
}
#[cfg(gpio_v1)]
#[inline]
unsafe fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
fn set_as_af_pull(&self, _af_num: u8, af_type: AFType, pull: Pull) {
// F1 uses the AFIO register for remapping.
// For now, this is not implemented, so af_num is ignored
// _af_num should be zero here, since it is not set by stm32-data
@ -599,7 +595,7 @@ pub(crate) mod sealed {
#[cfg(gpio_v2)]
#[inline]
unsafe fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
fn set_as_af_pull(&self, af_num: u8, af_type: AFType, pull: Pull) {
let pin = self._pin() as usize;
let block = self.block();
block.afr(pin / 8).modify(|w| w.set_afr(pin % 8, af_num));
@ -614,7 +610,7 @@ pub(crate) mod sealed {
}
#[inline]
unsafe fn set_as_analog(&self) {
fn set_as_analog(&self) {
let pin = self._pin() as usize;
let block = self.block();
#[cfg(gpio_v1)]
@ -635,12 +631,12 @@ pub(crate) mod sealed {
/// This is currently the same as set_as_analog but is semantically different really.
/// Drivers should set_as_disconnected pins when dropped.
#[inline]
unsafe fn set_as_disconnected(&self) {
fn set_as_disconnected(&self) {
self.set_as_analog();
}
#[inline]
unsafe fn set_speed(&self, speed: Speed) {
fn set_speed(&self, speed: Speed) {
let pin = self._pin() as usize;
#[cfg(gpio_v1)]

View File

@ -1,6 +1,6 @@
#![macro_use]
use crate::interrupt::Interrupt;
use crate::interrupt;
#[cfg_attr(i2c_v1, path = "v1.rs")]
#[cfg_attr(i2c_v2, path = "v2.rs")]
@ -35,7 +35,7 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + 'static {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
}
pin_trait!(SclPin, Instance);
@ -57,7 +57,7 @@ foreach_interrupt!(
}
impl Instance for peripherals::$inst {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
);

View File

@ -16,7 +16,7 @@ pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {}
}
@ -57,7 +57,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
_peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
@ -68,53 +68,45 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
T::enable();
T::reset();
unsafe {
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
}
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_pe(false);
//reg.set_anfoff(false);
});
}
T::regs().cr1().modify(|reg| {
reg.set_pe(false);
//reg.set_anfoff(false);
});
let timings = Timings::new(T::frequency(), freq.into());
unsafe {
T::regs().cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
T::regs().ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
T::regs().trise().modify(|reg| {
reg.set_trise(timings.trise);
});
}
T::regs().cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
T::regs().ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
T::regs().trise().modify(|reg| {
reg.set_trise(timings.trise);
});
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_pe(true);
});
}
T::regs().cr1().modify(|reg| {
reg.set_pe(true);
});
Self {
phantom: PhantomData,
@ -123,7 +115,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
}
unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> {
// Note that flags should only be cleared once they have been registered. If flags are
// cleared otherwise, there may be an inherent race condition and flags may be missed.
let sr1 = T::regs().sr1().read();
@ -162,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(sr1)
}
unsafe fn write_bytes(
fn write_bytes(
&mut self,
addr: u8,
bytes: &[u8],
@ -211,7 +203,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
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.
@ -234,7 +226,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> {
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()?;
@ -256,56 +248,52 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
) -> Result<(), Error> {
if let Some((last, buffer)) = buffer.split_last_mut() {
// Send a START condition and set ACK bit
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_start(true);
reg.set_ack(true);
});
}
T::regs().cr1().modify(|reg| {
reg.set_start(true);
reg.set_ack(true);
});
// Wait until START condition was generated
while unsafe { !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 {
let sr2 = unsafe { T::regs().sr2().read() };
let sr2 = 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)) }
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 !self.check_and_clear_error_flags()?.addr() {
check_timeout()?;
}
// Clear condition by reading SR2
let _ = unsafe { T::regs().sr2().read() };
let _ = T::regs().sr2().read();
// Receive bytes into buffer
for c in buffer {
*c = unsafe { self.recv_byte(&check_timeout)? };
*c = self.recv_byte(&check_timeout)?;
}
// Prepare to send NACK then STOP after next byte
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_ack(false);
reg.set_stop(true);
})
}
T::regs().cr1().modify(|reg| {
reg.set_ack(false);
reg.set_stop(true);
});
// Receive last byte
*last = unsafe { self.recv_byte(&check_timeout)? };
*last = self.recv_byte(&check_timeout)?;
// Wait for the STOP to be sent.
while unsafe { T::regs().cr1().read().stop() } {
while T::regs().cr1().read().stop() {
check_timeout()?;
}
@ -326,15 +314,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
write: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
unsafe {
self.write_bytes(addr, write, &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() {
check_timeout()?;
}
};
self.write_bytes(addr, write, &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() {
check_timeout()?;
}
// Fallthrough is success
Ok(())
@ -351,7 +337,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
read: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
unsafe { self.write_bytes(addr, write, &check_timeout)? };
self.write_bytes(addr, write, &check_timeout)?;
self.blocking_read_timeout(addr, read, &check_timeout)?;
Ok(())
@ -478,8 +464,6 @@ impl Timings {
assert!(freq >= 2 && freq <= 50);
// Configure bus frequency into I2C peripheral
//self.i2c.cr2.write(|w| unsafe { w.freq().bits(freq as u8) });
let trise = if speed <= 100_000 {
freq + 1
} else {
@ -539,18 +523,16 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
type Config = Hertz;
fn set_config(&mut self, config: &Self::Config) {
let timings = Timings::new(T::frequency(), *config);
unsafe {
T::regs().cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
T::regs().ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
T::regs().trise().modify(|reg| {
reg.set_trise(timings.trise);
});
}
T::regs().cr2().modify(|reg| {
reg.set_freq(timings.freq);
});
T::regs().ccr().modify(|reg| {
reg.set_f_s(timings.mode.f_s());
reg.set_duty(timings.duty.duty());
reg.set_ccr(timings.ccr);
});
T::regs().trise().modify(|reg| {
reg.set_trise(timings.trise);
});
}
}

View File

@ -3,7 +3,6 @@ use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_embedded_hal::SetConfig;
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef};
@ -13,6 +12,7 @@ use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
use crate::interrupt::typelevel::Interrupt;
use crate::pac::i2c;
use crate::time::Hertz;
use crate::{interrupt, Peripheral};
@ -22,7 +22,7 @@ pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let regs = T::regs();
let isr = regs.isr().read();
@ -78,7 +78,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
@ -89,52 +89,44 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
T::enable();
T::reset();
unsafe {
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
}
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_pe(false);
reg.set_anfoff(false);
});
}
T::regs().cr1().modify(|reg| {
reg.set_pe(false);
reg.set_anfoff(false);
});
let timings = Timings::new(T::frequency(), freq.into());
unsafe {
T::regs().timingr().write(|reg| {
reg.set_presc(timings.prescale);
reg.set_scll(timings.scll);
reg.set_sclh(timings.sclh);
reg.set_sdadel(timings.sdadel);
reg.set_scldel(timings.scldel);
});
}
T::regs().timingr().write(|reg| {
reg.set_presc(timings.prescale);
reg.set_scll(timings.scll);
reg.set_sclh(timings.sclh);
reg.set_sdadel(timings.sdadel);
reg.set_scldel(timings.scldel);
});
unsafe {
T::regs().cr1().modify(|reg| {
reg.set_pe(true);
});
}
T::regs().cr1().modify(|reg| {
reg.set_pe(true);
});
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Self {
_peri: peri,
@ -144,12 +136,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}
fn master_stop(&mut self) {
unsafe {
T::regs().cr2().write(|w| w.set_stop(true));
}
T::regs().cr2().write(|w| w.set_stop(true));
}
unsafe fn master_read(
fn master_read(
address: u8,
length: usize,
stop: Stop,
@ -191,7 +181,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
unsafe fn master_write(
fn master_write(
address: u8,
length: usize,
stop: Stop,
@ -229,7 +219,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
unsafe fn master_continue(
fn master_continue(
length: usize,
reload: bool,
check_timeout: impl Fn() -> Result<(), Error>,
@ -259,13 +249,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
//$i2c.txdr.write(|w| w.txdata().bits(0));
//}
unsafe {
if T::regs().isr().read().txis() {
T::regs().txdr().write(|w| w.set_txdata(0));
}
if !T::regs().isr().read().txe() {
T::regs().isr().modify(|w| w.set_txe(true))
}
if T::regs().isr().read().txis() {
T::regs().txdr().write(|w| w.set_txdata(0));
}
if !T::regs().isr().read().txe() {
T::regs().isr().modify(|w| w.set_txe(true))
}
// If TXDR is not flagged as empty, write 1 to flush it
@ -276,21 +264,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
if isr.txe() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
let isr = T::regs().isr().read();
if isr.txe() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
check_timeout()?;
@ -299,21 +285,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
if isr.rxne() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
let isr = T::regs().isr().read();
if isr.rxne() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
check_timeout()?;
@ -322,21 +306,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> {
loop {
unsafe {
let isr = T::regs().isr().read();
if isr.tc() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
let isr = T::regs().isr().read();
if isr.tc() {
return Ok(());
} else if isr.berr() {
T::regs().icr().write(|reg| reg.set_berrcf(true));
return Err(Error::Bus);
} else if isr.arlo() {
T::regs().icr().write(|reg| reg.set_arlocf(true));
return Err(Error::Arbitration);
} else if isr.nackf() {
T::regs().icr().write(|reg| reg.set_nackcf(true));
self.flush_txdr();
return Err(Error::Nack);
}
check_timeout()?;
@ -358,32 +340,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
};
let last_chunk_idx = total_chunks.saturating_sub(1);
unsafe {
Self::master_read(
address,
read.len().min(255),
Stop::Automatic,
last_chunk_idx != 0,
restart,
&check_timeout,
)?;
}
Self::master_read(
address,
read.len().min(255),
Stop::Automatic,
last_chunk_idx != 0,
restart,
&check_timeout,
)?;
for (number, chunk) in read.chunks_mut(255).enumerate() {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
for byte in chunk {
// Wait until we have received something
self.wait_rxne(&check_timeout)?;
unsafe {
*byte = T::regs().rxdr().read().rxdata();
}
*byte = T::regs().rxdr().read().rxdata();
}
}
Ok(())
@ -407,23 +382,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// I2C start
//
// ST SAD+W
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_write(
address,
write.len().min(255),
Stop::Software,
last_chunk_idx != 0,
&check_timeout,
)?;
}
Self::master_write(
address,
write.len().min(255),
Stop::Software,
last_chunk_idx != 0,
&check_timeout,
)?;
for (number, chunk) in write.chunks(255).enumerate() {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?;
}
for byte in chunk {
@ -432,9 +401,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// through)
self.wait_txe(&check_timeout)?;
unsafe {
T::regs().txdr().write(|w| w.set_txdata(*byte));
}
T::regs().txdr().write(|w| w.set_txdata(*byte));
}
}
// Wait until the write finishes
@ -467,7 +434,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
w.set_tcie(true);
}
});
let dst = regs.txdr().ptr() as *mut u8;
let dst = regs.txdr().as_ptr() as *mut u8;
let ch = &mut self.tx_dma;
let request = ch.request();
@ -479,37 +446,30 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let on_drop = OnDrop::new(|| {
let regs = T::regs();
unsafe {
regs.cr1().modify(|w| {
if last_slice {
w.set_txdmaen(false);
}
w.set_tcie(false);
})
}
regs.cr1().modify(|w| {
if last_slice {
w.set_txdmaen(false);
}
w.set_tcie(false);
})
});
poll_fn(|cx| {
state.waker.register(cx.waker());
let isr = unsafe { T::regs().isr().read() };
let isr = T::regs().isr().read();
if remaining_len == total_len {
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
if first_slice {
unsafe {
Self::master_write(
address,
total_len.min(255),
Stop::Software,
(total_len > 255) || !last_slice,
&check_timeout,
)?;
}
Self::master_write(
address,
total_len.min(255),
Stop::Software,
(total_len > 255) || !last_slice,
&check_timeout,
)?;
} else {
unsafe {
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
T::regs().cr1().modify(|w| w.set_tcie(true));
}
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?;
T::regs().cr1().modify(|w| w.set_tcie(true));
}
} else if !(isr.tcr() || isr.tc()) {
// poll_fn was woken without an interrupt present
@ -519,13 +479,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} else {
let last_piece = (remaining_len <= 255) && last_slice;
// NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers
unsafe {
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));
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));
}
remaining_len = remaining_len.saturating_sub(255);
@ -564,7 +521,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
w.set_rxdmaen(true);
w.set_tcie(true);
});
let src = regs.rxdr().ptr() as *mut u8;
let src = regs.rxdr().as_ptr() as *mut u8;
let ch = &mut self.rx_dma;
let request = ch.request();
@ -576,30 +533,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let on_drop = OnDrop::new(|| {
let regs = T::regs();
unsafe {
regs.cr1().modify(|w| {
w.set_rxdmaen(false);
w.set_tcie(false);
})
}
regs.cr1().modify(|w| {
w.set_rxdmaen(false);
w.set_tcie(false);
})
});
poll_fn(|cx| {
state.waker.register(cx.waker());
let isr = unsafe { T::regs().isr().read() };
let isr = T::regs().isr().read();
if remaining_len == total_len {
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
unsafe {
Self::master_read(
address,
total_len.min(255),
Stop::Software,
total_len > 255,
restart,
&check_timeout,
)?;
}
Self::master_read(
address,
total_len.min(255),
Stop::Software,
total_len > 255,
restart,
&check_timeout,
)?;
} else if !(isr.tcr() || isr.tc()) {
// poll_fn was woken without an interrupt present
return Poll::Pending;
@ -608,13 +560,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} else {
let last_piece = remaining_len <= 255;
// NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers
unsafe {
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));
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));
}
remaining_len = remaining_len.saturating_sub(255);
@ -758,16 +707,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let first_length = write[0].len();
let last_slice_index = write.len() - 1;
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_write(
address,
first_length.min(255),
Stop::Software,
(first_length > 255) || (last_slice_index != 0),
&check_timeout,
)?;
}
Self::master_write(
address,
first_length.min(255),
Stop::Software,
(first_length > 255) || (last_slice_index != 0),
&check_timeout,
)?;
for (idx, slice) in write.iter().enumerate() {
let slice_len = slice.len();
@ -780,26 +726,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let last_chunk_idx = total_chunks.saturating_sub(1);
if idx != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(
slice_len.min(255),
(idx != last_slice_index) || (slice_len > 255),
&check_timeout,
)?;
}
Self::master_continue(
slice_len.min(255),
(idx != last_slice_index) || (slice_len > 255),
&check_timeout,
)?;
}
for (number, chunk) in slice.chunks(255).enumerate() {
if number != 0 {
// NOTE(unsafe) We have &mut self
unsafe {
Self::master_continue(
chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index),
&check_timeout,
)?;
}
Self::master_continue(
chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index),
&check_timeout,
)?;
}
for byte in chunk {
@ -810,9 +750,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Put byte on the wire
//self.i2c.txdr.write(|w| w.txdata().bits(*byte));
unsafe {
T::regs().txdr().write(|w| w.set_txdata(*byte));
}
T::regs().txdr().write(|w| w.set_txdata(*byte));
}
}
}
@ -1061,14 +999,12 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
type Config = Hertz;
fn set_config(&mut self, config: &Self::Config) {
let timings = Timings::new(T::frequency(), *config);
unsafe {
T::regs().timingr().write(|reg| {
reg.set_presc(timings.prescale);
reg.set_scll(timings.scll);
reg.set_sclh(timings.sclh);
reg.set_sdadel(timings.sdadel);
reg.set_scldel(timings.scldel);
});
}
T::regs().timingr().write(|reg| {
reg.set_presc(timings.prescale);
reg.set_scll(timings.scll);
reg.set_sclh(timings.sclh);
reg.set_sdadel(timings.sdadel);
reg.set_scldel(timings.scldel);
});
}
}

View File

@ -153,19 +153,17 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
) -> Self {
into_ref!(sd, ws, ck, mck);
unsafe {
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
sd.set_speed(crate::gpio::Speed::VeryHigh);
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
sd.set_speed(crate::gpio::Speed::VeryHigh);
ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
ws.set_speed(crate::gpio::Speed::VeryHigh);
ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
ws.set_speed(crate::gpio::Speed::VeryHigh);
ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
ck.set_speed(crate::gpio::Speed::VeryHigh);
ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
ck.set_speed(crate::gpio::Speed::VeryHigh);
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
mck.set_speed(crate::gpio::Speed::VeryHigh);
}
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
mck.set_speed(crate::gpio::Speed::VeryHigh);
let spi = Spi::new_internal(peri, txdma, rxdma, freq, SpiConfig::default());
@ -178,7 +176,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
#[cfg(any(spi_v1, spi_f1))]
unsafe {
{
use stm32_metapac::spi::vals::{I2scfg, Odd};
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
@ -232,10 +230,6 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
w.set_i2se(true)
});
}
#[cfg(spi_v2)]
unsafe {}
#[cfg(any(spi_v3, spi_v4))]
unsafe {}
Self {
_peri: spi,
@ -264,12 +258,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
impl<'d, T: Instance, Tx, Rx> Drop for I2S<'d, T, Tx, Rx> {
fn drop(&mut self) {
unsafe {
self.sd.as_ref().map(|x| x.set_as_disconnected());
self.ws.as_ref().map(|x| x.set_as_disconnected());
self.ck.as_ref().map(|x| x.set_as_disconnected());
self.mck.as_ref().map(|x| x.set_as_disconnected());
}
self.sd.as_ref().map(|x| x.set_as_disconnected());
self.ws.as_ref().map(|x| x.set_as_disconnected());
self.ck.as_ref().map(|x| x.set_as_disconnected());
self.mck.as_ref().map(|x| x.set_as_disconnected());
}
}

337
embassy-stm32/src/ipcc.rs Normal file
View File

@ -0,0 +1,337 @@
use core::future::poll_fn;
use core::task::Poll;
use atomic_polyfill::{compiler_fence, Ordering};
use self::sealed::Instance;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::peripherals::IPCC;
use crate::rcc::sealed::RccPeripheral;
/// Interrupt handler.
pub struct ReceiveInterruptHandler {}
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for ReceiveInterruptHandler {
unsafe fn on_interrupt() {
let regs = IPCC::regs();
let channels = [
IpccChannel::Channel1,
IpccChannel::Channel2,
IpccChannel::Channel3,
IpccChannel::Channel4,
IpccChannel::Channel5,
IpccChannel::Channel6,
];
// Status register gives channel occupied status. For rx, use cpu1.
let sr = regs.cpu(1).sr().read();
regs.cpu(0).mr().modify(|w| {
for channel in channels {
if sr.chf(channel as usize) {
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
w.set_chom(channel as usize, true);
// There shouldn't be a race because the channel is masked only if the interrupt has fired
IPCC::state().rx_waker_for(channel).wake();
}
}
})
}
}
pub struct TransmitInterruptHandler {}
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
unsafe fn on_interrupt() {
let regs = IPCC::regs();
let channels = [
IpccChannel::Channel1,
IpccChannel::Channel2,
IpccChannel::Channel3,
IpccChannel::Channel4,
IpccChannel::Channel5,
IpccChannel::Channel6,
];
// Status register gives channel occupied status. For tx, use cpu0.
let sr = regs.cpu(0).sr().read();
regs.cpu(0).mr().modify(|w| {
for channel in channels {
if !sr.chf(channel as usize) {
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
w.set_chfm(channel as usize, true);
// There shouldn't be a race because the channel is masked only if the interrupt has fired
IPCC::state().tx_waker_for(channel).wake();
}
}
});
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Default)]
pub struct Config {
// TODO: add IPCC peripheral configuration, if any, here
// reserved for future use
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum IpccChannel {
Channel1 = 0,
Channel2 = 1,
Channel3 = 2,
Channel4 = 3,
Channel5 = 4,
Channel6 = 5,
}
pub struct Ipcc;
impl Ipcc {
pub fn enable(_config: Config) {
IPCC::enable();
IPCC::reset();
IPCC::set_cpu2(true);
_configure_pwr();
let regs = IPCC::regs();
regs.cpu(0).cr().modify(|w| {
w.set_rxoie(true);
w.set_txfie(true);
});
// enable interrupts
crate::interrupt::typelevel::IPCC_C1_RX::unpend();
crate::interrupt::typelevel::IPCC_C1_TX::unpend();
unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
}
/// Send data to an IPCC channel. The closure is called to write the data when appropriate.
pub async fn send(channel: IpccChannel, f: impl FnOnce()) {
let regs = IPCC::regs();
Self::flush(channel).await;
compiler_fence(Ordering::SeqCst);
f();
compiler_fence(Ordering::SeqCst);
trace!("ipcc: ch {}: send data", channel as u8);
regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true));
}
/// Wait for the tx channel to become clear
pub async fn flush(channel: IpccChannel) {
let regs = IPCC::regs();
// This is a race, but is nice for debugging
if regs.cpu(0).sr().read().chf(channel as usize) {
trace!("ipcc: ch {}: wait for tx free", channel as u8);
}
poll_fn(|cx| {
IPCC::state().tx_waker_for(channel).register(cx.waker());
// If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false));
compiler_fence(Ordering::SeqCst);
if !regs.cpu(0).sr().read().chf(channel as usize) {
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
/// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R {
let regs = IPCC::regs();
loop {
// This is a race, but is nice for debugging
if !regs.cpu(1).sr().read().chf(channel as usize) {
trace!("ipcc: ch {}: wait for rx occupied", channel as u8);
}
poll_fn(|cx| {
IPCC::state().rx_waker_for(channel).register(cx.waker());
// If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false));
compiler_fence(Ordering::SeqCst);
if regs.cpu(1).sr().read().chf(channel as usize) {
// If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true));
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
trace!("ipcc: ch {}: read data", channel as u8);
compiler_fence(Ordering::SeqCst);
match f() {
Some(ret) => return ret,
None => {}
}
trace!("ipcc: ch {}: clear rx", channel as u8);
compiler_fence(Ordering::SeqCst);
// If the channel is clear and the read function returns none, fetch more data
regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true));
}
}
}
impl sealed::Instance for crate::peripherals::IPCC {
fn regs() -> crate::pac::ipcc::Ipcc {
crate::pac::IPCC
}
fn set_cpu2(enabled: bool) {
crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled));
}
fn state() -> &'static self::sealed::State {
static STATE: self::sealed::State = self::sealed::State::new();
&STATE
}
}
pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker;
use super::*;
pub struct State {
rx_wakers: [AtomicWaker; 6],
tx_wakers: [AtomicWaker; 6],
}
impl State {
pub const fn new() -> Self {
const WAKER: AtomicWaker = AtomicWaker::new();
Self {
rx_wakers: [WAKER; 6],
tx_wakers: [WAKER; 6],
}
}
pub fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
match channel {
IpccChannel::Channel1 => &self.rx_wakers[0],
IpccChannel::Channel2 => &self.rx_wakers[1],
IpccChannel::Channel3 => &self.rx_wakers[2],
IpccChannel::Channel4 => &self.rx_wakers[3],
IpccChannel::Channel5 => &self.rx_wakers[4],
IpccChannel::Channel6 => &self.rx_wakers[5],
}
}
pub fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker {
match channel {
IpccChannel::Channel1 => &self.tx_wakers[0],
IpccChannel::Channel2 => &self.tx_wakers[1],
IpccChannel::Channel3 => &self.tx_wakers[2],
IpccChannel::Channel4 => &self.tx_wakers[3],
IpccChannel::Channel5 => &self.tx_wakers[4],
IpccChannel::Channel6 => &self.tx_wakers[5],
}
}
}
pub trait Instance: crate::rcc::RccPeripheral {
fn regs() -> crate::pac::ipcc::Ipcc;
fn set_cpu2(enabled: bool);
fn state() -> &'static State;
}
}
fn _configure_pwr() {
// TODO: move this to RCC
let pwr = crate::pac::PWR;
let rcc = crate::pac::RCC;
rcc.cfgr().modify(|w| w.set_stopwuck(true));
pwr.cr1().modify(|w| w.set_dbp(true));
pwr.cr1().modify(|w| w.set_dbp(true));
// configure LSE
rcc.bdcr().modify(|w| w.set_lseon(true));
// select system clock source = PLL
// set PLL coefficients
// m: 2,
// n: 12,
// r: 3,
// q: 4,
// p: 3,
let src_bits = 0b11;
let pllp = (3 - 1) & 0b11111;
let pllq = (4 - 1) & 0b111;
let pllr = (3 - 1) & 0b111;
let plln = 12 & 0b1111111;
let pllm = (2 - 1) & 0b111;
rcc.pllcfgr().modify(|w| {
w.set_pllsrc(src_bits);
w.set_pllm(pllm);
w.set_plln(plln);
w.set_pllr(pllr);
w.set_pllp(pllp);
w.set_pllpen(true);
w.set_pllq(pllq);
w.set_pllqen(true);
});
// enable PLL
rcc.cr().modify(|w| w.set_pllon(true));
rcc.cr().write(|w| w.set_hsion(false));
// while !rcc.cr().read().pllrdy() {}
// configure SYSCLK mux to use PLL clocl
rcc.cfgr().modify(|w| w.set_sw(0b11));
// configure CPU1 & CPU2 dividers
rcc.cfgr().modify(|w| w.set_hpre(0)); // not divided
rcc.extcfgr().modify(|w| {
w.set_c2hpre(0b1000); // div2
w.set_shdhpre(0); // not divided
});
// apply APB1 / APB2 values
rcc.cfgr().modify(|w| {
w.set_ppre1(0b000); // not divided
w.set_ppre2(0b000); // not divided
});
// TODO: required
// set RF wake-up clock = LSE
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
// set LPTIM1 & LPTIM2 clock source
rcc.ccipr().modify(|w| {
w.set_lptim1sel(0b00); // PCLK
w.set_lptim2sel(0b00); // PCLK
});
}

View File

@ -41,6 +41,8 @@ pub mod crc;
pub mod flash;
#[cfg(all(spi_v1, rcc_f4))]
pub mod i2s;
#[cfg(stm32wb)]
pub mod ipcc;
pub mod pwm;
#[cfg(quadspi)]
pub mod qspi;
@ -52,8 +54,6 @@ pub mod rtc;
pub mod sdmmc;
#[cfg(spi)]
pub mod spi;
#[cfg(stm32wb)]
pub mod tl_mbox;
#[cfg(usart)]
pub mod usart;
#[cfg(usb)]
@ -72,52 +72,47 @@ pub(crate) mod _generated {
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
}
pub mod interrupt {
//! Interrupt definitions and macros to bind them.
pub use cortex_m::interrupt::{CriticalSection, Mutex};
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
pub use crate::_generated::interrupt;
pub use crate::_generated::interrupt::*;
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
$vis struct $name;
/// Macro to bind interrupts to handlers.
///
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
/// prove at compile-time that the right interrupts have been bound.
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
#[macro_export]
macro_rules! bind_interrupts {
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
$vis struct $name;
$(
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn $irq() {
$(
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
)*
}
$(
#[allow(non_snake_case)]
#[no_mangle]
unsafe extern "C" fn $irq() {
$(
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
)*
}
$(
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
)*
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
)*
};
}
)*
};
}
// Reexports
pub use _generated::{peripherals, Peripherals};
pub use embassy_cortex_m::executor;
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")]
pub use stm32_metapac as pac;
#[cfg(not(feature = "unstable-pac"))]
pub(crate) use stm32_metapac as pac;
use crate::interrupt::Priority;
#[cfg(feature = "rt")]
pub use crate::pac::NVIC_PRIO_BITS;
#[non_exhaustive]
pub struct Config {
pub rcc: rcc::Config,
@ -151,35 +146,35 @@ impl Default for Config {
pub fn init(config: Config) -> Peripherals {
let p = Peripherals::take();
unsafe {
#[cfg(dbgmcu)]
if config.enable_debug_during_sleep {
crate::pac::DBGMCU.cr().modify(|cr| {
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
{
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
}
#[cfg(any(
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
))]
{
cr.set_dbg_sleep(true);
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
}
#[cfg(dbgmcu_h7)]
{
cr.set_d1dbgcken(true);
cr.set_d3dbgcken(true);
cr.set_dbgsleep_d1(true);
cr.set_dbgstby_d1(true);
cr.set_dbgstop_d1(true);
}
});
}
#[cfg(dbgmcu)]
if config.enable_debug_during_sleep {
crate::pac::DBGMCU.cr().modify(|cr| {
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
{
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
}
#[cfg(any(
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
))]
{
cr.set_dbg_sleep(true);
cr.set_dbg_stop(true);
cr.set_dbg_standby(true);
}
#[cfg(dbgmcu_h7)]
{
cr.set_d1dbgcken(true);
cr.set_d3dbgcken(true);
cr.set_dbgsleep_d1(true);
cr.set_dbgstby_d1(true);
cr.set_dbgstop_d1(true);
}
});
}
unsafe {
gpio::init();
dma::init(
#[cfg(bdma)]

View File

@ -21,7 +21,7 @@ macro_rules! complementary_channel_impl {
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
#[cfg(gpio_v2)]
@ -72,33 +72,27 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
this.inner.set_frequency(freq);
this.inner.start();
unsafe {
this.inner.enable_outputs(true);
this.inner.enable_outputs(true);
this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
}
this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
this
}
pub fn enable(&mut self, channel: Channel) {
unsafe {
self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true);
}
self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true);
}
pub fn disable(&mut self, channel: Channel) {
unsafe {
self.inner.enable_complementary_channel(channel, false);
self.inner.enable_channel(channel, false);
}
self.inner.enable_complementary_channel(channel, false);
self.inner.enable_channel(channel, false);
}
pub fn set_freq(&mut self, freq: Hertz) {
@ -106,22 +100,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
}
pub fn get_max_duty(&self) -> u16 {
unsafe { self.inner.get_max_compare_value() }
self.inner.get_max_compare_value()
}
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
assert!(duty < self.get_max_duty());
unsafe { self.inner.set_compare_value(channel, duty) }
self.inner.set_compare_value(channel, duty)
}
/// Set the dead time as a proportion of max_duty
pub fn set_dead_time(&mut self, value: u16) {
let (ckd, value) = compute_dead_time_value(value);
unsafe {
self.inner.set_dead_time_clock_division(ckd);
self.inner.set_dead_time_value(value);
}
self.inner.set_dead_time_clock_division(ckd);
self.inner.set_dead_time_value(value);
}
}

View File

@ -59,33 +59,33 @@ pub(crate) mod sealed {
pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance {
/// Global output enable. Does not do anything on non-advanced timers.
unsafe fn enable_outputs(&mut self, enable: bool);
fn enable_outputs(&mut self, enable: bool);
unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
fn enable_channel(&mut self, channel: Channel, enable: bool);
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16);
fn set_compare_value(&mut self, channel: Channel, value: u16);
unsafe fn get_max_compare_value(&self) -> u16;
fn get_max_compare_value(&self) -> u16;
}
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
unsafe fn set_dead_time_clock_division(&mut self, value: Ckd);
fn set_dead_time_clock_division(&mut self, value: Ckd);
unsafe fn set_dead_time_value(&mut self, value: u8);
fn set_dead_time_value(&mut self, value: u8);
unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
}
pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance {
unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
fn enable_channel(&mut self, channel: Channel, enable: bool);
unsafe fn set_compare_value(&mut self, channel: Channel, value: u32);
fn set_compare_value(&mut self, channel: Channel, value: u32);
unsafe fn get_max_compare_value(&self) -> u32;
fn get_max_compare_value(&self) -> u32;
}
}
@ -108,9 +108,9 @@ pub trait CaptureCompare32bitInstance:
macro_rules! impl_compare_capable_16bit {
($inst:ident) => {
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
unsafe fn enable_outputs(&mut self, _enable: bool) {}
fn enable_outputs(&mut self, _enable: bool) {}
unsafe fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) {
use crate::timer::sealed::GeneralPurpose16bitInstance;
let r = Self::regs_gp16();
let raw_channel: usize = channel.raw();
@ -118,19 +118,19 @@ macro_rules! impl_compare_capable_16bit {
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
}
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
fn enable_channel(&mut self, channel: Channel, enable: bool) {
use crate::timer::sealed::GeneralPurpose16bitInstance;
Self::regs_gp16()
.ccer()
.modify(|w| w.set_cce(channel.raw(), enable));
}
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) {
fn set_compare_value(&mut self, channel: Channel, value: u16) {
use crate::timer::sealed::GeneralPurpose16bitInstance;
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
}
unsafe fn get_max_compare_value(&self) -> u16 {
fn get_max_compare_value(&self) -> u16 {
use crate::timer::sealed::GeneralPurpose16bitInstance;
Self::regs_gp16().arr().read().arr()
}
@ -150,7 +150,7 @@ foreach_interrupt! {
($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
impl_compare_capable_16bit!($inst);
impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
unsafe fn set_output_compare_mode(
fn set_output_compare_mode(
&mut self,
channel: crate::pwm::Channel,
mode: OutputCompareMode,
@ -160,17 +160,17 @@ foreach_interrupt! {
Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
}
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
fn enable_channel(&mut self, channel: Channel, enable: bool) {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
}
unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) {
fn set_compare_value(&mut self, channel: Channel, value: u32) {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
}
unsafe fn get_max_compare_value(&self) -> u32 {
fn get_max_compare_value(&self) -> u32 {
use crate::timer::sealed::GeneralPurpose32bitInstance;
Self::regs_gp32().arr().read().arr() as u32
}
@ -185,13 +185,13 @@ foreach_interrupt! {
($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
unsafe fn enable_outputs(&mut self, enable: bool) {
fn enable_outputs(&mut self, enable: bool) {
use crate::timer::sealed::AdvancedControlInstance;
let r = Self::regs_advanced();
r.bdtr().modify(|w| w.set_moe(enable));
}
unsafe fn set_output_compare_mode(
fn set_output_compare_mode(
&mut self,
channel: crate::pwm::Channel,
mode: OutputCompareMode,
@ -203,21 +203,21 @@ foreach_interrupt! {
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
}
unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
fn enable_channel(&mut self, channel: Channel, enable: bool) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()
.ccer()
.modify(|w| w.set_cce(channel.raw(), enable));
}
unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) {
fn set_compare_value(&mut self, channel: Channel, value: u16) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()
.ccr(channel.raw())
.modify(|w| w.set_ccr(value));
}
unsafe fn get_max_compare_value(&self) -> u16 {
fn get_max_compare_value(&self) -> u16 {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced().arr().read().arr()
}
@ -228,17 +228,17 @@ foreach_interrupt! {
}
impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
unsafe fn set_dead_time_clock_division(&mut self, value: Ckd) {
fn set_dead_time_clock_division(&mut self, value: Ckd) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
}
unsafe fn set_dead_time_value(&mut self, value: u8) {
fn set_dead_time_value(&mut self, value: u8) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
}
unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
use crate::timer::sealed::AdvancedControlInstance;
Self::regs_advanced()
.ccer()

View File

@ -24,7 +24,7 @@ macro_rules! channel_impl {
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
pin.set_low();
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
#[cfg(gpio_v2)]
@ -71,31 +71,25 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
this.inner.set_frequency(freq);
this.inner.start();
unsafe {
this.inner.enable_outputs(true);
this.inner.enable_outputs(true);
this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
}
this.inner
.set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
this.inner
.set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
this
}
pub fn enable(&mut self, channel: Channel) {
unsafe {
self.inner.enable_channel(channel, true);
}
self.inner.enable_channel(channel, true);
}
pub fn disable(&mut self, channel: Channel) {
unsafe {
self.inner.enable_channel(channel, false);
}
self.inner.enable_channel(channel, false);
}
pub fn set_freq(&mut self, freq: Hertz) {
@ -103,11 +97,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
}
pub fn get_max_duty(&self) -> u16 {
unsafe { self.inner.get_max_compare_value() }
self.inner.get_max_compare_value()
}
pub fn set_duty(&mut self, channel: Channel, duty: u16) {
assert!(duty < self.get_max_duty());
unsafe { self.inner.set_compare_value(channel, duty) }
self.inner.set_compare_value(channel, duty)
}
}

View File

@ -96,20 +96,18 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
) -> Self {
into_ref!(peri, d0, d1, d2, d3, sck, nss);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
d3.set_speed(crate::gpio::Speed::VeryHigh);
}
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
d3.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner(
peri,
@ -138,21 +136,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
into_ref!(peri, dma);
T::enable();
unsafe {
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
while T::REGS.sr().read().busy() {}
while T::REGS.sr().read().busy() {}
T::REGS.cr().write(|w| {
w.set_prescaler(config.prescaler);
w.set_en(true);
});
T::REGS.dcr().write(|w| {
w.set_fsize(config.memory_size.into());
w.set_csht(config.cs_high_time.into());
w.set_ckmode(false);
});
}
T::REGS.cr().write(|w| {
w.set_prescaler(config.prescaler);
w.set_en(true);
});
T::REGS.dcr().write(|w| {
w.set_fsize(config.memory_size.into());
w.set_csht(config.cs_high_time.into());
w.set_ckmode(false);
});
Self {
_peri: peri,
@ -168,148 +164,140 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
}
pub fn command(&mut self, transaction: TransferConfig) {
unsafe {
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
unsafe {
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len {
let current_ar = T::REGS.ar().read().address();
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into());
});
T::REGS.ar().write(|v| {
v.set_address(current_ar);
});
if let Some(len) = transaction.data_len {
let current_ar = T::REGS.ar().read().address();
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into());
});
T::REGS.ar().write(|v| {
v.set_address(current_ar);
});
for idx in 0..len {
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
buf[idx] = *(T::REGS.dr().ptr() as *mut u8);
}
for idx in 0..len {
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
}
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
unsafe {
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len {
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into());
});
if let Some(len) = transaction.data_len {
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into());
});
for idx in 0..len {
while !T::REGS.sr().read().ftf() {}
*(T::REGS.dr().ptr() as *mut u8) = buf[idx];
}
for idx in 0..len {
while !T::REGS.sr().read().ftf() {}
unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
}
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true));
}
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
where
Dma: QuadDma<T>,
{
unsafe {
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into());
});
let current_ar = T::REGS.ar().read().address();
T::REGS.ar().write(|v| {
v.set_address(current_ar);
});
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into());
});
let current_ar = T::REGS.ar().read().address();
T::REGS.ar().write(|v| {
v.set_address(current_ar);
});
let request = self.dma.request();
let transfer = Transfer::new_read(
let request = self.dma.request();
let transfer = unsafe {
Transfer::new_read(
&mut self.dma,
request,
T::REGS.dr().ptr() as *mut u8,
T::REGS.dr().as_ptr() as *mut u8,
buf,
Default::default(),
);
)
};
T::REGS.cr().modify(|v| v.set_dmaen(true));
T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait();
}
transfer.blocking_wait();
}
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
where
Dma: QuadDma<T>,
{
unsafe {
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into());
});
T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into());
});
let request = self.dma.request();
let transfer = Transfer::new_write(
let request = self.dma.request();
let transfer = unsafe {
Transfer::new_write(
&mut self.dma,
request,
buf,
T::REGS.dr().ptr() as *mut u8,
T::REGS.dr().as_ptr() as *mut u8,
Default::default(),
);
)
};
T::REGS.cr().modify(|v| v.set_dmaen(true));
T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait();
}
transfer.blocking_wait();
}
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
unsafe {
T::REGS.fcr().modify(|v| {
v.set_csmf(true);
v.set_ctcf(true);
v.set_ctef(true);
v.set_ctof(true);
T::REGS.fcr().modify(|v| {
v.set_csmf(true);
v.set_ctcf(true);
v.set_ctef(true);
v.set_ctof(true);
});
while T::REGS.sr().read().busy() {}
if let Some(len) = transaction.data_len {
T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
}
T::REGS.ccr().write(|v| {
v.set_fmode(fmode.into());
v.set_imode(transaction.iwidth.into());
v.set_instruction(transaction.instruction);
v.set_admode(transaction.awidth.into());
v.set_adsize(self.config.address_size.into());
v.set_dmode(transaction.dwidth.into());
v.set_abmode(QspiWidth::NONE.into());
v.set_dcyc(transaction.dummy.into());
});
if let Some(addr) = transaction.address {
T::REGS.ar().write(|v| {
v.set_address(addr);
});
while T::REGS.sr().read().busy() {}
if let Some(len) = transaction.data_len {
T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
}
T::REGS.ccr().write(|v| {
v.set_fmode(fmode.into());
v.set_imode(transaction.iwidth.into());
v.set_instruction(transaction.instruction);
v.set_admode(transaction.awidth.into());
v.set_adsize(self.config.address_size.into());
v.set_dmode(transaction.dwidth.into());
v.set_abmode(QspiWidth::NONE.into());
v.set_dcyc(transaction.dummy.into());
});
if let Some(addr) = transaction.address {
T::REGS.ar().write(|v| {
v.set_address(addr);
});
}
}
}
}

View File

@ -36,18 +36,18 @@ pub struct Config {
}
#[cfg(stm32f410)]
unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
None
}
// Not currently implemented, but will be in the future
#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
unsafe fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
None
}
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
let min_div = 2;
let max_div = 7;
let target = match plli2s {
@ -82,13 +82,7 @@ unsafe fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
Some(output)
}
unsafe fn setup_pll(
pllsrcclk: u32,
use_hse: bool,
pllsysclk: Option<u32>,
plli2s: Option<u32>,
pll48clk: bool,
) -> PllResults {
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
@ -320,7 +314,7 @@ impl<'d, T: McoInstance> Mco<'d, T> {
}
}
unsafe fn flash_setup(sysclk: u32) {
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges

View File

@ -25,7 +25,7 @@ pub struct Config {
pub pll48: bool,
}
unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
@ -97,7 +97,7 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
}
}
unsafe fn flash_setup(sysclk: u32) {
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges

View File

@ -245,7 +245,7 @@ impl Default for Config {
}
impl PllConfig {
pub(crate) unsafe fn init(self) -> u32 {
pub(crate) fn init(self) -> u32 {
assert!(self.n >= 8 && self.n <= 86);
let (src, input_freq) = match self.source {
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),

View File

@ -1,4 +1,6 @@
use stm32_metapac::rcc::vals::{Hpre, Ppre, Sw};
use stm32_metapac::flash::vals::Latency;
use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::FLASH;
use crate::pac::{PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
@ -15,6 +17,7 @@ pub const LSI_FREQ: Hertz = Hertz(32_000);
pub enum ClockSrc {
HSE(Hertz),
HSI16,
PLL,
}
/// AHB prescaler
@ -41,6 +44,222 @@ pub enum APBPrescaler {
Div16,
}
/// PLL clock input source
#[derive(Clone, Copy, Debug)]
pub enum PllSrc {
HSI16,
HSE(Hertz),
}
impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc {
match self {
PllSrc::HSE(..) => Pllsrc::HSE,
PllSrc::HSI16 => Pllsrc::HSI16,
}
}
}
seq_macro::seq!(P in 2..=31 {
/// Output divider for the PLL P output.
#[derive(Clone, Copy)]
pub enum PllP {
// Note: If PLL P is set to 0 the PLLP bit controls the output division. There does not seem to
// a good reason to do this so the API does not support it.
// Div1 is invalid
#(
Div~P,
)*
}
impl From<PllP> for u8 {
/// Returns the register value for the P output divider.
fn from(val: PllP) -> u8 {
match val {
#(
PllP::Div~P => P,
)*
}
}
}
});
impl PllP {
/// Returns the numeric value of the P output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32
}
}
/// Output divider for the PLL Q output.
#[derive(Clone, Copy)]
pub enum PllQ {
Div2,
Div4,
Div6,
Div8,
}
impl PllQ {
/// Returns the numeric value of the Q output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PllQ> for u8 {
/// Returns the register value for the Q output divider.
fn from(val: PllQ) -> u8 {
match val {
PllQ::Div2 => 0b00,
PllQ::Div4 => 0b01,
PllQ::Div6 => 0b10,
PllQ::Div8 => 0b11,
}
}
}
/// Output divider for the PLL R output.
#[derive(Clone, Copy)]
pub enum PllR {
Div2,
Div4,
Div6,
Div8,
}
impl PllR {
/// Returns the numeric value of the R output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PllR> for u8 {
/// Returns the register value for the R output divider.
fn from(val: PllR) -> u8 {
match val {
PllR::Div2 => 0b00,
PllR::Div4 => 0b01,
PllR::Div6 => 0b10,
PllR::Div8 => 0b11,
}
}
}
seq_macro::seq!(N in 8..=127 {
/// Multiplication factor for the PLL VCO input clock.
#[derive(Clone, Copy)]
pub enum PllN {
#(
Mul~N,
)*
}
impl From<PllN> for u8 {
/// Returns the register value for the N multiplication factor.
fn from(val: PllN) -> u8 {
match val {
#(
PllN::Mul~N => N,
)*
}
}
}
impl PllN {
/// Returns the numeric value of the N multiplication factor.
pub fn to_mul(self) -> u32 {
match self {
#(
PllN::Mul~N => N,
)*
}
}
}
});
/// PLL Pre-division. This must be set such that the PLL input is between 2.66 MHz and 16 MHz.
#[derive(Copy, Clone)]
pub enum PllM {
Div1,
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
Div9,
Div10,
Div11,
Div12,
Div13,
Div14,
Div15,
Div16,
}
impl PllM {
/// Returns the numeric value of the M pre-division.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32 + 1
}
}
impl From<PllM> for u8 {
/// Returns the register value for the M pre-division.
fn from(val: PllM) -> u8 {
match val {
PllM::Div1 => 0b0000,
PllM::Div2 => 0b0001,
PllM::Div3 => 0b0010,
PllM::Div4 => 0b0011,
PllM::Div5 => 0b0100,
PllM::Div6 => 0b0101,
PllM::Div7 => 0b0110,
PllM::Div8 => 0b0111,
PllM::Div9 => 0b1000,
PllM::Div10 => 0b1001,
PllM::Div11 => 0b1010,
PllM::Div12 => 0b1011,
PllM::Div13 => 0b1100,
PllM::Div14 => 0b1101,
PllM::Div15 => 0b1110,
PllM::Div16 => 0b1111,
}
}
}
/// PLL Configuration
///
/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
/// frequency ranges for each of these settings.
pub struct Pll {
/// PLL Source clock selection.
pub source: PllSrc,
/// PLL pre-divider
pub prediv_m: PllM,
/// PLL multiplication factor for VCO
pub mul_n: PllN,
/// PLL division factor for P clock (ADC Clock)
pub div_p: Option<PllP>,
/// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
pub div_q: Option<PllQ>,
/// PLL division factor for R clock (SYSCLK)
pub div_r: Option<PllR>,
}
impl AHBPrescaler {
const fn div(self) -> u32 {
match self {
@ -104,6 +323,9 @@ pub struct Config {
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub low_power_run: bool,
/// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
/// MUST turn on the PLLR output.
pub pll: Option<Pll>,
}
impl Default for Config {
@ -115,11 +337,80 @@ impl Default for Config {
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
low_power_run: false,
pll: None,
}
}
}
pub struct PllFreq {
pub pll_p: Option<Hertz>,
pub pll_q: Option<Hertz>,
pub pll_r: Option<Hertz>,
}
pub(crate) unsafe fn init(config: Config) {
let pll_freq = config.pll.map(|pll_config| {
let src_freq = match pll_config.source {
PllSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0
}
PllSrc::HSE(freq) => {
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
};
// Disable PLL before configuration
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul();
RCC.pllcfgr().write(|w| {
w.set_plln(pll_config.mul_n.into());
w.set_pllm(pll_config.prediv_m.into());
w.set_pllsrc(pll_config.source.into());
});
let pll_p_freq = pll_config.div_p.map(|div_p| {
RCC.pllcfgr().modify(|w| {
w.set_pllpdiv(div_p.into());
w.set_pllpen(true);
});
Hertz(internal_freq / div_p.to_div())
});
let pll_q_freq = pll_config.div_q.map(|div_q| {
RCC.pllcfgr().modify(|w| {
w.set_pllq(div_q.into());
w.set_pllqen(true);
});
Hertz(internal_freq / div_q.to_div())
});
let pll_r_freq = pll_config.div_r.map(|div_r| {
RCC.pllcfgr().modify(|w| {
w.set_pllr(div_r.into());
w.set_pllren(true);
});
Hertz(internal_freq / div_r.to_div())
});
// Enable the PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
PllFreq {
pll_p: pll_p_freq,
pll_q: pll_q_freq,
pll_r: pll_r_freq,
}
});
let (sys_clk, sw) = match config.mux {
ClockSrc::HSI16 => {
// Enable HSI16
@ -135,6 +426,47 @@ pub(crate) unsafe fn init(config: Config) {
(freq.0, Sw::HSE)
}
ClockSrc::PLL => {
assert!(pll_freq.is_some());
assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
let freq = pll_freq.unwrap().pll_r.unwrap().0;
assert!(freq <= 170_000_000);
if freq >= 150_000_000 {
// Enable Core Boost mode on freq >= 150Mhz ([RM0440] p234)
PWR.cr5().modify(|w| w.set_r1mode(false));
// Set flash wait state in boost mode based on frequency ([RM0440] p191)
if freq <= 36_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
} else if freq <= 68_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
} else if freq <= 102_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
} else if freq <= 136_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
} else {
FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
}
} else {
PWR.cr5().modify(|w| w.set_r1mode(true));
// Set flash wait state in normal mode based on frequency ([RM0440] p191)
if freq <= 30_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS0));
} else if freq <= 60_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS1));
} else if freq <= 80_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS2));
} else if freq <= 120_000_000 {
FLASH.acr().modify(|w| w.set_latency(Latency::WS3));
} else {
FLASH.acr().modify(|w| w.set_latency(Latency::WS4));
}
}
(freq, Sw::PLLRCLK)
}
};
RCC.cfgr().modify(|w| {

View File

@ -462,7 +462,7 @@ struct PllOutput {
r: Option<Hertz>,
}
unsafe fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let Some(config) = config else {
// Stop PLL
RCC.cr().modify(|w| w.set_pllon(num, false));
@ -595,12 +595,9 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
// NOTE(unsafe) Atomic write
unsafe {
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}

View File

@ -253,14 +253,11 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
},
};
// NOTE(unsafe) Atomic write
unsafe {
FLASH.acr().write(|w| {
w.set_wrhighfreq(progr_delay);
w.set_latency(wait_states)
});
while FLASH.acr().read().latency() != wait_states {}
}
FLASH.acr().write(|w| {
w.set_wrhighfreq(progr_delay);
w.set_latency(wait_states)
});
while FLASH.acr().read().latency() != wait_states {}
}
pub enum McoClock {
@ -474,7 +471,6 @@ pub(crate) unsafe fn init(mut config: Config) {
// Configure traceclk from PLL if needed
traceclk_setup(&mut config, sys_use_pll1_p);
// NOTE(unsafe) We have exclusive access to the RCC
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
@ -756,7 +752,7 @@ mod pll {
/// # Safety
///
/// Must have exclusive access to the RCC register block
unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
@ -785,11 +781,7 @@ mod pll {
/// # Safety
///
/// Must have exclusive access to the RCC register block
pub(super) unsafe fn pll_setup(
pll_src: u32,
config: &PllConfig,
plln: usize,
) -> (Option<u32>, Option<u32>, Option<u32>) {
pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
use crate::pac::rcc::vals::Divp;
match config.p_ck {

View File

@ -34,40 +34,34 @@ 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() } {
if T::regs().sr().read().seis() {
T::reset();
}
unsafe {
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
reg.set_ie(true);
});
T::regs().sr().modify(|reg| {
reg.set_seis(false);
reg.set_ceis(false);
});
}
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
reg.set_ie(true);
});
T::regs().sr().modify(|reg| {
reg.set_seis(false);
reg.set_ceis(false);
});
// Reference manual says to discard the first.
let _ = self.next_u32();
}
pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
unsafe {
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
})
}
T::regs().cr().modify(|reg| {
reg.set_rngen(true);
});
for chunk in dest.chunks_mut(4) {
poll_fn(|cx| {
RNG_WAKER.register(cx.waker());
unsafe {
T::regs().cr().modify(|reg| {
reg.set_ie(true);
});
}
T::regs().cr().modify(|reg| {
reg.set_ie(true);
});
let bits = unsafe { T::regs().sr().read() };
let bits = T::regs().sr().read();
if bits.drdy() {
Poll::Ready(Ok(()))
@ -82,7 +76,7 @@ impl<'d, T: Instance> Rng<'d, T> {
}
})
.await?;
let random_bytes = unsafe { T::regs().dr().read() }.to_be_bytes();
let random_bytes = T::regs().dr().read().to_be_bytes();
for (dest, src) in chunk.iter_mut().zip(random_bytes.iter()) {
*dest = *src
}
@ -95,11 +89,11 @@ impl<'d, T: Instance> Rng<'d, T> {
impl<'d, T: Instance> RngCore for Rng<'d, T> {
fn next_u32(&mut self) -> u32 {
loop {
let sr = unsafe { T::regs().sr().read() };
let sr = T::regs().sr().read();
if sr.seis() | sr.ceis() {
self.reset();
} else if sr.drdy() {
return unsafe { T::regs().dr().read() };
return T::regs().dr().read();
}
}
}
@ -149,6 +143,7 @@ foreach_peripheral!(
};
);
#[cfg(feature = "rt")]
macro_rules! irq {
($irq:ident) => {
mod rng_irq {
@ -166,6 +161,7 @@ macro_rules! irq {
};
}
#[cfg(feature = "rt")]
foreach_interrupt!(
(RNG) => {
irq!(RNG);

View File

@ -154,29 +154,27 @@ pub(super) fn write_date_time(rtc: &Rtc, t: DateTime) {
let yr_offset = (yr - 1970_u16) as u8;
let (yt, yu) = byte_to_bcd2(yr_offset);
unsafe {
use crate::pac::rtc::vals::Ampm;
use crate::pac::rtc::vals::Ampm;
rtc.tr().write(|w| {
w.set_ht(ht);
w.set_hu(hu);
w.set_mnt(mnt);
w.set_mnu(mnu);
w.set_st(st);
w.set_su(su);
w.set_pm(Ampm::AM);
});
rtc.tr().write(|w| {
w.set_ht(ht);
w.set_hu(hu);
w.set_mnt(mnt);
w.set_mnu(mnu);
w.set_st(st);
w.set_su(su);
w.set_pm(Ampm::AM);
});
rtc.dr().write(|w| {
w.set_dt(dt);
w.set_du(du);
w.set_mt(mt > 0);
w.set_mu(mu);
w.set_yt(yt);
w.set_yu(yu);
w.set_wdu(day_of_week_to_u8(t.day_of_week));
});
}
rtc.dr().write(|w| {
w.set_dt(dt);
w.set_du(du);
w.set_mt(mt > 0);
w.set_mu(mu);
w.set_yt(yt);
w.set_yu(yu);
w.set_wdu(day_of_week_to_u8(t.day_of_week));
});
}
pub(super) fn datetime(

View File

@ -113,7 +113,7 @@ impl Default for RtcCalibrationCyclePeriod {
impl<'d, T: Instance> Rtc<'d, T> {
pub fn new(_rtc: impl Peripheral<P = T> + 'd, rtc_config: RtcConfig) -> Self {
unsafe { T::enable_peripheral_clk() };
T::enable_peripheral_clk();
let mut rtc_struct = Self {
phantom: PhantomData,
@ -144,34 +144,32 @@ impl<'d, T: Instance> Rtc<'d, T> {
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
pub fn now(&self) -> Result<DateTime, RtcError> {
let r = T::regs();
unsafe {
let tr = r.tr().read();
let second = bcd2_to_byte((tr.st(), tr.su()));
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order
// calendar shadow registers until RTC_DR is read.
let dr = r.dr().read();
let tr = r.tr().read();
let second = bcd2_to_byte((tr.st(), tr.su()));
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order
// calendar shadow registers until RTC_DR is read.
let dr = r.dr().read();
let weekday = dr.wdu();
let day = bcd2_to_byte((dr.dt(), dr.du()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
let weekday = dr.wdu();
let day = bcd2_to_byte((dr.dt(), dr.du()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}
/// Check if daylight savings time is active.
pub fn get_daylight_savings(&self) -> bool {
let cr = unsafe { T::regs().cr().read() };
let cr = T::regs().cr().read();
cr.bkp()
}
/// Enable/disable daylight savings time.
pub fn set_daylight_savings(&mut self, daylight_savings: bool) {
self.write(true, |rtc| {
unsafe { rtc.cr().modify(|w| w.set_bkp(daylight_savings)) };
rtc.cr().modify(|w| w.set_bkp(daylight_savings));
})
}
@ -228,7 +226,7 @@ pub(crate) mod sealed {
crate::pac::RTC
}
unsafe fn enable_peripheral_clk() {}
fn enable_peripheral_clk() {}
/// Read content of the backup register.
///

View File

@ -8,74 +8,72 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
/// It this changes the RTC clock source the time will be reset
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
// Unlock the backup domain
unsafe {
let clock_config = rtc_config.clock_config as u8;
let clock_config = rtc_config.clock_config as u8;
#[cfg(not(rtc_v2wb))]
use stm32_metapac::rcc::vals::Rtcsel;
#[cfg(not(rtc_v2wb))]
use stm32_metapac::rcc::vals::Rtcsel;
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
let cr = crate::pac::PWR.cr1();
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
let cr = crate::pac::PWR.cr1();
// TODO: Missing from PAC for l0 and f0?
#[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
{
cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {}
}
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let reg = crate::pac::RCC.bdcr().read();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let reg = crate::pac::RCC.csr().read();
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(rtc_v2wb)]
let rtcsel = reg.rtcsel();
#[cfg(not(rtc_v2wb))]
let rtcsel = reg.rtcsel().0;
if !reg.rtcen() || rtcsel != clock_config {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
cr.modify(|w| {
// Reset
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
w.set_bdrst(false);
// Select RTC source
#[cfg(not(rtc_v2wb))]
w.set_rtcsel(Rtcsel(clock_config));
#[cfg(rtc_v2wb)]
w.set_rtcsel(clock_config);
w.set_rtcen(true);
// Restore bcdr
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscosel(reg.lscosel());
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
// TODO: Missing from PAC for l0 and f0?
#[cfg(not(any(rtc_v2f0, rtc_v2l0)))]
{
cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {}
}
self.write(true, |rtc| unsafe {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let reg = crate::pac::RCC.bdcr().read();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let reg = crate::pac::RCC.csr().read();
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb))]
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(rtc_v2wb)]
let rtcsel = reg.rtcsel();
#[cfg(not(rtc_v2wb))]
let rtcsel = reg.rtcsel().0;
if !reg.rtcen() || rtcsel != clock_config {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
cr.modify(|w| {
// Reset
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
w.set_bdrst(false);
// Select RTC source
#[cfg(not(rtc_v2wb))]
w.set_rtcsel(Rtcsel(clock_config));
#[cfg(rtc_v2wb)]
w.set_rtcsel(clock_config);
w.set_rtcen(true);
// Restore bcdr
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscosel(reg.lscosel());
#[cfg(any(rtc_v2l4, rtc_v2wb))]
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb))]
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
self.write(true, |rtc| {
rtc.cr().modify(|w| {
#[cfg(rtc_v2f2)]
w.set_fmt(false);
@ -117,47 +115,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM;
self.write(false, |rtc| {
unsafe {
rtc.calr().write(|w| {
match period {
super::RtcCalibrationCyclePeriod::Seconds8 => {
w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
}
super::RtcCalibrationCyclePeriod::Seconds16 => {
w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
}
super::RtcCalibrationCyclePeriod::Seconds32 => {
// Set neither `calw8` nor `calw16` to use 32 seconds
}
rtc.calr().write(|w| {
match period {
super::RtcCalibrationCyclePeriod::Seconds8 => {
w.set_calw8(stm32_metapac::rtc::vals::Calw8::EIGHT_SECOND);
}
// Extra pulses during calibration cycle period: CALP * 512 - CALM
//
// CALP sets whether pulses are added or omitted.
//
// CALM contains how many pulses (out of 512) are masked in a
// given calibration cycle period.
if clock_drift > 0.0 {
// Maximum (about 512.2) rounds to 512.
clock_drift += 0.5;
// When the offset is positive (0 to 512), the opposite of
// the offset (512 - offset) is masked, i.e. for the
// maximum offset (512), 0 pulses are masked.
w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
w.set_calm(512 - clock_drift as u16);
} else {
// Minimum (about -510.7) rounds to -511.
clock_drift -= 0.5;
// When the offset is negative or zero (-511 to 0),
// the absolute offset is masked, i.e. for the minimum
// offset (-511), 511 pulses are masked.
w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
w.set_calm((clock_drift * -1.0) as u16);
super::RtcCalibrationCyclePeriod::Seconds16 => {
w.set_calw16(stm32_metapac::rtc::vals::Calw16::SIXTEEN_SECOND);
}
});
}
super::RtcCalibrationCyclePeriod::Seconds32 => {
// Set neither `calw8` nor `calw16` to use 32 seconds
}
}
// Extra pulses during calibration cycle period: CALP * 512 - CALM
//
// CALP sets whether pulses are added or omitted.
//
// CALM contains how many pulses (out of 512) are masked in a
// given calibration cycle period.
if clock_drift > 0.0 {
// Maximum (about 512.2) rounds to 512.
clock_drift += 0.5;
// When the offset is positive (0 to 512), the opposite of
// the offset (512 - offset) is masked, i.e. for the
// maximum offset (512), 0 pulses are masked.
w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ);
w.set_calm(512 - clock_drift as u16);
} else {
// Minimum (about -510.7) rounds to -511.
clock_drift -= 0.5;
// When the offset is negative or zero (-511 to 0),
// the absolute offset is masked, i.e. for the minimum
// offset (-511), 511 pulses are masked.
w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE);
w.set_calm((clock_drift * -1.0) as u16);
}
});
})
}
@ -168,31 +164,27 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
let r = T::regs();
// Disable write protection.
// This is safe, as we're only writin the correct and expected values.
unsafe {
r.wpr().write(|w| w.set_key(0xca));
r.wpr().write(|w| w.set_key(0x53));
r.wpr().write(|w| w.set_key(0xca));
r.wpr().write(|w| w.set_key(0x53));
// true if initf bit indicates RTC peripheral is in init mode
if init_mode && !r.isr().read().initf() {
// to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
r.isr().modify(|w| w.set_init(Init::INITMODE));
// wait till init state entered
// ~2 RTCCLK cycles
while !r.isr().read().initf() {}
}
// true if initf bit indicates RTC peripheral is in init mode
if init_mode && !r.isr().read().initf() {
// to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
r.isr().modify(|w| w.set_init(Init::INITMODE));
// wait till init state entered
// ~2 RTCCLK cycles
while !r.isr().read().initf() {}
}
let result = f(&r);
unsafe {
if init_mode {
r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
}
// Re-enable write protection.
// This is safe, as the field accepts the full range of 8-bit values.
r.wpr().write(|w| w.set_key(0xff));
if init_mode {
r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
}
// Re-enable write protection.
// This is safe, as the field accepts the full range of 8-bit values.
r.wpr().write(|w| w.set_key(0xff));
result
}
}
@ -200,7 +192,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
impl sealed::Instance for crate::peripherals::RTC {
const BACKUP_REGISTER_COUNT: usize = 20;
unsafe fn enable_peripheral_clk() {
fn enable_peripheral_clk() {
#[cfg(any(rtc_v2l4, rtc_v2wb))]
{
// enable peripheral clock for communication
@ -213,7 +205,7 @@ impl sealed::Instance for crate::peripherals::RTC {
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
if register < Self::BACKUP_REGISTER_COUNT {
Some(unsafe { rtc.bkpr(register).read().bkp() })
Some(rtc.bkpr(register).read().bkp())
} else {
None
}
@ -221,7 +213,7 @@ impl sealed::Instance for crate::peripherals::RTC {
fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
if register < Self::BACKUP_REGISTER_COUNT {
unsafe { rtc.bkpr(register).write(|w| w.set_bkp(value)) }
rtc.bkpr(register).write(|w| w.set_bkp(value));
}
}
}

View File

@ -8,75 +8,66 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
/// It this changes the RTC clock source the time will be reset
pub(super) fn apply_config(&mut self, rtc_config: RtcConfig) {
// Unlock the backup domain
unsafe {
#[cfg(any(rtc_v3u5, rcc_g0, rcc_g4))]
use crate::pac::rcc::vals::Rtcsel;
#[cfg(not(any(rtc_v3u5, rcc_g0, rcc_g4, rcc_wl5, rcc_wle)))]
use crate::pac::rtc::vals::Rtcsel;
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
{
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
while !crate::pac::PWR.cr1().read().dbp() {}
}
#[cfg(any(rcc_wl5, rcc_wle))]
{
use crate::pac::pwr::vals::Dbp;
#[cfg(not(any(rtc_v3u5, rcc_wl5, rcc_wle)))]
{
crate::pac::PWR.cr1().modify(|w| w.set_dbp(true));
while !crate::pac::PWR.cr1().read().dbp() {}
}
#[cfg(any(rcc_wl5, rcc_wle))]
{
use crate::pac::pwr::vals::Dbp;
crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
}
crate::pac::PWR.cr1().modify(|w| w.set_dbp(Dbp::ENABLED));
while crate::pac::PWR.cr1().read().dbp() != Dbp::ENABLED {}
}
let reg = crate::pac::RCC.bdcr().read();
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
let reg = crate::pac::RCC.bdcr().read();
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
let config_rtcsel = rtc_config.clock_config as u8;
#[cfg(not(any(rcc_wl5, rcc_wle)))]
let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel);
let config_rtcsel = rtc_config.clock_config as u8;
#[cfg(not(any(rcc_wl5, rcc_wle)))]
let config_rtcsel = Rtcsel(config_rtcsel);
if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
crate::pac::RCC.bdcr().modify(|w| {
// Reset
w.set_bdrst(false);
crate::pac::RCC.bdcr().modify(|w| {
// Reset
w.set_bdrst(false);
// Select RTC source
w.set_rtcsel(config_rtcsel);
// Select RTC source
w.set_rtcsel(config_rtcsel);
w.set_rtcen(true);
w.set_rtcen(true);
// Restore bcdr
w.set_lscosel(reg.lscosel());
w.set_lscoen(reg.lscoen());
// Restore bcdr
w.set_lscosel(reg.lscosel());
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
w.set_lseon(reg.lseon());
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
self.write(true, |rtc| {
unsafe {
rtc.cr().modify(|w| {
w.set_fmt(Fmt::TWENTYFOURHOUR);
w.set_osel(Osel::DISABLED);
w.set_pol(Pol::HIGH);
});
rtc.cr().modify(|w| {
w.set_fmt(Fmt::TWENTYFOURHOUR);
w.set_osel(Osel::DISABLED);
w.set_pol(Pol::HIGH);
});
rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler);
w.set_prediv_a(rtc_config.async_prescaler);
});
rtc.prer().modify(|w| {
w.set_prediv_s(rtc_config.sync_prescaler);
w.set_prediv_a(rtc_config.async_prescaler);
});
// TODO: configuration for output pins
rtc.cr().modify(|w| {
w.set_out2en(false);
w.set_tampalrm_type(TampalrmType::PUSHPULL);
w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
});
}
// TODO: configuration for output pins
rtc.cr().modify(|w| {
w.set_out2en(false);
w.set_tampalrm_type(TampalrmType::PUSHPULL);
w.set_tampalrm_pu(TampalrmPu::NOPULLUP);
});
});
self.rtc_config = rtc_config;
@ -104,47 +95,45 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
clock_drift = clock_drift / Self::RTC_CALR_RESOLUTION_PPM;
self.write(false, |rtc| {
unsafe {
rtc.calr().write(|w| {
match period {
RtcCalibrationCyclePeriod::Seconds8 => {
w.set_calw8(Calw8::EIGHTSECONDS);
}
RtcCalibrationCyclePeriod::Seconds16 => {
w.set_calw16(Calw16::SIXTEENSECONDS);
}
RtcCalibrationCyclePeriod::Seconds32 => {
// Set neither `calw8` nor `calw16` to use 32 seconds
}
rtc.calr().write(|w| {
match period {
RtcCalibrationCyclePeriod::Seconds8 => {
w.set_calw8(Calw8::EIGHTSECONDS);
}
// Extra pulses during calibration cycle period: CALP * 512 - CALM
//
// CALP sets whether pulses are added or omitted.
//
// CALM contains how many pulses (out of 512) are masked in a
// given calibration cycle period.
if clock_drift > 0.0 {
// Maximum (about 512.2) rounds to 512.
clock_drift += 0.5;
// When the offset is positive (0 to 512), the opposite of
// the offset (512 - offset) is masked, i.e. for the
// maximum offset (512), 0 pulses are masked.
w.set_calp(Calp::INCREASEFREQ);
w.set_calm(512 - clock_drift as u16);
} else {
// Minimum (about -510.7) rounds to -511.
clock_drift -= 0.5;
// When the offset is negative or zero (-511 to 0),
// the absolute offset is masked, i.e. for the minimum
// offset (-511), 511 pulses are masked.
w.set_calp(Calp::NOCHANGE);
w.set_calm((clock_drift * -1.0) as u16);
RtcCalibrationCyclePeriod::Seconds16 => {
w.set_calw16(Calw16::SIXTEENSECONDS);
}
});
}
RtcCalibrationCyclePeriod::Seconds32 => {
// Set neither `calw8` nor `calw16` to use 32 seconds
}
}
// Extra pulses during calibration cycle period: CALP * 512 - CALM
//
// CALP sets whether pulses are added or omitted.
//
// CALM contains how many pulses (out of 512) are masked in a
// given calibration cycle period.
if clock_drift > 0.0 {
// Maximum (about 512.2) rounds to 512.
clock_drift += 0.5;
// When the offset is positive (0 to 512), the opposite of
// the offset (512 - offset) is masked, i.e. for the
// maximum offset (512), 0 pulses are masked.
w.set_calp(Calp::INCREASEFREQ);
w.set_calm(512 - clock_drift as u16);
} else {
// Minimum (about -510.7) rounds to -511.
clock_drift -= 0.5;
// When the offset is negative or zero (-511 to 0),
// the absolute offset is masked, i.e. for the minimum
// offset (-511), 511 pulses are masked.
w.set_calp(Calp::NOCHANGE);
w.set_calm((clock_drift * -1.0) as u16);
}
});
})
}
@ -155,29 +144,26 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
let r = T::regs();
// Disable write protection.
// This is safe, as we're only writin the correct and expected values.
unsafe {
r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
r.wpr().write(|w| w.set_key(Key::DEACTIVATE1));
r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
if init_mode && !r.icsr().read().initf() {
r.icsr().modify(|w| w.set_init(Init::INITMODE));
// wait till init state entered
// ~2 RTCCLK cycles
while !r.icsr().read().initf() {}
}
if init_mode && !r.icsr().read().initf() {
r.icsr().modify(|w| w.set_init(Init::INITMODE));
// wait till init state entered
// ~2 RTCCLK cycles
while !r.icsr().read().initf() {}
}
let result = f(&r);
unsafe {
if init_mode {
r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
}
// Re-enable write protection.
// This is safe, as the field accepts the full range of 8-bit values.
r.wpr().write(|w| w.set_key(Key::ACTIVATE));
if init_mode {
r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode
}
// Re-enable write protection.
// This is safe, as the field accepts the full range of 8-bit values.
r.wpr().write(|w| w.set_key(Key::ACTIVATE));
result
}
}
@ -197,7 +183,7 @@ impl sealed::Instance for crate::peripherals::RTC {
fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
if register < Self::BACKUP_REGISTER_COUNT {
// RTC3 backup registers come from the TAMP peripe=heral, not RTC. Not() even in the L412 PAC
//unsafe { self.rtc.bkpr()[register].write(|w| w.bits(value)) }
//self.rtc.bkpr()[register].write(|w| w.bits(value))
}
}
}

View File

@ -14,7 +14,7 @@ use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID,
use crate::dma::NoDma;
use crate::gpio::sealed::{AFType, Pin};
use crate::gpio::{AnyPin, Pull, Speed};
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::pac::sdmmc::Sdmmc as RegBlock;
use crate::rcc::RccPeripheral;
use crate::time::Hertz;
@ -28,21 +28,18 @@ pub struct InterruptHandler<T: Instance> {
impl<T: Instance> InterruptHandler<T> {
fn data_interrupts(enable: bool) {
let regs = T::regs();
// NOTE(unsafe) Atomic write
unsafe {
regs.maskr().write(|w| {
w.set_dcrcfailie(enable);
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
regs.maskr().write(|w| {
w.set_dcrcfailie(enable);
w.set_dtimeoutie(enable);
w.set_dataendie(enable);
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
});
}
#[cfg(sdmmc_v2)]
w.set_dabortie(enable);
});
}
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
Self::data_interrupts(false);
T::state().wake();
@ -276,7 +273,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
pub fn new_1bit(
sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
clk: impl Peripheral<P = impl CkPin<T>> + 'd,
cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
) -> Self {
into_ref!(clk, cmd, d0);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -310,7 +307,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
pub fn new_4bit(
sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
clk: impl Peripheral<P = impl CkPin<T>> + 'd,
cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
) -> Self {
into_ref!(clk, cmd, d0, d1, d2, d3);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -356,7 +353,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
pub fn new_1bit(
sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
clk: impl Peripheral<P = impl CkPin<T>> + 'd,
cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
) -> Self {
into_ref!(clk, cmd, d0);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -389,7 +386,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
pub fn new_4bit(
sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
clk: impl Peripheral<P = impl CkPin<T>> + 'd,
cmd: impl Peripheral<P = impl CmdPin<T>> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
) -> Self {
into_ref!(clk, cmd, d0, d1, d2, d3);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
@ -447,30 +444,28 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
T::enable();
T::reset();
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
let regs = T::regs();
unsafe {
regs.clkcr().write(|w| {
w.set_pwrsav(false);
w.set_negedge(false);
regs.clkcr().write(|w| {
w.set_pwrsav(false);
w.set_negedge(false);
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
// See chip erratas for more details.
#[cfg(sdmmc_v1)]
w.set_hwfc_en(false);
#[cfg(sdmmc_v2)]
w.set_hwfc_en(true);
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
// See chip erratas for more details.
#[cfg(sdmmc_v1)]
w.set_hwfc_en(false);
#[cfg(sdmmc_v2)]
w.set_hwfc_en(true);
#[cfg(sdmmc_v1)]
w.set_clken(true);
});
#[cfg(sdmmc_v1)]
w.set_clken(true);
});
// 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));
}
// 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));
Self {
_peri: sdmmc,
@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
fn data_active() -> bool {
let regs = T::regs();
// NOTE(unsafe) Atomic read with no side-effects
unsafe {
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.rxact() || status.txact();
#[cfg(sdmmc_v2)]
return status.dpsmact();
}
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.rxact() || status.txact();
#[cfg(sdmmc_v2)]
return status.dpsmact();
}
/// Coammand transfer is in progress
@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
fn cmd_active() -> bool {
let regs = T::regs();
// NOTE(unsafe) Atomic read with no side-effects
unsafe {
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.cmdact();
#[cfg(sdmmc_v2)]
return status.cpsmact();
}
let status = regs.star().read();
#[cfg(sdmmc_v1)]
return status.cmdact();
#[cfg(sdmmc_v2)]
return status.cpsmact();
}
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::wait_idle();
Self::clear_interrupt_flags();
// NOTE(unsafe) We have exclusive access to the regisers
unsafe {
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
#[cfg(sdmmc_v1)]
let transfer = unsafe {
let request = self.dma.request();
Transfer::new_read(
&mut self.dma,
request,
regs.fifor().as_ptr() as *mut u32,
buffer,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(true);
#[cfg(sdmmc_v1)]
let transfer = {
let request = self.dma.request();
Transfer::new_read(
&mut self.dma,
request,
regs.fifor().ptr() as *mut u32,
buffer,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
{
w.set_dmaen(true);
w.set_dten(true);
}
});
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(true);
#[cfg(sdmmc_v1)]
{
w.set_dmaen(true);
w.set_dten(true);
}
});
transfer
}
transfer
}
/// # Safety
@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::wait_idle();
Self::clear_interrupt_flags();
// NOTE(unsafe) We have exclusive access to the regisers
unsafe {
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
regs.dtimer()
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
regs.dlenr().write(|w| w.set_datalength(length_bytes));
#[cfg(sdmmc_v1)]
let transfer = unsafe {
let request = self.dma.request();
Transfer::new_write(
&mut self.dma,
request,
buffer,
regs.fifor().as_ptr() as *mut u32,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(false);
#[cfg(sdmmc_v1)]
let transfer = {
let request = self.dma.request();
Transfer::new_write(
&mut self.dma,
request,
buffer,
regs.fifor().ptr() as *mut u32,
DMA_TRANSFER_OPTIONS,
)
};
#[cfg(sdmmc_v2)]
let transfer = {
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(true));
Transfer {
_dummy: core::marker::PhantomData,
}
};
{
w.set_dmaen(true);
w.set_dten(true);
}
});
regs.dctrl().modify(|w| {
w.set_dblocksize(block_size);
w.set_dtdir(false);
#[cfg(sdmmc_v1)]
{
w.set_dmaen(true);
w.set_dten(true);
}
});
transfer
}
transfer
}
/// Stops the DMA datapath
fn stop_datapath() {
let regs = T::regs();
unsafe {
#[cfg(sdmmc_v1)]
regs.dctrl().modify(|w| {
w.set_dmaen(false);
w.set_dten(false);
});
#[cfg(sdmmc_v2)]
regs.idmactrlr().modify(|w| w.set_idmaen(false));
}
#[cfg(sdmmc_v1)]
regs.dctrl().modify(|w| {
w.set_dmaen(false);
w.set_dten(false);
});
#[cfg(sdmmc_v2)]
regs.idmactrlr().modify(|w| w.set_idmaen(false));
}
/// Sets the CLKDIV field in CLKCR. Updates clock field in self
@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
self.clock = new_clock;
// NOTE(unsafe) We have exclusive access to the regblock
unsafe {
// CPSMACT and DPSMACT must be 0 to set CLKDIV
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
}
// CPSMACT and DPSMACT must be 0 to set CLKDIV
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
Ok(())
}
@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
InterruptHandler::<T>::data_interrupts(true);
@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
// NOTE(unsafe) Atomic read with no side-effects
let r1 = unsafe { regs.respr(0).read().cardstatus() };
let r1 = regs.respr(0).read().cardstatus();
Ok(r1.into())
}
@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
InterruptHandler::<T>::data_interrupts(true);
@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
#[inline(always)]
fn clear_interrupt_flags() {
let regs = T::regs();
// NOTE(unsafe) Atomic write
unsafe {
regs.icr().write(|w| {
w.set_ccrcfailc(true);
w.set_dcrcfailc(true);
w.set_ctimeoutc(true);
w.set_dtimeoutc(true);
w.set_txunderrc(true);
w.set_rxoverrc(true);
w.set_cmdrendc(true);
w.set_cmdsentc(true);
w.set_dataendc(true);
w.set_dbckendc(true);
w.set_sdioitc(true);
regs.icr().write(|w| {
w.set_ccrcfailc(true);
w.set_dcrcfailc(true);
w.set_ctimeoutc(true);
w.set_dtimeoutc(true);
w.set_txunderrc(true);
w.set_rxoverrc(true);
w.set_cmdrendc(true);
w.set_cmdsentc(true);
w.set_dataendc(true);
w.set_dbckendc(true);
w.set_sdioitc(true);
#[cfg(sdmmc_v2)]
{
w.set_dholdc(true);
w.set_dabortc(true);
w.set_busyd0endc(true);
w.set_ackfailc(true);
w.set_acktimeoutc(true);
w.set_vswendc(true);
w.set_ckstopc(true);
w.set_idmatec(true);
w.set_idmabtcc(true);
}
});
}
#[cfg(sdmmc_v2)]
{
w.set_dholdc(true);
w.set_dabortc(true);
w.set_busyd0endc(true);
w.set_ackfailc(true);
w.set_acktimeoutc(true);
w.set_vswendc(true);
w.set_ckstopc(true);
w.set_idmatec(true);
w.set_idmabtcc(true);
}
});
}
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Arm `OnDrop` after the buffer, so it will be dropped first
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
InterruptHandler::<T>::data_interrupts(true);
@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
Self::clear_interrupt_flags();
// NOTE(safety) Atomic operations
unsafe {
// CP state machine must be idle
while Self::cmd_active() {}
// CP state machine must be idle
while Self::cmd_active() {}
// Command arg
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
// Command arg
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
// Command index and start CP State Machine
regs.cmdr().write(|w| {
w.set_waitint(false);
w.set_waitresp(cmd.resp as u8);
w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true);
// Command index and start CP State Machine
regs.cmdr().write(|w| {
w.set_waitint(false);
w.set_waitresp(cmd.resp as u8);
w.set_cmdindex(cmd.cmd);
w.set_cpsmen(true);
#[cfg(sdmmc_v2)]
{
// Special mode in CP State Machine
// CMD12: Stop Transmission
let cpsm_stop_transmission = cmd.cmd == 12;
w.set_cmdstop(cpsm_stop_transmission);
w.set_cmdtrans(data);
}
});
let mut status;
if cmd.resp == Response::None {
// Wait for CMDSENT or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdsent())
} {}
} else {
// Wait for CMDREND or CCRCFAIL or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
} {}
#[cfg(sdmmc_v2)]
{
// Special mode in CP State Machine
// CMD12: Stop Transmission
let cpsm_stop_transmission = cmd.cmd == 12;
w.set_cmdstop(cpsm_stop_transmission);
w.set_cmdtrans(data);
}
});
if status.ctimeout() {
return Err(Error::Timeout);
} else if status.ccrcfail() {
return Err(Error::Crc);
}
Ok(())
let mut status;
if cmd.resp == Response::None {
// Wait for CMDSENT or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdsent())
} {}
} else {
// Wait for CMDREND or CCRCFAIL or a timeout
while {
status = regs.star().read();
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
} {}
}
if status.ctimeout() {
return Err(Error::Timeout);
} else if status.ccrcfail() {
return Err(Error::Crc);
}
Ok(())
}
/// # Safety
///
/// Ensure that `regs` has exclusive access to the regblocks
unsafe fn on_drop() {
fn on_drop() {
let regs = T::regs();
if Self::data_active() {
Self::clear_interrupt_flags();
@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
false => BusWidth::One,
};
// 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 (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
self.clock = init_clock;
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be no more than 400 kHz.
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
self.clock = init_clock;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
#[cfg(sdmmc_v1)]
w.set_bypass(_bypass);
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
Self::cmd(Cmd::idle(), false)?;
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
Self::cmd(Cmd::idle(), false)?;
// Check if cards supports CMD8 (with pattern)
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
let r1 = regs.respr(0).read().cardstatus();
// Check if cards supports CMD8 (with pattern)
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
let r1 = regs.respr(0).read().cardstatus();
let mut card = if r1 == 0x1AA {
// Card echoed back the pattern. Must be at least v2
Card::default()
} else {
return Err(Error::UnsupportedCardVersion);
};
let mut card = if r1 == 0x1AA {
// Card echoed back the pattern. Must be at least v2
Card::default()
} else {
return Err(Error::UnsupportedCardVersion);
};
let ocr = loop {
// Signal that next command is a app command
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
let ocr = loop {
// Signal that next command is a app command
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
| CmdAppOper::HIGH_CAPACITY as u32
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
| CmdAppOper::HIGH_CAPACITY as u32
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
// Initialize card
match Self::cmd(Cmd::app_op_cmd(arg), false) {
// ACMD41
Ok(_) => (),
Err(Error::Crc) => (),
Err(err) => return Err(err),
}
let ocr: OCR = regs.respr(0).read().cardstatus().into();
if !ocr.is_busy() {
// Power up done
break ocr;
}
};
if ocr.high_capacity() {
// Card is SDHC or SDXC or SDUC
card.card_type = CardCapacity::SDHC;
} else {
card.card_type = CardCapacity::SDSC;
// Initialize card
match Self::cmd(Cmd::app_op_cmd(arg), false) {
// ACMD41
Ok(_) => (),
Err(Error::Crc) => (),
Err(err) => return Err(err),
}
card.ocr = ocr;
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
let cid0 = regs.respr(0).read().cardstatus() as u128;
let cid1 = regs.respr(1).read().cardstatus() as u128;
let cid2 = regs.respr(2).read().cardstatus() as u128;
let cid3 = regs.respr(3).read().cardstatus() as u128;
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
card.cid = cid.into();
Self::cmd(Cmd::send_rel_addr(), false)?;
card.rca = regs.respr(0).read().cardstatus() >> 16;
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
let csd0 = regs.respr(0).read().cardstatus() as u128;
let csd1 = regs.respr(1).read().cardstatus() as u128;
let csd2 = regs.respr(2).read().cardstatus() as u128;
let csd3 = regs.respr(3).read().cardstatus() as u128;
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
card.csd = csd.into();
self.select_card(Some(&card))?;
self.get_scr(&mut card).await?;
// Set bus width
let (width, acmd_arg) = match bus_width {
BusWidth::Eight => unimplemented!(),
BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
_ => (BusWidth::One, 0),
};
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(match width {
BusWidth::One => 0,
BusWidth::Four => 1,
BusWidth::Eight => 2,
_ => panic!("Invalid Bus Width"),
})
});
// Set Clock
if freq.0 <= 25_000_000 {
// Final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
} else {
// Switch to max clock for SDR12
self.clkcr_set_clkdiv(25_000_000, width)?;
let ocr: OCR = regs.respr(0).read().cardstatus().into();
if !ocr.is_busy() {
// Power up done
break ocr;
}
};
self.card = Some(card);
// Read status
self.read_sd_status().await?;
if freq.0 > 25_000_000 {
// Switch to SDR25
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
if self.signalling == Signalling::SDR25 {
// Set final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
if self.read_status(&card)?.state() != CurrentState::Transfer {
return Err(Error::SignalingSwitchFailed);
}
}
}
// Read status after signalling change
self.read_sd_status().await?;
if ocr.high_capacity() {
// Card is SDHC or SDXC or SDUC
card.card_type = CardCapacity::SDHC;
} else {
card.card_type = CardCapacity::SDSC;
}
card.ocr = ocr;
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
let cid0 = regs.respr(0).read().cardstatus() as u128;
let cid1 = regs.respr(1).read().cardstatus() as u128;
let cid2 = regs.respr(2).read().cardstatus() as u128;
let cid3 = regs.respr(3).read().cardstatus() as u128;
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
card.cid = cid.into();
Self::cmd(Cmd::send_rel_addr(), false)?;
card.rca = regs.respr(0).read().cardstatus() >> 16;
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
let csd0 = regs.respr(0).read().cardstatus() as u128;
let csd1 = regs.respr(1).read().cardstatus() as u128;
let csd2 = regs.respr(2).read().cardstatus() as u128;
let csd3 = regs.respr(3).read().cardstatus() as u128;
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
card.csd = csd.into();
self.select_card(Some(&card))?;
self.get_scr(&mut card).await?;
// Set bus width
let (width, acmd_arg) = match bus_width {
BusWidth::Eight => unimplemented!(),
BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
_ => (BusWidth::One, 0),
};
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
Self::wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(match width {
BusWidth::One => 0,
BusWidth::Four => 1,
BusWidth::Eight => 2,
_ => panic!("Invalid Bus Width"),
})
});
// Set Clock
if freq.0 <= 25_000_000 {
// Final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
} else {
// Switch to max clock for SDR12
self.clkcr_set_clkdiv(25_000_000, width)?;
}
self.card = Some(card);
// Read status
self.read_sd_status().await?;
if freq.0 > 25_000_000 {
// Switch to SDR25
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
if self.signalling == Signalling::SDR25 {
// Set final clock frequency
self.clkcr_set_clkdiv(freq.0, width)?;
if self.read_status(&card)?.state() != CurrentState::Transfer {
return Err(Error::SignalingSwitchFailed);
}
}
}
// Read status after signalling change
self.read_sd_status().await?;
Ok(())
}
@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
let transfer = self.prepare_datapath_read(buffer, 512, 9);
InterruptHandler::<T>::data_interrupts(true);
@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
let on_drop = OnDrop::new(|| Self::on_drop());
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
#[cfg(sdmmc_v1)]
@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let res = poll_fn(|cx| {
T::state().register(cx.waker());
let status = unsafe { regs.star().read() };
let status = regs.star().read();
if status.dcrcfail() {
return Poll::Ready(Err(Error::Crc));
@ -1288,10 +1253,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
fn drop(&mut self) {
unsafe { T::Interrupt::steal() }.disable();
unsafe { Self::on_drop() };
T::Interrupt::disable();
Self::on_drop();
critical_section::with(|_| unsafe {
critical_section::with(|_| {
self.clk.set_as_disconnected();
self.cmd.set_as_disconnected();
self.d0.set_as_disconnected();
@ -1401,7 +1366,7 @@ pub(crate) mod sealed {
use super::*;
pub trait Instance {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> RegBlock;
fn state() -> &'static AtomicWaker;
@ -1490,7 +1455,7 @@ cfg_if::cfg_if! {
foreach_peripheral!(
(sdmmc, $inst:ident) => {
impl sealed::Instance for peripherals::$inst {
type Interrupt = crate::interrupt::$inst;
type Interrupt = crate::interrupt::typelevel::$inst;
fn regs() -> RegBlock {
crate::pac::$inst

View File

@ -98,14 +98,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Polarity::IdleHigh => Pull::Up,
};
unsafe {
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
mosi.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, sck_pull_mode);
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
mosi.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
miso.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner(
peri,
@ -129,12 +127,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
config: Config,
) -> Self {
into_ref!(sck, miso);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
miso.set_speed(crate::gpio::Speed::VeryHigh);
}
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
miso.set_as_af(miso.af_num(), AFType::Input);
miso.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner(
peri,
@ -158,12 +154,10 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
config: Config,
) -> Self {
into_ref!(sck, mosi);
unsafe {
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
mosi.set_speed(crate::gpio::Speed::VeryHigh);
}
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh);
mosi.set_as_af(mosi.af_num(), AFType::OutputPushPull);
mosi.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner(
peri,
@ -186,10 +180,8 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
config: Config,
) -> Self {
into_ref!(mosi);
unsafe {
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
mosi.set_speed(crate::gpio::Speed::Medium);
}
mosi.set_as_af_pull(mosi.af_num(), AFType::OutputPushPull, Pull::Down);
mosi.set_speed(crate::gpio::Speed::Medium);
Self::new_inner(peri, None, Some(mosi.map_into()), None, txdma, rxdma, freq, config)
}
@ -247,7 +239,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::reset();
#[cfg(any(spi_v1, spi_f1))]
unsafe {
{
T::REGS.cr2().modify(|w| {
w.set_ssoe(false);
});
@ -270,7 +262,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}
#[cfg(spi_v2)]
unsafe {
{
T::REGS.cr2().modify(|w| {
let (ds, frxth) = <u8 as sealed::Word>::CONFIG;
w.set_frxth(frxth);
@ -292,7 +284,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
unsafe {
{
T::REGS.ifcr().write(|w| w.0 = 0xffff_ffff);
T::REGS.cfg2().modify(|w| {
//w.set_ssoe(true);
@ -343,29 +335,25 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
let lsbfirst = config.raw_byte_order();
#[cfg(any(spi_v1, spi_f1, spi_v2))]
unsafe {
T::REGS.cr1().modify(|w| {
w.set_cpha(cpha);
w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst);
});
}
T::REGS.cr1().modify(|w| {
w.set_cpha(cpha);
w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
unsafe {
T::REGS.cfg2().modify(|w| {
w.set_cpha(cpha);
w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst);
});
}
T::REGS.cfg2().modify(|w| {
w.set_cpha(cpha);
w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst);
});
}
pub fn get_current_config(&self) -> Config {
#[cfg(any(spi_v1, spi_f1, spi_v2))]
let cfg = unsafe { T::REGS.cr1().read() };
let cfg = T::REGS.cr1().read();
#[cfg(any(spi_v3, spi_v4, spi_v5))]
let cfg = unsafe { T::REGS.cfg2().read() };
let cfg = T::REGS.cfg2().read();
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
Polarity::IdleLow
} else {
@ -395,7 +383,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
#[cfg(any(spi_v1, spi_f1))]
unsafe {
{
T::REGS.cr1().modify(|reg| {
reg.set_spe(false);
reg.set_dff(word_size)
@ -405,7 +393,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}
#[cfg(spi_v2)]
unsafe {
{
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
@ -418,7 +406,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
});
}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
unsafe {
{
T::REGS.cr1().modify(|w| {
w.set_csusp(true);
});
@ -447,26 +435,22 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
self.set_word_size(W::CONFIG);
unsafe {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
}
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
let tx_request = self.txdma.request();
let tx_dst = T::REGS.tx_ptr();
let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
unsafe {
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
}
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
tx_f.await;
@ -485,11 +469,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
self.set_word_size(W::CONFIG);
unsafe {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
}
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@ -517,16 +499,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
)
};
unsafe {
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
}
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
join(tx_f, rx_f).await;
@ -548,11 +528,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
self.set_word_size(W::CONFIG);
unsafe {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
}
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
@ -568,16 +546,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
let tx_dst = T::REGS.tx_ptr();
let tx_f = unsafe { Transfer::new_write_raw(&mut self.txdma, tx_request, write, tx_dst, Default::default()) };
unsafe {
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
}
set_txdmaen(T::REGS, true);
T::REGS.cr1().modify(|w| {
w.set_spe(true);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
T::REGS.cr1().modify(|w| {
w.set_cstart(true);
});
join(tx_f, rx_f).await;
@ -603,7 +579,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
self.set_word_size(W::CONFIG);
for word in words.iter() {
@ -613,7 +589,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
self.set_word_size(W::CONFIG);
for word in words.iter_mut() {
@ -623,7 +599,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
self.set_word_size(W::CONFIG);
for word in words.iter_mut() {
@ -633,7 +609,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
}
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
unsafe { T::REGS.cr1().modify(|w| w.set_spe(true)) }
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
self.set_word_size(W::CONFIG);
let len = read.len().max(write.len());
@ -650,11 +626,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> {
fn drop(&mut self) {
unsafe {
self.sck.as_ref().map(|x| x.set_as_disconnected());
self.mosi.as_ref().map(|x| x.set_as_disconnected());
self.miso.as_ref().map(|x| x.set_as_disconnected());
}
self.sck.as_ref().map(|x| x.set_as_disconnected());
self.mosi.as_ref().map(|x| x.set_as_disconnected());
self.miso.as_ref().map(|x| x.set_as_disconnected());
}
}
@ -690,7 +664,7 @@ impl RegsExt for Regs {
let dr = self.dr();
#[cfg(any(spi_v3, spi_v4, spi_v5))]
let dr = self.txdr();
dr.ptr() as *mut W
dr.as_ptr() as *mut W
}
fn rx_ptr<W>(&self) -> *mut W {
@ -698,7 +672,7 @@ impl RegsExt for Regs {
let dr = self.dr();
#[cfg(any(spi_v3, spi_v4, spi_v5))]
let dr = self.rxdr();
dr.ptr() as *mut W
dr.as_ptr() as *mut W
}
}
@ -731,7 +705,7 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
let sr = regs.sr().read();
check_error_flags(sr)?;
@ -748,7 +722,7 @@ fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
loop {
let sr = unsafe { regs.sr().read() };
let sr = regs.sr().read();
check_error_flags(sr)?;
@ -764,72 +738,64 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
}
fn flush_rx_fifo(regs: Regs) {
unsafe {
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().rxne() {
let _ = regs.dr().read();
}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while regs.sr().read().rxp() {
let _ = regs.rxdr().read();
}
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().rxne() {
let _ = regs.dr().read();
}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while regs.sr().read().rxp() {
let _ = regs.rxdr().read();
}
}
fn set_txdmaen(regs: Regs, val: bool) {
unsafe {
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(val);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(val);
});
}
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(val);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(val);
});
}
fn set_rxdmaen(regs: Regs, val: bool) {
unsafe {
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_rxdmaen(val);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_rxdmaen(val);
});
}
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_rxdmaen(val);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_rxdmaen(val);
});
}
fn finish_dma(regs: Regs) {
unsafe {
#[cfg(spi_v2)]
while regs.sr().read().ftlvl() > 0 {}
#[cfg(spi_v2)]
while regs.sr().read().ftlvl() > 0 {}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while !regs.sr().read().txc() {}
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().bsy() {}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while !regs.sr().read().txc() {}
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().bsy() {}
// Disable the spi peripheral
regs.cr1().modify(|w| {
w.set_spe(false);
});
// 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, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(false);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(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, spi_v5)))]
regs.cr2().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(false);
});
#[cfg(any(spi_v3, spi_v4, spi_v5))]
regs.cfg1().modify(|reg| {
reg.set_txdmaen(false);
reg.set_rxdmaen(false);
});
}
fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {

View File

@ -11,7 +11,7 @@ use embassy_time::driver::{AlarmHandle, Driver};
use embassy_time::TICK_HZ;
use stm32_metapac::timer::regs;
use crate::interrupt::InterruptExt;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::timer::vals;
use crate::rcc::sealed::RccPeripheral;
use crate::timer::sealed::{Basic16bitInstance as BasicInstance, GeneralPurpose16bitInstance as Instance};
@ -40,6 +40,7 @@ type T = peripherals::TIM15;
foreach_interrupt! {
(TIM2, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim2)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -47,6 +48,7 @@ foreach_interrupt! {
};
(TIM3, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim3)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -54,6 +56,7 @@ foreach_interrupt! {
};
(TIM4, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim4)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -61,6 +64,7 @@ foreach_interrupt! {
};
(TIM5, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim5)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -68,6 +72,7 @@ foreach_interrupt! {
};
(TIM12, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim12)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -75,6 +80,7 @@ foreach_interrupt! {
};
(TIM15, timer, $block:ident, UP, $irq:ident) => {
#[cfg(time_driver_tim15)]
#[cfg(feature = "rt")]
#[interrupt]
fn $irq() {
DRIVER.on_interrupt()
@ -149,8 +155,7 @@ impl RtcDriver {
let timer_freq = T::frequency();
// NOTE(unsafe) Critical section to use the unsafe methods
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.cr1().modify(|w| w.set_cen(false));
r.cnt().write(|w| w.set_cnt(0));
@ -177,9 +182,8 @@ impl RtcDriver {
w.set_ccie(0, true);
});
let irq: <T as BasicInstance>::Interrupt = core::mem::transmute(());
irq.unpend();
irq.enable();
<T as BasicInstance>::Interrupt::unpend();
unsafe { <T as BasicInstance>::Interrupt::enable() };
r.cr1().modify(|w| w.set_cen(true));
})
@ -188,9 +192,8 @@ impl RtcDriver {
fn on_interrupt(&self) {
let r = T::regs_gp16();
// NOTE(unsafe) Use critical section to access the methods
// XXX: reduce the size of this critical section ?
critical_section::with(|cs| unsafe {
critical_section::with(|cs| {
let sr = r.sr().read();
let dier = r.dier().read();
@ -223,7 +226,7 @@ impl RtcDriver {
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
let t = (period as u64) << 15;
critical_section::with(move |cs| unsafe {
critical_section::with(move |cs| {
r.dier().modify(move |w| {
for n in 0..ALARM_COUNT {
let alarm = &self.alarms.borrow(cs)[n];
@ -264,8 +267,7 @@ impl Driver for RtcDriver {
let period = self.period.load(Ordering::Relaxed);
compiler_fence(Ordering::Acquire);
// NOTE(unsafe) Atomic read with no side-effects
let counter = unsafe { r.cnt().read().cnt() };
let counter = r.cnt().read().cnt();
calc_now(period, counter)
}
@ -305,7 +307,7 @@ impl Driver for RtcDriver {
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)) };
r.dier().modify(|w| w.set_ccie(n + 1, false));
alarm.timestamp.set(u64::MAX);
@ -316,12 +318,11 @@ impl Driver for RtcDriver {
// Write the CCR value regardless of whether we're going to enable it now or not.
// This way, when we enable it later, the right value is already set.
unsafe { r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)) };
r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16));
// Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
let diff = timestamp - t;
// NOTE(unsafe) We're in a critical section
unsafe { r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)) };
r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
true
})

View File

@ -1,6 +1,6 @@
use stm32_metapac::timer::vals;
use crate::interrupt::Interrupt;
use crate::interrupt;
use crate::rcc::sealed::RccPeripheral as __RccPeri;
use crate::rcc::RccPeripheral;
use crate::time::Hertz;
@ -13,7 +13,7 @@ pub mod low_level {
pub(crate) mod sealed {
use super::*;
pub trait Basic16bitInstance: RccPeripheral {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> crate::pac::timer::TimBasic;
@ -57,28 +57,22 @@ pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
macro_rules! impl_basic_16bit_timer {
($inst:ident, $irq:ident) => {
impl sealed::Basic16bitInstance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
fn regs() -> crate::pac::timer::TimBasic {
crate::pac::timer::TimBasic(crate::pac::$inst.0)
unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
}
fn start(&mut self) {
unsafe {
Self::regs().cr1().modify(|r| r.set_cen(true));
}
Self::regs().cr1().modify(|r| r.set_cen(true));
}
fn stop(&mut self) {
unsafe {
Self::regs().cr1().modify(|r| r.set_cen(false));
}
Self::regs().cr1().modify(|r| r.set_cen(false));
}
fn reset(&mut self) {
unsafe {
Self::regs().cnt().write(|r| r.set_cnt(0));
}
Self::regs().cnt().write(|r| r.set_cnt(0));
}
fn set_frequency(&mut self, frequency: Hertz) {
@ -90,35 +84,29 @@ macro_rules! impl_basic_16bit_timer {
let arr: u16 = unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into());
let regs = Self::regs();
unsafe {
regs.psc().write(|r| r.set_psc(psc));
regs.arr().write(|r| r.set_arr(arr));
regs.psc().write(|r| r.set_psc(psc));
regs.arr().write(|r| r.set_arr(arr));
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
regs.egr().write(|r| r.set_ug(true));
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
regs.egr().write(|r| r.set_ug(true));
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
fn clear_update_interrupt(&mut self) -> bool {
let regs = Self::regs();
unsafe {
let sr = regs.sr().read();
if sr.uif() {
regs.sr().modify(|r| {
r.set_uif(false);
});
true
} else {
false
}
let sr = regs.sr().read();
if sr.uif() {
regs.sr().modify(|r| {
r.set_uif(false);
});
true
} else {
false
}
}
fn enable_update_interrupt(&mut self, enable: bool) {
unsafe {
Self::regs().dier().write(|r| r.set_uie(enable));
}
Self::regs().dier().write(|r| r.set_uie(enable));
}
}
};
@ -141,14 +129,12 @@ macro_rules! impl_32bit_timer {
let arr: u32 = unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into()));
let regs = Self::regs_gp32();
unsafe {
regs.psc().write(|r| r.set_psc(psc));
regs.arr().write(|r| r.set_arr(arr));
regs.psc().write(|r| r.set_psc(psc));
regs.arr().write(|r| r.set_arr(arr));
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
regs.egr().write(|r| r.set_ug(true));
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
regs.egr().write(|r| r.set_ug(true));
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
}
};
@ -185,7 +171,7 @@ foreach_interrupt! {
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
fn regs_gp16() -> crate::pac::timer::TimGp16 {
crate::pac::timer::TimGp16(crate::pac::$inst.0)
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
}
}
@ -206,7 +192,7 @@ foreach_interrupt! {
impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
fn regs_gp16() -> crate::pac::timer::TimGp16 {
crate::pac::timer::TimGp16(crate::pac::$inst.0)
unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
}
}

View File

@ -1,64 +0,0 @@
use embassy_futures::block_on;
use super::cmd::CmdSerial;
use super::consts::TlPacketType;
use super::evt::EvtBox;
use super::unsafe_linked_list::LinkedListNode;
use super::{
channels, BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE, TL_CHANNEL,
TL_REF_TABLE,
};
use crate::tl_mbox::cmd::CmdPacket;
use crate::tl_mbox::ipcc::Ipcc;
pub struct Ble;
impl Ble {
pub fn enable() {
unsafe {
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
pcs_buffer: CS_BUFFER.as_mut_ptr().cast(),
pevt_queue: EVT_QUEUE.as_ptr().cast(),
phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
});
}
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, true);
}
pub fn evt_handler() {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LinkedListNode::is_empty(EVT_QUEUE.as_mut_ptr()) {
LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
let event = node_ptr.cast();
let event = EvtBox::new(event);
block_on(TL_CHANNEL.send(event));
}
}
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_BLE_EVENT_CHANNEL);
}
pub fn send_cmd(buf: &[u8]) {
unsafe {
let pcmd_buffer: *mut CmdPacket = (*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
let pcmd_serial: *mut CmdSerial = &mut (*pcmd_buffer).cmd_serial;
let pcmd_serial_buf: *mut u8 = pcmd_serial.cast();
core::ptr::copy(buf.as_ptr(), pcmd_serial_buf, buf.len());
let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().ble_table).pcmd_buffer;
cmd_packet.cmd_serial.ty = TlPacketType::BleCmd as u8;
}
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_BLE_CMD_CHANNEL);
}
}

View File

@ -1,104 +0,0 @@
//! CPU1 CPU2
//! | (SYSTEM) |
//! |----HW_IPCC_SYSTEM_CMD_RSP_CHANNEL-------------->|
//! | |
//! |<---HW_IPCC_SYSTEM_EVENT_CHANNEL-----------------|
//! | |
//! | (ZIGBEE) |
//! |----HW_IPCC_ZIGBEE_CMD_APPLI_CHANNEL------------>|
//! | |
//! |----HW_IPCC_ZIGBEE_CMD_CLI_CHANNEL-------------->|
//! | |
//! |<---HW_IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL-------|
//! | |
//! |<---HW_IPCC_ZIGBEE_CLI_NOTIF_ACK_CHANNEL---------|
//! | |
//! | (THREAD) |
//! |----HW_IPCC_THREAD_OT_CMD_RSP_CHANNEL----------->|
//! | |
//! |----HW_IPCC_THREAD_CLI_CMD_CHANNEL-------------->|
//! | |
//! |<---HW_IPCC_THREAD_NOTIFICATION_ACK_CHANNEL------|
//! | |
//! |<---HW_IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL--|
//! | |
//! | (BLE) |
//! |----HW_IPCC_BLE_CMD_CHANNEL--------------------->|
//! | |
//! |----HW_IPCC_HCI_ACL_DATA_CHANNEL---------------->|
//! | |
//! |<---HW_IPCC_BLE_EVENT_CHANNEL--------------------|
//! | |
//! | (BLE LLD) |
//! |----HW_IPCC_BLE_LLD_CMD_CHANNEL----------------->|
//! | |
//! |<---HW_IPCC_BLE_LLD_RSP_CHANNEL------------------|
//! | |
//! |<---HW_IPCC_BLE_LLD_M0_CMD_CHANNEL---------------|
//! | |
//! | (MAC) |
//! |----HW_IPCC_MAC_802_15_4_CMD_RSP_CHANNEL-------->|
//! | |
//! |<---HW_IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL|
//! | |
//! | (BUFFER) |
//! |----HW_IPCC_MM_RELEASE_BUFFER_CHANNE------------>|
//! | |
//! | (TRACE) |
//! |<----HW_IPCC_TRACES_CHANNEL----------------------|
//! | |
//!
pub mod cpu1 {
use crate::tl_mbox::ipcc::IpccChannel;
// Not used currently but reserved
pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
// Not used currently but reserved
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
// Not used currently but reserved
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
}
pub mod cpu2 {
use crate::tl_mbox::ipcc::IpccChannel;
pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_BLE_LLD_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_BLE_LLD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
#[allow(dead_code)] // Not used currently but reserved
pub const IPCC_ZIGBEE_M0_REQUEST_CHANNEL: IpccChannel = IpccChannel::Channel5;
}

View File

@ -1,49 +0,0 @@
use super::PacketHeader;
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct Cmd {
pub cmd_code: u16,
pub payload_len: u8,
pub payload: [u8; 255],
}
impl Default for Cmd {
fn default() -> Self {
Self {
cmd_code: 0,
payload_len: 0,
payload: [0u8; 255],
}
}
}
#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
pub struct CmdSerial {
pub ty: u8,
pub cmd: Cmd,
}
#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
pub struct CmdPacket {
pub header: PacketHeader,
pub cmd_serial: CmdSerial,
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct AclDataSerial {
pub ty: u8,
pub handle: u16,
pub length: u16,
pub acl_data: [u8; 1],
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct AclDataPacket {
pub header: PacketHeader,
pub acl_data_serial: AclDataSerial,
}

View File

@ -1,53 +0,0 @@
#[derive(PartialEq)]
#[repr(C)]
pub enum TlPacketType {
BleCmd = 0x01,
AclData = 0x02,
BleEvt = 0x04,
OtCmd = 0x08,
OtRsp = 0x09,
CliCmd = 0x0A,
OtNot = 0x0C,
OtAck = 0x0D,
CliNot = 0x0E,
CliAck = 0x0F,
SysCmd = 0x10,
SysRsp = 0x11,
SysEvt = 0x12,
LocCmd = 0x20,
LocRsp = 0x21,
TracesApp = 0x40,
TracesWl = 0x41,
}
impl TryFrom<u8> for TlPacketType {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x01 => Ok(TlPacketType::BleCmd),
0x02 => Ok(TlPacketType::AclData),
0x04 => Ok(TlPacketType::BleEvt),
0x08 => Ok(TlPacketType::OtCmd),
0x09 => Ok(TlPacketType::OtRsp),
0x0A => Ok(TlPacketType::CliCmd),
0x0C => Ok(TlPacketType::OtNot),
0x0D => Ok(TlPacketType::OtAck),
0x0E => Ok(TlPacketType::CliNot),
0x0F => Ok(TlPacketType::CliAck),
0x10 => Ok(TlPacketType::SysCmd),
0x11 => Ok(TlPacketType::SysRsp),
0x12 => Ok(TlPacketType::SysEvt),
0x20 => Ok(TlPacketType::LocCmd),
0x21 => Ok(TlPacketType::LocRsp),
0x40 => Ok(TlPacketType::TracesApp),
0x41 => Ok(TlPacketType::TracesWl),
_ => Err(()),
}
}
}

View File

@ -1,136 +0,0 @@
use core::mem::MaybeUninit;
use super::cmd::{AclDataPacket, AclDataSerial};
use super::consts::TlPacketType;
use super::{PacketHeader, TL_EVT_HEADER_SIZE};
use crate::tl_mbox::mm::MemoryManager;
/// the payload of [`Evt`] for a command status event
#[derive(Copy, Clone)]
#[repr(C, packed)]
pub struct CsEvt {
pub status: u8,
pub num_cmd: u8,
pub cmd_code: u16,
}
/// the payload of [`Evt`] for a command complete event
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct CcEvt {
pub num_cmd: u8,
pub cmd_code: u8,
pub payload: [u8; 1],
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct Evt {
pub evt_code: u8,
pub payload_len: u8,
pub payload: [u8; 1],
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct EvtSerial {
pub kind: u8,
pub evt: Evt,
}
/// This format shall be used for all events (asynchronous and command response) reported
/// by the CPU2 except for the command response of a system command where the header is not there
/// and the format to be used shall be `EvtSerial`.
///
/// ### Note:
/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
/// include the header and shall use `EvtPacket` format. Only the command response format on the
/// system channel is different.
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct EvtPacket {
pub header: PacketHeader,
pub evt_serial: EvtSerial,
}
/// Smart pointer to the [`EvtPacket`] that will dispose of it automatically on drop
pub struct EvtBox {
ptr: *mut EvtPacket,
}
unsafe impl Send for EvtBox {}
impl EvtBox {
pub(super) fn new(ptr: *mut EvtPacket) -> Self {
Self { ptr }
}
/// Copies the event data from inner pointer and returns and event structure
pub fn evt(&self) -> EvtPacket {
let mut evt = MaybeUninit::uninit();
unsafe {
self.ptr.copy_to(evt.as_mut_ptr(), 1);
evt.assume_init()
}
}
/// Returns the size of a buffer required to hold this event
pub fn size(&self) -> Result<usize, ()> {
unsafe {
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
if evt_kind == TlPacketType::AclData {
let acl_data: *const AclDataPacket = self.ptr.cast();
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
Ok((*acl_serial).length as usize + 5)
} else {
let evt_data: *const EvtPacket = self.ptr.cast();
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
}
}
}
/// writes an underlying [`EvtPacket`] into the provided buffer. Returns the number of bytes that were
/// written. Returns an error if event kind is unkown or if provided buffer size is not enough
pub fn copy_into_slice(&self, buf: &mut [u8]) -> Result<usize, ()> {
unsafe {
let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
let evt_data: *const EvtPacket = self.ptr.cast();
let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
let evt_serial_buf: *const u8 = evt_serial.cast();
let acl_data: *const AclDataPacket = self.ptr.cast();
let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
let acl_serial_buf: *const u8 = acl_serial.cast();
if let TlPacketType::AclData = evt_kind {
let len = (*acl_serial).length as usize + 5;
if len > buf.len() {
return Err(());
}
core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
Ok(len)
} else {
let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
if len > buf.len() {
return Err(());
}
core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
Ok(len)
}
}
}
}
impl Drop for EvtBox {
fn drop(&mut self) {
MemoryManager::evt_drop(self.ptr);
}
}

View File

@ -1,174 +0,0 @@
use self::sealed::Instance;
use crate::peripherals::IPCC;
use crate::rcc::sealed::RccPeripheral;
#[non_exhaustive]
#[derive(Clone, Copy, Default)]
pub struct Config {
// TODO: add IPCC peripheral configuration, if any, here
// reserved for future use
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum IpccChannel {
Channel1 = 0,
Channel2 = 1,
Channel3 = 2,
Channel4 = 3,
Channel5 = 4,
Channel6 = 5,
}
pub mod sealed {
pub trait Instance: crate::rcc::RccPeripheral {
fn regs() -> crate::pac::ipcc::Ipcc;
fn set_cpu2(enabled: bool);
}
}
pub struct Ipcc;
impl Ipcc {
pub fn enable(_config: Config) {
IPCC::enable();
IPCC::reset();
IPCC::set_cpu2(true);
unsafe { _configure_pwr() };
let regs = IPCC::regs();
unsafe {
regs.cpu(0).cr().modify(|w| {
w.set_rxoie(true);
w.set_txfie(true);
})
}
}
pub fn c1_set_rx_channel(channel: IpccChannel, enabled: bool) {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
}
pub fn c1_get_rx_channel(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { !regs.cpu(0).mr().read().chom(channel as usize) }
}
#[allow(dead_code)]
pub fn c2_set_rx_channel(channel: IpccChannel, enabled: bool) {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { regs.cpu(1).mr().modify(|w| w.set_chom(channel as usize, !enabled)) }
}
#[allow(dead_code)]
pub fn c2_get_rx_channel(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { !regs.cpu(1).mr().read().chom(channel as usize) }
}
pub fn c1_set_tx_channel(channel: IpccChannel, enabled: bool) {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
}
pub fn c1_get_tx_channel(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { !regs.cpu(0).mr().read().chfm(channel as usize) }
}
#[allow(dead_code)]
pub fn c2_set_tx_channel(channel: IpccChannel, enabled: bool) {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { regs.cpu(1).mr().modify(|w| w.set_chfm(channel as usize, !enabled)) }
}
#[allow(dead_code)]
pub fn c2_get_tx_channel(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
// If bit is set to 1 then interrupt is disabled
unsafe { !regs.cpu(1).mr().read().chfm(channel as usize) }
}
/// clears IPCC receive channel status for CPU1
pub fn c1_clear_flag_channel(channel: IpccChannel) {
let regs = IPCC::regs();
unsafe { regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)) }
}
#[allow(dead_code)]
/// clears IPCC receive channel status for CPU2
pub fn c2_clear_flag_channel(channel: IpccChannel) {
let regs = IPCC::regs();
unsafe { regs.cpu(1).scr().write(|w| w.set_chc(channel as usize, true)) }
}
pub fn c1_set_flag_channel(channel: IpccChannel) {
let regs = IPCC::regs();
unsafe { regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)) }
}
#[allow(dead_code)]
pub fn c2_set_flag_channel(channel: IpccChannel) {
let regs = IPCC::regs();
unsafe { regs.cpu(1).scr().write(|w| w.set_chs(channel as usize, true)) }
}
pub fn c1_is_active_flag(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
unsafe { regs.cpu(0).sr().read().chf(channel as usize) }
}
pub fn c2_is_active_flag(channel: IpccChannel) -> bool {
let regs = IPCC::regs();
unsafe { regs.cpu(1).sr().read().chf(channel as usize) }
}
pub fn is_tx_pending(channel: IpccChannel) -> bool {
!Self::c1_is_active_flag(channel) && Self::c1_get_tx_channel(channel)
}
pub fn is_rx_pending(channel: IpccChannel) -> bool {
Self::c2_is_active_flag(channel) && Self::c1_get_rx_channel(channel)
}
}
impl sealed::Instance for crate::peripherals::IPCC {
fn regs() -> crate::pac::ipcc::Ipcc {
crate::pac::IPCC
}
fn set_cpu2(enabled: bool) {
unsafe { crate::pac::PWR.cr4().modify(|w| w.set_c2boot(enabled)) }
}
}
unsafe fn _configure_pwr() {
let rcc = crate::pac::RCC;
// set RF wake-up clock = LSE
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
}

View File

@ -1,67 +0,0 @@
use super::evt::EvtPacket;
use super::unsafe_linked_list::LinkedListNode;
use super::{
channels, MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUFF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE,
SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, TL_REF_TABLE,
};
use crate::tl_mbox::ipcc::Ipcc;
pub struct MemoryManager;
impl MemoryManager {
pub fn enable() {
unsafe {
LinkedListNode::init_head(FREE_BUFF_QUEUE.as_mut_ptr());
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
ble_pool: EVT_POOL.as_ptr().cast(),
ble_pool_size: POOL_SIZE as u32,
pevt_free_buffer_queue: FREE_BUFF_QUEUE.as_mut_ptr(),
traces_evt_pool: core::ptr::null(),
traces_pool_size: 0,
});
}
}
pub fn evt_handler() {
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, false);
Self::send_free_buf();
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
}
pub fn evt_drop(evt: *mut EvtPacket) {
unsafe {
let list_node = evt.cast();
LinkedListNode::remove_tail(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), list_node);
}
let channel_is_busy = Ipcc::c1_is_active_flag(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
// postpone event buffer freeing to IPCC interrupt handler
if channel_is_busy {
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, true);
} else {
Self::send_free_buf();
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL);
}
}
fn send_free_buf() {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), node_ptr_ptr);
LinkedListNode::insert_tail(
(*(*TL_REF_TABLE.as_ptr()).mem_manager_table).pevt_free_buffer_queue,
node_ptr,
);
}
}
}
}

View File

@ -1,417 +0,0 @@
use core::mem::MaybeUninit;
use atomic_polyfill::{compiler_fence, Ordering};
use bit_field::BitField;
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use self::ble::Ble;
use self::cmd::{AclDataPacket, CmdPacket};
use self::evt::{CsEvt, EvtBox};
use self::mm::MemoryManager;
use self::shci::{shci_ble_init, ShciBleInitCmdParam};
use self::sys::Sys;
use self::unsafe_linked_list::LinkedListNode;
use crate::interrupt;
use crate::peripherals::IPCC;
pub use crate::tl_mbox::ipcc::Config;
use crate::tl_mbox::ipcc::Ipcc;
mod ble;
mod channels;
mod cmd;
mod consts;
mod evt;
mod ipcc;
mod mm;
mod shci;
mod sys;
mod unsafe_linked_list;
pub type PacketHeader = LinkedListNode;
const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
const TL_EVT_HEADER_SIZE: usize = 3;
const TL_CS_EVT_SIZE: usize = core::mem::size_of::<CsEvt>();
const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5;
const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE;
const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
const fn divc(x: usize, y: usize) -> usize {
(x + y - 1) / y
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct SafeBootInfoTable {
version: u32,
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct FusInfoTable {
version: u32,
memory_size: u32,
fus_info: u32,
}
/// Interrupt handler.
pub struct ReceiveInterruptHandler {}
impl interrupt::Handler<interrupt::IPCC_C1_RX> for ReceiveInterruptHandler {
unsafe fn on_interrupt() {
// info!("ipcc rx interrupt");
if Ipcc::is_rx_pending(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL) {
sys::Sys::evt_handler();
} else if Ipcc::is_rx_pending(channels::cpu2::IPCC_BLE_EVENT_CHANNEL) {
ble::Ble::evt_handler();
} else {
todo!()
}
}
}
pub struct TransmitInterruptHandler {}
impl interrupt::Handler<interrupt::IPCC_C1_TX> for TransmitInterruptHandler {
unsafe fn on_interrupt() {
// info!("ipcc tx interrupt");
if Ipcc::is_tx_pending(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL) {
// TODO: handle this case
let _ = sys::Sys::cmd_evt_handler();
} else if Ipcc::is_tx_pending(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL) {
mm::MemoryManager::evt_handler();
} else {
todo!()
}
}
}
/// # Version
/// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version
/// - 4 -> 7 = branch - 0: Mass Market - x: ...
/// - 8 -> 15 = Subversion
/// - 16 -> 23 = Version minor
/// - 24 -> 31 = Version major
/// # Memory Size
/// - 0 -> 7 = Flash ( Number of 4k sector)
/// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension )
/// - 16 -> 23 = SRAM2b ( Number of 1k sector)
/// - 24 -> 31 = SRAM2a ( Number of 1k sector)
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct WirelessFwInfoTable {
version: u32,
memory_size: u32,
info_stack: u32,
reserved: u32,
}
impl WirelessFwInfoTable {
pub fn version_major(&self) -> u8 {
let version = self.version;
(version.get_bits(24..31) & 0xff) as u8
}
pub fn version_minor(&self) -> u8 {
let version = self.version;
(version.get_bits(16..23) & 0xff) as u8
}
pub fn subversion(&self) -> u8 {
let version = self.version;
(version.get_bits(8..15) & 0xff) as u8
}
/// size of FLASH, expressed in number of 4K sectors
pub fn flash_size(&self) -> u8 {
let memory_size = self.memory_size;
(memory_size.get_bits(0..7) & 0xff) as u8
}
/// size for SRAM2a, expressed in number of 1K sectors
pub fn sram2a_size(&self) -> u8 {
let memory_size = self.memory_size;
(memory_size.get_bits(24..31) & 0xff) as u8
}
/// size of SRAM2b, expressed in number of 1K sectors
pub fn sram2b_size(&self) -> u8 {
let memory_size = self.memory_size;
(memory_size.get_bits(16..23) & 0xff) as u8
}
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct DeviceInfoTable {
pub safe_boot_info_table: SafeBootInfoTable,
pub fus_info_table: FusInfoTable,
pub wireless_fw_info_table: WirelessFwInfoTable,
}
#[repr(C, packed)]
struct BleTable {
pcmd_buffer: *mut CmdPacket,
pcs_buffer: *const u8,
pevt_queue: *const u8,
phci_acl_data_buffer: *mut AclDataPacket,
}
#[repr(C, packed)]
struct ThreadTable {
no_stack_buffer: *const u8,
cli_cmd_rsp_buffer: *const u8,
ot_cmd_rsp_buffer: *const u8,
}
#[repr(C, packed)]
struct SysTable {
pcmd_buffer: *mut CmdPacket,
sys_queue: *const LinkedListNode,
}
#[allow(dead_code)] // Not used currently but reserved
#[repr(C, packed)]
struct LldTestTable {
cli_cmd_rsp_buffer: *const u8,
m0_cmd_buffer: *const u8,
}
#[allow(dead_code)] // Not used currently but reserved
#[repr(C, packed)]
struct BleLldTable {
cmd_rsp_buffer: *const u8,
m0_cmd_buffer: *const u8,
}
#[allow(dead_code)] // Not used currently but reserved
#[repr(C, packed)]
struct ZigbeeTable {
notif_m0_to_m4_buffer: *const u8,
appli_cmd_m4_to_m0_buffer: *const u8,
request_m0_to_m4_buffer: *const u8,
}
#[repr(C, packed)]
struct MemManagerTable {
spare_ble_buffer: *const u8,
spare_sys_buffer: *const u8,
ble_pool: *const u8,
ble_pool_size: u32,
pevt_free_buffer_queue: *mut LinkedListNode,
traces_evt_pool: *const u8,
traces_pool_size: u32,
}
#[repr(C, packed)]
struct TracesTable {
traces_queue: *const u8,
}
#[repr(C, packed)]
struct Mac802_15_4Table {
pcmd_rsp_buffer: *const u8,
pnotack_buffer: *const u8,
evt_queue: *const u8,
}
/// reference table. Contains pointers to all other tables
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct RefTable {
pub device_info_table: *const DeviceInfoTable,
ble_table: *const BleTable,
thread_table: *const ThreadTable,
sys_table: *const SysTable,
mem_manager_table: *const MemManagerTable,
traces_table: *const TracesTable,
mac_802_15_4_table: *const Mac802_15_4Table,
zigbee_table: *const ZigbeeTable,
lld_tests_table: *const LldTestTable,
ble_lld_table: *const BleLldTable,
}
#[link_section = "TL_REF_TABLE"]
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_LLD_TESTS_TABLE: MaybeUninit<LldTestTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_BLE_LLD_TABLE: MaybeUninit<BleLldTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
static mut TL_ZIGBEE_TABLE: MaybeUninit<ZigbeeTable> = MaybeUninit::uninit();
#[allow(dead_code)] // Not used currently but reserved
#[link_section = "MB_MEM1"]
static mut FREE_BUFF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
// not in shared RAM
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
// "magic" numbers from ST ---v---v
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
// TODO: get a better size, this is a placeholder
pub(crate) static TL_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 5> = Channel::new();
pub struct TlMbox<'d> {
_ipcc: PeripheralRef<'d, IPCC>,
}
impl<'d> TlMbox<'d> {
/// initializes low-level transport between CPU1 and BLE stack on CPU2
pub fn new(
ipcc: impl Peripheral<P = IPCC> + 'd,
_irqs: impl interrupt::Binding<interrupt::IPCC_C1_RX, ReceiveInterruptHandler>
+ interrupt::Binding<interrupt::IPCC_C1_TX, TransmitInterruptHandler>,
config: Config,
) -> Self {
into_ref!(ipcc);
unsafe {
compiler_fence(Ordering::AcqRel);
TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
ble_table: TL_BLE_TABLE.as_ptr(),
thread_table: TL_THREAD_TABLE.as_ptr(),
sys_table: TL_SYS_TABLE.as_ptr(),
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
traces_table: TL_TRACES_TABLE.as_ptr(),
mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
});
// info!("TL_REF_TABLE addr: {:x}", TL_REF_TABLE.as_ptr() as usize);
compiler_fence(Ordering::AcqRel);
TL_SYS_TABLE = MaybeUninit::zeroed();
TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed();
TL_BLE_TABLE = MaybeUninit::zeroed();
TL_THREAD_TABLE = MaybeUninit::zeroed();
TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed();
TL_TRACES_TABLE = MaybeUninit::zeroed();
TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed();
TL_ZIGBEE_TABLE = MaybeUninit::zeroed();
TL_LLD_TESTS_TABLE = MaybeUninit::zeroed();
TL_BLE_LLD_TABLE = MaybeUninit::zeroed();
EVT_POOL = MaybeUninit::zeroed();
SYS_SPARE_EVT_BUF = MaybeUninit::zeroed();
BLE_SPARE_EVT_BUF = MaybeUninit::zeroed();
CS_BUFFER = MaybeUninit::zeroed();
BLE_CMD_BUFFER = MaybeUninit::zeroed();
HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed();
compiler_fence(Ordering::AcqRel);
}
Ipcc::enable(config);
Sys::enable();
Ble::enable();
MemoryManager::enable();
// enable interrupts
unsafe { crate::interrupt::IPCC_C1_RX::steal() }.unpend();
unsafe { crate::interrupt::IPCC_C1_TX::steal() }.unpend();
unsafe { crate::interrupt::IPCC_C1_RX::steal() }.enable();
unsafe { crate::interrupt::IPCC_C1_TX::steal() }.enable();
Self { _ipcc: ipcc }
}
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table };
// zero version indicates that CPU2 wasn't active and didn't fill the information table
if info.version != 0 {
Some(*info)
} else {
None
}
}
pub fn shci_ble_init(&self, param: ShciBleInitCmdParam) {
shci_ble_init(param);
}
pub fn send_ble_cmd(&self, buf: &[u8]) {
ble::Ble::send_cmd(buf);
}
// pub fn send_sys_cmd(&self, buf: &[u8]) {
// sys::Sys::send_cmd(buf);
// }
pub async fn read(&self) -> EvtBox {
TL_CHANNEL.recv().await
}
}

View File

@ -1,101 +0,0 @@
//! HCI commands for system channel
use super::cmd::CmdPacket;
use super::consts::TlPacketType;
use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
use crate::tl_mbox::ipcc::Ipcc;
const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
#[allow(dead_code)]
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ShciBleInitCmdParam {
/// NOT USED CURRENTLY
pub p_ble_buffer_address: u32,
/// Size of the Buffer allocated in pBleBufferAddress
pub ble_buffer_size: u32,
pub num_attr_record: u16,
pub num_attr_serv: u16,
pub attr_value_arr_size: u16,
pub num_of_links: u8,
pub extended_packet_length_enable: u8,
pub pr_write_list_size: u8,
pub mb_lock_count: u8,
pub att_mtu: u16,
pub slave_sca: u16,
pub master_sca: u8,
pub ls_source: u8,
pub max_conn_event_length: u32,
pub hs_startup_time: u16,
pub viterbi_enable: u8,
pub ll_only: u8,
pub hw_version: u8,
}
impl Default for ShciBleInitCmdParam {
fn default() -> Self {
Self {
p_ble_buffer_address: 0,
ble_buffer_size: 0,
num_attr_record: 68,
num_attr_serv: 8,
attr_value_arr_size: 1344,
num_of_links: 2,
extended_packet_length_enable: 1,
pr_write_list_size: 0x3A,
mb_lock_count: 0x79,
att_mtu: 156,
slave_sca: 500,
master_sca: 0,
ls_source: 1,
max_conn_event_length: 0xFFFFFFFF,
hs_startup_time: 0x148,
viterbi_enable: 1,
ll_only: 0,
hw_version: 0,
}
}
}
#[derive(Clone, Copy, Default)]
#[repr(C, packed)]
pub struct ShciHeader {
metadata: [u32; 3],
}
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ShciBleInitCmdPacket {
header: ShciHeader,
param: ShciBleInitCmdParam,
}
pub fn shci_ble_init(param: ShciBleInitCmdParam) {
let mut packet = ShciBleInitCmdPacket {
header: ShciHeader::default(),
param,
};
let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
unsafe {
let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
(*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
(*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
core::ptr::write(cmd_buf, *cmd_ptr);
cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
}
}

View File

@ -1,83 +0,0 @@
use embassy_futures::block_on;
use super::cmd::{CmdPacket, CmdSerial};
use super::consts::TlPacketType;
use super::evt::{CcEvt, EvtBox, EvtSerial};
use super::unsafe_linked_list::LinkedListNode;
use super::{channels, SysTable, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_CHANNEL, TL_REF_TABLE, TL_SYS_TABLE};
use crate::tl_mbox::ipcc::Ipcc;
pub struct Sys;
impl Sys {
pub fn enable() {
unsafe {
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
});
}
Ipcc::c1_set_rx_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, true);
}
pub fn evt_handler() {
unsafe {
let mut node_ptr = core::ptr::null_mut();
let node_ptr_ptr: *mut _ = &mut node_ptr;
while !LinkedListNode::is_empty(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr(), node_ptr_ptr);
let event = node_ptr.cast();
let event = EvtBox::new(event);
// TODO: not really happy about this
block_on(TL_CHANNEL.send(event));
}
}
Ipcc::c1_clear_flag_channel(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL);
}
pub fn cmd_evt_handler() -> CcEvt {
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, false);
// ST's command response data structure is really convoluted.
//
// for command response events on SYS channel, the header is missing
// and one should:
// 1. interpret the content of CMD_BUFFER as CmdPacket
// 2. Access CmdPacket's cmdserial field and interpret its content as EvtSerial
// 3. Access EvtSerial's evt field (as Evt) and interpret its payload as CcEvt
// 4. CcEvt type is the actual SHCI response
// 5. profit
unsafe {
let cmd: *const CmdPacket = (*TL_SYS_TABLE.as_ptr()).pcmd_buffer;
let cmd_serial: *const CmdSerial = &(*cmd).cmd_serial;
let evt_serial: *const EvtSerial = cmd_serial.cast();
let cc = (*evt_serial).evt.payload.as_ptr().cast();
*cc
}
}
#[allow(dead_code)]
pub fn send_cmd(buf: &[u8]) {
unsafe {
// TODO: check this
let cmd_buffer = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
let cmd_serial: *mut CmdSerial = &mut cmd_buffer.cmd_serial;
let cmd_serial_buf = cmd_serial.cast();
core::ptr::copy(buf.as_ptr(), cmd_serial_buf, buf.len());
let cmd_packet = &mut *(*TL_REF_TABLE.assume_init().sys_table).pcmd_buffer;
cmd_packet.cmd_serial.ty = TlPacketType::SysCmd as u8;
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
}
}
}

View File

@ -1,125 +0,0 @@
//! Unsafe linked list.
//! Translated from ST's C by `c2rust` tool.
#![allow(
dead_code,
mutable_transmutes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unused_assignments,
unused_mut
)]
use cortex_m::interrupt;
#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct LinkedListNode {
pub next: *mut LinkedListNode,
pub prev: *mut LinkedListNode,
}
impl Default for LinkedListNode {
fn default() -> Self {
LinkedListNode {
next: core::ptr::null_mut(),
prev: core::ptr::null_mut(),
}
}
}
impl LinkedListNode {
pub unsafe fn init_head(mut list_head: *mut LinkedListNode) {
(*list_head).next = list_head;
(*list_head).prev = list_head;
}
pub unsafe fn is_empty(mut list_head: *mut LinkedListNode) -> bool {
interrupt::free(|_| ((*list_head).next) == list_head)
}
pub unsafe fn insert_head(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
interrupt::free(|_| {
(*node).next = (*list_head).next;
(*node).prev = list_head;
(*list_head).next = node;
(*(*node).next).prev = node;
});
}
pub unsafe fn insert_tail(mut list_head: *mut LinkedListNode, mut node: *mut LinkedListNode) {
interrupt::free(|_| {
(*node).next = list_head;
(*node).prev = (*list_head).prev;
(*list_head).prev = node;
(*(*node).prev).next = node;
});
}
pub unsafe fn remove_node(mut node: *mut LinkedListNode) {
interrupt::free(|_| {
(*(*node).prev).next = (*node).next;
(*(*node).next).prev = (*node).prev;
});
}
pub unsafe fn remove_head(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
interrupt::free(|_| {
*node = (*list_head).next;
Self::remove_node((*list_head).next);
});
}
pub unsafe fn remove_tail(mut list_head: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
interrupt::free(|_| {
*node = (*list_head).prev;
Self::remove_node((*list_head).prev);
});
}
pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
interrupt::free(|_| {
(*node).next = (*ref_node).next;
(*node).prev = ref_node;
(*ref_node).next = node;
(*(*node).next).prev = node;
});
}
pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
interrupt::free(|_| {
(*node).next = ref_node;
(*node).prev = (*ref_node).prev;
(*ref_node).prev = node;
(*(*node).prev).next = node;
});
}
pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
interrupt::free(|_| {
let mut size = 0;
let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
temp = (*list_head).next;
while temp != list_head {
size += 1;
temp = (*temp).next
}
size
})
}
pub unsafe fn get_next_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
interrupt::free(|_| {
*node = (*ref_node).next;
});
}
pub unsafe fn get_prev_node(mut ref_node: *mut LinkedListNode, mut node: *mut *mut LinkedListNode) {
interrupt::free(|_| {
*node = (*ref_node).prev;
});
}
}

View File

@ -2,79 +2,81 @@ use core::future::poll_fn;
use core::slice;
use core::task::Poll;
use embassy_cortex_m::interrupt::Interrupt;
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
use embassy_sync::waitqueue::AtomicWaker;
use super::*;
use crate::interrupt::typelevel::Interrupt;
/// Interrupt handler.
pub struct InterruptHandler<T: BasicInstance> {
_phantom: PhantomData<T>,
}
impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
let state = T::buffered_state();
// RX
unsafe {
let sr = sr(r).read();
clear_interrupt_flags(r, sr);
let sr_val = sr(r).read();
// On v1 & v2, reading DR clears the rxne, error and idle interrupt
// flags. Keep this close to the SR read to reduce the chance of a
// flag being set in-between.
let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
Some(rdr(r).read_volatile())
} else {
None
};
clear_interrupt_flags(r, sr_val);
if sr.rxne() {
if sr.pe() {
warn!("Parity error");
}
if sr.fe() {
warn!("Framing error");
}
if sr.ne() {
warn!("Noise error");
}
if sr.ore() {
warn!("Overrun error");
}
let mut rx_writer = state.rx_buf.writer();
let buf = rx_writer.push_slice();
if !buf.is_empty() {
// This read also clears the error and idle interrupt flags on v1.
buf[0] = rdr(r).read_volatile();
rx_writer.push_done(1);
} else {
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
}
if state.rx_buf.is_full() {
state.rx_waker.wake();
}
if sr_val.pe() {
warn!("Parity error");
}
if sr_val.fe() {
warn!("Framing error");
}
if sr_val.ne() {
warn!("Noise error");
}
if sr_val.ore() {
warn!("Overrun error");
}
if sr_val.rxne() {
let mut rx_writer = state.rx_buf.writer();
let buf = rx_writer.push_slice();
if !buf.is_empty() {
buf[0] = dr.unwrap();
rx_writer.push_done(1);
} else {
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
}
if sr.idle() {
if state.rx_buf.is_full() {
state.rx_waker.wake();
};
}
}
if sr_val.idle() {
state.rx_waker.wake();
}
// TX
unsafe {
if sr(r).read().txe() {
let mut tx_reader = state.tx_buf.reader();
let buf = tx_reader.pop_slice();
if !buf.is_empty() {
r.cr1().modify(|w| {
w.set_txeie(true);
});
tdr(r).write_volatile(buf[0].into());
tx_reader.pop_done(1);
state.tx_waker.wake();
} else {
// Disable interrupt until we have something to transmit again
r.cr1().modify(|w| {
w.set_txeie(false);
});
}
if sr(r).read().txe() {
let mut tx_reader = state.tx_buf.reader();
let buf = tx_reader.pop_slice();
if !buf.is_empty() {
r.cr1().modify(|w| {
w.set_txeie(true);
});
tdr(r).write_volatile(buf[0].into());
tx_reader.pop_done(1);
state.tx_waker.wake();
} else {
// Disable interrupt until we have something to transmit again
r.cr1().modify(|w| {
w.set_txeie(false);
});
}
}
}
@ -115,7 +117,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_buffer: &'d mut [u8],
@ -130,7 +132,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
@ -144,14 +146,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
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);
});
}
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, tx_buffer, rx_buffer, config)
}
@ -159,7 +159,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
#[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
@ -172,12 +172,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
T::enable();
T::reset();
unsafe {
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
}
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
}
@ -199,25 +197,21 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, true, true);
unsafe {
r.cr1().modify(|w| {
#[cfg(lpuart_v2)]
w.set_fifoen(true);
r.cr1().modify(|w| {
#[cfg(lpuart_v2)]
w.set_fifoen(true);
w.set_rxneie(true);
w.set_idleie(true);
});
}
w.set_rxneie(true);
w.set_idleie(true);
});
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Self {
rx: BufferedUartRx { phantom: PhantomData },
@ -245,7 +239,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
rx_reader.pop_done(len);
if do_pend {
unsafe { T::Interrupt::steal().pend() };
T::Interrupt::pend();
}
return Poll::Ready(Ok(len));
@ -271,7 +265,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
rx_reader.pop_done(len);
if do_pend {
unsafe { T::Interrupt::steal().pend() };
T::Interrupt::pend();
}
return Ok(len);
@ -301,7 +295,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
let full = state.rx_buf.is_full();
rx_reader.pop_done(amt);
if full {
unsafe { T::Interrupt::steal().pend() };
T::Interrupt::pend();
}
}
}
@ -324,7 +318,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
tx_writer.push_done(n);
if empty {
unsafe { T::Interrupt::steal() }.pend();
T::Interrupt::pend();
}
Poll::Ready(Ok(n))
@ -358,7 +352,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
tx_writer.push_done(n);
if empty {
unsafe { T::Interrupt::steal() }.pend();
T::Interrupt::pend();
}
return Ok(n);
@ -385,7 +379,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
// TX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler
if state.tx_buf.len() == 0 {
T::Interrupt::steal().disable();
T::Interrupt::disable();
}
}
}
@ -400,7 +394,7 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
// RX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler
if state.rx_buf.len() == 0 {
T::Interrupt::steal().disable();
T::Interrupt::disable();
}
}
}

View File

@ -5,13 +5,13 @@ use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::drop::OnDrop;
use embassy_hal_common::{into_ref, PeripheralRef};
use futures::future::{select, Either};
use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
#[cfg(not(any(usart_v1, usart_v2)))]
#[allow(unused_imports)]
use crate::pac::usart::regs::Isr as Sr;
@ -31,40 +31,36 @@ pub struct InterruptHandler<T: BasicInstance> {
_phantom: PhantomData<T>,
}
impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
let s = T::state();
let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
let (sr, cr1, cr3) = (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);
});
}
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);
});
} 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.cr1().modify(|w| {
// disable idle line detection
w.set_idleie(false);
});
} else if cr1.rxneie() {
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
@ -205,12 +201,10 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
T::enable();
T::reset();
unsafe {
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_ctse(true);
});
}
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)
}
@ -224,9 +218,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
let r = T::regs();
unsafe {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, false, true);
@ -245,11 +237,9 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
{
let ch = &mut self.tx_dma;
let request = ch.request();
unsafe {
T::regs().cr3().modify(|reg| {
reg.set_dmat(true);
});
}
T::regs().cr3().modify(|reg| {
reg.set_dmat(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 = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
@ -258,21 +248,17 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
unsafe {
let r = T::regs();
for &b in buffer {
while !sr(r).read().txe() {}
tdr(r).write_volatile(b);
}
let r = T::regs();
for &b in buffer {
while !sr(r).read().txe() {}
unsafe { tdr(r).write_volatile(b) };
}
Ok(())
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
unsafe {
let r = T::regs();
while !sr(r).read().tc() {}
}
let r = T::regs();
while !sr(r).read().tc() {}
Ok(())
}
}
@ -281,7 +267,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
/// Useful 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 interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
@ -294,7 +280,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
pub fn new_with_rts(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
@ -305,12 +291,10 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
T::enable();
T::reset();
unsafe {
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_rtse(true);
});
}
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_rtse(true);
});
Self::new_inner(peri, rx, rx_dma, config)
}
@ -325,14 +309,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
}
rx.set_as_af(rx.af_num(), AFType::Input);
configure(r, &config, T::frequency(), T::KIND, true, false);
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
@ -347,7 +329,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
}
#[cfg(any(usart_v1, usart_v2))]
unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
loop {
// Handle all buffered error flags.
@ -380,7 +362,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
}
#[cfg(any(usart_v3, usart_v4))]
unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
let sr = r.isr().read();
if sr.pe() {
@ -410,22 +392,18 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs();
unsafe {
if self.check_rx_flags()? {
Ok(rdr(r).read_volatile())
} else {
Err(nb::Error::WouldBlock)
}
if self.check_rx_flags()? {
Ok(unsafe { rdr(r).read_volatile() })
} else {
Err(nb::Error::WouldBlock)
}
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
unsafe {
let r = T::regs();
for b in buffer {
while !self.check_rx_flags()? {}
*b = rdr(r).read_volatile();
}
let r = T::regs();
for b in buffer {
while !self.check_rx_flags()? {}
unsafe { *b = rdr(r).read_volatile() }
}
Ok(())
}
@ -451,23 +429,20 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
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);
});
}
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;
@ -480,78 +455,74 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
// future which will complete when DMA Read request completes
let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
// 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);
// 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.
unsafe { 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.
unsafe { 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 {
// clear idle flag
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
// enable idle interrupt
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// enable parity interrupt if not ParityNone
w.set_peie(w.pce());
w.set_idleie(true);
});
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 {
// 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);
@ -562,15 +533,11 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
s.rx_waker.register(cx.waker());
// SAFETY: read only and we only use Rx related flags
let sr = unsafe { sr(r).read() };
let sr = 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);
}
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
compiler_fence(Ordering::SeqCst);
@ -650,7 +617,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
@ -665,7 +632,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
@ -677,14 +644,12 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
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);
});
}
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, tx_dma, rx_dma, config)
}
@ -693,7 +658,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
@ -704,12 +669,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
T::enable();
T::reset();
unsafe {
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
}
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
}
@ -725,15 +688,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
let r = T::regs();
unsafe {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, true, true);
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
@ -847,11 +808,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
over8 = true;
let div = div as u32;
unsafe {
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
}
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
found = Some(div);
break;
}
@ -860,11 +819,9 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
if div < brr_max {
let div = div as u32;
unsafe {
r.brr().write_value(regs::Brr(div));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
}
r.brr().write_value(regs::Brr(div));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
found = Some(div);
break;
}
@ -883,44 +840,42 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
pclk_freq.0 / div
);
unsafe {
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.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,
});
#[cfg(not(usart_v1))]
w.set_over8(vals::Over8(over8 as _));
});
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,
});
#[cfg(not(usart_v1))]
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
});
}
w.set_over8(vals::Over8(over8 as _));
});
#[cfg(not(usart_v1))]
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
});
}
mod eh02 {
@ -1111,12 +1066,12 @@ use self::sealed::Kind;
#[cfg(any(usart_v1, usart_v2))]
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().ptr() as _
r.dr().as_ptr() as _
}
#[cfg(any(usart_v1, usart_v2))]
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().ptr() as _
r.dr().as_ptr() as _
}
#[cfg(any(usart_v1, usart_v2))]
@ -1126,18 +1081,18 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::p
#[cfg(any(usart_v1, usart_v2))]
#[allow(unused)]
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
// On v1 the flags are cleared implicitly by reads and writes to DR.
}
#[cfg(any(usart_v3, usart_v4))]
fn tdr(r: Regs) -> *mut u8 {
r.tdr().ptr() as _
r.tdr().as_ptr() as _
}
#[cfg(any(usart_v3, usart_v4))]
fn rdr(r: Regs) -> *mut u8 {
r.rdr().ptr() as _
r.rdr().as_ptr() as _
}
#[cfg(any(usart_v3, usart_v4))]
@ -1147,7 +1102,7 @@ fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
#[cfg(any(usart_v3, usart_v4))]
#[allow(unused)]
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
r.icr().write(|w| *w = regs::Icr(sr.0));
}
@ -1179,7 +1134,7 @@ pub(crate) mod sealed {
pub trait BasicInstance: crate::rcc::RccPeripheral {
const KIND: Kind;
type Interrupt: crate::interrupt::Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> Regs;
fn state() -> &'static State;
@ -1211,10 +1166,10 @@ macro_rules! impl_usart {
($inst:ident, $irq:ident, $kind:expr) => {
impl sealed::BasicInstance for crate::peripherals::$inst {
const KIND: Kind = $kind;
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
fn regs() -> Regs {
Regs(crate::pac::$inst.0)
unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
}
fn state() -> &'static crate::usart::sealed::State {

View File

@ -59,23 +59,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
let r = T::regs();
// 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);
// enable parity interrupt if not ParityNone
w.set_peie(w.pce());
// enable idle line interrupt
w.set_idleie(true);
});
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);
});
}
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// enable parity interrupt if not ParityNone
w.set_peie(w.pce());
// enable idle line interrupt
w.set_idleie(true);
});
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);
});
}
/// Stop uart background receive
@ -84,23 +81,20 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
let r = T::regs();
// 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);
});
}
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);
}
@ -117,8 +111,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
let r = T::regs();
// Start background receive if it was not already started
// SAFETY: read only
match unsafe { r.cr3().read().dmar() } {
match r.cr3().read().dmar() {
false => self.start()?,
_ => {}
};
@ -213,19 +206,17 @@ fn check_for_errors(s: Sr) -> Result<(), Error> {
/// Clear IDLE and return the Sr register
fn clear_idle_flag(r: Regs) -> Sr {
unsafe {
// SAFETY: read only and we only use Rx related flags
// SAFETY: read only and we only use Rx related flags
let sr = sr(r).read();
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);
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
r.cr1().modify(|w| w.set_idleie(true));
r.cr1().modify(|w| w.set_idleie(true));
sr
}
sr
}
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]

View File

@ -1,4 +1,4 @@
use crate::interrupt::Interrupt;
use crate::interrupt;
use crate::rcc::RccPeripheral;
#[cfg(feature = "nightly")]
@ -13,7 +13,7 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + RccPeripheral + 'static {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
}
// Internal PHY pins
@ -29,7 +29,7 @@ foreach_interrupt!(
}
impl Instance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
);

View File

@ -14,7 +14,7 @@ use embassy_usb_driver::{
use super::{DmPin, DpPin, Instance};
use crate::gpio::sealed::AFType;
use crate::interrupt::{Interrupt, InterruptExt};
use crate::interrupt::typelevel::Interrupt;
use crate::pac::usb::regs;
use crate::pac::usb::vals::{EpType, Stat};
use crate::pac::USBRAM;
@ -26,84 +26,82 @@ pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
unsafe {
let regs = T::regs();
//let x = regs.istr().read().0;
//trace!("USB IRQ: {:08x}", x);
let regs = T::regs();
//let x = regs.istr().read().0;
//trace!("USB IRQ: {:08x}", x);
let istr = regs.istr().read();
let istr = regs.istr().read();
if istr.susp() {
//trace!("USB IRQ: susp");
IRQ_SUSPEND.store(true, Ordering::Relaxed);
regs.cntr().modify(|w| {
w.set_fsusp(true);
w.set_lpmode(true);
});
if istr.susp() {
//trace!("USB IRQ: susp");
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);
// 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();
}
// Wake main thread.
BUS_WAKER.wake();
}
if istr.wkup() {
//trace!("USB IRQ: wkup");
IRQ_RESUME.store(true, Ordering::Relaxed);
regs.cntr().modify(|w| {
w.set_fsusp(false);
w.set_lpmode(false);
});
if istr.wkup() {
//trace!("USB IRQ: wkup");
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);
// 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();
}
// Wake main thread.
BUS_WAKER.wake();
}
if istr.reset() {
//trace!("USB IRQ: reset");
IRQ_RESET.store(true, Ordering::Relaxed);
if istr.reset() {
//trace!("USB IRQ: 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);
// Write 0 to clear.
let mut clear = regs::Istr(!0);
clear.set_reset(false);
regs.istr().write_value(clear);
// Wake main thread.
BUS_WAKER.wake();
}
// Wake main thread.
BUS_WAKER.wake();
}
if istr.ctr() {
let index = istr.ep_id() as usize;
let mut epr = regs.epr(index).read();
if epr.ctr_rx() {
if index == 0 && epr.setup() {
EP0_SETUP.store(true, Ordering::Relaxed);
}
//trace!("EP {} RX, setup={}", index, epr.setup());
EP_OUT_WAKERS[index].wake();
if istr.ctr() {
let index = istr.ep_id() as usize;
let mut epr = regs.epr(index).read();
if epr.ctr_rx() {
if index == 0 && epr.setup() {
EP0_SETUP.store(true, Ordering::Relaxed);
}
if epr.ctr_tx() {
//trace!("EP {} TX", index);
EP_IN_WAKERS[index].wake();
}
epr.set_dtog_rx(false);
epr.set_dtog_tx(false);
epr.set_stat_rx(Stat(0));
epr.set_stat_tx(Stat(0));
epr.set_ctr_rx(!epr.ctr_rx());
epr.set_ctr_tx(!epr.ctr_tx());
regs.epr(index).write_value(epr);
//trace!("EP {} RX, setup={}", index, epr.setup());
EP_OUT_WAKERS[index].wake();
}
if epr.ctr_tx() {
//trace!("EP {} TX", index);
EP_IN_WAKERS[index].wake();
}
epr.set_dtog_rx(false);
epr.set_dtog_tx(false);
epr.set_stat_rx(Stat(0));
epr.set_stat_tx(Stat(0));
epr.set_ctr_rx(!epr.ctr_rx());
epr.set_ctr_tx(!epr.ctr_tx());
regs.epr(index).write_value(epr);
}
}
}
@ -168,20 +166,20 @@ fn calc_out_len(len: u16) -> (u16, u16) {
mod btable {
use super::*;
pub(super) unsafe fn write_in<T: Instance>(index: usize, addr: u16) {
pub(super) fn write_in<T: Instance>(index: usize, addr: u16) {
USBRAM.mem(index * 4 + 0).write_value(addr);
}
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
pub(super) fn write_in_len<T: Instance>(index: usize, _addr: u16, len: u16) {
USBRAM.mem(index * 4 + 1).write_value(len);
}
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
USBRAM.mem(index * 4 + 2).write_value(addr);
USBRAM.mem(index * 4 + 3).write_value(max_len_bits);
}
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
USBRAM.mem(index * 4 + 3).read()
}
}
@ -189,19 +187,19 @@ mod btable {
mod btable {
use super::*;
pub(super) unsafe fn write_in<T: Instance>(_index: usize, _addr: u16) {}
pub(super) fn write_in<T: Instance>(_index: usize, _addr: u16) {}
pub(super) unsafe fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
pub(super) fn write_in_len<T: Instance>(index: usize, addr: u16, len: u16) {
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
}
pub(super) unsafe fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
pub(super) fn write_out<T: Instance>(index: usize, addr: u16, max_len_bits: u16) {
USBRAM
.mem(index * 2 + 1)
.write_value((addr as u32) | ((max_len_bits as u32) << 16));
}
pub(super) unsafe fn read_out_len<T: Instance>(index: usize) -> u16 {
pub(super) fn read_out_len<T: Instance>(index: usize) -> u16 {
(USBRAM.mem(index * 2 + 1).read() >> 16) as u16
}
}
@ -216,7 +214,7 @@ impl<T: Instance> EndpointBuffer<T> {
fn read(&mut self, buf: &mut [u8]) {
assert!(buf.len() <= self.len as usize);
for i in 0..(buf.len() + USBRAM_ALIGN - 1) / USBRAM_ALIGN {
let val = unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read() };
let val = USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).read();
let n = USBRAM_ALIGN.min(buf.len() - i * USBRAM_ALIGN);
buf[i * USBRAM_ALIGN..][..n].copy_from_slice(&val.to_le_bytes()[..n]);
}
@ -233,7 +231,7 @@ impl<T: Instance> EndpointBuffer<T> {
let val = u16::from_le_bytes(val);
#[cfg(usbram_32_2048)]
let val = u32::from_le_bytes(val);
unsafe { USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val) };
USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
}
}
}
@ -255,47 +253,43 @@ pub struct Driver<'d, T: Instance> {
impl<'d, T: Instance> Driver<'d, T> {
pub fn new(
_usb: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dp: impl Peripheral<P = impl DpPin<T>> + 'd,
dm: impl Peripheral<P = impl DmPin<T>> + 'd,
) -> Self {
into_ref!(dp, dm);
unsafe { T::Interrupt::steal() }.unpend();
unsafe { T::Interrupt::steal() }.enable();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
let regs = T::regs();
#[cfg(stm32l5)]
unsafe {
{
crate::peripherals::PWR::enable();
crate::pac::PWR.cr2().modify(|w| w.set_usv(true));
}
#[cfg(pwr_h5)]
unsafe {
crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true))
}
crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true));
unsafe {
<T as RccPeripheral>::enable();
<T as RccPeripheral>::reset();
<T as RccPeripheral>::enable();
<T as RccPeripheral>::reset();
regs.cntr().write(|w| {
w.set_pdwn(false);
w.set_fres(true);
});
regs.cntr().write(|w| {
w.set_pdwn(false);
w.set_fres(true);
});
#[cfg(time)]
embassy_time::block_for(embassy_time::Duration::from_millis(100));
#[cfg(not(time))]
cortex_m::asm::delay(crate::rcc::get_freqs().sys.0 / 10);
#[cfg(time)]
embassy_time::block_for(embassy_time::Duration::from_millis(100));
#[cfg(not(time))]
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10);
#[cfg(not(usb_v4))]
regs.btable().write(|w| w.set_btable(0));
#[cfg(not(usb_v4))]
regs.btable().write(|w| w.set_btable(0));
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
}
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
// Initialize the bus so that it signals that power is available
BUS_WAKER.wake();
@ -363,7 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
let addr = self.alloc_ep_mem(len);
trace!(" len_bits = {:04x}", len_bits);
unsafe { btable::write_out::<T>(index, addr, len_bits) }
btable::write_out::<T>(index, addr, len_bits);
EndpointBuffer {
addr,
@ -379,7 +373,7 @@ impl<'d, T: Instance> Driver<'d, T> {
let addr = self.alloc_ep_mem(len);
// ep_in_len is written when actually TXing packets.
unsafe { btable::write_in::<T>(index, addr) }
btable::write_in::<T>(index, addr);
EndpointBuffer {
addr,
@ -440,19 +434,17 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
let regs = T::regs();
unsafe {
regs.cntr().write(|w| {
w.set_pdwn(false);
w.set_fres(false);
w.set_resetm(true);
w.set_suspm(true);
w.set_wkupm(true);
w.set_ctrm(true);
});
regs.cntr().write(|w| {
w.set_pdwn(false);
w.set_fres(false);
w.set_resetm(true);
w.set_suspm(true);
w.set_wkupm(true);
w.set_ctrm(true);
});
#[cfg(any(usb_v3, usb_v4))]
regs.bcdr().write(|w| w.set_dppu(true))
}
#[cfg(any(usb_v3, usb_v4))]
regs.bcdr().write(|w| w.set_dppu(true));
trace!("enabled");
@ -485,7 +477,7 @@ pub struct Bus<'d, T: Instance> {
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| unsafe {
poll_fn(move |cx| {
BUS_WAKER.register(cx.waker());
if self.inited {
@ -548,7 +540,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
match ep_addr.direction() {
Direction::In => {
loop {
let r = unsafe { reg.read() };
let r = reg.read();
match r.stat_tx() {
Stat::DISABLED => break, // if disabled, stall does nothing.
Stat::STALL => break, // done!
@ -559,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
};
let mut w = invariant(r);
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
unsafe { reg.write_value(w) };
reg.write_value(w);
}
}
}
@ -567,7 +559,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
}
Direction::Out => {
loop {
let r = unsafe { reg.read() };
let r = reg.read();
match r.stat_rx() {
Stat::DISABLED => break, // if disabled, stall does nothing.
Stat::STALL => break, // done!
@ -578,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
};
let mut w = invariant(r);
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
unsafe { reg.write_value(w) };
reg.write_value(w);
}
}
}
@ -589,7 +581,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
let regs = T::regs();
let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
let epr = regs.epr(ep_addr.index() as _).read();
match ep_addr.direction() {
Direction::In => epr.stat_tx() == Stat::STALL,
Direction::Out => epr.stat_rx() == Stat::STALL,
@ -600,7 +592,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
trace!("set_enabled {:x} {}", ep_addr, enabled);
// This can race, so do a retry loop.
let reg = T::regs().epr(ep_addr.index() as _);
trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
trace!("EPR before: {:04x}", reg.read().0);
match ep_addr.direction() {
Direction::In => {
loop {
@ -608,13 +600,13 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
false => Stat::DISABLED,
true => Stat::NAK,
};
let r = unsafe { reg.read() };
let r = reg.read();
if r.stat_tx() == want_stat {
break;
}
let mut w = invariant(r);
w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
unsafe { reg.write_value(w) };
reg.write_value(w);
}
EP_IN_WAKERS[ep_addr.index()].wake();
}
@ -624,18 +616,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
false => Stat::DISABLED,
true => Stat::VALID,
};
let r = unsafe { reg.read() };
let r = reg.read();
if r.stat_rx() == want_stat {
break;
}
let mut w = invariant(r);
w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
unsafe { reg.write_value(w) };
reg.write_value(w);
}
EP_OUT_WAKERS[ep_addr.index()].wake();
}
}
trace!("EPR after: {:04x}", unsafe { reg.read() }.0);
trace!("EPR after: {:04x}", reg.read().0);
}
async fn enable(&mut self) {}
@ -685,12 +677,12 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> {
fn write_data(&mut self, buf: &[u8]) {
let index = self.info.addr.index();
self.buf.write(buf);
unsafe { btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _) }
btable::write_in_len::<T>(index, self.buf.addr, buf.len() as _);
}
fn read_data(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
let index = self.info.addr.index();
let rx_len = unsafe { btable::read_out_len::<T>(index) as usize } & 0x3FF;
let rx_len = btable::read_out_len::<T>(index) as usize & 0x3FF;
trace!("READ DONE, rx_len = {}", rx_len);
if rx_len > buf.len() {
return Err(EndpointError::BufferOverflow);
@ -711,7 +703,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_tx() == Stat::DISABLED {
if regs.epr(index).read().stat_tx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
@ -733,7 +725,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
poll_fn(|cx| {
EP_OUT_WAKERS[index].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(index).read() }.stat_rx() == Stat::DISABLED {
if regs.epr(index).read().stat_rx() == Stat::DISABLED {
Poll::Pending
} else {
Poll::Ready(())
@ -751,7 +743,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
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();
let stat = regs.epr(index).read().stat_rx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
@ -767,16 +759,14 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
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
})
};
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)
@ -795,7 +785,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
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();
let stat = regs.epr(index).read().stat_tx();
if matches!(stat, Stat::NAK | Stat::DISABLED) {
Poll::Ready(stat)
} else {
@ -811,16 +801,14 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
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
})
};
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");
@ -889,22 +877,20 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
}
// 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
})
}
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());
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 regs.epr(0).read().stat_rx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
@ -919,19 +905,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
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
})
};
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)
}
@ -960,15 +944,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
}
// 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
})
}
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
});
}
trace!("WRITE WAITING");
@ -976,7 +958,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
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 {
if regs.epr(0).read().stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
@ -992,15 +974,13 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
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
})
};
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
});
trace!("WRITE OK");
@ -1014,16 +994,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
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
});
}
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.
@ -1031,7 +1009,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
let regs = T::regs();
if unsafe { regs.epr(0).read() }.stat_tx() == Stat::NAK {
if regs.epr(0).read().stat_tx() == Stat::NAK {
Poll::Ready(())
} else {
Poll::Pending
@ -1047,16 +1025,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
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
});
}
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
});
}
async fn accept_set_address(&mut self, addr: u8) {
@ -1064,11 +1040,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs();
trace!("setting addr: {}", addr);
unsafe {
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(addr);
})
}
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(addr);
});
}
}

View File

@ -1,7 +1,5 @@
use embassy_cortex_m::interrupt::Interrupt;
use crate::peripherals;
use crate::rcc::RccPeripheral;
use crate::{interrupt, peripherals};
#[cfg(feature = "nightly")]
mod usb;
@ -25,7 +23,7 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + RccPeripheral {
type Interrupt: Interrupt;
type Interrupt: interrupt::typelevel::Interrupt;
}
// Internal PHY pins
@ -109,7 +107,7 @@ foreach_interrupt!(
}
impl Instance for peripherals::USB_OTG_FS {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
@ -150,7 +148,7 @@ foreach_interrupt!(
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)
unsafe { crate::pac::otg::Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
}
#[cfg(feature = "nightly")]
@ -161,7 +159,7 @@ foreach_interrupt!(
}
impl Instance for peripherals::USB_OTG_HS {
type Interrupt = crate::interrupt::$irq;
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
);

View File

@ -3,7 +3,6 @@ use core::marker::PhantomData;
use core::task::Poll;
use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
use embassy_cortex_m::interrupt::InterruptExt;
use embassy_hal_common::{into_ref, Peripheral};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver::{
@ -15,6 +14,7 @@ use futures::future::poll_fn;
use super::*;
use crate::gpio::sealed::AFType;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::otg::{regs, vals};
use crate::rcc::sealed::RccPeripheral;
use crate::time::Hertz;
@ -24,25 +24,22 @@ pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
trace!("irq");
let r = T::regs();
let state = T::state();
// SAFETY: atomic read/write
let ints = unsafe { r.gintsts().read() };
let ints = r.gintsts().read();
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
// Mask interrupts and notify `Bus` to process them
unsafe { r.gintmsk().write(|_| {}) };
r.gintmsk().write(|_| {});
T::state().bus_waker.wake();
}
// Handle RX
// SAFETY: atomic read with no side effects
while unsafe { r.gintsts().read().rxflvl() } {
// SAFETY: atomic "pop" register
let status = unsafe { r.grxstsp().read() };
while r.gintsts().read().rxflvl() {
let status = r.grxstsp().read();
let ep_num = status.epnum() as usize;
let len = status.bcnt() as usize;
@ -57,21 +54,15 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
// SAFETY: exclusive access ensured by atomic bool
let data = unsafe { &mut *state.ep0_setup_data.get() };
// SAFETY: FIFO reads are exclusive to this IRQ
unsafe {
data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
}
data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
state.ep0_setup_ready.store(true, Ordering::Release);
state.ep_out_wakers[0].wake();
} else {
error!("received SETUP before previous finished processing");
// discard FIFO
// SAFETY: FIFO reads are exclusive to IRQ
unsafe {
r.fifo(0).read();
r.fifo(0).read();
}
r.fifo(0).read();
r.fifo(0).read();
}
}
vals::Pktstsd::OUT_DATA_RX => {
@ -84,8 +75,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
for chunk in buf.chunks_mut(4) {
// RX FIFO is shared so always read from fifo(0)
// SAFETY: FIFO reads are exclusive to IRQ
let data = unsafe { r.fifo(0).read().0 };
let data = r.fifo(0).read().0;
chunk.copy_from_slice(&data.to_ne_bytes()[0..chunk.len()]);
}
@ -97,8 +87,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
// discard FIFO data
let len_words = (len + 3) / 4;
for _ in 0..len_words {
// SAFETY: FIFO reads are exclusive to IRQ
unsafe { r.fifo(0).read().data() };
r.fifo(0).read().data();
}
}
}
@ -114,24 +103,20 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
// IN endpoint interrupt
if ints.iepint() {
// SAFETY: atomic read with no side effects
let mut ep_mask = unsafe { r.daint().read().iepint() };
let mut ep_mask = r.daint().read().iepint();
let mut ep_num = 0;
// Iterate over endpoints while there are non-zero bits in the mask
while ep_mask != 0 {
if ep_mask & 1 != 0 {
// SAFETY: atomic read with no side effects
let ep_ints = unsafe { r.diepint(ep_num).read() };
let ep_ints = r.diepint(ep_num).read();
// clear all
// SAFETY: DIEPINT is exclusive to IRQ
unsafe { r.diepint(ep_num).write_value(ep_ints) };
r.diepint(ep_num).write_value(ep_ints);
// TXFE is cleared in DIEPEMPMSK
if ep_ints.txfe() {
// SAFETY: DIEPEMPMSK is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.diepempmsk().modify(|w| {
w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
});
@ -172,8 +157,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
macro_rules! config_ulpi_pins {
($($pin:ident),*) => {
into_ref!($($pin),*);
// NOTE(unsafe) Exclusive access to the registers
critical_section::with(|_| unsafe {
critical_section::with(|_| {
$(
$pin.set_as_af($pin.af_num(), AFType::OutputPushPull);
#[cfg(gpio_v2)]
@ -291,17 +275,15 @@ impl<'d, T: Instance> Driver<'d, T> {
/// Endpoint allocation will fail if it is too small.
pub fn new_fs(
_peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dp: impl Peripheral<P = impl DpPin<T>> + 'd,
dm: impl Peripheral<P = impl DmPin<T>> + 'd,
ep_out_buffer: &'d mut [u8],
) -> Self {
into_ref!(dp, dm);
unsafe {
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
}
dp.set_as_af(dp.af_num(), AFType::OutputPushPull);
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
Self {
phantom: PhantomData,
@ -322,7 +304,7 @@ impl<'d, T: Instance> Driver<'d, T> {
/// Endpoint allocation will fail if it is too small.
pub fn new_hs_ulpi(
_peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<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,
@ -508,18 +490,15 @@ pub struct Bus<'d, T: Instance> {
impl<'d, T: Instance> Bus<'d, T> {
fn restore_irqs() {
// SAFETY: atomic write
unsafe {
T::regs().gintmsk().write(|w| {
w.set_usbrst(true);
w.set_enumdnem(true);
w.set_usbsuspm(true);
w.set_wuim(true);
w.set_iepint(true);
w.set_oepint(true);
w.set_rxflvlm(true);
});
}
T::regs().gintmsk().write(|w| {
w.set_usbrst(true);
w.set_enumdnem(true);
w.set_usbsuspm(true);
w.set_wuim(true);
w.set_iepint(true);
w.set_oepint(true);
w.set_rxflvlm(true);
});
}
}
@ -533,8 +512,7 @@ impl<'d, T: Instance> Bus<'d, T> {
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
// SAFETY: register is exclusive to `Bus` with `&mut self`
unsafe { r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)) };
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words;
@ -549,13 +527,10 @@ impl<'d, T: Instance> Bus<'d, T> {
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
// SAFETY: register is exclusive to `Bus` with `&mut self`
unsafe {
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
}
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
fifo_top += ep.fifo_size_words;
}
@ -575,8 +550,7 @@ impl<'d, T: Instance> Bus<'d, T> {
// Configure IN endpoints
for (index, ep) in self.ep_in.iter().enumerate() {
if let Some(ep) = ep {
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.diepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@ -593,8 +567,7 @@ impl<'d, T: Instance> Bus<'d, T> {
// Configure OUT endpoints
for (index, ep) in self.ep_out.iter().enumerate() {
if let Some(ep) = ep {
// SAFETY: DOEPCTL/DOEPTSIZ is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.doepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
@ -618,26 +591,21 @@ impl<'d, T: Instance> Bus<'d, T> {
}
// Enable IRQs for allocated endpoints
// SAFETY: register is exclusive to `Bus` with `&mut self`
unsafe {
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
fn disable(&mut self) {
unsafe { T::Interrupt::steal() }.disable();
T::Interrupt::disable();
<T as RccPeripheral>::disable();
#[cfg(stm32l4)]
unsafe {
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
}
@ -653,7 +621,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
T::state().bus_waker.register(cx.waker());
let ints = unsafe { r.gintsts().read() };
let ints = r.gintsts().read();
if ints.usbrst() {
trace!("reset");
@ -661,34 +629,27 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
self.configure_endpoints();
// Reset address
// SAFETY: DCFG is shared with `ControlPipe` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.dcfg().modify(|w| {
w.set_dad(0);
});
});
// SAFETY: atomic clear on rc_w1 register
unsafe { r.gintsts().write(|w| w.set_usbrst(true)) }; // clear
r.gintsts().write(|w| w.set_usbrst(true)); // clear
Self::restore_irqs();
}
if ints.enumdne() {
trace!("enumdne");
// SAFETY: atomic read with no side effects
let speed = unsafe { r.dsts().read().enumspd() };
let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.0);
// SAFETY: register is only accessed by `Bus` under `&mut self`
unsafe {
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
})
};
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
// SAFETY: atomic clear on rc_w1 register
unsafe { r.gintsts().write(|w| w.set_enumdne(true)) }; // clear
r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Reset);
@ -696,16 +657,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
if ints.usbsusp() {
trace!("suspend");
// SAFETY: atomic clear on rc_w1 register
unsafe { r.gintsts().write(|w| w.set_usbsusp(true)) }; // clear
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Suspend);
}
if ints.wkupint() {
trace!("resume");
// SAFETY: atomic clear on rc_w1 register
unsafe { r.gintsts().write(|w| w.set_wkupint(true)) }; // clear
r.gintsts().write(|w| w.set_wkupint(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Resume);
}
@ -727,8 +686,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => {
// SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
regs.doepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
@ -737,8 +695,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
regs.diepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
@ -758,10 +715,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
let regs = T::regs();
// SAFETY: atomic read with no side effects
match ep_addr.direction() {
Direction::Out => unsafe { regs.doepctl(ep_addr.index()).read().stall() },
Direction::In => unsafe { regs.diepctl(ep_addr.index()).read().stall() },
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
}
}
@ -777,8 +733,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
let r = T::regs();
match ep_addr.direction() {
Direction::Out => {
// SAFETY: DOEPCTL is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
r.doepctl(ep_addr.index()).modify(|w| {
@ -796,8 +751,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
@ -820,172 +774,193 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn enable(&mut self) {
trace!("enable");
// SAFETY: registers are only accessed by `Bus` under `&mut self`
unsafe {
#[cfg(stm32l4)]
{
crate::peripherals::PWR::enable();
critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
}
#[cfg(stm32h7)]
{
// If true, VDD33USB is generated by internal regulator from VDD50USB
// If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
// TODO: unhardcode
let internal_regulator = false;
// Enable USB power
critical_section::with(|_| {
crate::pac::PWR.cr3().modify(|w| {
w.set_usb33den(true);
w.set_usbregen(internal_regulator);
})
});
// Wait for USB power to stabilize
while !crate::pac::PWR.cr3().read().usb33rdy() {}
// Use internal 48MHz HSI clock. Should be enabled in RCC by default.
critical_section::with(|_| {
crate::pac::RCC
.d2ccip2r()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
});
// Enable ULPI clock if external PHY is used
let ulpien = !self.phy_type.internal();
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hs_ulpien(ulpien);
} else {
w.set_usb_otg_fs_ulpien(ulpien);
}
});
crate::pac::RCC.ahb1lpenr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hs_ulpilpen(ulpien);
} else {
w.set_usb_otg_fs_ulpilpen(ulpien);
}
});
});
}
#[cfg(stm32u5)]
{
// Enable USB power
critical_section::with(|_| {
crate::pac::RCC.ahb3enr().modify(|w| {
w.set_pwren(true);
});
cortex_m::asm::delay(2);
crate::pac::PWR.svmcr().modify(|w| {
w.set_usv(true);
w.set_uvmen(true);
});
});
// Wait for USB power to stabilize
while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
// Select HSI48 as USB clock source.
critical_section::with(|_| {
crate::pac::RCC.ccipr1().modify(|w| {
w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
})
});
}
<T as RccPeripheral>::enable();
<T as RccPeripheral>::reset();
T::Interrupt::steal().unpend();
T::Interrupt::steal().enable();
let r = T::regs();
let core_id = r.cid().read().0;
info!("Core id {:08x}", core_id);
// Wait for AHB ready.
while !r.grstctl().read().ahbidl() {}
// Configure as device.
r.gusbcfg().write(|w| {
// Force device mode
w.set_fdmod(true);
// Enable internal full-speed PHY
w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
});
// Configuring Vbus sense and SOF output
match core_id {
0x0000_1200 | 0x0000_1100 => {
assert!(self.phy_type != PhyType::InternalHighSpeed);
r.gccfg_v1().modify(|w| {
// Enable internal full-speed PHY, logic is inverted
w.set_pwrdwn(self.phy_type.internal());
});
// F429-like chips have the GCCFG.NOVBUSSENS bit
r.gccfg_v1().modify(|w| {
w.set_novbussens(true);
w.set_vbusasen(false);
w.set_vbusbsen(false);
w.set_sofouten(false);
});
}
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
// F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
r.gccfg_v2().modify(|w| {
// Enable internal full-speed PHY, logic is inverted
w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
});
r.gccfg_v2().modify(|w| {
w.set_vbden(false);
});
// Force B-peripheral session
r.gotgctl().modify(|w| {
w.set_bvaloen(true);
w.set_bvaloval(true);
});
}
_ => unimplemented!("Unknown USB core id {:X}", core_id),
}
// Soft disconnect.
r.dctl().write(|w| w.set_sdis(true));
// Set speed.
r.dcfg().write(|w| {
w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
w.set_dspd(self.phy_type.to_dspd());
});
// Unmask transfer complete EP interrupt
r.diepmsk().write(|w| {
w.set_xfrcm(true);
});
// Unmask and clear core interrupts
Bus::<T>::restore_irqs();
r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
// Unmask global interrupt
r.gahbcfg().write(|w| {
w.set_gint(true); // unmask global interrupt
});
// Connect
r.dctl().write(|w| w.set_sdis(false));
#[cfg(stm32l4)]
{
crate::peripherals::PWR::enable();
critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
}
#[cfg(stm32f7)]
{
// Enable ULPI clock if external PHY is used
let ulpien = !self.phy_type.internal();
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hsulpien(ulpien);
} else {
w.set_usb_otg_hsen(ulpien);
}
});
// Low power mode
crate::pac::RCC.ahb1lpenr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hsulpilpen(ulpien);
} else {
w.set_usb_otg_hslpen(ulpien);
}
});
});
}
#[cfg(stm32h7)]
{
// If true, VDD33USB is generated by internal regulator from VDD50USB
// If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
// TODO: unhardcode
let internal_regulator = false;
// Enable USB power
critical_section::with(|_| {
crate::pac::PWR.cr3().modify(|w| {
w.set_usb33den(true);
w.set_usbregen(internal_regulator);
})
});
// Wait for USB power to stabilize
while !crate::pac::PWR.cr3().read().usb33rdy() {}
// Use internal 48MHz HSI clock. Should be enabled in RCC by default.
critical_section::with(|_| {
crate::pac::RCC
.d2ccip2r()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
});
// Enable ULPI clock if external PHY is used
let ulpien = !self.phy_type.internal();
critical_section::with(|_| {
crate::pac::RCC.ahb1enr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hs_ulpien(ulpien);
} else {
w.set_usb_otg_fs_ulpien(ulpien);
}
});
crate::pac::RCC.ahb1lpenr().modify(|w| {
if T::HIGH_SPEED {
w.set_usb_otg_hs_ulpilpen(ulpien);
} else {
w.set_usb_otg_fs_ulpilpen(ulpien);
}
});
});
}
#[cfg(stm32u5)]
{
// Enable USB power
critical_section::with(|_| {
crate::pac::RCC.ahb3enr().modify(|w| {
w.set_pwren(true);
});
cortex_m::asm::delay(2);
crate::pac::PWR.svmcr().modify(|w| {
w.set_usv(true);
w.set_uvmen(true);
});
});
// Wait for USB power to stabilize
while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
// Select HSI48 as USB clock source.
critical_section::with(|_| {
crate::pac::RCC.ccipr1().modify(|w| {
w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
})
});
}
<T as RccPeripheral>::enable();
<T as RccPeripheral>::reset();
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
let r = T::regs();
let core_id = r.cid().read().0;
info!("Core id {:08x}", core_id);
// Wait for AHB ready.
while !r.grstctl().read().ahbidl() {}
// Configure as device.
r.gusbcfg().write(|w| {
// Force device mode
w.set_fdmod(true);
// Enable internal full-speed PHY
w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
});
// Configuring Vbus sense and SOF output
match core_id {
0x0000_1200 | 0x0000_1100 => {
assert!(self.phy_type != PhyType::InternalHighSpeed);
r.gccfg_v1().modify(|w| {
// Enable internal full-speed PHY, logic is inverted
w.set_pwrdwn(self.phy_type.internal());
});
// F429-like chips have the GCCFG.NOVBUSSENS bit
r.gccfg_v1().modify(|w| {
w.set_novbussens(true);
w.set_vbusasen(false);
w.set_vbusbsen(false);
w.set_sofouten(false);
});
}
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
// F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
r.gccfg_v2().modify(|w| {
// Enable internal full-speed PHY, logic is inverted
w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
});
r.gccfg_v2().modify(|w| {
w.set_vbden(false);
});
// Force B-peripheral session
r.gotgctl().modify(|w| {
w.set_bvaloen(true);
w.set_bvaloval(true);
});
}
_ => unimplemented!("Unknown USB core id {:X}", core_id),
}
// Soft disconnect.
r.dctl().write(|w| w.set_sdis(true));
// Set speed.
r.dcfg().write(|w| {
w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
w.set_dspd(self.phy_type.to_dspd());
});
// Unmask transfer complete EP interrupt
r.diepmsk().write(|w| {
w.set_xfrcm(true);
});
// Unmask and clear core interrupts
Bus::<T>::restore_irqs();
r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
// Unmask global interrupt
r.gahbcfg().write(|w| {
w.set_gint(true); // unmask global interrupt
});
// Connect
r.dctl().write(|w| w.set_sdis(false));
self.enabled = true;
}
@ -1042,8 +1017,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> {
T::state().ep_in_wakers[ep_index].register(cx.waker());
// SAFETY: atomic read without side effects
if unsafe { T::regs().diepctl(ep_index).read().usbaep() } {
if T::regs().diepctl(ep_index).read().usbaep() {
Poll::Ready(())
} else {
Poll::Pending
@ -1064,8 +1038,7 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
T::state().ep_out_wakers[ep_index].register(cx.waker());
// SAFETY: atomic read without side effects
if unsafe { T::regs().doepctl(ep_index).read().usbaep() } {
if T::regs().doepctl(ep_index).read().usbaep() {
Poll::Ready(())
} else {
Poll::Pending
@ -1100,8 +1073,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
// Release buffer
state.ep_out_size[index].store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
// SAFETY: DOEPCTL/DOEPTSIZ is shared with `Bus` so a critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
// Receive 1 packet
T::regs().doeptsiz(index).modify(|w| {
w.set_xfrsiz(self.info.max_packet_size as _);
@ -1139,8 +1111,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
poll_fn(|cx| {
state.ep_in_wakers[index].register(cx.waker());
// SAFETY: atomic read with no side effects
let diepctl = unsafe { r.diepctl(index).read() };
let diepctl = r.diepctl(index).read();
if !diepctl.usbaep() {
Poll::Ready(Err(EndpointError::Disabled))
} else if !diepctl.epena() {
@ -1157,12 +1128,10 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
let size_words = (buf.len() + 3) / 4;
// SAFETY: atomic read with no side effects
let fifo_space = unsafe { r.dtxfsts(index).read().ineptfsav() as usize };
let fifo_space = r.dtxfsts(index).read().ineptfsav() as usize;
if size_words > fifo_space {
// Not enough space in fifo, enable tx fifo empty interrupt
// SAFETY: DIEPEMPMSK is shared with IRQ so critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
r.diepempmsk().modify(|w| {
w.set_ineptxfem(w.ineptxfem() | (1 << index));
});
@ -1178,18 +1147,14 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
.await
}
// SAFETY: DIEPTSIZ is exclusive to this endpoint under `&mut self`
unsafe {
// Setup transfer size
r.dieptsiz(index).write(|w| {
w.set_mcnt(1);
w.set_pktcnt(1);
w.set_xfrsiz(buf.len() as _);
});
}
// Setup transfer size
r.dieptsiz(index).write(|w| {
w.set_mcnt(1);
w.set_pktcnt(1);
w.set_xfrsiz(buf.len() as _);
});
// SAFETY: DIEPCTL is shared with `Bus` so a critical section is needed for RMW
critical_section::with(|_| unsafe {
critical_section::with(|_| {
// Enable endpoint
r.diepctl(index).modify(|w| {
w.set_cnak(true);
@ -1201,8 +1166,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
for chunk in buf.chunks(4) {
let mut tmp = [0u8; 4];
tmp[0..chunk.len()].copy_from_slice(chunk);
// SAFETY: FIFO is exclusive to this endpoint under `&mut self`
unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) };
r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
}
trace!("write done ep={:?}", self.info.addr);
@ -1234,17 +1198,15 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
state.ep0_setup_ready.store(false, Ordering::Release);
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
unsafe {
// Receive 1 SETUP packet
T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
w.set_rxdpid_stupcnt(1);
});
// Receive 1 SETUP packet
T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
w.set_rxdpid_stupcnt(1);
});
// Clear NAK to indicate we are ready to receive more data
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
w.set_cnak(true);
});
}
// Clear NAK to indicate we are ready to receive more data
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
w.set_cnak(true);
});
trace!("SETUP received: {:?}", data);
Poll::Ready(data)
@ -1289,20 +1251,18 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
trace!("control: reject");
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section
unsafe {
let regs = T::regs();
regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
w.set_stall(true);
});
regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
w.set_stall(true);
});
}
let regs = T::regs();
regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
w.set_stall(true);
});
regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
w.set_stall(true);
});
}
async fn accept_set_address(&mut self, addr: u8) {
trace!("setting addr: {}", addr);
critical_section::with(|_| unsafe {
critical_section::with(|_| {
T::regs().dcfg().modify(|w| {
w.set_dad(addr);
});

View File

@ -48,11 +48,9 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
let rl = reload_value(psc, timeout_us);
let wdg = T::regs();
unsafe {
wdg.kr().write(|w| w.set_key(Key::ENABLE));
wdg.pr().write(|w| w.set_pr(Pr(pr)));
wdg.rlr().write(|w| w.set_rl(rl));
}
wdg.kr().write(|w| w.set_key(Key::ENABLE));
wdg.pr().write(|w| w.set_pr(Pr(pr)));
wdg.rlr().write(|w| w.set_rl(rl));
trace!(
"Watchdog configured with {}us timeout, desired was {}us (PR={}, RL={})",
@ -67,11 +65,11 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
}
}
pub unsafe fn unleash(&mut self) {
pub fn unleash(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::START));
}
pub unsafe fn pet(&mut self) {
pub fn pet(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::RESET));
}
}