diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index d8cc3e8a..8e36637a 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -62,7 +62,6 @@ embassy-macros = { version = "0.2.1", path = "../embassy-macros" } embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true} atomic-polyfill = "1.0.1" critical-section = "1.1" -static_cell = "1.1" # arch-cortex-m dependencies cortex-m = { version = "0.7.6", optional = true } diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 020f9095..f2c86d8e 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -47,7 +47,6 @@ pub use spawner::*; pub mod _export { #[cfg(feature = "rtos-trace")] pub use rtos_trace::trace; - pub use static_cell::StaticCell; /// Expands the given block of code when `embassy-executor` is compiled with /// the `rtos-trace-interrupt` feature. diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs index 7c4d5516..3c0d5856 100644 --- a/embassy-macros/src/macros/main.rs +++ b/embassy-macros/src/macros/main.rs @@ -53,8 +53,7 @@ pub fn wasm() -> TokenStream { quote! { #[wasm_bindgen::prelude::wasm_bindgen(start)] pub fn main() -> Result<(), wasm_bindgen::JsValue> { - static EXECUTOR: ::embassy_executor::_export::StaticCell<::embassy_executor::Executor> = ::embassy_executor::_export::StaticCell::new(); - let executor = EXECUTOR.init(::embassy_executor::Executor::new()); + let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new())); executor.start(|spawner| { spawner.spawn(__embassy_main(spawner)).unwrap(); diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index a781f3bd..08c6aabd 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -22,9 +22,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" [dev-dependencies] -# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged. -#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] } -embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] } +embedded-hal-mock = { version = "=0.10.0-rc.1", features = ["embedded-hal-async", "eh1"] } crc = "3.0.1" env_logger = "0.10" critical-section = { version = "1.1.2", features = ["std"] } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 5dc15c73..6be9f4bb 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -95,4 +95,4 @@ rp2040-boot2 = "0.3" [dev-dependencies] embassy-executor = { version = "0.3.1", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] } -static_cell = "1.1" +static_cell = { version = "2" } diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 8e75f641..20d8f904 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -1,3 +1,50 @@ +/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating +/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which +/// can use knowledge of which peripherals are currently blocked upon to transparently and safely +/// enter such low-power modes (currently, only `STOP2`) when idle. +/// +/// The executor determines which peripherals are active by their RCC state; consequently, +/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few +/// exceptions to this rule: +/// +/// * `GPIO` +/// * `RCC` +/// +/// Since entering and leaving low-power modes typically incurs a significant latency, the +/// low-power executor will only attempt to enter when the next timer event is at least +/// [`time_driver::MIN_STOP_PAUSE`] in the future. +/// +/// Currently there is no macro analogous to `embassy_executor::main` for this executor; +/// consequently one must define their entrypoint manually. Moveover, you must relinquish control +/// of the `RTC` peripheral to the executor. This will typically look like +/// +/// ```rust,no_run +/// use embassy_executor::Spawner; +/// use embassy_stm32::low_power::Executor; +/// use embassy_stm32::rtc::{Rtc, RtcConfig}; +/// use static_cell::make_static; +/// +/// #[cortex_m_rt::entry] +/// fn main() -> ! { +/// Executor::take().run(|spawner| { +/// unwrap!(spawner.spawn(async_main(spawner))); +/// }); +/// } +/// +/// #[embassy_executor::task] +/// async fn async_main(spawner: Spawner) { +/// // initialize the platform... +/// let mut config = embassy_stm32::Config::default(); +/// let p = embassy_stm32::init(config); +/// +/// // give the RTC to the executor... +/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); +/// let rtc = make_static!(rtc); +/// embassy_stm32::low_power::stop_with_rtc(rtc); +/// +/// // your application here... +/// } +/// ``` use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; @@ -67,7 +114,7 @@ pub struct Executor { impl Executor { /// Create a new Executor. pub fn take() -> &'static mut Self { - unsafe { + critical_section::with(|_| unsafe { assert!(EXECUTOR.is_none()); EXECUTOR = Some(Self { @@ -78,7 +125,7 @@ impl Executor { }); EXECUTOR.as_mut().unwrap() - } + }) } unsafe fn on_wakeup_irq(&mut self) { diff --git a/embassy-stm32/src/rcc/f4f7.rs b/embassy-stm32/src/rcc/f4f7.rs index 3102600a..2e4f9572 100644 --- a/embassy-stm32/src/rcc/f4f7.rs +++ b/embassy-stm32/src/rcc/f4f7.rs @@ -152,9 +152,9 @@ pub(crate) unsafe fn init(config: Config) { source: config.pll_src, }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); - #[cfg(any(all(stm32f4, not(any(stm32f410, stm32f429))), stm32f7))] + #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); - #[cfg(all(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7), not(stm32f429)))] + #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); // Configure sysclk @@ -197,25 +197,15 @@ pub(crate) unsafe fn init(config: Config) { pclk2_tim, rtc, pll1_q: pll.q, - #[cfg(all(rcc_f4, not(any(stm32f410, stm32f429))))] + #[cfg(all(rcc_f4, not(stm32f410)))] plli2s1_q: _plli2s.q, - #[cfg(all(rcc_f4, not(any(stm32f410, stm32f429))))] + #[cfg(all(rcc_f4, not(stm32f410)))] plli2s1_r: _plli2s.r, - #[cfg(stm32f429)] - plli2s1_q: None, - #[cfg(stm32f429)] - plli2s1_r: None, - - #[cfg(any(stm32f427, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pllsai1_q: _pllsai.q, - #[cfg(any(stm32f427, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] + #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pllsai1_r: _pllsai.r, - - #[cfg(stm32f429)] - pllsai1_q: None, - #[cfg(stm32f429)] - pllsai1_r: None, }); } @@ -233,7 +223,6 @@ struct PllOutput { r: Option, } -#[allow(dead_code)] #[derive(PartialEq, Eq, Clone, Copy)] enum PllInstance { Pll, diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index d897843d..f3428108 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -18,9 +18,13 @@ pub struct RtcInstant { } impl RtcInstant { - #[allow(dead_code)] - pub(super) fn from(second: u8, subsecond: u16) -> Result { - Ok(Self { second, subsecond }) + #[cfg(not(rtc_v2f2))] + pub(super) const fn from(second: u8, subsecond: u16) -> Result { + if second > 59 { + Err(Error::InvalidSecond) + } else { + Ok(Self { second, subsecond }) + } } } @@ -226,7 +230,7 @@ impl From for chrono::Weekday { } } -fn day_of_week_from_u8(v: u8) -> Result { +pub(super) const fn day_of_week_from_u8(v: u8) -> Result { Ok(match v { 1 => DayOfWeek::Monday, 2 => DayOfWeek::Tuesday, @@ -239,24 +243,6 @@ fn day_of_week_from_u8(v: u8) -> Result { }) } -pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 { +pub(super) const fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 { dotw as u8 } - -pub(super) fn validate_datetime(dt: &DateTime) -> Result<(), Error> { - if dt.year > 4095 { - Err(Error::InvalidYear) - } else if dt.month < 1 || dt.month > 12 { - Err(Error::InvalidMonth) - } else if dt.day < 1 || dt.day > 31 { - Err(Error::InvalidDay) - } else if dt.hour > 23 { - Err(Error::InvalidHour) - } else if dt.minute > 59 { - Err(Error::InvalidMinute) - } else if dt.second > 59 { - Err(Error::InvalidSecond) - } else { - Ok(()) - } -} diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 68836be0..e94a5857 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -9,8 +9,11 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; #[cfg(feature = "low-power")] use embassy_sync::blocking_mutex::Mutex; -pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError, RtcInstant}; -use crate::rtc::datetime::day_of_week_to_u8; +use self::datetime::day_of_week_to_u8; +#[cfg(not(rtc_v2f2))] +use self::datetime::RtcInstant; +pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; +use crate::pac::rtc::regs::{Dr, Tr}; use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 @@ -31,11 +34,15 @@ use crate::peripherals::RTC; use crate::rtc::sealed::Instance; /// Errors that can occur on methods on [RtcClock] +#[non_exhaustive] #[derive(Clone, Debug, PartialEq, Eq)] pub enum RtcError { /// An invalid DateTime was given or stored on the hardware. InvalidDateTime(DateTimeError), + /// The current time could not be read + ReadFailure, + /// The RTC clock is not running NotRunning, } @@ -45,48 +52,25 @@ pub struct RtcTimeProvider { } impl RtcTimeProvider { + #[cfg(not(rtc_v2f2))] + pub(crate) fn instant(&self) -> Result { + self.read(|_, tr, ss| { + let second = bcd2_to_byte((tr.st(), tr.su())); + + RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) + }) + } + /// Return the current datetime. /// /// # Errors /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1 - #[cfg(rcc_h7rm0433)] - loop { - let r = RTC::regs(); - let ss = r.ssr().read().ss(); - let dr = r.dr().read(); - let tr = r.tr().read(); - - // If an RTCCLK edge occurs during read we may see inconsistent values - // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9) - let ss_after = r.ssr().read().ss(); - if ss == ss_after { - 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())); - - 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; - - return DateTime::from(year, month, day, weekday, hour, minute, second) - .map_err(RtcError::InvalidDateTime); - } - } - - #[cfg(not(rcc_h7rm0433))] - { - let r = RTC::regs(); - let tr = r.tr().read(); + self.read(|dr, tr, _| { 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())); @@ -94,7 +78,33 @@ impl RtcTimeProvider { let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + }) + } + + fn read(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result) -> Result { + let r = RTC::regs(); + + #[cfg(not(rtc_v2f2))] + let read_ss = || r.ssr().read().ss(); + #[cfg(rtc_v2f2)] + let read_ss = || 0; + + let mut ss = read_ss(); + for _ in 0..5 { + let tr = r.tr().read(); + let dr = r.dr().read(); + let ss_after = read_ss(); + + // If an RTCCLK edge occurs during read we may see inconsistent values + // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9) + if ss == ss_after { + return f(dr, tr, ss.try_into().unwrap()); + } else { + ss = ss_after + } } + + return Err(RtcError::ReadFailure); } } @@ -158,6 +168,14 @@ impl Rtc { this.configure(async_psc, sync_psc); + // Wait for the clock to update after initialization + #[cfg(not(rtc_v2f2))] + { + let now = this.instant().unwrap(); + + while this.instant().unwrap().subsecond == now.subsecond {} + } + this } @@ -177,7 +195,6 @@ impl Rtc { /// /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> { - self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?; self.write(true, |rtc| { let (ht, hu) = byte_to_bcd2(t.hour() as u8); let (mnt, mnu) = byte_to_bcd2(t.minute() as u8); @@ -217,16 +234,8 @@ impl Rtc { #[cfg(not(rtc_v2f2))] /// Return the current instant. - pub fn instant(&self) -> Result { - let r = RTC::regs(); - let tr = r.tr().read(); - let subsecond = r.ssr().read().ss(); - let second = bcd2_to_byte((tr.st(), tr.su())); - - // Unlock the registers - r.dr().read(); - - RtcInstant::from(second, subsecond.try_into().unwrap()) + fn instant(&self) -> Result { + self.time_provider().instant() } /// Return the current datetime. diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index b6ab9b20..006fd63f 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -150,14 +150,14 @@ impl super::Rtc { pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { + #[cfg(not(rtc_v2f2))] + w.set_bypshad(true); #[cfg(rtc_v2f2)] w.set_fmt(false); #[cfg(not(rtc_v2f2))] w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); w.set_osel(Osel::DISABLED); w.set_pol(Pol::HIGH); - #[cfg(rcc_h7rm0433)] - w.set_bypshad(true); }); rtc.prer().modify(|w| { diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index a6b2655d..7bf757e7 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -11,6 +11,7 @@ impl super::Rtc { pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { self.write(true, |rtc| { rtc.cr().modify(|w| { + w.set_bypshad(true); w.set_fmt(Fmt::TWENTYFOURHOUR); w.set_osel(Osel::DISABLED); w.set_pol(Pol::HIGH); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index add8be83..564c9d08 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -345,6 +345,10 @@ impl RtcDriver { }); } + #[cfg(feature = "low-power")] + /// The minimum pause time beyond which the executor will enter a low-power state. + pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); + #[cfg(feature = "low-power")] /// Pause the timer if ready; return err if not pub(crate) fn pause_time(&self) -> Result<(), ()> { @@ -357,7 +361,7 @@ impl RtcDriver { self.stop_wakeup_alarm(cs); let time_until_next_alarm = self.time_until_next_alarm(cs); - if time_until_next_alarm < embassy_time::Duration::from_millis(250) { + if time_until_next_alarm < Self::MIN_STOP_PAUSE { Err(()) } else { self.rtc diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 81aeafae..9a47fa21 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -45,4 +45,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] } # Enable critical-section implementation for std, for tests critical-section = { version = "1.1", features = ["std"] } -static_cell = "1.1" +static_cell = { version = "2" } diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 29a8e421..48b8bbcc 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -13,6 +13,6 @@ embassy-usb = { version = "0.1.0", path = "../embassy-usb" } embassy-sync = { version = "0.4.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } futures = { version = "0.3", default-features = false } -static_cell = "1" +static_cell = { version = "2" } usbd-hid = "0.6.0" log = "0.4" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 0554b7e0..f803adb0 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -48,7 +48,7 @@ defmt = "0.3" defmt-rtt = "0.4" fixed = "1.10.0" -static_cell = "1.1" +static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 9c62508c..4196d61a 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -42,7 +42,7 @@ embedded-io-async = { version = "0.6.0" } defmt = "0.3" defmt-rtt = "0.4" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d020a0f5..fbe7acae 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -47,7 +47,8 @@ embedded-hal-async = "1.0.0-rc.1" embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } embedded-io-async = { version = "0.6.0", features = ["defmt-03"] } embedded-storage = { version = "0.3" } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} +portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" pio-proc = "0.2" pio = "0.2.1" diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs new file mode 100644 index 00000000..6d9d59df --- /dev/null +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -0,0 +1,81 @@ +//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::PIO0; +use embassy_rp::{bind_interrupts, pio}; +use fixed::traits::ToFixed; +use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct PioEncoder<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin_a: impl PioPin, + pin_b: impl PioPin, + ) -> Self { + let mut pin_a = pio.make_pio_pin(pin_a); + let mut pin_b = pio.make_pio_pin(pin_b); + pin_a.set_pull(Pull::Up); + pin_b.set_pull(Pull::Up); + sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + + let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); + + let mut cfg = Config::default(); + cfg.set_in_pins(&[&pin_a, &pin_b]); + cfg.fifo_join = FifoJoin::RxOnly; + cfg.shift_in.direction = ShiftDirection::Left; + cfg.clock_divider = 10_000.to_fixed(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + pub async fn read(&mut self) -> Direction { + loop { + match self.sm.rx().wait_pull().await { + 0 => return Direction::CounterClockwise, + 1 => return Direction::Clockwise, + _ => {} + } + } + } +} + +pub enum Direction { + Clockwise, + CounterClockwise, +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); + + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; + } +} diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs new file mode 100644 index 00000000..0fc2e40c --- /dev/null +++ b/examples/rp/src/bin/pwm_input.rs @@ -0,0 +1,26 @@ +//! This example shows how to use the PWM module to measure the frequency of an input signal. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::pwm::{Config, InputMode, Pwm}; +use embassy_time::{Duration, Ticker}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + let cfg: Config = Default::default(); + let pwm = Pwm::new_input(p.PWM_CH2, p.PIN_5, InputMode::RisingEdge, cfg); + + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + info!("Input frequency: {} Hz", pwm.counter()); + pwm.set_counter(0); + ticker.next().await; + } +} diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 12ec40fa..99511292 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -24,7 +24,7 @@ nix = "0.26.2" clap = { version = "3.0.0-beta.5", features = ["derive"] } rand_core = { version = "0.6.3", features = ["std"] } heapless = { version = "0.7.5", default-features = false } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [profile.release] debug = 2 diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 953fa584..3f781d76 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -17,7 +17,8 @@ panic-probe = "0.3" embassy-sync = { version = "0.4.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.1", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.1.5", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} +portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } [profile.release] debug = 2 diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 548191ca..0ab25c4c 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -24,7 +24,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } nb = "1.0.0" embedded-storage = "0.3.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [profile.release] debug = 2 diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index b42cc996..b3bfde44 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } nb = "1.0.0" embedded-storage = "0.3.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 916d0490..fca18203 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -27,7 +27,7 @@ heapless = { version = "0.7.5", default-features = false } nb = "1.0.0" embedded-storage = "0.3.0" micromath = "2.0.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} chrono = { version = "^0.4", default-features = false} [profile.release] diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 35757e62..0a567d04 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -27,7 +27,7 @@ nb = "1.0.0" rand_core = "0.6.3" critical-section = "1.1" embedded-storage = "0.3.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [profile.release] debug = 2 diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index fb7f780f..42d7d328 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -20,6 +20,7 @@ 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.7.5", default-features = false } +portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } [profile.release] debug = 2 diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index c4f41d1c..db56b685 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -31,7 +31,7 @@ critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} # cargo build/run [profile.dev] diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index d6b14a60..c300c864 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -31,7 +31,7 @@ critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.0" -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} chrono = { version = "^0.4", default-features = false } # cargo build/run diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index edd1d026..e294d042 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -33,7 +33,8 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } embedded-hal = "0.2.6" -static_cell = "1.1" +static_cell = { version = "2" } +portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } [profile.release] debug = 2 diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 2fbba463..5d79cf1e 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -32,7 +32,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } chrono = { version = "^0.4", default-features = false } rand = { version = "0.8.5", default-features = false } -static_cell = {version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} micromath = "2.0.0" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 2457b40d..1cd32892 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -26,7 +26,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } rand_core = { version = "0.6.3", default-features = false } embedded-io-async = { version = "0.6.0" } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [profile.release] debug = 2 diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 5864906d..daacc11c 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -22,7 +22,7 @@ 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.7.5", default-features = false } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [features] default = ["ble", "mac"] diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 12e0e5ab..c5284850 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -20,7 +20,7 @@ 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.7.5", default-features = false } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} [profile.release] debug = 2 diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 6441d5c3..f7a10409 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -18,7 +18,7 @@ embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-host embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0.0-rc.1" } embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } -static_cell = { version = "1.1", features = [ "nightly" ] } +static_cell = { version = "2", features = [ "nightly" ] } perf-client = { path = "../perf-client" } defmt = "0.3" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index d947568b..1bf149c9 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -31,7 +31,8 @@ panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } embedded-io-async = { version = "0.6.0" } embedded-storage = { version = "0.3" } -static_cell = { version = "1.1", features = ["nightly"]} +static_cell = { version = "2", features = ["nightly"]} +portable-atomic = { version = "1.5", features = ["critical-section"] } pio = "0.2" pio-proc = "0.2" rand = { version = "0.8.5", default-features = false } diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index 6ab7f671..a4923b6b 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -5,12 +5,12 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_executor::_export::StaticCell; use embassy_rp::gpio::{Input, Level, Output, Pull}; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{PIN_0, PIN_1}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; static mut CORE1_STACK: Stack<1024> = Stack::new(); diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 425f2d08..7ddb71c7 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -5,12 +5,12 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert_eq, info, panic, unwrap}; use embassy_executor::Executor; -use embassy_executor::_export::StaticCell; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{I2C0, I2C1}; use embassy_rp::{bind_interrupts, i2c, i2c_slave}; use embedded_hal_1::i2c::Operation; use embedded_hal_async::i2c::I2c; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; static mut CORE1_STACK: Stack<1024> = Stack::new(); diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index f4188135..6560b6c8 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs @@ -5,10 +5,10 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{info, unwrap}; use embassy_executor::Executor; -use embassy_executor::_export::StaticCell; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; static mut CORE1_STACK: Stack<1024> = Stack::new(); diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index db265daa..4b769b1c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -8,8 +8,8 @@ autobins = false [features] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin", "rng"] -stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] -stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] +stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac-adc-pin"] +stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "not-gpdma", "rng"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin", "rng"] stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"] @@ -19,7 +19,7 @@ stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"] stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng"] stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng"] -stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma", "rng"] +stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng"] stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] @@ -42,6 +42,8 @@ embassy-stm32-wpan = [] not-gpdma = [] dac-adc-pin = [] +cm0 = ["portable-atomic/unsafe-assume-single-core"] + [dependencies] teleprobe-meta = "1" @@ -66,7 +68,8 @@ micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } rand_core = { version = "0.6", default-features = false } rand_chacha = { version = "0.3", default-features = false } -static_cell = {version = "1.1", features = ["nightly"] } +static_cell = { version = "2", features = ["nightly"] } +portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true}