for Temperature {
}
impl<'d, T: Instance> Adc<'d, T> {
- pub fn new(adc: impl Peripheral + 'd, delay: &mut impl DelayUs) -> Self {
+ pub fn new(adc: impl Peripheral + 'd) -> Self {
into_ref!(adc);
T::enable_and_reset();
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);
+ // for at least two ADC clock cycles.
+ blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1);
// Reset calibration
T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -70,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
// One cycle after calibration
- delay.delay_us((1_000_000) / Self::freq().0 + 1);
+ blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1);
Self {
adc,
@@ -95,7 +95,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
}
- pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref {
+ pub fn enable_vref(&self) -> Vref {
T::regs().cr2().modify(|reg| {
reg.set_tsvrefe(true);
});
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index c5581dba1..c22a3fe4a 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -3,8 +3,8 @@ use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::into_ref;
-use embedded_hal_02::blocking::delay::DelayUs;
+use super::blocking_delay_us;
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
use crate::interrupt::typelevel::Interrupt;
use crate::time::Hertz;
@@ -58,7 +58,6 @@ impl<'d, T: Instance> Adc<'d, T> {
pub fn new(
adc: impl Peripheral + 'd,
_irq: impl interrupt::typelevel::Binding> + 'd,
- delay: &mut impl DelayUs,
) -> Self {
use crate::pac::adc::vals;
@@ -71,7 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED));
// Wait for the regulator to stabilize
- delay.delay_us(10);
+ blocking_delay_us(10);
assert!(!T::regs().cr().read().aden());
@@ -81,8 +80,8 @@ impl<'d, T: Instance> Adc<'d, T> {
while T::regs().cr().read().adcal() {}
- // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
- delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
+ // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
+ blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1);
// Enable the adc
T::regs().cr().modify(|w| w.set_aden(true));
@@ -117,7 +116,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
}
- pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref {
+ pub fn enable_vref(&self) -> Vref {
T::common_regs().ccr().modify(|w| w.set_vrefen(true));
Vref {}
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
new file mode 100644
index 000000000..f6741f019
--- /dev/null
+++ b/embassy-stm32/src/adc/g4.rs
@@ -0,0 +1,304 @@
+#[allow(unused)]
+use pac::adc::vals::{Adcaldif, Difsel, Exten};
+use pac::adccommon::vals::Presc;
+
+use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
+use crate::time::Hertz;
+use crate::{pac, Peripheral};
+
+/// Default VREF voltage used for sample conversion to millivolts.
+pub const VREF_DEFAULT_MV: u32 = 3300;
+/// VREF voltage used for factory calibration of VREFINTCAL register.
+pub const VREF_CALIB_MV: u32 = 3300;
+
+/// Max single ADC operation clock frequency
+#[cfg(stm32g4)]
+const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
+#[cfg(stm32h7)]
+const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
+
+#[cfg(stm32g4)]
+const VREF_CHANNEL: u8 = 18;
+#[cfg(stm32g4)]
+const TEMP_CHANNEL: u8 = 16;
+
+#[cfg(stm32h7)]
+const VREF_CHANNEL: u8 = 19;
+#[cfg(stm32h7)]
+const TEMP_CHANNEL: u8 = 18;
+
+// TODO this should be 14 for H7a/b/35
+const VBAT_CHANNEL: u8 = 17;
+
+// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
+/// Internal voltage reference channel.
+pub struct VrefInt;
+impl InternalChannel for VrefInt {}
+impl super::SealedInternalChannel for VrefInt {
+ fn channel(&self) -> u8 {
+ VREF_CHANNEL
+ }
+}
+
+/// Internal temperature channel.
+pub struct Temperature;
+impl InternalChannel for Temperature {}
+impl super::SealedInternalChannel for Temperature {
+ fn channel(&self) -> u8 {
+ TEMP_CHANNEL
+ }
+}
+
+/// Internal battery voltage channel.
+pub struct Vbat;
+impl InternalChannel for Vbat {}
+impl super::SealedInternalChannel for Vbat {
+ fn channel(&self) -> u8 {
+ VBAT_CHANNEL
+ }
+}
+
+// NOTE (unused): The prescaler enum closely copies the hardware capabilities,
+// but high prescaling doesn't make a lot of sense in the current implementation and is ommited.
+#[allow(unused)]
+enum Prescaler {
+ NotDivided,
+ DividedBy2,
+ DividedBy4,
+ DividedBy6,
+ DividedBy8,
+ DividedBy10,
+ DividedBy12,
+ DividedBy16,
+ DividedBy32,
+ DividedBy64,
+ DividedBy128,
+ DividedBy256,
+}
+
+impl Prescaler {
+ fn from_ker_ck(frequency: Hertz) -> Self {
+ let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
+ match raw_prescaler {
+ 0 => Self::NotDivided,
+ 1 => Self::DividedBy2,
+ 2..=3 => Self::DividedBy4,
+ 4..=5 => Self::DividedBy6,
+ 6..=7 => Self::DividedBy8,
+ 8..=9 => Self::DividedBy10,
+ 10..=11 => Self::DividedBy12,
+ _ => unimplemented!(),
+ }
+ }
+
+ fn divisor(&self) -> u32 {
+ match self {
+ Prescaler::NotDivided => 1,
+ Prescaler::DividedBy2 => 2,
+ Prescaler::DividedBy4 => 4,
+ Prescaler::DividedBy6 => 6,
+ Prescaler::DividedBy8 => 8,
+ Prescaler::DividedBy10 => 10,
+ Prescaler::DividedBy12 => 12,
+ Prescaler::DividedBy16 => 16,
+ Prescaler::DividedBy32 => 32,
+ Prescaler::DividedBy64 => 64,
+ Prescaler::DividedBy128 => 128,
+ Prescaler::DividedBy256 => 256,
+ }
+ }
+
+ fn presc(&self) -> Presc {
+ match self {
+ Prescaler::NotDivided => Presc::DIV1,
+ Prescaler::DividedBy2 => Presc::DIV2,
+ Prescaler::DividedBy4 => Presc::DIV4,
+ Prescaler::DividedBy6 => Presc::DIV6,
+ Prescaler::DividedBy8 => Presc::DIV8,
+ Prescaler::DividedBy10 => Presc::DIV10,
+ Prescaler::DividedBy12 => Presc::DIV12,
+ Prescaler::DividedBy16 => Presc::DIV16,
+ Prescaler::DividedBy32 => Presc::DIV32,
+ Prescaler::DividedBy64 => Presc::DIV64,
+ Prescaler::DividedBy128 => Presc::DIV128,
+ Prescaler::DividedBy256 => Presc::DIV256,
+ }
+ }
+}
+
+impl<'d, T: Instance> Adc<'d, T> {
+ /// Create a new ADC driver.
+ pub fn new(adc: impl Peripheral + 'd) -> Self {
+ embassy_hal_internal::into_ref!(adc);
+ T::enable_and_reset();
+
+ let prescaler = Prescaler::from_ker_ck(T::frequency());
+
+ 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);
+
+ if frequency > MAX_ADC_CLK_FREQ {
+ panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 );
+ }
+
+ let mut s = Self {
+ adc,
+ sample_time: SampleTime::from_bits(0),
+ };
+ s.power_up();
+ s.configure_differential_inputs();
+
+ s.calibrate();
+ blocking_delay_us(1);
+
+ s.enable();
+ s.configure();
+
+ s
+ }
+
+ fn power_up(&mut self) {
+ T::regs().cr().modify(|reg| {
+ reg.set_deeppwd(false);
+ reg.set_advregen(true);
+ });
+
+ blocking_delay_us(10);
+ }
+
+ fn configure_differential_inputs(&mut self) {
+ T::regs().difsel().modify(|w| {
+ for n in 0..20 {
+ w.set_difsel(n, Difsel::SINGLEENDED);
+ }
+ });
+ }
+
+ fn calibrate(&mut self) {
+ T::regs().cr().modify(|w| {
+ w.set_adcaldif(Adcaldif::SINGLEENDED);
+ });
+
+ T::regs().cr().modify(|w| w.set_adcal(true));
+
+ while T::regs().cr().read().adcal() {}
+ }
+
+ fn enable(&mut self) {
+ 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
+ T::regs().cfgr().modify(|w| {
+ w.set_cont(false);
+ w.set_exten(Exten::DISABLED);
+ });
+ }
+
+ /// Enable reading the voltage reference internal channel.
+ pub fn enable_vrefint(&self) -> VrefInt {
+ T::common_regs().ccr().modify(|reg| {
+ reg.set_vrefen(true);
+ });
+
+ VrefInt {}
+ }
+
+ /// Enable reading the temperature internal channel.
+ pub fn enable_temperature(&self) -> Temperature {
+ T::common_regs().ccr().modify(|reg| {
+ reg.set_vsenseen(true);
+ });
+
+ Temperature {}
+ }
+
+ /// Enable reading the vbat internal channel.
+ pub fn enable_vbat(&self) -> Vbat {
+ T::common_regs().ccr().modify(|reg| {
+ reg.set_vbaten(true);
+ });
+
+ Vbat {}
+ }
+
+ /// Set the ADC sample time.
+ pub fn set_sample_time(&mut self, sample_time: SampleTime) {
+ self.sample_time = sample_time;
+ }
+
+ /// Set the ADC resolution.
+ pub fn set_resolution(&mut self, resolution: Resolution) {
+ T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
+ }
+
+ /// Perform a single conversion.
+ fn convert(&mut self) -> u16 {
+ T::regs().isr().modify(|reg| {
+ reg.set_eos(true);
+ reg.set_eoc(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
+ }
+
+ /// Read an ADC pin.
+ pub fn read
(&mut self, pin: &mut P) -> u16
+ where
+ P: AdcPin,
+ P: crate::gpio::Pin,
+ {
+ pin.set_as_analog();
+
+ self.read_channel(pin.channel())
+ }
+
+ /// Read an ADC internal channel.
+ pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 {
+ self.read_channel(channel.channel())
+ }
+
+ fn read_channel(&mut self, channel: u8) -> u16 {
+ // Configure channel
+ Self::set_channel_sample_time(channel, self.sample_time);
+
+ #[cfg(stm32h7)]
+ {
+ T::regs().cfgr2().modify(|w| w.set_lshift(0));
+ T::regs()
+ .pcsel()
+ .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
+ }
+
+ T::regs().sqr1().write(|reg| {
+ reg.set_sq(0, channel);
+ reg.set_l(0);
+ });
+
+ self.convert()
+ }
+
+ fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
+ let sample_time = sample_time.into();
+ if ch <= 9 {
+ T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time));
+ } else {
+ T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
+ }
+ }
+}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ead2357ce..12c5751bd 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -12,6 +12,7 @@
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")]
#[cfg_attr(adc_v4, path = "v4.rs")]
+#[cfg_attr(adc_g4, path = "g4.rs")]
mod _version;
#[allow(unused)]
@@ -69,14 +70,47 @@ trait SealedInternalChannel {
fn channel(&self) -> u8;
}
+/// Performs a busy-wait delay for a specified number of microseconds.
+#[allow(unused)]
+pub(crate) fn blocking_delay_us(us: u32) {
+ #[cfg(time)]
+ embassy_time::block_for(embassy_time::Duration::from_micros(us));
+ #[cfg(not(time))]
+ cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 * us / 1_000_000);
+}
+
/// ADC instance.
-#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))]
+#[cfg(not(any(
+ adc_f1,
+ adc_v1,
+ adc_l0,
+ adc_v2,
+ adc_v3,
+ adc_v4,
+ adc_g4,
+ adc_f3,
+ adc_f3_v1_1,
+ adc_g0,
+ adc_h5
+)))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::Peripheral {
type Interrupt: crate::interrupt::typelevel::Interrupt;
}
/// ADC instance.
-#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))]
+#[cfg(any(
+ adc_f1,
+ adc_v1,
+ adc_l0,
+ adc_v2,
+ adc_v3,
+ adc_v4,
+ adc_g4,
+ adc_f3,
+ adc_f3_v1_1,
+ adc_g0,
+ adc_h5
+))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::Peripheral
+ crate::rcc::RccPeripheral {
type Interrupt: crate::interrupt::typelevel::Interrupt;
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index e9b46be80..1dda28cf2 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -3,10 +3,10 @@ use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::into_ref;
-use embedded_hal_02::blocking::delay::DelayUs;
#[cfg(adc_l0)]
use stm32_metapac::adc::vals::Ckmode;
+use super::blocking_delay_us;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::interrupt::typelevel::Interrupt;
use crate::peripherals::ADC;
@@ -65,7 +65,6 @@ impl<'d, T: Instance> Adc<'d, T> {
pub fn new(
adc: impl Peripheral
+ 'd,
_irq: impl interrupt::typelevel::Binding> + 'd,
- delay: &mut impl DelayUs,
) -> Self {
into_ref!(adc);
T::enable_and_reset();
@@ -74,7 +73,7 @@ impl<'d, T: Instance> Adc<'d, T> {
//
// Table 57. ADC characteristics
// tstab = 14 * 1/fadc
- delay.delay_us(1);
+ blocking_delay_us(1);
// set default PCKL/2 on L0s because HSI is disabled in the default clock config
#[cfg(adc_l0)]
@@ -114,7 +113,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
#[cfg(not(adc_l0))]
- pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat {
+ pub fn enable_vbat(&self) -> Vbat {
// SMP must be ≥ 56 ADC clock cycles when using HSI14.
//
// 6.3.20 Vbat monitoring characteristics
@@ -123,22 +122,22 @@ impl<'d, T: Instance> Adc<'d, T> {
Vbat
}
- pub fn enable_vref(&self, delay: &mut impl DelayUs) -> Vref {
+ pub fn enable_vref(&self) -> Vref {
// Table 28. Embedded internal reference voltage
// tstart = 10μs
T::regs().ccr().modify(|reg| reg.set_vrefen(true));
- delay.delay_us(10);
+ blocking_delay_us(10);
Vref
}
- pub fn enable_temperature(&self, delay: &mut impl DelayUs) -> Temperature {
+ pub fn enable_temperature(&self) -> Temperature {
// SMP must be ≥ 56 ADC clock cycles when using HSI14.
//
// 6.3.19 Temperature sensor characteristics
// tstart ≤ 10μs
// ts_temp ≥ 4μs
T::regs().ccr().modify(|reg| reg.set_tsen(true));
- delay.delay_us(10);
+ blocking_delay_us(10);
Temperature
}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index a43eb72db..7771cf768 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,6 +1,6 @@
use embassy_hal_internal::into_ref;
-use embedded_hal_02::blocking::delay::DelayUs;
+use super::blocking_delay_us;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::peripherals::ADC1;
use crate::time::Hertz;
@@ -11,9 +11,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3300;
-/// ADC turn-on time
-pub const ADC_POWERUP_TIME_US: u32 = 3;
-
pub struct VrefInt;
impl AdcPin for VrefInt {}
impl super::SealedAdcPin for VrefInt {
@@ -97,7 +94,7 @@ impl<'d, T> Adc<'d, T>
where
T: Instance,
{
- pub fn new(adc: impl Peripheral + 'd, delay: &mut impl DelayUs) -> Self {
+ pub fn new(adc: impl Peripheral + 'd) -> Self {
into_ref!(adc);
T::enable_and_reset();
@@ -107,7 +104,7 @@ where
reg.set_adon(true);
});
- delay.delay_us(ADC_POWERUP_TIME_US);
+ blocking_delay_us(3);
Self {
adc,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 8c9b47197..4fd8558ba 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,7 +1,7 @@
use cfg_if::cfg_if;
use embassy_hal_internal::into_ref;
-use embedded_hal_02::blocking::delay::DelayUs;
+use super::blocking_delay_us;
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
use crate::Peripheral;
@@ -74,7 +74,7 @@ cfg_if! {
}
impl<'d, T: Instance> Adc<'d, T> {
- pub fn new(adc: impl Peripheral
+ 'd, delay: &mut impl DelayUs) -> Self {
+ pub fn new(adc: impl Peripheral + 'd) -> Self {
into_ref!(adc);
T::enable_and_reset();
T::regs().cr().modify(|reg| {
@@ -88,7 +88,7 @@ impl<'d, T: Instance> Adc<'d, T> {
reg.set_chselrmod(false);
});
- delay.delay_us(20);
+ blocking_delay_us(20);
T::regs().cr().modify(|reg| {
reg.set_adcal(true);
@@ -98,7 +98,7 @@ impl<'d, T: Instance> Adc<'d, T> {
// spin
}
- delay.delay_us(1);
+ blocking_delay_us(1);
Self {
adc,
@@ -106,7 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> {
}
}
- pub fn enable_vrefint(&self, delay: &mut impl DelayUs) -> VrefInt {
+ pub fn enable_vrefint(&self) -> VrefInt {
#[cfg(not(adc_g0))]
T::common_regs().ccr().modify(|reg| {
reg.set_vrefen(true);
@@ -117,10 +117,8 @@ impl<'d, T: Instance> Adc<'d, T> {
});
// "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.
- // TODO: delay 15us
- //cortex_m::asm::delay(20_000_000);
- delay.delay_us(15);
+ // to stabilize the internal voltage reference.
+ blocking_delay_us(15);
VrefInt {}
}
@@ -222,6 +220,13 @@ impl<'d, T: Instance> Adc<'d, T> {
// spin
}
+ // RM0492, RM0481, etc.
+ // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
+ #[cfg(adc_h5)]
+ if pin.channel() == 0 {
+ T::regs().or().modify(|reg| reg.set_op0(true));
+ }
+
// Configure channel
Self::set_channel_sample_time(pin.channel(), self.sample_time);
@@ -244,6 +249,13 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cr().modify(|reg| reg.set_addis(true));
+ // RM0492, RM0481, etc.
+ // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
+ #[cfg(adc_h5)]
+ if pin.channel() == 0 {
+ T::regs().or().modify(|reg| reg.set_op0(false));
+ }
+
val
}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 1ae25bea2..ca87b41ee 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -1,9 +1,8 @@
-use embedded_hal_02::blocking::delay::DelayUs;
#[allow(unused)]
use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel};
use pac::adccommon::vals::Presc;
-use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
+use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
use crate::time::Hertz;
use crate::{pac, Peripheral};
@@ -129,7 +128,7 @@ impl Prescaler {
impl<'d, T: Instance> Adc<'d, T> {
/// Create a new ADC driver.
- pub fn new(adc: impl Peripheral + 'd, delay: &mut impl DelayUs) -> Self {
+ pub fn new(adc: impl Peripheral + 'd) -> Self {
embassy_hal_internal::into_ref!(adc);
T::enable_and_reset();
@@ -161,11 +160,11 @@ impl<'d, T: Instance> Adc<'d, T> {
adc,
sample_time: SampleTime::from_bits(0),
};
- s.power_up(delay);
+ s.power_up();
s.configure_differential_inputs();
s.calibrate();
- delay.delay_us(1);
+ blocking_delay_us(1);
s.enable();
s.configure();
@@ -173,13 +172,13 @@ impl<'d, T: Instance> Adc<'d, T> {
s
}
- fn power_up(&mut self, delay: &mut impl DelayUs) {
+ fn power_up(&mut self) {
T::regs().cr().modify(|reg| {
reg.set_deeppwd(false);
reg.set_advregen(true);
});
- delay.delay_us(10);
+ blocking_delay_us(10);
}
fn configure_differential_inputs(&mut self) {
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index f8909d438..e8e0270af 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -32,6 +32,9 @@ impl<'d> Crc<'d> {
/// 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
+ #[cfg(not(crc_v1))]
+ PAC_CRC.dr32().write_value(word);
+ #[cfg(crc_v1)]
PAC_CRC.dr().write_value(word);
self.read()
}
@@ -39,6 +42,9 @@ impl<'d> Crc<'d> {
/// 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 {
+ #[cfg(not(crc_v1))]
+ PAC_CRC.dr32().write_value(*word);
+ #[cfg(crc_v1)]
PAC_CRC.dr().write_value(*word);
}
@@ -46,6 +52,12 @@ impl<'d> Crc<'d> {
}
/// Read the CRC result value.
+ #[cfg(not(crc_v1))]
+ pub fn read(&self) -> u32 {
+ PAC_CRC.dr32().read()
+ }
+ /// Read the CRC result value.
+ #[cfg(crc_v1)]
pub fn read(&self) -> u32 {
PAC_CRC.dr().read()
}
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index 46f5ea1be..13fb6778c 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -136,7 +136,7 @@ impl<'d> Crc<'d> {
/// Feeds a byte into the CRC peripheral. Returns the computed checksum.
pub fn feed_byte(&mut self, byte: u8) -> u32 {
PAC_CRC.dr8().write_value(byte);
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().read()
}
/// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
@@ -144,30 +144,30 @@ impl<'d> Crc<'d> {
for byte in bytes {
PAC_CRC.dr8().write_value(*byte);
}
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().read()
}
/// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
PAC_CRC.dr16().write_value(halfword);
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().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 {
PAC_CRC.dr16().write_value(*halfword);
}
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().read()
}
/// Feeds a words into the CRC peripheral. Returns the computed checksum.
pub fn feed_word(&mut self, word: u32) -> u32 {
- PAC_CRC.dr().write_value(word as u32);
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().write_value(word as u32);
+ PAC_CRC.dr32().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 {
- PAC_CRC.dr().write_value(*word as u32);
+ PAC_CRC.dr32().write_value(*word as u32);
}
- PAC_CRC.dr().read()
+ PAC_CRC.dr32().read()
}
}
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 8d5dae436..224d51b84 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -27,11 +27,11 @@ fn cpu_regs() -> pac::exti::Exti {
EXTI
}
-#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
+#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))]
fn exticr_regs() -> pac::syscfg::Syscfg {
pac::SYSCFG
}
-#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
+#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
fn exticr_regs() -> pac::exti::Exti {
EXTI
}
@@ -44,9 +44,9 @@ unsafe fn on_irq() {
#[cfg(feature = "low-power")]
crate::low_power::on_wakeup_irq();
- #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
+ #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
let bits = EXTI.pr(0).read().0;
- #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
+ #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
// We don't handle or change any EXTI lines above 16.
@@ -61,9 +61,9 @@ unsafe fn on_irq() {
}
// Clear pending
- #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
+ #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
EXTI.pr(0).write_value(Lines(bits));
- #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
+ #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
{
EXTI.rpr(0).write_value(Lines(bits));
EXTI.fpr(0).write_value(Lines(bits));
@@ -241,9 +241,9 @@ impl<'a> ExtiInputFuture<'a> {
EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
// clear pending bit
- #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
+ #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))]
EXTI.pr(0).write(|w| w.set_line(pin, true));
- #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
+ #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))]
{
EXTI.rpr(0).write(|w| w.set_line(pin, true));
EXTI.fpr(0).write(|w| w.set_line(pin, true));
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 00e61f2d2..90f13ff29 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -16,7 +16,7 @@ mod alt_regions {
use embassy_hal_internal::PeripheralRef;
use stm32_metapac::FLASH_SIZE;
- use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION};
+ use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3};
use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion};
use crate::peripherals::FLASH;
@@ -62,7 +62,6 @@ mod alt_regions {
pub bank2_region1: AltBank2Region1<'d, MODE>,
pub bank2_region2: AltBank2Region2<'d, MODE>,
pub bank2_region3: AltBank2Region3<'d, MODE>,
- pub otp_region: OTPRegion<'d, MODE>,
}
impl<'d> Flash<'d> {
@@ -79,7 +78,6 @@ mod alt_regions {
bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
- otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
}
}
@@ -96,7 +94,6 @@ mod alt_regions {
bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData),
bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData),
- otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData),
}
}
}
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index db05bef5d..5b15be261 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -55,7 +55,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
}
pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
- assert!(sector.bank != FlashBank::Otp);
assert!(sector.index_in_bank < 8);
while busy() {}
@@ -63,9 +62,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
interrupt::free(|_| {
pac::FLASH.nscr().modify(|w| {
w.set_bksel(match sector.bank {
- FlashBank::Bank1 => Bksel::B_0X0,
- FlashBank::Bank2 => Bksel::B_0X1,
- _ => unreachable!(),
+ FlashBank::Bank1 => Bksel::BANK1,
+ FlashBank::Bank2 => Bksel::BANK2,
});
w.set_snb(sector.index_in_bank);
w.set_ser(true);
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 1d8031e82..9d7861816 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -89,8 +89,6 @@ pub enum FlashBank {
Bank1 = 0,
/// Bank 2
Bank2 = 1,
- /// OTP region
- Otp,
}
#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 9079ddd41..d7235ac7f 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -49,6 +49,7 @@ pub struct Config {
pub sys: Sysclk,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
+ #[cfg(not(stm32u0))]
pub apb2_pre: APBPrescaler,
#[cfg(any(stm32wl5x, stm32wb))]
pub core2_ahb_pre: AHBPrescaler,
@@ -75,6 +76,7 @@ impl Default for Config {
sys: Sysclk::MSI,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
+ #[cfg(not(stm32u0))]
apb2_pre: APBPrescaler::DIV1,
#[cfg(any(stm32wl5x, stm32wb))]
core2_ahb_pre: AHBPrescaler::DIV1,
@@ -130,7 +132,7 @@ pub const WPAN_DEFAULT: Config = Config {
};
fn msi_enable(range: MSIRange) {
- #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
+ #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
RCC.cr().modify(|w| {
#[cfg(not(stm32wb))]
w.set_msirgsel(crate::pac::rcc::vals::Msirgsel::CR);
@@ -240,7 +242,7 @@ pub(crate) unsafe fn init(config: Config) {
let pll_input = PllInput {
hse,
hsi,
- #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
+ #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
msi,
};
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
@@ -254,6 +256,10 @@ pub(crate) unsafe fn init(config: Config) {
Sysclk::HSI => hsi.unwrap(),
Sysclk::MSI => msi.unwrap(),
Sysclk::PLL1_R => pll.r.unwrap(),
+ #[cfg(stm32u0)]
+ Sysclk::LSI | Sysclk::LSE => todo!(),
+ #[cfg(stm32u0)]
+ Sysclk::_RESERVED_6 | Sysclk::_RESERVED_7 => unreachable!(),
};
#[cfg(rcc_l4plus)]
@@ -263,6 +269,7 @@ pub(crate) unsafe fn init(config: Config) {
let hclk1 = sys_clk / config.ahb_pre;
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
+ #[cfg(not(stm32u0))]
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
#[cfg(any(stm32l4, stm32l5, stm32wlex))]
let hclk2 = hclk1;
@@ -315,6 +322,13 @@ pub(crate) unsafe fn init(config: Config) {
..=64_000_000 => 3,
_ => 4,
};
+ #[cfg(stm32u0)]
+ let latency = match hclk1.0 {
+ // VOS RANGE1, others TODO.
+ ..=24_000_000 => 0,
+ ..=48_000_000 => 1,
+ _ => 2,
+ };
#[cfg(stm32l1)]
FLASH.acr().write(|w| w.set_acc64(true));
@@ -326,7 +340,11 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| {
w.set_sw(config.sys);
w.set_hpre(config.ahb_pre);
+ #[cfg(stm32u0)]
+ w.set_ppre(config.apb1_pre);
+ #[cfg(not(stm32u0))]
w.set_ppre1(config.apb1_pre);
+ #[cfg(not(stm32u0))]
w.set_ppre2(config.apb2_pre);
});
while RCC.cfgr().read().sws() != config.sys {}
@@ -353,8 +371,10 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
hclk3: Some(hclk3),
pclk1: Some(pclk1),
+ #[cfg(not(stm32u0))]
pclk2: Some(pclk2),
pclk1_tim: Some(pclk1_tim),
+ #[cfg(not(stm32u0))]
pclk2_tim: Some(pclk2_tim),
#[cfg(stm32wl)]
pclk3: Some(hclk3),
@@ -408,7 +428,7 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz {
Hertz(32_768 * (1 << (range as u8 + 1)))
}
-#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
+#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
fn msirange_to_hertz(range: MSIRange) -> Hertz {
match range {
MSIRange::RANGE100K => Hertz(100_000),
@@ -521,7 +541,7 @@ mod pll {
}
}
-#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
+#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
mod pll {
use super::{pll_enable, PllInstance};
pub use crate::pac::rcc::vals::{
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index d8604e07e..4b22a099d 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -52,7 +52,7 @@ macro_rules! impl_peri {
};
}
-#[cfg(any(rcc_c0, rcc_g0))]
+#[cfg(any(rcc_c0, rcc_g0, rcc_u0))]
#[allow(unused_imports)]
use self::{McoSource as Mco1Source, McoSource as Mco2Source};
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d53d02203..a4e497fe7 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -25,7 +25,7 @@ pub use hsi48::*;
#[cfg_attr(stm32g0, path = "g0.rs")]
#[cfg_attr(stm32g4, path = "g4.rs")]
#[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")]
-#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")]
+#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
#[cfg_attr(stm32u5, path = "u5.rs")]
#[cfg_attr(stm32wba, path = "wba.rs")]
mod _version;
@@ -111,7 +111,7 @@ mod util {
}
}
-/// Get the kernel clocok frequency of the peripheral `T`.
+/// Get the kernel clock frequency of the peripheral `T`.
///
/// # Panics
///
@@ -119,3 +119,21 @@ mod util {
pub fn frequency() -> Hertz {
T::frequency()
}
+
+/// Enables and resets peripheral `T`.
+///
+/// # Safety
+///
+/// Peripheral must not be in use.
+pub unsafe fn enable_and_reset() {
+ T::enable_and_reset();
+}
+
+/// Disables peripheral `T`.
+///
+/// # Safety
+///
+/// Peripheral must not be in use.
+pub unsafe fn disable() {
+ T::disable();
+}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 0b38c4288..450975f18 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -735,18 +735,22 @@ trait RegsExt {
impl RegsExt for Regs {
fn tx_ptr(&self) -> *mut W {
- #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
+ #[cfg(any(spi_v1, spi_f1))]
let dr = self.dr();
+ #[cfg(spi_v2)]
+ let dr = self.dr16();
#[cfg(any(spi_v3, spi_v4, spi_v5))]
- let dr = self.txdr();
+ let dr = self.txdr32();
dr.as_ptr() as *mut W
}
fn rx_ptr(&self) -> *mut W {
- #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
+ #[cfg(any(spi_v1, spi_f1))]
let dr = self.dr();
+ #[cfg(spi_v2)]
+ let dr = self.dr16();
#[cfg(any(spi_v3, spi_v4, spi_v5))]
- let dr = self.rxdr();
+ let dr = self.rxdr32();
dr.as_ptr() as *mut W
}
}
@@ -815,11 +819,14 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
fn flush_rx_fifo(regs: Regs) {
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
while regs.sr().read().rxne() {
+ #[cfg(not(spi_v2))]
let _ = regs.dr().read();
+ #[cfg(spi_v2)]
+ let _ = regs.dr16().read();
}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while regs.sr().read().rxp() {
- let _ = regs.rxdr().read();
+ let _ = regs.rxdr32().read();
}
}
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index b0e7067bd..cabc06367 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -317,7 +317,7 @@ impl<'d, T: Instance> Driver<'d, T> {
///
/// # Arguments
///
- /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets.
+ /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_fs(
@@ -348,7 +348,7 @@ impl<'d, T: Instance> Driver<'d, T> {
///
/// # Arguments
///
- /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets.
+ /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
/// Must be large enough to fit all OUT endpoint max packet sizes.
/// Endpoint allocation will fail if it is too small.
pub fn new_hs_ulpi(
@@ -562,51 +562,29 @@ impl<'d, T: Instance> Bus<'d, T> {
fn init(&mut self) {
super::common_init::();
- #[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);
- }
- });
+ // Enable ULPI clock if external PHY is used
+ let _ulpien = !self.phy_type.internal();
- // 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(any(stm32f2, stm32f4, stm32f7))]
+ if T::HIGH_SPEED {
+ critical_section::with(|_| {
+ let rcc = crate::pac::RCC;
+ rcc.ahb1enr().modify(|w| w.set_usb_otg_hsulpien(_ulpien));
+ rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hsulpilpen(_ulpien));
});
}
#[cfg(stm32h7)]
- {
- // 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);
- }
- });
- });
- }
+ critical_section::with(|_| {
+ let rcc = crate::pac::RCC;
+ if T::HIGH_SPEED {
+ rcc.ahb1enr().modify(|w| w.set_usb_otg_hs_ulpien(_ulpien));
+ rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hs_ulpilpen(_ulpien));
+ } else {
+ rcc.ahb1enr().modify(|w| w.set_usb_otg_fs_ulpien(_ulpien));
+ rcc.ahb1lpenr().modify(|w| w.set_usb_otg_fs_ulpilpen(_ulpien));
+ }
+ });
let r = T::regs();
let core_id = r.cid().read().0;
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index e7db97ef7..3f6b39d8b 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+- Add `len`, `is_empty` and `is_full` functions to `Channel`.
+
## 0.5.0 - 2023-12-04
- Add a PriorityChannel.
@@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove unnecessary uses of `atomic-polyfill`
- Add `#[must_use]` to all futures.
-
## 0.1.0 - 2022-08-26
- First release
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 48f4dafd6..18be462cb 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -449,6 +449,18 @@ impl ChannelState {
Poll::Pending
}
}
+
+ fn len(&self) -> usize {
+ self.queue.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.queue.is_empty()
+ }
+
+ fn is_full(&self) -> bool {
+ self.queue.is_full()
+ }
}
/// A bounded channel for communicating between asynchronous tasks
@@ -572,6 +584,21 @@ where
pub fn try_receive(&self) -> Result {
self.lock(|c| c.try_receive())
}
+
+ /// Returns the number of elements currently in the channel.
+ pub fn len(&self) -> usize {
+ self.lock(|c| c.len())
+ }
+
+ /// Returns whether the channel is empty.
+ pub fn is_empty(&self) -> bool {
+ self.lock(|c| c.is_empty())
+ }
+
+ /// Returns whether the channel is full.
+ pub fn is_full(&self) -> bool {
+ self.lock(|c| c.is_full())
+ }
}
/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 72459d660..b48a408c4 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -3,6 +3,7 @@
//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
use core::cell::{RefCell, UnsafeCell};
use core::future::poll_fn;
+use core::mem;
use core::ops::{Deref, DerefMut};
use core::task::Poll;
@@ -134,6 +135,7 @@ where
/// successfully locked the mutex, and grants access to the contents.
///
/// Dropping it unlocks the mutex.
+#[clippy::has_significant_drop]
pub struct MutexGuard<'a, M, T>
where
M: RawMutex,
@@ -142,6 +144,25 @@ where
mutex: &'a Mutex,
}
+impl<'a, M, T> MutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ /// Returns a locked view over a portion of the locked data.
+ pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
+ let mutex = this.mutex;
+ let value = fun(unsafe { &mut *this.mutex.inner.get() });
+ // Don't run the `drop` method for MutexGuard. The ownership of the underlying
+ // locked state is being moved to the returned MappedMutexGuard.
+ mem::forget(this);
+ MappedMutexGuard {
+ state: &mutex.state,
+ value,
+ }
+ }
+}
+
impl<'a, M, T> Drop for MutexGuard<'a, M, T>
where
M: RawMutex,
@@ -180,3 +201,115 @@ where
unsafe { &mut *(self.mutex.inner.get()) }
}
}
+
+/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or
+/// [`MappedMutexGuard::map`].
+///
+/// This can be used to hold a subfield of the protected data.
+#[clippy::has_significant_drop]
+pub struct MappedMutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ state: &'a BlockingMutex>,
+ value: *mut T,
+}
+
+impl<'a, M, T> MappedMutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ /// Returns a locked view over a portion of the locked data.
+ pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
+ let state = this.state;
+ let value = fun(unsafe { &mut *this.value });
+ // Don't run the `drop` method for MutexGuard. The ownership of the underlying
+ // locked state is being moved to the returned MappedMutexGuard.
+ mem::forget(this);
+ MappedMutexGuard { state, value }
+ }
+}
+
+impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ // Safety: the MutexGuard represents exclusive access to the contents
+ // of the mutex, so it's OK to get it.
+ unsafe { &*self.value }
+ }
+}
+
+impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // Safety: the MutexGuard represents exclusive access to the contents
+ // of the mutex, so it's OK to get it.
+ unsafe { &mut *self.value }
+ }
+}
+
+impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T>
+where
+ M: RawMutex,
+ T: ?Sized,
+{
+ fn drop(&mut self) {
+ self.state.lock(|s| {
+ let mut s = unwrap!(s.try_borrow_mut());
+ s.locked = false;
+ s.waker.wake();
+ })
+ }
+}
+
+unsafe impl Send for MappedMutexGuard<'_, M, T>
+where
+ M: RawMutex + Sync,
+ T: Send + ?Sized,
+{
+}
+
+unsafe impl Sync for MappedMutexGuard<'_, M, T>
+where
+ M: RawMutex + Sync,
+ T: Sync + ?Sized,
+{
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::blocking_mutex::raw::NoopRawMutex;
+ use crate::mutex::{Mutex, MutexGuard};
+
+ #[futures_test::test]
+ async fn mapped_guard_releases_lock_when_dropped() {
+ let mutex: Mutex = Mutex::new([0, 1]);
+
+ {
+ let guard = mutex.lock().await;
+ assert_eq!(*guard, [0, 1]);
+ let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
+ assert_eq!(*mapped, 1);
+ *mapped = 2;
+ }
+
+ {
+ let guard = mutex.lock().await;
+ assert_eq!(*guard, [0, 2]);
+ let mut mapped = MutexGuard::map(guard, |this| &mut this[1]);
+ assert_eq!(*mapped, 2);
+ *mapped = 3;
+ }
+
+ assert_eq!(*mutex.lock().await, [0, 3]);
+ }
+}
diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md
index 8852b0358..b9fb12d94 100644
--- a/embassy-time-queue-driver/README.md
+++ b/embassy-time-queue-driver/README.md
@@ -4,5 +4,5 @@ This crate contains the driver trait used by the [`embassy-time`](https://crates
You should rarely need to use this crate directly. Only use it when implementing your own timer queue.
-There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and
+There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and
another in `embassy-executor` enabled by the `integrated-timers` feature.
diff --git a/embassy-time/README.md b/embassy-time/README.md
index f5d46df7b..6a4b049b4 100644
--- a/embassy-time/README.md
+++ b/embassy-time/README.md
@@ -5,7 +5,7 @@ Timekeeping, delays and timeouts.
Timekeeping is done with elapsed time since system boot. Time is represented in
ticks, where the tick rate is defined either by the driver (in the case of a fixed-rate
tick) or chosen by the user with a [tick rate](#tick-rate) feature. The chosen
-tick rate applies to everything in `embassy-time` and thus determines the maximum
+tick rate applies to everything in `embassy-time` and thus determines the maximum
timing resolution of (1 / tick_rate) seconds
.
Tick counts are 64 bits. The default tick rate of 1Mhz supports
diff --git a/embassy-usb/README.md b/embassy-usb/README.md
index d2adae4f5..400fc6695 100644
--- a/embassy-usb/README.md
+++ b/embassy-usb/README.md
@@ -34,8 +34,8 @@ They can be set in two ways:
- Via Cargo features: enable a feature like `-`. `name` must be in lowercase and
use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values
is available, check `Cargo.toml` for the list.
-- Via environment variables at build time: set the variable named `EMBASSY_USB_`. For example
-`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
+- Via environment variables at build time: set the variable named `EMBASSY_USB_`. For example
+`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`.
Any value can be set, unlike with Cargo features.
Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index c06107396..387b780de 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -38,11 +38,12 @@ pub struct Config<'a> {
/// Maximum packet size in bytes for the control endpoint 0.
///
- /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default
- /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in
- /// which case using a larger packet size may be more efficient.
+ /// Valid values depend on the speed at which the bus is enumerated.
+ /// - low speed: 8
+ /// - full speed: 8, 16, 32, or 64
+ /// - high speed: 64
///
- /// Default: 8 bytes
+ /// Default: 64 bytes
pub max_packet_size_0: u8,
/// Manufacturer name string descriptor.
diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md
index 3de3171cd..cd6c0bc84 100644
--- a/examples/boot/bootloader/stm32-dual-bank/README.md
+++ b/examples/boot/bootloader/stm32-dual-bank/README.md
@@ -2,16 +2,16 @@
## Overview
-This bootloader leverages `embassy-boot` to interact with the flash.
-This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
+This bootloader leverages `embassy-boot` to interact with the flash.
+This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series.
Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device.
Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions.
## Memory Configuration
-In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
-For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
+In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment.
+For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks.
### Symbol Definitions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 585349506..0f58f143c 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
-embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
+embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] }
embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
index c2fb143cd..a5a4186ea 100644
--- a/examples/stm32f0/src/bin/adc.rs
+++ b/examples/stm32f0/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC;
use embassy_stm32::{adc, bind_interrupts};
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
- let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
+ let mut adc = Adc::new(p.ADC, Irqs);
adc.set_sample_time(SampleTime::CYCLES71_5);
let mut pin = p.PA1;
- let mut vrefint = adc.enable_vref(&mut Delay);
+ let mut vrefint = adc.enable_vref();
let vrefint_sample = adc.read(&mut vrefint).await;
let convert_to_millivolts = |sample| {
// From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index e49951726..1c3f3991a 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -126,6 +126,11 @@ fn main() -> ! {
// Initialize and create handle for devicer peripherals
let _p = embassy_stm32::init(Default::default());
+ // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
+ // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
+ // In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt
+ // vector would work exactly the same.
+
// High-priority executor: USART1, priority level 6
interrupt::USART1.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 1440460a9..541ff159e 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
use embassy_stm32::adc::Adc;
use embassy_stm32::peripherals::ADC1;
use embassy_stm32::{adc, bind_interrupts};
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
- let mut adc = Adc::new(p.ADC1, &mut Delay);
+ let mut adc = Adc::new(p.ADC1);
let mut pin = p.PB1;
- let mut vrefint = adc.enable_vref(&mut Delay);
+ let mut vrefint = adc.enable_vref();
let vrefint_sample = adc.read(&mut vrefint).await;
let convert_to_millivolts = |sample| {
// From http://www.st.com/resource/en/datasheet/CD00161566.pdf
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 328447210..87830b416 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
let _p = embassy_stm32::init(Default::default());
+ // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
+ // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
+ // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
+ // vector would work exactly the same.
+
// High-priority executor: UART4, priority level 6
interrupt::UART4.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs
index bd126ce68..0528a9637 100644
--- a/examples/stm32f334/src/bin/adc.rs
+++ b/examples/stm32f334/src/bin/adc.rs
@@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC1;
use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config};
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! {
info!("create adc...");
- let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay);
+ let mut adc = Adc::new(p.ADC1, Irqs);
adc.set_sample_time(SampleTime::CYCLES601_5);
info!("enable vrefint...");
- let mut vrefint = adc.enable_vref(&mut Delay);
+ let mut vrefint = adc.enable_vref();
let mut temperature = adc.enable_temperature();
loop {
diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs
index a5c710aa2..2dbf1bdab 100644
--- a/examples/stm32f334/src/bin/opamp.rs
+++ b/examples/stm32f334/src/bin/opamp.rs
@@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain};
use embassy_stm32::peripherals::ADC2;
use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config};
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! {
info!("create adc...");
- let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay);
+ let mut adc = Adc::new(p.ADC2, Irqs);
let mut opamp = OpAmp::new(p.OPAMP2);
adc.set_sample_time(SampleTime::CYCLES601_5);
info!("enable vrefint...");
- let mut vrefint = adc.enable_vref(&mut Delay);
+ let mut vrefint = adc.enable_vref();
let mut temperature = adc.enable_temperature();
let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1);
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 699c29c05..9473b7b7f 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
info!("Hello World!");
let mut delay = Delay;
- let mut adc = Adc::new(p.ADC1, &mut delay);
+ let mut adc = Adc::new(p.ADC1);
let mut pin = p.PC1;
let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 328447210..87830b416 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
let _p = embassy_stm32::init(Default::default());
+ // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
+ // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
+ // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
+ // vector would work exactly the same.
+
// High-priority executor: UART4, priority level 6
interrupt::UART4.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index a799b4e72..d6e0be5ea 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -49,6 +49,7 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
let mut config = embassy_stm32::usb::Config::default();
+ // If the board you’re using doesn’t have the VBUS pin wired up correctly for detecting the USB bus voltage (e.g. on the f4 blackpill board), set this to false
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs
index a280a3b77..56ccb67b8 100644
--- a/examples/stm32f4/src/bin/ws2812_spi.rs
+++ b/examples/stm32f4/src/bin/ws2812_spi.rs
@@ -8,7 +8,7 @@
// If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA.
//
// Warning:
-// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
+// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn.
#![no_std]
#![no_main]
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index f8d7b691f..641157960 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -4,7 +4,7 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::Adc;
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
@@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
- let mut adc = Adc::new(p.ADC1, &mut Delay);
+ let mut adc = Adc::new(p.ADC1);
let mut pin = p.PA3;
let mut vrefint = adc.enable_vrefint();
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index ae64bc8e4..3de38cbd6 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -5,7 +5,7 @@ use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::Config;
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
@@ -28,8 +28,8 @@ async fn main(_spawner: Spawner) {
let mut p = embassy_stm32::init(config);
info!("Hello World!");
- let mut adc = Adc::new(p.ADC2, &mut Delay);
- adc.set_sample_time(SampleTime::CYCLES32_5);
+ let mut adc = Adc::new(p.ADC2);
+ adc.set_sample_time(SampleTime::CYCLES24_5);
loop {
let measured = adc.read(&mut p.PA7);
diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs
index a5594d10c..0009103d1 100644
--- a/examples/stm32h7/src/bin/adc.rs
+++ b/examples/stm32h7/src/bin/adc.rs
@@ -5,7 +5,7 @@ use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::Config;
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
@@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) {
info!("Hello World!");
- let mut adc = Adc::new(p.ADC3, &mut Delay);
+ let mut adc = Adc::new(p.ADC3);
adc.set_sample_time(SampleTime::CYCLES32_5);
diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs
index 73f8dd092..fcbb6c653 100644
--- a/examples/stm32h7/src/bin/multiprio.rs
+++ b/examples/stm32h7/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
let _p = embassy_stm32::init(Default::default());
+ // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
+ // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
+ // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
+ // vector would work exactly the same.
+
// High-priority executor: UART4, priority level 6
interrupt::UART4.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs
index 97d41ca4b..507c3204a 100644
--- a/examples/stm32l0/src/bin/adc.rs
+++ b/examples/stm32l0/src/bin/adc.rs
@@ -6,7 +6,7 @@ use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC;
use embassy_stm32::{adc, bind_interrupts};
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default());
info!("Hello World!");
- let mut adc = Adc::new(p.ADC, Irqs, &mut Delay);
+ let mut adc = Adc::new(p.ADC, Irqs);
adc.set_sample_time(SampleTime::CYCLES79_5);
let mut pin = p.PA1;
- let mut vrefint = adc.enable_vref(&mut Delay);
+ let mut vrefint = adc.enable_vref();
let vrefint_sample = adc.read(&mut vrefint).await;
let convert_to_millivolts = |sample| {
// From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index a9f4604aa..7a89334e0 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -4,7 +4,6 @@
use defmt::*;
use embassy_stm32::adc::{Adc, Resolution};
use embassy_stm32::Config;
-use embassy_time::Delay;
use {defmt_rtt as _, panic_probe as _};
#[cortex_m_rt::entry]
@@ -18,7 +17,7 @@ fn main() -> ! {
}
let p = embassy_stm32::init(config);
- let mut adc = Adc::new(p.ADC1, &mut Delay);
+ let mut adc = Adc::new(p.ADC1);
//adc.enable_vref();
adc.set_resolution(Resolution::BITS8);
let mut channel = p.PC0;
diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml
new file mode 100644
index 000000000..688347084
--- /dev/null
+++ b/examples/stm32u0/.cargo/config.toml
@@ -0,0 +1,9 @@
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+# replace stm32u083rctx with your chip as listed in `probe-rs chip list`
+runner = "probe-rs run --chip stm32u083rctx"
+
+[build]
+target = "thumbv6m-none-eabi"
+
+[env]
+DEFMT_LOG = "trace"
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
new file mode 100644
index 000000000..495be3e75
--- /dev/null
+++ b/examples/stm32u0/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+edition = "2021"
+name = "embassy-stm32u0-examples"
+version = "0.1.0"
+license = "MIT OR Apache-2.0"
+
+[dependencies]
+# Change stm32u083rc to your chip name, if necessary.
+embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] }
+embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
+embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
+embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
+
+defmt = "0.3"
+defmt-rtt = "0.4"
+
+cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
+cortex-m-rt = "0.7.0"
+embedded-hal = "0.2.6"
+panic-probe = { version = "0.3", features = ["print-defmt"] }
+futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
+heapless = { version = "0.8", default-features = false }
+
+[profile.release]
+debug = 2
diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32u0/build.rs
@@ -0,0 +1,5 @@
+fn main() {
+ println!("cargo:rustc-link-arg-bins=--nmagic");
+ println!("cargo:rustc-link-arg-bins=-Tlink.x");
+ println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
+}
diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs
new file mode 100644
index 000000000..90e479aae
--- /dev/null
+++ b/examples/stm32u0/src/bin/blinky.rs
@@ -0,0 +1,26 @@
+#![no_std]
+#![no_main]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::gpio::{Level, Output, Speed};
+use embassy_time::Timer;
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+ let p = embassy_stm32::init(Default::default());
+ info!("Hello World!");
+
+ let mut led = Output::new(p.PA5, Level::High, Speed::Low);
+
+ loop {
+ info!("high");
+ led.set_high();
+ Timer::after_millis(300).await;
+
+ info!("low");
+ led.set_low();
+ Timer::after_millis(300).await;
+ }
+}
diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs
new file mode 100644
index 000000000..8017f0274
--- /dev/null
+++ b/examples/stm32u0/src/bin/button.rs
@@ -0,0 +1,24 @@
+#![no_std]
+#![no_main]
+
+use cortex_m_rt::entry;
+use defmt::*;
+use embassy_stm32::gpio::{Input, Pull};
+use {defmt_rtt as _, panic_probe as _};
+
+#[entry]
+fn main() -> ! {
+ info!("Hello World!");
+
+ let p = embassy_stm32::init(Default::default());
+
+ let button = Input::new(p.PC13, Pull::Up);
+
+ loop {
+ if button.is_high() {
+ info!("high");
+ } else {
+ info!("low");
+ }
+ }
+}
diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs
new file mode 100644
index 000000000..34a08bbc6
--- /dev/null
+++ b/examples/stm32u0/src/bin/button_exti.rs
@@ -0,0 +1,25 @@
+#![no_std]
+#![no_main]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::exti::ExtiInput;
+use embassy_stm32::gpio::Pull;
+use {defmt_rtt as _, panic_probe as _};
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+ let p = embassy_stm32::init(Default::default());
+ info!("Hello World!");
+
+ let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up);
+
+ info!("Press the USER button...");
+
+ loop {
+ button.wait_for_falling_edge().await;
+ info!("Pressed!");
+ button.wait_for_rising_edge().await;
+ info!("Released!");
+ }
+}
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index 98696fd2b..ac160b995 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
[toolchain]
-channel = "nightly-2024-03-20"
+channel = "nightly-2024-04-14"
components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
targets = [
"thumbv7em-none-eabi",
diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs
index 9d64742df..06501ab14 100644
--- a/tests/stm32/src/bin/dac.rs
+++ b/tests/stm32/src/bin/dac.rs
@@ -13,7 +13,7 @@ use embassy_executor::Spawner;
use embassy_stm32::adc::Adc;
use embassy_stm32::dac::{DacCh1, Value};
use embassy_stm32::dma::NoDma;
-use embassy_time::{Delay, Timer};
+use embassy_time::Timer;
use micromath::F32Ext;
use {defmt_rtt as _, panic_probe as _};
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
let mut adc_pin = unsafe { core::ptr::read(&dac_pin) };
let mut dac = DacCh1::new(dac, NoDma, dac_pin);
- let mut adc = Adc::new(adc, &mut Delay);
+ let mut adc = Adc::new(adc);
#[cfg(feature = "stm32h755zi")]
let normalization_factor = 256;