From f07e25c97049888f61e63517bc497307ac5c2edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 30 Oct 2024 09:12:15 +0100 Subject: [PATCH 01/67] Add option to disable waiti (#2329) --- esp-hal-embassy/CHANGELOG.md | 2 + esp-hal-embassy/Cargo.toml | 1 + esp-hal-embassy/build.rs | 12 +++++ esp-hal-embassy/src/executor/thread.rs | 66 +++++++++++++------------- hil-test/Cargo.toml | 14 +++--- 5 files changed, 56 insertions(+), 39 deletions(-) diff --git a/esp-hal-embassy/CHANGELOG.md b/esp-hal-embassy/CHANGELOG.md index c3cad863938..95d69b3ddc4 100644 --- a/esp-hal-embassy/CHANGELOG.md +++ b/esp-hal-embassy/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `ESP_HAL_EMBASSY_LOW_POWER_WAIT` configuration option. (#2329) + ### Changed - Reduce memory footprint by 4 bytes on multi-core MCUs. diff --git a/esp-hal-embassy/Cargo.toml b/esp-hal-embassy/Cargo.toml index ffac4445831..d4827afca27 100644 --- a/esp-hal-embassy/Cargo.toml +++ b/esp-hal-embassy/Cargo.toml @@ -25,6 +25,7 @@ static_cell = "2.1.0" [build-dependencies] esp-build = { version = "0.1.0", path = "../esp-build" } +esp-config = { version = "0.1.0", path = "../esp-config", features = ["build"] } esp-metadata = { version = "0.4.0", path = "../esp-metadata" } [features] diff --git a/esp-hal-embassy/build.rs b/esp-hal-embassy/build.rs index 1c7ecfc2ff6..ff1606cbeef 100644 --- a/esp-hal-embassy/build.rs +++ b/esp-hal-embassy/build.rs @@ -1,6 +1,7 @@ use std::{error::Error, str::FromStr}; use esp_build::assert_unique_used_features; +use esp_config::{generate_config, Value}; use esp_metadata::{Chip, Config}; fn main() -> Result<(), Box> { @@ -37,5 +38,16 @@ fn main() -> Result<(), Box> { // Define all necessary configuration symbols for the configured device: config.define_symbols(); + // emit config + generate_config( + "esp_hal_embassy", + &[( + "low-power-wait", + Value::Bool(true), + "Enables the lower-power wait if no tasks are ready to run on the thread-mode executor. This allows the MCU to use less power if the workload allows. Recommended for battery-powered systems. May impact analog performance.", + )], + true, + ); + Ok(()) } diff --git a/esp-hal-embassy/src/executor/thread.rs b/esp-hal-embassy/src/executor/thread.rs index 4af62ba3ecb..b279c6d417b 100644 --- a/esp-hal-embassy/src/executor/thread.rs +++ b/esp-hal-embassy/src/executor/thread.rs @@ -6,6 +6,7 @@ use embassy_executor::{raw, Spawner}; use esp_hal::{get_core, Cpu}; #[cfg(multi_core)] use esp_hal::{interrupt::software::SoftwareInterrupt, macros::handler}; +#[cfg(low_power_wait)] use portable_atomic::{AtomicBool, Ordering}; pub(crate) const THREAD_MODE_CONTEXT: usize = 16; @@ -15,7 +16,7 @@ pub(crate) const THREAD_MODE_CONTEXT: usize = 16; static SIGNAL_WORK_THREAD_MODE: [AtomicBool; Cpu::COUNT] = [const { AtomicBool::new(false) }; Cpu::COUNT]; -#[cfg(multi_core)] +#[cfg(all(multi_core, low_power_wait))] #[handler] fn software3_interrupt() { // This interrupt is fired when the thread-mode executor's core needs to be @@ -25,30 +26,33 @@ fn software3_interrupt() { unsafe { SoftwareInterrupt::<3>::steal().reset() }; } -pub(crate) fn pend_thread_mode(core: usize) { - // Signal that there is work to be done. - SIGNAL_WORK_THREAD_MODE[core].store(true, Ordering::SeqCst); - - // If we are pending a task on the current core, we're done. Otherwise, we - // need to make sure the other core wakes up. - #[cfg(multi_core)] - if core != get_core() as usize { - // We need to clear the interrupt from software. We don't actually - // need it to trigger and run the interrupt handler, we just need to - // kick waiti to return. - unsafe { SoftwareInterrupt::<3>::steal().raise() }; +pub(crate) fn pend_thread_mode(_core: usize) { + #[cfg(low_power_wait)] + { + // Signal that there is work to be done. + SIGNAL_WORK_THREAD_MODE[_core].store(true, Ordering::SeqCst); + + // If we are pending a task on the current core, we're done. Otherwise, we + // need to make sure the other core wakes up. + #[cfg(multi_core)] + if _core != get_core() as usize { + // We need to clear the interrupt from software. We don't actually + // need it to trigger and run the interrupt handler, we just need to + // kick waiti to return. + unsafe { SoftwareInterrupt::<3>::steal().raise() }; + } } } -/// A thread aware Executor +/// Thread mode executor. +/// +/// This is the simplest and most common kind of executor. It runs on thread +/// mode (at the lowest priority level). +#[cfg_attr(multi_core, doc = "")] #[cfg_attr( multi_core, - doc = r#" -This executor is capable of waking an -executor running on another core if work -needs to be completed there for a task to -progress on this core. -"# + doc = "This executor is safe to use on multiple cores. You need to +create one instance per core. The executors don't steal tasks from each other." )] pub struct Executor { inner: raw::Executor, @@ -64,7 +68,7 @@ impl Executor { This will use software-interrupt 3 which isn't available for anything else to wake the other core(s)."# )] pub fn new() -> Self { - #[cfg(multi_core)] + #[cfg(all(multi_core, low_power_wait))] unsafe { SoftwareInterrupt::<3>::steal().set_interrupt_handler(software3_interrupt); } @@ -90,7 +94,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa /// you mutable access. There's a few ways to do this: /// /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) - /// - a `static mut` (unsafe) + /// - a `static mut` (unsafe, not recommended) /// - a local variable in a function you know never returns (like `fn main() /// -> !`), upgrading its lifetime with `transmute`. (unsafe) /// @@ -98,20 +102,19 @@ This will use software-interrupt 3 which isn't available for anything else to wa pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { init(self.inner.spawner()); + #[cfg(low_power_wait)] let cpu = get_core() as usize; loop { - unsafe { - self.inner.poll(); + unsafe { self.inner.poll() }; - Self::wait_impl(cpu); - } + #[cfg(low_power_wait)] + Self::wait_impl(cpu); } } - #[doc(hidden)] - #[cfg(xtensa)] - pub fn wait_impl(cpu: usize) { + #[cfg(all(xtensa, low_power_wait))] + fn wait_impl(cpu: usize) { // Manual critical section implementation that only masks interrupts handlers. // We must not acquire the cross-core on dual-core systems because that would // prevent the other core from doing useful work while this core is sleeping. @@ -140,9 +143,8 @@ This will use software-interrupt 3 which isn't available for anything else to wa } } - #[doc(hidden)] - #[cfg(riscv)] - pub fn wait_impl(cpu: usize) { + #[cfg(all(riscv, low_power_wait))] + fn wait_impl(cpu: usize) { // we do not care about race conditions between the load and store operations, // interrupts will only set this value to true. critical_section::with(|_| { diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 300190c173a..980d53dce0e 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -235,33 +235,33 @@ esp32 = [ "embedded-test/xtensa-semihosting", "esp-backtrace/esp32", "esp-hal/esp32", - "esp-hal-embassy/esp32", + "esp-hal-embassy?/esp32", "esp-wifi?/esp32", ] esp32c2 = [ "esp-backtrace/esp32c2", "esp-hal/esp32c2", - "esp-hal-embassy/esp32c2", + "esp-hal-embassy?/esp32c2", "esp-wifi?/esp32c2", ] esp32c3 = [ "esp-backtrace/esp32c3", "esp-hal/esp32c3", - "esp-hal-embassy/esp32c3", + "esp-hal-embassy?/esp32c3", "esp-wifi?/esp32c3", "esp-wifi?/phy-enable-usb", ] esp32c6 = [ "esp-backtrace/esp32c6", "esp-hal/esp32c6", - "esp-hal-embassy/esp32c6", + "esp-hal-embassy?/esp32c6", "esp-wifi?/esp32c6", "esp-wifi?/phy-enable-usb", ] esp32h2 = [ "esp-backtrace/esp32h2", "esp-hal/esp32h2", - "esp-hal-embassy/esp32h2", + "esp-hal-embassy?/esp32h2", "esp-wifi?/esp32h2", "esp-wifi?/phy-enable-usb", ] @@ -269,14 +269,14 @@ esp32s2 = [ "embedded-test/xtensa-semihosting", "esp-backtrace/esp32s2", "esp-hal/esp32s2", - "esp-hal-embassy/esp32s2", + "esp-hal-embassy?/esp32s2", "esp-wifi?/esp32s2", ] esp32s3 = [ "embedded-test/xtensa-semihosting", "esp-backtrace/esp32s3", "esp-hal/esp32s3", - "esp-hal-embassy/esp32s3", + "esp-hal-embassy?/esp32s3", "esp-wifi?/esp32s3", "esp-wifi?/phy-enable-usb", ] From 3e42b76993de480eddee079471f4d221354f1984 Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov <62840029+playfulFence@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:46:34 +0100 Subject: [PATCH 02/67] Add an option to configure `WDT` action (#2330) * WIP * revert example revert config * changelog entry * Make `RWDT` API work correctly, make `RWDT` and `MWDT`APIs same * update documentation code oops * rev * Polishing * Document bootloader limitation + typo fix * Address reviews * fix documentation examples --- esp-hal/CHANGELOG.md | 2 +- esp-hal/src/lib.rs | 7 +- esp-hal/src/rtc_cntl/mod.rs | 209 ++++++++++++++++++++++--------- esp-hal/src/timer/timg.rs | 174 ++++++++++++++++++------- examples/src/bin/rtc_watchdog.rs | 8 +- examples/src/bin/watchdog.rs | 8 +- 6 files changed, 297 insertions(+), 111 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 4690eb3b58d..ae63754f5ca 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - - A new config option `PLACE_SWITCH_TABLES_IN_RAM` to improve performance (especially for interrupts) at the cost of slightly more RAM usage (#2331) - A new config option `PLACE_ANON_IN_RAM` to improve performance (especially for interrupts) at the cost of RAM usage (#2331) - Add burst transfer support to DMA buffers (#2336) @@ -22,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373) - `Cpu::COUNT` and `Cpu::current()` (#2411) - `UartInterrupt` and related functions (#2406) +- Add an option to configure `WDT` action (#2330) ### Changed diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 6622d34c5e3..2155b18ffd7 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -509,7 +509,8 @@ pub fn init(config: Config) -> Peripherals { match config.watchdog.rwdt { WatchdogStatus::Enabled(duration) => { rtc.rwdt.enable(); - rtc.rwdt.set_timeout(duration); + rtc.rwdt + .set_timeout(crate::rtc_cntl::RwdtStage::Stage0, duration); } WatchdogStatus::Disabled => { rtc.rwdt.disable(); @@ -520,7 +521,7 @@ pub fn init(config: Config) -> Peripherals { WatchdogStatus::Enabled(duration) => { let mut timg0_wd = crate::timer::timg::Wdt::::new(); timg0_wd.enable(); - timg0_wd.set_timeout(duration); + timg0_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration); } WatchdogStatus::Disabled => { crate::timer::timg::Wdt::::new().disable(); @@ -532,7 +533,7 @@ pub fn init(config: Config) -> Peripherals { WatchdogStatus::Enabled(duration) => { let mut timg1_wd = crate::timer::timg::Wdt::::new(); timg1_wd.enable(); - timg1_wd.set_timeout(duration); + timg1_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration); } WatchdogStatus::Disabled => { crate::timer::timg::Wdt::::new().disable(); diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 4a51ca11b19..c63c7538fa8 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -26,6 +26,7 @@ //! # use esp_hal::delay::Delay; //! # use esp_hal::rtc_cntl::Rtc; //! # use esp_hal::rtc_cntl::Rwdt; +//! # use esp_hal::rtc_cntl::RwdtStage; //! # use crate::esp_hal::InterruptConfigurable; //! static RWDT: Mutex>> = Mutex::new(RefCell::new(None)); //! let mut delay = Delay::new(); @@ -33,7 +34,7 @@ //! let mut rtc = Rtc::new(peripherals.LPWR); //! //! rtc.set_interrupt_handler(interrupt_handler); -//! rtc.rwdt.set_timeout(2000.millis()); +//! rtc.rwdt.set_timeout(RwdtStage::Stage0, 2000.millis()); //! rtc.rwdt.listen(); //! //! critical_section::with(|cs| RWDT.borrow_ref_mut(cs).replace(rtc.rwdt)); @@ -44,6 +45,7 @@ //! //! # use critical_section::Mutex; //! # use esp_hal::rtc_cntl::Rwdt; +//! # use esp_hal::rtc_cntl::RwdtStage; //! //! static RWDT: Mutex>> = Mutex::new(RefCell::new(None)); //! @@ -59,7 +61,7 @@ //! //! // esp_println::println!("Restarting in 5 seconds..."); //! -//! rwdt.set_timeout(5000u64.millis()); +//! rwdt.set_timeout(RwdtStage::Stage0, 5000u64.millis()); //! rwdt.unlisten(); //! }); //! } @@ -225,7 +227,7 @@ impl<'d> Rtc<'d> { let this = Self { _inner: rtc_cntl.into_ref(), - rwdt: Rwdt::default(), + rwdt: Rwdt::new(), #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] swd: Swd::new(), }; @@ -799,36 +801,55 @@ impl RtcClock { /// Behavior of the RWDT stage if it times out. #[allow(unused)] #[derive(Debug, Clone, Copy)] -enum RwdtStageAction { +pub enum RwdtStageAction { + /// No effect on the system. Off = 0, + /// Trigger an interrupt. Interrupt = 1, + /// Reset the CPU core. ResetCpu = 2, - ResetSystem = 3, - ResetRtc = 4, + /// Reset the main system. + /// The power management unit and RTC peripherals will not be reset. + ResetCore = 3, + /// Reset the main system, power management unit and RTC peripherals. + ResetSystem = 4, } -/// RTC Watchdog Timer. -pub struct Rwdt { - stg0_action: RwdtStageAction, - stg1_action: RwdtStageAction, - stg2_action: RwdtStageAction, - stg3_action: RwdtStageAction, +/// RWDT stages. +/// +/// Timer stages allow for a timer to have a series of different timeout values +/// and corresponding expiry action. +#[derive(Debug, Clone, Copy)] +pub enum RwdtStage { + /// RWDT stage 0. + Stage0, + /// RWDT stage 1. + Stage1, + /// RWDT stage 2. + Stage2, + /// RWDT stage 3. + Stage3, } +/// RTC Watchdog Timer. +pub struct Rwdt; + impl Default for Rwdt { fn default() -> Self { - Self { - stg0_action: RwdtStageAction::ResetRtc, - stg1_action: RwdtStageAction::Off, - stg2_action: RwdtStageAction::Off, - stg3_action: RwdtStageAction::Off, - } + Self::new() } } /// RTC Watchdog Timer driver. impl Rwdt { + /// Create a new RTC watchdog timer instance + pub fn new() -> Self { + Self + } + /// Enable the watchdog timer instance. + /// Watchdog starts with default settings (`stage 0` resets the system, the + /// others are deactivated) pub fn enable(&mut self) { self.set_enabled(true); } @@ -838,36 +859,32 @@ impl Rwdt { self.set_enabled(false); } - /// Listen for interrupts. + /// Listen for interrupts on stage 0. pub fn listen(&mut self) { let rtc_cntl = unsafe { lp_wdt() }; - self.stg0_action = RwdtStageAction::Interrupt; - self.set_write_protection(false); // Configure STAGE0 to trigger an interrupt upon expiration rtc_cntl .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg0().bits(self.stg0_action as u8) }); + .modify(|_, w| unsafe { w.wdt_stg0().bits(RwdtStageAction::Interrupt as u8) }); rtc_cntl.int_ena().modify(|_, w| w.wdt().set_bit()); self.set_write_protection(true); } - /// Stop listening for interrupts. + /// Stop listening for interrupts on stage 0. pub fn unlisten(&mut self) { let rtc_cntl = unsafe { lp_wdt() }; - self.stg0_action = RwdtStageAction::ResetRtc; - self.set_write_protection(false); // Configure STAGE0 to reset the main system and the RTC upon expiration. rtc_cntl .wdtconfig0() - .modify(|_, w| unsafe { w.wdt_stg0().bits(self.stg0_action as u8) }); + .modify(|_, w| unsafe { w.wdt_stg0().bits(RwdtStageAction::ResetSystem as u8) }); rtc_cntl.int_ena().modify(|_, w| w.wdt().clear_bit()); @@ -914,15 +931,43 @@ impl Rwdt { self.set_write_protection(false); - rtc_cntl - .wdtconfig0() - .modify(|_, w| w.wdt_en().bit(enable).wdt_flashboot_mod_en().bit(enable)); + if !enable { + rtc_cntl.wdtconfig0().modify(|_, w| unsafe { w.bits(0) }); + } else { + rtc_cntl + .wdtconfig0() + .write(|w| w.wdt_flashboot_mod_en().bit(false)); + + rtc_cntl + .wdtconfig0() + .modify(|_, w| w.wdt_en().bit(enable).wdt_pause_in_slp().bit(enable)); + + // Apply default settings for WDT + unsafe { + rtc_cntl.wdtconfig0().modify(|_, w| { + w.wdt_stg0() + .bits(RwdtStageAction::ResetSystem as u8) + .wdt_cpu_reset_length() + .bits(7) + .wdt_sys_reset_length() + .bits(7) + .wdt_stg1() + .bits(RwdtStageAction::Off as u8) + .wdt_stg2() + .bits(RwdtStageAction::Off as u8) + .wdt_stg3() + .bits(RwdtStageAction::Off as u8) + .wdt_en() + .set_bit() + }); + } + } self.set_write_protection(true); } - /// Configure timeout value in ms. - pub fn set_timeout(&mut self, timeout: MicrosDurationU64) { + /// Configure timeout value in ms for the selected stage. + pub fn set_timeout(&mut self, stage: RwdtStage, timeout: MicrosDurationU64) { let rtc_cntl = unsafe { lp_wdt() }; let timeout_raw = (timeout.to_millis() * (RtcClock::cycles_to_1ms() as u64)) as u32; @@ -930,38 +975,84 @@ impl Rwdt { unsafe { #[cfg(esp32)] - rtc_cntl - .wdtconfig1() - .modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw)); + match stage { + RwdtStage::Stage0 => rtc_cntl + .wdtconfig1() + .modify(|_, w| w.wdt_stg0_hold().bits(timeout_raw)), + RwdtStage::Stage1 => rtc_cntl + .wdtconfig2() + .modify(|_, w| w.wdt_stg1_hold().bits(timeout_raw)), + RwdtStage::Stage2 => rtc_cntl + .wdtconfig3() + .modify(|_, w| w.wdt_stg2_hold().bits(timeout_raw)), + RwdtStage::Stage3 => rtc_cntl + .wdtconfig4() + .modify(|_, w| w.wdt_stg3_hold().bits(timeout_raw)), + } #[cfg(any(esp32c6, esp32h2))] - rtc_cntl.config1().modify(|_, w| { - w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) - }); + match stage { + RwdtStage::Stage0 => rtc_cntl.config1().modify(|_, w| { + w.wdt_stg0_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage1 => rtc_cntl.config2().modify(|_, w| { + w.wdt_stg1_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage2 => rtc_cntl.config3().modify(|_, w| { + w.wdt_stg2_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage3 => rtc_cntl.config4().modify(|_, w| { + w.wdt_stg3_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + } #[cfg(not(any(esp32, esp32c6, esp32h2)))] - rtc_cntl.wdtconfig1().modify(|_, w| { - w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) - }); + match stage { + RwdtStage::Stage0 => rtc_cntl.wdtconfig1().modify(|_, w| { + w.wdt_stg0_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage1 => rtc_cntl.wdtconfig2().modify(|_, w| { + w.wdt_stg1_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage2 => rtc_cntl.wdtconfig3().modify(|_, w| { + w.wdt_stg2_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + RwdtStage::Stage3 => rtc_cntl.wdtconfig4().modify(|_, w| { + w.wdt_stg3_hold() + .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + }), + } + } - rtc_cntl.wdtconfig0().modify(|_, w| { - w.wdt_stg0() - .bits(self.stg0_action as u8) - .wdt_cpu_reset_length() - .bits(7) - .wdt_sys_reset_length() - .bits(7) - .wdt_stg1() - .bits(self.stg1_action as u8) - .wdt_stg2() - .bits(self.stg2_action as u8) - .wdt_stg3() - .bits(self.stg3_action as u8) - .wdt_en() - .set_bit() - }); + self.set_write_protection(true); + } + + /// Set the action for a specific stage. + pub fn set_stage_action(&mut self, stage: RwdtStage, action: RwdtStageAction) { + let rtc_cntl = unsafe { lp_wdt() }; + + self.set_write_protection(false); + + match stage { + RwdtStage::Stage0 => rtc_cntl + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) }), + RwdtStage::Stage1 => rtc_cntl + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) }), + RwdtStage::Stage2 => rtc_cntl + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) }), + RwdtStage::Stage3 => rtc_cntl + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }), } self.set_write_protection(true); @@ -981,7 +1072,7 @@ impl embedded_hal_02::watchdog::WatchdogEnable for Rwdt { where T: Into, { - self.set_timeout(period.into()); + self.set_timeout(RwdtStage::Stage0, period.into()); } } diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 96a7bb1c629..27818ed8f14 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -50,11 +50,12 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::timer::timg::TimerGroup; +//! # use esp_hal::timer::timg::MwdtStage; //! //! let timg0 = TimerGroup::new(peripherals.TIMG0); //! let mut wdt = timg0.wdt; //! -//! wdt.set_timeout(5_000.millis()); +//! wdt.set_timeout(MwdtStage::Stage0, 5_000.millis()); //! wdt.enable(); //! //! loop { @@ -911,6 +912,36 @@ where { } +/// Behavior of the MWDT stage if it times out. +#[allow(unused)] +#[derive(Debug, Clone, Copy)] +pub enum MwdtStageAction { + /// No effect on the system. + Off = 0, + /// Trigger an interrupt. + Interrupt = 1, + /// Reset the CPU core. + ResetCpu = 2, + /// Reset the main system, power management unit and RTC peripherals. + ResetSystem = 3, +} + +/// MWDT stages. +/// +/// Timer stages allow for a timer to have a series of different timeout values +/// and corresponding expiry action. +#[derive(Debug, Clone, Copy)] +pub enum MwdtStage { + /// MWDT stage 0. + Stage0, + /// MWDT stage 1. + Stage1, + /// MWDT stage 2. + Stage2, + /// MWDT stage 3. + Stage3, +} + /// Watchdog timer pub struct Wdt { phantom: PhantomData, @@ -937,14 +968,14 @@ where pub fn enable(&mut self) { // SAFETY: The `TG` instance being modified is owned by `self`, which is behind // a mutable reference. - unsafe { Self::set_wdt_enabled(true) }; + unsafe { self.set_wdt_enabled(true) }; } /// Disable the watchdog timer instance pub fn disable(&mut self) { // SAFETY: The `TG` instance being modified is owned by `self`, which is behind // a mutable reference. - unsafe { Self::set_wdt_enabled(false) }; + unsafe { self.set_wdt_enabled(false) }; } /// Forcibly enable or disable the watchdog timer @@ -954,83 +985,140 @@ where /// This bypasses the usual ownership rules for the peripheral, so users /// must take care to ensure that no driver instance is active for the /// timer. - pub unsafe fn set_wdt_enabled(enabled: bool) { + pub unsafe fn set_wdt_enabled(&mut self, enabled: bool) { let reg_block = unsafe { &*TG::register_block() }; - reg_block - .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0x50D8_3AA1u32) }); + self.set_write_protection(false); if !enabled { reg_block.wdtconfig0().write(|w| unsafe { w.bits(0) }); } else { reg_block.wdtconfig0().write(|w| w.wdt_en().bit(true)); + + reg_block + .wdtconfig0() + .write(|w| w.wdt_flashboot_mod_en().bit(false)); + + #[cfg_attr(esp32, allow(unused_unsafe))] + reg_block.wdtconfig0().write(|w| unsafe { + w.wdt_en() + .bit(true) + .wdt_stg0() + .bits(MwdtStageAction::ResetSystem as u8) + .wdt_cpu_reset_length() + .bits(7) + .wdt_sys_reset_length() + .bits(7) + .wdt_stg1() + .bits(MwdtStageAction::Off as u8) + .wdt_stg2() + .bits(MwdtStageAction::Off as u8) + .wdt_stg3() + .bits(MwdtStageAction::Off as u8) + }); + + #[cfg(any(esp32c2, esp32c3, esp32c6))] + reg_block + .wdtconfig0() + .modify(|_, w| w.wdt_conf_update_en().set_bit()); } - reg_block - .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0u32) }); + self.set_write_protection(true); } /// Feed the watchdog timer pub fn feed(&mut self) { let reg_block = unsafe { &*TG::register_block() }; - reg_block - .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0x50D8_3AA1u32) }); + self.set_write_protection(false); reg_block.wdtfeed().write(|w| unsafe { w.bits(1) }); + self.set_write_protection(true); + } + + fn set_write_protection(&mut self, enable: bool) { + let reg_block = unsafe { &*TG::register_block() }; + + let wkey = if enable { 0u32 } else { 0x50D8_3AA1u32 }; + reg_block .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0u32) }); + .write(|w| unsafe { w.wdt_wkey().bits(wkey) }); } /// Set the timeout, in microseconds, of the watchdog timer - pub fn set_timeout(&mut self, timeout: MicrosDurationU64) { + pub fn set_timeout(&mut self, stage: MwdtStage, timeout: MicrosDurationU64) { let timeout_raw = (timeout.to_nanos() * 10 / 125) as u32; let reg_block = unsafe { &*TG::register_block() }; - reg_block - .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0x50D8_3AA1u32) }); + self.set_write_protection(false); reg_block .wdtconfig1() .write(|w| unsafe { w.wdt_clk_prescale().bits(1) }); - reg_block - .wdtconfig2() - .write(|w| unsafe { w.wdt_stg0_hold().bits(timeout_raw) }); - - #[cfg_attr(esp32, allow(unused_unsafe))] - reg_block.wdtconfig0().write(|w| unsafe { - w.wdt_en() - .bit(true) - .wdt_stg0() - .bits(3) - .wdt_cpu_reset_length() - .bits(1) - .wdt_sys_reset_length() - .bits(1) - .wdt_stg1() - .bits(0) - .wdt_stg2() - .bits(0) - .wdt_stg3() - .bits(0) - }); + unsafe { + match stage { + MwdtStage::Stage0 => reg_block + .wdtconfig2() + .write(|w| w.wdt_stg0_hold().bits(timeout_raw)), + MwdtStage::Stage1 => reg_block + .wdtconfig3() + .write(|w| w.wdt_stg1_hold().bits(timeout_raw)), + MwdtStage::Stage2 => reg_block + .wdtconfig4() + .write(|w| w.wdt_stg2_hold().bits(timeout_raw)), + MwdtStage::Stage3 => reg_block + .wdtconfig5() + .write(|w| w.wdt_stg3_hold().bits(timeout_raw)), + } + } #[cfg(any(esp32c2, esp32c3, esp32c6))] reg_block .wdtconfig0() .modify(|_, w| w.wdt_conf_update_en().set_bit()); - reg_block - .wdtwprotect() - .write(|w| unsafe { w.wdt_wkey().bits(0u32) }); + self.set_write_protection(true); + } + + /// Set the stage action of the MWDT for a specific stage. + /// + /// This function modifies MWDT behavior only if a custom bootloader with + /// the following modifications is used: + /// - `ESP_TASK_WDT_EN` parameter **disabled** + /// - `ESP_INT_WDT` parameter **disabled** + pub fn set_stage_action(&mut self, stage: MwdtStage, action: MwdtStageAction) { + let reg_block = unsafe { &*TG::register_block() }; + + self.set_write_protection(false); + + match stage { + MwdtStage::Stage0 => { + reg_block + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) }); + } + MwdtStage::Stage1 => { + reg_block + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) }); + } + MwdtStage::Stage2 => { + reg_block + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) }); + } + MwdtStage::Stage3 => { + reg_block + .wdtconfig0() + .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }); + } + } + + self.set_write_protection(true); } } @@ -1078,7 +1166,7 @@ where T: Into, { self.enable(); - self.set_timeout(period.into()); + self.set_timeout(MwdtStage::Stage0, period.into()); } } diff --git a/examples/src/bin/rtc_watchdog.rs b/examples/src/bin/rtc_watchdog.rs index 255f0bf1225..58dc04619cd 100644 --- a/examples/src/bin/rtc_watchdog.rs +++ b/examples/src/bin/rtc_watchdog.rs @@ -16,7 +16,7 @@ use esp_backtrace as _; use esp_hal::{ interrupt::Priority, prelude::*, - rtc_cntl::{Rtc, Rwdt}, + rtc_cntl::{Rtc, Rwdt, RwdtStage}, }; use esp_println::println; @@ -28,7 +28,9 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); rtc.set_interrupt_handler(interrupt_handler); - rtc.rwdt.set_timeout(2000.millis()); + + rtc.rwdt.enable(); + rtc.rwdt.set_timeout(RwdtStage::Stage0, 2.secs()); rtc.rwdt.listen(); critical_section::with(|cs| RWDT.borrow_ref_mut(cs).replace(rtc.rwdt)); @@ -47,7 +49,7 @@ fn interrupt_handler() { println!("Restarting in 5 seconds..."); - rwdt.set_timeout(5000.millis()); + rwdt.set_timeout(RwdtStage::Stage0, 5.secs()); rwdt.unlisten(); }); } diff --git a/examples/src/bin/watchdog.rs b/examples/src/bin/watchdog.rs index ee01618c217..f6c6213795b 100644 --- a/examples/src/bin/watchdog.rs +++ b/examples/src/bin/watchdog.rs @@ -9,7 +9,11 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{delay::Delay, prelude::*, timer::timg::TimerGroup}; +use esp_hal::{ + delay::Delay, + prelude::*, + timer::timg::{MwdtStage, TimerGroup}, +}; use esp_println::println; #[entry] @@ -21,7 +25,7 @@ fn main() -> ! { let timg0 = TimerGroup::new_async(peripherals.TIMG0); let mut wdt0 = timg0.wdt; wdt0.enable(); - wdt0.set_timeout(2u64.secs()); + wdt0.set_timeout(MwdtStage::Stage0, 2u64.secs()); loop { wdt0.feed(); From a8fedf0130dba2190bedb27bd8af5d34fcff341f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 30 Oct 2024 16:11:48 +0100 Subject: [PATCH 03/67] Move some implementation details out of GPIO (#2429) * Move macros out of gpio * Align S2 impl --- esp-hal/src/gpio/mod.rs | 319 +------------------------------- esp-hal/src/soc/esp32/gpio.rs | 248 +++++++++++++++++++++++-- esp-hal/src/soc/esp32c2/gpio.rs | 43 ++++- esp-hal/src/soc/esp32c3/gpio.rs | 44 ++++- esp-hal/src/soc/esp32s2/gpio.rs | 154 ++++++++++++--- esp-hal/src/soc/esp32s3/gpio.rs | 154 ++++++++++++--- 6 files changed, 581 insertions(+), 381 deletions(-) diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 1631aa655c1..bc8199cf3ac 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -1122,312 +1122,6 @@ macro_rules! gpio { }; } -#[cfg(xtensa)] -#[doc(hidden)] -#[macro_export] -macro_rules! rtcio_analog { - ( @ignore $rue:literal ) => {}; - - ( - $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal)? - ) => { - impl $crate::gpio::RtcPin for GpioPin<$pin_num> - { - fn rtc_number(&self) -> u8 { - $rtc_pin - } - - /// Set the RTC properties of the pin. If `mux` is true then then pin is - /// routed to RTC, when false it is routed to IO_MUX. - fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { - use $crate::peripherals::RTC_IO; - - let rtcio = unsafe{ &*RTC_IO::ptr() }; - - $crate::gpio::enable_iomux_clk_gate(); - - // disable input - paste::paste!{ - rtcio.$pin_reg.modify(|_,w| unsafe { - w.[<$prefix fun_ie>]().bit(input_enable); - w.[<$prefix mux_sel>]().bit(mux); - w.[<$prefix fun_sel>]().bits(func as u8) - }); - } - } - - fn rtcio_pad_hold(&mut self, enable: bool) { - let rtc_ctrl = unsafe { $crate::peripherals::LPWR::steal() }; - - cfg_if::cfg_if! { - if #[cfg(esp32)] { - let pad_hold = rtc_ctrl.hold_force(); - } else { - let pad_hold = rtc_ctrl.pad_hold(); - } - }; - - pad_hold.modify(|_, w| w.$hold().bit(enable)); - } - } - - $( - // FIXME: replace with $(ignore($rue)) once stable - $crate::rtcio_analog!(@ignore $rue); - impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> - { - fn rtcio_pullup(&mut self, enable: bool) { - let rtcio = unsafe { $crate::peripherals::RTC_IO::steal() }; - - paste::paste! { - rtcio.$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); - } - } - - fn rtcio_pulldown(&mut self, enable: bool) { - let rtcio = unsafe { $crate::peripherals::RTC_IO::steal() }; - - paste::paste! { - rtcio.$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); - } - } - } - )? - - #[cfg(any(adc, dac))] - impl $crate::gpio::AnalogPin for GpioPin<$pin_num> { - /// Configures the pin for analog mode. - fn set_analog(&self, _: $crate::private::Internal) { - let rtcio = unsafe{ &*$crate::peripherals::RTC_IO::ptr() }; - - #[cfg(esp32s2)] - $crate::gpio::enable_iomux_clk_gate(); - - // We need `paste` (and a [< >] in it) to rewrite the token stream to - // handle indexed pins. - paste::paste! { - // disable input - rtcio.$pin_reg.modify(|_,w| w.[<$prefix fun_ie>]().bit(false)); - - // disable output - rtcio.enable_w1tc().write(|w| unsafe { w.enable_w1tc().bits(1 << $rtc_pin) }); - - // disable open drain - rtcio.pin($rtc_pin).modify(|_,w| w.pad_driver().bit(false)); - - rtcio.$pin_reg.modify(|_,w| { - w.[<$prefix fun_ie>]().clear_bit(); - - // Connect pin to analog / RTC module instead of standard GPIO - w.[<$prefix mux_sel>]().set_bit(); - - // Select function "RTC function 1" (GPIO) for analog use - unsafe { w.[<$prefix fun_sel>]().bits(0b00) }; - - // Disable pull-up and pull-down resistors on the pin, if it has them - $( - // FIXME: replace with $(ignore($rue)) once stable - $crate::rtcio_analog!( @ignore $rue ); - w.[<$prefix rue>]().bit(false); - w.[<$prefix rde>]().bit(false); - )? - - w - }); - } - } - } - }; - - ( - $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal )? ) )+ - ) => { - $( - $crate::rtcio_analog!($pin_num, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue )?); - )+ - - #[cfg(esp32)] - pub(crate) fn errata36(mut pin: AnyPin, pull_up: bool, pull_down: bool) { - use $crate::gpio::{Pin, RtcPinWithResistors}; - - let has_pullups = match pin.number() { - $( - $( $pin_num => $rue, )? - )+ - _ => false, - }; - - if has_pullups { - pin.rtcio_pullup(pull_up); - pin.rtcio_pulldown(pull_down); - } - } - }; -} - -#[cfg(any(esp32c2, esp32c3))] -#[doc(hidden)] -#[macro_export] -macro_rules! rtc_pins { - ( $( $pin_num:expr )+ ) => { - $( - impl $crate::gpio::RtcPin for GpioPin<$pin_num> { - unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { - let rtc_cntl = unsafe { &*$crate::peripherals::RTC_CNTL::ptr() }; - cfg_if::cfg_if! { - if #[cfg(esp32c2)] { - let gpio_wakeup = rtc_cntl.cntl_gpio_wakeup(); - } else { - let gpio_wakeup = rtc_cntl.gpio_wakeup(); - } - } - - paste::paste! { - gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _wakeup_enable >]().bit(wakeup)); - gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _int_type >]().bits(level)); - } - } - - fn rtcio_pad_hold(&mut self, enable: bool) { - let rtc_cntl = unsafe { &*$crate::peripherals::RTC_CNTL::ptr() }; - paste::paste! { - rtc_cntl.pad_hold().modify(|_, w| w.[< gpio_pin $pin_num _hold >]().bit(enable)); - } - } - } - - impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> { - fn rtcio_pullup(&mut self, enable: bool) { - let io_mux = unsafe { &*$crate::peripherals::IO_MUX::ptr() }; - io_mux.gpio($pin_num).modify(|_, w| w.fun_wpu().bit(enable)); - } - - fn rtcio_pulldown(&mut self, enable: bool) { - let io_mux = unsafe { &*$crate::peripherals::IO_MUX::ptr() }; - io_mux.gpio($pin_num).modify(|_, w| w.fun_wpd().bit(enable)); - } - } - )+ - }; -} - -#[doc(hidden)] -pub fn enable_iomux_clk_gate() { - cfg_if::cfg_if! { - if #[cfg(esp32s2)] { - let sensors = unsafe { &*crate::peripherals::SENS::ptr() }; - sensors - .sar_io_mux_conf() - .modify(|_, w| w.iomux_clk_gate_en().set_bit()); - } else if #[cfg(esp32s3)] { - let sensors = unsafe { &*crate::peripherals::SENS::ptr() }; - sensors - .sar_peri_clk_gate_conf() - .modify(|_,w| w.iomux_clk_en().set_bit()); - } - } -} - -/// Common functionality for all touch pads -#[doc(hidden)] -#[macro_export] -macro_rules! touch { - (@pin_specific $touch_num:expr, true) => { - paste::paste! { - unsafe { &*RTC_IO::ptr() }.[< touch_pad $touch_num >]().write(|w| unsafe { - w.xpd().set_bit(); - // clear input_enable - w.fun_ie().clear_bit(); - // Connect pin to analog / RTC module instead of standard GPIO - w.mux_sel().set_bit(); - // Disable pull-up and pull-down resistors on the pin - w.rue().clear_bit(); - w.rde().clear_bit(); - w.tie_opt().clear_bit(); - // Select function "RTC function 1" (GPIO) for analog use - w.fun_sel().bits(0b00) - }); - } - }; - - (@pin_specific $touch_num:expr, false) => { - paste::paste! { - unsafe { &*RTC_IO::ptr() }.[< touch_pad $touch_num >]().write(|w| { - w.xpd().set_bit(); - w.tie_opt().clear_bit() - }); - } - }; - - ( - $( - ( - $touch_num:literal, $pin_num:literal, $rtc_pin:literal, $touch_out_reg:expr, $meas_field: expr, $touch_thres_reg:expr, $touch_thres_field:expr, $normal_pin:literal - ) - )+ - ) => { - $( - impl $crate::gpio::TouchPin for GpioPin<$pin_num> { - fn set_touch(&self, _: $crate::private::Internal) { - use $crate::peripherals::{GPIO, RTC_IO, SENS}; - - let gpio = unsafe { &*GPIO::ptr() }; - let rtcio = unsafe { &*RTC_IO::ptr() }; - let sens = unsafe { &*SENS::ptr() }; - - // Pad to normal mode (not open-drain) - gpio.pin($rtc_pin).write(|w| w.pad_driver().clear_bit()); - - // clear output - rtcio - .enable_w1tc() - .write(|w| unsafe { w.enable_w1tc().bits(1 << $rtc_pin) }); - paste::paste! { - sens . $touch_thres_reg () - .write(|w| unsafe { - w. $touch_thres_field ().bits( - 0b0 // Default: 0 for esp32 gets overridden later anyway. - ) - }); - - $crate::touch!( @pin_specific $touch_num, $normal_pin ); - - // enable the pin - sens.sar_touch_enable().modify(|r, w| unsafe { - w.touch_pad_worken().bits( - r.touch_pad_worken().bits() | ( 1 << [< $touch_num >] ) - ) - }); - } - } - - fn get_touch_measurement(&self, _: $crate::private::Internal) -> u16 { - paste::paste! { - unsafe { &* $crate::peripherals::SENS::ptr() } - . $touch_out_reg () - .read() - . $meas_field () - .bits() - } - } - - fn get_touch_nr(&self, _: $crate::private::Internal) -> u8 { - $touch_num - } - - fn set_threshold(&self, threshold: u16, _: $crate::private::Internal) { - paste::paste! { - unsafe { &* $crate::peripherals::SENS::ptr() } - . $touch_thres_reg () - .write(|w| unsafe { - w. $touch_thres_field ().bits(threshold) - }); - } - } - })+ - }; -} - /// GPIO output driver. pub struct Output<'d, P = AnyPin> { pin: Flex<'d, P>, @@ -2100,12 +1794,13 @@ fn is_listening(pin_num: u8) -> bool { } fn set_int_enable(gpio_num: u8, int_ena: u8, int_type: u8, wake_up_from_light_sleep: bool) { - let gpio = unsafe { GPIO::steal() }; - gpio.pin(gpio_num as usize).modify(|_, w| unsafe { - w.int_ena().bits(int_ena); - w.int_type().bits(int_type); - w.wakeup_enable().bit(wake_up_from_light_sleep) - }); + unsafe { GPIO::steal() } + .pin(gpio_num as usize) + .modify(|_, w| unsafe { + w.int_ena().bits(int_ena); + w.int_type().bits(int_type); + w.wakeup_enable().bit(wake_up_from_light_sleep) + }); } #[ram] diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index e33368f0aa2..f5899cbd209 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -527,6 +527,220 @@ pub enum OutputSignal { MTDO, } +macro_rules! rtcio_analog { + ( @ignore $rue:literal ) => {}; + + ( + $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal)? + ) => { + impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + fn rtc_number(&self) -> u8 { + $rtc_pin + } + + /// Set the RTC properties of the pin. If `mux` is true then then pin is + /// routed to RTC, when false it is routed to IO_MUX. + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { + // disable input + paste::paste!{ + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_,w| unsafe { + w.[<$prefix fun_ie>]().bit(input_enable); + w.[<$prefix mux_sel>]().bit(mux); + w.[<$prefix fun_sel>]().bits(func as u8) + }); + } + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + unsafe { $crate::peripherals::LPWR::steal() } + .hold_force() + .modify(|_, w| w.$hold().bit(enable)); + } + } + + $( + // FIXME: replace with $(ignore($rue)) once stable + rtcio_analog!(@ignore $rue); + impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> { + fn rtcio_pullup(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); + } + } + + fn rtcio_pulldown(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); + } + } + } + )? + + impl $crate::gpio::AnalogPin for GpioPin<$pin_num> { + /// Configures the pin for analog mode. + fn set_analog(&self, _: $crate::private::Internal) { + use $crate::gpio::RtcPin; + let rtcio = unsafe{ $crate::peripherals::RTC_IO::steal() }; + + paste::paste! { + // disable input + rtcio.$pin_reg.modify(|_,w| w.[<$prefix fun_ie>]().bit(false)); + + // disable output + rtcio.enable_w1tc().write(|w| unsafe { w.enable_w1tc().bits(1 << self.rtc_number()) }); + + // disable open drain + rtcio.pin(self.rtc_number() as usize).modify(|_,w| w.pad_driver().bit(false)); + + rtcio.$pin_reg.modify(|_,w| { + w.[<$prefix fun_ie>]().clear_bit(); + + // Connect pin to analog / RTC module instead of standard GPIO + w.[<$prefix mux_sel>]().set_bit(); + + // Select function "RTC function 1" (GPIO) for analog use + unsafe { w.[<$prefix fun_sel>]().bits(0b00) }; + + // Disable pull-up and pull-down resistors on the pin, if it has them + $( + // FIXME: replace with $(ignore($rue)) once stable + rtcio_analog!( @ignore $rue ); + w.[<$prefix rue>]().bit(false); + w.[<$prefix rde>]().bit(false); + )? + + w + }); + } + } + } + }; + + ( + $( ( $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal )? ) )+ + ) => { + $( + rtcio_analog!($pin_num, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue )?); + )+ + + pub(crate) fn errata36(mut pin: AnyPin, pull_up: bool, pull_down: bool) { + use $crate::gpio::{Pin, RtcPinWithResistors}; + + let has_pullups = match pin.number() { + $( + $( $pin_num => $rue, )? + )+ + _ => false, + }; + + if has_pullups { + pin.rtcio_pullup(pull_up); + pin.rtcio_pulldown(pull_down); + } + } + }; +} + +/// Common functionality for all touch pads +macro_rules! touch { + (@pin_specific $touch_num:expr, true) => { + paste::paste! { + unsafe { RTC_IO::steal() }.[< touch_pad $touch_num >]().write(|w| unsafe { + w.xpd().set_bit(); + // clear input_enable + w.fun_ie().clear_bit(); + // Connect pin to analog / RTC module instead of standard GPIO + w.mux_sel().set_bit(); + // Disable pull-up and pull-down resistors on the pin + w.rue().clear_bit(); + w.rde().clear_bit(); + w.tie_opt().clear_bit(); + // Select function "RTC function 1" (GPIO) for analog use + w.fun_sel().bits(0b00) + }); + } + }; + + (@pin_specific $touch_num:expr, false) => { + paste::paste! { + unsafe { RTC_IO::steal() }.[< touch_pad $touch_num >]().write(|w| { + w.xpd().set_bit(); + w.tie_opt().clear_bit() + }); + } + }; + + ( + $( + ( + $touch_num:literal, $pin_num:literal, $touch_out_reg:expr, $touch_thres_reg:expr, $normal_pin:literal + ) + )+ + ) => { + $( + impl $crate::gpio::TouchPin for GpioPin<$pin_num> { + fn set_touch(&self, _: $crate::private::Internal) { + use $crate::peripherals::{GPIO, RTC_IO, SENS}; + use $crate::gpio::RtcPin; + + let gpio = unsafe { GPIO::steal() }; + let rtcio = unsafe { RTC_IO::steal() }; + let sens = unsafe { SENS::steal() }; + + // Pad to normal mode (not open-drain) + gpio.pin(self.rtc_number() as usize).write(|w| w.pad_driver().clear_bit()); + + // clear output + rtcio + .enable_w1tc() + .write(|w| unsafe { w.enable_w1tc().bits(1 << self.rtc_number()) }); + paste::paste! { + sens . $touch_thres_reg () + .write(|w| unsafe { + w. [] ().bits( + 0b0 // Default: 0 for esp32 gets overridden later anyway. + ) + }); + + touch!( @pin_specific $touch_num, $normal_pin ); + + // enable the pin + sens.sar_touch_enable().modify(|r, w| unsafe { + w.touch_pad_worken().bits( + r.touch_pad_worken().bits() | ( 1 << $touch_num ) + ) + }); + } + } + + fn get_touch_measurement(&self, _: $crate::private::Internal) -> u16 { + paste::paste! { + unsafe { $crate::peripherals::SENS::steal() } + . $touch_out_reg ().read() + . [] ().bits() + } + } + + fn get_touch_nr(&self, _: $crate::private::Internal) -> u8 { + $touch_num + } + + fn set_threshold(&self, threshold: u16, _: $crate::private::Internal) { + paste::paste! { + unsafe { $crate::peripherals::SENS::steal() } + . $touch_thres_reg () + .write(|w| unsafe { + w. [] ().bits(threshold) + }); + } + } + })+ + }; +} + crate::gpio! { (0, [Input, Output, Analog, RtcIo, Touch] (5 => EMAC_TX_CLK) (1 => CLK_OUT1)) (1, [Input, Output] (5 => EMAC_RXD2) (0 => U0TXD 1 => CLK_OUT3)) @@ -566,7 +780,7 @@ crate::gpio! { (39, [Input, Analog, RtcIoInput]) } -crate::rtcio_analog! { +rtcio_analog! { (36, 0, sensor_pads(), sense1_, sense1_hold_force ) (37, 1, sensor_pads(), sense2_, sense2_hold_force ) (38, 2, sensor_pads(), sense3_, sense3_hold_force ) @@ -587,19 +801,19 @@ crate::rtcio_analog! { (27, 17, touch_pad7(), "", touch_pad7_hold_force, true) } -crate::touch! { - // touch_nr, pin_nr, rtc_pin, touch_out_reg, meas_field, touch_thres_reg, touch_thres_field, normal_pin - (0, 4, 10, sar_touch_out1, touch_meas_out0, sar_touch_thres1, touch_out_th0, true) - (1, 0, 11, sar_touch_out1, touch_meas_out1, sar_touch_thres1, touch_out_th1, true) - (2, 2, 12, sar_touch_out2, touch_meas_out2, sar_touch_thres2, touch_out_th2, true) - (3, 15, 13, sar_touch_out2, touch_meas_out3, sar_touch_thres2, touch_out_th3, true) - (4, 13, 14, sar_touch_out3, touch_meas_out4, sar_touch_thres3, touch_out_th4, true) - (5, 12, 15, sar_touch_out3, touch_meas_out5, sar_touch_thres3, touch_out_th5, true) - (6, 14, 16, sar_touch_out4, touch_meas_out6, sar_touch_thres4, touch_out_th6, true) - (7, 27, 17, sar_touch_out4, touch_meas_out7, sar_touch_thres4, touch_out_th7, true) +touch! { + // touch_nr, pin_nr, touch_out_reg, touch_thres_reg, normal_pin + (0, 4, sar_touch_out1, sar_touch_thres1, true) + (1, 0, sar_touch_out1, sar_touch_thres1, true) + (2, 2, sar_touch_out2, sar_touch_thres2, true) + (3, 15, sar_touch_out2, sar_touch_thres2, true) + (4, 13, sar_touch_out3, sar_touch_thres3, true) + (5, 12, sar_touch_out3, sar_touch_thres3, true) + (6, 14, sar_touch_out4, sar_touch_thres4, true) + (7, 27, sar_touch_out4, sar_touch_thres4, true) // --- - (8, 33, 8, sar_touch_out5, touch_meas_out8, sar_touch_thres5, touch_out_th8, false) - (9, 32, 9, sar_touch_out5, touch_meas_out9, sar_touch_thres5, touch_out_th9, false) + (8, 33, sar_touch_out5, sar_touch_thres5, false) + (9, 32, sar_touch_out5, sar_touch_thres5, false) } #[derive(Clone, Copy)] @@ -612,12 +826,12 @@ impl InterruptStatusRegisterAccess { pub(crate) fn interrupt_status_read(self) -> u32 { match self { Self::Bank0 => match crate::get_core() { - crate::Cpu::ProCpu => unsafe { &*GPIO::PTR }.pcpu_int().read().bits(), - crate::Cpu::AppCpu => unsafe { &*GPIO::PTR }.acpu_int().read().bits(), + crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int().read().bits(), + crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int().read().bits(), }, Self::Bank1 => match crate::get_core() { - crate::Cpu::ProCpu => unsafe { &*GPIO::PTR }.pcpu_int1().read().bits(), - crate::Cpu::AppCpu => unsafe { &*GPIO::PTR }.acpu_int1().read().bits(), + crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), + crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int1().read().bits(), }, } } diff --git a/esp-hal/src/soc/esp32c2/gpio.rs b/esp-hal/src/soc/esp32c2/gpio.rs index 81d3a0463df..f639d54fd71 100644 --- a/esp-hal/src/soc/esp32c2/gpio.rs +++ b/esp-hal/src/soc/esp32c2/gpio.rs @@ -171,6 +171,47 @@ pub enum OutputSignal { GPIO = 128, } +macro_rules! rtc_pins { + ( $( $pin_num:expr )+ ) => { + $( + impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { + let rtc_cntl = unsafe { $crate::peripherals::RTC_CNTL::steal() }; + let gpio_wakeup = rtc_cntl.cntl_gpio_wakeup(); + paste::paste! { + gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _wakeup_enable >]().bit(wakeup)); + gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _int_type >]().bits(level)); + } + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_CNTL::steal() } + .pad_hold().modify(|_, w| w.[< gpio_pin $pin_num _hold >]().bit(enable)); + } + } + } + )+ + }; +} + +impl crate::gpio::RtcPinWithResistors for GpioPin +where + Self: crate::gpio::RtcPin, +{ + fn rtcio_pullup(&mut self, enable: bool) { + unsafe { crate::peripherals::IO_MUX::steal() } + .gpio(N as usize) + .modify(|_, w| w.fun_wpu().bit(enable)); + } + + fn rtcio_pulldown(&mut self, enable: bool) { + unsafe { crate::peripherals::IO_MUX::steal() } + .gpio(N as usize) + .modify(|_, w| w.fun_wpd().bit(enable)); + } +} + crate::gpio! { (0, [Input, Output, Analog, RtcIo]) (1, [Input, Output, Analog, RtcIo]) @@ -188,7 +229,7 @@ crate::gpio! { (20, [Input, Output] (0 => U0RXD) ()) } -crate::rtc_pins! { +rtc_pins! { 0 1 2 diff --git a/esp-hal/src/soc/esp32c3/gpio.rs b/esp-hal/src/soc/esp32c3/gpio.rs index edef675d1b6..5139199f0c2 100644 --- a/esp-hal/src/soc/esp32c3/gpio.rs +++ b/esp-hal/src/soc/esp32c3/gpio.rs @@ -198,6 +198,48 @@ pub enum OutputSignal { GPIO = 128, } +macro_rules! rtc_pins { + ( $( $pin_num:expr )+ ) => { + $( + impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8) { + let rtc_cntl = unsafe { $crate::peripherals::RTC_CNTL::steal() }; + let gpio_wakeup = rtc_cntl.gpio_wakeup(); + + paste::paste! { + gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _wakeup_enable >]().bit(wakeup)); + gpio_wakeup.modify(|_, w| w.[< gpio_pin $pin_num _int_type >]().bits(level)); + } + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_CNTL::steal() } + .pad_hold().modify(|_, w| w.[< gpio_pin $pin_num _hold >]().bit(enable)); + } + } + } + )+ + }; +} + +impl crate::gpio::RtcPinWithResistors for GpioPin +where + Self: crate::gpio::RtcPin, +{ + fn rtcio_pullup(&mut self, enable: bool) { + unsafe { crate::peripherals::IO_MUX::steal() } + .gpio(N as usize) + .modify(|_, w| w.fun_wpu().bit(enable)); + } + + fn rtcio_pulldown(&mut self, enable: bool) { + unsafe { crate::peripherals::IO_MUX::steal() } + .gpio(N as usize) + .modify(|_, w| w.fun_wpd().bit(enable)); + } +} + crate::gpio! { (0, [Input, Output, Analog, RtcIo]) (1, [Input, Output, Analog, RtcIo]) @@ -224,7 +266,7 @@ crate::gpio! { } // RTC pins 0 through 5 (inclusive) support GPIO wakeup -crate::rtc_pins! { +rtc_pins! { 0 1 2 diff --git a/esp-hal/src/soc/esp32s2/gpio.rs b/esp-hal/src/soc/esp32s2/gpio.rs index 8a760a95b1f..a90998f2c8f 100644 --- a/esp-hal/src/soc/esp32s2/gpio.rs +++ b/esp-hal/src/soc/esp32s2/gpio.rs @@ -314,6 +314,104 @@ pub enum OutputSignal { GPIO = 256, } +macro_rules! rtcio_analog { + ( @ignore $rue:literal ) => {}; + + ( + $pin_num:expr, $pin_reg:expr, $prefix:pat, $hold:ident + ) => { + impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + fn rtc_number(&self) -> u8 { + $pin_num + } + + /// Set the RTC properties of the pin. If `mux` is true then then pin is + /// routed to RTC, when false it is routed to IO_MUX. + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { + enable_iomux_clk_gate(); + + // disable input + paste::paste!{ + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_,w| unsafe { + w.[<$prefix fun_ie>]().bit(input_enable); + w.[<$prefix mux_sel>]().bit(mux); + w.[<$prefix fun_sel>]().bits(func as u8) + }); + } + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + unsafe { $crate::peripherals::LPWR::steal() } + .pad_hold() + .modify(|_, w| w.$hold().bit(enable)); + } + } + + impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> + { + fn rtcio_pullup(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); + } + } + + fn rtcio_pulldown(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); + } + } + } + + impl $crate::gpio::AnalogPin for GpioPin<$pin_num> { + /// Configures the pin for analog mode. + fn set_analog(&self, _: $crate::private::Internal) { + use $crate::gpio::RtcPin; + enable_iomux_clk_gate(); + + let rtcio = unsafe{ $crate::peripherals::RTC_IO::steal() }; + + paste::paste! { + // disable input + rtcio.$pin_reg.modify(|_,w| w.[<$prefix fun_ie>]().bit(false)); + + // disable output + rtcio.enable_w1tc().write(|w| unsafe { w.enable_w1tc().bits(1 << self.rtc_number()) }); + + // disable open drain + rtcio.pin(self.rtc_number() as usize).modify(|_,w| w.pad_driver().bit(false)); + + rtcio.$pin_reg.modify(|_,w| { + w.[<$prefix fun_ie>]().clear_bit(); + + // Connect pin to analog / RTC module instead of standard GPIO + w.[<$prefix mux_sel>]().set_bit(); + + // Select function "RTC function 1" (GPIO) for analog use + unsafe { w.[<$prefix fun_sel>]().bits(0b00) }; + + // Disable pull-up and pull-down resistors on the pin + w.[<$prefix rue>]().bit(false); + w.[<$prefix rde>]().bit(false); + + w + }); + } + } + } + }; + + ( + $( ( $pin_num:expr, $pin_reg:expr, $prefix:pat, $hold:ident ) )+ + ) => { + $( + rtcio_analog!($pin_num, $pin_reg, $prefix, $hold); + )+ + }; +} + crate::gpio! { (0, [Input, Output, Analog, RtcIo]) (1, [Input, Output, Analog, RtcIo]) @@ -361,29 +459,29 @@ crate::gpio! { (46, [Input, Output]) } -crate::rtcio_analog! { - ( 0, 0, touch_pad(0), "", touch_pad0_hold, true) - ( 1, 1, touch_pad(1), "", touch_pad1_hold, true) - ( 2, 2, touch_pad(2), "", touch_pad2_hold, true) - ( 3, 3, touch_pad(3), "", touch_pad3_hold, true) - ( 4, 4, touch_pad(4), "", touch_pad4_hold, true) - ( 5, 5, touch_pad(5), "", touch_pad5_hold, true) - ( 6, 6, touch_pad(6), "", touch_pad6_hold, true) - ( 7, 7, touch_pad(7), "", touch_pad7_hold, true) - ( 8, 8, touch_pad(8), "", touch_pad8_hold, true) - ( 9, 9, touch_pad(9), "", touch_pad9_hold, true) - (10, 10, touch_pad(10), "", touch_pad10_hold, true) - (11, 11, touch_pad(11), "", touch_pad11_hold, true) - (12, 12, touch_pad(12), "", touch_pad12_hold, true) - (13, 13, touch_pad(13), "", touch_pad13_hold, true) - (14, 14, touch_pad(14), "", touch_pad14_hold, true) - (15, 15, xtal_32p_pad(), x32p_, x32p_hold, true) - (16, 16, xtal_32n_pad(), x32n_, x32n_hold, true) - (17, 17, pad_dac1(), "", pdac1_hold, true) - (18, 18, pad_dac2(), "", pdac2_hold, true) - (19, 19, rtc_pad19(), "", pad19_hold, true) - (20, 20, rtc_pad20(), "", pad20_hold, true) - (21, 21, rtc_pad21(), "", pad21_hold, true) +rtcio_analog! { + ( 0, touch_pad(0), "", touch_pad0_hold ) + ( 1, touch_pad(1), "", touch_pad1_hold ) + ( 2, touch_pad(2), "", touch_pad2_hold ) + ( 3, touch_pad(3), "", touch_pad3_hold ) + ( 4, touch_pad(4), "", touch_pad4_hold ) + ( 5, touch_pad(5), "", touch_pad5_hold ) + ( 6, touch_pad(6), "", touch_pad6_hold ) + ( 7, touch_pad(7), "", touch_pad7_hold ) + ( 8, touch_pad(8), "", touch_pad8_hold ) + ( 9, touch_pad(9), "", touch_pad9_hold ) + (10, touch_pad(10), "", touch_pad10_hold) + (11, touch_pad(11), "", touch_pad11_hold) + (12, touch_pad(12), "", touch_pad12_hold) + (13, touch_pad(13), "", touch_pad13_hold) + (14, touch_pad(14), "", touch_pad14_hold) + (15, xtal_32p_pad(), x32p_, x32p_hold ) + (16, xtal_32n_pad(), x32n_, x32n_hold ) + (17, pad_dac1(), "", pdac1_hold ) + (18, pad_dac2(), "", pdac2_hold ) + (19, rtc_pad19(), "", pad19_hold ) + (20, rtc_pad20(), "", pad20_hold ) + (21, rtc_pad21(), "", pad21_hold ) } #[derive(Clone, Copy)] @@ -395,8 +493,8 @@ pub(crate) enum InterruptStatusRegisterAccess { impl InterruptStatusRegisterAccess { pub(crate) fn interrupt_status_read(self) -> u32 { match self { - Self::Bank0 => unsafe { &*GPIO::PTR }.pcpu_int().read().bits(), - Self::Bank1 => unsafe { &*GPIO::PTR }.pcpu_int1().read().bits(), + Self::Bank0 => unsafe { GPIO::steal() }.pcpu_int().read().bits(), + Self::Bank1 => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), } } } @@ -404,3 +502,9 @@ impl InterruptStatusRegisterAccess { // implement marker traits on USB pins impl crate::otg_fs::UsbDm for GpioPin<19> {} impl crate::otg_fs::UsbDp for GpioPin<20> {} + +fn enable_iomux_clk_gate() { + unsafe { crate::peripherals::SENS::steal() } + .sar_io_mux_conf() + .modify(|_, w| w.iomux_clk_gate_en().set_bit()); +} diff --git a/esp-hal/src/soc/esp32s3/gpio.rs b/esp-hal/src/soc/esp32s3/gpio.rs index a7daf2c6ec2..8bcb487987d 100644 --- a/esp-hal/src/soc/esp32s3/gpio.rs +++ b/esp-hal/src/soc/esp32s3/gpio.rs @@ -345,6 +345,104 @@ pub enum OutputSignal { GPIO = 256, } +macro_rules! rtcio_analog { + ( @ignore $rue:literal ) => {}; + + ( + $pin_num:expr, $pin_reg:expr, $prefix:pat, $hold:ident + ) => { + impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + fn rtc_number(&self) -> u8 { + $pin_num + } + + /// Set the RTC properties of the pin. If `mux` is true then then pin is + /// routed to RTC, when false it is routed to IO_MUX. + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) { + enable_iomux_clk_gate(); + + // disable input + paste::paste!{ + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_,w| unsafe { + w.[<$prefix fun_ie>]().bit(input_enable); + w.[<$prefix mux_sel>]().bit(mux); + w.[<$prefix fun_sel>]().bits(func as u8) + }); + } + } + + fn rtcio_pad_hold(&mut self, enable: bool) { + unsafe { $crate::peripherals::LPWR::steal() } + .pad_hold() + .modify(|_, w| w.$hold().bit(enable)); + } + } + + impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> + { + fn rtcio_pullup(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rue >]().bit(enable)); + } + } + + fn rtcio_pulldown(&mut self, enable: bool) { + paste::paste! { + unsafe { $crate::peripherals::RTC_IO::steal() } + .$pin_reg.modify(|_, w| w.[< $prefix rde >]().bit(enable)); + } + } + } + + impl $crate::gpio::AnalogPin for GpioPin<$pin_num> { + /// Configures the pin for analog mode. + fn set_analog(&self, _: $crate::private::Internal) { + use $crate::gpio::RtcPin; + enable_iomux_clk_gate(); + + let rtcio = unsafe{ $crate::peripherals::RTC_IO::steal() }; + + paste::paste! { + // disable input + rtcio.$pin_reg.modify(|_,w| w.[<$prefix fun_ie>]().bit(false)); + + // disable output + rtcio.enable_w1tc().write(|w| unsafe { w.enable_w1tc().bits(1 << self.rtc_number()) }); + + // disable open drain + rtcio.pin(self.rtc_number() as usize).modify(|_,w| w.pad_driver().bit(false)); + + rtcio.$pin_reg.modify(|_,w| { + w.[<$prefix fun_ie>]().clear_bit(); + + // Connect pin to analog / RTC module instead of standard GPIO + w.[<$prefix mux_sel>]().set_bit(); + + // Select function "RTC function 1" (GPIO) for analog use + unsafe { w.[<$prefix fun_sel>]().bits(0b00) }; + + // Disable pull-up and pull-down resistors on the pin + w.[<$prefix rue>]().bit(false); + w.[<$prefix rde>]().bit(false); + + w + }); + } + } + } + }; + + ( + $( ( $pin_num:expr, $pin_reg:expr, $prefix:pat, $hold:ident ) )+ + ) => { + $( + rtcio_analog!($pin_num, $pin_reg, $prefix, $hold); + )+ + }; +} + crate::gpio! { (0, [Input, Output, Analog, RtcIo]) (1, [Input, Output, Analog, RtcIo]) @@ -393,29 +491,29 @@ crate::gpio! { (48, [Input, Output]) } -crate::rtcio_analog! { - ( 0, 0, touch_pad(0), "", touch_pad0_hold, true) - ( 1, 1, touch_pad(1), "", touch_pad1_hold, true) - ( 2, 2, touch_pad(2), "", touch_pad2_hold, true) - ( 3, 3, touch_pad(3), "", touch_pad3_hold, true) - ( 4, 4, touch_pad(4), "", touch_pad4_hold, true) - ( 5, 5, touch_pad(5), "", touch_pad5_hold, true) - ( 6, 6, touch_pad(6), "", touch_pad6_hold, true) - ( 7, 7, touch_pad(7), "", touch_pad7_hold, true) - ( 8, 8, touch_pad(8), "", touch_pad8_hold, true) - ( 9, 9, touch_pad(9), "", touch_pad9_hold, true) - (10, 10, touch_pad(10), "", touch_pad10_hold, true) - (11, 11, touch_pad(11), "", touch_pad11_hold, true) - (12, 12, touch_pad(12), "", touch_pad12_hold, true) - (13, 13, touch_pad(13), "", touch_pad13_hold, true) - (14, 14, touch_pad(14), "", touch_pad14_hold, true) - (15, 15, xtal_32p_pad(), x32p_, x32p_hold, true) - (16, 16, xtal_32n_pad(), x32n_, x32n_hold, true) - (17, 17, pad_dac1(), pdac1_, pdac1_hold, true) - (18, 18, pad_dac2(), pdac2_, pdac2_hold, true) - (19, 19, rtc_pad19(), "", pad19_hold, true) - (20, 20, rtc_pad20(), "", pad20_hold, true) - (21, 21, rtc_pad21(), "", pad21_hold, true) +rtcio_analog! { + ( 0, touch_pad(0), "", touch_pad0_hold ) + ( 1, touch_pad(1), "", touch_pad1_hold ) + ( 2, touch_pad(2), "", touch_pad2_hold ) + ( 3, touch_pad(3), "", touch_pad3_hold ) + ( 4, touch_pad(4), "", touch_pad4_hold ) + ( 5, touch_pad(5), "", touch_pad5_hold ) + ( 6, touch_pad(6), "", touch_pad6_hold ) + ( 7, touch_pad(7), "", touch_pad7_hold ) + ( 8, touch_pad(8), "", touch_pad8_hold ) + ( 9, touch_pad(9), "", touch_pad9_hold ) + (10, touch_pad(10), "", touch_pad10_hold) + (11, touch_pad(11), "", touch_pad11_hold) + (12, touch_pad(12), "", touch_pad12_hold) + (13, touch_pad(13), "", touch_pad13_hold) + (14, touch_pad(14), "", touch_pad14_hold) + (15, xtal_32p_pad(), x32p_, x32p_hold ) + (16, xtal_32n_pad(), x32n_, x32n_hold ) + (17, pad_dac1(), pdac1_, pdac1_hold ) + (18, pad_dac2(), pdac2_, pdac2_hold ) + (19, rtc_pad19(), "", pad19_hold ) + (20, rtc_pad20(), "", pad20_hold ) + (21, rtc_pad21(), "", pad21_hold ) } // Whilst the S3 is a dual core chip, it shares the enable registers between @@ -429,8 +527,8 @@ pub(crate) enum InterruptStatusRegisterAccess { impl InterruptStatusRegisterAccess { pub(crate) fn interrupt_status_read(self) -> u32 { match self { - Self::Bank0 => unsafe { &*GPIO::PTR }.pcpu_int().read().bits(), - Self::Bank1 => unsafe { &*GPIO::PTR }.pcpu_int1().read().bits(), + Self::Bank0 => unsafe { GPIO::steal() }.pcpu_int().read().bits(), + Self::Bank1 => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), } } } @@ -438,3 +536,9 @@ impl InterruptStatusRegisterAccess { // implement marker traits on USB pins impl crate::otg_fs::UsbDm for GpioPin<19> {} impl crate::otg_fs::UsbDp for GpioPin<20> {} + +fn enable_iomux_clk_gate() { + unsafe { crate::peripherals::SENS::steal() } + .sar_peri_clk_gate_conf() + .modify(|_, w| w.iomux_clk_en().set_bit()); +} From 4546f861c849dc9249769a67ae0a6e2e48c77eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 30 Oct 2024 16:51:33 +0100 Subject: [PATCH 04/67] Reduce UART Instance trait to the bare minimum (#2410) * Merge signal fns * Remove logic from UART Instance, remove uart_number * Use the unwrap macro * Place peripheral info into static structs * Clean up * Clean up * Update todo * Rename * Separate out state --- esp-hal/src/uart.rs | 1065 ++++++++++++++++++++----------------------- 1 file changed, 500 insertions(+), 565 deletions(-) diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index e22355c1122..dacfa36d481 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -128,6 +128,7 @@ use core::marker::PhantomData; +use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; use self::config::Config; @@ -150,14 +151,8 @@ use crate::{ Mode, }; -const CONSOLE_UART_NUM: usize = 0; const UART_FIFO_SIZE: u16 = 128; -#[cfg(not(any(esp32, esp32s2)))] -use crate::soc::constants::RC_FAST_CLK; -#[cfg(any(esp32, esp32s2))] -use crate::soc::constants::REF_TICK; - /// UART Error #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -390,10 +385,15 @@ pub mod config { data_bits: DataBits::DataBits8, parity: Parity::ParityNone, stop_bits: StopBits::STOP1, - #[cfg(any(esp32c6, esp32h2, lp_uart))] - clock_source: super::ClockSource::Xtal, - #[cfg(not(any(esp32c6, esp32h2, lp_uart)))] - clock_source: super::ClockSource::Apb, + clock_source: { + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2, lp_uart))] { + super::ClockSource::Xtal + } else { + super::ClockSource::Apb + } + } + }, rx_fifo_full_threshold: UART_FULL_THRESH_DEFAULT, rx_timeout: Some(UART_TOUT_THRESH_DEFAULT), } @@ -459,20 +459,20 @@ where } } - fn with_rx(self, rx: impl Peripheral

+ 'd) -> Self { + fn with_rx(self, rx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rx); rx.init_input(Pull::Up, Internal); - rx.connect_input_to_peripheral(self.uart.rx_signal(), Internal); + rx.connect_input_to_peripheral(self.uart.info().rx_signal, Internal); self } - fn with_tx(self, tx: impl Peripheral

+ 'd) -> Self { + fn with_tx(self, tx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(tx); // Make sure we don't cause an unexpected low pulse on the pin. tx.set_output_high(true, Internal); tx.set_to_push_pull_output(Internal); - tx.connect_peripheral_to_output(self.uart.tx_signal(), Internal); + tx.connect_peripheral_to_output(self.uart.info().tx_signal, Internal); self } @@ -526,10 +526,10 @@ where M: Mode, { /// Configure RTS pin - pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { + pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rts); rts.set_to_push_pull_output(Internal); - rts.connect_peripheral_to_output(self.uart.rts_signal(), Internal); + rts.connect_peripheral_to_output(self.uart.info().rts_signal, Internal); self } @@ -545,9 +545,8 @@ where } fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { - let register_block = self.uart.register_block(); - if get_tx_fifo_count(register_block) < UART_FIFO_SIZE { - register_block + if self.tx_fifo_count() < UART_FIFO_SIZE { + self.register_block() .fifo() .write(|w| unsafe { w.rxfifo_rd_byte().bits(word) }); @@ -557,31 +556,81 @@ where } } + #[allow(clippy::useless_conversion)] + /// Returns the number of bytes currently in the TX FIFO for this UART + /// instance. + fn tx_fifo_count(&self) -> u16 { + self.register_block() + .status() + .read() + .txfifo_cnt() + .bits() + .into() + } + /// Flush the transmit buffer of the UART pub fn flush_tx(&mut self) -> nb::Result<(), Error> { - if self.uart.is_tx_idle() { + if self.is_tx_idle() { Ok(()) } else { Err(nb::Error::WouldBlock) } } + + /// Checks if the TX line is idle for this UART instance. + /// + /// Returns `true` if the transmit line is idle, meaning no data is + /// currently being transmitted. + fn is_tx_idle(&self) -> bool { + #[cfg(esp32)] + let status = self.register_block().status(); + #[cfg(not(esp32))] + let status = self.register_block().fsm_status(); + + status.read().st_utx_out().bits() == 0x0 + } + + /// Disables all TX-related interrupts for this UART instance. + /// + /// This function clears and disables the `transmit FIFO empty` interrupt, + /// `transmit break done`, `transmit break idle done`, and `transmit done` + /// interrupts. + fn disable_tx_interrupts(&self) { + self.register_block().int_clr().write(|w| { + w.txfifo_empty().clear_bit_by_one(); + w.tx_brk_done().clear_bit_by_one(); + w.tx_brk_idle_done().clear_bit_by_one(); + w.tx_done().clear_bit_by_one() + }); + + self.register_block().int_ena().write(|w| { + w.txfifo_empty().clear_bit(); + w.tx_brk_done().clear_bit(); + w.tx_brk_idle_done().clear_bit(); + w.tx_done().clear_bit() + }); + } + + fn register_block(&self) -> &RegisterBlock { + self.uart.info().register_block() + } } impl<'d> UartTx<'d, Blocking> { /// Create a new UART TX instance in [`Blocking`] mode. - pub fn new( + pub fn new( uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_typed(uart.map_into(), tx) } /// Create a new UART TX instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config( + pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, - tx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config_typed(uart.map_into(), config, tx) } @@ -592,19 +641,19 @@ where T: Instance, { /// Create a new UART TX instance in [`Blocking`] mode. - pub fn new_typed( + pub fn new_typed( uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config_typed(uart, Config::default(), tx) } /// Create a new UART TX instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config_typed( + pub fn new_with_config_typed( uart: impl Peripheral

+ 'd, config: Config, - tx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { let (_, uart_tx) = UartBuilder::<'d, Blocking, T>::new(uart) .with_tx(tx) @@ -615,94 +664,24 @@ where } } -#[allow(clippy::useless_conversion)] -/// Returns the number of bytes currently in the TX FIFO for this UART -/// instance. -fn get_tx_fifo_count(register_block: &RegisterBlock) -> u16 { - register_block.status().read().txfifo_cnt().bits().into() -} - -#[allow(clippy::useless_conversion)] -fn get_rx_fifo_count(register_block: &RegisterBlock) -> u16 { - let fifo_cnt: u16 = register_block.status().read().rxfifo_cnt().bits().into(); - // Calculate the real count based on the FIFO read and write offset address: - // https://www.espressif.com/sites/default/files/documentation/esp32_errata_en.pdf - // section 3.17 - #[cfg(esp32)] +#[inline(always)] +fn sync_regs(_register_block: &RegisterBlock) { + #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] { - let status = register_block.mem_rx_status().read(); - let rd_addr = status.mem_rx_rd_addr().bits(); - let wr_addr = status.mem_rx_wr_addr().bits(); - - if wr_addr > rd_addr { - wr_addr - rd_addr - } else if wr_addr < rd_addr { - (wr_addr + UART_FIFO_SIZE) - rd_addr - } else if fifo_cnt > 0 { - UART_FIFO_SIZE - } else { - 0 - } - } - - #[cfg(not(esp32))] - fifo_cnt -} - -fn read_bytes(register_block: &RegisterBlock, buf: &mut [u8]) -> Result<(), Error> { - cfg_if::cfg_if! { - if #[cfg(esp32s2)] { - // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: - let fifo = unsafe { - &*((register_block.fifo().as_ptr() as *mut u8).add(0x20C00000) - as *mut crate::peripherals::uart0::FIFO) - }; - } else { - let fifo = register_block.fifo(); - } - } - - for byte in buf.iter_mut() { - while get_rx_fifo_count(register_block) == 0 { - // Block until we received at least one byte - } - *byte = fifo.read().rxfifo_rd_byte().bits(); - } - - Ok(()) -} - -fn read_byte(register_block: &RegisterBlock) -> nb::Result { - cfg_if::cfg_if! { - if #[cfg(esp32s2)] { - // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: - let fifo = unsafe { - &*((register_block.fifo().as_ptr() as *mut u8).add(0x20C00000) - as *mut crate::peripherals::uart0::FIFO) - }; - } else { - let fifo = register_block.fifo(); + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2))] { + let update_reg = _register_block.reg_update(); + } else { + let update_reg = _register_block.id(); + } } - } - if get_rx_fifo_count(register_block) > 0 { - Ok(fifo.read().rxfifo_rd_byte().bits()) - } else { - Err(nb::Error::WouldBlock) - } -} + update_reg.modify(|_, w| w.reg_update().set_bit()); -fn drain_fifo(register_block: &RegisterBlock, buf: &mut [u8]) -> usize { - let mut count = 0; - while count < buf.len() { - if let Ok(byte) = read_byte(register_block) { - buf[count] = byte; - count += 1; - } else { - break; + while update_reg.read().reg_update().bit_is_set() { + // wait } } - count } impl<'d, M, T> UartRx<'d, M, T> @@ -711,28 +690,106 @@ where M: Mode, { /// Configure CTS pin - pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { + pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cts); cts.init_input(Pull::None, Internal); - cts.connect_input_to_peripheral(self.uart.cts_signal(), Internal); + cts.connect_input_to_peripheral(self.uart.info().cts_signal, Internal); self } /// Fill a buffer with received bytes pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { - read_bytes(self.uart.register_block(), buf) + cfg_if::cfg_if! { + if #[cfg(esp32s2)] { + // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: + let fifo = unsafe { + &*((self.register_block().fifo().as_ptr() as *mut u8).add(0x20C00000) + as *mut crate::peripherals::uart0::FIFO) + }; + } else { + let fifo = self.register_block().fifo(); + } + } + + for byte in buf.iter_mut() { + while self.rx_fifo_count() == 0 { + // Block until we received at least one byte + } + *byte = fifo.read().rxfifo_rd_byte().bits(); + } + + Ok(()) } /// Read a byte from the UART pub fn read_byte(&mut self) -> nb::Result { - read_byte(self.uart.register_block()) + cfg_if::cfg_if! { + if #[cfg(esp32s2)] { + // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: + let fifo = unsafe { + &*((self.register_block().fifo().as_ptr() as *mut u8).add(0x20C00000) + as *mut crate::peripherals::uart0::FIFO) + }; + } else { + let fifo = self.register_block().fifo(); + } + } + + if self.rx_fifo_count() > 0 { + Ok(fifo.read().rxfifo_rd_byte().bits()) + } else { + Err(nb::Error::WouldBlock) + } } /// Read all available bytes from the RX FIFO into the provided buffer and /// returns the number of read bytes. Never blocks pub fn drain_fifo(&mut self, buf: &mut [u8]) -> usize { - drain_fifo(self.uart.register_block(), buf) + let mut count = 0; + while count < buf.len() { + if let Ok(byte) = self.read_byte() { + buf[count] = byte; + count += 1; + } else { + break; + } + } + count + } + + #[allow(clippy::useless_conversion)] + fn rx_fifo_count(&self) -> u16 { + let fifo_cnt: u16 = self + .register_block() + .status() + .read() + .rxfifo_cnt() + .bits() + .into(); + + // Calculate the real count based on the FIFO read and write offset address: + // https://www.espressif.com/sites/default/files/documentation/esp32_errata_en.pdf + // section 3.17 + #[cfg(esp32)] + { + let status = self.register_block().mem_rx_status().read(); + let rd_addr = status.mem_rx_rd_addr().bits(); + let wr_addr = status.mem_rx_wr_addr().bits(); + + if wr_addr > rd_addr { + wr_addr - rd_addr + } else if wr_addr < rd_addr { + (wr_addr + UART_FIFO_SIZE) - rd_addr + } else if fifo_cnt > 0 { + UART_FIFO_SIZE + } else { + 0 + } + } + + #[cfg(not(esp32))] + fifo_cnt } /// Configures the RX-FIFO threshold @@ -758,8 +815,7 @@ where return Err(Error::InvalidArgument); } - self.uart - .register_block() + self.register_block() .conf1() .modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold as _) }); @@ -787,67 +843,88 @@ where } } - cfg_if::cfg_if! { - if #[cfg(esp32)] { - let reg_thrhd = self.uart.register_block().conf1(); - } else if #[cfg(any(esp32c6, esp32h2))] { - let reg_thrhd = self.uart.register_block().tout_conf(); - } else { - let reg_thrhd = self.uart.register_block().mem_conf(); + let register_block = self.register_block(); + + if let Some(timeout) = timeout { + // the esp32 counts directly in number of symbols (symbol len fixed to 8) + #[cfg(esp32)] + let timeout_reg = timeout; + // all other count in bits, so we need to multiply by the symbol len. + #[cfg(not(esp32))] + let timeout_reg = timeout as u16 * self.symbol_len as u16; + + if timeout_reg > MAX_THRHD { + return Err(Error::InvalidArgument); + } + + cfg_if::cfg_if! { + if #[cfg(esp32)] { + let reg_thrhd = register_block.conf1(); + } else if #[cfg(any(esp32c6, esp32h2))] { + let reg_thrhd = register_block.tout_conf(); + } else { + let reg_thrhd = register_block.mem_conf(); + } } + reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) }); } cfg_if::cfg_if! { if #[cfg(any(esp32c6, esp32h2))] { - let reg_en = self.uart.register_block().tout_conf(); + let reg_en = register_block.tout_conf(); } else { - let reg_en = self.uart.register_block().conf1(); + let reg_en = register_block.conf1(); } } + reg_en.modify(|_, w| w.rx_tout_en().bit(timeout.is_some())); - match timeout { - None => { - reg_en.modify(|_, w| w.rx_tout_en().clear_bit()); - } - Some(timeout) => { - // the esp32 counts directly in number of symbols (symbol len fixed to 8) - #[cfg(esp32)] - let timeout_reg = timeout; - // all other count in bits, so we need to multiply by the symbol len. - #[cfg(not(esp32))] - let timeout_reg = timeout as u16 * self.symbol_len as u16; + sync_regs(register_block); + self.rx_timeout_config = timeout; - if timeout_reg > MAX_THRHD { - return Err(Error::InvalidArgument); - } + Ok(()) + } - reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) }); - reg_en.modify(|_, w| w.rx_tout_en().set_bit()); - } - } + /// Disables all RX-related interrupts for this UART instance. + /// + /// This function clears and disables the `receive FIFO full` interrupt, + /// `receive FIFO overflow`, `receive FIFO timeout`, and `AT command + /// character detection` interrupts. + fn disable_rx_interrupts(&self) { + self.register_block().int_clr().write(|w| { + w.rxfifo_full().clear_bit_by_one(); + w.rxfifo_ovf().clear_bit_by_one(); + w.rxfifo_tout().clear_bit_by_one(); + w.at_cmd_char_det().clear_bit_by_one() + }); - self.rx_timeout_config = timeout; + self.register_block().int_ena().write(|w| { + w.rxfifo_full().clear_bit(); + w.rxfifo_ovf().clear_bit(); + w.rxfifo_tout().clear_bit(); + w.at_cmd_char_det().clear_bit() + }); + } - self.uart.sync_regs(); - Ok(()) + fn register_block(&self) -> &RegisterBlock { + self.uart.info().register_block() } } impl<'d> UartRx<'d, Blocking> { /// Create a new UART RX instance in [`Blocking`] mode. - pub fn new( + pub fn new( uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { UartRx::new_typed(uart.map_into(), rx) } /// Create a new UART RX instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config( + pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { UartRx::new_with_config_typed(uart.map_into(), config, rx) } @@ -858,19 +935,19 @@ where T: Instance, { /// Create a new UART RX instance in [`Blocking`] mode. - pub fn new_typed( + pub fn new_typed( uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config_typed(uart, Config::default(), rx) } /// Create a new UART RX instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config_typed( + pub fn new_with_config_typed( uart: impl Peripheral

+ 'd, config: Config, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { let (uart_rx, _) = UartBuilder::new(uart).with_rx(rx).init(config)?.split(); @@ -880,21 +957,21 @@ where impl<'d> Uart<'d, Blocking> { /// Create a new UART instance in [`Blocking`] mode. - pub fn new( + pub fn new( uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_typed(uart.map_into(), rx, tx) } /// Create a new UART instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config( + pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config_typed(uart.map_into(), config, rx, tx) } @@ -905,21 +982,21 @@ where T: Instance, { /// Create a new UART instance in [`Blocking`] mode. - pub fn new_typed( + pub fn new_typed( uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config_typed(uart, Config::default(), rx, tx) } /// Create a new UART instance with configuration options in /// [`Blocking`] mode. - pub fn new_with_config_typed( + pub fn new_with_config_typed( uart: impl Peripheral

+ 'd, config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, ) -> Result { UartBuilder::new(uart).with_tx(tx).with_rx(rx).init(config) } @@ -948,32 +1025,32 @@ where { fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) { // `self.tx.uart` and `self.rx.uart` are the same + let interrupt = self.tx.uart.info().interrupt; unsafe { - crate::interrupt::bind_interrupt(self.tx.uart.interrupt(), handler.handler()); - crate::interrupt::enable(self.tx.uart.interrupt(), handler.priority()).unwrap(); + crate::interrupt::bind_interrupt(interrupt, handler.handler()); + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); } } /// Configure CTS pin - pub fn with_cts(mut self, cts: impl Peripheral

+ 'd) -> Self { + pub fn with_cts(mut self, cts: impl Peripheral

+ 'd) -> Self { self.rx = self.rx.with_cts(cts); self } /// Configure RTS pin - pub fn with_rts(mut self, rts: impl Peripheral

+ 'd) -> Self { + pub fn with_rts(mut self, rts: impl Peripheral

+ 'd) -> Self { self.tx = self.tx.with_rts(rts); self } fn register_block(&self) -> &RegisterBlock { // `self.tx.uart` and `self.rx.uart` are the same - self.tx.uart.register_block() + self.tx.uart.info().register_block() } fn sync_regs(&self) { - // `self.tx.uart` and `self.rx.uart` are the same - self.tx.uart.sync_regs(); + sync_regs(self.register_block()); } /// Split the UART into a transmitter and receiver @@ -1115,24 +1192,22 @@ where /// Change the number of stop bits pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { - // workaround for hardware issue, when UART stop bit set as 2-bit mode. #[cfg(esp32)] - if stop_bits == config::StopBits::STOP2 { - self.register_block() - .rs485_conf() - .modify(|_, w| w.dl1_en().bit(true)); - - self.register_block() - .conf0() - .modify(|_, w| unsafe { w.stop_bit_num().bits(1) }); - } else { - self.register_block() - .rs485_conf() - .modify(|_, w| w.dl1_en().bit(false)); - - self.register_block() - .conf0() - .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); + { + // workaround for hardware issue, when UART stop bit set as 2-bit mode. + if stop_bits == config::StopBits::STOP2 { + self.register_block() + .rs485_conf() + .modify(|_, w| w.dl1_en().bit(stop_bits == config::StopBits::STOP2)); + + self.register_block().conf0().modify(|_, w| { + if stop_bits == config::StopBits::STOP2 { + unsafe { w.stop_bit_num().bits(1) } + } else { + unsafe { w.stop_bit_num().bits(stop_bits as u8) } + } + }); + } } #[cfg(not(esp32))] @@ -1167,12 +1242,11 @@ where let clk = match clock_source { ClockSource::Apb => clocks.apb_clock.to_Hz(), ClockSource::Xtal => clocks.xtal_clock.to_Hz(), - ClockSource::RcFast => RC_FAST_CLK.to_Hz(), + ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), }; if clock_source == ClockSource::RcFast { - let rtc_cntl = unsafe { &*crate::peripherals::RTC_CNTL::ptr() }; - rtc_cntl + unsafe { crate::peripherals::RTC_CNTL::steal() } .clk_conf() .modify(|_, w| w.dig_clk8m_en().variant(true)); // esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH); @@ -1180,7 +1254,7 @@ where } let max_div = 0b1111_1111_1111 - 1; - let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); + let clk_div = clk.div_ceil(max_div * baudrate); self.register_block().clk_conf().write(|w| unsafe { w.sclk_sel().bits(match clock_source { ClockSource::Apb => 1, @@ -1208,49 +1282,45 @@ where let clk = match clock_source { ClockSource::Apb => clocks.apb_clock.to_Hz(), ClockSource::Xtal => clocks.xtal_clock.to_Hz(), - ClockSource::RcFast => RC_FAST_CLK.to_Hz(), + ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), }; let max_div = 0b1111_1111_1111 - 1; let clk_div = clk.div_ceil(max_div * baudrate); // UART clocks are configured via PCR - let pcr = unsafe { &*crate::peripherals::PCR::PTR }; - - match self.tx.uart.uart_number() { - 0 => { - pcr.uart0_conf() - .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); - - pcr.uart0_sclk_conf().modify(|_, w| unsafe { - w.uart0_sclk_div_a().bits(0); - w.uart0_sclk_div_b().bits(0); - w.uart0_sclk_div_num().bits(clk_div as u8 - 1); - w.uart0_sclk_sel().bits(match clock_source { - ClockSource::Apb => 1, - ClockSource::RcFast => 2, - ClockSource::Xtal => 3, - }); - w.uart0_sclk_en().set_bit() + let pcr = unsafe { crate::peripherals::PCR::steal() }; + + if self.is_instance(unsafe { crate::peripherals::UART0::steal() }) { + pcr.uart0_conf() + .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); + + pcr.uart0_sclk_conf().modify(|_, w| unsafe { + w.uart0_sclk_div_a().bits(0); + w.uart0_sclk_div_b().bits(0); + w.uart0_sclk_div_num().bits(clk_div as u8 - 1); + w.uart0_sclk_sel().bits(match clock_source { + ClockSource::Apb => 1, + ClockSource::RcFast => 2, + ClockSource::Xtal => 3, }); - } - 1 => { - pcr.uart1_conf() - .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); - - pcr.uart1_sclk_conf().modify(|_, w| unsafe { - w.uart1_sclk_div_a().bits(0); - w.uart1_sclk_div_b().bits(0); - w.uart1_sclk_div_num().bits(clk_div as u8 - 1); - w.uart1_sclk_sel().bits(match clock_source { - ClockSource::Apb => 1, - ClockSource::RcFast => 2, - ClockSource::Xtal => 3, - }); - w.uart1_sclk_en().set_bit() + w.uart0_sclk_en().set_bit() + }); + } else { + pcr.uart1_conf() + .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); + + pcr.uart1_sclk_conf().modify(|_, w| unsafe { + w.uart1_sclk_div_a().bits(0); + w.uart1_sclk_div_b().bits(0); + w.uart1_sclk_div_num().bits(clk_div as u8 - 1); + w.uart1_sclk_sel().bits(match clock_source { + ClockSource::Apb => 1, + ClockSource::RcFast => 2, + ClockSource::Xtal => 3, }); - } - _ => unreachable!(), // ESP32-C6 only has 2 UART instances + w.uart1_sclk_en().set_bit() + }); } let clk = clk / clk_div; @@ -1266,19 +1336,15 @@ where #[cfg(any(esp32, esp32s2))] fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource) { - let clocks = Clocks::get(); let clk = match clock_source { - ClockSource::Apb => clocks.apb_clock.to_Hz(), - ClockSource::RefTick => REF_TICK.to_Hz(), /* ESP32(/-S2) TRM, section 3.2.4.2 - * (6.2.4.2 for S2) */ + ClockSource::Apb => Clocks::get().apb_clock.to_Hz(), + // ESP32(/-S2) TRM, section 3.2.4.2 (6.2.4.2 for S2) + ClockSource::RefTick => crate::soc::constants::REF_TICK.to_Hz(), }; - self.register_block().conf0().modify(|_, w| { - w.tick_ref_always_on().bit(match clock_source { - ClockSource::Apb => true, - ClockSource::RefTick => false, - }) - }); + self.register_block() + .conf0() + .modify(|_, w| w.tick_ref_always_on().bit(clock_source == ClockSource::Apb)); let divider = clk / baudrate; @@ -1300,8 +1366,7 @@ where if #[cfg(any(esp32, esp32s2))] { // Nothing to do } else if #[cfg(any(esp32c2, esp32c3, esp32s3))] { - let system = unsafe { crate::peripherals::SYSTEM::steal() }; - system + unsafe { crate::peripherals::SYSTEM::steal() } .perip_clk_en0() .modify(|_, w| w.uart_mem_clk_en().set_bit()); } else { @@ -1313,8 +1378,8 @@ where PeripheralClockControl::enable(self.tx.uart.peripheral()); self.uart_peripheral_reset(); - self.tx.uart.disable_rx_interrupts(); - self.tx.uart.disable_tx_interrupts(); + self.rx.disable_rx_interrupts(); + self.tx.disable_tx_interrupts(); self.rx .set_rx_fifo_full_threshold(config.rx_fifo_full_threshold)?; @@ -1344,6 +1409,10 @@ where Ok(()) } + fn is_instance(&self, other: impl Instance) -> bool { + self.tx.uart.info() == other.info() + } + #[inline(always)] fn uart_peripheral_reset(&self) { // don't reset the console UART - this will cause trouble (i.e. the UART will @@ -1354,47 +1423,42 @@ where // already enough to make this a no-go. (i.e. one needs to mute the ROM // code via efuse / strapping pin AND use a silent bootloader) // - // Ideally this should be configurable once we have a solution for https://github.com/esp-rs/esp-hal/issues/1111 + // TODO: make this configurable // see https://github.com/espressif/esp-idf/blob/5f4249357372f209fdd57288265741aaba21a2b1/components/esp_driver_uart/src/uart.c#L179 - if self.tx.uart.uart_number() == CONSOLE_UART_NUM { + if self.is_instance(unsafe { crate::peripherals::UART0::steal() }) { return; } - #[cfg(not(any(esp32, esp32s2)))] - self.register_block() - .clk_conf() - .modify(|_, w| w.rst_core().set_bit()); + fn rst_core(_reg_block: &RegisterBlock, _enable: bool) { + #[cfg(not(any(esp32, esp32s2)))] + _reg_block + .clk_conf() + .modify(|_, w| w.rst_core().bit(_enable)); + } + rst_core(self.register_block(), true); PeripheralClockControl::reset(self.tx.uart.peripheral()); - - #[cfg(not(any(esp32, esp32s2)))] - self.register_block() - .clk_conf() - .modify(|_, w| w.rst_core().clear_bit()); + rst_core(self.register_block(), false); } fn rxfifo_reset(&mut self) { - self.register_block() - .conf0() - .modify(|_, w| w.rxfifo_rst().set_bit()); - self.sync_regs(); + fn rxfifo_rst(reg_block: &RegisterBlock, enable: bool) { + reg_block.conf0().modify(|_, w| w.rxfifo_rst().bit(enable)); + sync_regs(reg_block); + } - self.register_block() - .conf0() - .modify(|_, w| w.rxfifo_rst().clear_bit()); - self.sync_regs(); + rxfifo_rst(self.register_block(), true); + rxfifo_rst(self.register_block(), false); } fn txfifo_reset(&mut self) { - self.register_block() - .conf0() - .modify(|_, w| w.txfifo_rst().set_bit()); - self.sync_regs(); + fn txfifo_rst(reg_block: &RegisterBlock, enable: bool) { + reg_block.conf0().modify(|_, w| w.txfifo_rst().bit(enable)); + sync_regs(reg_block); + } - self.register_block() - .conf0() - .modify(|_, w| w.txfifo_rst().clear_bit()); - self.sync_regs(); + txfifo_rst(self.register_block(), true); + txfifo_rst(self.register_block(), false); } } @@ -1409,184 +1473,6 @@ where } } -/// UART Peripheral Instance -pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { - /// Returns a reference to the UART register block for the specific - /// instance. - /// - /// # Safety - /// This function returns a reference to the raw hardware registers, so - /// direct interaction with the registers may require careful handling - /// to avoid unintended side effects. - fn register_block(&self) -> &RegisterBlock; - - /// Returns the UART number associated with this instance (e.g., UART0, - /// UART1, etc.). - fn uart_number(&self) -> usize; - - /// Returns the interrupt handler for this UART instance. - fn async_handler(&self) -> InterruptHandler; - - /// Returns the interrupt associated with this UART instance. - fn interrupt(&self) -> Interrupt; - - #[doc(hidden)] - #[inline(always)] - fn sync_regs(&self) { - #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] - { - cfg_if::cfg_if! { - if #[cfg(any(esp32c6, esp32h2))] { - let update_reg = self.register_block().reg_update(); - } else { - let update_reg = self.register_block().id(); - } - } - - update_reg.modify(|_, w| w.reg_update().set_bit()); - - while update_reg.read().reg_update().bit_is_set() { - // wait - } - } - } - - /// Disables all TX-related interrupts for this UART instance. - /// - /// This function clears and disables the `transmit FIFO empty` interrupt, - /// `transmit break done`, `transmit break idle done`, and `transmit done` - /// interrupts. - fn disable_tx_interrupts(&self) { - self.register_block().int_clr().write(|w| { - w.txfifo_empty().clear_bit_by_one(); - w.tx_brk_done().clear_bit_by_one(); - w.tx_brk_idle_done().clear_bit_by_one(); - w.tx_done().clear_bit_by_one() - }); - - self.register_block().int_ena().write(|w| { - w.txfifo_empty().clear_bit(); - w.tx_brk_done().clear_bit(); - w.tx_brk_idle_done().clear_bit(); - w.tx_done().clear_bit() - }); - } - - /// Disables all RX-related interrupts for this UART instance. - /// - /// This function clears and disables the `receive FIFO full` interrupt, - /// `receive FIFO overflow`, `receive FIFO timeout`, and `AT command - /// character detection` interrupts. - fn disable_rx_interrupts(&self) { - self.register_block().int_clr().write(|w| { - w.rxfifo_full().clear_bit_by_one(); - w.rxfifo_ovf().clear_bit_by_one(); - w.rxfifo_tout().clear_bit_by_one(); - w.at_cmd_char_det().clear_bit_by_one() - }); - - self.register_block().int_ena().write(|w| { - w.rxfifo_full().clear_bit(); - w.rxfifo_ovf().clear_bit(); - w.rxfifo_tout().clear_bit(); - w.at_cmd_char_det().clear_bit() - }); - } - - /// Checks if the TX line is idle for this UART instance. - /// - /// Returns `true` if the transmit line is idle, meaning no data is - /// currently being transmitted. - fn is_tx_idle(&self) -> bool { - #[cfg(esp32)] - let status = self.register_block().status(); - #[cfg(not(esp32))] - let status = self.register_block().fsm_status(); - - status.read().st_utx_out().bits() == 0x0 - } - - /// Checks if the RX line is idle for this UART instance. - /// - /// Returns `true` if the receive line is idle, meaning no data is currently - /// being received. - fn is_rx_idle(&self) -> bool { - #[cfg(esp32)] - let status = self.register_block().status(); - #[cfg(not(esp32))] - let status = self.register_block().fsm_status(); - - status.read().st_urx_out().bits() == 0x0 - } - - /// Returns the output signal identifier for the TX pin of this UART - /// instance. - fn tx_signal(&self) -> OutputSignal; - - /// Returns the input signal identifier for the RX pin of this UART - /// instance. - fn rx_signal(&self) -> InputSignal; - - /// Returns the input signal identifier for the CTS (Clear to Send) pin of - /// this UART instance. - fn cts_signal(&self) -> InputSignal; - - /// Returns the output signal identifier for the RTS (Request to Send) pin - /// of this UART instance. - fn rts_signal(&self) -> OutputSignal; -} - -macro_rules! impl_instance { - ($inst:ident, $num:expr, $txd:ident, $rxd:ident, $cts:ident, $rts:ident, $async_handler:path) => { - impl Instance for crate::peripherals::$inst { - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - unsafe { &*crate::peripherals::$inst::PTR } - } - - #[inline(always)] - fn uart_number(&self) -> usize { - $num - } - - #[inline(always)] - fn async_handler(&self) -> InterruptHandler { - $async_handler - } - - #[inline(always)] - fn interrupt(&self) -> Interrupt { - Interrupt::$inst - } - - #[inline(always)] - fn tx_signal(&self) -> OutputSignal { - OutputSignal::$txd - } - - #[inline(always)] - fn rx_signal(&self) -> InputSignal { - InputSignal::$rxd - } - - #[inline(always)] - fn cts_signal(&self) -> InputSignal { - InputSignal::$cts - } - - #[inline(always)] - fn rts_signal(&self) -> OutputSignal { - OutputSignal::$rts - } - } - }; -} - -impl_instance!(UART0, 0, U0TXD, U0RXD, U0CTS, U0RTS, asynch::uart0); -impl_instance!(UART1, 1, U1TXD, U1RXD, U1CTS, U1RTS, asynch::uart1); -#[cfg(uart2)] -impl_instance!(UART2, 2, U2TXD, U2RXD, U2CTS, U2RTS, asynch::uart2); - impl ufmt_write::uWrite for Uart<'_, M, T> where T: Instance, @@ -1791,7 +1677,7 @@ where return Ok(0); } - while get_rx_fifo_count(self.uart.register_block()) == 0 { + while self.rx_fifo_count() == 0 { // Block until we received at least one byte } @@ -1815,7 +1701,7 @@ where M: Mode, { fn read_ready(&mut self) -> Result { - Ok(get_rx_fifo_count(self.uart.register_block()) > 0) + Ok(self.rx_fifo_count() > 0) } } @@ -1858,18 +1744,11 @@ where mod asynch { use core::task::Poll; - use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; - use procmacros::handler; use super::*; use crate::Async; - const NUM_UART: usize = 1 + cfg!(uart1) as usize + cfg!(uart2) as usize; - - static TX_WAKERS: [AtomicWaker; NUM_UART] = [const { AtomicWaker::new() }; NUM_UART]; - static RX_WAKERS: [AtomicWaker; NUM_UART] = [const { AtomicWaker::new() }; NUM_UART]; - #[derive(EnumSetType, Debug)] pub(crate) enum TxEvent { TxDone, @@ -1892,34 +1771,24 @@ mod asynch { /// is dropped it disables the interrupt again. The future returns the event /// that was initially passed, when it resolves. #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct UartRxFuture<'d, T> - where - T: Instance, - { + struct UartRxFuture<'d> { events: EnumSet, - uart: &'d mut T, - registered: bool, - } - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct UartTxFuture<'d, T> - where - T: Instance, - { - events: EnumSet, - uart: &'d mut T, + uart: &'d Info, + state: &'d State, registered: bool, } - impl<'d, T: Instance> UartRxFuture<'d, T> { - pub fn new(uart: &'d mut T, events: impl Into>) -> Self { + impl<'d> UartRxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { Self { events: events.into(), uart, + state, registered: false, } } - fn get_triggered_events(&self) -> EnumSet { + fn triggered_events(&self) -> EnumSet { let interrupts_enabled = self.uart.register_block().int_ena().read(); let mut events_triggered = EnumSet::new(); for event in self.events { @@ -1958,7 +1827,7 @@ mod asynch { } } - impl<'d, T: Instance> core::future::Future for UartRxFuture<'d, T> { + impl core::future::Future for UartRxFuture<'_> { type Output = EnumSet; fn poll( @@ -1966,11 +1835,11 @@ mod asynch { cx: &mut core::task::Context<'_>, ) -> core::task::Poll { if !self.registered { - RX_WAKERS[self.uart.uart_number()].register(cx.waker()); + self.state.rx_waker.register(cx.waker()); self.enable_listen(true); self.registered = true; } - let events = self.get_triggered_events(); + let events = self.triggered_events(); if !events.is_empty() { Poll::Ready(events) } else { @@ -1979,7 +1848,7 @@ mod asynch { } } - impl<'d, T: Instance> Drop for UartRxFuture<'d, T> { + impl Drop for UartRxFuture<'_> { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as @@ -1988,16 +1857,24 @@ mod asynch { } } - impl<'d, T: Instance> UartTxFuture<'d, T> { - pub fn new(uart: &'d mut T, events: impl Into>) -> Self { + #[must_use = "futures do nothing unless you `.await` or poll them"] + struct UartTxFuture<'d> { + events: EnumSet, + uart: &'d Info, + state: &'d State, + registered: bool, + } + impl<'d> UartTxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { Self { events: events.into(), uart, + state, registered: false, } } - fn get_triggered_events(&self) -> bool { + fn triggered_events(&self) -> bool { let interrupts_enabled = self.uart.register_block().int_ena().read(); let mut event_triggered = false; for event in self.events { @@ -2022,7 +1899,7 @@ mod asynch { } } - impl<'d, T: Instance> core::future::Future for UartTxFuture<'d, T> { + impl core::future::Future for UartTxFuture<'_> { type Output = (); fn poll( @@ -2030,12 +1907,12 @@ mod asynch { cx: &mut core::task::Context<'_>, ) -> core::task::Poll { if !self.registered { - TX_WAKERS[self.uart.uart_number()].register(cx.waker()); + self.state.tx_waker.register(cx.waker()); self.enable_listen(true); self.registered = true; } - if self.get_triggered_events() { + if self.triggered_events() { Poll::Ready(()) } else { Poll::Pending @@ -2043,7 +1920,7 @@ mod asynch { } } - impl<'d, T: Instance> Drop for UartTxFuture<'d, T> { + impl Drop for UartTxFuture<'_> { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as @@ -2103,7 +1980,7 @@ mod asynch { .with_rx(rx) .init(config)?; - this.inner_set_interrupt_handler(this.tx.uart.async_handler()); + this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); Ok(this) } @@ -2171,7 +2048,7 @@ mod asynch { ) -> Result { let mut this = UartBuilder::new(uart).with_tx(tx).init(config)?; - this.inner_set_interrupt_handler(this.tx.uart.async_handler()); + this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); let (_, uart_tx) = this.split(); Ok(uart_tx) @@ -2187,9 +2064,7 @@ mod asynch { let mut count = 0; let mut offset: usize = 0; loop { - let register_block = self.uart.register_block(); - let mut next_offset = - offset + (UART_FIFO_SIZE - get_tx_fifo_count(register_block)) as usize; + let mut next_offset = offset + (UART_FIFO_SIZE - self.tx_fifo_count()) as usize; if next_offset > words.len() { next_offset = words.len(); } @@ -2204,7 +2079,7 @@ mod asynch { } offset = next_offset; - UartTxFuture::::new(&mut *self.uart, TxEvent::TxFiFoEmpty).await; + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; } Ok(count) @@ -2216,9 +2091,9 @@ mod asynch { /// been sent over the UART. If the FIFO contains data, it waits /// for the transmission to complete before returning. pub async fn flush_async(&mut self) -> Result<(), Error> { - let count = get_tx_fifo_count(self.uart.register_block()); + let count = self.tx_fifo_count(); if count > 0 { - UartTxFuture::::new(&mut *self.uart, TxEvent::TxDone).await; + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; } Ok(()) @@ -2250,23 +2125,23 @@ mod asynch { T: Instance, { /// Create a new UART RX instance in [`Async`] mode. - pub fn new_async_typed( + pub fn new_async_typed( uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { Self::new_async_with_config_typed(uart, Config::default(), rx) } /// Create a new UART RX instance with configuration options in /// [`Async`] mode. - pub fn new_async_with_config_typed( + pub fn new_async_with_config_typed( uart: impl Peripheral

+ 'd, config: Config, - rx: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, ) -> Result { let mut this = UartBuilder::new(uart).with_rx(rx).init(config)?; - this.inner_set_interrupt_handler(this.tx.uart.async_handler()); + this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); let (uart_rx, _) = this.split(); Ok(uart_rx) @@ -2307,11 +2182,12 @@ mod asynch { if self.at_cmd_config.is_some() { events |= RxEvent::CmdCharDetected; } - if self.rx_timeout_config.is_some() { events |= RxEvent::FifoTout; } - let events_happened = UartRxFuture::::new(&mut self.uart, events).await; + + let events_happened = + UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; // always drain the fifo, if an error has occurred the data is lost let read_bytes = self.drain_fifo(buf); // check error events @@ -2330,8 +2206,7 @@ mod asynch { // data in the fifo, even if the interrupt is disabled and the status bit // cleared. Since we do not drain the fifo in the interrupt handler, we need to // reset the counter here, after draining the fifo. - self.uart - .register_block() + self.register_block() .int_clr() .write(|w| w.rxfifo_tout().clear_bit_by_one()); @@ -2396,12 +2271,9 @@ mod asynch { /// Clears and disables interrupts that have occurred and have their enable /// bit set. The fact that an interrupt has been disabled is used by the /// futures to detect that they should indeed resolve after being woken up - fn intr_handler(uart: &RegisterBlock) -> (bool, bool) { - let interrupts = uart.int_st().read(); + pub(super) fn intr_handler(uart: &Info, state: &State) { + let interrupts = uart.register_block().int_st().read(); let interrupt_bits = interrupts.bits(); // = int_raw & int_ena - if interrupt_bits == 0 { - return (false, false); - } let rx_wake = interrupts.rxfifo_full().bit_is_set() || interrupts.rxfifo_ovf().bit_is_set() || interrupts.rxfifo_tout().bit_is_set() @@ -2410,49 +2282,18 @@ mod asynch { || interrupts.frm_err().bit_is_set() || interrupts.parity_err().bit_is_set(); let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); - uart.int_clr().write(|w| unsafe { w.bits(interrupt_bits) }); - uart.int_ena() + uart.register_block() + .int_clr() + .write(|w| unsafe { w.bits(interrupt_bits) }); + uart.register_block() + .int_ena() .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); - (rx_wake, tx_wake) - } - - #[cfg(uart0)] - #[handler] - pub(super) fn uart0() { - let uart = unsafe { &*crate::peripherals::UART0::ptr() }; - let (rx, tx) = intr_handler(uart); - if rx { - RX_WAKERS[0].wake(); + if tx_wake { + state.tx_waker.wake(); } - if tx { - TX_WAKERS[0].wake(); - } - } - - #[cfg(uart1)] - #[handler] - pub(super) fn uart1() { - let uart = unsafe { &*crate::peripherals::UART1::ptr() }; - let (rx, tx) = intr_handler(uart); - if rx { - RX_WAKERS[1].wake(); - } - if tx { - TX_WAKERS[1].wake(); - } - } - - #[cfg(uart2)] - #[handler] - pub(super) fn uart2() { - let uart = unsafe { &*crate::peripherals::UART2::ptr() }; - let (rx, tx) = intr_handler(uart); - if rx { - RX_WAKERS[2].wake(); - } - if tx { - TX_WAKERS[2].wake(); + if rx_wake { + state.rx_waker.wake(); } } } @@ -2476,8 +2317,8 @@ pub mod lp_uart { /// Initialize the UART driver using the default configuration // TODO: CTS and RTS pins pub fn new(uart: LP_UART, _tx: LowPowerOutput<'_, 5>, _rx: LowPowerInput<'_, 4>) -> Self { - let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; - let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; + let lp_io = unsafe { crate::peripherals::LP_IO::steal() }; + let lp_aon = unsafe { crate::peripherals::LP_AON::steal() }; // FIXME: use GPIO APIs to configure pins lp_aon @@ -2521,7 +2362,7 @@ pub mod lp_uart { // default == SOC_MOD_CLK_RTC_FAST == 2 // LP_CLKRST.lpperi.lp_uart_clk_sel = 0; - unsafe { &*LP_CLKRST::PTR } + unsafe { LP_CLKRST::steal() } .lpperi() .modify(|_, w| w.lp_uart_clk_sel().clear_bit()); @@ -2651,6 +2492,108 @@ pub mod lp_uart { } } +/// UART Peripheral Instance +pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { + /// Returns the peripheral data and state describing this UART instance. + fn parts(&self) -> (&Info, &State); + + /// Returns the peripheral data describing this UART instance. + #[inline(always)] + fn info(&self) -> &Info { + self.parts().0 + } + + /// Returns the peripheral state for this UART instance. + #[inline(always)] + fn state(&self) -> &State { + self.parts().1 + } +} + +/// Peripheral data describing a particular UART instance. +pub struct Info { + /// Pointer to the register block for this UART instance. + /// + /// Use [Self::register_block] to access the register block. + pub register_block: *const RegisterBlock, + + /// Interrupt handler for the asynchronous operations of this UART instance. + pub async_handler: InterruptHandler, + + /// Interrupt for this UART instance. + pub interrupt: Interrupt, + + /// TX pin + pub tx_signal: OutputSignal, + + /// RX pin + pub rx_signal: InputSignal, + + /// CTS (Clear to Send) pin + pub cts_signal: InputSignal, + + /// RTS (Request to Send) pin + pub rts_signal: OutputSignal, +} + +/// Peripheral state for a UART instance. +pub struct State { + /// Waker for the asynchronous RX operations. + pub rx_waker: AtomicWaker, + + /// Waker for the asynchronous TX operations. + pub tx_waker: AtomicWaker, +} + +impl Info { + /// Returns the register block for this UART instance. + pub fn register_block(&self) -> &RegisterBlock { + unsafe { &*self.register_block } + } +} + +impl PartialEq for Info { + fn eq(&self, other: &Self) -> bool { + self.register_block == other.register_block + } +} + +unsafe impl Sync for Info {} + +macro_rules! impl_instance { + ($inst:ident, $txd:ident, $rxd:ident, $cts:ident, $rts:ident) => { + impl Instance for crate::peripherals::$inst { + fn parts(&self) -> (&Info, &State) { + #[crate::macros::handler] + pub(super) fn irq_handler() { + asynch::intr_handler(&PERIPHERAL, &STATE); + } + + static STATE: State = State { + tx_waker: AtomicWaker::new(), + rx_waker: AtomicWaker::new(), + }; + + static PERIPHERAL: Info = Info { + register_block: crate::peripherals::$inst::ptr(), + async_handler: irq_handler, + interrupt: Interrupt::$inst, + tx_signal: OutputSignal::$txd, + rx_signal: InputSignal::$rxd, + cts_signal: InputSignal::$cts, + rts_signal: OutputSignal::$rts, + }; + (&PERIPHERAL, &STATE) + } + } + }; +} + +impl_instance!(UART0, U0TXD, U0RXD, U0CTS, U0RTS); +impl_instance!(UART1, U1TXD, U1RXD, U1CTS, U1RTS); +#[cfg(uart2)] +impl_instance!(UART2, U2TXD, U2RXD, U2CTS, U2RTS); + crate::any_peripheral! { /// Any UART peripheral. pub peripheral AnyUart { @@ -2664,23 +2607,15 @@ crate::any_peripheral! { } impl Instance for AnyUart { - delegate::delegate! { - to match &self.0 { + #[inline] + fn parts(&self) -> (&Info, &State) { + match &self.0 { #[cfg(uart0)] - AnyUartInner::Uart0(uart) => uart, + AnyUartInner::Uart0(uart) => uart.parts(), #[cfg(uart1)] - AnyUartInner::Uart1(uart) => uart, + AnyUartInner::Uart1(uart) => uart.parts(), #[cfg(uart2)] - AnyUartInner::Uart2(uart) => uart, - } { - fn register_block(&self) -> &RegisterBlock; - fn uart_number(&self) -> usize; - fn async_handler(&self) -> InterruptHandler; - fn interrupt(&self) -> Interrupt; - fn tx_signal(&self) -> OutputSignal; - fn rx_signal(&self) -> InputSignal; - fn cts_signal(&self) -> InputSignal; - fn rts_signal(&self) -> OutputSignal; + AnyUartInner::Uart2(uart) => uart.parts(), } } } From 416c1481aee4ef132407a1270c78f1162482cac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 30 Oct 2024 17:25:29 +0100 Subject: [PATCH 05/67] Circular dma improvements (#2409) * Check for error when pushing into a circular dma transaction too late * Adapt tests * Adapt example * Don't block forever if trxing to pop from a circular DMA transfer too late * Have a dedicated error for circular-DMA reading/writing too late * Stop I2S RX before resetting it * Migration guide * Address review comment, make CI pass * Adopt ideas from review * Fix * Update esp-hal/MIGRATING-0.21.md Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> * assert --------- Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 16 +++++++ esp-hal/src/dma/gdma.rs | 6 +++ esp-hal/src/dma/mod.rs | 71 +++++++++++++++++++++++------- esp-hal/src/dma/pdma.rs | 12 +++++ esp-hal/src/i2s.rs | 9 ++-- examples/src/bin/i2s_read.rs | 2 +- examples/src/bin/i2s_sound.rs | 2 +- hil-test/tests/i2s.rs | 83 +++++++++++++++++++++++++++++++---- 9 files changed, 173 insertions(+), 29 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index ae63754f5ca..f6122875053 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Renamed `SpiDma` functions: `dma_transfer` to `transfer`, `dma_write` to `write`, `dma_read` to `read`. (#2373) - Peripheral type erasure for UART (#2381) - Changed listening for UART events (#2406) +- Circular DMA transfers now correctly error, `available` returns `Result` now (#2409) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index a693ab966f2..7898ecabc5b 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -160,3 +160,19 @@ You can now listen/unlisten multiple interrupt bits at once: -uart0.listen_rx_fifo_full(); +uart0.listen(UartInterrupt::AtCmd | UartConterrupt::RxFifoFull); ```˛ +## Circular DMA transfer's `available` returns `Result` now + +In case of any error you should drop the transfer and restart it. + +```diff + loop { +- let avail = transfer.available(); ++ let avail = match transfer.available() { ++ Ok(avail) => avail, ++ Err(_) => { ++ core::mem::drop(transfer); ++ transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap(); ++ continue; ++ }, ++ }; +``` diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 59d19ecdb80..11c0b624884 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -151,6 +151,12 @@ impl RegisterAccess for ChannelTxImpl { } impl TxRegisterAccess for ChannelTxImpl { + fn set_auto_write_back(&self, enable: bool) { + self.ch() + .out_conf0() + .modify(|_, w| w.out_auto_wrback().bit(enable)); + } + fn last_dscr_address(&self) -> usize { self.ch() .out_eof_des_addr() diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index c228517e691..bb3e6577352 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -781,6 +781,9 @@ pub enum DmaError { UnsupportedMemoryRegion, /// Invalid DMA chunk size InvalidChunkSize, + /// Indicates writing to or reading from a circular DMA transaction is done + /// too late and the DMA buffers already overrun / underrun. + Late, } impl From for DmaError { @@ -1313,7 +1316,7 @@ impl TxCircularState { } } - pub(crate) fn update(&mut self, channel: &T) + pub(crate) fn update(&mut self, channel: &T) -> Result<(), DmaError> where T: Tx, { @@ -1323,6 +1326,23 @@ impl TxCircularState { { channel.clear_out(DmaTxInterrupt::Eof); + // check if all descriptors are owned by CPU - this indicates we failed to push + // data fast enough in future we can enable `check_owner` and check + // the interrupt instead + let mut current = self.last_seen_handled_descriptor_ptr; + loop { + let descr = unsafe { current.read_volatile() }; + if descr.owner() == Owner::Cpu { + current = descr.next; + } else { + break; + } + + if current == self.last_seen_handled_descriptor_ptr { + return Err(DmaError::Late); + } + } + let descr_address = channel.last_out_dscr_address() as *mut DmaDescriptor; let mut ptr = self.last_seen_handled_descriptor_ptr; @@ -1376,6 +1396,8 @@ impl TxCircularState { self.last_seen_handled_descriptor_ptr = descr_address; } + + Ok(()) } pub(crate) fn push(&mut self, data: &[u8]) -> Result { @@ -1404,6 +1426,8 @@ impl TxCircularState { &mut self, f: impl FnOnce(&mut [u8]) -> usize, ) -> Result { + // this might write less than available in case of a wrap around + // caller needs to check and write the remaining part let written = unsafe { let dst = self.buffer_start.add(self.write_offset).cast_mut(); let block_size = usize::min(self.available, self.buffer_len - self.write_offset); @@ -1414,12 +1438,15 @@ impl TxCircularState { let mut forward = written; loop { unsafe { - let dw0 = self.write_descr_ptr.read_volatile(); - let segment_len = dw0.len(); - self.write_descr_ptr = if dw0.next.is_null() { + let mut descr = self.write_descr_ptr.read_volatile(); + descr.set_owner(Owner::Dma); + self.write_descr_ptr.write_volatile(descr); + + let segment_len = descr.len(); + self.write_descr_ptr = if descr.next.is_null() { self.first_desc_ptr } else { - dw0.next + descr.next }; if forward <= segment_len { @@ -1454,7 +1481,7 @@ impl RxCircularState { } } - pub(crate) fn update(&mut self) { + pub(crate) fn update(&mut self) -> Result<(), DmaError> { if self.last_seen_handled_descriptor_ptr.is_null() { // initially start at last descriptor (so that next will be the first // descriptor) @@ -1465,6 +1492,7 @@ impl RxCircularState { unsafe { self.last_seen_handled_descriptor_ptr.read_volatile() }.next; let mut current_in_descr = unsafe { current_in_descr_ptr.read_volatile() }; + let last_seen_ptr = self.last_seen_handled_descriptor_ptr; while current_in_descr.owner() == Owner::Cpu { self.available += current_in_descr.len(); self.last_seen_handled_descriptor_ptr = current_in_descr_ptr; @@ -1472,7 +1500,13 @@ impl RxCircularState { current_in_descr_ptr = unsafe { self.last_seen_handled_descriptor_ptr.read_volatile() }.next; current_in_descr = unsafe { current_in_descr_ptr.read_volatile() }; + + if current_in_descr_ptr == last_seen_ptr { + return Err(DmaError::Late); + } } + + Ok(()) } pub(crate) fn pop(&mut self, data: &mut [u8]) -> Result { @@ -1902,6 +1936,10 @@ where self.tx_impl.set_link_addr(chain.first() as u32); self.tx_impl.set_peripheral(peri as u8); + // enable descriptor write back in circular mode + self.tx_impl + .set_auto_write_back(!(*chain.last()).next.is_null()); + Ok(()) } @@ -2035,6 +2073,9 @@ pub trait RxRegisterAccess: RegisterAccess { #[doc(hidden)] pub trait TxRegisterAccess: RegisterAccess { + /// Enable/disable outlink-writeback + fn set_auto_write_back(&self, enable: bool); + /// Outlink descriptor address when EOF occurs of Tx channel. fn last_dscr_address(&self) -> usize; } @@ -2378,14 +2419,14 @@ where } /// Amount of bytes which can be pushed. - pub fn available(&mut self) -> usize { - self.state.update(self.instance.tx()); - self.state.available + pub fn available(&mut self) -> Result { + self.state.update(self.instance.tx())?; + Ok(self.state.available) } /// Push bytes into the DMA buffer. pub fn push(&mut self, data: &[u8]) -> Result { - self.state.update(self.instance.tx()); + self.state.update(self.instance.tx())?; self.state.push(data) } @@ -2394,7 +2435,7 @@ where /// The closure *might* get called with a slice which is smaller than the /// total available buffer. pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> Result { - self.state.update(self.instance.tx()); + self.state.update(self.instance.tx())?; self.state.push_with(f) } @@ -2454,9 +2495,9 @@ where /// /// It's expected to call this before trying to [DmaTransferRxCircular::pop] /// data. - pub fn available(&mut self) -> usize { - self.state.update(); - self.state.available + pub fn available(&mut self) -> Result { + self.state.update()?; + Ok(self.state.available) } /// Get available data. @@ -2468,7 +2509,7 @@ where /// Fails with [DmaError::BufferTooSmall] if the given buffer is too small /// to hold all available data pub fn pop(&mut self, data: &mut [u8]) -> Result { - self.state.update(); + self.state.update()?; self.state.pop(data) } } diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index de853696aee..ce037bb145b 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -90,6 +90,11 @@ impl> RegisterAccess for SpiDma } impl> TxRegisterAccess for SpiDmaTxChannelImpl { + fn set_auto_write_back(&self, enable: bool) { + // there is no `auto_wrback` for SPI + assert!(!enable); + } + fn last_dscr_address(&self) -> usize { let spi = self.0.register_block(); spi.out_eof_des_addr().read().dma_out_eof_des_addr().bits() as usize @@ -507,6 +512,13 @@ impl> RegisterAccess for I2sDma } impl> TxRegisterAccess for I2sDmaTxChannelImpl { + fn set_auto_write_back(&self, enable: bool) { + let reg_block = self.0.register_block(); + reg_block + .lc_conf() + .modify(|_, w| w.out_auto_wrback().bit(enable)); + } + fn last_dscr_address(&self) -> usize { let reg_block = self.0.register_block(); reg_block diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index 577390040fa..db0aaf02790 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -64,7 +64,7 @@ //! let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap(); //! //! loop { -//! let avail = transfer.available(); +//! let avail = transfer.available().unwrap(); //! //! if avail > 0 { //! let mut rcv = [0u8; 5000]; @@ -1545,6 +1545,9 @@ mod private { fn reset_rx(&self) { let i2s = self.register_block(); + + i2s.rx_conf().modify(|_, w| w.rx_start().clear_bit()); + i2s.rx_conf().modify(|_, w| { w.rx_reset().set_bit(); w.rx_fifo_reset().set_bit() @@ -1954,7 +1957,7 @@ pub mod asynch { /// Will wait for more than 0 bytes available. pub async fn available(&mut self) -> Result { loop { - self.state.update(&self.i2s_tx.tx_channel); + self.state.update(&self.i2s_tx.tx_channel)?; let res = self.state.available; if res != 0 { @@ -2077,7 +2080,7 @@ pub mod asynch { /// Will wait for more than 0 bytes available. pub async fn available(&mut self) -> Result { loop { - self.state.update(); + self.state.update()?; let res = self.state.available; diff --git a/examples/src/bin/i2s_read.rs b/examples/src/bin/i2s_read.rs index 30f45361264..8274fb69d71 100644 --- a/examples/src/bin/i2s_read.rs +++ b/examples/src/bin/i2s_read.rs @@ -68,7 +68,7 @@ fn main() -> ! { println!("Started transfer"); loop { - let avail = transfer.available(); + let avail = transfer.available().unwrap(); if avail > 0 { let mut rcv = [0u8; 5000]; diff --git a/examples/src/bin/i2s_sound.rs b/examples/src/bin/i2s_sound.rs index e998928b7d2..72e2d7b8e12 100644 --- a/examples/src/bin/i2s_sound.rs +++ b/examples/src/bin/i2s_sound.rs @@ -96,7 +96,7 @@ fn main() -> ! { let mut transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap(); loop { - let avail = transfer.available(); + let avail = transfer.available().unwrap(); if avail > 0 { let avail = usize::min(10000, avail); for bidx in 0..avail { diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 2420264edc5..1ce7176d631 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -235,7 +235,7 @@ mod tests { assert_eq!(0, rx_transfer.pop(&mut rcv[..100]).unwrap()); // no data available yet - assert_eq!(0, rx_transfer.available()); + assert_eq!(0, rx_transfer.available().unwrap()); let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap(); @@ -243,7 +243,7 @@ mod tests { let mut sample_idx = 0; let mut check_samples = SampleSource::new(); loop { - let tx_avail = tx_transfer.available(); + let tx_avail = tx_transfer.available().unwrap(); // make sure there are more than one descriptor buffers ready to push if tx_avail > 5000 { @@ -254,13 +254,13 @@ mod tests { } // test calling available multiple times doesn't break anything - rx_transfer.available(); - rx_transfer.available(); - rx_transfer.available(); - rx_transfer.available(); - rx_transfer.available(); - rx_transfer.available(); - let rx_avail = rx_transfer.available(); + rx_transfer.available().unwrap(); + rx_transfer.available().unwrap(); + rx_transfer.available().unwrap(); + rx_transfer.available().unwrap(); + rx_transfer.available().unwrap(); + rx_transfer.available().unwrap(); + let rx_avail = rx_transfer.available().unwrap(); // make sure there are more than one descriptor buffers ready to pop if rx_avail > 0 { @@ -298,4 +298,69 @@ mod tests { } } } + + #[test] + fn test_i2s_push_too_late(ctx: Context) { + let (_, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(0, 16000); + + let i2s = I2s::new( + ctx.i2s, + Standard::Philips, + DataFormat::Data16Channel16, + 16000.Hz(), + ctx.dma_channel.configure(false, DmaPriority::Priority0), + rx_descriptors, + tx_descriptors, + ); + + let (_, dout) = hil_test::common_test_pins!(ctx.io); + + let mut i2s_tx = i2s + .i2s_tx + .with_bclk(NoPin) + .with_ws(NoPin) + .with_dout(dout) + .build(); + + let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap(); + + let delay = esp_hal::delay::Delay::new(); + delay.delay_millis(300); + + assert!(matches!(tx_transfer.push(&[0; 128]), Err(_))); + } + + #[test] + #[timeout(1)] + fn test_i2s_read_too_late(ctx: Context) { + let (rx_buffer, rx_descriptors, _, tx_descriptors) = dma_buffers!(16000, 0); + + let i2s = I2s::new( + ctx.i2s, + Standard::Philips, + DataFormat::Data16Channel16, + 16000.Hz(), + ctx.dma_channel.configure(false, DmaPriority::Priority0), + rx_descriptors, + tx_descriptors, + ); + + let (_, dout) = hil_test::common_test_pins!(ctx.io); + let din = dout.peripheral_input(); + + let mut i2s_rx = i2s + .i2s_rx + .with_bclk(NoPin) + .with_ws(NoPin) + .with_din(din) + .build(); + + let mut buffer = [0u8; 1024]; + let mut rx_transfer = i2s_rx.read_dma_circular(rx_buffer).unwrap(); + + let delay = esp_hal::delay::Delay::new(); + delay.delay_millis(300); + + assert!(matches!(rx_transfer.pop(&mut buffer), Err(_))); + } } From 05a1ebead33e92af0ad42815897a9db783340515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 30 Oct 2024 17:38:16 +0100 Subject: [PATCH 06/67] Use esp-wifi-sys from Git (#2426) * Use esp-wifi-sys from Git * Update esp-wifi-sys rev --- esp-ieee802154/Cargo.toml | 2 +- esp-wifi/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esp-ieee802154/Cargo.toml b/esp-ieee802154/Cargo.toml index 67367b17521..079a1954133 100644 --- a/esp-ieee802154/Cargo.toml +++ b/esp-ieee802154/Cargo.toml @@ -20,7 +20,7 @@ byte = "0.2.7" critical-section = "1.1.3" document-features = "0.2.10" esp-hal = { version = "0.21.0", path = "../esp-hal" } -esp-wifi-sys = { version = "0.6.0" } +esp-wifi-sys = { version = "0.6.0", git = "https://github.com/esp-rs/esp-wifi-sys.git", rev = "a3e2ed64e9095f120bbcebe6287ddf62760774db" } heapless = "0.8.0" ieee802154 = "0.6.1" cfg-if = "1.0.0" diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index a0193547fcf..d6d92be54f8 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -32,7 +32,7 @@ heapless = { version = "0.8.0", default-features = false, features = [ ] } num-derive = { version = "0.4.2" } num-traits = { version = "0.2.19", default-features = false } -esp-wifi-sys = { version = "0.6.0" } +esp-wifi-sys = { version = "0.6.0", git = "https://github.com/esp-rs/esp-wifi-sys.git", rev = "a3e2ed64e9095f120bbcebe6287ddf62760774db"} embassy-sync = { version = "0.6.0", optional = true } embassy-net-driver = { version = "0.2.0", optional = true } libm = "0.2.8" From 9d4b8fdbc62902401cbc2db19003d64a8a5f6bfb Mon Sep 17 00:00:00 2001 From: Tu Nguyen <126753419+TuEmb@users.noreply.github.com> Date: Wed, 30 Oct 2024 23:59:11 +0700 Subject: [PATCH 07/67] [TWAI] bus-off error is never reached when using `transmit_async` (#2421) * cancel pending tx request when error is from tx * fix format error * update CHANGELOG.md --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/twai/mod.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f6122875053..bd8da8709c4 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix conflict between `RtcClock::get_xtal_freq` and `Rtc::disable_rom_message_printing` (#2360) - Fixed an issue where interrupts enabled before `esp_hal::init` were disabled. This issue caused the executor created by `#[esp_hal_embassy::main]` to behave incorrectly in multi-core applications. (#2377) +- Fixed `TWAI::transmit_async`: bus-off state is not reached when CANH and CANL are shorted. (#2421) ### Removed diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index eaed7d1424e..7d4c148f7a4 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -1943,6 +1943,22 @@ mod asynch { } if intr_status.bits() & 0b11111100 > 0 { + let err_capture = register_block.err_code_cap().read(); + let status = register_block.status().read(); + + // Read error code direction (transmitting or receiving) + cfg_if::cfg_if! { + if #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] { + let ecc_direction = err_capture.ecc_direction().bit_is_set(); + } else { + let ecc_direction = err_capture.err_capture_code_direction().bit_is_set(); + } + } + // If the error comes from Tx and Tx request is pending + if !ecc_direction && !status.tx_buf_st().bit_is_set() { + // Cancel a pending transmission request + register_block.cmd().write(|w| w.abort_tx().set_bit()); + } async_state.err_waker.wake(); } From 448ed9a001c07b834a86a77cc11e8fcd65602151 Mon Sep 17 00:00:00 2001 From: liebman Date: Wed, 30 Oct 2024 11:55:47 -0700 Subject: [PATCH 08/67] implement a parallel interface for esp32 using the i2s peripheral (#2348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i2s_parallel for esp32 - partially working * i2s_parallel for esp32 - works sync 16bit (still WIP) * i2s_parallel - add 8-bit * i2s_parallel - naive async implementation * i2s_parallel - clippy * add examples (mainly for testing now and we can reduce these before merge) * set tx_wrx2 in 8 bit mode or it updates on half clocks! * adjust clock config (still really a hack) * better clock calculation/configuration * no need to reset dma or interrupts in start, the DMA DmaTxBuf handles that * seems to need a short delay during tx_reset * use 20 clocks instead of 1us * 1us delay between dma start and tx_start (like idf) * changelog & documentation * remove debugging functions * no need for option in example * make async example actually use async & remove Option * implement Drop for I2sParallelTransfer * fix signal offset comment for I2S0 * small cleanup in i2s_parallel examples * added a note re I2S0 not supporting true 8bit * update doc & fmt * instace functions take &self * fmt * if run at 240MHz (CPU) delay needs to be bigger * wait for fifo on start and fixes for 240MHz * update for esp-hal-changes * fmt --------- Co-authored-by: Dániel Buga --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/i2s_parallel.rs | 714 +++++++++++++++++++++++ esp-hal/src/lib.rs | 2 + examples/src/bin/embassy_i2s_parallel.rs | 92 +++ examples/src/bin/i2s_parallel.rs | 86 +++ 5 files changed, 895 insertions(+) create mode 100644 esp-hal/src/i2s_parallel.rs create mode 100644 examples/src/bin/embassy_i2s_parallel.rs create mode 100644 examples/src/bin/i2s_parallel.rs diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index bd8da8709c4..b87fc35238f 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373) - `Cpu::COUNT` and `Cpu::current()` (#2411) - `UartInterrupt` and related functions (#2406) +- I2S Parallel output driver for esp32. (#2348) - Add an option to configure `WDT` action (#2330) ### Changed diff --git a/esp-hal/src/i2s_parallel.rs b/esp-hal/src/i2s_parallel.rs new file mode 100644 index 00000000000..bb4790e8953 --- /dev/null +++ b/esp-hal/src/i2s_parallel.rs @@ -0,0 +1,714 @@ +//! # Parallel Interface (via I2S) +//! +//! ## Overview +//! The I2S parallel interface allows for high-speed data transfer between the +//! ESP32 and external devices. It is commonly used to external devices such as +//! LED matrix, LCD display, and Printer. Only TX is implemented. Each +//! unit can have up to 8 or 16 data signals (depending on your target hardware) +//! plus 1 clock signal. +//! +//! ## Notes +//! +//! Data output is interleaved: +//! - 8bit: [A, B, C, D] is output as [C, D, A, B] (i.e., swapped as 16bit +//! words) +//! - 16bit: [A, B, C, D] is output as [B, A, D, C] (i.e., 16bit words are +//! swapped) +#![cfg_attr(esp32, doc = "")] +#![cfg_attr( + esp32, + doc = "I2S0 does not support true 8bit parallel output, so if you want to do 8bit" +)] +#![cfg_attr( + esp32, + doc = "you should use I2S1. If you have to use I2S0, it will only output the even" +)] +#![cfg_attr(esp32, doc = "bytes! so [A, B, C, D] will be output as [A, C]!!!!")] +#![cfg_attr(esp32, doc = "")] +//! ## Configuration +//! +//! The driver uses DMA (Direct Memory Access) for efficient data transfer and +//! supports various configurations, such as different data formats, standards +//! (e.g., Philips) and pin configurations. It relies on other peripheral +//! modules, such as +//! - `GPIO` +//! - `DMA` +//! - `system` (to configure and enable the I2S peripheral) +use core::{ + marker::PhantomData, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, +}; + +use fugit::HertzU32; +use private::{calculate_clock, I2sClockDividers, TxPins}; + +use crate::{ + dma::{ + asynch::DmaTxFuture, + Channel, + ChannelTx, + DmaChannelConvert, + DmaEligible, + DmaError, + DmaTxBuffer, + PeripheralMarker, + Tx, + }, + gpio::{ + interconnect::{OutputConnection, PeripheralOutput}, + OutputSignal, + }, + peripheral::{Peripheral, PeripheralRef}, + peripherals::{i2s0::RegisterBlock, I2S0, I2S1}, + system::PeripheralClockControl, + Mode, +}; + +/// Represents a group of 16 output pins configured for 16-bit parallel data +/// transmission. +pub struct TxSixteenBits<'d> { + pins: [PeripheralRef<'d, OutputConnection>; 16], +} + +impl<'d> TxSixteenBits<'d> { + #[allow(clippy::too_many_arguments)] + /// Creates a new `TxSixteenBits` instance with the provided output pins. + pub fn new( + pin_0: impl Peripheral

+ 'd, + pin_1: impl Peripheral

+ 'd, + pin_2: impl Peripheral

+ 'd, + pin_3: impl Peripheral

+ 'd, + pin_4: impl Peripheral

+ 'd, + pin_5: impl Peripheral

+ 'd, + pin_6: impl Peripheral

+ 'd, + pin_7: impl Peripheral

+ 'd, + pin_8: impl Peripheral

+ 'd, + pin_9: impl Peripheral

+ 'd, + pin_10: impl Peripheral

+ 'd, + pin_11: impl Peripheral

+ 'd, + pin_12: impl Peripheral

+ 'd, + pin_13: impl Peripheral

+ 'd, + pin_14: impl Peripheral

+ 'd, + pin_15: impl Peripheral

+ 'd, + ) -> Self { + crate::into_mapped_ref!( + pin_0, pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7, pin_8, pin_9, pin_10, pin_11, + pin_12, pin_13, pin_14, pin_15 + ); + + Self { + pins: [ + pin_0, pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7, pin_8, pin_9, pin_10, + pin_11, pin_12, pin_13, pin_14, pin_15, + ], + } + } +} + +impl<'d> TxPins for TxSixteenBits<'d> { + fn bits(&self) -> u8 { + 16 + } + + fn configure(&mut self, instance: &PeripheralRef<'_, I>) { + use crate::private::Internal; + let bits: u8 = self.bits(); + for (i, pin) in self.pins.iter_mut().enumerate() { + pin.set_to_push_pull_output(Internal); + pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), Internal); + } + } +} + +/// Represents a group of 8 output pins configured for 8-bit parallel data +/// transmission. +pub struct TxEightBits<'d> { + pins: [PeripheralRef<'d, OutputConnection>; 8], +} + +impl<'d> TxEightBits<'d> { + #[allow(clippy::too_many_arguments)] + /// Creates a new `TxSEightBits` instance with the provided output pins. + pub fn new( + pin_0: impl Peripheral

+ 'd, + pin_1: impl Peripheral

+ 'd, + pin_2: impl Peripheral

+ 'd, + pin_3: impl Peripheral

+ 'd, + pin_4: impl Peripheral

+ 'd, + pin_5: impl Peripheral

+ 'd, + pin_6: impl Peripheral

+ 'd, + pin_7: impl Peripheral

+ 'd, + ) -> Self { + crate::into_mapped_ref!(pin_0); + crate::into_mapped_ref!(pin_1); + crate::into_mapped_ref!(pin_2); + crate::into_mapped_ref!(pin_3); + crate::into_mapped_ref!(pin_4); + crate::into_mapped_ref!(pin_5); + crate::into_mapped_ref!(pin_6); + crate::into_mapped_ref!(pin_7); + + Self { + pins: [pin_0, pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7], + } + } +} + +impl<'d> TxPins for TxEightBits<'d> { + fn bits(&self) -> u8 { + 8 + } + + fn configure(&mut self, instance: &PeripheralRef<'_, I>) { + use crate::private::Internal; + let bits: u8 = self.bits(); + for (i, pin) in self.pins.iter_mut().enumerate() { + pin.set_to_push_pull_output(Internal); + pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), Internal); + } + } +} + +/// I2S Parallel Interface +pub struct I2sParallel<'d, I: Instance, DM: Mode> { + instance: PeripheralRef<'d, I>, + tx_channel: ChannelTx<'d, ::Dma>, + mode: PhantomData, +} + +impl<'d, I: Instance, DM: Mode> I2sParallel<'d, I, DM> { + /// Create a new I2S Parallel Interface + pub fn new( + i2s: impl Peripheral

+ 'd, + channel: Channel<'d, CH, DM>, + frequency: impl Into, + mut pins: P, + clock_pin: impl Peripheral

+ 'd, + ) -> Self + where + CH: DmaChannelConvert, + P: TxPins, + { + crate::into_ref!(i2s); + crate::into_mapped_ref!(clock_pin); + + channel.runtime_ensure_compatible(&i2s); + let channel = channel.degrade(); + + PeripheralClockControl::reset(i2s.get_peripheral()); + PeripheralClockControl::enable(i2s.get_peripheral()); + // configure the I2S peripheral for parallel mode + i2s.setup(frequency, pins.bits()); + // setup the clock pin + clock_pin.set_to_push_pull_output(crate::private::Internal); + clock_pin.connect_peripheral_to_output(i2s.ws_signal(), crate::private::Internal); + + pins.configure(&i2s); + Self { + instance: i2s, + tx_channel: channel.tx, + mode: PhantomData, + } + } + + /// Write data to the I2S peripheral + pub fn send( + mut self, + mut data: BUF, + ) -> Result, (DmaError, Self, BUF)> { + self.instance.tx_reset(); + self.instance.tx_fifo_reset(); + let result = unsafe { + self.tx_channel + .prepare_transfer(self.instance.get_dma_peripheral(), &mut data) + } + .and_then(|_| self.tx_channel.start_transfer()); + if let Err(err) = result { + return Err((err, self, data)); + } + crate::rom::ets_delay_us(1); + self.instance.tx_start(); + Ok(I2sParallelTransfer { + i2s: ManuallyDrop::new(self), + buf_view: ManuallyDrop::new(data.into_view()), + }) + } +} + +/// Represents an ongoing (or potentially finished) transfer using the i2s +/// parallel interface +pub struct I2sParallelTransfer<'d, I, BUF, DM> +where + I: Instance, + BUF: DmaTxBuffer, + DM: Mode, +{ + i2s: ManuallyDrop>, + buf_view: ManuallyDrop, +} + +impl<'d, I, BUF, DM> I2sParallelTransfer<'d, I, BUF, DM> +where + I: Instance, + BUF: DmaTxBuffer, + DM: Mode, +{ + /// Returns true when [Self::wait] will not block. + pub fn is_done(&self) -> bool { + self.i2s.instance.is_tx_done() + } + + /// Wait for the transfer to finish + pub fn wait(mut self) -> (I2sParallel<'d, I, DM>, BUF) { + self.i2s.instance.tx_wait_done(); + let i2s = unsafe { ManuallyDrop::take(&mut self.i2s) }; + let view = unsafe { ManuallyDrop::take(&mut self.buf_view) }; + (i2s, BUF::from_view(view)) + } + + fn stop_peripherals(&mut self) { + self.i2s.instance.tx_stop(); + self.i2s.tx_channel.stop_transfer(); + } +} + +impl<'d, I, BUF> I2sParallelTransfer<'d, I, BUF, crate::Async> +where + I: Instance, + BUF: DmaTxBuffer, +{ + /// Wait for the transfer to finish + pub async fn wait_for_done(&mut self) -> Result<(), DmaError> { + DmaTxFuture::new(&mut self.i2s.tx_channel).await + } +} + +impl<'d, I, BUF, DM> Deref for I2sParallelTransfer<'d, I, BUF, DM> +where + I: Instance, + BUF: DmaTxBuffer, + DM: Mode, +{ + type Target = BUF::View; + + fn deref(&self) -> &Self::Target { + &self.buf_view + } +} + +impl<'d, I, BUF, DM> DerefMut for I2sParallelTransfer<'d, I, BUF, DM> +where + I: Instance, + BUF: DmaTxBuffer, + DM: Mode, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buf_view + } +} + +impl<'d, I, BUF, DM> Drop for I2sParallelTransfer<'d, I, BUF, DM> +where + I: Instance, + BUF: DmaTxBuffer, + DM: Mode, +{ + fn drop(&mut self) { + self.stop_peripherals(); + + // SAFETY: This is Drop, we know that self.i2s and self.buf_view + // won't be touched again. + let view = unsafe { + ManuallyDrop::drop(&mut self.i2s); + ManuallyDrop::take(&mut self.buf_view) + }; + let _ = BUF::from_view(view); + } +} + +mod private { + use fugit::HertzU32; + + use crate::peripheral::PeripheralRef; + + pub trait TxPins { + fn bits(&self) -> u8; + fn configure(&mut self, instance: &PeripheralRef<'_, I>); + } + + #[derive(Debug)] + pub struct I2sClockDividers { + pub mclk_divider: u32, + pub bclk_divider: u32, + pub denominator: u32, + pub numerator: u32, + } + + #[cfg(any(esp32, esp32s2))] + const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; + + const I2S_LL_MCLK_DIVIDER_MAX: usize = (1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1; + + pub fn calculate_clock( + sample_rate: impl Into, + data_bits: u8, + ) -> I2sClockDividers { + // this loosely corresponds to `i2s_std_calculate_clock` and + // `i2s_ll_tx_set_mclk` in esp-idf + // + // main difference is we are using fixed-point arithmetic here + // plus adjusted for parallel interface clocking + + let sclk = crate::soc::constants::I2S_SCLK; // for now it's fixed 160MHz and 96MHz (just H2) + + let rate_hz: HertzU32 = sample_rate.into(); + let rate = rate_hz.raw(); + + let mclk = rate * 2; + let bclk_divider: u32 = if data_bits == 8 { 2 } else { 1 }; + let mut mclk_divider = sclk / mclk; + + let mut ma: u32; + let mut mb: u32; + let mut denominator: u32 = 0; + let mut numerator: u32 = 0; + + let freq_diff = sclk.abs_diff(mclk * mclk_divider); + + if freq_diff != 0 { + let decimal = freq_diff as u64 * 10000 / mclk as u64; + // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / + // 126.0 + if decimal > 1250000 / 126 { + mclk_divider += 1; + } else { + let mut min: u32 = !0; + + for a in 2..=I2S_LL_MCLK_DIVIDER_MAX { + let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000; + ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32; + mb = (mclk as u64 * (b / 10000)) as u32; + + if ma == mb { + denominator = a as u32; + numerator = (b / 10000) as u32; + break; + } + + if mb.abs_diff(ma) < min { + denominator = a as u32; + numerator = b as u32; + min = mb.abs_diff(ma); + } + } + } + } + + I2sClockDividers { + mclk_divider, + bclk_divider, + denominator, + numerator, + } + } +} + +#[allow(missing_docs)] +pub trait RegBlock: PeripheralMarker + DmaEligible { + fn register_block(&self) -> &'static RegisterBlock; +} + +#[allow(missing_docs)] +pub trait Signals { + fn get_peripheral(&self) -> crate::system::Peripheral; + fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral; + fn ws_signal(&self) -> OutputSignal; + fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal; +} + +#[allow(missing_docs)] +pub trait Instance: Signals + RegBlock { + fn rx_reset(&self) { + let r = self.register_block(); + r.conf().modify(|_, w| w.rx_reset().set_bit()); + r.conf().modify(|_, w| w.rx_reset().clear_bit()); + } + + fn rx_dma_reset(&self) { + let r = self.register_block(); + r.lc_conf().modify(|_, w| w.in_rst().set_bit()); + r.lc_conf().modify(|_, w| w.in_rst().clear_bit()); + } + + fn rx_fifo_reset(&self) { + let r = self.register_block(); + r.conf().modify(|_, w| w.rx_fifo_reset().set_bit()); + r.conf().modify(|_, w| w.rx_fifo_reset().clear_bit()); + } + + fn tx_reset(&self) { + let r = self.register_block(); + r.conf().modify(|_, w| w.tx_reset().set_bit()); + // without this delay starting a subsequent transfer will hang waiting + // for tx_idle to clear (the transfer does not start). + // While 20 clocks works for 80MHz cpu but 100 is needed for 240MHz! + xtensa_lx::timer::delay(100); + r.conf().modify(|_, w| w.tx_reset().clear_bit()); + } + + fn tx_dma_reset(&self) { + let r = self.register_block(); + r.lc_conf().modify(|_, w| w.out_rst().set_bit()); + r.lc_conf().modify(|_, w| w.out_rst().clear_bit()); + } + + fn tx_fifo_reset(&self) { + let r = self.register_block(); + r.conf().modify(|_, w| w.tx_fifo_reset().set_bit()); + r.conf().modify(|_, w| w.tx_fifo_reset().clear_bit()); + } + + fn tx_clear_interrupts(&self) { + let r = self.register_block(); + r.int_clr().write(|w| { + w.out_done().clear_bit_by_one(); + w.out_total_eof().clear_bit_by_one() + }); + } + + fn tx_start(&self) { + let r = self.register_block(); + + // wait for data to show up in the fifo + while r.int_raw().read().tx_rempty().bit_is_clear() { + // wait + } + + // without this transfers are not reliable! + xtensa_lx::timer::delay(1); + + r.conf().modify(|_, w| w.tx_start().set_bit()); + + while r.state().read().tx_idle().bit_is_set() { + // wait + } + } + + fn tx_stop(&self) { + let r = self.register_block(); + r.conf().modify(|_, w| w.tx_start().clear_bit()); + } + + fn is_tx_done(&self) -> bool { + self.register_block().state().read().tx_idle().bit_is_set() + } + + fn tx_wait_done(&self) { + let r = self.register_block(); + while r.state().read().tx_idle().bit_is_clear() { + // wait + } + + r.conf().modify(|_, w| w.tx_start().clear_bit()); + r.int_clr().write(|w| { + w.out_done().clear_bit_by_one(); + w.out_total_eof().clear_bit_by_one() + }); + } + + fn set_clock(&self, clock_settings: I2sClockDividers) { + let r = self.register_block(); + + r.clkm_conf().modify(|r, w| unsafe { + w.bits(r.bits() | (crate::soc::constants::I2S_DEFAULT_CLK_SRC << 21)) + // select PLL_160M + }); + + #[cfg(esp32)] + r.clkm_conf().modify(|_, w| w.clka_ena().clear_bit()); + + r.clkm_conf().modify(|_, w| unsafe { + w.clk_en().set_bit(); + w.clkm_div_num().bits(clock_settings.mclk_divider as u8) + }); + + r.clkm_conf().modify(|_, w| unsafe { + w.clkm_div_a().bits(clock_settings.denominator as u8); + w.clkm_div_b().bits(clock_settings.numerator as u8) + }); + + r.sample_rate_conf().modify(|_, w| unsafe { + w.tx_bck_div_num().bits(clock_settings.bclk_divider as u8); + w.rx_bck_div_num().bits(clock_settings.bclk_divider as u8) + }); + } + + fn setup(&self, frequency: impl Into, bits: u8) { + let frequency: HertzU32 = frequency.into(); + + self.set_clock(calculate_clock(frequency, bits)); + + // Initialize I2S dev + self.rx_reset(); + self.tx_reset(); + self.rx_fifo_reset(); + self.tx_fifo_reset(); + self.rx_dma_reset(); + self.tx_dma_reset(); + + let r = self.register_block(); + + // clear all bits and enable lcd mode + r.conf2().write(|w| { + // 8 bit mode needs this or it updates on half clocks! + w.lcd_tx_wrx2_en().bit(bits == 8); + w.lcd_en().set_bit() + }); + + r.sample_rate_conf().modify(|_, w| unsafe { + w.rx_bits_mod().bits(bits); + w.tx_bits_mod().bits(bits) + }); + + r.fifo_conf().write(|w| unsafe { + w.rx_fifo_mod_force_en().set_bit(); + w.tx_fifo_mod_force_en().set_bit(); + w.rx_fifo_mod().bits(1); + w.tx_fifo_mod().bits(1); + w.rx_data_num().bits(32); + w.tx_data_num().bits(32); + w.dscr_en().set_bit() + }); + + r.conf1().write(|w| { + w.tx_stop_en().set_bit(); + w.rx_pcm_bypass().set_bit(); + w.tx_pcm_bypass().set_bit() + }); + + r.conf_chan().write(|w| unsafe { + w.rx_chan_mod().bits(1); + w.tx_chan_mod().bits(1) + }); + + r.conf().modify(|_, w| { + w.rx_mono().set_bit(); + w.tx_mono().set_bit(); + w.rx_right_first().set_bit(); + w.tx_right_first().set_bit() + }); + r.timing().reset(); + + r.pd_conf().modify(|_, w| { + w.fifo_force_pu().set_bit(); + w.fifo_force_pd().clear_bit() + }); + } +} + +impl RegBlock for I2S0 { + fn register_block(&self) -> &'static RegisterBlock { + unsafe { &*I2S0::PTR.cast::() } + } +} + +impl Signals for I2S0 { + fn get_peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s0 + } + + fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral { + crate::dma::DmaPeripheral::I2s0 + } + + fn ws_signal(&self) -> OutputSignal { + OutputSignal::I2S0O_WS + } + fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal { + // signals for 8bit and 16bit both start at an offset of 8 for I2S0 + let offset = match bits { + 8 => 8, + 16 => 8, + _ => panic!("Invalid number of bits"), + }; + match i + offset { + 0 => OutputSignal::I2S0O_DATA_0, + 1 => OutputSignal::I2S0O_DATA_1, + 2 => OutputSignal::I2S0O_DATA_2, + 3 => OutputSignal::I2S0O_DATA_3, + 4 => OutputSignal::I2S0O_DATA_4, + 5 => OutputSignal::I2S0O_DATA_5, + 6 => OutputSignal::I2S0O_DATA_6, + 7 => OutputSignal::I2S0O_DATA_7, + 8 => OutputSignal::I2S0O_DATA_8, + 9 => OutputSignal::I2S0O_DATA_9, + 10 => OutputSignal::I2S0O_DATA_10, + 11 => OutputSignal::I2S0O_DATA_11, + 12 => OutputSignal::I2S0O_DATA_12, + 13 => OutputSignal::I2S0O_DATA_13, + 14 => OutputSignal::I2S0O_DATA_14, + 15 => OutputSignal::I2S0O_DATA_15, + 16 => OutputSignal::I2S0O_DATA_16, + 17 => OutputSignal::I2S0O_DATA_17, + 18 => OutputSignal::I2S0O_DATA_18, + 19 => OutputSignal::I2S0O_DATA_19, + 20 => OutputSignal::I2S0O_DATA_20, + 21 => OutputSignal::I2S0O_DATA_21, + 22 => OutputSignal::I2S0O_DATA_22, + 23 => OutputSignal::I2S0O_DATA_23, + _ => panic!("Invalid I2S0 Dout pin"), + } + } +} +impl Instance for I2S0 {} + +impl RegBlock for I2S1 { + fn register_block(&self) -> &'static RegisterBlock { + unsafe { &*I2S1::PTR.cast::() } + } +} +impl Signals for I2S1 { + fn get_peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s1 + } + fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral { + crate::dma::DmaPeripheral::I2s1 + } + + fn ws_signal(&self) -> OutputSignal { + OutputSignal::I2S1O_WS + } + fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal { + // Because of... reasons... the 16-bit values for i2s1 appear on d8...d23 + let offset = if bits == 16 { 8 } else { 0 }; + match i + offset { + 0 => OutputSignal::I2S1O_DATA_0, + 1 => OutputSignal::I2S1O_DATA_1, + 2 => OutputSignal::I2S1O_DATA_2, + 3 => OutputSignal::I2S1O_DATA_3, + 4 => OutputSignal::I2S1O_DATA_4, + 5 => OutputSignal::I2S1O_DATA_5, + 6 => OutputSignal::I2S1O_DATA_6, + 7 => OutputSignal::I2S1O_DATA_7, + 8 => OutputSignal::I2S1O_DATA_8, + 9 => OutputSignal::I2S1O_DATA_9, + 10 => OutputSignal::I2S1O_DATA_10, + 11 => OutputSignal::I2S1O_DATA_11, + 12 => OutputSignal::I2S1O_DATA_12, + 13 => OutputSignal::I2S1O_DATA_13, + 14 => OutputSignal::I2S1O_DATA_14, + 15 => OutputSignal::I2S1O_DATA_15, + 16 => OutputSignal::I2S1O_DATA_16, + 17 => OutputSignal::I2S1O_DATA_17, + 18 => OutputSignal::I2S1O_DATA_18, + 19 => OutputSignal::I2S1O_DATA_19, + 20 => OutputSignal::I2S1O_DATA_20, + 21 => OutputSignal::I2S1O_DATA_21, + 22 => OutputSignal::I2S1O_DATA_22, + 23 => OutputSignal::I2S1O_DATA_23, + _ => panic!("Invalid I2S1 Dout pin"), + } + } +} +impl Instance for I2S1 {} diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 2155b18ffd7..15658f6f5ca 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -191,6 +191,8 @@ pub mod hmac; pub mod i2c; #[cfg(any(i2s0, i2s1))] pub mod i2s; +#[cfg(all(esp32, any(i2s0, i2s1)))] +pub mod i2s_parallel; #[cfg(any(dport, interrupt_core0, interrupt_core1))] pub mod interrupt; #[cfg(lcd_cam)] diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs new file mode 100644 index 00000000000..dcf0167d846 --- /dev/null +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -0,0 +1,92 @@ +//! This shows using Parallel IO to output 8 bit parallel data at 1MHz clock +//! rate with a delay of 10ms between each transfer. +//! +//! The following wiring is assumed: +//! - Data pins => GPIO16, GPIO4, GPIO17, GPIO18, GPIO5, GPIO19, GPIO12, and +//! GPIO14 +//! - Clock output pin => GPIO25 +//! +//! You can use a logic analyzer to see how the pins are used. + +//% CHIPS: esp32 +//% FEATURES: embassy embassy-generic-timers + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use esp_backtrace as _; +use esp_hal::{ + dma::{Dma, DmaPriority, DmaTxBuf}, + dma_buffers, + gpio::Io, + i2s_parallel::{I2sParallel, TxEightBits}, + prelude::*, + timer::timg::TimerGroup, +}; +use log::info; + +const BUFFER_SIZE: usize = 256; + +#[main] +async fn main(_spawner: Spawner) { + esp_println::logger::init_logger(log::LevelFilter::Info); + info!("Starting!"); + let peripherals = esp_hal::init(esp_hal::Config::default()); + let dma = Dma::new(peripherals.DMA); + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + + info!("init embassy"); + esp_hal_embassy::init(timg0.timer0); + + let dma_channel = dma.i2s1channel; + let i2s = peripherals.I2S1; + let clock = io.pins.gpio25; + + let pins = TxEightBits::new( + io.pins.gpio16, + io.pins.gpio4, + io.pins.gpio17, + io.pins.gpio18, + io.pins.gpio5, + io.pins.gpio19, + io.pins.gpio12, + io.pins.gpio14, + ); + + let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); + let mut parallel = I2sParallel::new( + i2s, + dma_channel.configure_for_async(false, DmaPriority::Priority0), + 1.MHz(), + pins, + clock, + ); + + for (i, data) in tx_buffer.chunks_mut(4).enumerate() { + let offset = i * 4; + // i2s parallel driver expects the buffer to be interleaved + data[0] = (offset + 2) as u8; + data[1] = (offset + 3) as u8; + data[2] = offset as u8; + data[3] = (offset + 1) as u8; + } + + let mut tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).expect("DmaTxBuf::new failed"); + + info!("Sending {} bytes!", BUFFER_SIZE); + loop { + let mut xfer = match parallel.send(tx_buf) { + Ok(xfer) => xfer, + Err(_) => { + panic!("Failed to send buffer"); + } + }; + xfer.wait_for_done().await.expect("Failed to send buffer"); + (parallel, tx_buf) = xfer.wait(); + Timer::after_millis(10).await; + } +} diff --git a/examples/src/bin/i2s_parallel.rs b/examples/src/bin/i2s_parallel.rs new file mode 100644 index 00000000000..0634b8cbe9a --- /dev/null +++ b/examples/src/bin/i2s_parallel.rs @@ -0,0 +1,86 @@ +//! This shows using Parallel IO to output 8 bit parallel data at 1MHz clock +//! rate with a delay of 10ms between each transfer. +//! +//! The following wiring is assumed: +//! - Data pins => GPIO16, GPIO4, GPIO17, GPIO18, GPIO5, GPIO19, GPIO12, and +//! GPIO14 +//! - Clock output pin => GPIO25 +//! +//! You can use a logic analyzer to see how the pins are used. + +//% CHIPS: esp32 + +#![no_std] +#![no_main] + +use esp_backtrace as _; +use esp_hal::{ + delay::Delay, + dma::{Dma, DmaPriority, DmaTxBuf}, + dma_buffers, + gpio::Io, + i2s_parallel::{I2sParallel, TxEightBits}, + prelude::*, +}; +use log::info; + +const BUFFER_SIZE: usize = 256; + +#[entry] +fn main() -> ! { + esp_println::logger::init_logger(log::LevelFilter::Info); + info!("Starting!"); + let peripherals = esp_hal::init(esp_hal::Config::default()); + let dma = Dma::new(peripherals.DMA); + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + + let delay = Delay::new(); + + let dma_channel = dma.i2s1channel; + let i2s = peripherals.I2S1; + let clock = io.pins.gpio25; + + let pins = TxEightBits::new( + io.pins.gpio16, + io.pins.gpio4, + io.pins.gpio17, + io.pins.gpio18, + io.pins.gpio5, + io.pins.gpio19, + io.pins.gpio12, + io.pins.gpio14, + ); + + let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); + let mut parallel = I2sParallel::new( + i2s, + dma_channel.configure(false, DmaPriority::Priority0), + 1.MHz(), + pins, + clock, + ); + + for (i, data) in tx_buffer.chunks_mut(4).enumerate() { + let offset = i * 4; + // i2s parallel driver expects the buffer to be interleaved + data[0] = (offset + 2) as u8; + data[1] = (offset + 3) as u8; + data[2] = offset as u8; + data[3] = (offset + 1) as u8; + } + + let mut tx_buf: DmaTxBuf = + DmaTxBuf::new(tx_descriptors, tx_buffer).expect("DmaTxBuf::new failed"); + + info!("Sending {} bytes!", BUFFER_SIZE); + loop { + let xfer = match parallel.send(tx_buf) { + Ok(xfer) => xfer, + Err(_) => { + panic!("Failed to send buffer"); + } + }; + (parallel, tx_buf) = xfer.wait(); + delay.delay_millis(10); + } +} From 25d8390d68f5b996c3df5200b485ef217cf5793b Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Thu, 31 Oct 2024 06:43:11 +0000 Subject: [PATCH 09/67] Fix typo in migration guide (#2435) --- esp-hal/MIGRATING-0.20.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal/MIGRATING-0.20.md b/esp-hal/MIGRATING-0.20.md index 543cb03185a..0064d8a1d45 100644 --- a/esp-hal/MIGRATING-0.20.md +++ b/esp-hal/MIGRATING-0.20.md @@ -230,7 +230,7 @@ We've replaced some usage of features with [esp-config](https://docs.rs/esp-conf # feature in Cargo.toml - esp-hal = { version = "0.20", features = ["place-spi-driver-in-ram"] } # key in .cargo/config.toml [env] section -+ ESP_HAL_PLACE_SPI_DRIVER_IN_RAM=true ++ ESP_HAL_PLACE_SPI_DRIVER_IN_RAM="true" ``` ## `Camera` driver now uses `DmaRxBuffer` and moves the driver into the transfer object. From 6fa2823e1072b7349a820772d59a40d25ab66110 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Thu, 31 Oct 2024 05:22:37 -0700 Subject: [PATCH 10/67] Use latest PAC which aligns TWAI field names (#2438) --- esp-hal/Cargo.toml | 14 +++++++------- esp-hal/src/twai/mod.rs | 10 +++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 399c4e7222b..71f0a184cc8 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -55,13 +55,13 @@ xtensa-lx = { version = "0.9.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { version = "0.33.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32c2 = { version = "0.22.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32c3 = { version = "0.25.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32c6 = { version = "0.16.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32h2 = { version = "0.12.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32s2 = { version = "0.24.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } -esp32s3 = { version = "0.28.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "48fd400", features = ["critical-section", "rt"], optional = true } +esp32 = { version = "0.33.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32c2 = { version = "0.22.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32c3 = { version = "0.25.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32c6 = { version = "0.16.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32h2 = { version = "0.12.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32s2 = { version = "0.24.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32s3 = { version = "0.28.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] esp-riscv-rt = { version = "0.9.0", path = "../esp-riscv-rt" } diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 7d4c148f7a4..705b7a60ab2 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -1947,18 +1947,14 @@ mod asynch { let status = register_block.status().read(); // Read error code direction (transmitting or receiving) - cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] { - let ecc_direction = err_capture.ecc_direction().bit_is_set(); - } else { - let ecc_direction = err_capture.err_capture_code_direction().bit_is_set(); - } - } + let ecc_direction = err_capture.ecc_direction().bit_is_set(); + // If the error comes from Tx and Tx request is pending if !ecc_direction && !status.tx_buf_st().bit_is_set() { // Cancel a pending transmission request register_block.cmd().write(|w| w.abort_tx().set_bit()); } + async_state.err_waker.wake(); } From e5b923b678c60e5263ff9cf6460807c31e8a517a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Thu, 31 Oct 2024 13:26:10 +0100 Subject: [PATCH 11/67] Esp wifi/more dynamic allocations (#2396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dynamic allocation of timers * Replace statically allocated NPL events * Remove NPL CALLOUTS * Remove NPL EventQueue * Use `Vec` instead of `heapless::spsc::Queue` internally in NPL * Use `alloc` since we have it in NPL * Refactor * Fix * More `Vec` * Fix * Fix nightly-warnings * Limit RX_STA queue * Revert unintentional change * esp-now: Make data private * CHANGELOG.md * Clippy * MSRV * Move locking into RawQueue * Remove unused import * Simplify `queue_recv` * Address TODO * Clippy * Review I * Review II * Clarify * Review III * Review IV * Review V * Fix * `steal` RNG and RADIO_CLOCKS * `drop_in_place` * De-duplicate * Use `VecDeque` * Revert unintentional changes * Fix * Update esp-wifi/MIGRATING-0.10.md Co-authored-by: Dániel Buga * assert * Fix * Expect `*mut ConcurrentQueue` where applicable * Comment why stealing is fine * Fix --------- Co-authored-by: Dániel Buga --- esp-wifi/CHANGELOG.md | 1 + esp-wifi/MIGRATING-0.10.md | 6 + esp-wifi/src/ble/btdm.rs | 225 ++--------- esp-wifi/src/ble/controller/mod.rs | 2 +- esp-wifi/src/ble/mod.rs | 73 +++- esp-wifi/src/ble/npl.rs | 359 ++++++------------ esp-wifi/src/ble/os_adapter_esp32c2.rs | 20 +- esp-wifi/src/ble/os_adapter_esp32c6.rs | 22 +- esp-wifi/src/ble/os_adapter_esp32h2.rs | 22 +- .../common_adapter/common_adapter_esp32.rs | 21 +- .../common_adapter/common_adapter_esp32c2.rs | 19 +- .../common_adapter/common_adapter_esp32c3.rs | 20 +- .../common_adapter/common_adapter_esp32c6.rs | 15 +- .../common_adapter/common_adapter_esp32h2.rs | 15 +- .../common_adapter/common_adapter_esp32s2.rs | 23 +- .../common_adapter/common_adapter_esp32s3.rs | 21 +- esp-wifi/src/common_adapter/mod.rs | 36 +- esp-wifi/src/compat/common.rs | 147 +++++-- esp-wifi/src/compat/mod.rs | 7 +- esp-wifi/src/compat/timer_compat.rs | 164 ++++++-- esp-wifi/src/esp_now/mod.rs | 77 ++-- esp-wifi/src/lib.rs | 22 +- esp-wifi/src/preempt/mod.rs | 28 +- esp-wifi/src/tasks.rs | 40 +- esp-wifi/src/wifi/mod.rs | 187 +++++---- esp-wifi/src/wifi/os_adapter.rs | 43 +-- .../src/bin/wifi_embassy_esp_now_duplex.rs | 2 +- 27 files changed, 787 insertions(+), 830 deletions(-) diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 5597d41884c..aa932a0287a 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - No need to add `rom_functions.x` manually anymore (#2374) +- esp-now: Data is now private in `ReceivedData` - use `data()`(#2396) ### Fixed diff --git a/esp-wifi/MIGRATING-0.10.md b/esp-wifi/MIGRATING-0.10.md index 6bfc390fd6b..a8c7414dce1 100644 --- a/esp-wifi/MIGRATING-0.10.md +++ b/esp-wifi/MIGRATING-0.10.md @@ -10,3 +10,9 @@ rustflags = [ - "-C", "link-arg=-Trom_functions.x", ] ``` + +## ESP-NOW: Use `data` to access the received payload + +Previously `data` and `len` were public - use the previously already existing `data()` function. + +Accessing `data` or `len` was never encouraged. diff --git a/esp-wifi/src/ble/btdm.rs b/esp-wifi/src/ble/btdm.rs index 3c8a90d43cd..ba84cf1a54c 100644 --- a/esp-wifi/src/ble/btdm.rs +++ b/esp-wifi/src/ble/btdm.rs @@ -1,8 +1,10 @@ -use core::{cell::RefCell, ptr::addr_of}; +use alloc::boxed::Box; +use core::ptr::{addr_of, addr_of_mut}; -use critical_section::Mutex; +use esp_wifi_sys::c_types::c_void; use portable_atomic::{AtomicBool, Ordering}; +use super::ReceivedPacket; use crate::{ binary::include::*, ble::{ @@ -10,10 +12,8 @@ use crate::{ HciOutCollector, HCI_OUT_COLLECTOR, }, - compat::{common::str_from_c, queue::SimpleQueue}, + compat::common::{self, str_from_c, ConcurrentQueue}, hal::macros::ram, - memory_fence::memory_fence, - timer::yield_task, }; #[cfg_attr(esp32c3, path = "os_adapter_esp32c3.rs")] @@ -21,23 +21,10 @@ use crate::{ #[cfg_attr(esp32, path = "os_adapter_esp32.rs")] pub(crate) mod ble_os_adapter_chip_specific; -static BT_RECEIVE_QUEUE: Mutex>> = - Mutex::new(RefCell::new(SimpleQueue::new())); - -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ReceivedPacket { - pub len: u8, - pub data: [u8; 256], -} - -static BT_INTERNAL_QUEUE: Mutex>> = - Mutex::new(RefCell::new(SimpleQueue::new())); - static PACKET_SENT: AtomicBool = AtomicBool::new(true); #[repr(C)] -struct vhci_host_callback_s { +struct VhciHostCallbacks { notify_host_send_available: extern "C" fn(), /* callback used to notify that the host can * send packet to controller */ notify_host_recv: extern "C" fn(*mut u8, u16) -> i32, /* callback used to notify that the @@ -62,10 +49,10 @@ extern "C" { fn API_vhci_host_check_send_available() -> bool; fn API_vhci_host_send_packet(data: *const u8, len: u16); - fn API_vhci_host_register_callback(vhci_host_callbac: *const vhci_host_callback_s) -> i32; + fn API_vhci_host_register_callback(vhci_host_callbac: *const VhciHostCallbacks) -> i32; } -static VHCI_HOST_CALLBACK: vhci_host_callback_s = vhci_host_callback_s { +static VHCI_HOST_CALLBACK: VhciHostCallbacks = VhciHostCallbacks { notify_host_send_available, notify_host_recv, }; @@ -79,27 +66,21 @@ extern "C" fn notify_host_send_available() { extern "C" fn notify_host_recv(data: *mut u8, len: u16) -> i32 { trace!("notify_host_recv {:?} {}", data, len); - unsafe { - let mut buf = [0u8; 256]; - buf[..len as usize].copy_from_slice(core::slice::from_raw_parts(data, len as usize)); - - let packet = ReceivedPacket { - len: len as u8, - data: buf, - }; - - critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - if queue.enqueue(packet).is_err() { - warn!("Dropping BLE packet"); - } - }); + let data = unsafe { core::slice::from_raw_parts(data, len as usize) }; + + let packet = ReceivedPacket { + data: Box::from(data), + }; - dump_packet_info(core::slice::from_raw_parts(data as *const u8, len as usize)); + critical_section::with(|cs| { + let mut queue = super::BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + queue.push_back(packet); + }); - #[cfg(feature = "async")] - crate::ble::controller::asynch::hci_read_data_available(); - } + super::dump_packet_info(data); + + #[cfg(feature = "async")] + crate::ble::controller::asynch::hci_read_data_available(); 0 } @@ -178,38 +159,21 @@ unsafe extern "C" fn mutex_unlock(_mutex: *const ()) -> i32 { } unsafe extern "C" fn queue_create(len: u32, item_size: u32) -> *const () { - if len != 5 && item_size != 8 { - panic!("Unexpected queue spec {} {}", len, item_size); - } - &BT_INTERNAL_QUEUE as *const _ as *const () + let ptr = common::create_queue(len as i32, item_size as i32); + ptr.cast() } unsafe extern "C" fn queue_delete(queue: *const ()) { - trace!("Unimplemented queue_delete {:?}", queue); + common::delete_queue(queue as *mut ConcurrentQueue) } #[ram] -unsafe extern "C" fn queue_send(queue: *const (), item: *const (), _block_time_ms: u32) -> i32 { - if queue == &BT_INTERNAL_QUEUE as *const _ as *const () { - critical_section::with(|_| { - // assume the size is 8 - shouldn't rely on that - let message = item as *const u8; - let mut data = [0u8; 8]; - for (i, data) in data.iter_mut().enumerate() { - *data = *message.add(i); - } - trace!("queue posting {:?}", data); - - critical_section::with(|cs| { - let mut queue = BT_INTERNAL_QUEUE.borrow_ref_mut(cs); - unwrap!(queue.enqueue(data)); - }); - memory_fence(); - }); - } else { - panic!("Unknown queue"); - } - 1 +unsafe extern "C" fn queue_send(queue: *const (), item: *const (), block_time_ms: u32) -> i32 { + common::send_queued( + queue as *mut ConcurrentQueue, + item as *mut c_void, + block_time_ms, + ) } #[ram] @@ -225,53 +189,11 @@ unsafe extern "C" fn queue_send_from_isr( } unsafe extern "C" fn queue_recv(queue: *const (), item: *const (), block_time_ms: u32) -> i32 { - trace!( - "queue_recv {:?} item {:?} block_time_tick {}", - queue, - item, - block_time_ms - ); - - let forever = block_time_ms == crate::compat::common::OSI_FUNCS_TIME_BLOCKING; - let start = crate::timer::get_systimer_count(); - let block_ticks = crate::timer::millis_to_ticks(block_time_ms as u64); - - // handle the BT_QUEUE - if queue == &BT_INTERNAL_QUEUE as *const _ as *const () { - loop { - let res = critical_section::with(|_| { - memory_fence(); - - critical_section::with(|cs| { - let mut queue = BT_INTERNAL_QUEUE.borrow_ref_mut(cs); - if let Some(message) = queue.dequeue() { - let item = item as *mut u8; - for i in 0..8 { - item.offset(i).write_volatile(message[i as usize]); - } - trace!("received {:?}", message); - 1 - } else { - 0 - } - }) - }); - - if res == 1 { - trace!("queue_recv returns"); - return res; - } - - if !forever && crate::timer::elapsed_time_since(start) > block_ticks { - trace!("queue_recv returns with timeout"); - return -1; - } - - yield_task(); - } - } else { - panic!("Unknown queue to handle in queue_recv"); - } + common::receive_queued( + queue as *mut ConcurrentQueue, + item as *mut c_void, + block_time_ms, + ) } #[ram] @@ -444,7 +366,7 @@ unsafe extern "C" fn custom_queue_create( pub(crate) fn ble_init() { unsafe { - *(HCI_OUT_COLLECTOR.as_mut_ptr()) = HciOutCollector::new(); + (*addr_of_mut!(HCI_OUT_COLLECTOR)).write(HciOutCollector::new()); // turn on logging #[cfg(feature = "sys-logs")] { @@ -532,67 +454,8 @@ pub(crate) fn ble_deinit() { } } -static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256]; -static mut BLE_HCI_READ_DATA_INDEX: usize = 0; -static mut BLE_HCI_READ_DATA_LEN: usize = 0; - -#[cfg(feature = "async")] -pub(crate) fn have_hci_read_data() -> bool { - critical_section::with(|cs| { - let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - !queue.is_empty() - || unsafe { - BLE_HCI_READ_DATA_LEN > 0 && (BLE_HCI_READ_DATA_LEN >= BLE_HCI_READ_DATA_INDEX) - } - }) -} - -pub(crate) fn read_next(data: &mut [u8]) -> usize { - critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - - match queue.dequeue() { - Some(packet) => { - data[..packet.len as usize].copy_from_slice(&packet.data[..packet.len as usize]); - packet.len as usize - } - None => 0, - } - }) -} - -pub(crate) fn read_hci(data: &mut [u8]) -> usize { - unsafe { - if BLE_HCI_READ_DATA_LEN == 0 { - critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - - if let Some(packet) = queue.dequeue() { - BLE_HCI_READ_DATA[..packet.len as usize] - .copy_from_slice(&packet.data[..packet.len as usize]); - BLE_HCI_READ_DATA_LEN = packet.len as usize; - BLE_HCI_READ_DATA_INDEX = 0; - } - }); - } - - if BLE_HCI_READ_DATA_LEN > 0 { - data[0] = BLE_HCI_READ_DATA[BLE_HCI_READ_DATA_INDEX]; - BLE_HCI_READ_DATA_INDEX += 1; - - if BLE_HCI_READ_DATA_INDEX >= BLE_HCI_READ_DATA_LEN { - BLE_HCI_READ_DATA_LEN = 0; - BLE_HCI_READ_DATA_INDEX = 0; - } - return 1; - } - } - - 0 -} - -pub(crate) fn send_hci(data: &[u8]) { - let hci_out = unsafe { &mut *HCI_OUT_COLLECTOR.as_mut_ptr() }; +pub fn send_hci(data: &[u8]) { + let hci_out = unsafe { (*addr_of_mut!(HCI_OUT_COLLECTOR)).assume_init_mut() }; hci_out.push(data); if hci_out.is_ready() { @@ -611,7 +474,7 @@ pub(crate) fn send_hci(data: &[u8]) { API_vhci_host_send_packet(packet.as_ptr(), packet.len() as u16); trace!("sent vhci host packet"); - dump_packet_info(packet); + super::dump_packet_info(packet); break; } @@ -623,13 +486,3 @@ pub(crate) fn send_hci(data: &[u8]) { hci_out.reset(); } } - -#[allow(unreachable_code, unused_variables)] -fn dump_packet_info(buffer: &[u8]) { - #[cfg(not(feature = "dump-packets"))] - return; - - critical_section::with(|cs| { - info!("@HCIFRAME {:?}", buffer); - }); -} diff --git a/esp-wifi/src/ble/controller/mod.rs b/esp-wifi/src/ble/controller/mod.rs index 9ca3cc76177..1d639b469e0 100644 --- a/esp-wifi/src/ble/controller/mod.rs +++ b/esp-wifi/src/ble/controller/mod.rs @@ -95,7 +95,7 @@ pub mod asynch { use super::{read_hci, send_hci, BleConnectorError}; use crate::{ - ble::ble::have_hci_read_data, + ble::have_hci_read_data, hal::peripheral::{Peripheral, PeripheralRef}, EspWifiInitialization, }; diff --git a/esp-wifi/src/ble/mod.rs b/esp-wifi/src/ble/mod.rs index bf26fc3d913..1ea694fde5d 100644 --- a/esp-wifi/src/ble/mod.rs +++ b/esp-wifi/src/ble/mod.rs @@ -6,9 +6,11 @@ pub(crate) mod btdm; #[cfg(any(esp32c2, esp32c6, esp32h2))] pub(crate) mod npl; -use core::mem::MaybeUninit; +use alloc::{boxed::Box, collections::vec_deque::VecDeque, vec::Vec}; +use core::{cell::RefCell, mem::MaybeUninit}; -pub(crate) use ble::{ble_init, read_hci, read_next, send_hci}; +pub(crate) use ble::{ble_init, send_hci}; +use critical_section::Mutex; #[cfg(any(esp32, esp32c3, esp32s3))] use self::btdm as ble; @@ -30,6 +32,10 @@ pub(crate) unsafe extern "C" fn free(ptr: *mut crate::binary::c_types::c_void) { crate::compat::malloc::free(ptr.cast()) } +// Stores received packets until the the BLE stack dequeues them +static BT_RECEIVE_QUEUE: Mutex>> = + Mutex::new(RefCell::new(VecDeque::new())); + static mut HCI_OUT_COLLECTOR: MaybeUninit = MaybeUninit::uninit(); #[derive(PartialEq, Debug)] @@ -96,3 +102,66 @@ impl HciOutCollector { &self.data[0..self.index] } } + +static BLE_HCI_READ_DATA: Mutex>> = Mutex::new(RefCell::new(Vec::new())); + +#[derive(Debug, Clone)] +pub struct ReceivedPacket { + pub data: Box<[u8]>, +} + +#[cfg(feature = "defmt")] +impl defmt::Format for ReceivedPacket { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "ReceivedPacket {}", &self.data[..]) + } +} + +#[cfg(feature = "async")] +pub fn have_hci_read_data() -> bool { + critical_section::with(|cs| { + let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + let hci_read_data = BLE_HCI_READ_DATA.borrow_ref(cs); + !queue.is_empty() || !hci_read_data.is_empty() + }) +} + +pub(crate) fn read_next(data: &mut [u8]) -> usize { + critical_section::with(|cs| { + let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + + match queue.pop_front() { + Some(packet) => { + data[..packet.data.len()].copy_from_slice(&packet.data[..packet.data.len()]); + packet.data.len() + } + None => 0, + } + }) +} + +pub fn read_hci(data: &mut [u8]) -> usize { + critical_section::with(|cs| { + let mut hci_read_data = BLE_HCI_READ_DATA.borrow_ref_mut(cs); + + if hci_read_data.is_empty() { + let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + + if let Some(packet) = queue.pop_front() { + hci_read_data.extend_from_slice(&packet.data); + } + } + + let l = usize::min(hci_read_data.len(), data.len()); + data[..l].copy_from_slice(&hci_read_data[..l]); + hci_read_data.drain(..l); + l + }) +} + +fn dump_packet_info(_buffer: &[u8]) { + #[cfg(feature = "dump-packets")] + critical_section::with(|_cs| { + info!("@HCIFRAME {:?}", _buffer); + }); +} diff --git a/esp-wifi/src/ble/npl.rs b/esp-wifi/src/ble/npl.rs index 8deaadc5bc3..a7d34884f6d 100644 --- a/esp-wifi/src/ble/npl.rs +++ b/esp-wifi/src/ble/npl.rs @@ -1,18 +1,19 @@ +use alloc::boxed::Box; use core::{ - cell::RefCell, + mem::size_of_val, ptr::{addr_of, addr_of_mut}, }; -use critical_section::Mutex; - use super::*; use crate::{ binary::{ c_types::{c_char, c_void}, include::*, }, - compat, - compat::{common::str_from_c, queue::SimpleQueue}, + compat::{ + self, + common::{str_from_c, ConcurrentQueue}, + }, timer::yield_task, }; @@ -21,6 +22,8 @@ use crate::{ #[cfg_attr(esp32h2, path = "os_adapter_esp32h2.rs")] pub(crate) mod ble_os_adapter_chip_specific; +const EVENT_QUEUE_SIZE: usize = 16; + const TIME_FOREVER: u32 = crate::compat::common::OSI_FUNCS_TIME_BLOCKING; #[cfg(esp32c2)] @@ -41,41 +44,25 @@ const BLE_HCI_TRANS_BUF_CMD: i32 = 3; // ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data const ACL_DATA_MBUF_LEADINGSPACE: usize = 4; +#[repr(C)] #[derive(Copy, Clone)] struct Callout { - _callout: *const ble_npl_callout, eventq: *const ble_npl_eventq, timer_handle: ets_timer, events: ble_npl_event, } -static mut CALLOUTS: [Option; 18] = [None; 18]; - +#[repr(C)] #[derive(Copy, Clone)] struct Event { - event: *const ble_npl_event, event_fn_ptr: *const ble_npl_event_fn, ev_arg_ptr: *const c_void, queued: bool, } -static mut EVENTS: [Option; 95] = [None; 95]; - -static mut EVENT_QUEUE: SimpleQueue = SimpleQueue::new(); - -static BT_RECEIVE_QUEUE: Mutex>> = - Mutex::new(RefCell::new(SimpleQueue::new())); - #[cfg(esp32c2)] type OsMembufT = u32; -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ReceivedPacket { - pub len: u8, - pub data: [u8; 256], -} - /// Memory pool #[repr(C)] pub(crate) struct OsMempool { @@ -711,14 +698,12 @@ unsafe extern "C" fn ble_npl_callout_deinit(callout: *const ble_npl_callout) { unsafe extern "C" fn ble_npl_callout_stop(callout: *const ble_npl_callout) { trace!("ble_npl_callout_stop {:?}", callout); - if (*callout).dummy == 0 { - panic!("Trying to stop an uninitialzed callout"); - } + assert!((*callout).dummy != 0); - let co = unwrap!(CALLOUTS[((*callout).dummy - 1) as usize].as_mut()); + let co = (*callout).dummy as *mut Callout; // stop timer - compat::timer_compat::compat_timer_disarm(addr_of_mut!(co.timer_handle)); + compat::timer_compat::compat_timer_disarm(addr_of_mut!((*co).timer_handle)); } unsafe extern "C" fn ble_npl_callout_reset( @@ -727,10 +712,10 @@ unsafe extern "C" fn ble_npl_callout_reset( ) -> ble_npl_error_t { trace!("ble_npl_callout_reset {:?} {}", callout, time); - let co = unwrap!(CALLOUTS[((*callout).dummy - 1) as usize].as_mut()); + let co = (*callout).dummy as *mut Callout; // start timer - compat::timer_compat::compat_timer_arm(addr_of_mut!(co.timer_handle), time, false); + compat::timer_compat::compat_timer_arm(addr_of_mut!((*co).timer_handle), time, false); 0 } @@ -775,20 +760,20 @@ unsafe extern "C" fn ble_npl_mutex_deinit(_mutex: *const ble_npl_mutex) -> ble_n unsafe extern "C" fn ble_npl_event_set_arg(event: *const ble_npl_event, arg: *const c_void) { trace!("ble_npl_event_set_arg {:?} {:?}", event, arg); - if (*event).dummy == 0 { - panic!("Call set_arg on uninitialized event"); - } - unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).ev_arg_ptr = arg; + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); + + (*evt).ev_arg_ptr = arg; } unsafe extern "C" fn ble_npl_event_get_arg(event: *const ble_npl_event) -> *const c_void { trace!("ble_npl_event_get_arg {:?}", event); - if (*event).dummy == 0 { - panic!("Call get_arg on uninitialized event"); - } - let arg_ptr = unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).ev_arg_ptr; + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); + + let arg_ptr = (*evt).ev_arg_ptr; trace!("returning arg {:x}", arg_ptr as usize); @@ -797,36 +782,31 @@ unsafe extern "C" fn ble_npl_event_get_arg(event: *const ble_npl_event) -> *cons unsafe extern "C" fn ble_npl_event_is_queued(event: *const ble_npl_event) -> bool { trace!("ble_npl_event_is_queued {:?}", event); - if (*event).dummy == 0 { - panic!("Call is_queued on uninitialized event"); - } - unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).queued + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); + + (*evt).queued } unsafe extern "C" fn ble_npl_event_reset(event: *const ble_npl_event) { trace!("ble_npl_event_reset {:?}", event); - let event = event as *mut ble_npl_event; - if (*event).dummy == 0 { - panic!("Trying to reset an uninitialized event"); - } else { - unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).queued = false; - } + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); + + (*evt).queued = false } unsafe extern "C" fn ble_npl_event_deinit(event: *const ble_npl_event) { trace!("ble_npl_event_deinit {:?}", event); - let event = event.cast_mut(); + let event = event as *mut ble_npl_event; + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); - if (*event).dummy == 0 { - panic!("Trying to deinitialize an uninitialized event"); - } else { - let idx = ((*event).dummy - 1) as usize; - EVENTS[idx] = None; - (*event).dummy = 0; - } + crate::compat::malloc::free(evt.cast()); + (*event).dummy = 0; } unsafe extern "C" fn ble_npl_event_init( @@ -837,41 +817,34 @@ unsafe extern "C" fn ble_npl_event_init( trace!("ble_npl_event_init {:?} {:?} {:?}", event, func, arg); if (*event).dummy == 0 { - let idx = unwrap!(EVENTS.iter().position(|item| item.is_none())); - EVENTS[idx] = Some(Event { - event, - event_fn_ptr: func, - ev_arg_ptr: arg, - queued: false, - }); + let evt = crate::compat::malloc::calloc(1, core::mem::size_of::()) as *mut Event; + + (*evt).event_fn_ptr = func; + (*evt).ev_arg_ptr = arg; + (*evt).queued = false; let event = event.cast_mut(); - (*event).dummy = (idx + 1) as i32; + (*event).dummy = evt as i32; } } unsafe extern "C" fn ble_npl_eventq_is_empty(queue: *const ble_npl_eventq) -> bool { trace!("ble_npl_eventq_is_empty {:?}", queue); - if (*queue).dummy == 0 { - panic!("Try to use uninitialized queue"); - } - - critical_section::with(|_| EVENT_QUEUE.is_empty()) + let queue = (*queue).dummy as *mut ConcurrentQueue; + assert!(!queue.is_null()); + (*queue).count() == 0 } unsafe extern "C" fn ble_npl_event_run(event: *const ble_npl_event) { trace!("ble_npl_event_run {:?}", event); - let event = event as *mut ble_npl_event; - if (*event).dummy == 0 { - panic!("Trying to run an uninitialized event"); - } else { - let ev = unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()); - trace!("info {:?} with arg {:x}", ev.event_fn_ptr, event as u32); - let func: unsafe extern "C" fn(u32) = core::mem::transmute(ev.event_fn_ptr); - func(event as u32); - } + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); + + trace!("info {:?} with arg {:x}", (*evt).event_fn_ptr, event as u32); + let func: unsafe extern "C" fn(u32) = core::mem::transmute((*evt).event_fn_ptr); + func(event as u32); trace!("ble_npl_event_run done"); } @@ -880,36 +853,35 @@ unsafe extern "C" fn ble_npl_eventq_remove( queue: *const ble_npl_eventq, event: *const ble_npl_event, ) { - trace!("ble_npl_eventq_remove {:?} {:?}", queue, event); + info!("ble_npl_eventq_remove {:?} {:?}", queue, event); - if (*queue).dummy == 0 { - panic!("Try to use uninitialized queue"); - } + assert!((*queue).dummy != 0); + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); - if (*event).dummy == 0 { - panic!("Try to use uninitialized event"); + if !(*evt).queued { + return; } - critical_section::with(|_| { - unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).queued = false; - }); + let queue = (*queue).dummy as *mut ConcurrentQueue; + (*queue).remove(addr_of!(event) as *mut _); + + (*evt).queued = false; } unsafe extern "C" fn ble_npl_eventq_put(queue: *const ble_npl_eventq, event: *const ble_npl_event) { trace!("ble_npl_eventq_put {:?} {:?}", queue, event); - if (*queue).dummy == 0 { - panic!("Try to use uninitialized queue"); - } + assert!((*queue).dummy != 0); - if (*event).dummy == 0 { - panic!("Try to use uninitialized event"); - } + let evt = (*event).dummy as *mut Event; + assert!(!evt.is_null()); - critical_section::with(|_| { - unwrap!(EVENTS[((*event).dummy - 1) as usize].as_mut()).queued = true; - unwrap!(EVENT_QUEUE.enqueue((*event).dummy as usize)); - }); + (*evt).queued = true; + + let queue = (*queue).dummy as *mut ConcurrentQueue; + let mut event = event as usize; + (*queue).enqueue(addr_of_mut!(event).cast()); } unsafe extern "C" fn ble_npl_eventq_get( @@ -918,16 +890,18 @@ unsafe extern "C" fn ble_npl_eventq_get( ) -> *const ble_npl_event { trace!("ble_npl_eventq_get {:?} {}", queue, time); + let queue = (*queue).dummy as *mut ConcurrentQueue; + + let mut event: usize = 0; if time == TIME_FOREVER { loop { - let dequeued = critical_section::with(|_| EVENT_QUEUE.dequeue()); - - if let Some(event_idx) = dequeued { - let evt = unwrap!(EVENTS[event_idx - 1].as_mut()); - if evt.queued { - trace!("got {:x}", evt.event as usize); - evt.queued = false; - return evt.event; + if (*queue).try_dequeue(addr_of_mut!(event).cast()) { + let event = event as *mut ble_npl_event; + let evt = (*event).dummy as *mut Event; + if (*evt).queued { + trace!("got {:x}", evt as usize); + (*evt).queued = false; + return event as *const ble_npl_event; } } @@ -942,19 +916,13 @@ unsafe extern "C" fn ble_npl_eventq_deinit(queue: *const ble_npl_eventq) { trace!("ble_npl_eventq_deinit {:?}", queue); let queue = queue.cast_mut(); - if (*queue).dummy == 0 { - panic!("Trying to deinitialize an uninitialized queue"); - } else { - critical_section::with(|_| { - while let Some(event_idx) = EVENT_QUEUE.dequeue() { - if let Some(event) = EVENTS[event_idx - 1].as_mut() { - event.queued = false; - } - } - }); + assert!((*queue).dummy != 0); - (*queue).dummy = 0; + let real_queue = (*queue).dummy as *mut ConcurrentQueue; + unsafe { + core::ptr::drop_in_place(real_queue); } + (*queue).dummy = 0; } unsafe extern "C" fn ble_npl_callout_init( @@ -973,58 +941,46 @@ unsafe extern "C" fn ble_npl_callout_init( if (*callout).dummy == 0 { let callout = callout.cast_mut(); - let idx = unwrap!(CALLOUTS.iter().position(|item| item.is_none())); - - let new_callout = CALLOUTS[idx].insert(Callout { - _callout: callout, - eventq, - timer_handle: ets_timer { - next: core::ptr::null_mut(), - expire: 0, - period: 0, - func: None, - priv_: core::ptr::null_mut(), - }, - events: ble_npl_event { dummy: 0 }, - }); - ble_npl_event_init(addr_of_mut!(new_callout.events), func, args); + let new_callout = + crate::compat::malloc::calloc(1, core::mem::size_of::()) as *mut Callout; + ble_npl_event_init(addr_of_mut!((*new_callout).events), func, args); + (*callout).dummy = new_callout as i32; crate::compat::timer_compat::compat_timer_setfn( - addr_of_mut!(new_callout.timer_handle), + addr_of_mut!((*new_callout).timer_handle), callout_timer_callback_wrapper, - idx as *mut c_void, + callout as *mut c_void, ); - - (*callout).dummy = (idx + 1) as i32; } 0 } unsafe extern "C" fn callout_timer_callback_wrapper(arg: *mut c_void) { - info!("callout_timer_callback_wrapper {:?}", arg); - let co = unwrap!(CALLOUTS[arg as usize].as_mut()); + trace!("callout_timer_callback_wrapper {:?}", arg); + let co = (*(arg as *mut ble_npl_callout)).dummy as *mut Callout; - if co.eventq.is_null() { - ble_npl_eventq_put(addr_of!(co.events).cast(), addr_of!(co.events)); + if !(*co).eventq.is_null() { + ble_npl_eventq_put(addr_of!((*co).eventq).cast(), addr_of!((*co).events)); } else { - ble_npl_event_run(addr_of!(co.events)); + ble_npl_event_run(addr_of!((*co).events)); } } unsafe extern "C" fn ble_npl_eventq_init(queue: *const ble_npl_eventq) { trace!("ble_npl_eventq_init {:?}", queue); - critical_section::with(|_cs| { - let queue = queue as *mut ble_npl_eventq; + let queue = queue as *mut ble_npl_eventq; - if (*queue).dummy == 0 { - (*queue).dummy = 1; - } else { - panic!("Only one emulated queue supported"); - } - }); + let raw_queue = ConcurrentQueue::new(EVENT_QUEUE_SIZE, 4); + let ptr = + unsafe { crate::compat::malloc::malloc(size_of_val(&raw_queue)) as *mut ConcurrentQueue }; + unsafe { + ptr.write(raw_queue); + } + + (*queue).dummy = ptr as i32; } unsafe extern "C" fn ble_npl_mutex_init(_mutex: *const ble_npl_mutex) -> u32 { @@ -1050,7 +1006,7 @@ pub struct BleNplCountInfoT { pub(crate) fn ble_init() { unsafe { - *(HCI_OUT_COLLECTOR.as_mut_ptr()) = HciOutCollector::new(); + (*addr_of_mut!(HCI_OUT_COLLECTOR)).write(HciOutCollector::new()); // turn on logging #[cfg(all(feature = "sys-logs", esp32c2))] @@ -1247,10 +1203,6 @@ pub(crate) fn ble_deinit() { npl::esp_unregister_ext_funcs(); crate::common_adapter::chip_specific::phy_disable(); - - CALLOUTS.iter_mut().for_each(|item| { - item.take(); - }); } } @@ -1325,7 +1277,7 @@ unsafe extern "C" fn ble_hs_hci_rx_evt(cmd: *const u8, arg: *const c_void) -> i3 trace!("$ pld = {:?}", payload); critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + let mut queue = super::BT_RECEIVE_QUEUE.borrow_ref_mut(cs); let mut data = [0u8; 256]; data[0] = 0x04; // this is an event @@ -1333,15 +1285,9 @@ unsafe extern "C" fn ble_hs_hci_rx_evt(cmd: *const u8, arg: *const c_void) -> i3 data[2] = len as u8; data[3..][..len].copy_from_slice(payload); - if queue - .enqueue(ReceivedPacket { - len: (len + 3) as u8, - data, - }) - .is_err() - { - warn!("Dropping BLE packet"); - } + queue.push_back(ReceivedPacket { + data: Box::from(&data[..len + 3]), + }); dump_packet_info(&data[..(len + 3)]); }); @@ -1362,23 +1308,17 @@ unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) -> i3 let data_slice = core::slice::from_raw_parts(data_ptr, len as usize); critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); + let mut queue = super::BT_RECEIVE_QUEUE.borrow_ref_mut(cs); let mut data = [0u8; 256]; data[0] = 0x02; // ACL data[1..][..data_slice.len()].copy_from_slice(data_slice); - if queue - .enqueue(ReceivedPacket { - len: (len + 1) as u8, - data, - }) - .is_err() - { - warn!("Dropping BLE packet"); - } + queue.push_back(ReceivedPacket { + data: Box::from(&data[..data_slice.len() + 1]), + }); - dump_packet_info(&data[..(len + 1) as usize]); + super::dump_packet_info(&data[..(len + 1) as usize]); }); r_os_mbuf_free_chain(om as *mut _); @@ -1389,67 +1329,8 @@ unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) -> i3 0 } -static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256]; -static mut BLE_HCI_READ_DATA_INDEX: usize = 0; -static mut BLE_HCI_READ_DATA_LEN: usize = 0; - -#[cfg(feature = "async")] -pub fn have_hci_read_data() -> bool { - critical_section::with(|cs| { - let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - !queue.is_empty() - || unsafe { - BLE_HCI_READ_DATA_LEN > 0 && (BLE_HCI_READ_DATA_LEN >= BLE_HCI_READ_DATA_INDEX) - } - }) -} - -pub(crate) fn read_next(data: &mut [u8]) -> usize { - critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - - match queue.dequeue() { - Some(packet) => { - data[..packet.len as usize].copy_from_slice(&packet.data[..packet.len as usize]); - packet.len as usize - } - None => 0, - } - }) -} - -pub fn read_hci(data: &mut [u8]) -> usize { - unsafe { - if BLE_HCI_READ_DATA_LEN == 0 { - critical_section::with(|cs| { - let mut queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); - - if let Some(packet) = queue.dequeue() { - BLE_HCI_READ_DATA[..packet.len as usize] - .copy_from_slice(&packet.data[..packet.len as usize]); - BLE_HCI_READ_DATA_LEN = packet.len as usize; - BLE_HCI_READ_DATA_INDEX = 0; - } - }); - } - - if BLE_HCI_READ_DATA_LEN > 0 { - data[0] = BLE_HCI_READ_DATA[BLE_HCI_READ_DATA_INDEX]; - BLE_HCI_READ_DATA_INDEX += 1; - - if BLE_HCI_READ_DATA_INDEX >= BLE_HCI_READ_DATA_LEN { - BLE_HCI_READ_DATA_LEN = 0; - BLE_HCI_READ_DATA_INDEX = 0; - } - return 1; - } - } - - 0 -} - pub fn send_hci(data: &[u8]) { - let hci_out = unsafe { &mut *HCI_OUT_COLLECTOR.as_mut_ptr() }; + let hci_out = unsafe { (*addr_of_mut!(HCI_OUT_COLLECTOR)).assume_init_mut() }; hci_out.push(data); if hci_out.is_ready() { @@ -1503,13 +1384,3 @@ pub fn send_hci(data: &[u8]) { hci_out.reset(); } } - -#[allow(unreachable_code, unused_variables)] -fn dump_packet_info(buffer: &[u8]) { - #[cfg(not(feature = "dump-packets"))] - return; - - critical_section::with(|cs| { - info!("@HCIFRAME {:?}", buffer); - }); -} diff --git a/esp-wifi/src/ble/os_adapter_esp32c2.rs b/esp-wifi/src/ble/os_adapter_esp32c2.rs index 06307c58ac3..8a24212b7b1 100644 --- a/esp-wifi/src/ble/os_adapter_esp32c2.rs +++ b/esp-wifi/src/ble/os_adapter_esp32c2.rs @@ -1,8 +1,4 @@ -use crate::{ - binary::include::esp_bt_controller_config_t, - common_adapter::RADIO_CLOCKS, - hal::system::RadioClockController, -}; +use crate::{binary::include::esp_bt_controller_config_t, hal::system::RadioClockController}; pub(crate) static mut ISR_INTERRUPT_4: ( *mut crate::binary::c_types::c_void, @@ -103,14 +99,16 @@ pub(super) unsafe extern "C" fn esp_intr_alloc( } pub(super) fn ble_rtc_clk_init() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).ble_rtc_clk_init(); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.ble_rtc_clk_init(); } pub(super) unsafe extern "C" fn esp_reset_rpa_moudle() { trace!("esp_reset_rpa_moudle"); - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).reset_rpa(); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.reset_rpa(); } diff --git a/esp-wifi/src/ble/os_adapter_esp32c6.rs b/esp-wifi/src/ble/os_adapter_esp32c6.rs index 50b1127e058..49cc0c033cd 100644 --- a/esp-wifi/src/ble/os_adapter_esp32c6.rs +++ b/esp-wifi/src/ble/os_adapter_esp32c6.rs @@ -1,6 +1,5 @@ use crate::{ binary::include::esp_bt_controller_config_t, - common_adapter::RADIO_CLOCKS, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -66,9 +65,10 @@ pub(crate) static BLE_CONFIG: esp_bt_controller_config_t = esp_bt_controller_con }; pub(crate) fn bt_periph_module_enable() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Bt); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Bt); } pub(crate) fn disable_sleep_mode() { @@ -101,16 +101,18 @@ pub(super) unsafe extern "C" fn esp_intr_alloc( } pub(super) fn ble_rtc_clk_init() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).ble_rtc_clk_init(); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.ble_rtc_clk_init(); } pub(super) unsafe extern "C" fn esp_reset_rpa_moudle() { trace!("esp_reset_rpa_moudle"); - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).reset_rpa(); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.reset_rpa(); } #[allow(improper_ctypes_definitions)] diff --git a/esp-wifi/src/ble/os_adapter_esp32h2.rs b/esp-wifi/src/ble/os_adapter_esp32h2.rs index f0f8d49b1f1..5c310927023 100644 --- a/esp-wifi/src/ble/os_adapter_esp32h2.rs +++ b/esp-wifi/src/ble/os_adapter_esp32h2.rs @@ -1,6 +1,5 @@ use crate::{ binary::include::esp_bt_controller_config_t, - common_adapter::RADIO_CLOCKS, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -66,9 +65,10 @@ pub(crate) static BLE_CONFIG: esp_bt_controller_config_t = esp_bt_controller_con }; pub(crate) fn bt_periph_module_enable() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Bt); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Bt); } pub(crate) fn disable_sleep_mode() { @@ -101,16 +101,18 @@ pub(super) unsafe extern "C" fn esp_intr_alloc( } pub(super) fn ble_rtc_clk_init() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).ble_rtc_clk_init(); - } + // stealing RADIO_CLK is safe since it is passed (as reference or by value) into + // `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.ble_rtc_clk_init(); } pub(super) unsafe extern "C" fn esp_reset_rpa_moudle() { trace!("esp_reset_rpa_moudle"); - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).reset_rpa(); - } + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.reset_rpa(); } #[allow(improper_ctypes_definitions)] diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32.rs b/esp-wifi/src/common_adapter/common_adapter_esp32.rs index cdc16fa0434..26a05931a95 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, hal::{ prelude::ram, system::{RadioClockController, RadioPeripherals}, @@ -16,8 +15,8 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); -static mut PHY_CLOCK_ENABLE_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_CLOCK_ENABLE_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { unsafe { @@ -35,7 +34,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -123,9 +122,10 @@ pub(crate) unsafe fn phy_enable_clock() { let count = PHY_CLOCK_ENABLE_REF.fetch_add(1, Ordering::SeqCst); if count == 0 { - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); } } @@ -135,9 +135,10 @@ pub(crate) unsafe fn phy_disable_clock() { let count = PHY_CLOCK_ENABLE_REF.fetch_sub(1, Ordering::SeqCst); if count == 1 { - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); } } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32c2.rs b/esp-wifi/src/common_adapter/common_adapter_esp32c2.rs index 53265bb42a2..99a8f74da20 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32c2.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32c2.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, compat::common::str_from_c, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -14,7 +13,7 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { // In esp-idf, neither SOC_PM_SUPPORT_MODEM_PD or SOC_PM_SUPPORT_WIFI_PD are @@ -23,7 +22,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -114,9 +113,10 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { trace!("phy_enable_clock"); - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } @@ -124,9 +124,10 @@ pub(crate) unsafe fn phy_enable_clock() { #[allow(unused)] pub(crate) unsafe fn phy_disable_clock() { trace!("phy_disable_clock"); - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs b/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs index b901b3423b0..8a4bf0ab044 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, compat::common::str_from_c, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -14,7 +13,7 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { const SYSTEM_WIFIBB_RST: u32 = 1 << 0; @@ -58,7 +57,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -156,19 +155,20 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { trace!("phy_enable_clock"); - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } #[allow(unused)] pub(crate) unsafe fn phy_disable_clock() { trace!("phy_disable_clock"); - const SYSTEM_WIFI_CLK_EN_REG: u32 = 0x60026000 + 0x014; - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); - }); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs b/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs index 215879d7f6c..74f3d76cecd 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, compat::common::str_from_c, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -14,7 +13,7 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { // In esp-idf, SOC_PMU_SUPPORTED is set which makes @@ -23,7 +22,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -120,13 +119,19 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { trace!("phy_enable_clock"); - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } #[allow(unused)] pub(crate) unsafe fn phy_disable_clock() { trace!("phy_disable_clock"); - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs b/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs index 8b2e4646d90..1cb0b537589 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs @@ -4,7 +4,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, compat::common::str_from_c, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -15,7 +14,7 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { // In esp-idf, SOC_PMU_SUPPORTED is set which makes @@ -24,7 +23,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -123,13 +122,19 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { trace!("phy_enable_clock"); - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } #[allow(unused)] pub(crate) unsafe fn phy_disable_clock() { trace!("phy_disable_clock"); - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32s2.rs b/esp-wifi/src/common_adapter/common_adapter_esp32s2.rs index a48a28870f6..b87536dbf75 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32s2.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32s2.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, hal::{ prelude::ram, system::{RadioClockController, RadioPeripherals}, @@ -16,8 +15,8 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); -static mut PHY_CLOCK_ENABLE_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_CLOCK_ENABLE_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn enable_wifi_power_domain() { const DPORT_WIFIBB_RST: u32 = 1 << 0; @@ -58,7 +57,7 @@ pub(crate) fn enable_wifi_power_domain() { pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -137,10 +136,10 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { let count = PHY_CLOCK_ENABLE_REF.fetch_add(1, Ordering::SeqCst); if count == 0 { - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); - }); - + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } } @@ -149,10 +148,10 @@ pub(crate) unsafe fn phy_enable_clock() { pub(crate) unsafe fn phy_disable_clock() { let count = PHY_CLOCK_ENABLE_REF.fetch_sub(1, Ordering::SeqCst); if count == 1 { - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); - }); - + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs b/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs index 49b9aabc52f..249370caa1f 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs @@ -3,7 +3,6 @@ use portable_atomic::{AtomicU32, Ordering}; use super::phy_init_data::PHY_INIT_DATA_DEFAULT; use crate::{ binary::include::*, - common_adapter::RADIO_CLOCKS, hal::system::{RadioClockController, RadioPeripherals}, }; @@ -13,11 +12,11 @@ static mut SOC_PHY_DIG_REGS_MEM: [u8; SOC_PHY_DIG_REGS_MEM_SIZE] = [0u8; SOC_PHY static mut G_IS_PHY_CALIBRATED: bool = false; static mut G_PHY_DIGITAL_REGS_MEM: *mut u32 = core::ptr::null_mut(); static mut S_IS_PHY_REG_STORED: bool = false; -static mut PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); +static PHY_ACCESS_REF: AtomicU32 = AtomicU32::new(0); pub(crate) fn phy_mem_init() { unsafe { - G_PHY_DIGITAL_REGS_MEM = SOC_PHY_DIG_REGS_MEM.as_ptr() as *mut u32; + G_PHY_DIGITAL_REGS_MEM = core::ptr::addr_of_mut!(SOC_PHY_DIG_REGS_MEM).cast(); } } @@ -148,20 +147,20 @@ fn phy_digital_regs_store() { pub(crate) unsafe fn phy_enable_clock() { trace!("phy_enable_clock"); - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Phy); - }); - + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Phy); trace!("phy_enable_clock done!"); } #[allow(unused)] pub(crate) unsafe fn phy_disable_clock() { trace!("phy_disable_clock"); - critical_section::with(|_| { - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Phy); - }); - + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Phy); trace!("phy_disable_clock done!"); } diff --git a/esp-wifi/src/common_adapter/mod.rs b/esp-wifi/src/common_adapter/mod.rs index be2b5d52422..e41dc17ec9f 100644 --- a/esp-wifi/src/common_adapter/mod.rs +++ b/esp-wifi/src/common_adapter/mod.rs @@ -1,7 +1,7 @@ use core::ptr::addr_of; use esp_wifi_sys::include::timeval; -use hal::{macros::ram, rng::Rng}; +use hal::macros::ram; use crate::{ binary::include::{esp_event_base_t, esp_timer_get_time}, @@ -27,22 +27,6 @@ pub(crate) mod chip_specific; #[cfg_attr(esp32s2, path = "phy_init_data_esp32s2.rs")] pub(crate) mod phy_init_data; -pub(crate) static mut RANDOM_GENERATOR: Option = None; - -pub(crate) static mut RADIO_CLOCKS: Option = None; - -pub(crate) fn init_rng(rng: Rng) { - unsafe { RANDOM_GENERATOR = Some(rng) }; -} - -pub(crate) fn init_radio_clock_control(rcc: hal::peripherals::RADIO_CLK) { - unsafe { RADIO_CLOCKS = Some(rcc) }; -} - -pub(crate) fn deinit_radio_clock_control() -> Option { - unsafe { RADIO_CLOCKS.take() } -} - /// ************************************************************************** /// Name: esp_semphr_create /// @@ -131,11 +115,9 @@ pub unsafe extern "C" fn semphr_give(semphr: *mut crate::binary::c_types::c_void pub unsafe extern "C" fn random() -> crate::binary::c_types::c_ulong { trace!("random"); - if let Some(ref mut rng) = RANDOM_GENERATOR { - rng.random() - } else { - 0 - } + // stealing RNG is safe since we own it (passed into `init`) + let mut rng = esp_hal::rng::Rng::new(unsafe { esp_hal::peripherals::RNG::steal() }); + rng.random() } /// ************************************************************************** @@ -308,11 +290,11 @@ pub unsafe extern "C" fn esp_fill_random(dst: *mut u8, len: u32) { trace!("esp_fill_random"); let dst = core::slice::from_raw_parts_mut(dst, len as usize); - if let Some(ref mut rng) = RANDOM_GENERATOR { - for chunk in dst.chunks_mut(4) { - let bytes = rng.random().to_le_bytes(); - chunk.copy_from_slice(&bytes[..chunk.len()]); - } + // stealing RNG is safe since we own it (passed into `init`) + let mut rng = esp_hal::rng::Rng::new(unsafe { esp_hal::peripherals::RNG::steal() }); + for chunk in dst.chunks_mut(4) { + let bytes = rng.random().to_le_bytes(); + chunk.copy_from_slice(&bytes[..chunk.len()]); } } diff --git a/esp-wifi/src/compat/common.rs b/esp-wifi/src/compat/common.rs index d8d29aa2245..946650f75c2 100644 --- a/esp-wifi/src/compat/common.rs +++ b/esp-wifi/src/compat/common.rs @@ -1,9 +1,10 @@ #![allow(unused)] use core::{ + cell::RefCell, fmt::Write, mem::size_of_val, - ptr::{addr_of, addr_of_mut}, + ptr::{self, addr_of, addr_of_mut}, }; use esp_wifi_sys::include::malloc; @@ -25,10 +26,52 @@ struct Mutex { recursive: bool, } +pub(crate) struct ConcurrentQueue { + raw_queue: critical_section::Mutex>, +} + +impl ConcurrentQueue { + pub(crate) fn new(count: usize, item_size: usize) -> Self { + Self { + raw_queue: critical_section::Mutex::new(RefCell::new(RawQueue::new(count, item_size))), + } + } + + fn release_storage(&mut self) { + critical_section::with(|cs| unsafe { + self.raw_queue.borrow_ref_mut(cs).release_storage(); + }) + } + + pub(crate) fn enqueue(&mut self, item: *mut c_void) -> i32 { + critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).enqueue(item) }) + } + + pub(crate) fn try_dequeue(&mut self, item: *mut c_void) -> bool { + critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).try_dequeue(item) }) + } + + pub(crate) fn remove(&mut self, item: *mut c_void) { + critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref_mut(cs).remove(item) }); + } + + pub(crate) fn count(&self) -> usize { + critical_section::with(|cs| unsafe { self.raw_queue.borrow_ref(cs).count() }) + } +} + +impl Drop for ConcurrentQueue { + fn drop(&mut self) { + self.release_storage(); + } +} + /// A naive and pretty much unsafe queue to back the queues used in drivers and -/// supplicant code -struct RawQueue { - count: usize, +/// supplicant code. +/// +/// The [ConcurrentQueue] wrapper should be used. +pub struct RawQueue { + capacity: usize, item_size: usize, current_read: usize, current_write: usize, @@ -36,10 +79,13 @@ struct RawQueue { } impl RawQueue { - fn new(count: usize, item_size: usize) -> Self { - let storage = unsafe { malloc((count * item_size) as u32) as *mut u8 }; + /// This allocates underlying storage. See [release_storage] + pub fn new(capacity: usize, item_size: usize) -> Self { + let storage = unsafe { malloc((capacity * item_size) as u32) as *mut u8 }; + assert!(!storage.is_null()); + Self { - count, + capacity, item_size, current_read: 0, current_write: 0, @@ -47,19 +93,20 @@ impl RawQueue { } } - fn free_storage(&mut self) { + /// Call `release_storage` to deallocate the underlying storage + unsafe fn release_storage(&mut self) { unsafe { free(self.storage); } self.storage = core::ptr::null_mut(); } - fn enqueue(&mut self, item: *mut c_void) -> i32 { - if self.count() < self.count { + unsafe fn enqueue(&mut self, item: *mut c_void) -> i32 { + if self.count() < self.capacity { unsafe { let p = self.storage.byte_add(self.item_size * self.current_write); p.copy_from(item as *mut u8, self.item_size); - self.current_write = (self.current_write + 1) % self.count; + self.current_write = (self.current_write + 1) % self.capacity; } 1 @@ -68,12 +115,12 @@ impl RawQueue { } } - fn try_dequeue(&mut self, item: *mut c_void) -> bool { + unsafe fn try_dequeue(&mut self, item: *mut c_void) -> bool { if self.count() > 0 { unsafe { let p = self.storage.byte_add(self.item_size * self.current_read) as *const c_void; item.copy_from(p, self.item_size); - self.current_read = (self.current_read + 1) % self.count; + self.current_read = (self.current_read + 1) % self.capacity; } true } else { @@ -81,11 +128,40 @@ impl RawQueue { } } - fn count(&self) -> usize { + unsafe fn remove(&mut self, item: *mut c_void) { + // do what the ESP-IDF implementations does ... + // just remove all elements and add them back except the one we need to remove - + // good enough for now + let item_slice = core::slice::from_raw_parts_mut(item as *mut u8, self.item_size); + let count = self.count(); + + if count == 0 { + return; + } + + let tmp_item = crate::compat::malloc::malloc(self.item_size); + + if tmp_item.is_null() { + panic!("Out of memory"); + } + + for _ in 0..count { + if self.try_dequeue(tmp_item as *mut c_void) { + let tmp_slice = core::slice::from_raw_parts_mut(tmp_item, self.item_size); + if tmp_slice != item_slice { + self.enqueue(tmp_item as *mut c_void); + } + } + } + + crate::compat::malloc::free(tmp_item); + } + + unsafe fn count(&self) -> usize { if self.current_write >= self.current_read { self.current_write - self.current_read } else { - self.count - self.current_read + self.current_write + self.capacity - self.current_read + self.current_write } } } @@ -248,31 +324,34 @@ pub(crate) fn unlock_mutex(mutex: *mut c_void) -> i32 { }) } -pub(crate) fn create_queue(queue_len: c_int, item_size: c_int) -> *mut c_void { +pub(crate) fn create_queue(queue_len: c_int, item_size: c_int) -> *mut ConcurrentQueue { trace!("wifi_create_queue len={} size={}", queue_len, item_size,); - let queue = RawQueue::new(queue_len as usize, item_size as usize); - let ptr = unsafe { malloc(size_of_val(&queue) as u32) as *mut RawQueue }; + let queue = ConcurrentQueue::new(queue_len as usize, item_size as usize); + let ptr = unsafe { malloc(size_of_val(&queue) as u32) as *mut ConcurrentQueue }; unsafe { ptr.write(queue); } trace!("created queue @{:?}", ptr); - ptr.cast() + ptr } -pub(crate) fn delete_queue(queue: *mut c_void) { +pub(crate) fn delete_queue(queue: *mut ConcurrentQueue) { trace!("delete_queue {:?}", queue); - let queue: *mut RawQueue = queue.cast(); unsafe { - (*queue).free_storage(); - free(queue.cast()); + ptr::drop_in_place(queue); + crate::compat::malloc::free(queue.cast()); } } -pub(crate) fn send_queued(queue: *mut c_void, item: *mut c_void, block_time_tick: u32) -> i32 { +pub(crate) fn send_queued( + queue: *mut ConcurrentQueue, + item: *mut c_void, + block_time_tick: u32, +) -> i32 { trace!( "queue_send queue {:?} item {:x} block_time_tick {}", queue, @@ -280,11 +359,15 @@ pub(crate) fn send_queued(queue: *mut c_void, item: *mut c_void, block_time_tick block_time_tick ); - let queue: *mut RawQueue = queue.cast(); - critical_section::with(|_| unsafe { (*queue).enqueue(item) }) + let queue: *mut ConcurrentQueue = queue.cast(); + unsafe { (*queue).enqueue(item) } } -pub(crate) fn receive_queued(queue: *mut c_void, item: *mut c_void, block_time_tick: u32) -> i32 { +pub(crate) fn receive_queued( + queue: *mut ConcurrentQueue, + item: *mut c_void, + block_time_tick: u32, +) -> i32 { trace!( "queue_recv {:?} item {:?} block_time_tick {}", queue, @@ -296,10 +379,8 @@ pub(crate) fn receive_queued(queue: *mut c_void, item: *mut c_void, block_time_t let timeout = block_time_tick as u64; let start = crate::timer::get_systimer_count(); - let queue: *mut RawQueue = queue.cast(); - loop { - if critical_section::with(|_| unsafe { (*queue).try_dequeue(item) }) { + if unsafe { (*queue).try_dequeue(item) } { trace!("received"); return 1; } @@ -313,11 +394,11 @@ pub(crate) fn receive_queued(queue: *mut c_void, item: *mut c_void, block_time_t } } -pub(crate) fn number_of_messages_in_queue(queue: *const c_void) -> u32 { +pub(crate) fn number_of_messages_in_queue(queue: *const ConcurrentQueue) -> u32 { trace!("queue_msg_waiting {:?}", queue); - let queue: *const RawQueue = queue.cast(); - critical_section::with(|_| unsafe { (*queue).count() as u32 }) + let queue: *const ConcurrentQueue = queue.cast(); + unsafe { (*queue).count() as u32 } } /// Implementation of sleep() from newlib in esp-idf. diff --git a/esp-wifi/src/compat/mod.rs b/esp-wifi/src/compat/mod.rs index 25e6d6a1ccb..dc68d68e125 100644 --- a/esp-wifi/src/compat/mod.rs +++ b/esp-wifi/src/compat/mod.rs @@ -3,16 +3,13 @@ pub mod malloc; pub mod misc; pub mod timer_compat; -pub mod queue { - pub use heapless::spsc::Queue as SimpleQueue; -} - #[no_mangle] unsafe extern "C" fn _putchar(c: u8) { static mut BUFFER: [u8; 256] = [0u8; 256]; static mut IDX: usize = 0; - if c == 0 || c == b'\n' || IDX == BUFFER.len() - 1 { + let buffer = core::ptr::addr_of_mut!(BUFFER); + if c == 0 || c == b'\n' || IDX == (*buffer).len() - 1 { if c != 0 { BUFFER[IDX] = c; } else { diff --git a/esp-wifi/src/compat/timer_compat.rs b/esp-wifi/src/compat/timer_compat.rs index b44cade7625..c7f67ea4778 100644 --- a/esp-wifi/src/compat/timer_compat.rs +++ b/esp-wifi/src/compat/timer_compat.rs @@ -1,3 +1,8 @@ +use alloc::boxed::Box; +use core::cell::RefCell; + +use critical_section::Mutex; + use crate::binary::{ c_types, include::{esp_timer_create_args_t, ets_timer}, @@ -25,7 +30,8 @@ impl From<&esp_timer_create_args_t> for TimerCallback { } } -#[derive(Debug, Clone, Copy)] +#[repr(C)] +#[derive(Debug, Clone)] pub(crate) struct Timer { pub ets_timer: *mut ets_timer, pub started: u64, @@ -33,6 +39,8 @@ pub(crate) struct Timer { pub active: bool, pub periodic: bool, pub callback: TimerCallback, + + next: Option>, } impl Timer { @@ -40,10 +48,97 @@ impl Timer { self.ets_timer as usize } } -#[cfg(coex)] -pub(crate) static mut TIMERS: heapless::Vec = heapless::Vec::new(); -#[cfg(not(coex))] -pub(crate) static mut TIMERS: heapless::Vec = heapless::Vec::new(); + +pub(crate) struct TimerQueue { + head: Option>, +} + +impl TimerQueue { + const fn new() -> Self { + Self { head: None } + } + + fn find(&mut self, ets_timer: *mut ets_timer) -> Option<&mut Box> { + let mut current = self.head.as_mut(); + while let Some(timer) = current { + if timer.ets_timer == ets_timer { + return Some(timer); + } + current = timer.next.as_mut(); + } + + None + } + + pub(crate) unsafe fn find_next_due( + &mut self, + current_timestamp: u64, + ) -> Option<&mut Box> { + let mut current = self.head.as_mut(); + while let Some(timer) = current { + if timer.active + && crate::timer::time_diff(timer.started, current_timestamp) >= timer.timeout + { + return Some(timer); + } + current = timer.next.as_mut(); + } + + None + } + + fn remove(&mut self, ets_timer: *mut ets_timer) { + if let Some(head) = self.head.as_mut() { + if head.ets_timer == ets_timer { + self.head = head.next.take(); + return; + } + } + + let timer = self.find(ets_timer); + if let Some(to_remove) = timer { + let tail = to_remove.next.take(); + + let mut current = self.head.as_mut(); + let before = { + let mut found = None; + while let Some(before) = current { + if before.next.as_mut().unwrap().ets_timer == ets_timer { + found = Some(before); + break; + } + current = before.next.as_mut(); + } + found + }; + + if let Some(before) = before { + before.next = tail; + } + } + } + + fn push(&mut self, to_add: Box) -> Result<(), ()> { + if self.head.is_none() { + self.head = Some(to_add); + return Ok(()); + } + + let mut current = self.head.as_mut(); + while let Some(timer) = current { + if timer.next.is_none() { + timer.next = Some(to_add); + break; + } + current = timer.next.as_mut(); + } + Ok(()) + } +} + +unsafe impl Send for TimerQueue {} + +pub(crate) static TIMERS: Mutex> = Mutex::new(RefCell::new(TimerQueue::new())); pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bool) { compat_timer_arm_us(ets_timer, tmout * 1000, repeat); @@ -61,8 +156,8 @@ pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bo repeat ); - critical_section::with(|_| unsafe { - if let Some(timer) = TIMERS.iter_mut().find(|t| t.ets_timer == ets_timer) { + critical_section::with(|cs| { + if let Some(timer) = TIMERS.borrow_ref_mut(cs).find(ets_timer) { timer.started = systick; timer.timeout = ticks; timer.active = true; @@ -73,9 +168,10 @@ pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bo }) } -pub(crate) fn compat_timer_disarm(ets_timer: *mut ets_timer) { - critical_section::with(|_| unsafe { - if let Some(timer) = TIMERS.iter_mut().find(|t| t.ets_timer == ets_timer) { +pub fn compat_timer_disarm(ets_timer: *mut ets_timer) { + trace!("timer disarm"); + critical_section::with(|cs| { + if let Some(timer) = TIMERS.borrow_ref_mut(cs).find(ets_timer) { trace!("timer_disarm {:x}", timer.id()); timer.active = false; } else { @@ -84,20 +180,20 @@ pub(crate) fn compat_timer_disarm(ets_timer: *mut ets_timer) { }) } -pub(crate) fn compat_timer_done(ets_timer: *mut ets_timer) { - critical_section::with(|_| unsafe { - if let Some((idx, timer)) = TIMERS - .iter_mut() - .enumerate() - .find(|(_, t)| t.ets_timer == ets_timer) - { +pub fn compat_timer_done(ets_timer: *mut ets_timer) { + trace!("timer done"); + critical_section::with(|cs| { + let mut timers = TIMERS.borrow_ref_mut(cs); + if let Some(timer) = timers.find(ets_timer) { trace!("timer_done {:x}", timer.id()); timer.active = false; - (*ets_timer).priv_ = core::ptr::null_mut(); - (*ets_timer).expire = 0; + unsafe { + (*ets_timer).priv_ = core::ptr::null_mut(); + (*ets_timer).expire = 0; + } - TIMERS.swap_remove(idx); + timers.remove(ets_timer); } else { trace!("timer_done {:x} not found", ets_timer as usize); } @@ -115,9 +211,9 @@ pub(crate) fn compat_timer_setfn( pfunction, parg ); - - let set = critical_section::with(|_| unsafe { - if let Some(timer) = TIMERS.iter_mut().find(|t| t.ets_timer == ets_timer) { + let set = critical_section::with(|cs| unsafe { + let mut timers = TIMERS.borrow_ref_mut(cs); + if let Some(timer) = timers.find(ets_timer) { timer.callback = TimerCallback::new(pfunction, parg); timer.active = false; @@ -129,16 +225,18 @@ pub(crate) fn compat_timer_setfn( (*ets_timer).period = 0; (*ets_timer).func = None; (*ets_timer).priv_ = core::ptr::null_mut(); - TIMERS - .push(Timer { - ets_timer, - started: 0, - timeout: 0, - active: false, - periodic: false, - callback: TimerCallback::new(pfunction, parg), - }) - .is_ok() + + let timer = + crate::compat::malloc::calloc(1, core::mem::size_of::()) as *mut Timer; + (*timer).next = None; + (*timer).ets_timer = ets_timer; + (*timer).started = 0; + (*timer).timeout = 0; + (*timer).active = false; + (*timer).periodic = false; + (*timer).callback = TimerCallback::new(pfunction, parg); + + timers.push(Box::from_raw(timer)).is_ok() } }); diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index 5099fe78cd4..ecdbd6886a5 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -9,6 +9,7 @@ //! //! For more information see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html +use alloc::{boxed::Box, collections::vec_deque::VecDeque}; use core::{cell::RefCell, fmt::Debug, marker::PhantomData}; use critical_section::Mutex; @@ -17,20 +18,23 @@ use portable_atomic::{AtomicBool, AtomicU8, Ordering}; use crate::{ binary::include::*, - compat::queue::SimpleQueue, hal::peripheral::{Peripheral, PeripheralRef}, wifi::{Protocol, RxControlInfo}, EspWifiInitialization, }; +const RECEIVE_QUEUE_SIZE: usize = 10; + /// Maximum payload length pub const ESP_NOW_MAX_DATA_LEN: usize = 250; /// Broadcast address pub const BROADCAST_ADDRESS: [u8; 6] = [0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8]; -static RECEIVE_QUEUE: Mutex>> = - Mutex::new(RefCell::new(SimpleQueue::new())); +// Stores received packets until dequeued by the user +static RECEIVE_QUEUE: Mutex>> = + Mutex::new(RefCell::new(VecDeque::new())); + /// This atomic behaves like a guard, so we need strict memory ordering when /// operating it. /// @@ -231,30 +235,30 @@ pub struct ReceiveInfo { /// Stores information about the received data, including the packet content and /// associated information. -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Clone)] pub struct ReceivedData { - /// The length of the received data. - pub len: u8, - - /// The buffer containing the received data. - pub data: [u8; 256], - - /// Information about a received packet. + data: Box<[u8]>, pub info: ReceiveInfo, } impl ReceivedData { /// Returns the received payload. - pub fn get_data(&self) -> &[u8] { - &self.data[..self.len as usize] + pub fn data(&self) -> &[u8] { + &self.data + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for ReceivedData { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "ReceivedData {}, Info {}", &self.data[..], &self.info,) } } impl Debug for ReceivedData { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("ReceivedData") - .field("data", &self.get_data()) + .field("data", &self.data()) .field("info", &self.info) .finish() } @@ -277,7 +281,7 @@ pub struct EspNowManager<'d> { _rc: EspNowRc<'d>, } -impl<'d> EspNowManager<'d> { +impl EspNowManager<'_> { /// Set the wifi protocol. /// /// This will set the wifi protocol to the desired protocol @@ -476,7 +480,7 @@ pub struct EspNowSender<'d> { _rc: EspNowRc<'d>, } -impl<'d> EspNowSender<'d> { +impl EspNowSender<'_> { /// Send data to peer /// /// The peer needs to be added to the peer list first. @@ -506,7 +510,7 @@ impl<'d> EspNowSender<'d> { #[must_use] pub struct SendWaiter<'s>(PhantomData<&'s mut EspNowSender<'s>>); -impl<'s> SendWaiter<'s> { +impl SendWaiter<'_> { /// Wait for the previous sending to complete, i.e. the send callback is /// invoked with status of the sending. pub fn wait(self) -> Result<(), EspNowError> { @@ -523,7 +527,7 @@ impl<'s> SendWaiter<'s> { } } -impl<'s> Drop for SendWaiter<'s> { +impl Drop for SendWaiter<'_> { /// wait for the send to complete to prevent the lock on `EspNowSender` get /// unlocked before a callback is invoked. fn drop(&mut self) { @@ -537,12 +541,12 @@ pub struct EspNowReceiver<'d> { _rc: EspNowRc<'d>, } -impl<'d> EspNowReceiver<'d> { +impl EspNowReceiver<'_> { /// Receives data from the ESP-NOW queue. pub fn receive(&self) -> Option { critical_section::with(|cs| { let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); - queue.dequeue() + queue.pop_front() }) } } @@ -554,7 +558,7 @@ struct EspNowRc<'d> { inner: PhantomData>, } -impl<'d> EspNowRc<'d> { +impl EspNowRc<'_> { fn new() -> Result { static ESP_NOW_RC: AtomicU8 = AtomicU8::new(0); // The reference counter is not 0, which means there is another instance of @@ -570,7 +574,7 @@ impl<'d> EspNowRc<'d> { } } -impl<'d> Clone for EspNowRc<'d> { +impl Clone for EspNowRc<'_> { fn clone(&self) -> Self { self.rc.fetch_add(1, Ordering::Release); Self { @@ -580,7 +584,7 @@ impl<'d> Clone for EspNowRc<'d> { } } -impl<'d> Drop for EspNowRc<'d> { +impl Drop for EspNowRc<'_> { fn drop(&mut self) { if self.rc.fetch_sub(1, Ordering::AcqRel) == 1 { unsafe { @@ -834,18 +838,13 @@ unsafe extern "C" fn rcv_cb( let slice = core::slice::from_raw_parts(data, data_len as usize); critical_section::with(|cs| { let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); - let mut data = [0u8; 256]; - data[..slice.len()].copy_from_slice(slice); + let data = Box::from(slice); - if queue.is_full() { - queue.dequeue(); + if queue.len() >= RECEIVE_QUEUE_SIZE { + queue.pop_front(); } - unwrap!(queue.enqueue(ReceivedData { - len: slice.len() as u8, - data, - info, - })); + queue.push_back(ReceivedData { data, info }); #[cfg(feature = "async")] asynch::ESP_NOW_RX_WAKER.wake(); @@ -866,7 +865,7 @@ mod asynch { pub(super) static ESP_NOW_TX_WAKER: AtomicWaker = AtomicWaker::new(); pub(super) static ESP_NOW_RX_WAKER: AtomicWaker = AtomicWaker::new(); - impl<'d> EspNowReceiver<'d> { + impl EspNowReceiver<'_> { /// This function takes mutable reference to self because the /// implementation of `ReceiveFuture` is not logically thread /// safe. @@ -875,7 +874,7 @@ mod asynch { } } - impl<'d> EspNowSender<'d> { + impl EspNowSender<'_> { /// Sends data asynchronously to a peer (using its MAC) using ESP-NOW. pub fn send_async<'s, 'r>( &'s mut self, @@ -891,7 +890,7 @@ mod asynch { } } - impl<'d> EspNow<'d> { + impl EspNow<'_> { /// This function takes mutable reference to self because the /// implementation of `ReceiveFuture` is not logically thread /// safe. @@ -920,7 +919,7 @@ mod asynch { sent: bool, } - impl<'s, 'r> core::future::Future for SendFuture<'s, 'r> { + impl core::future::Future for SendFuture<'_, '_> { type Output = Result<(), EspNowError>; fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -953,7 +952,7 @@ mod asynch { #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct ReceiveFuture<'r>(PhantomData<&'r mut EspNowReceiver<'r>>); - impl<'r> core::future::Future for ReceiveFuture<'r> { + impl core::future::Future for ReceiveFuture<'_> { type Output = ReceivedData; fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -961,7 +960,7 @@ mod asynch { if let Some(data) = critical_section::with(|cs| { let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs); - queue.dequeue() + queue.pop_front() }) { Poll::Ready(data) } else { diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 55d60a9c3fa..7d415259004 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -93,12 +93,7 @@ extern crate alloc; // MUST be the first module mod fmt; -use common_adapter::{ - chip_specific::phy_mem_init, - deinit_radio_clock_control, - init_radio_clock_control, - RADIO_CLOCKS, -}; +use common_adapter::chip_specific::phy_mem_init; use esp_config::*; use esp_hal as hal; #[cfg(not(feature = "esp32"))] @@ -118,7 +113,6 @@ use crate::{ wifi::WifiError, }; use crate::{ - common_adapter::init_rng, tasks::init_tasks, timer::{setup_timer_isr, shutdown_timer_isr}, }; @@ -389,8 +383,8 @@ impl EspWifiTimerSource for TimeBase { pub fn init( init_for: EspWifiInitFor, timer: impl EspWifiTimerSource, - rng: hal::rng::Rng, - radio_clocks: hal::peripherals::RADIO_CLK, + _rng: hal::rng::Rng, + _radio_clocks: hal::peripherals::RADIO_CLK, ) -> Result { // A minimum clock of 80MHz is required to operate WiFi module. const MIN_CLOCK: u32 = 80; @@ -402,8 +396,6 @@ pub fn init( info!("esp-wifi configuration {:?}", crate::CONFIG); crate::common_adapter::chip_specific::enable_wifi_power_domain(); phy_mem_init(); - init_radio_clock_control(radio_clocks); - init_rng(rng); init_tasks(); setup_timer_isr(timer.timer())?; @@ -501,8 +493,7 @@ pub unsafe fn deinit_unchecked( let timer = critical_section::with(|cs| crate::timer::TIMER.borrow_ref_mut(cs).take()) .ok_or(InitializationError::TimerUnavailable)?; - let radio_clocks = - deinit_radio_clock_control().ok_or(InitializationError::RadioClockUnavailable)?; + let radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; Ok((timer, radio_clocks)) } @@ -548,7 +539,6 @@ pub fn wifi_set_log_verbose() { } fn init_clocks() { - unsafe { - unwrap!(RADIO_CLOCKS.as_mut()).init_clocks(); - } + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.init_clocks(); } diff --git a/esp-wifi/src/preempt/mod.rs b/esp-wifi/src/preempt/mod.rs index edf76b6caae..18e2ffe7e68 100644 --- a/esp-wifi/src/preempt/mod.rs +++ b/esp-wifi/src/preempt/mod.rs @@ -10,21 +10,27 @@ use esp_wifi_sys::include::malloc; use crate::{compat::malloc::free, hal::trapframe::TrapFrame, memory_fence::memory_fence}; -static mut CTX_NOW: Mutex> = Mutex::new(RefCell::new(core::ptr::null_mut())); +#[repr(transparent)] +struct ContextWrapper(*mut Context); + +unsafe impl Send for ContextWrapper {} + +static CTX_NOW: Mutex> = + Mutex::new(RefCell::new(ContextWrapper(core::ptr::null_mut()))); static mut SCHEDULED_TASK_TO_DELETE: *mut Context = core::ptr::null_mut(); pub(crate) fn allocate_main_task() -> *mut Context { critical_section::with(|cs| unsafe { let mut ctx_now = CTX_NOW.borrow_ref_mut(cs); - if !(*ctx_now).is_null() { + if !ctx_now.0.is_null() { panic!("Tried to allocate main task multiple times"); } let ptr = malloc(size_of::() as u32) as *mut Context; core::ptr::write(ptr, Context::new()); (*ptr).next = ptr; - *ctx_now = ptr; + ctx_now.0 = ptr; ptr }) } @@ -32,14 +38,14 @@ pub(crate) fn allocate_main_task() -> *mut Context { fn allocate_task() -> *mut Context { critical_section::with(|cs| unsafe { let mut ctx_now = CTX_NOW.borrow_ref_mut(cs); - if (*ctx_now).is_null() { + if ctx_now.0.is_null() { panic!("Called `allocate_task` before allocating main task"); } let ptr = malloc(size_of::() as u32) as *mut Context; core::ptr::write(ptr, Context::new()); - (*ptr).next = (**ctx_now).next; - (**ctx_now).next = ptr; + (*ptr).next = (*ctx_now.0).next; + (*ctx_now.0).next = ptr; ptr }) } @@ -47,7 +53,7 @@ fn allocate_task() -> *mut Context { fn next_task() { critical_section::with(|cs| unsafe { let mut ctx_now = CTX_NOW.borrow_ref_mut(cs); - *ctx_now = (**ctx_now).next; + ctx_now.0 = (*ctx_now.0).next; }); } @@ -56,7 +62,7 @@ fn next_task() { /// This will also free the memory (stack and context) allocated for it. pub(crate) fn delete_task(task: *mut Context) { critical_section::with(|cs| unsafe { - let mut ptr = *CTX_NOW.borrow_ref_mut(cs); + let mut ptr = CTX_NOW.borrow_ref_mut(cs).0; let initial = ptr; loop { if (*ptr).next == task { @@ -81,7 +87,7 @@ pub(crate) fn delete_task(task: *mut Context) { pub(crate) fn delete_all_tasks() { critical_section::with(|cs| unsafe { let mut ctx_now_ref = CTX_NOW.borrow_ref_mut(cs); - let current_task = *ctx_now_ref; + let current_task = ctx_now_ref.0; if current_task.is_null() { return; @@ -102,14 +108,14 @@ pub(crate) fn delete_all_tasks() { task_to_delete = next_task; } - *ctx_now_ref = core::ptr::null_mut(); + ctx_now_ref.0 = core::ptr::null_mut(); memory_fence(); }); } pub(crate) fn current_task() -> *mut Context { - critical_section::with(|cs| unsafe { *CTX_NOW.borrow_ref(cs) }) + critical_section::with(|cs| CTX_NOW.borrow_ref(cs).0) } pub(crate) fn schedule_task_deletion(task: *mut Context) { diff --git a/esp-wifi/src/tasks.rs b/esp-wifi/src/tasks.rs index 18040173f79..21df825955d 100644 --- a/esp-wifi/src/tasks.rs +++ b/esp-wifi/src/tasks.rs @@ -1,6 +1,5 @@ use crate::{ - compat::{queue::SimpleQueue, timer_compat::TIMERS}, - memory_fence::memory_fence, + compat::timer_compat::TIMERS, preempt::arch_specific::task_create, timer::{get_systimer_count, yield_task}, }; @@ -18,34 +17,31 @@ pub(crate) fn init_tasks() { /// events. pub(crate) extern "C" fn timer_task(_param: *mut esp_wifi_sys::c_types::c_void) { loop { - let mut to_run = SimpleQueue::<_, 20>::new(); - let current_timestamp = get_systimer_count(); - critical_section::with(|_| unsafe { - memory_fence(); - for timer in TIMERS.iter_mut() { - if timer.active - && crate::timer::time_diff(timer.started, current_timestamp) >= timer.timeout - { - trace!("timer is due.... {:x}", timer.id()); + let to_run = critical_section::with(|cs| unsafe { + let mut timers = TIMERS.borrow_ref_mut(cs); + let to_run = timers.find_next_due(current_timestamp); + + if let Some(to_run) = to_run { + to_run.active = to_run.periodic; - if to_run.enqueue(timer.callback).is_err() { - break; - } + if to_run.periodic { + to_run.started = current_timestamp; + } - timer.active = timer.periodic; - }; + Some(to_run.callback) + } else { + None } - memory_fence(); }); - // run the due timer callbacks NOT in an interrupt free context - while let Some(callback) = to_run.dequeue() { + // run the due timer callback NOT in an interrupt free context + if let Some(to_run) = to_run { trace!("trigger timer...."); - callback.call(); + to_run.call(); trace!("timer callback called"); + } else { + yield_task(); } - - yield_task(); } } diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index 16d92c0d2bb..c307f6c61bd 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -3,6 +3,7 @@ pub(crate) mod os_adapter; pub(crate) mod state; +use alloc::collections::vec_deque::VecDeque; use core::{ cell::{RefCell, RefMut}, fmt::Debug, @@ -81,65 +82,62 @@ pub mod utils; #[cfg(coex)] use include::{coex_adapter_funcs_t, coex_pre_init, esp_coex_adapter_register}; -use crate::{ - binary::{ - c_types, - include::{ - self, - __BindgenBitfieldUnit, - esp_err_t, - esp_interface_t_ESP_IF_WIFI_AP, - esp_interface_t_ESP_IF_WIFI_STA, - esp_supplicant_init, - esp_wifi_connect, - esp_wifi_disconnect, - esp_wifi_get_mode, - esp_wifi_init_internal, - esp_wifi_internal_free_rx_buffer, - esp_wifi_internal_reg_rxcb, - esp_wifi_internal_tx, - esp_wifi_scan_start, - esp_wifi_set_config, - esp_wifi_set_country, - esp_wifi_set_mode, - esp_wifi_set_protocol, - esp_wifi_set_ps, - esp_wifi_set_tx_done_cb, - esp_wifi_start, - esp_wifi_stop, - g_wifi_default_wpa_crypto_funcs, - wifi_active_scan_time_t, - wifi_ap_config_t, - wifi_auth_mode_t, - wifi_cipher_type_t_WIFI_CIPHER_TYPE_CCMP, - wifi_config_t, - wifi_country_policy_t_WIFI_COUNTRY_POLICY_MANUAL, - wifi_country_t, - wifi_init_config_t, - wifi_interface_t, - wifi_interface_t_WIFI_IF_AP, - wifi_interface_t_WIFI_IF_STA, - wifi_mode_t, - wifi_mode_t_WIFI_MODE_AP, - wifi_mode_t_WIFI_MODE_APSTA, - wifi_mode_t_WIFI_MODE_NULL, - wifi_mode_t_WIFI_MODE_STA, - wifi_osi_funcs_t, - wifi_pmf_config_t, - wifi_scan_config_t, - wifi_scan_threshold_t, - wifi_scan_time_t, - wifi_scan_type_t_WIFI_SCAN_TYPE_ACTIVE, - wifi_scan_type_t_WIFI_SCAN_TYPE_PASSIVE, - wifi_sort_method_t_WIFI_CONNECT_AP_BY_SIGNAL, - wifi_sta_config_t, - wpa_crypto_funcs_t, - ESP_WIFI_OS_ADAPTER_MAGIC, - ESP_WIFI_OS_ADAPTER_VERSION, - WIFI_INIT_CONFIG_MAGIC, - }, +use crate::binary::{ + c_types, + include::{ + self, + __BindgenBitfieldUnit, + esp_err_t, + esp_interface_t_ESP_IF_WIFI_AP, + esp_interface_t_ESP_IF_WIFI_STA, + esp_supplicant_init, + esp_wifi_connect, + esp_wifi_disconnect, + esp_wifi_get_mode, + esp_wifi_init_internal, + esp_wifi_internal_free_rx_buffer, + esp_wifi_internal_reg_rxcb, + esp_wifi_internal_tx, + esp_wifi_scan_start, + esp_wifi_set_config, + esp_wifi_set_country, + esp_wifi_set_mode, + esp_wifi_set_protocol, + esp_wifi_set_ps, + esp_wifi_set_tx_done_cb, + esp_wifi_start, + esp_wifi_stop, + g_wifi_default_wpa_crypto_funcs, + wifi_active_scan_time_t, + wifi_ap_config_t, + wifi_auth_mode_t, + wifi_cipher_type_t_WIFI_CIPHER_TYPE_CCMP, + wifi_config_t, + wifi_country_policy_t_WIFI_COUNTRY_POLICY_MANUAL, + wifi_country_t, + wifi_init_config_t, + wifi_interface_t, + wifi_interface_t_WIFI_IF_AP, + wifi_interface_t_WIFI_IF_STA, + wifi_mode_t, + wifi_mode_t_WIFI_MODE_AP, + wifi_mode_t_WIFI_MODE_APSTA, + wifi_mode_t_WIFI_MODE_NULL, + wifi_mode_t_WIFI_MODE_STA, + wifi_osi_funcs_t, + wifi_pmf_config_t, + wifi_scan_config_t, + wifi_scan_threshold_t, + wifi_scan_time_t, + wifi_scan_type_t_WIFI_SCAN_TYPE_ACTIVE, + wifi_scan_type_t_WIFI_SCAN_TYPE_PASSIVE, + wifi_sort_method_t_WIFI_CONNECT_AP_BY_SIGNAL, + wifi_sta_config_t, + wpa_crypto_funcs_t, + ESP_WIFI_OS_ADAPTER_MAGIC, + ESP_WIFI_OS_ADAPTER_VERSION, + WIFI_INIT_CONFIG_MAGIC, }, - compat::queue::SimpleQueue, }; /// Supported Wi-Fi authentication methods. @@ -1031,13 +1029,11 @@ const DATA_FRAME_SIZE: usize = MTU + ETHERNET_FRAME_HEADER_SIZE; const RX_QUEUE_SIZE: usize = crate::CONFIG.rx_queue_size; const TX_QUEUE_SIZE: usize = crate::CONFIG.tx_queue_size; -pub(crate) static DATA_QUEUE_RX_AP: Mutex< - RefCell>, -> = Mutex::new(RefCell::new(SimpleQueue::new())); +pub(crate) static DATA_QUEUE_RX_AP: Mutex>> = + Mutex::new(RefCell::new(VecDeque::new())); -pub(crate) static DATA_QUEUE_RX_STA: Mutex< - RefCell>, -> = Mutex::new(RefCell::new(SimpleQueue::new())); +pub(crate) static DATA_QUEUE_RX_STA: Mutex>> = + Mutex::new(RefCell::new(VecDeque::new())); /// Common errors. #[derive(Debug, Clone, Copy)] @@ -1607,16 +1603,21 @@ unsafe extern "C" fn recv_cb_sta( // which will try to lock an internal mutex. If the mutex is already taken, // the function will try to trigger a context switch, which will fail if we // are in a critical section. - match critical_section::with(|cs| DATA_QUEUE_RX_STA.borrow_ref_mut(cs).enqueue(packet)) { - Ok(_) => { - #[cfg(feature = "embassy-net")] - embassy::STA_RECEIVE_WAKER.wake(); - include::ESP_OK as esp_err_t - } - Err(_) => { - debug!("RX QUEUE FULL"); - include::ESP_ERR_NO_MEM as esp_err_t + if critical_section::with(|cs| { + let mut queue = DATA_QUEUE_RX_STA.borrow_ref_mut(cs); + if queue.len() < RX_QUEUE_SIZE { + queue.push_back(packet); + true + } else { + false } + }) { + #[cfg(feature = "embassy-net")] + embassy::STA_RECEIVE_WAKER.wake(); + include::ESP_OK as esp_err_t + } else { + debug!("RX QUEUE FULL"); + include::ESP_ERR_NO_MEM as esp_err_t } } @@ -1632,16 +1633,21 @@ unsafe extern "C" fn recv_cb_ap( // which will try to lock an internal mutex. If the mutex is already taken, // the function will try to trigger a context switch, which will fail if we // are in a critical section. - match critical_section::with(|cs| DATA_QUEUE_RX_AP.borrow_ref_mut(cs).enqueue(packet)) { - Ok(_) => { - #[cfg(feature = "embassy-net")] - embassy::AP_RECEIVE_WAKER.wake(); - include::ESP_OK as esp_err_t - } - Err(_) => { - debug!("RX QUEUE FULL"); - include::ESP_ERR_NO_MEM as esp_err_t + if critical_section::with(|cs| { + let mut queue = DATA_QUEUE_RX_AP.borrow_ref_mut(cs); + if queue.len() < RX_QUEUE_SIZE { + queue.push_back(packet); + true + } else { + false } + }) { + #[cfg(feature = "embassy-net")] + embassy::AP_RECEIVE_WAKER.wake(); + include::ESP_OK as esp_err_t + } else { + debug!("RX QUEUE FULL"); + include::ESP_ERR_NO_MEM as esp_err_t } } @@ -1984,10 +1990,7 @@ mod sealed { fn wrap_config(config: Self::Config) -> Configuration; - fn data_queue_rx( - self, - cs: CriticalSection, - ) -> RefMut<'_, SimpleQueue>; + fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque>; fn can_send(self) -> bool { WIFI_TX_INFLIGHT.load(Ordering::SeqCst) < TX_QUEUE_SIZE @@ -2053,10 +2056,7 @@ mod sealed { Configuration::Client(config) } - fn data_queue_rx( - self, - cs: CriticalSection, - ) -> RefMut<'_, SimpleQueue> { + fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque> { DATA_QUEUE_RX_STA.borrow_ref_mut(cs) } @@ -2095,10 +2095,7 @@ mod sealed { Configuration::AccessPoint(config) } - fn data_queue_rx( - self, - cs: CriticalSection, - ) -> RefMut<'_, SimpleQueue> { + fn data_queue_rx(self, cs: CriticalSection) -> RefMut<'_, VecDeque> { DATA_QUEUE_RX_AP.borrow_ref_mut(cs) } @@ -2714,7 +2711,7 @@ impl WifiRxToken { let mut queue = self.mode.data_queue_rx(cs); unwrap!( - queue.dequeue(), + queue.pop_front(), "unreachable: transmit()/receive() ensures there is a packet to process" ) }); diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index cbed1db74cb..c059c8c1a5f 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -14,7 +14,6 @@ use enumset::EnumSet; use super::WifiEvent; use crate::{ - common_adapter::RADIO_CLOCKS, compat::{ common::{ create_queue, @@ -27,6 +26,7 @@ use crate::{ str_from_c, thread_sem_get, unlock_mutex, + ConcurrentQueue, }, malloc::calloc, }, @@ -35,7 +35,7 @@ use crate::{ timer::yield_task, }; -static mut QUEUE_HANDLE: *mut crate::binary::c_types::c_void = core::ptr::null_mut(); +static mut QUEUE_HANDLE: *mut ConcurrentQueue = core::ptr::null_mut(); // useful for waiting for events - clear and wait for the event bit to be set // again @@ -391,7 +391,7 @@ pub unsafe extern "C" fn queue_create( (3, 8) }; - create_queue(queue_len as i32, item_size as i32) + create_queue(queue_len as i32, item_size as i32).cast() } /// ************************************************************************** @@ -408,7 +408,7 @@ pub unsafe extern "C" fn queue_create( /// /// ************************************************************************* pub unsafe extern "C" fn queue_delete(queue: *mut crate::binary::c_types::c_void) { - delete_queue(queue); + delete_queue(queue.cast()); } /// ************************************************************************** @@ -431,7 +431,7 @@ pub unsafe extern "C" fn queue_send( item: *mut crate::binary::c_types::c_void, block_time_tick: u32, ) -> i32 { - send_queued(queue, item, block_time_tick) + send_queued(queue.cast(), item, block_time_tick) } /// ************************************************************************** @@ -526,7 +526,7 @@ pub unsafe extern "C" fn queue_recv( item: *mut crate::binary::c_types::c_void, block_time_tick: u32, ) -> i32 { - receive_queued(queue, item, block_time_tick) + receive_queued(queue.cast(), item, block_time_tick) } /// ************************************************************************** @@ -543,7 +543,7 @@ pub unsafe extern "C" fn queue_recv( /// /// ************************************************************************* pub unsafe extern "C" fn queue_msg_waiting(queue: *mut crate::binary::c_types::c_void) -> u32 { - number_of_messages_in_queue(queue) + number_of_messages_in_queue(queue.cast()) } /// ************************************************************************** @@ -1040,7 +1040,10 @@ pub unsafe extern "C" fn phy_update_country_info( /// ************************************************************************* pub unsafe extern "C" fn wifi_reset_mac() { trace!("wifi_reset_mac"); - unwrap!(RADIO_CLOCKS.as_mut()).reset_mac(); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.reset_mac(); } /// ************************************************************************** @@ -1058,7 +1061,10 @@ pub unsafe extern "C" fn wifi_reset_mac() { /// ************************************************************************* pub unsafe extern "C" fn wifi_clock_enable() { trace!("wifi_clock_enable"); - unwrap!(RADIO_CLOCKS.as_mut()).enable(RadioPeripherals::Wifi); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.enable(RadioPeripherals::Wifi); } /// ************************************************************************** @@ -1076,7 +1082,10 @@ pub unsafe extern "C" fn wifi_clock_enable() { /// ************************************************************************* pub unsafe extern "C" fn wifi_clock_disable() { trace!("wifi_clock_disable"); - unwrap!(RADIO_CLOCKS.as_mut()).disable(RadioPeripherals::Wifi); + // stealing RADIO_CLK is safe since it is passed (as mutable reference or by + // value) into `init` + let mut radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + radio_clocks.disable(RadioPeripherals::Wifi); } /// ************************************************************************** @@ -1394,18 +1403,8 @@ pub unsafe extern "C" fn nvs_erase_key( /// ************************************************************************* pub unsafe extern "C" fn get_random(buf: *mut u8, len: usize) -> crate::binary::c_types::c_int { trace!("get_random"); - if let Some(ref mut rng) = crate::common_adapter::RANDOM_GENERATOR { - let buffer = unsafe { core::slice::from_raw_parts_mut(buf, len) }; - - for chunk in buffer.chunks_mut(4) { - let bytes = rng.random().to_le_bytes(); - chunk.copy_from_slice(&bytes[..chunk.len()]); - } - - 0 - } else { - -1 - } + crate::common_adapter::esp_fill_random(buf, len as u32); + 0 } /// ************************************************************************** diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index c8bf8e4e078..270a68a7a66 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -117,7 +117,7 @@ async fn broadcaster(sender: &'static Mutex> async fn listener(manager: &'static EspNowManager<'static>, mut receiver: EspNowReceiver<'static>) { loop { let r = receiver.receive_async().await; - println!("Received {:?}", r.get_data()); + println!("Received {:?}", r.data()); if r.info.dst_address == BROADCAST_ADDRESS { if !manager.peer_exists(&r.info.src_address) { manager From f9c7d06a6e06cdbfc83cc5518b2b0676d2323fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 31 Oct 2024 15:16:39 +0100 Subject: [PATCH 12/67] Disable i2s test (#2439) --- hil-test/tests/i2s.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 1ce7176d631..b6d785879ed 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -3,8 +3,9 @@ //! This test uses I2S TX to transmit known data to I2S RX (forced to slave mode //! with loopback mode enabled). -//% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 //% FEATURES: generic-queue +// FIXME: re-enable on ESP32 when it no longer fails spuriously #![no_std] #![no_main] From 7d717c6acf54f1164c54501278bdea34d5f41b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 31 Oct 2024 16:00:36 +0100 Subject: [PATCH 13/67] Fix UART erratum on ESP32 (#2441) --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/uart.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b87fc35238f..4a2ae03bff5 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -41,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix conflict between `RtcClock::get_xtal_freq` and `Rtc::disable_rom_message_printing` (#2360) - Fixed an issue where interrupts enabled before `esp_hal::init` were disabled. This issue caused the executor created by `#[esp_hal_embassy::main]` to behave incorrectly in multi-core applications. (#2377) - Fixed `TWAI::transmit_async`: bus-off state is not reached when CANH and CANL are shorted. (#2421) +- ESP32: added UART-specific workaround for https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html (#2441) ### Removed diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index dacfa36d481..f7418dc721a 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -716,7 +716,17 @@ where while self.rx_fifo_count() == 0 { // Block until we received at least one byte } - *byte = fifo.read().rxfifo_rd_byte().bits(); + + cfg_if::cfg_if! { + if #[cfg(esp32)] { + // https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html + xtensa_lx::interrupt::free(|_| { + *byte = fifo.read().rxfifo_rd_byte().bits(); + }); + } else { + *byte = fifo.read().rxfifo_rd_byte().bits(); + } + } } Ok(()) From a5c4aa1cea9463bf56da50752b7e6b965f50ccbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 31 Oct 2024 17:18:44 +0100 Subject: [PATCH 14/67] Tweak interrupt API (#2442) * Tweak interrupt API * Constrain SPI interrupt handling to Blocking mode --- esp-hal/CHANGELOG.md | 2 + esp-hal/src/dma/mod.rs | 12 +-- esp-hal/src/i2s.rs | 20 ++--- esp-hal/src/parl_io.rs | 24 +++--- esp-hal/src/spi/master.rs | 166 ++++++++++++++++---------------------- 5 files changed, 96 insertions(+), 128 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 4a2ae03bff5..479f60b9557 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Peripheral type erasure for UART (#2381) - Changed listening for UART events (#2406) - Circular DMA transfers now correctly error, `available` returns `Result` now (#2409) +- Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442) +- SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) ### Fixed diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index bb3e6577352..0e80eefddb8 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -2129,8 +2129,8 @@ where } /// Listen for the given interrupts - pub fn listen(&mut self, interrupts: EnumSet) { - for interrupt in interrupts { + pub fn listen(&mut self, interrupts: impl Into>) { + for interrupt in interrupts.into() { match interrupt { DmaInterrupt::RxDone => self.rx.listen_in(DmaRxInterrupt::Done), DmaInterrupt::TxDone => self.tx.listen_out(DmaTxInterrupt::Done), @@ -2139,8 +2139,8 @@ where } /// Unlisten the given interrupts - pub fn unlisten(&mut self, interrupts: EnumSet) { - for interrupt in interrupts { + pub fn unlisten(&mut self, interrupts: impl Into>) { + for interrupt in interrupts.into() { match interrupt { DmaInterrupt::RxDone => self.rx.unlisten_in(DmaRxInterrupt::Done), DmaInterrupt::TxDone => self.tx.unlisten_out(DmaTxInterrupt::Done), @@ -2161,8 +2161,8 @@ where } /// Resets asserted interrupts - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - for interrupt in interrupts { + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { + for interrupt in interrupts.into() { match interrupt { DmaInterrupt::RxDone => self.rx.clear_in(DmaRxInterrupt::Done), DmaInterrupt::TxDone => self.tx.clear_out(DmaTxInterrupt::Done), diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index db0aaf02790..fcbd7eab4a7 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -328,15 +328,15 @@ where } /// Listen for the given interrupts - pub fn listen(&mut self, interrupts: EnumSet) { + pub fn listen(&mut self, interrupts: impl Into>) { // tx.i2s and rx.i2s is the same, we could use either one - self.i2s_tx.i2s.listen(interrupts); + self.i2s_tx.i2s.enable_listen(interrupts.into(), true); } /// Unlisten the given interrupts - pub fn unlisten(&mut self, interrupts: EnumSet) { + pub fn unlisten(&mut self, interrupts: impl Into>) { // tx.i2s and rx.i2s is the same, we could use either one - self.i2s_tx.i2s.unlisten(interrupts); + self.i2s_tx.i2s.enable_listen(interrupts.into(), false); } /// Gets asserted interrupts @@ -346,9 +346,9 @@ where } /// Resets asserted interrupts - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { // tx.i2s and rx.i2s is the same, we could use either one - self.i2s_tx.i2s.clear_interrupts(interrupts); + self.i2s_tx.i2s.clear_interrupts(interrupts.into()); } } @@ -914,14 +914,6 @@ mod private { }); } - fn listen(&self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), true); - } - - fn unlisten(&self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), false); - } - fn interrupts(&self) -> EnumSet { let mut res = EnumSet::new(); let reg_block = self.register_block(); diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 4e698a5a259..489786d92d6 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -1125,13 +1125,13 @@ impl<'d> ParlIoTxOnly<'d, Blocking> { } /// Listen for the given interrupts - pub fn listen(&mut self, interrupts: EnumSet) { - internal_listen(interrupts, true); + pub fn listen(&mut self, interrupts: impl Into>) { + internal_listen(interrupts.into(), true); } /// Unlisten the given interrupts - pub fn unlisten(&mut self, interrupts: EnumSet) { - internal_listen(interrupts, false); + pub fn unlisten(&mut self, interrupts: impl Into>) { + internal_listen(interrupts.into(), false); } /// Gets asserted interrupts @@ -1140,8 +1140,8 @@ impl<'d> ParlIoTxOnly<'d, Blocking> { } /// Resets asserted interrupts - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - internal_clear_interrupts(interrupts); + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { + internal_clear_interrupts(interrupts.into()); } } @@ -1200,13 +1200,13 @@ impl<'d> ParlIoRxOnly<'d, Blocking> { } /// Listen for the given interrupts - pub fn listen(&mut self, interrupts: EnumSet) { - internal_listen(interrupts, true); + pub fn listen(&mut self, interrupts: impl Into>) { + internal_listen(interrupts.into(), true); } /// Unlisten the given interrupts - pub fn unlisten(&mut self, interrupts: EnumSet) { - internal_listen(interrupts, false); + pub fn unlisten(&mut self, interrupts: impl Into>) { + internal_listen(interrupts.into(), false); } /// Gets asserted interrupts @@ -1215,8 +1215,8 @@ impl<'d> ParlIoRxOnly<'d, Blocking> { } /// Resets asserted interrupts - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - internal_clear_interrupts(interrupts); + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { + internal_clear_interrupts(interrupts.into()); } } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index dab8b9eb8d8..6241aa2b19a 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -812,6 +812,7 @@ mod dma { Rx, Tx, }, + Blocking, InterruptConfigurable, Mode, }; @@ -858,6 +859,46 @@ mod dma { } } + impl<'d, T> InterruptConfigurable for SpiDma<'d, Blocking, T> + where + T: InstanceDma, + { + /// Sets the interrupt handler + /// + /// Interrupts are not enabled at the peripheral level here. + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + let interrupt = self.spi.interrupt(); + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); + } + } + + #[cfg(gdma)] + impl<'d, T> SpiDma<'d, Blocking, T> + where + T: InstanceDma, + { + /// Listen for the given interrupts + pub fn listen(&mut self, interrupts: impl Into>) { + self.spi.enable_listen(interrupts.into(), true); + } + + /// Unlisten the given interrupts + pub fn unlisten(&mut self, interrupts: impl Into>) { + self.spi.enable_listen(interrupts.into(), false); + } + + /// Gets asserted interrupts + pub fn interrupts(&mut self) -> EnumSet { + self.spi.interrupts() + } + + /// Resets asserted interrupts + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { + self.spi.clear_interrupts(interrupts.into()); + } + } + impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, @@ -894,37 +935,6 @@ mod dma { } } - /// Sets the interrupt handler - /// - /// Interrupts are not enabled at the peripheral level here. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.spi.set_interrupt_handler(handler); - } - - /// Listen for the given interrupts - #[cfg(gdma)] - pub fn listen(&mut self, interrupts: EnumSet) { - self.spi.listen(interrupts); - } - - /// Unlisten the given interrupts - #[cfg(gdma)] - pub fn unlisten(&mut self, interrupts: EnumSet) { - self.spi.unlisten(interrupts); - } - - /// Gets asserted interrupts - #[cfg(gdma)] - pub fn interrupts(&mut self) -> EnumSet { - self.spi.interrupts() - } - - /// Resets asserted interrupts - #[cfg(gdma)] - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - self.spi.clear_interrupts(interrupts); - } - fn is_done(&self) -> bool { if self.tx_transfer_in_progress && !self.channel.tx.is_done() { return false; @@ -1071,17 +1081,6 @@ mod dma { { } - impl<'d, M, T> InterruptConfigurable for SpiDma<'d, M, T> - where - T: InstanceDma, - M: Mode, - { - /// Configures the interrupt handler for the DMA-enabled SPI instance. - fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - SpiDma::set_interrupt_handler(self, handler); - } - } - impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, @@ -1480,51 +1479,47 @@ mod dma { self.spi_dma.wait_for_idle(); } + /// Changes the SPI bus frequency for the DMA-enabled SPI instance. + pub fn change_bus_frequency(&mut self, frequency: HertzU32) { + self.spi_dma.change_bus_frequency(frequency); + } + } + + impl<'d, T> InterruptConfigurable for SpiDmaBus<'d, Blocking, T> + where + T: InstanceDma, + { /// Sets the interrupt handler /// /// Interrupts are not enabled at the peripheral level here. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.spi_dma.set_interrupt_handler(handler); } + } + #[cfg(gdma)] + impl<'d, T> SpiDmaBus<'d, Blocking, T> + where + T: InstanceDma, + { /// Listen for the given interrupts - #[cfg(gdma)] - pub fn listen(&mut self, interrupts: EnumSet) { - self.spi_dma.listen(interrupts); + pub fn listen(&mut self, interrupts: impl Into>) { + self.spi_dma.listen(interrupts.into()); } /// Unlisten the given interrupts - #[cfg(gdma)] - pub fn unlisten(&mut self, interrupts: EnumSet) { - self.spi_dma.unlisten(interrupts); + pub fn unlisten(&mut self, interrupts: impl Into>) { + self.spi_dma.unlisten(interrupts.into()); } /// Gets asserted interrupts - #[cfg(gdma)] pub fn interrupts(&mut self) -> EnumSet { self.spi_dma.interrupts() } /// Resets asserted interrupts - #[cfg(gdma)] - pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - self.spi_dma.clear_interrupts(interrupts); - } - - /// Changes the SPI bus frequency for the DMA-enabled SPI instance. - pub fn change_bus_frequency(&mut self, frequency: HertzU32) { - self.spi_dma.change_bus_frequency(frequency); - } - } - - impl<'d, M, T> InterruptConfigurable for SpiDmaBus<'d, M, T> - where - T: InstanceDma, - M: Mode, - { - /// Configures the interrupt handler for the DMA-enabled SPI instance. - fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - SpiDma::set_interrupt_handler(&mut self.spi_dma, handler); + pub fn clear_interrupts(&mut self, interrupts: impl Into>) { + self.spi_dma.clear_interrupts(interrupts.into()); } } @@ -2203,6 +2198,8 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static fn sio3_output_signal(&self) -> Option; fn sio3_input_signal(&self) -> Option; + fn interrupt(&self) -> crate::peripherals::Interrupt; + #[inline(always)] fn enable_peripheral(&self) { PeripheralClockControl::enable(self.peripheral()); @@ -2428,9 +2425,6 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static .write(|w| unsafe { w.bits(reg_val) }); } - /// Set the interrupt handler - fn set_interrupt_handler(&mut self, handler: InterruptHandler); - /// Enable or disable listening for the given interrupts. #[cfg(gdma)] fn enable_listen(&mut self, interrupts: EnumSet, enable: bool) { @@ -2446,18 +2440,6 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static }); } - /// Listen for the given interrupts - #[cfg(gdma)] - fn listen(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), true); - } - - /// Unlisten the given interrupts - #[cfg(gdma)] - fn unlisten(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), false); - } - /// Gets asserted interrupts #[cfg(gdma)] fn interrupts(&mut self) -> EnumSet { @@ -2880,9 +2862,8 @@ macro_rules! spi_instance { } #[inline(always)] - fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.[](handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::[], handler.priority()).unwrap(); + fn interrupt(&self) -> crate::peripherals::Interrupt { + crate::peripherals::Interrupt::[] } #[inline(always)] @@ -2998,15 +2979,8 @@ impl Instance for super::AnySpi { fn sio2_input_signal(&self) -> Option; fn sio3_output_signal(&self) -> Option; fn sio3_input_signal(&self) -> Option; - } - } - delegate::delegate! { - to match &mut self.0 { - super::AnySpiInner::Spi2(spi) => spi, - #[cfg(spi3)] - super::AnySpiInner::Spi3(spi) => spi, - } { - fn set_interrupt_handler(&mut self, handler: InterruptHandler); + + fn interrupt(&self) -> crate::peripherals::Interrupt; } } } From fc4eaa1ebf560915709cec20e79f4c9a8733ce4e Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Fri, 1 Nov 2024 03:31:56 -0700 Subject: [PATCH 15/67] Make our nightly CI checks pass (#2356) * Fix nightly lint errors for ESP32-C2 * Fix nightly lint errors for ESP32-C3 * Fix nightly lint errors for ESP32-C6 * Fix remaining nightly lint errors --- esp-hal/src/aes/esp32cX.rs | 2 +- esp-hal/src/aes/mod.rs | 6 +-- esp-hal/src/analog/adc/riscv.rs | 4 +- esp-hal/src/assist_debug.rs | 8 +-- esp-hal/src/dma/m2m.rs | 2 +- esp-hal/src/dma/mod.rs | 36 ++++++------- esp-hal/src/ecc.rs | 6 +-- esp-hal/src/etm.rs | 2 +- esp-hal/src/gpio/etm.rs | 27 +++++----- esp-hal/src/gpio/mod.rs | 73 +++++++++++++------------- esp-hal/src/i2c.rs | 8 +-- esp-hal/src/i2s.rs | 22 ++++---- esp-hal/src/ledc/channel.rs | 6 +-- esp-hal/src/ledc/timer.rs | 2 +- esp-hal/src/mcpwm/operator.rs | 12 ++--- esp-hal/src/parl_io.rs | 44 ++++++++-------- esp-hal/src/pcnt/channel.rs | 2 +- esp-hal/src/pcnt/mod.rs | 4 +- esp-hal/src/pcnt/unit.rs | 8 +-- esp-hal/src/peripheral.rs | 4 +- esp-hal/src/rmt.rs | 12 ++--- esp-hal/src/rng.rs | 3 +- esp-hal/src/rsa/esp32cX.rs | 8 +-- esp-hal/src/rsa/mod.rs | 12 ++--- esp-hal/src/rtc_cntl/mod.rs | 4 +- esp-hal/src/rtc_cntl/sleep/esp32c2.rs | 2 +- esp-hal/src/rtc_cntl/sleep/esp32c3.rs | 2 +- esp-hal/src/sha.rs | 4 +- esp-hal/src/spi/master.rs | 36 ++++++------- esp-hal/src/spi/slave.rs | 4 +- esp-hal/src/sync.rs | 2 +- esp-hal/src/timer/mod.rs | 20 +++---- esp-hal/src/timer/systimer.rs | 42 +++++++-------- esp-hal/src/timer/timg.rs | 4 +- esp-hal/src/twai/mod.rs | 4 +- esp-hal/src/usb_serial_jtag.rs | 16 +++--- esp-ieee802154/src/lib.rs | 2 +- esp-println/Cargo.toml | 3 ++ esp-wifi/src/ble/btdm.rs | 1 + esp-wifi/src/ble/controller/mod.rs | 2 +- esp-wifi/src/ble/npl.rs | 1 + esp-wifi/src/wifi/mod.rs | 2 +- examples/src/bin/ram.rs | 1 + examples/src/bin/wifi_coex.rs | 1 + examples/src/bin/wifi_embassy_bench.rs | 1 + 45 files changed, 233 insertions(+), 234 deletions(-) diff --git a/esp-hal/src/aes/esp32cX.rs b/esp-hal/src/aes/esp32cX.rs index bd653da4a84..b20923cc9e3 100644 --- a/esp-hal/src/aes/esp32cX.rs +++ b/esp-hal/src/aes/esp32cX.rs @@ -3,7 +3,7 @@ use crate::{ system::{Peripheral as PeripheralEnable, PeripheralClockControl}, }; -impl<'d> Aes<'d> { +impl Aes<'_> { pub(super) fn init(&mut self) { PeripheralClockControl::enable(PeripheralEnable::Aes); self.write_dma(false); diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index bbf18752534..f8c4f970c7c 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -301,13 +301,13 @@ pub mod dma { } } - impl<'d> core::fmt::Debug for AesDma<'d> { + impl core::fmt::Debug for AesDma<'_> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("AesDma").finish() } } - impl<'d> DmaSupport for AesDma<'d> { + impl DmaSupport for AesDma<'_> { fn peripheral_wait_dma(&mut self, _is_rx: bool, _is_tx: bool) { while self.aes.aes.state().read().state().bits() != 2 // DMA status DONE == 2 && !self.channel.tx.is_done() @@ -347,7 +347,7 @@ pub mod dma { } } - impl<'d> AesDma<'d> { + impl AesDma<'_> { /// Writes the encryption key to the AES hardware, checking that its /// length matches expected constraints. pub fn write_key(&mut self, key: K) diff --git a/esp-hal/src/analog/adc/riscv.rs b/esp-hal/src/analog/adc/riscv.rs index b25eaa2fc86..6b54131600a 100644 --- a/esp-hal/src/analog/adc/riscv.rs +++ b/esp-hal/src/analog/adc/riscv.rs @@ -530,8 +530,8 @@ impl super::AdcCalEfuse for crate::peripherals::ADC2 { } } -impl<'d, ADCI, PIN, CS> embedded_hal_02::adc::OneShot> - for Adc<'d, ADCI> +impl embedded_hal_02::adc::OneShot> + for Adc<'_, ADCI> where PIN: embedded_hal_02::adc::Channel + super::AdcChannel, ADCI: RegisterAccess, diff --git a/esp-hal/src/assist_debug.rs b/esp-hal/src/assist_debug.rs index 4e5fe1e8c90..1426ff2fa91 100644 --- a/esp-hal/src/assist_debug.rs +++ b/esp-hal/src/assist_debug.rs @@ -47,9 +47,9 @@ impl<'d> DebugAssist<'d> { } } -impl<'d> crate::private::Sealed for DebugAssist<'d> {} +impl crate::private::Sealed for DebugAssist<'_> {} -impl<'d> InterruptConfigurable for DebugAssist<'d> { +impl InterruptConfigurable for DebugAssist<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { unsafe { crate::interrupt::bind_interrupt( @@ -66,7 +66,7 @@ impl<'d> InterruptConfigurable for DebugAssist<'d> { } #[cfg(assist_debug_sp_monitor)] -impl<'d> DebugAssist<'d> { +impl DebugAssist<'_> { /// Enable SP monitoring on main core. When the SP exceeds the /// `lower_bound` or `upper_bound` threshold, the module will record the PC /// pointer and generate an interrupt. @@ -228,7 +228,7 @@ impl<'d> DebugAssist<'d> { } #[cfg(assist_debug_region_monitor)] -impl<'d> DebugAssist<'d> { +impl DebugAssist<'_> { /// Enable region monitoring of read/write performed by the main CPU in a /// certain memory region0. Whenever the bus reads or writes in the /// specified memory region, an interrupt will be triggered. Two memory diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index 0e0aee187d1..c6e69984f3d 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -157,7 +157,7 @@ where } } -impl<'d, MODE> DmaSupport for Mem2Mem<'d, MODE> +impl DmaSupport for Mem2Mem<'_, MODE> where MODE: Mode, { diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 0e80eefddb8..bd2754cf715 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1685,9 +1685,9 @@ where } } -impl<'a, CH> crate::private::Sealed for ChannelRx<'a, CH> where CH: DmaChannel {} +impl crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} -impl<'a, CH> Rx for ChannelRx<'a, CH> +impl Rx for ChannelRx<'_, CH> where CH: DmaChannel, { @@ -1901,9 +1901,9 @@ where } } -impl<'a, CH> crate::private::Sealed for ChannelTx<'a, CH> where CH: DmaChannel {} +impl crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} -impl<'a, CH> Tx for ChannelTx<'a, CH> +impl Tx for ChannelTx<'_, CH> where CH: DmaChannel, { @@ -2113,7 +2113,7 @@ where phantom: PhantomData, } -impl<'d, C> Channel<'d, C, crate::Blocking> +impl Channel<'_, C, crate::Blocking> where C: DmaChannel, { @@ -2272,7 +2272,7 @@ where } } -impl<'a, I> Drop for DmaTransferTx<'a, I> +impl Drop for DmaTransferTx<'_, I> where I: dma_private::DmaSupportTx, { @@ -2325,7 +2325,7 @@ where } } -impl<'a, I> Drop for DmaTransferRx<'a, I> +impl Drop for DmaTransferRx<'_, I> where I: dma_private::DmaSupportRx, { @@ -2384,7 +2384,7 @@ where } } -impl<'a, I> Drop for DmaTransferRxTx<'a, I> +impl Drop for DmaTransferRxTx<'_, I> where I: dma_private::DmaSupportTx + dma_private::DmaSupportRx, { @@ -2457,7 +2457,7 @@ where } } -impl<'a, I> Drop for DmaTransferTxCircular<'a, I> +impl Drop for DmaTransferTxCircular<'_, I> where I: dma_private::DmaSupportTx, { @@ -2514,7 +2514,7 @@ where } } -impl<'a, I> Drop for DmaTransferRxCircular<'a, I> +impl Drop for DmaTransferRxCircular<'_, I> where I: dma_private::DmaSupportRx, { @@ -2545,7 +2545,7 @@ pub(crate) mod asynch { } } - impl<'a, TX> core::future::Future for DmaTxFuture<'a, TX> + impl core::future::Future for DmaTxFuture<'_, TX> where TX: Tx, { @@ -2574,7 +2574,7 @@ pub(crate) mod asynch { } } - impl<'a, TX> Drop for DmaTxFuture<'a, TX> + impl Drop for DmaTxFuture<'_, TX> where TX: Tx, { @@ -2601,7 +2601,7 @@ pub(crate) mod asynch { } } - impl<'a, RX> core::future::Future for DmaRxFuture<'a, RX> + impl core::future::Future for DmaRxFuture<'_, RX> where RX: Rx, { @@ -2634,7 +2634,7 @@ pub(crate) mod asynch { } } - impl<'a, RX> Drop for DmaRxFuture<'a, RX> + impl Drop for DmaRxFuture<'_, RX> where RX: Rx, { @@ -2667,7 +2667,7 @@ pub(crate) mod asynch { } #[cfg(any(i2s0, i2s1))] - impl<'a, TX> core::future::Future for DmaTxDoneChFuture<'a, TX> + impl core::future::Future for DmaTxDoneChFuture<'_, TX> where TX: Tx, { @@ -2701,7 +2701,7 @@ pub(crate) mod asynch { } #[cfg(any(i2s0, i2s1))] - impl<'a, TX> Drop for DmaTxDoneChFuture<'a, TX> + impl Drop for DmaTxDoneChFuture<'_, TX> where TX: Tx, { @@ -2731,7 +2731,7 @@ pub(crate) mod asynch { } #[cfg(any(i2s0, i2s1))] - impl<'a, RX> core::future::Future for DmaRxDoneChFuture<'a, RX> + impl core::future::Future for DmaRxDoneChFuture<'_, RX> where RX: Rx, { @@ -2769,7 +2769,7 @@ pub(crate) mod asynch { } #[cfg(any(i2s0, i2s1))] - impl<'a, RX> Drop for DmaRxDoneChFuture<'a, RX> + impl Drop for DmaRxDoneChFuture<'_, RX> where RX: Rx, { diff --git a/esp-hal/src/ecc.rs b/esp-hal/src/ecc.rs index 10d0a17fac5..59ee1f891eb 100644 --- a/esp-hal/src/ecc.rs +++ b/esp-hal/src/ecc.rs @@ -113,9 +113,9 @@ impl<'d> Ecc<'d, crate::Blocking> { } } -impl<'d> crate::private::Sealed for Ecc<'d, crate::Blocking> {} +impl crate::private::Sealed for Ecc<'_, crate::Blocking> {} -impl<'d> InterruptConfigurable for Ecc<'d, crate::Blocking> { +impl InterruptConfigurable for Ecc<'_, crate::Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { unsafe { crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::ECC, handler.handler()); @@ -125,7 +125,7 @@ impl<'d> InterruptConfigurable for Ecc<'d, crate::Blocking> { } } -impl<'d, DM: crate::Mode> Ecc<'d, DM> { +impl Ecc<'_, DM> { /// Resets the ECC peripheral. pub fn reset(&mut self) { self.ecc.mult_conf().reset() diff --git a/esp-hal/src/etm.rs b/esp-hal/src/etm.rs index 1e8322c1852..692594c924a 100644 --- a/esp-hal/src/etm.rs +++ b/esp-hal/src/etm.rs @@ -123,7 +123,7 @@ where _task: &'a T, } -impl<'a, E, T, const C: u8> Drop for EtmConfiguredChannel<'a, E, T, C> +impl Drop for EtmConfiguredChannel<'_, E, T, C> where E: EtmEvent, T: EtmTask, diff --git a/esp-hal/src/gpio/etm.rs b/esp-hal/src/gpio/etm.rs index bc5958256a7..262536ad1ee 100644 --- a/esp-hal/src/gpio/etm.rs +++ b/esp-hal/src/gpio/etm.rs @@ -202,12 +202,12 @@ where _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmEventChannelRising<'d, PIN, C> where +impl private::Sealed for GpioEtmEventChannelRising<'_, PIN, C> where PIN: super::Pin { } -impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelRising<'d, PIN, C> +impl crate::etm::EtmEvent for GpioEtmEventChannelRising<'_, PIN, C> where PIN: super::Pin, { @@ -225,12 +225,12 @@ where _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmEventChannelFalling<'d, PIN, C> where +impl private::Sealed for GpioEtmEventChannelFalling<'_, PIN, C> where PIN: super::Pin { } -impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelFalling<'d, PIN, C> +impl crate::etm::EtmEvent for GpioEtmEventChannelFalling<'_, PIN, C> where PIN: super::Pin, { @@ -248,12 +248,9 @@ where _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmEventChannelAny<'d, PIN, C> where - PIN: super::Pin -{ -} +impl private::Sealed for GpioEtmEventChannelAny<'_, PIN, C> where PIN: super::Pin {} -impl<'d, PIN, const C: u8> crate::etm::EtmEvent for GpioEtmEventChannelAny<'d, PIN, C> +impl crate::etm::EtmEvent for GpioEtmEventChannelAny<'_, PIN, C> where PIN: super::Pin, { @@ -372,9 +369,9 @@ where _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmTaskSet<'d, PIN, C> where PIN: super::Pin {} +impl private::Sealed for GpioEtmTaskSet<'_, PIN, C> where PIN: super::Pin {} -impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskSet<'d, PIN, C> +impl crate::etm::EtmTask for GpioEtmTaskSet<'_, PIN, C> where PIN: super::Pin, { @@ -389,9 +386,9 @@ pub struct GpioEtmTaskClear<'d, PIN, const C: u8> { _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmTaskClear<'d, PIN, C> where PIN: super::Pin {} +impl private::Sealed for GpioEtmTaskClear<'_, PIN, C> where PIN: super::Pin {} -impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskClear<'d, PIN, C> +impl crate::etm::EtmTask for GpioEtmTaskClear<'_, PIN, C> where PIN: super::Pin, { @@ -406,9 +403,9 @@ pub struct GpioEtmTaskToggle<'d, PIN, const C: u8> { _pin: PeripheralRef<'d, PIN>, } -impl<'d, PIN, const C: u8> private::Sealed for GpioEtmTaskToggle<'d, PIN, C> where PIN: super::Pin {} +impl private::Sealed for GpioEtmTaskToggle<'_, PIN, C> where PIN: super::Pin {} -impl<'d, PIN, const C: u8> crate::etm::EtmTask for GpioEtmTaskToggle<'d, PIN, C> +impl crate::etm::EtmTask for GpioEtmTaskToggle<'_, PIN, C> where PIN: super::Pin, { diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index bc8199cf3ac..02eff2d7d57 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -83,7 +83,6 @@ pub mod lp_io; pub mod rtc_io; /// Convenience constant for `Option::None` pin - static USER_INTERRUPT_HANDLER: CFnPtr = CFnPtr::new(); struct CFnPtr(AtomicPtr<()>); @@ -1129,7 +1128,7 @@ pub struct Output<'d, P = AnyPin> { impl

private::Sealed for Output<'_, P> {} -impl<'d, P> Peripheral for Output<'d, P> { +impl

Peripheral for Output<'_, P> { type P = P; unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() @@ -1232,7 +1231,7 @@ pub struct Input<'d, P = AnyPin> { impl

private::Sealed for Input<'_, P> {} -impl<'d, P> Peripheral for Input<'d, P> { +impl

Peripheral for Input<'_, P> { type P = P; unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() @@ -1330,7 +1329,7 @@ pub struct OutputOpenDrain<'d, P = AnyPin> { impl

private::Sealed for OutputOpenDrain<'_, P> {} -impl<'d, P> Peripheral for OutputOpenDrain<'d, P> { +impl

Peripheral for OutputOpenDrain<'_, P> { type P = P; unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() @@ -1461,7 +1460,7 @@ pub struct Flex<'d, P = AnyPin> { impl

private::Sealed for Flex<'_, P> {} -impl<'d, P> Peripheral for Flex<'d, P> { +impl

Peripheral for Flex<'_, P> { type P = P; unsafe fn clone_unchecked(&self) -> P { core::ptr::read(&*self.pin as *const _) @@ -1490,7 +1489,7 @@ where } } -impl<'d, P> Flex<'d, P> +impl

Flex<'_, P> where P: InputPin, { @@ -1589,7 +1588,7 @@ where } } -impl<'d, P> Flex<'d, P> +impl

Flex<'_, P> where P: OutputPin, { @@ -1658,7 +1657,7 @@ where } } -impl<'d, P> Flex<'d, P> +impl

Flex<'_, P> where P: InputPin + OutputPin, { @@ -1843,7 +1842,7 @@ mod asynch { pub(super) static PIN_WAKERS: [AtomicWaker; NUM_PINS] = [const { AtomicWaker::new() }; NUM_PINS]; - impl<'d, P> Flex<'d, P> + impl

Flex<'_, P> where P: InputPin, { @@ -1880,7 +1879,7 @@ mod asynch { } } - impl<'d, P> Input<'d, P> + impl

Input<'_, P> where P: InputPin, { @@ -1945,7 +1944,7 @@ mod embedded_hal_02_impls { use super::*; - impl<'d, P> digital::InputPin for Input<'d, P> + impl

digital::InputPin for Input<'_, P> where P: InputPin, { @@ -1959,7 +1958,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::OutputPin for Output<'d, P> + impl

digital::OutputPin for Output<'_, P> where P: OutputPin, { @@ -1975,7 +1974,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::StatefulOutputPin for Output<'d, P> + impl

digital::StatefulOutputPin for Output<'_, P> where P: OutputPin, { @@ -1987,7 +1986,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::ToggleableOutputPin for Output<'d, P> + impl

digital::ToggleableOutputPin for Output<'_, P> where P: OutputPin, { @@ -1999,7 +1998,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::InputPin for OutputOpenDrain<'d, P> + impl

digital::InputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2013,7 +2012,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::OutputPin for OutputOpenDrain<'d, P> + impl

digital::OutputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2030,7 +2029,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::StatefulOutputPin for OutputOpenDrain<'d, P> + impl

digital::StatefulOutputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2042,7 +2041,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::ToggleableOutputPin for OutputOpenDrain<'d, P> + impl

digital::ToggleableOutputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2054,7 +2053,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::InputPin for Flex<'d, P> + impl

digital::InputPin for Flex<'_, P> where P: InputPin + OutputPin, { @@ -2068,7 +2067,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::OutputPin for Flex<'d, P> + impl

digital::OutputPin for Flex<'_, P> where P: InputPin + OutputPin, { @@ -2084,7 +2083,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::StatefulOutputPin for Flex<'d, P> + impl

digital::StatefulOutputPin for Flex<'_, P> where P: InputPin + OutputPin, { @@ -2096,7 +2095,7 @@ mod embedded_hal_02_impls { } } - impl<'d, P> digital::ToggleableOutputPin for Flex<'d, P> + impl

digital::ToggleableOutputPin for Flex<'_, P> where P: InputPin + OutputPin, { @@ -2114,14 +2113,14 @@ mod embedded_hal_impls { use super::*; - impl<'d, P> digital::ErrorType for Input<'d, P> + impl

digital::ErrorType for Input<'_, P> where P: InputPin, { type Error = core::convert::Infallible; } - impl<'d, P> digital::InputPin for Input<'d, P> + impl

digital::InputPin for Input<'_, P> where P: InputPin, { @@ -2134,14 +2133,14 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::ErrorType for Output<'d, P> + impl

digital::ErrorType for Output<'_, P> where P: OutputPin, { type Error = core::convert::Infallible; } - impl<'d, P> digital::OutputPin for Output<'d, P> + impl

digital::OutputPin for Output<'_, P> where P: OutputPin, { @@ -2156,7 +2155,7 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::StatefulOutputPin for Output<'d, P> + impl

digital::StatefulOutputPin for Output<'_, P> where P: OutputPin, { @@ -2169,7 +2168,7 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::InputPin for OutputOpenDrain<'d, P> + impl

digital::InputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2182,14 +2181,14 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::ErrorType for OutputOpenDrain<'d, P> + impl

digital::ErrorType for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { type Error = core::convert::Infallible; } - impl<'d, P> digital::OutputPin for OutputOpenDrain<'d, P> + impl

digital::OutputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2204,7 +2203,7 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::StatefulOutputPin for OutputOpenDrain<'d, P> + impl

digital::StatefulOutputPin for OutputOpenDrain<'_, P> where P: InputPin + OutputPin, { @@ -2217,7 +2216,7 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::InputPin for Flex<'d, P> + impl

digital::InputPin for Flex<'_, P> where P: InputPin, { @@ -2230,11 +2229,11 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::ErrorType for Flex<'d, P> { + impl

digital::ErrorType for Flex<'_, P> { type Error = core::convert::Infallible; } - impl<'d, P> digital::OutputPin for Flex<'d, P> + impl

digital::OutputPin for Flex<'_, P> where P: OutputPin, { @@ -2249,7 +2248,7 @@ mod embedded_hal_impls { } } - impl<'d, P> digital::StatefulOutputPin for Flex<'d, P> + impl

digital::StatefulOutputPin for Flex<'_, P> where P: OutputPin, { @@ -2268,7 +2267,7 @@ mod embedded_hal_async_impls { use super::*; - impl<'d, P> Wait for Flex<'d, P> + impl

Wait for Flex<'_, P> where P: InputPin, { @@ -2298,7 +2297,7 @@ mod embedded_hal_async_impls { } } - impl<'d, P> Wait for Input<'d, P> + impl

Wait for Input<'_, P> where P: InputPin, { diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 9eb4219e3f4..8b919fd6c9b 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -587,9 +587,9 @@ where } } -impl<'d, T> crate::private::Sealed for I2c<'d, Blocking, T> where T: Instance {} +impl crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} -impl<'d, T> InterruptConfigurable for I2c<'d, Blocking, T> +impl InterruptConfigurable for I2c<'_, Blocking, T> where T: Instance, { @@ -745,7 +745,7 @@ mod asynch { } #[cfg(not(esp32))] - impl<'a, T> core::future::Future for I2cFuture<'a, T> + impl core::future::Future for I2cFuture<'_, T> where T: Instance, { @@ -1158,7 +1158,7 @@ mod asynch { } } - impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, Async, T> + impl embedded_hal_async::i2c::I2c for I2c<'_, Async, T> where T: Instance, { diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index fcbd7eab4a7..6b9f44ad135 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -314,7 +314,7 @@ where } } -impl<'d, DmaMode, T> I2s<'d, DmaMode, T> +impl I2s<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -352,14 +352,14 @@ where } } -impl<'d, DmaMode, I> crate::private::Sealed for I2s<'d, DmaMode, I> +impl crate::private::Sealed for I2s<'_, DmaMode, I> where I: RegisterAccess, DmaMode: Mode, { } -impl<'d, DmaMode, I> InterruptConfigurable for I2s<'d, DmaMode, I> +impl InterruptConfigurable for I2s<'_, DmaMode, I> where I: RegisterAccess, DmaMode: Mode, @@ -453,7 +453,7 @@ where phantom: PhantomData, } -impl<'d, DmaMode, T> core::fmt::Debug for I2sTx<'d, DmaMode, T> +impl core::fmt::Debug for I2sTx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -463,7 +463,7 @@ where } } -impl<'d, DmaMode, T> DmaSupport for I2sTx<'d, DmaMode, T> +impl DmaSupport for I2sTx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -493,7 +493,7 @@ where } } -impl<'d, DmaMode, T> I2sTx<'d, DmaMode, T> +impl I2sTx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -586,7 +586,7 @@ where phantom: PhantomData, } -impl<'d, DmaMode, T> core::fmt::Debug for I2sRx<'d, DmaMode, T> +impl core::fmt::Debug for I2sRx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -596,7 +596,7 @@ where } } -impl<'d, DmaMode, T> DmaSupport for I2sRx<'d, DmaMode, T> +impl DmaSupport for I2sRx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -626,7 +626,7 @@ where } } -impl<'d, DmaMode, T> I2sRx<'d, DmaMode, T> +impl I2sRx<'_, DmaMode, T> where T: RegisterAccess, DmaMode: Mode, @@ -1941,7 +1941,7 @@ pub mod asynch { _buffer: BUFFER, } - impl<'d, T, BUFFER> I2sWriteDmaTransferAsync<'d, BUFFER, T> + impl I2sWriteDmaTransferAsync<'_, BUFFER, T> where T: RegisterAccess, { @@ -2064,7 +2064,7 @@ pub mod asynch { _buffer: BUFFER, } - impl<'d, T, BUFFER> I2sReadDmaTransferAsync<'d, BUFFER, T> + impl I2sReadDmaTransferAsync<'_, BUFFER, T> where T: RegisterAccess, { diff --git a/esp-hal/src/ledc/channel.rs b/esp-hal/src/ledc/channel.rs index fa27cc3689b..a1f18c5ba41 100644 --- a/esp-hal/src/ledc/channel.rs +++ b/esp-hal/src/ledc/channel.rs @@ -312,7 +312,7 @@ mod ehal1 { } } - impl<'a, S: TimerSpeed> ErrorType for Channel<'a, S> { + impl ErrorType for Channel<'_, S> { type Error = Error; } @@ -343,7 +343,7 @@ mod ehal1 { } } -impl<'a, S: crate::ledc::timer::TimerSpeed> Channel<'a, S> { +impl Channel<'_, S> { #[cfg(esp32)] fn set_channel(&mut self, timer_number: u8) { if S::IS_HS { @@ -541,7 +541,7 @@ impl<'a, S: crate::ledc::timer::TimerSpeed> Channel<'a, S> { } } -impl<'a, S> ChannelHW for Channel<'a, S> +impl ChannelHW for Channel<'_, S> where S: crate::ledc::timer::TimerSpeed, { diff --git a/esp-hal/src/ledc/timer.rs b/esp-hal/src/ledc/timer.rs index 6b6c0f8c13b..051520c6e10 100644 --- a/esp-hal/src/ledc/timer.rs +++ b/esp-hal/src/ledc/timer.rs @@ -306,7 +306,7 @@ impl<'a, S: TimerSpeed> Timer<'a, S> { } /// Timer HW implementation for LowSpeed timers -impl<'a> TimerHW for Timer<'a, LowSpeed> { +impl TimerHW for Timer<'_, LowSpeed> { /// Get the current source timer frequency from the HW fn get_freq_hw(&self) -> Option { self.clock_source.map(|source| match source { diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index 0b20764b364..d2df0a68ec9 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -413,8 +413,8 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, } } -impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal_02::PwmPin - for PwmPin<'d, PWM, OP, IS_A> +impl embedded_hal_02::PwmPin + for PwmPin<'_, PWM, OP, IS_A> { type Duty = u16; @@ -447,15 +447,15 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal_02::Pw } /// Implement no error type for the PwmPin because the method are infallible -impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal::pwm::ErrorType - for PwmPin<'d, PWM, OP, IS_A> +impl embedded_hal::pwm::ErrorType + for PwmPin<'_, PWM, OP, IS_A> { type Error = core::convert::Infallible; } /// Implement the trait SetDutyCycle for PwmPin -impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal::pwm::SetDutyCycle - for PwmPin<'d, PWM, OP, IS_A> +impl embedded_hal::pwm::SetDutyCycle + for PwmPin<'_, PWM, OP, IS_A> { /// Get the max duty of the PwmPin fn max_duty_cycle(&self) -> u16 { diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 489786d92d6..0c4229d721e 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -339,7 +339,7 @@ impl<'d> RxClkInPin<'d> { Self { pin, sample_edge } } } -impl<'d> RxClkPin for RxClkInPin<'d> { +impl RxClkPin for RxClkInPin<'_> { fn configure(&mut self) { let pcr = unsafe { &*crate::peripherals::PCR::PTR }; pcr.parl_clk_rx_conf() @@ -376,12 +376,12 @@ where } } -impl<'d, P> TxPins for TxPinConfigWithValidPin<'d, P> where +impl

TxPins for TxPinConfigWithValidPin<'_, P> where P: NotContainsValidSignalPin + TxPins + ConfigurePins { } -impl<'d, P> ConfigurePins for TxPinConfigWithValidPin<'d, P> +impl

ConfigurePins for TxPinConfigWithValidPin<'_, P> where P: NotContainsValidSignalPin + TxPins + ConfigurePins, { @@ -570,12 +570,12 @@ where } } -impl<'d, P> RxPins for RxPinConfigWithValidPin<'d, P> where +impl

RxPins for RxPinConfigWithValidPin<'_, P> where P: NotContainsValidSignalPin + RxPins + ConfigurePins { } -impl<'d, P> ConfigurePins for RxPinConfigWithValidPin<'d, P> +impl

ConfigurePins for RxPinConfigWithValidPin<'_, P> where P: NotContainsValidSignalPin + RxPins + ConfigurePins, { @@ -832,7 +832,7 @@ where phantom: PhantomData, } -impl<'d, DM> core::fmt::Debug for ParlIoTx<'d, DM> +impl core::fmt::Debug for ParlIoTx<'_, DM> where DM: Mode, { @@ -911,7 +911,7 @@ where phantom: PhantomData, } -impl<'d, DM> core::fmt::Debug for ParlIoRx<'d, DM> +impl core::fmt::Debug for ParlIoRx<'_, DM> where DM: Mode, { @@ -1040,7 +1040,7 @@ where } } -impl<'d> ParlIoFullDuplex<'d, Blocking> { +impl ParlIoFullDuplex<'_, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1070,9 +1070,9 @@ impl<'d> ParlIoFullDuplex<'d, Blocking> { } } -impl<'d> crate::private::Sealed for ParlIoFullDuplex<'d, Blocking> {} +impl crate::private::Sealed for ParlIoFullDuplex<'_, Blocking> {} -impl<'d> InterruptConfigurable for ParlIoFullDuplex<'d, Blocking> { +impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoFullDuplex::set_interrupt_handler(self, handler); } @@ -1115,7 +1115,7 @@ where } } -impl<'d> ParlIoTxOnly<'d, Blocking> { +impl ParlIoTxOnly<'_, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1145,9 +1145,9 @@ impl<'d> ParlIoTxOnly<'d, Blocking> { } } -impl<'d> crate::private::Sealed for ParlIoTxOnly<'d, Blocking> {} +impl crate::private::Sealed for ParlIoTxOnly<'_, Blocking> {} -impl<'d> InterruptConfigurable for ParlIoTxOnly<'d, Blocking> { +impl InterruptConfigurable for ParlIoTxOnly<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoTxOnly::set_interrupt_handler(self, handler); } @@ -1190,7 +1190,7 @@ where } } -impl<'d> ParlIoRxOnly<'d, Blocking> { +impl ParlIoRxOnly<'_, Blocking> { /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1220,9 +1220,9 @@ impl<'d> ParlIoRxOnly<'d, Blocking> { } } -impl<'d> crate::private::Sealed for ParlIoRxOnly<'d, Blocking> {} +impl crate::private::Sealed for ParlIoRxOnly<'_, Blocking> {} -impl<'d> InterruptConfigurable for ParlIoRxOnly<'d, Blocking> { +impl InterruptConfigurable for ParlIoRxOnly<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { ParlIoRxOnly::set_interrupt_handler(self, handler); } @@ -1261,7 +1261,7 @@ fn internal_init(frequency: HertzU32) -> Result<(), Error> { Ok(()) } -impl<'d, DM> ParlIoTx<'d, DM> +impl ParlIoTx<'_, DM> where DM: Mode, { @@ -1316,7 +1316,7 @@ where } } -impl<'d, DM> DmaSupport for ParlIoTx<'d, DM> +impl DmaSupport for ParlIoTx<'_, DM> where DM: Mode, { @@ -1405,7 +1405,7 @@ where } } -impl<'d, DM> DmaSupport for ParlIoRx<'d, DM> +impl DmaSupport for ParlIoRx<'_, DM> where DM: Mode, { @@ -1546,11 +1546,11 @@ pub mod asynch { } } - impl<'d> ParlIoTx<'d, crate::Async> { + impl ParlIoTx<'_, crate::Async> { /// Perform a DMA write. /// /// The maximum amount of data to be sent is 32736 bytes. - pub async fn write_dma_async<'t, TXBUF>(&mut self, words: &'t TXBUF) -> Result<(), Error> + pub async fn write_dma_async(&mut self, words: &TXBUF) -> Result<(), Error> where TXBUF: ReadBuffer, { @@ -1568,7 +1568,7 @@ pub mod asynch { } } - impl<'d> ParlIoRx<'d, crate::Async> { + impl ParlIoRx<'_, crate::Async> { /// Perform a DMA write. /// /// The maximum amount of data to be sent is 32736 bytes. diff --git a/esp-hal/src/pcnt/channel.rs b/esp-hal/src/pcnt/channel.rs index 34b1f971258..b85a4b05f0d 100644 --- a/esp-hal/src/pcnt/channel.rs +++ b/esp-hal/src/pcnt/channel.rs @@ -22,7 +22,7 @@ pub struct Channel<'d, const UNIT: usize, const NUM: usize> { _not_send: PhantomData<*const ()>, } -impl<'d, const UNIT: usize, const NUM: usize> Channel<'d, UNIT, NUM> { +impl Channel<'_, UNIT, NUM> { /// return a new Channel pub(super) fn new() -> Self { Self { diff --git a/esp-hal/src/pcnt/mod.rs b/esp-hal/src/pcnt/mod.rs index 4c4817c46cf..d7598a5e7a3 100644 --- a/esp-hal/src/pcnt/mod.rs +++ b/esp-hal/src/pcnt/mod.rs @@ -109,9 +109,9 @@ impl<'d> Pcnt<'d> { } } -impl<'d> crate::private::Sealed for Pcnt<'d> {} +impl crate::private::Sealed for Pcnt<'_> {} -impl<'d> InterruptConfigurable for Pcnt<'d> { +impl InterruptConfigurable for Pcnt<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()); diff --git a/esp-hal/src/pcnt/unit.rs b/esp-hal/src/pcnt/unit.rs index 1f0006f64e6..cdcaae7830e 100644 --- a/esp-hal/src/pcnt/unit.rs +++ b/esp-hal/src/pcnt/unit.rs @@ -84,7 +84,7 @@ pub struct Unit<'d, const NUM: usize> { pub channel1: Channel<'d, NUM, 1>, } -impl<'d, const NUM: usize> Unit<'d, NUM> { +impl Unit<'_, NUM> { /// return a new Unit pub(super) fn new() -> Self { Self { @@ -301,14 +301,14 @@ impl<'d, const NUM: usize> Unit<'d, NUM> { } } -impl<'d, const NUM: usize> Drop for Unit<'d, NUM> { +impl Drop for Unit<'_, NUM> { fn drop(&mut self) { // This is here to prevent the destructuring of Unit. } } // The entire Unit is Send but the individual channels are not. -unsafe impl<'d, const NUM: usize> Send for Unit<'d, NUM> {} +unsafe impl Send for Unit<'_, NUM> {} /// Represents the counter within a pulse counter unit. #[derive(Clone)] @@ -316,7 +316,7 @@ pub struct Counter<'d, const NUM: usize> { _phantom: PhantomData<&'d ()>, } -impl<'d, const NUM: usize> Counter<'d, NUM> { +impl Counter<'_, NUM> { fn new() -> Self { Self { _phantom: PhantomData, diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index 7d5b665e2ea..9b3c230e3a9 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -82,7 +82,7 @@ impl<'a, T> PeripheralRef<'a, T> { } } -impl<'a, T> Deref for PeripheralRef<'a, T> { +impl Deref for PeripheralRef<'_, T> { type Target = T; #[inline] @@ -91,7 +91,7 @@ impl<'a, T> Deref for PeripheralRef<'a, T> { } } -impl<'a, T> DerefMut for PeripheralRef<'a, T> { +impl DerefMut for PeripheralRef<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index ef61e03e5f9..80f0d99fe79 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -275,9 +275,9 @@ impl<'d> Rmt<'d, crate::Blocking> { } } -impl<'d> crate::private::Sealed for Rmt<'d, crate::Blocking> {} +impl crate::private::Sealed for Rmt<'_, crate::Blocking> {} -impl<'d> InterruptConfigurable for Rmt<'d, crate::Blocking> { +impl InterruptConfigurable for Rmt<'_, crate::Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { self.internal_set_interrupt_handler(handler); } @@ -448,7 +448,7 @@ where data: &'a [T], } -impl<'a, C, T: Into + Copy> SingleShotTxTransaction<'a, C, T> +impl + Copy> SingleShotTxTransaction<'_, C, T> where C: TxChannel, { @@ -1045,7 +1045,7 @@ where data: &'a mut [T], } -impl<'a, C, T: From + Copy> RxTransaction<'a, C, T> +impl + Copy> RxTransaction<'_, C, T> where C: RxChannel, { @@ -1163,7 +1163,7 @@ pub mod asynch { /// Start transmitting the given pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. - async fn transmit<'a, T: Into + Copy>(&mut self, data: &'a [T]) -> Result<(), Error> + async fn transmit + Copy>(&mut self, data: &[T]) -> Result<(), Error> where Self: Sized, { @@ -1226,7 +1226,7 @@ pub mod asynch { /// Start receiving a pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. - async fn receive<'a, T: From + Copy>(&mut self, data: &'a mut [T]) -> Result<(), Error> + async fn receive + Copy>(&mut self, data: &mut [T]) -> Result<(), Error> where Self: Sized, { diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index 8e469bd43d5..406a9980818 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -164,7 +164,6 @@ impl rand_core::RngCore for Rng { /// let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); /// # } /// ``` - pub struct Trng<'d> { /// The hardware random number generator instance. pub rng: Rng, @@ -211,7 +210,7 @@ impl<'d> Trng<'d> { } } -impl<'d> Drop for Trng<'d> { +impl Drop for Trng<'_> { fn drop(&mut self) { crate::soc::trng::revert_trng(); } diff --git a/esp-hal/src/rsa/esp32cX.rs b/esp-hal/src/rsa/esp32cX.rs index 084ba5473f9..88f4bf99a50 100644 --- a/esp-hal/src/rsa/esp32cX.rs +++ b/esp-hal/src/rsa/esp32cX.rs @@ -10,7 +10,7 @@ use crate::rsa::{ RsaMultiplication, }; -impl<'d, DM: crate::Mode> Rsa<'d, DM> { +impl Rsa<'_, DM> { /// After the RSA Accelerator is released from reset, the memory blocks /// needs to be initialized, only after that peripheral should be used. /// This function would return without an error if the memory is initialized @@ -229,7 +229,7 @@ pub mod operand_sizes { ); } -impl<'a, 'd, T: RsaMode, DM: crate::Mode, const N: usize> RsaModularExponentiation<'a, 'd, T, DM> +impl<'d, T: RsaMode, DM: crate::Mode, const N: usize> RsaModularExponentiation<'_, 'd, T, DM> where T: RsaMode, { @@ -249,7 +249,7 @@ where } } -impl<'a, 'd, T: RsaMode, DM: crate::Mode, const N: usize> RsaModularMultiplication<'a, 'd, T, DM> +impl<'d, T: RsaMode, DM: crate::Mode, const N: usize> RsaModularMultiplication<'_, 'd, T, DM> where T: RsaMode, { @@ -262,7 +262,7 @@ where } } -impl<'a, 'd, T: RsaMode + Multi, DM: crate::Mode, const N: usize> RsaMultiplication<'a, 'd, T, DM> +impl<'d, T: RsaMode + Multi, DM: crate::Mode, const N: usize> RsaMultiplication<'_, 'd, T, DM> where T: RsaMode, { diff --git a/esp-hal/src/rsa/mod.rs b/esp-hal/src/rsa/mod.rs index d71668c0df5..a92c6bb51db 100644 --- a/esp-hal/src/rsa/mod.rs +++ b/esp-hal/src/rsa/mod.rs @@ -56,9 +56,9 @@ impl<'d> Rsa<'d, crate::Blocking> { } } -impl<'d> crate::private::Sealed for Rsa<'d, crate::Blocking> {} +impl crate::private::Sealed for Rsa<'_, crate::Blocking> {} -impl<'d> InterruptConfigurable for Rsa<'d, crate::Blocking> { +impl InterruptConfigurable for Rsa<'_, crate::Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.internal_set_interrupt_handler(handler); } @@ -435,7 +435,7 @@ pub(crate) mod asynch { } } - impl<'a, 'd, T: RsaMode, const N: usize> RsaModularExponentiation<'a, 'd, T, Async> + impl RsaModularExponentiation<'_, '_, T, Async> where T: RsaMode, { @@ -454,7 +454,7 @@ pub(crate) mod asynch { } } - impl<'a, 'd, T: RsaMode, const N: usize> RsaModularMultiplication<'a, 'd, T, Async> + impl RsaModularMultiplication<'_, '_, T, Async> where T: RsaMode, { @@ -483,12 +483,12 @@ pub(crate) mod asynch { } } - impl<'a, 'd, T: RsaMode + Multi, const N: usize> RsaMultiplication<'a, 'd, T, Async> + impl RsaMultiplication<'_, '_, T, Async> where T: RsaMode, { /// Asynchronously performs an RSA multiplication operation. - pub async fn multiplication<'b, const O: usize>( + pub async fn multiplication( &mut self, operand_b: &T::InputType, outbuf: &mut T::OutputType, diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index c63c7538fa8..140e9c42c31 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -430,9 +430,9 @@ impl<'d> Rtc<'d> { .modify(|r, w| unsafe { w.bits(r.bits() | Self::RTC_DISABLE_ROM_LOG) }); } } -impl<'d> crate::private::Sealed for Rtc<'d> {} +impl crate::private::Sealed for Rtc<'_> {} -impl<'d> InterruptConfigurable for Rtc<'d> { +impl InterruptConfigurable for Rtc<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { unsafe { interrupt::bind_interrupt( diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c2.rs b/esp-hal/src/rtc_cntl/sleep/esp32c2.rs index 7fb003fd11b..ef690a704c3 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c2.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c2.rs @@ -157,7 +157,7 @@ impl WakeSource for TimerWakeupSource { } } -impl<'a, 'b> RtcioWakeupSource<'a, 'b> { +impl RtcioWakeupSource<'_, '_> { fn apply_pin(&self, pin: &mut dyn RtcPinWithResistors, level: WakeupLevel) { // The pullup/pulldown part is like in gpio_deep_sleep_wakeup_prepare let level = match level { diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c3.rs b/esp-hal/src/rtc_cntl/sleep/esp32c3.rs index 39d165ce29c..cd01c636164 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c3.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c3.rs @@ -157,7 +157,7 @@ impl WakeSource for TimerWakeupSource { } } -impl<'a, 'b> RtcioWakeupSource<'a, 'b> { +impl RtcioWakeupSource<'_, '_> { fn apply_pin(&self, pin: &mut dyn RtcPinWithResistors, level: WakeupLevel) { // The pullup/pulldown part is like in gpio_deep_sleep_wakeup_prepare let level = match level { diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index 6758ea2ec48..b230f3b1774 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -98,10 +98,10 @@ impl<'d> Sha<'d> { } } -impl<'d> crate::private::Sealed for Sha<'d> {} +impl crate::private::Sealed for Sha<'_> {} #[cfg(not(esp32))] -impl<'d> crate::InterruptConfigurable for Sha<'d> { +impl crate::InterruptConfigurable for Sha<'_> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { unsafe { crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler()); diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 6241aa2b19a..3e54ad3dd34 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -448,7 +448,7 @@ where } } -impl<'d, T> Spi<'d, T> +impl Spi<'_, T> where T: Instance, { @@ -845,7 +845,7 @@ mod dma { { } - impl<'d, M, T> core::fmt::Debug for SpiDma<'d, M, T> + impl core::fmt::Debug for SpiDma<'_, M, T> where T: InstanceDma, M: Mode, @@ -859,7 +859,7 @@ mod dma { } } - impl<'d, T> InterruptConfigurable for SpiDma<'d, Blocking, T> + impl InterruptConfigurable for SpiDma<'_, Blocking, T> where T: InstanceDma, { @@ -874,7 +874,7 @@ mod dma { } #[cfg(gdma)] - impl<'d, T> SpiDma<'d, Blocking, T> + impl SpiDma<'_, Blocking, T> where T: InstanceDma, { @@ -1074,7 +1074,7 @@ mod dma { } } - impl<'d, M, T> crate::private::Sealed for SpiDma<'d, M, T> + impl crate::private::Sealed for SpiDma<'_, M, T> where T: InstanceDma, M: Mode, @@ -1162,7 +1162,7 @@ mod dma { } } - impl<'d, M, T, Buf> Drop for SpiDmaTransfer<'d, M, Buf, T> + impl Drop for SpiDmaTransfer<'_, M, Buf, T> where T: InstanceDma, M: Mode, @@ -1180,7 +1180,7 @@ mod dma { } } - impl<'d, T, Buf> SpiDmaTransfer<'d, crate::Async, Buf, T> + impl SpiDmaTransfer<'_, crate::Async, Buf, T> where T: InstanceDma, { @@ -1485,7 +1485,7 @@ mod dma { } } - impl<'d, T> InterruptConfigurable for SpiDmaBus<'d, Blocking, T> + impl InterruptConfigurable for SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1498,7 +1498,7 @@ mod dma { } #[cfg(gdma)] - impl<'d, T> SpiDmaBus<'d, Blocking, T> + impl SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1523,14 +1523,14 @@ mod dma { } } - impl<'d, M, T> crate::private::Sealed for SpiDmaBus<'d, M, T> + impl crate::private::Sealed for SpiDmaBus<'_, M, T> where T: InstanceDma, M: Mode, { } - impl<'d, M, T> SpiDmaBus<'d, M, T> + impl SpiDmaBus<'_, M, T> where T: InstanceDma, M: Mode, @@ -1630,7 +1630,7 @@ mod dma { } } - impl<'d, M, T> SpiDmaBus<'d, M, T> + impl SpiDmaBus<'_, M, T> where T: InstanceDma, M: Mode, @@ -1699,7 +1699,7 @@ mod dma { } } - impl<'d, T> embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'d, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, crate::Blocking, T> where T: InstanceDma, { @@ -1711,7 +1711,7 @@ mod dma { } } - impl<'d, T> embedded_hal_02::blocking::spi::Write for SpiDmaBus<'d, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, crate::Blocking, T> where T: InstanceDma, { @@ -1770,7 +1770,7 @@ mod dma { } } - impl<'d, T> SpiDmaBus<'d, crate::Async, T> + impl SpiDmaBus<'_, crate::Async, T> where T: InstanceDma, { @@ -1884,7 +1884,7 @@ mod dma { } } - impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, crate::Async, T> + impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T> where T: InstanceDma, { @@ -1916,7 +1916,7 @@ mod dma { use super::*; - impl<'d, M, T> ErrorType for SpiDmaBus<'d, M, T> + impl ErrorType for SpiDmaBus<'_, M, T> where T: InstanceDma, M: Mode, @@ -1924,7 +1924,7 @@ mod dma { type Error = Error; } - impl<'d, M, T> SpiBus for SpiDmaBus<'d, M, T> + impl SpiBus for SpiDmaBus<'_, M, T> where T: InstanceDma, M: Mode, diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 97315ab6f92..0447c1870f7 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -227,7 +227,7 @@ pub mod dma { tx_chain: DescriptorChain, } - impl<'d, DmaMode, T> core::fmt::Debug for SpiDma<'d, DmaMode, T> + impl core::fmt::Debug for SpiDma<'_, DmaMode, T> where T: InstanceDma, DmaMode: Mode, @@ -237,7 +237,7 @@ pub mod dma { } } - impl<'d, DmaMode, T> DmaSupport for SpiDma<'d, DmaMode, T> + impl DmaSupport for SpiDma<'_, DmaMode, T> where T: InstanceDma, DmaMode: Mode, diff --git a/esp-hal/src/sync.rs b/esp-hal/src/sync.rs index 0b50edfba4d..6d9ccfaab32 100644 --- a/esp-hal/src/sync.rs +++ b/esp-hal/src/sync.rs @@ -248,7 +248,7 @@ pub(crate) fn lock(lock: &Lock, f: impl FnOnce() -> T) -> T { } } - impl<'a> Drop for LockGuard<'a> { + impl Drop for LockGuard<'_> { fn drop(&mut self) { unsafe { self.lock.release(self.token) }; } diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index d0ffb517c27..de0c4e4da6b 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -201,9 +201,9 @@ where } } -impl<'d, T> crate::private::Sealed for OneShotTimer<'d, T> where T: Timer {} +impl crate::private::Sealed for OneShotTimer<'_, T> where T: Timer {} -impl<'d, T> InterruptConfigurable for OneShotTimer<'d, T> +impl InterruptConfigurable for OneShotTimer<'_, T> where T: Timer, { @@ -212,7 +212,7 @@ where } } -impl<'d, T, UXX> embedded_hal_02::blocking::delay::DelayMs for OneShotTimer<'d, T> +impl embedded_hal_02::blocking::delay::DelayMs for OneShotTimer<'_, T> where T: Timer, UXX: Into, @@ -222,7 +222,7 @@ where } } -impl<'d, T, UXX> embedded_hal_02::blocking::delay::DelayUs for OneShotTimer<'d, T> +impl embedded_hal_02::blocking::delay::DelayUs for OneShotTimer<'_, T> where T: Timer, UXX: Into, @@ -232,7 +232,7 @@ where } } -impl<'d, T> embedded_hal::delay::DelayNs for OneShotTimer<'d, T> +impl embedded_hal::delay::DelayNs for OneShotTimer<'_, T> where T: Timer, { @@ -315,9 +315,9 @@ where } } -impl<'d, T> crate::private::Sealed for PeriodicTimer<'d, T> where T: Timer {} +impl crate::private::Sealed for PeriodicTimer<'_, T> where T: Timer {} -impl<'d, T> InterruptConfigurable for PeriodicTimer<'d, T> +impl InterruptConfigurable for PeriodicTimer<'_, T> where T: Timer, { @@ -326,7 +326,7 @@ where } } -impl<'d, T> embedded_hal_02::timer::CountDown for PeriodicTimer<'d, T> +impl embedded_hal_02::timer::CountDown for PeriodicTimer<'_, T> where T: Timer, { @@ -344,7 +344,7 @@ where } } -impl<'d, T> embedded_hal_02::timer::Cancel for PeriodicTimer<'d, T> +impl embedded_hal_02::timer::Cancel for PeriodicTimer<'_, T> where T: Timer, { @@ -355,7 +355,7 @@ where } } -impl<'d, T> embedded_hal_02::timer::Periodic for PeriodicTimer<'d, T> where T: Timer {} +impl embedded_hal_02::timer::Periodic for PeriodicTimer<'_, T> where T: Timer {} /// An enum of all timer types enum AnyTimerInner { diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 7ecbd9f5ec2..de70e909ec3 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -368,13 +368,13 @@ pub trait Unit { #[derive(Debug)] pub struct SpecificUnit<'d, const CHANNEL: u8>(PhantomData<&'d ()>); -impl<'d, const CHANNEL: u8> SpecificUnit<'d, CHANNEL> { +impl SpecificUnit<'_, CHANNEL> { fn new() -> Self { Self(PhantomData) } } -impl<'d, const CHANNEL: u8> Unit for SpecificUnit<'d, CHANNEL> { +impl Unit for SpecificUnit<'_, CHANNEL> { fn channel(&self) -> u8 { CHANNEL } @@ -384,7 +384,7 @@ impl<'d, const CHANNEL: u8> Unit for SpecificUnit<'d, CHANNEL> { #[derive(Debug)] pub struct AnyUnit<'d>(PhantomData<&'d ()>, u8); -impl<'d> Unit for AnyUnit<'d> { +impl Unit for AnyUnit<'_> { fn channel(&self) -> u8 { self.1 } @@ -598,13 +598,13 @@ pub trait Comparator { #[derive(Debug)] pub struct SpecificComparator<'d, const CHANNEL: u8>(PhantomData<&'d ()>); -impl<'d, const CHANNEL: u8> SpecificComparator<'d, CHANNEL> { +impl SpecificComparator<'_, CHANNEL> { fn new() -> Self { Self(PhantomData) } } -impl<'d, const CHANNEL: u8> Comparator for SpecificComparator<'d, CHANNEL> { +impl Comparator for SpecificComparator<'_, CHANNEL> { fn channel(&self) -> u8 { CHANNEL } @@ -614,7 +614,7 @@ impl<'d, const CHANNEL: u8> Comparator for SpecificComparator<'d, CHANNEL> { #[derive(Debug)] pub struct AnyComparator<'d>(PhantomData<&'d ()>, u8); -impl<'d> Comparator for AnyComparator<'d> { +impl Comparator for AnyComparator<'_> { fn channel(&self) -> u8 { self.1 } @@ -737,7 +737,7 @@ where _pd: PhantomData<(MODE, DM)>, } -impl<'d, T, DM, COMP: Comparator, UNIT: Unit> Debug for Alarm<'d, T, DM, COMP, UNIT> +impl Debug for Alarm<'_, T, DM, COMP, UNIT> where DM: Mode, { @@ -771,9 +771,7 @@ impl<'d, T, COMP: Comparator, UNIT: Unit> Alarm<'d, T, Async, COMP, UNIT> { } } -impl<'d, T, COMP: Comparator, UNIT: Unit> InterruptConfigurable - for Alarm<'d, T, Blocking, COMP, UNIT> -{ +impl InterruptConfigurable for Alarm<'_, T, Blocking, COMP, UNIT> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { self.comparator.set_interrupt_handler(handler) } @@ -851,14 +849,12 @@ where } } -impl<'d, T, DM, COMP: Comparator, UNIT: Unit> crate::private::Sealed - for Alarm<'d, T, DM, COMP, UNIT> -where - DM: Mode, +impl crate::private::Sealed for Alarm<'_, T, DM, COMP, UNIT> where + DM: Mode { } -impl<'d, T, DM, COMP: Comparator, UNIT: Unit> super::Timer for Alarm<'d, T, DM, COMP, UNIT> +impl super::Timer for Alarm<'_, T, DM, COMP, UNIT> where DM: Mode, { @@ -996,7 +992,7 @@ where } } -impl<'d, T, DM, COMP: Comparator, UNIT: Unit> Peripheral for Alarm<'d, T, DM, COMP, UNIT> +impl Peripheral for Alarm<'_, T, DM, COMP, UNIT> where DM: Mode, { @@ -1063,7 +1059,7 @@ mod asynch { } } - impl<'a, COMP: Comparator, UNIT: Unit> core::future::Future for AlarmFuture<'a, COMP, UNIT> { + impl core::future::Future for AlarmFuture<'_, COMP, UNIT> { type Output = (); fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { @@ -1077,8 +1073,8 @@ mod asynch { } } - impl<'d, COMP: Comparator, UNIT: Unit> embedded_hal_async::delay::DelayNs - for Alarm<'d, Target, crate::Async, COMP, UNIT> + impl embedded_hal_async::delay::DelayNs + for Alarm<'_, Target, crate::Async, COMP, UNIT> { async fn delay_ns(&mut self, nanos: u32) { self.set_target( @@ -1180,13 +1176,13 @@ pub mod etm { } } - impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed - for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> + impl crate::private::Sealed + for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT> { } - impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent - for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> + impl crate::etm::EtmEvent + for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT> { fn id(&self) -> u8 { 50 + self.alarm.comparator.channel() diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 27818ed8f14..1409e162066 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -1232,7 +1232,7 @@ mod asynch { } } - impl<'a, T> core::future::Future for TimerFuture<'a, T> + impl core::future::Future for TimerFuture<'_, T> where T: Instance, { @@ -1250,7 +1250,7 @@ mod asynch { } } - impl<'a, T> Drop for TimerFuture<'a, T> + impl Drop for TimerFuture<'_, T> where T: Instance, { diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 705b7a60ab2..12f3ffd4e45 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -1444,7 +1444,7 @@ unsafe fn copy_to_data_register(dest: *mut u32, src: &[u8]) { } } -impl<'d, DM, T> embedded_hal_02::can::Can for Twai<'d, DM, T> +impl embedded_hal_02::can::Can for Twai<'_, DM, T> where T: Instance, DM: crate::Mode, @@ -1468,7 +1468,7 @@ where } } -impl<'d, DM, T> embedded_can::nb::Can for Twai<'d, DM, T> +impl embedded_can::nb::Can for Twai<'_, DM, T> where T: Instance, DM: crate::Mode, diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index ea604f8767d..a2247bacab6 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -106,7 +106,7 @@ pub struct UsbSerialJtagRx<'d, M> { phantom: PhantomData<(&'d mut USB_DEVICE, M)>, } -impl<'d, M> UsbSerialJtagTx<'d, M> +impl UsbSerialJtagTx<'_, M> where M: Mode, { @@ -183,7 +183,7 @@ where } } -impl<'d, M> UsbSerialJtagRx<'d, M> +impl UsbSerialJtagRx<'_, M> where M: Mode, { @@ -265,9 +265,9 @@ impl<'d> UsbSerialJtag<'d, Blocking> { } } -impl<'d> crate::private::Sealed for UsbSerialJtag<'d, Blocking> {} +impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {} -impl<'d> InterruptConfigurable for UsbSerialJtag<'d, Blocking> { +impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { self.inner_set_interrupt_handler(handler); } @@ -670,7 +670,7 @@ mod asynch { phantom: PhantomData<&'d mut USB_DEVICE>, } - impl<'d> UsbSerialJtagWriteFuture<'d> { + impl UsbSerialJtagWriteFuture<'_> { pub fn new() -> Self { // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT // interrupt @@ -692,7 +692,7 @@ mod asynch { } } - impl<'d> core::future::Future for UsbSerialJtagWriteFuture<'d> { + impl core::future::Future for UsbSerialJtagWriteFuture<'_> { type Output = (); fn poll( @@ -713,7 +713,7 @@ mod asynch { phantom: PhantomData<&'d mut USB_DEVICE>, } - impl<'d> UsbSerialJtagReadFuture<'d> { + impl UsbSerialJtagReadFuture<'_> { pub fn new() -> Self { // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT // interrupt @@ -735,7 +735,7 @@ mod asynch { } } - impl<'d> core::future::Future for UsbSerialJtagReadFuture<'d> { + impl core::future::Future for UsbSerialJtagReadFuture<'_> { type Output = (); fn poll( diff --git a/esp-ieee802154/src/lib.rs b/esp-ieee802154/src/lib.rs index 810056b226f..4d0d43f9f6c 100644 --- a/esp-ieee802154/src/lib.rs +++ b/esp-ieee802154/src/lib.rs @@ -305,7 +305,7 @@ impl<'a> Ieee802154<'a> { } } -impl<'a> Drop for Ieee802154<'a> { +impl Drop for Ieee802154<'_> { fn drop(&mut self) { self.clear_tx_done_callback(); self.clear_tx_done_callback_fn(); diff --git a/esp-println/Cargo.toml b/esp-println/Cargo.toml index 75f7c09d50a..06a0cba29f6 100644 --- a/esp-println/Cargo.toml +++ b/esp-println/Cargo.toml @@ -52,3 +52,6 @@ defmt-espflash = ["dep:defmt", "defmt?/encoding-rzcobs"] # logging sub-features colors = [] + +[lints.rust] +static_mut_refs = "allow" diff --git a/esp-wifi/src/ble/btdm.rs b/esp-wifi/src/ble/btdm.rs index ba84cf1a54c..aa601f69de8 100644 --- a/esp-wifi/src/ble/btdm.rs +++ b/esp-wifi/src/ble/btdm.rs @@ -368,6 +368,7 @@ pub(crate) fn ble_init() { unsafe { (*addr_of_mut!(HCI_OUT_COLLECTOR)).write(HciOutCollector::new()); // turn on logging + #[allow(static_mut_refs)] #[cfg(feature = "sys-logs")] { extern "C" { diff --git a/esp-wifi/src/ble/controller/mod.rs b/esp-wifi/src/ble/controller/mod.rs index 1d639b469e0..de26dfb51b0 100644 --- a/esp-wifi/src/ble/controller/mod.rs +++ b/esp-wifi/src/ble/controller/mod.rs @@ -211,7 +211,7 @@ pub mod asynch { } } - impl<'d> Transport for BleConnector<'d> { + impl Transport for BleConnector<'_> { /// Read a complete HCI packet into the rx buffer async fn read<'a>( &self, diff --git a/esp-wifi/src/ble/npl.rs b/esp-wifi/src/ble/npl.rs index a7d34884f6d..6b755ee6857 100644 --- a/esp-wifi/src/ble/npl.rs +++ b/esp-wifi/src/ble/npl.rs @@ -1009,6 +1009,7 @@ pub(crate) fn ble_init() { (*addr_of_mut!(HCI_OUT_COLLECTOR)).write(HciOutCollector::new()); // turn on logging + #[allow(static_mut_refs)] #[cfg(all(feature = "sys-logs", esp32c2))] { extern "C" { diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index c307f6c61bd..3d92900e855 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -3271,7 +3271,7 @@ mod asynch { use super::*; // TODO assumes STA mode only - impl<'d> WifiController<'d> { + impl WifiController<'_> { /// Async version of [`crate::wifi::WifiController`]'s `scan_n` method pub async fn scan_n( &mut self, diff --git a/examples/src/bin/ram.rs b/examples/src/bin/ram.rs index c8c802fcc9b..70c14731ab8 100644 --- a/examples/src/bin/ram.rs +++ b/examples/src/bin/ram.rs @@ -13,6 +13,7 @@ //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +#![allow(static_mut_refs)] #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index 02aa7c8f8f3..ad0e92e812e 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -11,6 +11,7 @@ //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/ble esp-wifi/coex //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +#![allow(static_mut_refs)] #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 3214804fa88..6659ed60451 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -13,6 +13,7 @@ //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 +#![allow(static_mut_refs)] #![no_std] #![no_main] From 111ae93cc55abefaf9a61049889baab91850abe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 1 Nov 2024 11:50:39 +0100 Subject: [PATCH 16/67] Fix, clean up and type-erase parallel i2s (#2436) * Fix, clean up and type-erase parallel i2s * Fix capitalization * Add link to esp-idf code that offsets by 8 --- esp-hal/CHANGELOG.md | 2 +- esp-hal/src/i2s.rs | 6 +- esp-hal/src/i2s_parallel.rs | 368 +++++++++++++++++++----------------- esp-hal/src/lib.rs | 2 +- 4 files changed, 200 insertions(+), 178 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 479f60b9557..5f2dbf8ec94 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373) - `Cpu::COUNT` and `Cpu::current()` (#2411) - `UartInterrupt` and related functions (#2406) -- I2S Parallel output driver for esp32. (#2348) +- I2S Parallel output driver for ESP32. (#2348, #2436) - Add an option to configure `WDT` action (#2330) ### Changed diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index 6b9f44ad135..d17e87a8859 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -128,12 +128,12 @@ pub enum I2sInterrupt { } #[cfg(any(esp32, esp32s2, esp32s3))] -const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; +pub(crate) const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; #[cfg(any(esp32c3, esp32c6, esp32h2))] -const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 9; +pub(crate) const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 9; -const I2S_LL_MCLK_DIVIDER_MAX: usize = (1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1; +pub(crate) const I2S_LL_MCLK_DIVIDER_MAX: usize = (1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1; /// Data types that the I2S peripheral can work with. pub trait AcceptedWord: crate::private::Sealed {} diff --git a/esp-hal/src/i2s_parallel.rs b/esp-hal/src/i2s_parallel.rs index bb4790e8953..556ccc00ecb 100644 --- a/esp-hal/src/i2s_parallel.rs +++ b/esp-hal/src/i2s_parallel.rs @@ -41,7 +41,6 @@ use core::{ }; use fugit::HertzU32; -use private::{calculate_clock, I2sClockDividers, TxPins}; use crate::{ dma::{ @@ -51,6 +50,7 @@ use crate::{ DmaChannelConvert, DmaEligible, DmaError, + DmaPeripheral, DmaTxBuffer, PeripheralMarker, Tx, @@ -61,10 +61,18 @@ use crate::{ }, peripheral::{Peripheral, PeripheralRef}, peripherals::{i2s0::RegisterBlock, I2S0, I2S1}, + private, system::PeripheralClockControl, + Async, Mode, }; +#[doc(hidden)] +pub trait TxPins<'d> { + fn bus_width(&self) -> u8; + fn configure(&mut self, instance: impl Peripheral

); +} + /// Represents a group of 16 output pins configured for 16-bit parallel data /// transmission. pub struct TxSixteenBits<'d> { @@ -106,17 +114,17 @@ impl<'d> TxSixteenBits<'d> { } } -impl<'d> TxPins for TxSixteenBits<'d> { - fn bits(&self) -> u8 { - 16 +impl<'d> TxPins<'d> for TxSixteenBits<'d> { + fn bus_width(&self) -> u8 { + self.pins.len() as u8 } - fn configure(&mut self, instance: &PeripheralRef<'_, I>) { - use crate::private::Internal; - let bits: u8 = self.bits(); + fn configure(&mut self, instance: impl Peripheral

) { + crate::into_ref!(instance); + let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), Internal); + pin.set_to_push_pull_output(private::Internal); + pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); } } } @@ -140,14 +148,7 @@ impl<'d> TxEightBits<'d> { pin_6: impl Peripheral

+ 'd, pin_7: impl Peripheral

+ 'd, ) -> Self { - crate::into_mapped_ref!(pin_0); - crate::into_mapped_ref!(pin_1); - crate::into_mapped_ref!(pin_2); - crate::into_mapped_ref!(pin_3); - crate::into_mapped_ref!(pin_4); - crate::into_mapped_ref!(pin_5); - crate::into_mapped_ref!(pin_6); - crate::into_mapped_ref!(pin_7); + crate::into_mapped_ref!(pin_0, pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7); Self { pins: [pin_0, pin_1, pin_2, pin_3, pin_4, pin_5, pin_6, pin_7], @@ -155,40 +156,66 @@ impl<'d> TxEightBits<'d> { } } -impl<'d> TxPins for TxEightBits<'d> { - fn bits(&self) -> u8 { - 8 +impl<'d> TxPins<'d> for TxEightBits<'d> { + fn bus_width(&self) -> u8 { + self.pins.len() as u8 } - fn configure(&mut self, instance: &PeripheralRef<'_, I>) { - use crate::private::Internal; - let bits: u8 = self.bits(); + fn configure(&mut self, instance: impl Peripheral

) { + crate::into_ref!(instance); + let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), Internal); + pin.set_to_push_pull_output(private::Internal); + pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); } } } /// I2S Parallel Interface -pub struct I2sParallel<'d, I: Instance, DM: Mode> { +pub struct I2sParallel<'d, DM, I = AnyI2s> +where + DM: Mode, + I: Instance, +{ instance: PeripheralRef<'d, I>, - tx_channel: ChannelTx<'d, ::Dma>, + tx_channel: ChannelTx<'d, I::Dma>, mode: PhantomData, } -impl<'d, I: Instance, DM: Mode> I2sParallel<'d, I, DM> { +impl<'d, DM> I2sParallel<'d, DM> +where + DM: Mode, +{ /// Create a new I2S Parallel Interface - pub fn new( + pub fn new( + i2s: impl Peripheral

+ 'd, + channel: Channel<'d, CH, DM>, + frequency: impl Into, + pins: impl TxPins<'d>, + clock_pin: impl Peripheral

+ 'd, + ) -> Self + where + CH: DmaChannelConvert<::Dma>, + { + Self::new_typed(i2s.map_into(), channel, frequency, pins, clock_pin) + } +} + +impl<'d, I, DM> I2sParallel<'d, DM, I> +where + I: Instance, + DM: Mode, +{ + /// Create a new I2S Parallel Interface + pub fn new_typed( i2s: impl Peripheral

+ 'd, channel: Channel<'d, CH, DM>, frequency: impl Into, - mut pins: P, - clock_pin: impl Peripheral

+ 'd, + mut pins: impl TxPins<'d>, + clock_pin: impl Peripheral

+ 'd, ) -> Self where CH: DmaChannelConvert, - P: TxPins, { crate::into_ref!(i2s); crate::into_mapped_ref!(clock_pin); @@ -196,15 +223,15 @@ impl<'d, I: Instance, DM: Mode> I2sParallel<'d, I, DM> { channel.runtime_ensure_compatible(&i2s); let channel = channel.degrade(); - PeripheralClockControl::reset(i2s.get_peripheral()); - PeripheralClockControl::enable(i2s.get_peripheral()); + PeripheralClockControl::reset(i2s.peripheral()); + PeripheralClockControl::enable(i2s.peripheral()); // configure the I2S peripheral for parallel mode - i2s.setup(frequency, pins.bits()); + i2s.setup(frequency, pins.bus_width()); // setup the clock pin - clock_pin.set_to_push_pull_output(crate::private::Internal); - clock_pin.connect_peripheral_to_output(i2s.ws_signal(), crate::private::Internal); + clock_pin.set_to_push_pull_output(private::Internal); + clock_pin.connect_peripheral_to_output(i2s.ws_signal(), private::Internal); - pins.configure(&i2s); + pins.configure(i2s.reborrow()); Self { instance: i2s, tx_channel: channel.tx, @@ -216,12 +243,12 @@ impl<'d, I: Instance, DM: Mode> I2sParallel<'d, I, DM> { pub fn send( mut self, mut data: BUF, - ) -> Result, (DmaError, Self, BUF)> { + ) -> Result, (DmaError, Self, BUF)> { self.instance.tx_reset(); self.instance.tx_fifo_reset(); let result = unsafe { self.tx_channel - .prepare_transfer(self.instance.get_dma_peripheral(), &mut data) + .prepare_transfer(self.instance.dma_peripheral(), &mut data) } .and_then(|_| self.tx_channel.start_transfer()); if let Err(err) = result { @@ -238,17 +265,17 @@ impl<'d, I: Instance, DM: Mode> I2sParallel<'d, I, DM> { /// Represents an ongoing (or potentially finished) transfer using the i2s /// parallel interface -pub struct I2sParallelTransfer<'d, I, BUF, DM> +pub struct I2sParallelTransfer<'d, BUF, DM, I = AnyI2s> where I: Instance, BUF: DmaTxBuffer, DM: Mode, { - i2s: ManuallyDrop>, + i2s: ManuallyDrop>, buf_view: ManuallyDrop, } -impl<'d, I, BUF, DM> I2sParallelTransfer<'d, I, BUF, DM> +impl<'d, I, BUF, DM> I2sParallelTransfer<'d, BUF, DM, I> where I: Instance, BUF: DmaTxBuffer, @@ -260,7 +287,7 @@ where } /// Wait for the transfer to finish - pub fn wait(mut self) -> (I2sParallel<'d, I, DM>, BUF) { + pub fn wait(mut self) -> (I2sParallel<'d, DM, I>, BUF) { self.i2s.instance.tx_wait_done(); let i2s = unsafe { ManuallyDrop::take(&mut self.i2s) }; let view = unsafe { ManuallyDrop::take(&mut self.buf_view) }; @@ -273,7 +300,7 @@ where } } -impl<'d, I, BUF> I2sParallelTransfer<'d, I, BUF, crate::Async> +impl<'d, I, BUF> I2sParallelTransfer<'d, BUF, Async, I> where I: Instance, BUF: DmaTxBuffer, @@ -284,7 +311,7 @@ where } } -impl<'d, I, BUF, DM> Deref for I2sParallelTransfer<'d, I, BUF, DM> +impl<'d, I, BUF, DM> Deref for I2sParallelTransfer<'d, BUF, DM, I> where I: Instance, BUF: DmaTxBuffer, @@ -297,7 +324,7 @@ where } } -impl<'d, I, BUF, DM> DerefMut for I2sParallelTransfer<'d, I, BUF, DM> +impl<'d, I, BUF, DM> DerefMut for I2sParallelTransfer<'d, BUF, DM, I> where I: Instance, BUF: DmaTxBuffer, @@ -308,7 +335,7 @@ where } } -impl<'d, I, BUF, DM> Drop for I2sParallelTransfer<'d, I, BUF, DM> +impl<'d, I, BUF, DM> Drop for I2sParallelTransfer<'d, BUF, DM, I> where I: Instance, BUF: DmaTxBuffer, @@ -327,108 +354,83 @@ where } } -mod private { - use fugit::HertzU32; - - use crate::peripheral::PeripheralRef; - - pub trait TxPins { - fn bits(&self) -> u8; - fn configure(&mut self, instance: &PeripheralRef<'_, I>); - } - - #[derive(Debug)] - pub struct I2sClockDividers { - pub mclk_divider: u32, - pub bclk_divider: u32, - pub denominator: u32, - pub numerator: u32, - } - - #[cfg(any(esp32, esp32s2))] - const I2S_LL_MCLK_DIVIDER_BIT_WIDTH: usize = 6; - - const I2S_LL_MCLK_DIVIDER_MAX: usize = (1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1; - - pub fn calculate_clock( - sample_rate: impl Into, - data_bits: u8, - ) -> I2sClockDividers { - // this loosely corresponds to `i2s_std_calculate_clock` and - // `i2s_ll_tx_set_mclk` in esp-idf - // - // main difference is we are using fixed-point arithmetic here - // plus adjusted for parallel interface clocking - - let sclk = crate::soc::constants::I2S_SCLK; // for now it's fixed 160MHz and 96MHz (just H2) - - let rate_hz: HertzU32 = sample_rate.into(); - let rate = rate_hz.raw(); - - let mclk = rate * 2; - let bclk_divider: u32 = if data_bits == 8 { 2 } else { 1 }; - let mut mclk_divider = sclk / mclk; - - let mut ma: u32; - let mut mb: u32; - let mut denominator: u32 = 0; - let mut numerator: u32 = 0; - - let freq_diff = sclk.abs_diff(mclk * mclk_divider); - - if freq_diff != 0 { - let decimal = freq_diff as u64 * 10000 / mclk as u64; - // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / - // 126.0 - if decimal > 1250000 / 126 { - mclk_divider += 1; - } else { - let mut min: u32 = !0; - - for a in 2..=I2S_LL_MCLK_DIVIDER_MAX { - let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000; - ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32; - mb = (mclk as u64 * (b / 10000)) as u32; +#[doc(hidden)] +#[derive(Debug)] +pub struct I2sClockDividers { + pub mclk_divider: u32, + pub bclk_divider: u32, + pub denominator: u32, + pub numerator: u32, +} - if ma == mb { - denominator = a as u32; - numerator = (b / 10000) as u32; - break; - } +fn calculate_clock(sample_rate: impl Into, data_bits: u8) -> I2sClockDividers { + // this loosely corresponds to `i2s_std_calculate_clock` and + // `i2s_ll_tx_set_mclk` in esp-idf + // + // main difference is we are using fixed-point arithmetic here + // plus adjusted for parallel interface clocking + + let sclk = crate::soc::constants::I2S_SCLK; // for now it's fixed 160MHz and 96MHz (just H2) + + let rate_hz: HertzU32 = sample_rate.into(); + let rate = rate_hz.raw(); + + let mclk = rate * 2; + let bclk_divider: u32 = if data_bits == 8 { 2 } else { 1 }; + let mut mclk_divider = sclk / mclk; + + let mut ma: u32; + let mut mb: u32; + let mut denominator: u32 = 0; + let mut numerator: u32 = 0; + + let freq_diff = sclk.abs_diff(mclk * mclk_divider); + + if freq_diff != 0 { + let decimal = freq_diff as u64 * 10000 / mclk as u64; + // Carry bit if the decimal is greater than 1.0 - 1.0 / (63.0 * 2) = 125.0 / + // 126.0 + if decimal > 1250000 / 126 { + mclk_divider += 1; + } else { + let mut min: u32 = !0; + + for a in 2..=crate::i2s::I2S_LL_MCLK_DIVIDER_MAX { + let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000; + ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32; + mb = (mclk as u64 * (b / 10000)) as u32; + + if ma == mb { + denominator = a as u32; + numerator = (b / 10000) as u32; + break; + } - if mb.abs_diff(ma) < min { - denominator = a as u32; - numerator = b as u32; - min = mb.abs_diff(ma); - } + if mb.abs_diff(ma) < min { + denominator = a as u32; + numerator = b as u32; + min = mb.abs_diff(ma); } } } - - I2sClockDividers { - mclk_divider, - bclk_divider, - denominator, - numerator, - } } -} -#[allow(missing_docs)] -pub trait RegBlock: PeripheralMarker + DmaEligible { - fn register_block(&self) -> &'static RegisterBlock; + I2sClockDividers { + mclk_divider, + bclk_divider, + denominator, + numerator, + } } -#[allow(missing_docs)] -pub trait Signals { - fn get_peripheral(&self) -> crate::system::Peripheral; - fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral; +#[doc(hidden)] +pub trait Instance: + Peripheral

+ PeripheralMarker + DmaEligible + Into + 'static +{ + fn register_block(&self) -> &RegisterBlock; fn ws_signal(&self) -> OutputSignal; fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal; -} -#[allow(missing_docs)] -pub trait Instance: Signals + RegBlock { fn rx_reset(&self) { let r = self.register_block(); r.conf().modify(|_, w| w.rx_reset().set_bit()); @@ -607,32 +609,24 @@ pub trait Instance: Signals + RegBlock { } } -impl RegBlock for I2S0 { - fn register_block(&self) -> &'static RegisterBlock { +impl Instance for I2S0 { + fn register_block(&self) -> &RegisterBlock { unsafe { &*I2S0::PTR.cast::() } } -} - -impl Signals for I2S0 { - fn get_peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::I2s0 - } - - fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral { - crate::dma::DmaPeripheral::I2s0 - } fn ws_signal(&self) -> OutputSignal { OutputSignal::I2S0O_WS } fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal { + assert!( + bits == 8 || bits == 16, + "Number of bits must be 8 or 16, got {}", + bits + ); + // signals for 8bit and 16bit both start at an offset of 8 for I2S0 - let offset = match bits { - 8 => 8, - 16 => 8, - _ => panic!("Invalid number of bits"), - }; - match i + offset { + // https://github.com/espressif/esp-idf/blob/9106c43accd9f5e75379f62f12597677213f5023/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c#L701 + match i + 8 { 0 => OutputSignal::I2S0O_DATA_0, 1 => OutputSignal::I2S0O_DATA_1, 2 => OutputSignal::I2S0O_DATA_2, @@ -657,32 +651,29 @@ impl Signals for I2S0 { 21 => OutputSignal::I2S0O_DATA_21, 22 => OutputSignal::I2S0O_DATA_22, 23 => OutputSignal::I2S0O_DATA_23, - _ => panic!("Invalid I2S0 Dout pin"), + other => panic!("Invalid I2S0 Dout pin {}", other), } } } -impl Instance for I2S0 {} -impl RegBlock for I2S1 { - fn register_block(&self) -> &'static RegisterBlock { +impl Instance for I2S1 { + fn register_block(&self) -> &RegisterBlock { unsafe { &*I2S1::PTR.cast::() } } -} -impl Signals for I2S1 { - fn get_peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::I2s1 - } - fn get_dma_peripheral(&self) -> crate::dma::DmaPeripheral { - crate::dma::DmaPeripheral::I2s1 - } fn ws_signal(&self) -> OutputSignal { OutputSignal::I2S1O_WS } fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal { - // Because of... reasons... the 16-bit values for i2s1 appear on d8...d23 - let offset = if bits == 16 { 8 } else { 0 }; - match i + offset { + assert!( + bits == 8 || bits == 16, + "Number of bits must be 8 or 16, got {}", + bits + ); + + // signals for 8bit and 16bit both start at an offset of 8 for I2S1 + // https://github.com/espressif/esp-idf/blob/9106c43accd9f5e75379f62f12597677213f5023/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c#L701 + match i + 8 { 0 => OutputSignal::I2S1O_DATA_0, 1 => OutputSignal::I2S1O_DATA_1, 2 => OutputSignal::I2S1O_DATA_2, @@ -707,8 +698,39 @@ impl Signals for I2S1 { 21 => OutputSignal::I2S1O_DATA_21, 22 => OutputSignal::I2S1O_DATA_22, 23 => OutputSignal::I2S1O_DATA_23, - _ => panic!("Invalid I2S1 Dout pin"), + other => panic!("Invalid I2S1 Dout pin {}", other), + } + } +} + +crate::any_peripheral! { + /// Any SPI peripheral. + pub peripheral AnyI2s { + I2s0(crate::peripherals::I2S0), + I2s1(crate::peripherals::I2S1), + } +} + +impl DmaEligible for AnyI2s { + type Dma = crate::dma::AnyI2sDmaChannel; + + fn dma_peripheral(&self) -> DmaPeripheral { + match &self.0 { + AnyI2sInner::I2s0(_) => DmaPeripheral::I2s0, + AnyI2sInner::I2s1(_) => DmaPeripheral::I2s1, + } + } +} + +impl Instance for AnyI2s { + delegate::delegate! { + to match &self.0 { + AnyI2sInner::I2s0(i2s) => i2s, + AnyI2sInner::I2s1(i2s) => i2s, + } { + fn register_block(&self) -> &RegisterBlock; + fn ws_signal(&self) -> OutputSignal; + fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal ; } } } -impl Instance for I2S1 {} diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 15658f6f5ca..de8b0c6c861 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -191,7 +191,7 @@ pub mod hmac; pub mod i2c; #[cfg(any(i2s0, i2s1))] pub mod i2s; -#[cfg(all(esp32, any(i2s0, i2s1)))] +#[cfg(esp32)] pub mod i2s_parallel; #[cfg(any(dport, interrupt_core0, interrupt_core1))] pub mod interrupt; From b953f178b8a5b1e43209c698c825d8b627cc1638 Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Sat, 2 Nov 2024 16:07:40 +0000 Subject: [PATCH 17/67] Add check owner support to DMA buffers (#2337) * Add check owner support to DMA buffers * More docs * Explicit check owner bit setting --------- Co-authored-by: Dominic Fischer --- esp-hal/src/dma/buffers.rs | 47 +++++++++++++++++++++++++++++++++++++- esp-hal/src/dma/gdma.rs | 12 ++++++++++ esp-hal/src/dma/mod.rs | 8 +++++++ esp-hal/src/dma/pdma.rs | 26 +++++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/esp-hal/src/dma/buffers.rs b/esp-hal/src/dma/buffers.rs index b3f2d43351f..84b34345f0a 100644 --- a/esp-hal/src/dma/buffers.rs +++ b/esp-hal/src/dma/buffers.rs @@ -23,7 +23,34 @@ pub struct Preparation { /// but RX transfers require all descriptors to have buffer pointers and /// sizes that are a multiple of 4 (word aligned). pub(super) is_burstable: bool, - // alignment, check_owner, etc. + + /// Configures the "check owner" feature of the DMA channel. + /// + /// Most DMA channels allow software to configure whether the hardware + /// checks that [DmaDescriptor::owner] is set to [Owner::Dma] before + /// consuming the descriptor. If this check fails, the channel stops + /// operating and fires + /// [DmaRxInterrupt::DescriptorError]/[DmaTxInterrupt::DescriptorError]. + /// + /// This field allows buffer implementation to configure this behaviour. + /// - `Some(true)`: DMA channel must check the owner bit. + /// - `Some(false)`: DMA channel must NOT check the owner bit. + /// - `None`: DMA channel should check the owner bit if it is supported. + /// + /// Some buffer implementations may require that the DMA channel performs + /// this check before consuming the descriptor to ensure correct + /// behaviour. e.g. To prevent wrap-around in a circular transfer. + /// + /// Some buffer implementations may require that the DMA channel does NOT + /// perform this check as the ownership bit will not be set before the + /// channel tries to consume the descriptor. + /// + /// Most implementations won't have any such requirements and will work + /// correctly regardless of whether the DMA channel checks or not. + /// + /// Note: If the DMA channel doesn't support the provided option, + /// preparation will fail. + pub(super) check_owner: Option, } /// [DmaTxBuffer] is a DMA descriptor + memory combo that can be used for @@ -303,6 +330,7 @@ unsafe impl DmaTxBuffer for DmaTxBuf { block_size: self.block_size, // This is TX, the DMA channel is free to do a burst transfer. is_burstable: true, + check_owner: None, } } @@ -453,6 +481,7 @@ unsafe impl DmaRxBuffer for DmaRxBuf { // In the future, it could either enforce the alignment or calculate if the alignment // requirements happen to be met. is_burstable: false, + check_owner: None, } } @@ -580,6 +609,7 @@ unsafe impl DmaTxBuffer for DmaRxTxBuf { // This is TX, the DMA channel is free to do a burst transfer. is_burstable: true, + check_owner: None, } } @@ -611,6 +641,7 @@ unsafe impl DmaRxBuffer for DmaRxTxBuf { // DmaRxTxBuf doesn't currently enforce the alignment requirements required for // bursting. is_burstable: false, + check_owner: None, } } @@ -751,6 +782,12 @@ unsafe impl DmaRxBuffer for DmaRxStreamBuf { // DmaRxStreamBuf doesn't currently enforce the alignment requirements required for // bursting. is_burstable: false, + + // Whilst we give ownership of the descriptors the DMA, the correctness of this buffer + // implementation doesn't rely on the DMA checking for descriptor ownership. + // No descriptor is added back to the end of the stream before it's ready for the DMA + // to consume it. + check_owner: None, } } @@ -958,6 +995,10 @@ unsafe impl DmaTxBuffer for EmptyBuf { // This is TX, the DMA channel is free to do a burst transfer. is_burstable: true, + + // As we don't give ownership of the descriptor to the DMA, it's important that the DMA + // channel does *NOT* check for ownership, otherwise the channel will return an error. + check_owner: Some(false), } } @@ -985,6 +1026,10 @@ unsafe impl DmaRxBuffer for EmptyBuf { // As much as bursting is meaningless here, the descriptor does meet the requirements. is_burstable: true, + + // As we don't give ownership of the descriptor to the DMA, it's important that the DMA + // channel does *NOT* check for ownership, otherwise the channel will return an error. + check_owner: Some(false), } } diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 11c0b624884..0eac232c8f0 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -142,6 +142,12 @@ impl RegisterAccess for ChannelTxImpl { .modify(|_, w| w.outlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + self.ch() + .out_conf1() + .modify(|_, w| w.out_check_owner().bit(check_owner.unwrap_or(true))); + } + #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) { self.ch() @@ -327,6 +333,12 @@ impl RegisterAccess for ChannelRxImpl { .modify(|_, w| w.inlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + self.ch() + .in_conf1() + .modify(|_, w| w.in_check_owner().bit(check_owner.unwrap_or(true))); + } + #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) { self.ch() diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index bd2754cf715..a956ab1dee5 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1743,6 +1743,8 @@ where self.rx_impl .set_burst_mode(self.burst_mode && preparation.is_burstable); + self.rx_impl.set_check_owner(preparation.check_owner); + compiler_fence(core::sync::atomic::Ordering::SeqCst); self.rx_impl.clear_all(); @@ -1965,6 +1967,8 @@ where self.tx_impl .set_burst_mode(self.burst_mode && preparation.is_burstable); + self.tx_impl.set_check_owner(preparation.check_owner); + compiler_fence(core::sync::atomic::Ordering::SeqCst); self.tx_impl.clear_all(); @@ -2058,6 +2062,10 @@ pub trait RegisterAccess: crate::private::Sealed { /// Mount a new descriptor. fn restart(&self); + /// Configure the bit to enable checking the owner attribute of the + /// descriptor. + fn set_check_owner(&self, check_owner: Option); + #[cfg(esp32s3)] fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize); diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index ce037bb145b..56941dd13dc 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -84,6 +84,12 @@ impl> RegisterAccess for SpiDma .modify(|_, w| w.outlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + if check_owner == Some(true) { + panic!("SPI DMA does not support checking descriptor ownership"); + } + } + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { self.0.is_compatible_with(peripheral) } @@ -222,6 +228,12 @@ impl> RegisterAccess for SpiDma .modify(|_, w| w.inlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + if check_owner == Some(true) { + panic!("SPI DMA does not support checking descriptor ownership"); + } + } + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { self.0.is_compatible_with(peripheral) } @@ -506,6 +518,13 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.outlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + let reg_block = self.0.register_block(); + reg_block + .lc_conf() + .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true))); + } + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { self.0.is_compatible_with(peripheral) } @@ -655,6 +674,13 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.inlink_restart().set_bit()); } + fn set_check_owner(&self, check_owner: Option) { + let reg_block = self.0.register_block(); + reg_block + .lc_conf() + .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true))); + } + fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { self.0.is_compatible_with(peripheral) } From 05f2ee5a72551a49ab17559153cdd61f6caeeba6 Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:38:46 +0000 Subject: [PATCH 18/67] Allow users to create DMA `Preparation`s (#2455) Co-authored-by: Dominic Fischer --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/dma/buffers.rs | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 5f2dbf8ec94..f05e201b644 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Circular DMA transfers now correctly error, `available` returns `Result` now (#2409) - Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442) - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) +- Allow users to create DMA `Preparation`s (#2455) ### Fixed diff --git a/esp-hal/src/dma/buffers.rs b/esp-hal/src/dma/buffers.rs index 84b34345f0a..c00b9c46912 100644 --- a/esp-hal/src/dma/buffers.rs +++ b/esp-hal/src/dma/buffers.rs @@ -7,11 +7,12 @@ use crate::soc::is_slice_in_psram; /// Holds all the information needed to configure a DMA channel for a transfer. pub struct Preparation { - pub(super) start: *mut DmaDescriptor, + /// The descriptor the DMA will start from. + pub start: *mut DmaDescriptor, - /// block size for PSRAM transfers + /// Block size for PSRAM transfers #[cfg_attr(not(esp32s3), allow(dead_code))] - pub(super) block_size: Option, + pub block_size: Option, /// Specifies whether descriptor linked list specified in `start` conforms /// to the alignment requirements required to enable burst transfers. @@ -22,7 +23,7 @@ pub struct Preparation { /// There are no additional alignment requirements for TX burst transfers, /// but RX transfers require all descriptors to have buffer pointers and /// sizes that are a multiple of 4 (word aligned). - pub(super) is_burstable: bool, + pub is_burstable: bool, /// Configures the "check owner" feature of the DMA channel. /// @@ -50,7 +51,7 @@ pub struct Preparation { /// /// Note: If the DMA channel doesn't support the provided option, /// preparation will fail. - pub(super) check_owner: Option, + pub check_owner: Option, } /// [DmaTxBuffer] is a DMA descriptor + memory combo that can be used for From f9ba299f2ef555a3cbd48539150a494737478fba Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:50:44 +0000 Subject: [PATCH 19/67] Mark `DmaDescriptor`s as Send (#2456) Co-authored-by: Dominic Fischer --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/dma/mod.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f05e201b644..d24d3bb079d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `UartInterrupt` and related functions (#2406) - I2S Parallel output driver for ESP32. (#2348, #2436) - Add an option to configure `WDT` action (#2330) +- `DmaDescriptor` is now `Send` (#2456) ### Changed diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index a956ab1dee5..389b1aceaae 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -351,6 +351,11 @@ impl DmaDescriptor { } } +// The pointers in the descriptor can be Sent. +// Marking this Send also allows DmaBuffer implementations to automatically be +// Send (where the compiler sees fit). +unsafe impl Send for DmaDescriptor {} + use enumset::{EnumSet, EnumSetType}; pub use self::buffers::*; From c717f04d4d1fa9b5ccb22c60fa6a14c506e7ef06 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Mon, 4 Nov 2024 08:08:19 +0000 Subject: [PATCH 20/67] Remove `EspWifiInitFor` & more granular init/deinit per driver (#2301) * More granular init and deinit per driver - Rework EspWifiInit - No longer require EspWifiInitFor - Add Drop impls for each driver, and add Drop for EspWifiController to fully deinit the stack * unwrap! more stuff * fixup examples and esp-now * unwrap less stuff * review feedback * seal wifi traits, allow rng or trng to init esp-wifi * changelog and migration guide * return wifi error in esp now constructor instead of panic --- esp-hal/src/rng.rs | 5 +- esp-wifi/CHANGELOG.md | 1 + esp-wifi/Cargo.toml | 1 + esp-wifi/MIGRATING-0.10.md | 17 ++ esp-wifi/src/ble/btdm.rs | 2 + esp-wifi/src/ble/controller/mod.rs | 49 +--- esp-wifi/src/ble/mod.rs | 2 +- esp-wifi/src/ble/npl.rs | 3 + esp-wifi/src/compat/misc.rs | 3 +- esp-wifi/src/esp_now/mod.rs | 43 ++- esp-wifi/src/lib.rs | 248 ++++++++---------- esp-wifi/src/timer/mod.rs | 10 +- esp-wifi/src/timer/riscv.rs | 12 +- esp-wifi/src/timer/xtensa.rs | 11 +- esp-wifi/src/wifi/mod.rs | 57 ++-- esp-wifi/src/wifi/utils.rs | 6 +- examples/Cargo.toml | 2 +- examples/src/bin/wifi_80211_tx.rs | 14 +- examples/src/bin/wifi_access_point.rs | 2 - .../src/bin/wifi_access_point_with_sta.rs | 2 - examples/src/bin/wifi_bench.rs | 2 - examples/src/bin/wifi_ble.rs | 3 +- examples/src/bin/wifi_coex.rs | 2 - examples/src/bin/wifi_dhcp.rs | 2 - examples/src/bin/wifi_embassy_access_point.rs | 18 +- .../bin/wifi_embassy_access_point_with_sta.rs | 18 +- examples/src/bin/wifi_embassy_bench.rs | 18 +- examples/src/bin/wifi_embassy_ble.rs | 28 +- examples/src/bin/wifi_embassy_dhcp.rs | 18 +- examples/src/bin/wifi_embassy_esp_now.rs | 28 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 18 +- examples/src/bin/wifi_embassy_trouble.rs | 30 ++- examples/src/bin/wifi_esp_now.rs | 2 - examples/src/bin/wifi_sniffer.rs | 14 +- examples/src/bin/wifi_static_ip.rs | 2 - hil-test/tests/esp_wifi_floats.rs | 7 +- 36 files changed, 355 insertions(+), 345 deletions(-) diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index 406a9980818..d0875012a13 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -130,10 +130,7 @@ impl rand_core::RngCore for Rng { /// the randomness from the hardware RNG and an ADC. This struct provides /// methods to generate random numbers and fill buffers with random bytes. /// Due to pulling the entropy source from the ADC, it uses the associated -/// regiters, so to use TRNG we need to "occupy" the ADC peripheral. -/// -/// For now, even after calling `core::mem::drop()` on `TRNG` ADC1 will not be -/// usable (details in esp-hal/#1750) +/// registers, so to use TRNG we need to "occupy" the ADC peripheral. /// /// ```rust, no_run #[doc = crate::before_snippet!()] diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index aa932a0287a..24189dc5a6e 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `esp_wifi::init` no longer requires `EspWifiInitFor`, and now returns `EspWifiController`, see the migration guide for more details (#2301) - No need to add `rom_functions.x` manually anymore (#2374) - esp-now: Data is now private in `ReceivedData` - use `data()`(#2396) diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index d6d92be54f8..0b448583c2a 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -39,6 +39,7 @@ libm = "0.2.8" cfg-if = "1.0.0" portable-atomic = { version = "1.9.0", default-features = false } portable_atomic_enum = { version = "0.3.1", features = ["portable-atomic"] } +rand_core = "0.6.4" bt-hci = { version = "0.1.1", optional = true } esp-config = { version = "0.1.0", path = "../esp-config" } diff --git a/esp-wifi/MIGRATING-0.10.md b/esp-wifi/MIGRATING-0.10.md index a8c7414dce1..0bf1d4c5c73 100644 --- a/esp-wifi/MIGRATING-0.10.md +++ b/esp-wifi/MIGRATING-0.10.md @@ -1,5 +1,22 @@ # Migration Guide from 0.10.x to v0.11.x +## Initialization changes + +`EspWifiInitFor` has been removed, individual drivers such as `Wifi` and `BleConnector` handle the initialization and de-initialization of the radio stack. + +`EspWifiInit` has been removed in favour of `EspWifiController`, each radio driver takes reference to this object. If no driver is borrowing `EspWifiController`, +you can safely call `EspWifiController::deinit()` to completely deinit the stack and return the peripherals used in `esp_wifi::init`. + +`esp-wifi::init` now takes all peripherals using the `PeripheralRef` pattern, with the exception of the rng source. + +`esp_wifi::init` now accepts `esp_hal::rng::Rng` or `esp_hal::rng::Trng`. + +The following error enum variants have been removed from `InitializationError`: + +- `Timer(hal::timer::Error)` +- `TimerUnavailable` +- `RadioClockUnavailable` + ## No need to include `rom_functions.x` manually Don't include `rom_functions.x` from esp-wifi diff --git a/esp-wifi/src/ble/btdm.rs b/esp-wifi/src/ble/btdm.rs index aa601f69de8..c6ca321db35 100644 --- a/esp-wifi/src/ble/btdm.rs +++ b/esp-wifi/src/ble/btdm.rs @@ -442,6 +442,7 @@ pub(crate) fn ble_init() { API_vhci_host_register_callback(&VHCI_HOST_CALLBACK); } + crate::flags::BLE.store(true, Ordering::Release); } pub(crate) fn ble_deinit() { @@ -453,6 +454,7 @@ pub(crate) fn ble_deinit() { btdm_controller_deinit(); crate::common_adapter::chip_specific::phy_disable(); } + crate::flags::BLE.store(false, Ordering::Release); } pub fn send_hci(data: &[u8]) { diff --git a/esp-wifi/src/ble/controller/mod.rs b/esp-wifi/src/ble/controller/mod.rs index de26dfb51b0..bd2b58c92f9 100644 --- a/esp-wifi/src/ble/controller/mod.rs +++ b/esp-wifi/src/ble/controller/mod.rs @@ -3,7 +3,7 @@ use embedded_io::{Error, ErrorType, Read, Write}; use super::{read_hci, read_next, send_hci}; use crate::{ hal::peripheral::{Peripheral, PeripheralRef}, - EspWifiInitialization, + EspWifiController, }; /// A blocking HCI connector @@ -11,14 +11,18 @@ pub struct BleConnector<'d> { _device: PeripheralRef<'d, crate::hal::peripherals::BT>, } +impl<'d> Drop for BleConnector<'d> { + fn drop(&mut self) { + crate::ble::ble_deinit(); + } +} + impl<'d> BleConnector<'d> { pub fn new( - init: &EspWifiInitialization, + _init: &'d EspWifiController<'d>, device: impl Peripheral

+ 'd, ) -> BleConnector<'d> { - if !init.is_ble() { - panic!("Not initialized for BLE use"); - } + crate::ble::ble_init(); Self { _device: device.into_ref(), @@ -80,7 +84,7 @@ impl Write for BleConnector<'_> { /// Async Interface #[cfg(feature = "async")] -pub mod asynch { +pub(crate) mod asynch { use core::task::Poll; use bt_hci::{ @@ -91,14 +95,9 @@ pub mod asynch { WriteHci, }; use embassy_sync::waitqueue::AtomicWaker; - use embedded_io::ErrorType; - use super::{read_hci, send_hci, BleConnectorError}; - use crate::{ - ble::have_hci_read_data, - hal::peripheral::{Peripheral, PeripheralRef}, - EspWifiInitialization, - }; + use super::*; + use crate::ble::have_hci_read_data; static HCI_WAKER: AtomicWaker = AtomicWaker::new(); @@ -106,30 +105,6 @@ pub mod asynch { HCI_WAKER.wake(); } - /// Async HCI connector - pub struct BleConnector<'d> { - _device: PeripheralRef<'d, crate::hal::peripherals::BT>, - } - - impl<'d> BleConnector<'d> { - pub fn new( - init: &EspWifiInitialization, - device: impl Peripheral

+ 'd, - ) -> BleConnector<'d> { - if !init.is_ble() { - panic!("Not initialized for BLE use"); - } - - Self { - _device: device.into_ref(), - } - } - } - - impl ErrorType for BleConnector<'_> { - type Error = BleConnectorError; - } - impl embedded_io_async::Read for BleConnector<'_> { async fn read(&mut self, buf: &mut [u8]) -> Result { if !have_hci_read_data() { diff --git a/esp-wifi/src/ble/mod.rs b/esp-wifi/src/ble/mod.rs index 1ea694fde5d..7246ffbcb8b 100644 --- a/esp-wifi/src/ble/mod.rs +++ b/esp-wifi/src/ble/mod.rs @@ -9,7 +9,7 @@ pub(crate) mod npl; use alloc::{boxed::Box, collections::vec_deque::VecDeque, vec::Vec}; use core::{cell::RefCell, mem::MaybeUninit}; -pub(crate) use ble::{ble_init, send_hci}; +pub(crate) use ble::{ble_deinit, ble_init, send_hci}; use critical_section::Mutex; #[cfg(any(esp32, esp32c3, esp32s3))] diff --git a/esp-wifi/src/ble/npl.rs b/esp-wifi/src/ble/npl.rs index 6b755ee6857..3d8696966b5 100644 --- a/esp-wifi/src/ble/npl.rs +++ b/esp-wifi/src/ble/npl.rs @@ -2,6 +2,7 @@ use alloc::boxed::Box; use core::{ mem::size_of_val, ptr::{addr_of, addr_of_mut}, + sync::atomic::Ordering, }; use super::*; @@ -1179,6 +1180,7 @@ pub(crate) fn ble_init() { debug!("The ble_controller_init was initialized"); } + crate::flags::BLE.store(true, Ordering::Release); } pub(crate) fn ble_deinit() { @@ -1205,6 +1207,7 @@ pub(crate) fn ble_deinit() { crate::common_adapter::chip_specific::phy_disable(); } + crate::flags::BLE.store(false, Ordering::Release); } #[cfg(esp32c2)] diff --git a/esp-wifi/src/compat/misc.rs b/esp-wifi/src/compat/misc.rs index 91035ffe268..783fd5f5993 100644 --- a/esp-wifi/src/compat/misc.rs +++ b/esp-wifi/src/compat/misc.rs @@ -34,6 +34,7 @@ unsafe extern "C" fn strcat(destination: *mut u8, source: *const u8) -> *const u unsafe extern "C" fn strcmp(str1: *const i8, str2: *const i8) -> i32 { trace!("strcmp {:?} {:?}", str1, str2); + // TODO: unwrap!() when defmt supports it let s1 = core::ffi::CStr::from_ptr(str1).to_str().unwrap(); let s2 = core::ffi::CStr::from_ptr(str2).to_str().unwrap(); @@ -146,7 +147,7 @@ unsafe extern "C" fn strdup(str: *const i8) -> *const u8 { unsafe { let s = core::ffi::CStr::from_ptr(str); - let s = s.to_str().unwrap(); + let s = s.to_str().unwrap(); // TODO when defmt supports it let p = malloc(s.len() + 1); core::ptr::copy_nonoverlapping(str, p as *mut i8, s.len() + 1); diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index ecdbd6886a5..febd478bf30 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -19,8 +19,8 @@ use portable_atomic::{AtomicBool, AtomicU8, Ordering}; use crate::{ binary::include::*, hal::peripheral::{Peripheral, PeripheralRef}, - wifi::{Protocol, RxControlInfo}, - EspWifiInitialization, + wifi::{Protocol, RxControlInfo, WifiError}, + EspWifiController, }; const RECEIVE_QUEUE_SIZE: usize = 10; @@ -113,6 +113,14 @@ pub enum EspNowError { SendFailed, /// Attempt to create `EspNow` instance twice. DuplicateInstance, + /// Initialization error + Initialization(WifiError), +} + +impl From for EspNowError { + fn from(f: WifiError) -> Self { + Self::Initialization(f) + } } /// Holds the count of peers in an ESP-NOW communication context. @@ -469,6 +477,21 @@ impl EspNowManager<'_> { } } +impl<'d> Drop for EspNowManager<'d> { + fn drop(&mut self) { + if unwrap!( + crate::flags::WIFI.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| { + Some(x.saturating_sub(1)) + }) + ) == 0 + { + if let Err(e) = crate::wifi::wifi_deinit() { + warn!("Failed to cleanly deinit wifi: {:?}", e); + } + } + } +} + /// This is the sender part of ESP-NOW. You can get this sender by splitting /// a `EspNow` instance. /// @@ -607,16 +630,16 @@ impl Drop for EspNowRc<'_> { /// Currently this implementation (when used together with traditional Wi-Fi) /// ONLY support STA mode. pub struct EspNow<'d> { - _device: Option>, manager: EspNowManager<'d>, sender: EspNowSender<'d>, receiver: EspNowReceiver<'d>, + _phantom: PhantomData<&'d ()>, } impl<'d> EspNow<'d> { /// Creates an `EspNow` instance. pub fn new( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl Peripheral

+ 'd, ) -> Result, EspNowError> { EspNow::new_internal(inited, Some(device.into_ref())) @@ -624,7 +647,7 @@ impl<'d> EspNow<'d> { /// Creates an `EspNow` instance with support for Wi-Fi coexistence. pub fn new_with_wifi( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, _token: EspNowWithWifiCreateToken, ) -> Result, EspNowError> { EspNow::new_internal( @@ -634,16 +657,17 @@ impl<'d> EspNow<'d> { } fn new_internal( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: Option>, ) -> Result, EspNowError> { - if !inited.is_wifi() { - return Err(EspNowError::Error(Error::NotInitialized)); + if !inited.wifi() { + // if wifi isn't already enabled, and we try to coexist - panic + assert!(device.is_some()); + crate::wifi::wifi_init()?; } let espnow_rc = EspNowRc::new()?; let esp_now = EspNow { - _device: device, manager: EspNowManager { _rc: espnow_rc.clone(), }, @@ -651,6 +675,7 @@ impl<'d> EspNow<'d> { _rc: espnow_rc.clone(), }, receiver: EspNowReceiver { _rc: espnow_rc }, + _phantom: PhantomData, }; check_error!({ esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA) })?; check_error!({ esp_wifi_start() })?; diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 7d415259004..e96f3c41769 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -93,25 +93,25 @@ extern crate alloc; // MUST be the first module mod fmt; +use core::marker::PhantomData; + use common_adapter::chip_specific::phy_mem_init; use esp_config::*; use esp_hal as hal; +use esp_hal::peripheral::Peripheral; #[cfg(not(feature = "esp32"))] use esp_hal::timer::systimer::Alarm; use fugit::MegahertzU32; use hal::{ clock::Clocks, + rng::{Rng, Trng}, system::RadioClockController, timer::{timg::Timer as TimgTimer, AnyTimer, PeriodicTimer}, }; -#[cfg(feature = "wifi")] -use num_traits::FromPrimitive; +use portable_atomic::Ordering; #[cfg(feature = "wifi")] -use crate::{ - binary::include::{self, esp_supplicant_deinit, esp_wifi_deinit_internal, esp_wifi_stop}, - wifi::WifiError, -}; +use crate::wifi::WifiError; use crate::{ tasks::init_tasks, timer::{setup_timer_isr, shutdown_timer_isr}, @@ -233,73 +233,53 @@ const _: () = { type TimeBase = PeriodicTimer<'static, AnyTimer>; -#[derive(Debug, PartialEq, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -/// An internal struct designed to make [`EspWifiInitialization`] uncreatable -/// outside of this crate. -pub struct EspWifiInitializationInternal; +pub(crate) mod flags { + use portable_atomic::{AtomicBool, AtomicUsize}; + + pub(crate) static ESP_WIFI_INITIALIZED: AtomicBool = AtomicBool::new(false); + pub(crate) static WIFI: AtomicUsize = AtomicUsize::new(0); + pub(crate) static BLE: AtomicBool = AtomicBool::new(false); +} #[derive(Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Initialized the driver for WiFi, Bluetooth or both. -pub enum EspWifiInitialization { - #[cfg(feature = "wifi")] - Wifi(EspWifiInitializationInternal), - #[cfg(feature = "ble")] - Ble(EspWifiInitializationInternal), - #[cfg(coex)] - WifiBle(EspWifiInitializationInternal), +pub struct EspWifiController<'d> { + _inner: PhantomData<&'d ()>, } -impl EspWifiInitialization { - #[allow(unused)] - fn is_wifi(&self) -> bool { - match self { - #[cfg(feature = "ble")] - EspWifiInitialization::Ble(_) => false, - _ => true, - } +impl<'d> EspWifiController<'d> { + /// Is the WiFi part of the radio running + pub fn wifi(&self) -> bool { + crate::flags::WIFI.load(Ordering::Acquire) > 0 } - #[allow(unused)] - fn is_ble(&self) -> bool { - match self { - #[cfg(feature = "wifi")] - EspWifiInitialization::Wifi(_) => false, - _ => true, - } + /// Is the BLE part of the radio running + pub fn ble(&self) -> bool { + crate::flags::BLE.load(Ordering::Acquire) } -} -#[derive(Debug, PartialEq, PartialOrd)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Initialize the driver for WiFi, Bluetooth or both. -pub enum EspWifiInitFor { - #[cfg(feature = "wifi")] - Wifi, - #[cfg(feature = "ble")] - Ble, - #[cfg(coex)] - WifiBle, -} + /// De-initialize the radio + pub fn deinit(self) -> Result<(), InitializationError> { + if crate::flags::ESP_WIFI_INITIALIZED.load(Ordering::Acquire) { + // safety: no other driver can be using this if this is callable + unsafe { deinit_unchecked() } + } else { + Ok(()) + } + } -impl EspWifiInitFor { - #[allow(unused)] - fn is_wifi(&self) -> bool { - match self { - #[cfg(feature = "ble")] - EspWifiInitFor::Ble => false, - _ => true, + pub(crate) unsafe fn conjure() -> Self { + Self { + _inner: PhantomData, } } +} - #[allow(unused)] - fn is_ble(&self) -> bool { - match self { - #[cfg(feature = "wifi")] - EspWifiInitFor::Wifi => false, - _ => true, +impl<'d> Drop for EspWifiController<'d> { + fn drop(&mut self) { + if crate::flags::ESP_WIFI_INITIALIZED.load(Ordering::Acquire) { + // safety: no other driver can be using this if this is callable + unsafe { deinit_unchecked().ok() }; } } } @@ -308,7 +288,7 @@ impl EspWifiInitFor { /// /// This trait is meant to be used only for the `init` function. /// Calling `timers()` multiple times may panic. -pub trait EspWifiTimerSource { +pub trait EspWifiTimerSource: private::Sealed { /// Returns the timer source. fn timer(self) -> TimeBase; } @@ -338,7 +318,7 @@ impl IntoAnyTimer for AnyTimer {} impl EspWifiTimerSource for T where - T: IntoAnyTimer, + T: IntoAnyTimer + private::Sealed, { fn timer(self) -> TimeBase { TimeBase::new(self.into()).timer() @@ -351,6 +331,29 @@ impl EspWifiTimerSource for TimeBase { } } +impl private::Sealed for TimeBase {} +impl private::Sealed for TimgTimer +where + DM: esp_hal::Mode, + Self: Into, +{ +} +#[cfg(not(feature = "esp32"))] +impl private::Sealed for Alarm<'_, T, DM, COMP, UNIT> +where + DM: esp_hal::Mode, + Self: Into, +{ +} + +/// A marker trait for suitable Rng sources for esp-wifi +pub trait EspWifiRngSource: rand_core::RngCore + private::Sealed {} + +impl EspWifiRngSource for Rng {} +impl private::Sealed for Rng {} +impl EspWifiRngSource for Trng<'_> {} +impl private::Sealed for Trng<'_> {} + /// Initialize for using WiFi and or BLE. /// /// # The `timer` argument @@ -380,12 +383,11 @@ impl EspWifiTimerSource for TimeBase { /// .unwrap(); /// # } /// ``` -pub fn init( - init_for: EspWifiInitFor, - timer: impl EspWifiTimerSource, - _rng: hal::rng::Rng, - _radio_clocks: hal::peripherals::RADIO_CLK, -) -> Result { +pub fn init<'d, T: EspWifiTimerSource>( + timer: impl Peripheral

+ 'd, + _rng: impl EspWifiRngSource, + _radio_clocks: impl Peripheral

+ 'd, +) -> Result, InitializationError> { // A minimum clock of 80MHz is required to operate WiFi module. const MIN_CLOCK: u32 = 80; let clocks = Clocks::get(); @@ -397,7 +399,7 @@ pub fn init( crate::common_adapter::chip_specific::enable_wifi_power_domain(); phy_mem_init(); init_tasks(); - setup_timer_isr(timer.timer())?; + setup_timer_isr(unsafe { timer.clone_unchecked() }.timer()); wifi_set_log_verbose(); init_clocks(); @@ -408,60 +410,23 @@ pub fn init( error => return Err(InitializationError::General(error)), } - #[cfg(feature = "wifi")] - if init_for.is_wifi() { - debug!("wifi init"); - // wifi init - crate::wifi::wifi_init()?; - } - - #[cfg(feature = "ble")] - if init_for.is_ble() { - // ble init - // for some reason things don't work when initializing things the other way - // around while the original implementation in NuttX does it like that - debug!("ble init"); - crate::ble::ble_init(); - } + crate::flags::ESP_WIFI_INITIALIZED.store(true, Ordering::Release); - match init_for { - #[cfg(feature = "wifi")] - EspWifiInitFor::Wifi => Ok(EspWifiInitialization::Wifi(EspWifiInitializationInternal)), - #[cfg(feature = "ble")] - EspWifiInitFor::Ble => Ok(EspWifiInitialization::Ble(EspWifiInitializationInternal)), - #[cfg(coex)] - EspWifiInitFor::WifiBle => Ok(EspWifiInitialization::WifiBle( - EspWifiInitializationInternal, - )), - } + Ok(EspWifiController { + _inner: PhantomData, + }) } -/// Deinitializes WiFi and/or BLE +/// Deinitializes the entire radio stack /// -/// After user calls this function, WiFi and/or BLE (depending on what has been -/// initialized) are fully stopped and deinitialized. After that, they should -/// not be used until they have been reinitialized with the `init` function. -/// -/// The function also disables the corresponding interrupts, deinitializes -/// the timer and radio clock, freeing these resources and returning them. -/// -/// Calling this while still using WiFi/BLE will cause crashes or undefined -/// behavior. +/// This can be useful to shutdown the stack before going to sleep for example. /// /// # Safety -/// Actual implementation assumes that the user takes responsibility for how the -/// function is used. For example, after using this function, user should not -/// use BLE or WiFi stack or controller instances (it is possible to -/// reinitialize communication using the `init` function), not to call -/// `deinit_unsafe` before the first initialization, and so on. Also, there is -/// currently no way to track whether a peripheral has been initialized, -/// so deinitialization is done based on the activated feature (`wifi`, `ble` -/// and/or `coex`). -/// Before deinitializing, chips with NPL bluetooth (esp32c2, esp32c6, esp32h2) -/// users must make sure to stop BLE advertising before. -pub unsafe fn deinit_unchecked( - init: EspWifiInitialization, -) -> Result<(TimeBase, hal::peripherals::RADIO_CLK), InitializationError> { +/// +/// The user must ensure that any use of the radio via the WIFI/BLE/ESP-NOW +/// drivers are complete, else undefined behavour may occur within those +/// drivers. +pub unsafe fn deinit_unchecked() -> Result<(), InitializationError> { // Disable coexistence #[cfg(coex)] { @@ -469,33 +434,35 @@ pub unsafe fn deinit_unchecked( unsafe { crate::wifi::os_adapter::coex_deinit() }; } - // Deinitialize WiFi - #[cfg(feature = "wifi")] - if init.is_wifi() { - esp_wifi_result!(unsafe { esp_wifi_stop() })?; - esp_wifi_result!(unsafe { esp_wifi_deinit_internal() })?; - esp_wifi_result!(esp_supplicant_deinit())?; - } + let controller = unsafe { EspWifiController::conjure() }; - // Deinitialize BLE - #[cfg(feature = "ble")] - if init.is_ble() { - #[cfg(any(esp32, esp32c3, esp32s3))] - crate::ble::btdm::ble_deinit(); + // Peripheral drivers should already take care of shutting these down + // we have to check this in the case where a user calls `deinit_unchecked` + // directly. + if controller.wifi() { + #[cfg(feature = "wifi")] + crate::wifi::wifi_deinit()?; + crate::flags::WIFI.store(0, Ordering::Release); + } - #[cfg(any(esp32c2, esp32c6, esp32h2))] - crate::ble::npl::ble_deinit(); + if controller.ble() { + #[cfg(feature = "ble")] + crate::ble::ble_deinit(); + crate::flags::BLE.store(false, Ordering::Release); } - shutdown_timer_isr().unwrap(); + shutdown_timer_isr(); crate::preempt::delete_all_tasks(); - let timer = critical_section::with(|cs| crate::timer::TIMER.borrow_ref_mut(cs).take()) - .ok_or(InitializationError::TimerUnavailable)?; + critical_section::with(|cs| crate::timer::TIMER.borrow_ref_mut(cs).take()); + + crate::flags::ESP_WIFI_INITIALIZED.store(false, Ordering::Release); - let radio_clocks = unsafe { esp_hal::peripherals::RADIO_CLK::steal() }; + Ok(()) +} - Ok((timer, radio_clocks)) +pub(crate) mod private { + pub trait Sealed {} } #[derive(Debug, Clone, Copy)] @@ -506,15 +473,6 @@ pub enum InitializationError { #[cfg(feature = "wifi")] WifiError(WifiError), WrongClockConfig, - Timer(hal::timer::Error), - TimerUnavailable, - RadioClockUnavailable, -} - -impl From for InitializationError { - fn from(value: hal::timer::Error) -> Self { - InitializationError::Timer(value) - } } #[cfg(feature = "wifi")] diff --git a/esp-wifi/src/timer/mod.rs b/esp-wifi/src/timer/mod.rs index f6531158ac9..d806fd9111a 100644 --- a/esp-wifi/src/timer/mod.rs +++ b/esp-wifi/src/timer/mod.rs @@ -22,24 +22,22 @@ use crate::TimeBase; pub(crate) static TIMER: Mutex>> = Mutex::new(RefCell::new(None)); -pub(crate) fn setup_timer_isr(timebase: TimeBase) -> Result<(), esp_hal::timer::Error> { +pub(crate) fn setup_timer_isr(timebase: TimeBase) { setup_radio_isr(); - setup_timer(timebase)?; + setup_timer(timebase); setup_multitasking(); yield_task(); - Ok(()) } -pub(crate) fn shutdown_timer_isr() -> Result<(), esp_hal::timer::Error> { +pub(crate) fn shutdown_timer_isr() { shutdown_radio_isr(); - disable_timer()?; + disable_timer(); disable_multitasking(); - Ok(()) } #[allow(unused)] diff --git a/esp-wifi/src/timer/riscv.rs b/esp-wifi/src/timer/riscv.rs index 46eafa16220..8cb7c919144 100644 --- a/esp-wifi/src/timer/riscv.rs +++ b/esp-wifi/src/timer/riscv.rs @@ -23,28 +23,24 @@ pub const TICKS_PER_SECOND: u64 = 1_000_000; use super::TIMER; -pub(crate) fn setup_timer(mut alarm0: TimeBase) -> Result<(), esp_hal::timer::Error> { +pub(crate) fn setup_timer(mut alarm0: TimeBase) { // make sure the scheduling won't start before everything is setup riscv::interrupt::disable(); let cb: extern "C" fn() = unsafe { core::mem::transmute(handler as *const ()) }; alarm0.set_interrupt_handler(InterruptHandler::new(cb, interrupt::Priority::Priority1)); - alarm0.start(TIMESLICE_FREQUENCY.into_duration())?; + unwrap!(alarm0.start(TIMESLICE_FREQUENCY.into_duration())); critical_section::with(|cs| { alarm0.enable_interrupt(true); TIMER.borrow_ref_mut(cs).replace(alarm0); }); - - Ok(()) } -pub(crate) fn disable_timer() -> Result<(), esp_hal::timer::Error> { +pub(crate) fn disable_timer() { critical_section::with(|cs| { unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).enable_interrupt(false); - unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel().unwrap(); + unwrap!(unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel()); }); - - Ok(()) } pub(crate) fn setup_multitasking() { diff --git a/esp-wifi/src/timer/xtensa.rs b/esp-wifi/src/timer/xtensa.rs index 6c123edaefb..dedb61b4a42 100644 --- a/esp-wifi/src/timer/xtensa.rs +++ b/esp-wifi/src/timer/xtensa.rs @@ -21,26 +21,23 @@ pub(crate) fn get_systimer_count() -> u64 { esp_hal::time::now().ticks() } -pub(crate) fn setup_timer(mut timer1: TimeBase) -> Result<(), esp_hal::timer::Error> { +pub(crate) fn setup_timer(mut timer1: TimeBase) { timer1.set_interrupt_handler(InterruptHandler::new( unsafe { core::mem::transmute::<*const (), extern "C" fn()>(handler as *const ()) }, interrupt::Priority::Priority2, )); - timer1.start(TIMESLICE_FREQUENCY.into_duration())?; + unwrap!(timer1.start(TIMESLICE_FREQUENCY.into_duration())); critical_section::with(|cs| { timer1.enable_interrupt(true); TIMER.borrow_ref_mut(cs).replace(timer1); }); - Ok(()) } -pub(crate) fn disable_timer() -> Result<(), esp_hal::timer::Error> { +pub(crate) fn disable_timer() { critical_section::with(|cs| { unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).enable_interrupt(false); - unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel().unwrap(); + unwrap!(unwrap!(TIMER.borrow_ref_mut(cs).as_mut()).cancel()); }); - - Ok(()) } pub(crate) fn setup_multitasking() { diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index 3d92900e855..33df1bcefee 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -69,7 +69,7 @@ use crate::{ macros::ram, peripheral::{Peripheral, PeripheralRef}, }, - EspWifiInitialization, + EspWifiController, }; const ETHERNET_FRAME_HEADER_SIZE: usize = 18; @@ -90,8 +90,10 @@ use crate::binary::{ esp_err_t, esp_interface_t_ESP_IF_WIFI_AP, esp_interface_t_ESP_IF_WIFI_STA, + esp_supplicant_deinit, esp_supplicant_init, esp_wifi_connect, + esp_wifi_deinit_internal, esp_wifi_disconnect, esp_wifi_get_mode, esp_wifi_init_internal, @@ -281,7 +283,7 @@ pub struct AccessPointConfiguration { impl Default for AccessPointConfiguration { fn default() -> Self { Self { - ssid: "iot-device".try_into().unwrap(), + ssid: unwrap!("iot-device".try_into()), ssid_hidden: false, channel: 1, secondary_channel: None, @@ -1587,10 +1589,19 @@ pub(crate) fn wifi_init() -> Result<(), WifiError> { chip_specific::g_misc_nvs = addr_of!(NVS_STRUCT) as u32; } + crate::flags::WIFI.fetch_add(1, Ordering::SeqCst); + Ok(()) } } +pub(crate) fn wifi_deinit() -> Result<(), crate::InitializationError> { + esp_wifi_result!(unsafe { esp_wifi_stop() })?; + esp_wifi_result!(unsafe { esp_wifi_deinit_internal() })?; + esp_wifi_result!(unsafe { esp_supplicant_deinit() })?; + Ok(()) +} + unsafe extern "C" fn recv_cb_sta( buffer: *mut c_types::c_void, len: u16, @@ -1654,11 +1665,11 @@ unsafe extern "C" fn recv_cb_ap( pub(crate) static WIFI_TX_INFLIGHT: AtomicUsize = AtomicUsize::new(0); fn decrement_inflight_counter() { - WIFI_TX_INFLIGHT - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| { + unwrap!( + WIFI_TX_INFLIGHT.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| { Some(x.saturating_sub(1)) }) - .unwrap(); + ); } #[ram] @@ -1878,7 +1889,7 @@ pub(crate) fn wifi_start_scan( /// /// If you want to use AP-STA mode, use `[new_ap_sta]`. pub fn new_with_config<'d, MODE: WifiDeviceMode>( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl Peripheral

+ 'd, config: MODE::Config, ) -> Result<(WifiDevice<'d, MODE>, WifiController<'d>), WifiError> { @@ -1896,8 +1907,8 @@ pub fn new_with_config<'d, MODE: WifiDeviceMode>( /// This function will panic if the mode is [`WifiMode::ApSta`]. /// If you want to use AP-STA mode, use `[new_ap_sta]`. pub fn new_with_mode<'d, MODE: WifiDeviceMode>( - inited: &EspWifiInitialization, - device: impl crate::hal::peripheral::Peripheral

+ 'd, + inited: &'d EspWifiController<'d>, + device: impl Peripheral

+ 'd, _mode: MODE, ) -> Result<(WifiDevice<'d, MODE>, WifiController<'d>), WifiError> { new_with_config(inited, device, ::Config::default()) @@ -1908,7 +1919,7 @@ pub fn new_with_mode<'d, MODE: WifiDeviceMode>( /// /// Returns a tuple of `(AP device, STA device, controller)`. pub fn new_ap_sta<'d>( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl Peripheral

+ 'd, ) -> Result< ( @@ -1925,7 +1936,7 @@ pub fn new_ap_sta<'d>( /// /// Returns a tuple of `(AP device, STA device, controller)`. pub fn new_ap_sta_with_config<'d>( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl Peripheral

+ 'd, sta_config: crate::wifi::ClientConfiguration, ap_config: crate::wifi::AccessPointConfiguration, @@ -2448,8 +2459,9 @@ impl Sniffer { pub(crate) fn new() -> Self { // This shouldn't fail, since the way this is created, means that wifi will // always be initialized. - esp_wifi_result!(unsafe { esp_wifi_set_promiscuous_rx_cb(Some(promiscuous_rx_cb)) }) - .unwrap(); + unwrap!(esp_wifi_result!(unsafe { + esp_wifi_set_promiscuous_rx_cb(Some(promiscuous_rx_cb)) + })); Self { promiscuous_mode_enabled: AtomicBool::new(false), } @@ -2493,14 +2505,29 @@ pub struct WifiController<'d> { sniffer_taken: AtomicBool, } +impl<'d> Drop for WifiController<'d> { + fn drop(&mut self) { + if unwrap!( + crate::flags::WIFI.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| { + Some(x.saturating_sub(1)) + }) + ) == 0 + { + if let Err(e) = crate::wifi::wifi_deinit() { + warn!("Failed to cleanly deinit wifi: {:?}", e); + } + } + } +} + impl<'d> WifiController<'d> { pub(crate) fn new_with_config( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, _device: PeripheralRef<'d, crate::hal::peripherals::WIFI>, config: Configuration, ) -> Result { - if !inited.is_wifi() { - return Err(WifiError::NotInitialized); + if !inited.wifi() { + crate::wifi::wifi_init()?; } // We set up the controller with the default config because we need to call diff --git a/esp-wifi/src/wifi/utils.rs b/esp-wifi/src/wifi/utils.rs index 1eb5da3a247..e48f28f8d38 100644 --- a/esp-wifi/src/wifi/utils.rs +++ b/esp-wifi/src/wifi/utils.rs @@ -8,7 +8,7 @@ use smoltcp::{ }; use super::{WifiApDevice, WifiController, WifiDevice, WifiDeviceMode, WifiError, WifiStaDevice}; -use crate::{timestamp, EspWifiInitialization}; +use crate::{timestamp, EspWifiController}; fn setup_iface<'a, MODE: WifiDeviceMode>( device: &mut WifiDevice<'_, MODE>, @@ -38,7 +38,7 @@ fn setup_iface<'a, MODE: WifiDeviceMode>( /// You can use the provided macros to create and pass a suitable backing /// storage. pub fn create_network_interface<'a, 'd, MODE: WifiDeviceMode>( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl crate::hal::peripheral::Peripheral

+ 'd, mode: MODE, storage: &'a mut [SocketStorage<'a>], @@ -69,7 +69,7 @@ pub struct ApStaInterface<'a, 'd> { } pub fn create_ap_sta_network_interface<'a, 'd>( - inited: &EspWifiInitialization, + inited: &'d EspWifiController<'d>, device: impl crate::hal::peripheral::Peripheral

+ 'd, ap_storage: &'a mut [SocketStorage<'a>], sta_storage: &'a mut [SocketStorage<'a>], diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d3aeba47443..c9af3773735 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -30,7 +30,7 @@ esp-hal-embassy = { path = "../esp-hal-embassy", optional = true } esp-ieee802154 = { path = "../esp-ieee802154", optional = true } esp-println = { path = "../esp-println", features = ["log"] } esp-storage = { path = "../esp-storage", optional = true } -esp-wifi = { path = "../esp-wifi", optional = true } +esp-wifi = { path = "../esp-wifi", features = ["log"], optional = true } fugit = "0.3.7" heapless = "0.8.0" hmac = { version = "0.12.1", default-features = false } diff --git a/examples/src/bin/wifi_80211_tx.rs b/examples/src/bin/wifi_80211_tx.rs index 8cc6deb75b4..c073ce12789 100644 --- a/examples/src/bin/wifi_80211_tx.rs +++ b/examples/src/bin/wifi_80211_tx.rs @@ -13,13 +13,8 @@ use core::marker::PhantomData; use esp_alloc as _; use esp_backtrace as _; -use esp_hal::{ - delay::Delay, - prelude::*, - rng::Rng, - timer::{timg::TimerGroup, AnyTimer, PeriodicTimer}, -}; -use esp_wifi::{init, wifi, EspWifiInitFor}; +use esp_hal::{delay::Delay, prelude::*, rng::Rng, timer::timg::TimerGroup}; +use esp_wifi::{init, wifi}; use ieee80211::{ common::{CapabilitiesInformation, FCFFlags}, element_chain, @@ -47,12 +42,9 @@ fn main() -> ! { let delay = Delay::new(); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer = PeriodicTimer::new(timer0); let init = init( - EspWifiInitFor::Wifi, - timer, + timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, ) diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index fec2923ff79..a4e8032851f 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -33,7 +33,6 @@ use esp_wifi::{ WifiApDevice, }, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::iface::SocketStorage; @@ -51,7 +50,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index 03f963c4c7c..36e17512864 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -34,7 +34,6 @@ use esp_wifi::{ Configuration, }, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::{ iface::SocketStorage, @@ -58,7 +57,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index 4ab9e4fa17c..06a474b8f70 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -36,7 +36,6 @@ use esp_wifi::{ WifiStaDevice, }, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::{ iface::SocketStorage, @@ -71,7 +70,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_ble.rs b/examples/src/bin/wifi_ble.rs index 4ba170f332a..26ac4f4becf 100644 --- a/examples/src/bin/wifi_ble.rs +++ b/examples/src/bin/wifi_ble.rs @@ -32,7 +32,7 @@ use esp_hal::{ timer::timg::TimerGroup, }; use esp_println::println; -use esp_wifi::{ble::controller::BleConnector, init, EspWifiInitFor}; +use esp_wifi::{ble::controller::BleConnector, init}; #[entry] fn main() -> ! { @@ -48,7 +48,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Ble, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index ad0e92e812e..a8c779d117f 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -41,7 +41,6 @@ use esp_wifi::{ init, wifi::{utils::create_network_interface, ClientConfiguration, Configuration, WifiStaDevice}, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::{ iface::SocketStorage, @@ -83,7 +82,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::WifiBle, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index c223de675e5..68f642c3d38 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -35,7 +35,6 @@ use esp_wifi::{ WifiStaDevice, }, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::{ iface::SocketStorage, @@ -59,7 +58,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index d99dd331c2c..748df8ccba5 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -41,7 +41,7 @@ use esp_wifi::{ WifiEvent, WifiState, }, - EspWifiInitFor, + EspWifiController, }; // When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html @@ -67,13 +67,15 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let (wifi_interface, controller) = diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 8beb0f16389..82f74805509 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -46,7 +46,7 @@ use esp_wifi::{ WifiStaDevice, WifiState, }, - EspWifiInitFor, + EspWifiController, }; const SSID: &str = env!("SSID"); @@ -75,13 +75,15 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let (wifi_ap_interface, wifi_sta_interface, mut controller) = diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 6659ed60451..80334b862db 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -36,7 +36,7 @@ use esp_wifi::{ WifiStaDevice, WifiState, }, - EspWifiInitFor, + EspWifiController, }; // When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html @@ -98,13 +98,15 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let (wifi_interface, controller) = diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index f9ab2b322e1..3fb6d0dd181 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -35,7 +35,17 @@ use esp_hal::{ timer::timg::TimerGroup, }; use esp_println::println; -use esp_wifi::{ble::controller::asynch::BleConnector, init, EspWifiInitFor}; +use esp_wifi::{ble::controller::BleConnector, init, EspWifiController}; + +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} #[esp_hal_embassy::main] async fn main(_spawner: Spawner) -> ! { @@ -50,13 +60,15 @@ async fn main(_spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Ble, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 65f4443cefa..5ee5bb322ba 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -32,7 +32,7 @@ use esp_wifi::{ WifiStaDevice, WifiState, }, - EspWifiInitFor, + EspWifiController, }; // When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html @@ -61,13 +61,15 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let (wifi_interface, controller) = diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index ada75152122..3b7aecd43e8 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -20,9 +20,19 @@ use esp_println::println; use esp_wifi::{ esp_now::{PeerInfo, BROADCAST_ADDRESS}, init, - EspWifiInitFor, + EspWifiController, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} + #[esp_hal_embassy::main] async fn main(_spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -36,13 +46,15 @@ async fn main(_spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let mut esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 270a68a7a66..1eeec3a88a5 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -20,7 +20,7 @@ use esp_println::println; use esp_wifi::{ esp_now::{EspNowManager, EspNowReceiver, EspNowSender, PeerInfo, BROADCAST_ADDRESS}, init, - EspWifiInitFor, + EspWifiController, }; // When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html @@ -46,13 +46,15 @@ async fn main(spawner: Spawner) -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - EspWifiInitFor::Wifi, - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); let wifi = peripherals.WIFI; let esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); diff --git a/examples/src/bin/wifi_embassy_trouble.rs b/examples/src/bin/wifi_embassy_trouble.rs index 2e3d6672465..45253463ae6 100644 --- a/examples/src/bin/wifi_embassy_trouble.rs +++ b/examples/src/bin/wifi_embassy_trouble.rs @@ -18,8 +18,8 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_time::{Duration, Timer}; use esp_alloc as _; use esp_backtrace as _; -use esp_hal::{prelude::*, timer::timg::TimerGroup}; -use esp_wifi::ble::controller::asynch::BleConnector; +use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; +use esp_wifi::{ble::controller::BleConnector, init, EspWifiController}; use log::*; use static_cell::StaticCell; use trouble_host::{ @@ -31,6 +31,16 @@ use trouble_host::{ PacketQos, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +macro_rules! mk_static { + ($t:ty,$val:expr) => {{ + static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); + #[deny(unused_attributes)] + let x = STATIC_CELL.uninit().write(($val)); + x + }}; +} + #[esp_hal_embassy::main] async fn main(_s: Spawner) { esp_println::logger::init_logger_from_env(); @@ -44,13 +54,15 @@ async fn main(_s: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = esp_wifi::init( - esp_wifi::EspWifiInitFor::Ble, - timg0.timer0, - esp_hal::rng::Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = &*mk_static!( + EspWifiController<'static>, + init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap() + ); #[cfg(feature = "esp32")] { diff --git a/examples/src/bin/wifi_esp_now.rs b/examples/src/bin/wifi_esp_now.rs index 294bddc1e52..0b3a268dba2 100644 --- a/examples/src/bin/wifi_esp_now.rs +++ b/examples/src/bin/wifi_esp_now.rs @@ -20,7 +20,6 @@ use esp_println::println; use esp_wifi::{ esp_now::{PeerInfo, BROADCAST_ADDRESS}, init, - EspWifiInitFor, }; #[entry] @@ -37,7 +36,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 2e82c66f57a..4e56d6338ef 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -19,13 +19,9 @@ use core::cell::RefCell; use critical_section::Mutex; use esp_backtrace as _; -use esp_hal::{ - prelude::*, - rng::Rng, - timer::{timg::TimerGroup, AnyTimer, PeriodicTimer}, -}; +use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; -use esp_wifi::{init, wifi, EspWifiInitFor}; +use esp_wifi::{init, wifi}; use ieee80211::{match_frames, mgmt_frame::BeaconFrame}; static KNOWN_SSIDS: Mutex>> = Mutex::new(RefCell::new(BTreeSet::new())); @@ -42,12 +38,8 @@ fn main() -> ! { esp_alloc::heap_allocator!(72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer = PeriodicTimer::new(timer0); - let init = init( - EspWifiInitFor::Wifi, - timer, + timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, ) diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index 4e0742e3049..e9a91fe1fac 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -34,7 +34,6 @@ use esp_wifi::{ WifiStaDevice, }, wifi_interface::WifiStack, - EspWifiInitFor, }; use smoltcp::iface::SocketStorage; @@ -57,7 +56,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); let init = init( - EspWifiInitFor::Wifi, timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, diff --git a/hil-test/tests/esp_wifi_floats.rs b/hil-test/tests/esp_wifi_floats.rs index 0b9a82c8ac7..f04fe728336 100644 --- a/hil-test/tests/esp_wifi_floats.rs +++ b/hil-test/tests/esp_wifi_floats.rs @@ -17,7 +17,6 @@ use esp_hal::{ rng::Rng, timer::timg::TimerGroup, }; -use esp_wifi::{init, EspWifiInitFor}; use hil_test as _; #[inline(never)] @@ -101,8 +100,7 @@ mod tests { #[timeout(3)] fn fpu_stays_enabled_with_wifi(peripherals: Peripherals) { let timg0 = TimerGroup::new(peripherals.TIMG0); - let _init = init( - EspWifiInitFor::Wifi, + let _init = esp_wifi::init( timg0.timer1, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, @@ -138,8 +136,7 @@ mod tests { unsafe { &mut *core::ptr::addr_of_mut!(APP_CORE_STACK) }, move || { let timg0 = TimerGroup::new(peripherals.TIMG0); - let _init = init( - EspWifiInitFor::Wifi, + let _init = esp_wifi::init( timg0.timer1, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, From 40c0a6944e765c4a51f83a3f0e060721350afbd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 10:32:12 +0100 Subject: [PATCH 21/67] `into_async` (#2430) * Remove configure_for_async * Add into_async and into_blocking to I2c * Add into_async and into_blocking to UsbSerialJtag * Rework LCD_CAM * Rmt * RSA * TWAI * Uart * Documentation * Disable interrupts set on other core * Move configure into RegisterAccess * Disable interrupts on the other core * Use EnumSet in RMT --- .cargo/config.toml | 1 + esp-hal/CHANGELOG.md | 5 + esp-hal/MIGRATING-0.21.md | 35 + esp-hal/src/aes/mod.rs | 6 +- esp-hal/src/assist_debug.rs | 19 +- esp-hal/src/dma/gdma.rs | 106 +- esp-hal/src/dma/m2m.rs | 42 +- esp-hal/src/dma/mod.rs | 146 +- esp-hal/src/dma/pdma.rs | 196 ++- esp-hal/src/ecc.rs | 10 +- esp-hal/src/i2c.rs | 1300 ++++++++--------- esp-hal/src/i2s.rs | 103 +- esp-hal/src/interrupt/software.rs | 7 +- esp-hal/src/lcd_cam/cam.rs | 9 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 14 +- esp-hal/src/lcd_cam/mod.rs | 413 +++--- esp-hal/src/lib.rs | 15 + esp-hal/src/parl_io.rs | 75 +- esp-hal/src/pcnt/mod.rs | 7 +- esp-hal/src/rmt.rs | 1076 ++++++-------- esp-hal/src/rsa/mod.rs | 47 +- esp-hal/src/rtc_cntl/mod.rs | 27 +- esp-hal/src/sha.rs | 10 +- esp-hal/src/spi/master.rs | 158 +- esp-hal/src/spi/slave.rs | 37 +- esp-hal/src/timer/systimer.rs | 4 + esp-hal/src/timer/timg.rs | 7 +- esp-hal/src/twai/mod.rs | 95 +- esp-hal/src/uart.rs | 1063 +++++++------- esp-hal/src/usb_serial_jtag.rs | 410 +++--- examples/src/bin/embassy_i2c.rs | 2 +- .../embassy_i2c_bmp180_calibration_data.rs | 2 +- examples/src/bin/embassy_i2s_parallel.rs | 4 +- examples/src/bin/embassy_i2s_read.rs | 5 +- examples/src/bin/embassy_i2s_sound.rs | 5 +- examples/src/bin/embassy_parl_io_rx.rs | 4 +- examples/src/bin/embassy_parl_io_tx.rs | 4 +- examples/src/bin/embassy_rmt_rx.rs | 4 +- examples/src/bin/embassy_rmt_tx.rs | 4 +- examples/src/bin/embassy_serial.rs | 4 +- examples/src/bin/embassy_spi.rs | 5 +- examples/src/bin/embassy_twai.rs | 7 +- examples/src/bin/embassy_usb_serial_jtag.rs | 4 +- hil-test/tests/embassy_interrupt_spi_dma.rs | 13 +- hil-test/tests/i2s.rs | 6 +- hil-test/tests/lcd_cam_i8080.rs | 6 +- hil-test/tests/lcd_cam_i8080_async.rs | 8 +- hil-test/tests/parl_io_tx_async.rs | 6 +- hil-test/tests/rsa_async.rs | 2 +- hil-test/tests/spi_full_duplex.rs | 27 +- hil-test/tests/spi_slave.rs | 3 +- hil-test/tests/uart_async.rs | 2 +- hil-test/tests/uart_tx_rx_async.rs | 4 +- hil-test/tests/usb_serial_jtag.rs | 4 +- 54 files changed, 2857 insertions(+), 2721 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 35049cbcb13..9f81e304413 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,3 @@ [alias] xtask = "run --package xtask --" +xfmt = "xtask fmt-packages" diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d24d3bb079d..e01115be039 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - I2S Parallel output driver for ESP32. (#2348, #2436) - Add an option to configure `WDT` action (#2330) - `DmaDescriptor` is now `Send` (#2456) +- `into_async` and `into_blocking` functions for most peripherals (#2430) +- API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430) ### Changed @@ -39,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442) - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) - Allow users to create DMA `Preparation`s (#2455) +- The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) ### Fixed @@ -64,6 +67,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed the pin type parameters from `parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits}` (#2388) - Removed the pin type parameters from `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#2388) - Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388) +- Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430) +- The `configure_for_async` DMA functions have been removed (#2430) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 7898ecabc5b..70bc8386e0b 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -23,6 +23,41 @@ For example: } ``` +## Removed `async`-specific constructors + +The following async-specific constuctors have been removed: + +- `configure_for_async` DMA channel constructors +- `TwaiConfiguration::new_async` and `TwaiConfiguration::new_async_no_transceiver` +- `I2c::new_async` +- `LcdCam::new_async` +- `UsbSerialJtag::new_async` +- `Rsa::new_async` +- `Rmt::new_async` +- `Uart::new_async`, `Uart::new_async_with_config` +- `UartRx::new_async`, `UartRx::new_async_with_config` +- `UartTx::new_async`, `UartTx::new_async_with_config` + +You can use the blocking counterparts, then call `into_async` on the returned peripheral instead. + +```diff +-let mut config = twai::TwaiConfiguration::new_async( ++let mut config = twai::TwaiConfiguration::new( + peripherals.TWAI0, + loopback_pin.peripheral_input(), + loopback_pin, + twai::BaudRate::B1000K, + TwaiMode::SelfTest, +-); ++).into_async(); +``` + +Some drivers were implicitly configured to the asyncness of the DMA channel used to construct them. +This is no longer the case, and the following drivers will always be created in blocking mode: + +- `I2s` +- `master::SpiDma` and `master::SpiDmaBus` + ## Peripheral types are now optional You no longer have to specify the peripheral instance in the driver's type for the following diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index f8c4f970c7c..eac8f95066a 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -250,6 +250,7 @@ pub mod dma { WriteBuffer, }, peripherals::AES, + Blocking, }; const ALIGN_SIZE: usize = core::mem::size_of::(); @@ -275,7 +276,7 @@ pub mod dma { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, - channel: Channel<'d, ::Dma, crate::Blocking>, + channel: Channel<'d, ::Dma, Blocking>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } @@ -284,12 +285,11 @@ pub mod dma { /// Enable DMA for the current instance of the AES driver pub fn with_dma( self, - channel: Channel<'d, C, crate::Blocking>, + channel: Channel<'d, C, Blocking>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> AesDma<'d> where - Self: Sized, C: DmaChannelConvert<::Dma>, { AesDma { diff --git a/esp-hal/src/assist_debug.rs b/esp-hal/src/assist_debug.rs index 1426ff2fa91..945d1e87ce6 100644 --- a/esp-hal/src/assist_debug.rs +++ b/esp-hal/src/assist_debug.rs @@ -26,7 +26,7 @@ use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::ASSIST_DEBUG, + peripherals::{Interrupt, ASSIST_DEBUG}, InterruptConfigurable, }; @@ -51,17 +51,14 @@ impl crate::private::Sealed for DebugAssist<'_> {} impl InterruptConfigurable for DebugAssist<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt( - crate::peripherals::Interrupt::ASSIST_DEBUG, - handler.handler(), - ); - crate::interrupt::enable( - crate::peripherals::Interrupt::ASSIST_DEBUG, - handler.priority(), - ) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::ASSIST_DEBUG); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::ASSIST_DEBUG, handler.handler()) }; + unwrap!(crate::interrupt::enable( + Interrupt::ASSIST_DEBUG, + handler.priority() + )); } } diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 0eac232c8f0..769b570e278 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -17,7 +17,9 @@ use crate::{ dma::*, peripheral::PeripheralRef, + peripherals::Interrupt, system::{Peripheral, PeripheralClockControl}, + Blocking, }; #[doc(hidden)] @@ -33,6 +35,36 @@ impl crate::private::Sealed for AnyGdmaChannel {} impl DmaChannel for AnyGdmaChannel { type Rx = ChannelRxImpl; type Tx = ChannelTxImpl; + + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { + match ch.tx.tx_impl.0.number() { + 0 => DmaChannel0::handler(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::handler(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::handler(), + #[cfg(esp32s3)] + 3 => DmaChannel3::handler(), + #[cfg(esp32s3)] + 4 => DmaChannel4::handler(), + _ => unreachable!(), + } + } + + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + match ch.tx.tx_impl.0.number() { + 0 => DmaChannel0::isrs(), + #[cfg(not(esp32c2))] + 1 => DmaChannel1::isrs(), + #[cfg(not(esp32c2))] + 2 => DmaChannel2::isrs(), + #[cfg(esp32s3)] + 3 => DmaChannel3::isrs(), + #[cfg(esp32s3)] + 4 => DmaChannel4::isrs(), + _ => unreachable!(), + } + } } #[non_exhaustive] @@ -460,9 +492,27 @@ macro_rules! impl_channel { impl crate::private::Sealed for [] {} + impl [] { + fn handler() -> InterruptHandler { + $async_handler + } + + fn isrs() -> &'static [Interrupt] { + &[$(Interrupt::$interrupt),*] + } + } + impl DmaChannel for [] { type Rx = ChannelRxImpl>; type Tx = ChannelTxImpl>; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelConvert for [] { @@ -482,64 +532,22 @@ macro_rules! impl_channel { fn get_tx_interrupts() -> impl InterruptAccess { ChannelTxImpl(SpecificGdmaChannel::<$num> {}) } - - fn set_isr(handler: $crate::interrupt::InterruptHandler) { - let mut dma = unsafe { crate::peripherals::DMA::steal() }; - $( - dma.[< bind_ $interrupt:lower _interrupt >](handler.handler()); - $crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap(); - )* - } } impl ChannelCreator<$num> { - fn do_configure<'a, M: crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> crate::dma::Channel<'a, [], M> { - let tx_impl = ChannelTxImpl(SpecificGdmaChannel::<$num> {}); - tx_impl.set_burst_mode(burst_mode); - tx_impl.set_priority(priority); - - let rx_impl = ChannelRxImpl(SpecificGdmaChannel::<$num> {}); - rx_impl.set_burst_mode(burst_mode); - rx_impl.set_priority(priority); - // clear the mem2mem mode to avoid failed DMA if this - // channel was previously used for a mem2mem transfer. - rx_impl.set_mem2mem_mode(false); - - crate::dma::Channel { - tx: ChannelTx::new(tx_impl, burst_mode), - rx: ChannelRx::new(rx_impl, burst_mode), - phantom: PhantomData, - } - } - /// Configure the channel for use with blocking APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. pub fn configure<'a>( self, burst_mode: bool, priority: DmaPriority, - ) -> crate::dma::Channel<'a, [], crate::Blocking> { - self.do_configure(burst_mode, priority) - } - - /// Configure the channel for use with async APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. - pub fn configure_for_async<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> crate::dma::Channel<'a, [], $crate::Async> { - let this = self.do_configure(burst_mode, priority); + ) -> Channel<'a, [], Blocking> { + let mut this = Channel { + tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})), + rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})), + phantom: PhantomData, + }; - []::set_isr($async_handler); + this.configure(burst_mode, priority); this } diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index c6e69984f3d..2fce9e40c2a 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -18,6 +18,8 @@ use crate::{ Tx, WriteBuffer, }, + Async, + Blocking, Mode, }; @@ -36,19 +38,18 @@ where peripheral: DmaPeripheral, } -impl<'d, M> Mem2Mem<'d, M> -where - M: Mode, -{ +impl<'d> Mem2Mem<'d, Blocking> { /// Create a new Mem2Mem instance. - pub fn new( - channel: Channel<'d, CH, M>, + pub fn new( + channel: Channel<'d, CH, DM>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { unsafe { Self::new_unsafe( @@ -62,8 +63,8 @@ where } /// Create a new Mem2Mem instance with specific chunk size. - pub fn new_with_chunk_size( - channel: Channel<'d, CH, M>, + pub fn new_with_chunk_size( + channel: Channel<'d, CH, DM>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -71,6 +72,8 @@ where ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { unsafe { Self::new_unsafe( @@ -89,8 +92,8 @@ where /// /// You must ensure that your not using DMA for the same peripheral and /// that your the only one using the DmaPeripheral. - pub unsafe fn new_unsafe( - channel: Channel<'d, CH, M>, + pub unsafe fn new_unsafe( + channel: Channel<'d, CH, DM>, peripheral: DmaPeripheral, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -98,6 +101,8 @@ where ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { if !(1..=4092).contains(&chunk_size) { return Err(DmaError::InvalidChunkSize); @@ -106,13 +111,28 @@ where return Err(DmaError::OutOfDescriptors); } Ok(Mem2Mem { - channel: channel.degrade(), + channel: Channel::<_, Blocking>::from(channel).degrade(), peripheral, rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size), tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size), }) } + /// Convert Mem2Mem to an async Mem2Mem. + pub fn into_async(self) -> Mem2Mem<'d, Async> { + Mem2Mem { + channel: self.channel.into_async(), + rx_chain: self.rx_chain, + tx_chain: self.tx_chain, + peripheral: self.peripheral, + } + } +} + +impl<'d, M> Mem2Mem<'d, M> +where + M: Mode, +{ /// Start a memory to memory transfer. pub fn start_transfer<'t, TXBUF, RXBUF>( &mut self, diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 389b1aceaae..df652f9ff2b 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -58,6 +58,25 @@ use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence}; +use enumset::{EnumSet, EnumSetType}; + +pub use self::buffers::*; +#[cfg(gdma)] +pub use self::gdma::*; +#[cfg(gdma)] +pub use self::m2m::*; +#[cfg(pdma)] +pub use self::pdma::*; +use crate::{ + interrupt::InterruptHandler, + peripherals::Interrupt, + soc::is_slice_in_dram, + Async, + Blocking, + Cpu, + Mode, +}; + trait Word: crate::private::Sealed {} macro_rules! impl_word { @@ -356,17 +375,6 @@ impl DmaDescriptor { // Send (where the compiler sees fit). unsafe impl Send for DmaDescriptor {} -use enumset::{EnumSet, EnumSetType}; - -pub use self::buffers::*; -#[cfg(gdma)] -pub use self::gdma::*; -#[cfg(gdma)] -pub use self::m2m::*; -#[cfg(pdma)] -pub use self::pdma::*; -use crate::{interrupt::InterruptHandler, soc::is_slice_in_dram, Mode}; - mod buffers; #[cfg(gdma)] mod gdma; @@ -1562,21 +1570,24 @@ impl RxCircularState { } /// A description of a DMA Channel. -pub trait DmaChannel: crate::private::Sealed { +pub trait DmaChannel: crate::private::Sealed + Sized { /// A description of the RX half of a DMA Channel. type Rx: RxRegisterAccess + InterruptAccess; /// A description of the TX half of a DMA Channel. type Tx: TxRegisterAccess + InterruptAccess; + + /// Returns the async interrupt handler. + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler; + + /// Returns the interrupt. + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt]; } #[doc(hidden)] pub trait DmaChannelExt: DmaChannel { fn get_rx_interrupts() -> impl InterruptAccess; fn get_tx_interrupts() -> impl InterruptAccess; - - #[doc(hidden)] - fn set_isr(handler: InterruptHandler); } #[doc(hidden)] @@ -1668,9 +1679,14 @@ impl<'a, CH> ChannelRx<'a, CH> where CH: DmaChannel, { - fn new(rx_impl: CH::Rx, burst_mode: bool) -> Self { + fn new(rx_impl: CH::Rx) -> Self { + #[cfg(gdma)] + // clear the mem2mem mode to avoid failed DMA if this + // channel was previously used for a mem2mem transfer. + rx_impl.set_mem2mem_mode(false); + Self { - burst_mode, + burst_mode: false, rx_impl, _phantom: PhantomData, } @@ -1688,6 +1704,12 @@ where _phantom: PhantomData, } } + + /// Configure the channel. + pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { + self.burst_mode = burst_mode; + self.rx_impl.configure(burst_mode, priority); + } } impl crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} @@ -1886,9 +1908,9 @@ impl<'a, CH> ChannelTx<'a, CH> where CH: DmaChannel, { - fn new(tx_impl: CH::Tx, burst_mode: bool) -> Self { + fn new(tx_impl: CH::Tx) -> Self { Self { - burst_mode, + burst_mode: false, tx_impl, _phantom: PhantomData, } @@ -1906,6 +1928,12 @@ where _phantom: PhantomData, } } + + /// Configure the channel. + pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { + self.burst_mode = burst_mode; + self.tx_impl.configure(burst_mode, priority); + } } impl crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} @@ -2076,6 +2104,12 @@ pub trait RegisterAccess: crate::private::Sealed { #[cfg(pdma)] fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; + + /// Configure the channel. + fn configure(&self, burst_mode: bool, priority: DmaPriority) { + self.set_burst_mode(burst_mode); + self.set_priority(priority); + } } #[doc(hidden)] @@ -2114,31 +2148,38 @@ pub trait InterruptAccess: crate::private::Sealed { } /// DMA Channel -pub struct Channel<'d, CH, MODE> +pub struct Channel<'d, CH, M> where CH: DmaChannel, - MODE: Mode, + M: Mode, { /// RX half of the channel pub rx: ChannelRx<'d, CH>, /// TX half of the channel pub tx: ChannelTx<'d, CH>, - phantom: PhantomData, + pub(crate) phantom: PhantomData, } -impl Channel<'_, C, crate::Blocking> +impl<'d, C> Channel<'d, C, Blocking> where C: DmaChannel, { - /// Sets the interrupt handler for RX and TX interrupts, enables them - /// with [crate::interrupt::Priority::max()] + /// Sets the interrupt handler for RX and TX interrupts. /// /// Interrupts are not enabled at the peripheral level here. pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) where - C: DmaChannelExt, + C: DmaChannel, { - C::set_isr(handler); + self.unlisten(EnumSet::all()); + self.clear_interrupts(EnumSet::all()); + for interrupt in C::interrupts(self).iter().copied() { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); + } } /// Listen for the given interrupts @@ -2182,6 +2223,53 @@ where } } } + + /// Configure the channel. + pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) { + self.tx.configure(burst_mode, priority); + self.rx.configure(burst_mode, priority); + } + + /// Converts a blocking channel to an async channel. + pub fn into_async(mut self) -> Channel<'d, C, Async> { + self.set_interrupt_handler(C::async_handler(&self)); + + Channel { + tx: self.tx, + rx: self.rx, + phantom: PhantomData, + } + } +} + +impl<'d, C> Channel<'d, C, Async> +where + C: DmaChannel, +{ + /// Converts an async channel to a blocking channel. + pub fn into_blocking(self) -> Channel<'d, C, Blocking> { + for interrupt in C::interrupts(&self).iter().copied() { + crate::interrupt::disable(Cpu::current(), interrupt); + } + + Channel { + tx: self.tx, + rx: self.rx, + phantom: PhantomData, + } + } +} + +impl<'d, C: DmaChannel> From> for Channel<'d, C, Async> { + fn from(channel: Channel<'d, C, Blocking>) -> Self { + channel.into_async() + } +} + +impl<'d, C: DmaChannel> From> for Channel<'d, C, Blocking> { + fn from(channel: Channel<'d, C, Async>) -> Self { + channel.into_blocking() + } } impl<'d, CH, M: Mode> Channel<'d, CH, M> @@ -2906,13 +2994,13 @@ pub(crate) mod asynch { #[cfg(i2s0)] #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s0() { + pub(crate) fn interrupt_handler_i2s0_dma() { handle_interrupt::(); } #[cfg(i2s1)] #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s1() { + pub(crate) fn interrupt_handler_i2s1_dma() { handle_interrupt::(); } } diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 56941dd13dc..ab18f2387c0 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -16,7 +16,9 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::{ dma::*, peripheral::PeripheralRef, + peripherals::Interrupt, system::{Peripheral, PeripheralClockControl}, + Blocking, }; type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock; @@ -341,9 +343,27 @@ macro_rules! ImplSpiChannel { #[non_exhaustive] pub struct [] {} + impl [] { + fn handler() -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] + } + + fn isrs() -> &'static [Interrupt] { + &[Interrupt::[< SPI $num _DMA >]] + } + } + impl DmaChannel for [] { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelExt for [] { @@ -353,14 +373,6 @@ macro_rules! ImplSpiChannel { fn get_tx_interrupts() -> impl InterruptAccess { SpiDmaTxChannelImpl(Self {}) } - - fn set_isr(handler: InterruptHandler) { - let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >]; - unsafe { - crate::interrupt::bind_interrupt(interrupt, handler.handler()); - } - crate::interrupt::enable(interrupt, handler.priority()).unwrap(); - } } impl PdmaChannel for [] { @@ -399,59 +411,19 @@ macro_rules! ImplSpiChannel { pub struct [] {} impl [] { - fn do_configure<'a, M: $crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], M> { - #[cfg(esp32)] - { - // (only) on ESP32 we need to configure DPORT for the SPI DMA channels - let dport = unsafe { &*crate::peripherals::DPORT::PTR }; - dport - .spi_dma_chan_sel() - .modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) }); - } - - let tx_impl = SpiDmaTxChannelImpl([] {}); - tx_impl.set_burst_mode(burst_mode); - tx_impl.set_priority(priority); - - let rx_impl = SpiDmaRxChannelImpl([] {}); - rx_impl.set_burst_mode(burst_mode); - rx_impl.set_priority(priority); - - Channel { - tx: ChannelTx::new(tx_impl, burst_mode), - rx: ChannelRx::new(rx_impl, burst_mode), - phantom: PhantomData, - } - } - /// Configure the channel for use with blocking APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. pub fn configure<'a>( self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], $crate::Blocking> { - Self::do_configure(self, burst_mode, priority) - } - - /// Configure the channel for use with async APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. - pub fn configure_for_async<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], $crate::Async> { - let this = Self::do_configure(self, burst_mode, priority); + ) -> Channel<'a, [], Blocking> { + let mut this = Channel { + tx: ChannelTx::new(SpiDmaTxChannelImpl([] {})), + rx: ChannelRx::new(SpiDmaRxChannelImpl([] {})), + phantom: PhantomData, + }; - []::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]); + this.configure(burst_mode, priority); this } @@ -784,9 +756,27 @@ macro_rules! ImplI2sChannel { impl $crate::private::Sealed for [] {} + impl [] { + fn handler() -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] + } + + fn isrs() -> &'static [Interrupt] { + &[Interrupt::[< I2S $num >]] + } + } + impl DmaChannel for [] { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelExt for [] { @@ -796,14 +786,6 @@ macro_rules! ImplI2sChannel { fn get_tx_interrupts() -> impl InterruptAccess { I2sDmaTxChannelImpl(Self {}) } - - fn set_isr(handler: InterruptHandler) { - let interrupt = $crate::peripherals::Interrupt::[< I2S $num >]; - unsafe { - crate::interrupt::bind_interrupt(interrupt, handler.handler()); - } - crate::interrupt::enable(interrupt, handler.priority()).unwrap(); - } } impl PdmaChannel for [] { @@ -838,50 +820,19 @@ macro_rules! ImplI2sChannel { pub struct [] {} impl [] { - fn do_configure<'a, M: $crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], M> { - let tx_impl = I2sDmaTxChannelImpl([] {}); - tx_impl.set_burst_mode(burst_mode); - tx_impl.set_priority(priority); - - let rx_impl = I2sDmaRxChannelImpl([] {}); - rx_impl.set_burst_mode(burst_mode); - rx_impl.set_priority(priority); - - Channel { - tx: ChannelTx::new(tx_impl, burst_mode), - rx: ChannelRx::new(rx_impl, burst_mode), - phantom: PhantomData, - } - } - /// Configure the channel for use with blocking APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. pub fn configure<'a>( self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], $crate::Blocking> { - Self::do_configure(self, burst_mode, priority) - } - - /// Configure the channel for use with async APIs - /// - /// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to - /// transfer buffers of size `1..=4092`, you need 1 descriptor. - pub fn configure_for_async<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], $crate::Async> { - let this = Self::do_configure(self, burst_mode, priority); + ) -> Channel<'a, [], Blocking> { + let mut this = Channel { + tx: ChannelTx::new(I2sDmaTxChannelImpl([] {})), + rx: ChannelRx::new(I2sDmaRxChannelImpl([] {})), + phantom: PhantomData, + }; - []::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]); + this.configure(burst_mode, priority); this } @@ -929,6 +880,19 @@ impl<'d> Dma<'d> { ) -> Dma<'d> { PeripheralClockControl::enable(Peripheral::Dma); + #[cfg(esp32)] + { + // (only) on ESP32 we need to configure DPORT for the SPI DMA channels + // This assignes the DMA channels to the SPI peripherals, which is more + // restrictive than necessary but we currently support the same + // number of SPI peripherals as SPI DMA channels so it's not a big + // deal. + let dport = unsafe { &*crate::peripherals::DPORT::PTR }; + dport.spi_dma_chan_sel().modify(|_, w| unsafe { + w.spi2_dma_chan_sel().bits(1).spi3_dma_chan_sel().bits(2) + }); + } + Dma { _inner: dma.into_ref(), spi2channel: Spi2DmaChannelCreator {}, @@ -962,6 +926,20 @@ impl crate::private::Sealed for AnySpiDmaChannel {} impl DmaChannel for AnySpiDmaChannel { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; + + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { + match &ch.tx.tx_impl.0 { + AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(), + AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(), + } + } + + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + match &ch.tx.tx_impl.0 { + AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(), + AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(), + } + } } crate::any_enum! { @@ -998,6 +976,22 @@ impl crate::private::Sealed for AnyI2sDmaChannel {} impl DmaChannel for AnyI2sDmaChannel { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; + + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { + match &ch.tx.tx_impl.0 { + AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(), + #[cfg(i2s1)] + AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(), + } + } + + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + match &ch.tx.tx_impl.0 { + AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(), + #[cfg(i2s1)] + AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(), + } + } } crate::any_enum! { diff --git a/esp-hal/src/ecc.rs b/esp-hal/src/ecc.rs index 59ee1f891eb..7c6ccfcc2b9 100644 --- a/esp-hal/src/ecc.rs +++ b/esp-hal/src/ecc.rs @@ -30,7 +30,7 @@ use core::marker::PhantomData; use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::ECC, + peripherals::{Interrupt, ECC}, reg_access::{AlignmentHelper, SocDependentEndianess}, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, InterruptConfigurable, @@ -117,11 +117,11 @@ impl crate::private::Sealed for Ecc<'_, crate::Blocking> {} impl InterruptConfigurable for Ecc<'_, crate::Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::ECC, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::ECC, handler.priority()) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::ECC); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::ECC, handler.priority())); } } diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 8b919fd6c9b..452369252f4 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -53,8 +53,16 @@ //! [`embedded-hal`]: https://crates.io/crates/embedded-hal use core::marker::PhantomData; +#[cfg(not(esp32))] +use core::{ + pin::Pin, + task::{Context, Poll}, +}; +use embassy_sync::waitqueue::AtomicWaker; +use embedded_hal::i2c::Operation as EhalOperation; use fugit::HertzU32; +use procmacros::handler; use crate::{ clock::Clocks, @@ -66,6 +74,7 @@ use crate::{ system::PeripheralClockControl, Async, Blocking, + Cpu, InterruptConfigurable, Mode, }; @@ -240,11 +249,123 @@ pub struct I2c<'d, DM: Mode, T = AnyI2c> { timeout: Option, } -impl I2c<'_, DM, T> +impl embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T> +where + T: Instance, +{ + type Error = Error; + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(address, buffer) + } +} + +impl embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T> +where + T: Instance, +{ + type Error = Error; + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(addr, bytes) + } +} + +impl embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T> +where + T: Instance, +{ + type Error = Error; + + fn write_read( + &mut self, + address: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.write_read(address, bytes, buffer) + } +} + +impl embedded_hal::i2c::ErrorType for I2c<'_, DM, T> { + type Error = Error; +} + +impl embedded_hal::i2c::I2c for I2c<'_, DM, T> +where + T: Instance, +{ + fn transaction( + &mut self, + address: u8, + operations: &mut [embedded_hal::i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + self.transaction_impl(address, operations.iter_mut().map(Operation::from)) + } +} + +impl<'d, T, DM: Mode> I2c<'d, DM, T> where T: Instance, - DM: Mode, { + fn new_internal( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, + frequency: HertzU32, + ) -> Self { + crate::into_ref!(i2c); + crate::into_mapped_ref!(sda, scl); + + let i2c = I2c { + i2c, + phantom: PhantomData, + frequency, + timeout: None, + }; + + PeripheralClockControl::reset(i2c.i2c.peripheral()); + PeripheralClockControl::enable(i2c.i2c.peripheral()); + + // TODO: implement with_pins et. al. + // avoid SCL/SDA going low during configuration + scl.set_output_high(true, crate::private::Internal); + sda.set_output_high(true, crate::private::Internal); + + scl.set_to_open_drain_output(crate::private::Internal); + scl.enable_input(true, crate::private::Internal); + scl.pull_direction(Pull::Up, crate::private::Internal); + + scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal); + scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal); + + sda.set_to_open_drain_output(crate::private::Internal); + sda.enable_input(true, crate::private::Internal); + sda.pull_direction(Pull::Up, crate::private::Internal); + + sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal); + sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal); + + i2c.i2c.setup(frequency, None); + i2c + } + + fn internal_recover(&self) { + PeripheralClockControl::reset(self.i2c.peripheral()); + PeripheralClockControl::enable(self.i2c.peripheral()); + + self.i2c.setup(self.frequency, self.timeout); + } + + /// Set the I2C timeout. + // TODO: explain this function better - what's the unit, what happens on + // timeout, and just what exactly is a timeout in this context? + pub fn with_timeout(mut self, timeout: Option) -> Self { + self.timeout = timeout; + self.i2c.setup(self.frequency, self.timeout); + self + } + fn transaction_impl<'a>( &mut self, address: u8, @@ -303,10 +424,50 @@ where } } -impl I2c<'_, Blocking, T> +impl<'d> I2c<'d, Blocking> { + /// Create a new I2C instance + /// This will enable the peripheral but the peripheral won't get + /// automatically disabled when this gets dropped. + pub fn new( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, + frequency: HertzU32, + ) -> Self { + Self::new_typed(i2c.map_into(), sda, scl, frequency) + } +} + +impl<'d, T> I2c<'d, Blocking, T> where T: Instance, { + /// Create a new I2C instance + /// This will enable the peripheral but the peripheral won't get + /// automatically disabled when this gets dropped. + pub fn new_typed( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, + frequency: HertzU32, + ) -> Self { + Self::new_internal(i2c, sda, scl, frequency) + } + + // TODO: missing interrupt APIs + + /// Configures the I2C peripheral to operate in asynchronous mode. + pub fn into_async(mut self) -> I2c<'d, Async, T> { + self.set_interrupt_handler(self.i2c.async_handler()); + + I2c { + i2c: self.i2c, + phantom: PhantomData, + frequency: self.frequency, + timeout: self.timeout, + } + } + /// Reads enough bytes from slave with `address` to fill `buffer` pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); @@ -430,782 +591,587 @@ where } } -impl embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T> +impl crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} + +impl InterruptConfigurable for I2c<'_, Blocking, T> where T: Instance, { - type Error = Error; - - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.read(address, buffer) + fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { + for core in Cpu::other() { + crate::interrupt::disable(core, self.i2c.interrupt()); + } + unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) }; + unwrap!(crate::interrupt::enable( + self.i2c.interrupt(), + handler.priority() + )); } } -impl embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T> +const NUM_I2C: usize = 1 + cfg!(i2c1) as usize; +static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C]; + +#[cfg_attr(esp32, allow(dead_code))] +pub(crate) enum Event { + EndDetect, + TxComplete, + #[cfg(not(any(esp32, esp32s2)))] + TxFifoWatermark, +} + +#[cfg(not(esp32))] +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct I2cFuture<'a, T> where T: Instance, { - type Error = Error; - - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.write(addr, bytes) - } + event: Event, + instance: &'a T, } -impl embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T> +#[cfg(not(esp32))] +impl<'a, T> I2cFuture<'a, T> where T: Instance, { - type Error = Error; + pub fn new(event: Event, instance: &'a T) -> Self { + instance.register_block().int_ena().modify(|_, w| { + let w = match event { + Event::EndDetect => w.end_detect().set_bit(), + Event::TxComplete => w.trans_complete().set_bit(), + #[cfg(not(any(esp32, esp32s2)))] + Event::TxFifoWatermark => w.txfifo_wm().set_bit(), + }; - fn write_read( - &mut self, - address: u8, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.write_read(address, bytes, buffer) + w.arbitration_lost().set_bit(); + w.time_out().set_bit(); + + #[cfg(esp32)] + w.ack_err().set_bit(); + #[cfg(not(esp32))] + w.nack().set_bit(); + + w + }); + + Self { event, instance } } -} -impl embedded_hal::i2c::ErrorType for I2c<'_, DM, T> { - type Error = Error; + fn event_bit_is_clear(&self) -> bool { + let r = self.instance.register_block().int_ena().read(); + + match self.event { + Event::EndDetect => r.end_detect().bit_is_clear(), + Event::TxComplete => r.trans_complete().bit_is_clear(), + #[cfg(not(any(esp32, esp32s2)))] + Event::TxFifoWatermark => r.txfifo_wm().bit_is_clear(), + } + } + + fn check_error(&self) -> Result<(), Error> { + let r = self.instance.register_block().int_raw().read(); + + if r.arbitration_lost().bit_is_set() { + return Err(Error::ArbitrationLost); + } + + if r.time_out().bit_is_set() { + return Err(Error::TimeOut); + } + + #[cfg(not(esp32))] + if r.nack().bit_is_set() { + return Err(Error::AckCheckFailed); + } + + #[cfg(esp32)] + if r.ack_err().bit_is_set() { + return Err(Error::AckCheckFailed); + } + + #[cfg(not(esp32))] + if r.trans_complete().bit_is_set() + && self + .instance + .register_block() + .sr() + .read() + .resp_rec() + .bit_is_clear() + { + return Err(Error::AckCheckFailed); + } + + Ok(()) + } } -impl embedded_hal::i2c::I2c for I2c<'_, DM, T> +#[cfg(not(esp32))] +impl<'a, T> core::future::Future for I2cFuture<'a, T> where T: Instance, { - fn transaction( - &mut self, - address: u8, - operations: &mut [embedded_hal::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - self.transaction_impl(address, operations.iter_mut().map(Operation::from)) + type Output = Result<(), Error>; + + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKERS[self.instance.i2c_number()].register(ctx.waker()); + + let error = self.check_error(); + + if error.is_err() { + return Poll::Ready(error); + } + + if self.event_bit_is_clear() { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } } } -impl<'d, T, DM: Mode> I2c<'d, DM, T> +impl<'d, T> I2c<'d, Async, T> where T: Instance, { - fn new_internal( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - crate::into_ref!(i2c); - crate::into_mapped_ref!(sda, scl); + /// Configure the I2C peripheral to operate in blocking mode. + pub fn into_blocking(self) -> I2c<'d, Blocking, T> { + crate::interrupt::disable(Cpu::current(), self.i2c.interrupt()); - let i2c = I2c { - i2c, + I2c { + i2c: self.i2c, phantom: PhantomData, - frequency, - timeout: None, - }; - - PeripheralClockControl::reset(i2c.i2c.peripheral()); - PeripheralClockControl::enable(i2c.i2c.peripheral()); + frequency: self.frequency, + timeout: self.timeout, + } + } - // TODO: implement with_pins et. al. - // avoid SCL/SDA going low during configuration - scl.set_output_high(true, crate::private::Internal); - sda.set_output_high(true, crate::private::Internal); - - scl.set_to_open_drain_output(crate::private::Internal); - scl.enable_input(true, crate::private::Internal); - scl.pull_direction(Pull::Up, crate::private::Internal); - - scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal); - scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal); - - sda.set_to_open_drain_output(crate::private::Internal); - sda.enable_input(true, crate::private::Internal); - sda.pull_direction(Pull::Up, crate::private::Internal); - - sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal); - sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal); - - i2c.i2c.setup(frequency, None); - i2c - } - - fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) }; - unwrap!(crate::interrupt::enable( - self.i2c.interrupt(), - handler.priority() - )); - } - - fn internal_recover(&self) { - PeripheralClockControl::reset(self.i2c.peripheral()); - PeripheralClockControl::enable(self.i2c.peripheral()); - - self.i2c.setup(self.frequency, self.timeout); - } - - /// Set the I2C timeout. - // TODO: explain this function better - what's the unit, what happens on - // timeout, and just what exactly is a timeout in this context? - pub fn with_timeout(mut self, timeout: Option) -> Self { - self.timeout = timeout; - self.i2c.setup(self.frequency, self.timeout); - self - } -} - -impl<'d> I2c<'d, Blocking> { - /// Create a new I2C instance - /// This will enable the peripheral but the peripheral won't get - /// automatically disabled when this gets dropped. - pub fn new( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_typed(i2c.map_into(), sda, scl, frequency) - } -} + #[cfg(any(esp32, esp32s2))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + if buffer.len() > 32 { + panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); + } -impl<'d, T> I2c<'d, Blocking, T> -where - T: Instance, -{ - /// Create a new I2C instance - /// This will enable the peripheral but the peripheral won't get - /// automatically disabled when this gets dropped. - pub fn new_typed( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_internal(i2c, sda, scl, frequency) - } -} + self.wait_for_completion(false).await?; -impl crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} + for byte in buffer.iter_mut() { + *byte = read_fifo(self.i2c.register_block()); + } -impl InterruptConfigurable for I2c<'_, Blocking, T> -where - T: Instance, -{ - fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - self.internal_set_interrupt_handler(handler); + Ok(()) } -} -impl<'d> I2c<'d, Async> { - /// Create a new I2C instance - /// This will enable the peripheral but the peripheral won't get - /// automatically disabled when this gets dropped. - pub fn new_async( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_async_typed(i2c.map_into(), sda, scl, frequency) + #[cfg(not(any(esp32, esp32s2)))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + self.i2c.read_all_from_fifo(buffer) } -} -impl<'d, T> I2c<'d, Async, T> -where - T: Instance, -{ - /// Create a new I2C instance - /// This will enable the peripheral but the peripheral won't get - /// automatically disabled when this gets dropped. - pub fn new_async_typed( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - let mut this = Self::new_internal(i2c, sda, scl, frequency); + #[cfg(any(esp32, esp32s2))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + if start_index >= bytes.len() { + return Ok(()); + } - this.internal_set_interrupt_handler(this.i2c.async_handler()); + for b in bytes { + write_fifo(self.i2c.register_block(), *b); + self.i2c.check_errors()?; + } - this + Ok(()) } -} -mod asynch { - #[cfg(not(esp32))] - use core::{ - pin::Pin, - task::{Context, Poll}, - }; + #[cfg(not(any(esp32, esp32s2)))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + let mut index = start_index; + loop { + self.i2c.check_errors()?; - use embassy_sync::waitqueue::AtomicWaker; - use embedded_hal::i2c::Operation as EhalOperation; - use procmacros::handler; + I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - use super::*; + self.i2c + .register_block() + .int_clr() + .write(|w| w.txfifo_wm().clear_bit_by_one()); - const NUM_I2C: usize = 1 + cfg!(i2c1) as usize; - static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C]; + I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - #[cfg_attr(esp32, allow(dead_code))] - pub(crate) enum Event { - EndDetect, - TxComplete, - #[cfg(not(any(esp32, esp32s2)))] - TxFifoWatermark, - } + if index >= bytes.len() { + break Ok(()); + } - #[cfg(not(esp32))] - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct I2cFuture<'a, T> - where - T: Instance, - { - event: Event, - instance: &'a T, + write_fifo(self.i2c.register_block(), bytes[index]); + index += 1; + } } #[cfg(not(esp32))] - impl<'a, T> I2cFuture<'a, T> - where - T: Instance, - { - pub fn new(event: Event, instance: &'a T) -> Self { - instance.register_block().int_ena().modify(|_, w| { - let w = match event { - Event::EndDetect => w.end_detect().set_bit(), - Event::TxComplete => w.trans_complete().set_bit(), - #[cfg(not(any(esp32, esp32s2)))] - Event::TxFifoWatermark => w.txfifo_wm().set_bit(), - }; - - w.arbitration_lost().set_bit(); - w.time_out().set_bit(); - - #[cfg(esp32)] - w.ack_err().set_bit(); - #[cfg(not(esp32))] - w.nack().set_bit(); - - w - }); - - Self { event, instance } - } + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + self.i2c.check_errors()?; - fn event_bit_is_clear(&self) -> bool { - let r = self.instance.register_block().int_ena().read(); - - match self.event { - Event::EndDetect => r.end_detect().bit_is_clear(), - Event::TxComplete => r.trans_complete().bit_is_clear(), - #[cfg(not(any(esp32, esp32s2)))] - Event::TxFifoWatermark => r.txfifo_wm().bit_is_clear(), + if end_only { + I2cFuture::new(Event::EndDetect, &*self.i2c).await?; + } else { + let res = embassy_futures::select::select( + I2cFuture::new(Event::TxComplete, &*self.i2c), + I2cFuture::new(Event::EndDetect, &*self.i2c), + ) + .await; + + match res { + embassy_futures::select::Either::First(res) => res?, + embassy_futures::select::Either::Second(res) => res?, } } + self.i2c.check_all_commands_done()?; - fn check_error(&self) -> Result<(), Error> { - let r = self.instance.register_block().int_raw().read(); + Ok(()) + } - if r.arbitration_lost().bit_is_set() { - return Err(Error::ArbitrationLost); - } + #[cfg(esp32)] + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + // for ESP32 we need a timeout here but wasting a timer seems unnecessary + // given the short time we spend here - if r.time_out().bit_is_set() { - return Err(Error::TimeOut); - } + let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop + loop { + let interrupts = self.i2c.register_block().int_raw().read(); - #[cfg(not(esp32))] - if r.nack().bit_is_set() { - return Err(Error::AckCheckFailed); - } + self.i2c.check_errors()?; - #[cfg(esp32)] - if r.ack_err().bit_is_set() { - return Err(Error::AckCheckFailed); + // Handle completion cases + // A full transmission was completed (either a STOP condition or END was + // processed) + if (!end_only && interrupts.trans_complete().bit_is_set()) + || interrupts.end_detect().bit_is_set() + { + break; } - #[cfg(not(esp32))] - if r.trans_complete().bit_is_set() - && self - .instance - .register_block() - .sr() - .read() - .resp_rec() - .bit_is_clear() - { - return Err(Error::AckCheckFailed); + tout -= 1; + if tout == 0 { + return Err(Error::TimeOut); } - Ok(()) + embassy_futures::yield_now().await; } + self.i2c.check_all_commands_done()?; + Ok(()) } - #[cfg(not(esp32))] - impl core::future::Future for I2cFuture<'_, T> + /// Executes an async I2C write operation. + /// - `addr` is the address of the slave device. + /// - `bytes` is the data two be sent. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `cmd_iterator` is an iterator over the command registers. + async fn write_operation<'a, I>( + &self, + address: u8, + bytes: &[u8], + start: bool, + stop: bool, + cmd_iterator: &mut I, + ) -> Result<(), Error> where - T: Instance, + I: Iterator, { - type Output = Result<(), Error>; - - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKERS[self.instance.i2c_number()].register(ctx.waker()); - - let error = self.check_error(); - - if error.is_err() { - return Poll::Ready(error); - } + // Short circuit for zero length writes without start or end as that would be an + // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 + if bytes.is_empty() && !start && !stop { + return Ok(()); + } - if self.event_bit_is_clear() { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } + // Reset FIFO and command list + self.i2c.reset_fifo(); + self.i2c.reset_command_list(); + if start { + add_cmd(cmd_iterator, Command::Start)?; } + self.i2c.setup_write(address, bytes, start, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + let index = self.i2c.fill_tx_fifo(bytes); + self.i2c.start_transmission(); + + // Fill the FIFO with the remaining bytes: + self.write_remaining_tx_fifo(index, bytes).await?; + self.wait_for_completion(!stop).await?; + Ok(()) } - impl I2c<'_, Async, T> + /// Executes an async I2C read operation. + /// - `addr` is the address of the slave device. + /// - `buffer` is the buffer to store the read data. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `will_continue` indicates whether there is another read operation + /// following this one and we should not nack the last byte. + /// - `cmd_iterator` is an iterator over the command registers. + async fn read_operation<'a, I>( + &self, + address: u8, + buffer: &mut [u8], + start: bool, + stop: bool, + will_continue: bool, + cmd_iterator: &mut I, + ) -> Result<(), Error> where - T: Instance, + I: Iterator, { - #[cfg(any(esp32, esp32s2))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() > 32 { - panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); - } - - self.wait_for_completion(false).await?; - - for byte in buffer.iter_mut() { - *byte = read_fifo(self.i2c.register_block()); - } - - Ok(()) + // Short circuit for zero length reads as that would be an invalid operation + // read lengths in the TRM (at least for ESP32-S3) are 1-255 + if buffer.is_empty() { + return Ok(()); } - #[cfg(not(any(esp32, esp32s2)))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - self.i2c.read_all_from_fifo(buffer) + // Reset FIFO and command list + self.i2c.reset_fifo(); + self.i2c.reset_command_list(); + if start { + add_cmd(cmd_iterator, Command::Start)?; } + self.i2c + .setup_read(address, buffer, start, will_continue, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + self.i2c.start_transmission(); + self.read_all_from_fifo(buffer).await?; + self.wait_for_completion(!stop).await?; + Ok(()) + } - #[cfg(any(esp32, esp32s2))] - async fn write_remaining_tx_fifo( - &self, - start_index: usize, - bytes: &[u8], - ) -> Result<(), Error> { - if start_index >= bytes.len() { - return Ok(()); - } + /// Writes bytes to slave with address `address` + pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); - for b in bytes { - write_fifo(self.i2c.register_block(), *b); - self.i2c.check_errors()?; - } + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - Ok(()) + self.write_operation( + address, + chunk, + idx == 0, + idx == chunk_count - 1, + cmd_iterator, + ) + .await?; } - #[cfg(not(any(esp32, esp32s2)))] - async fn write_remaining_tx_fifo( - &self, - start_index: usize, - bytes: &[u8], - ) -> Result<(), Error> { - let mut index = start_index; - loop { - self.i2c.check_errors()?; - - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - - self.i2c - .register_block() - .int_clr() - .write(|w| w.txfifo_wm().clear_bit_by_one()); + Ok(()) + } - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; + /// Reads enough bytes from slave with `address` to fill `buffer` + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); - if index >= bytes.len() { - break Ok(()); - } + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - write_fifo(self.i2c.register_block(), bytes[index]); - index += 1; - } + self.read_operation( + address, + chunk, + idx == 0, + idx == chunk_count - 1, + idx < chunk_count - 1, + cmd_iterator, + ) + .await?; } - #[cfg(not(esp32))] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - self.i2c.check_errors()?; + Ok(()) + } - if end_only { - I2cFuture::new(Event::EndDetect, &*self.i2c).await?; - } else { - let res = embassy_futures::select::select( - I2cFuture::new(Event::TxComplete, &*self.i2c), - I2cFuture::new(Event::EndDetect, &*self.i2c), - ) - .await; + /// Writes bytes to slave with address `address` and then reads enough + /// bytes to fill `buffer` *in a single transaction* + pub async fn write_read( + &mut self, + address: u8, + write_buffer: &[u8], + read_buffer: &mut [u8], + ) -> Result<(), Error> { + let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); + let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); - match res { - embassy_futures::select::Either::First(res) => res?, - embassy_futures::select::Either::Second(res) => res?, - } - } - self.i2c.check_all_commands_done()?; + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - Ok(()) + self.write_operation( + address, + chunk, + idx == 0, + idx == write_count - 1 && read_count == 0, + cmd_iterator, + ) + .await?; } - #[cfg(esp32)] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - // for ESP32 we need a timeout here but wasting a timer seems unnecessary - // given the short time we spend here - - let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop - loop { - let interrupts = self.i2c.register_block().int_raw().read(); - - self.i2c.check_errors()?; - - // Handle completion cases - // A full transmission was completed (either a STOP condition or END was - // processed) - if (!end_only && interrupts.trans_complete().bit_is_set()) - || interrupts.end_detect().bit_is_set() - { - break; - } - - tout -= 1; - if tout == 0 { - return Err(Error::TimeOut); - } - - embassy_futures::yield_now().await; - } - self.i2c.check_all_commands_done()?; - Ok(()) - } - - /// Executes an async I2C write operation. - /// - `addr` is the address of the slave device. - /// - `bytes` is the data two be sent. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `cmd_iterator` is an iterator over the command registers. - async fn write_operation<'a, I>( - &self, - address: u8, - bytes: &[u8], - start: bool, - stop: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length writes without start or end as that would be an - // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 - if bytes.is_empty() && !start && !stop { - return Ok(()); - } + for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); - // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.i2c.setup_write(address, bytes, start, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - let index = self.i2c.fill_tx_fifo(bytes); - self.i2c.start_transmission(); - - // Fill the FIFO with the remaining bytes: - self.write_remaining_tx_fifo(index, bytes).await?; - self.wait_for_completion(!stop).await?; - Ok(()) - } - - /// Executes an async I2C read operation. - /// - `addr` is the address of the slave device. - /// - `buffer` is the buffer to store the read data. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `will_continue` indicates whether there is another read operation - /// following this one and we should not nack the last byte. - /// - `cmd_iterator` is an iterator over the command registers. - async fn read_operation<'a, I>( - &self, - address: u8, - buffer: &mut [u8], - start: bool, - stop: bool, - will_continue: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length reads as that would be an invalid operation - // read lengths in the TRM (at least for ESP32-S3) are 1-255 - if buffer.is_empty() { - return Ok(()); - } + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.i2c - .setup_read(address, buffer, start, will_continue, cmd_iterator)?; - add_cmd( + self.read_operation( + address, + chunk, + idx == 0, + idx == read_count - 1, + idx < read_count - 1, cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - self.i2c.start_transmission(); - self.read_all_from_fifo(buffer).await?; - self.wait_for_completion(!stop).await?; - Ok(()) + ) + .await?; } - /// Writes bytes to slave with address `address` - pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - cmd_iterator, - ) - .await?; - } + Ok(()) + } - Ok(()) - } + /// Execute the provided operations on the I2C bus as a single + /// transaction. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This + /// is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each + /// other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is + /// sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an + /// acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 + /// to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + pub async fn transaction<'a>( + &mut self, + address: u8, + operations: impl IntoIterator>, + ) -> Result<(), Error> { + self.transaction_impl_async(address, operations.into_iter().map(Operation::from)) + .await + } - /// Reads enough bytes from slave with `address` to fill `buffer` - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + async fn transaction_impl_async<'a>( + &mut self, + address: u8, + operations: impl Iterator>, + ) -> Result<(), Error> { + let mut last_op: Option = None; + // filter out 0 length read operations + let mut op_iter = operations + .filter(|op| op.is_write() || !op.is_empty()) + .peekable(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + while let Some(op) = op_iter.next() { + let next_op = op_iter.peek().map(|v| v.kind()); + let kind = op.kind(); + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); - self.read_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - idx < chunk_count - 1, - cmd_iterator, - ) - .await?; + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + match op { + Operation::Write(buffer) => { + // execute a write operation: + // - issue START/RSTART if op is different from previous + // - issue STOP if op is the last one + self.write_operation( + address, + buffer, + !matches!(last_op, Some(OpKind::Write)), + next_op.is_none(), + cmd_iterator, + ) + .await?; + } + Operation::Read(buffer) => { + // execute a read operation: + // - issue START/RSTART if op is different from previous + // - issue STOP if op is the last one + // - will_continue is true if there is another read operation next + self.read_operation( + address, + buffer, + !matches!(last_op, Some(OpKind::Read)), + next_op.is_none(), + matches!(next_op, Some(OpKind::Read)), + cmd_iterator, + ) + .await?; + } } - Ok(()) + last_op = Some(kind); } - /// Writes bytes to slave with address `address` and then reads enough - /// bytes to fill `buffer` *in a single transaction* - pub async fn write_read( - &mut self, - address: u8, - write_buffer: &[u8], - read_buffer: &mut [u8], - ) -> Result<(), Error> { - let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); - let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == write_count - 1 && read_count == 0, - cmd_iterator, - ) - .await?; - } - - for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.read_operation( - address, - chunk, - idx == 0, - idx == read_count - 1, - idx < read_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) - } - - /// Execute the provided operations on the I2C bus as a single - /// transaction. - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. - /// This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each - /// other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W - /// is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an - /// acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or - /// 0 to indicate writing - /// - `SR` = repeated start condition - /// - `SP` = stop condition - pub async fn transaction<'a>( - &mut self, - address: u8, - operations: impl IntoIterator>, - ) -> Result<(), Error> { - self.transaction_impl_async(address, operations.into_iter().map(Operation::from)) - .await - } - - async fn transaction_impl_async<'a>( - &mut self, - address: u8, - operations: impl Iterator>, - ) -> Result<(), Error> { - let mut last_op: Option = None; - // filter out 0 length read operations - let mut op_iter = operations - .filter(|op| op.is_write() || !op.is_empty()) - .peekable(); - - while let Some(op) = op_iter.next() { - let next_op = op_iter.peek().map(|v| v.kind()); - let kind = op.kind(); - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - match op { - Operation::Write(buffer) => { - // execute a write operation: - // - issue START/RSTART if op is different from previous - // - issue STOP if op is the last one - self.write_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Write)), - next_op.is_none(), - cmd_iterator, - ) - .await?; - } - Operation::Read(buffer) => { - // execute a read operation: - // - issue START/RSTART if op is different from previous - // - issue STOP if op is the last one - // - will_continue is true if there is another read operation next - self.read_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Read)), - next_op.is_none(), - matches!(next_op, Some(OpKind::Read)), - cmd_iterator, - ) - .await?; - } - } - - last_op = Some(kind); - } + Ok(()) + } +} - Ok(()) - } +impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, Async, T> +where + T: Instance, +{ + async fn transaction( + &mut self, + address: u8, + operations: &mut [EhalOperation<'_>], + ) -> Result<(), Self::Error> { + self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) + .await } +} - impl embedded_hal_async::i2c::I2c for I2c<'_, Async, T> - where - T: Instance, - { - async fn transaction( - &mut self, - address: u8, - operations: &mut [EhalOperation<'_>], - ) -> Result<(), Self::Error> { - self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) - .await - } - } - - fn handler(regs: &RegisterBlock) { - regs.int_ena().modify(|_, w| { - w.end_detect().clear_bit(); - w.trans_complete().clear_bit(); - w.arbitration_lost().clear_bit(); - w.time_out().clear_bit() - }); +fn handler(regs: &RegisterBlock) { + regs.int_ena().modify(|_, w| { + w.end_detect().clear_bit(); + w.trans_complete().clear_bit(); + w.arbitration_lost().clear_bit(); + w.time_out().clear_bit() + }); - #[cfg(not(any(esp32, esp32s2)))] - regs.int_ena().modify(|_, w| w.txfifo_wm().clear_bit()); + #[cfg(not(any(esp32, esp32s2)))] + regs.int_ena().modify(|_, w| w.txfifo_wm().clear_bit()); - #[cfg(not(esp32))] - regs.int_ena().modify(|_, w| w.nack().clear_bit()); + #[cfg(not(esp32))] + regs.int_ena().modify(|_, w| w.nack().clear_bit()); - #[cfg(esp32)] - regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); - } + #[cfg(esp32)] + regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); +} - #[handler] - pub(super) fn i2c0_handler() { - let regs = unsafe { &*crate::peripherals::I2C0::PTR }; - handler(regs); +#[handler] +pub(super) fn i2c0_handler() { + let regs = unsafe { crate::peripherals::I2C0::steal() }; + handler(regs.register_block()); - WAKERS[0].wake(); - } + WAKERS[0].wake(); +} - #[cfg(i2c1)] - #[handler] - pub(super) fn i2c1_handler() { - let regs = unsafe { &*crate::peripherals::I2C1::PTR }; - handler(regs); +#[cfg(i2c1)] +#[handler] +pub(super) fn i2c1_handler() { + let regs = unsafe { crate::peripherals::I2C1::steal() }; + handler(regs.register_block()); - WAKERS[1].wake(); - } + WAKERS[1].wake(); } /// I2C Peripheral Instance @@ -2248,7 +2214,7 @@ impl PeripheralMarker for crate::peripherals::I2C0 { impl Instance for crate::peripherals::I2C0 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { - asynch::i2c0_handler + i2c0_handler } #[inline(always)] @@ -2299,7 +2265,7 @@ impl PeripheralMarker for crate::peripherals::I2C1 { impl Instance for crate::peripherals::I2C1 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { - asynch::i2c1_handler + i2c1_handler } #[inline(always)] diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index d17e87a8859..c5b2c1bbc34 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -107,6 +107,8 @@ use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, system::PeripheralClockControl, + Async, + Blocking, InterruptConfigurable, Mode, }; @@ -253,16 +255,16 @@ impl DataFormat { } /// Instance of the I2S peripheral driver -pub struct I2s<'d, DmaMode, T = AnyI2s> +pub struct I2s<'d, M, T = AnyI2s> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { /// Handles the reception (RX) side of the I2S peripheral. - pub i2s_rx: RxCreator<'d, DmaMode, T>, + pub i2s_rx: RxCreator<'d, M, T>, /// Handles the transmission (TX) side of the I2S peripheral. - pub i2s_tx: TxCreator<'d, DmaMode, T>, - phantom: PhantomData, + pub i2s_tx: TxCreator<'d, M, T>, + phantom: PhantomData, } impl<'d, DmaMode, T> I2s<'d, DmaMode, T> @@ -369,24 +371,23 @@ where } } -impl<'d, DmaMode> I2s<'d, DmaMode> -where - DmaMode: Mode, -{ +impl<'d> I2s<'d, Blocking> { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert<::Dma>, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { Self::new_typed( i2s.map_into(), @@ -400,25 +401,26 @@ where } } -impl<'d, DmaMode, T> I2s<'d, DmaMode, T> +impl<'d, T> I2s<'d, Blocking, T> where T: RegisterAccess, - DmaMode: Mode, { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new_typed( + pub fn new_typed( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { crate::into_ref!(i2s); Self::new_internal( @@ -426,12 +428,43 @@ where standard, data_format, sample_rate, - channel, + channel.into(), rx_descriptors, tx_descriptors, ) } + /// Converts the SPI instance into async mode. + pub fn into_async(self) -> I2s<'d, Async, T> { + let channel = Channel { + rx: self.i2s_rx.rx_channel, + tx: self.i2s_tx.tx_channel, + phantom: PhantomData::, + }; + let channel = channel.into_async(); + I2s { + i2s_rx: RxCreator { + i2s: self.i2s_rx.i2s, + rx_channel: channel.rx, + descriptors: self.i2s_rx.descriptors, + phantom: PhantomData, + }, + i2s_tx: TxCreator { + i2s: self.i2s_tx.i2s, + tx_channel: channel.tx, + descriptors: self.i2s_tx.descriptors, + phantom: PhantomData, + }, + phantom: PhantomData, + } + } +} + +impl<'d, M, T> I2s<'d, M, T> +where + T: RegisterAccess, + M: Mode, +{ /// Configures the I2S peripheral to use a master clock (MCLK) output pin. pub fn with_mclk(self, pin: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(pin); @@ -757,20 +790,20 @@ mod private { }, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::I2S0, + peripherals::{Interrupt, I2S0}, private, Mode, }; - pub struct TxCreator<'d, DmaMode, T> + pub struct TxCreator<'d, M, T> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { pub i2s: PeripheralRef<'d, T>, pub tx_channel: ChannelTx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, + pub(crate) phantom: PhantomData, } impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T> @@ -821,23 +854,23 @@ mod private { } } - pub struct RxCreator<'d, DmaMode, T> + pub struct RxCreator<'d, M, T> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { pub i2s: PeripheralRef<'d, T>, pub rx_channel: ChannelRx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, + pub(crate) phantom: PhantomData, } - impl<'d, DmaMode, T> RxCreator<'d, DmaMode, T> + impl<'d, M, T> RxCreator<'d, M, T> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { - pub fn build(self) -> I2sRx<'d, DmaMode, T> { + pub fn build(self) -> I2sRx<'d, M, T> { I2sRx { i2s: self.i2s, rx_channel: self.rx_channel, @@ -1582,9 +1615,14 @@ mod private { impl RegisterAccessPrivate for I2S0 { fn set_interrupt_handler(&self, handler: InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::I2S0); + } unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::I2S0, + handler.priority() + )); } } @@ -1682,9 +1720,14 @@ mod private { #[cfg(i2s1)] impl RegisterAccessPrivate for I2S1 { fn set_interrupt_handler(&self, handler: InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::I2S1); + } unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::I2S1, + handler.priority() + )); } } diff --git a/esp-hal/src/interrupt/software.rs b/esp-hal/src/interrupt/software.rs index 64156a68d91..8b4284f7b33 100644 --- a/esp-hal/src/interrupt/software.rs +++ b/esp-hal/src/interrupt/software.rs @@ -62,10 +62,11 @@ impl SoftwareInterrupt { _ => unreachable!(), }; - unsafe { - crate::interrupt::bind_interrupt(interrupt, handler.handler()); - crate::interrupt::enable(interrupt, handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); } + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); } /// Trigger this software-interrupt diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index abf7b5d398f..dee3a375949 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -81,7 +81,7 @@ use crate::{ OutputSignal, Pull, }, - lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder}, + lcd_cam::{calculate_clkm, BitOrder, ByteOrder}, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, }; @@ -604,8 +604,7 @@ impl RxPins for RxSixteenBits { const BUS_WIDTH: usize = 2; } -mod private { - pub trait RxPins { - const BUS_WIDTH: usize; - } +#[doc(hidden)] +pub trait RxPins { + const BUS_WIDTH: usize; } diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 72ab45dea80..2017f4d07cb 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -75,12 +75,13 @@ use crate::{ OutputSignal, }, lcd_cam::{ - asynch::LCD_DONE_WAKER, - lcd::{i8080::private::TxPins, ClockMode, DelayMode, Phase, Polarity}, - private::{calculate_clkm, Instance}, + calculate_clkm, + lcd::{ClockMode, DelayMode, Phase, Polarity}, BitOrder, ByteOrder, + Instance, Lcd, + LCD_DONE_WAKER, }, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, @@ -703,8 +704,7 @@ impl<'d> TxPins for TxSixteenBits<'d> { } } -mod private { - pub trait TxPins { - fn configure(&mut self); - } +#[doc(hidden)] +pub trait TxPins { + fn configure(&mut self); } diff --git a/esp-hal/src/lcd_cam/mod.rs b/esp-hal/src/lcd_cam/mod.rs index 38a29f83b4a..b7172260d3f 100644 --- a/esp-hal/src/lcd_cam/mod.rs +++ b/esp-hal/src/lcd_cam/mod.rs @@ -10,12 +10,18 @@ pub mod lcd; use core::marker::PhantomData; +use embassy_sync::waitqueue::AtomicWaker; + use crate::{ interrupt::InterruptHandler, lcd_cam::{cam::Cam, lcd::Lcd}, + macros::handler, peripheral::Peripheral, - peripherals::LCD_CAM, + peripherals::{Interrupt, LCD_CAM}, system::{self, PeripheralClockControl}, + Async, + Blocking, + Cpu, InterruptConfigurable, }; @@ -27,7 +33,7 @@ pub struct LcdCam<'d, DM: crate::Mode> { pub cam: Cam<'d>, } -impl<'d> LcdCam<'d, crate::Blocking> { +impl<'d> LcdCam<'d, Blocking> { /// Creates a new `LcdCam` instance. pub fn new(lcd_cam: impl Peripheral

+ 'd) -> Self { crate::into_ref!(lcd_cam); @@ -40,56 +46,49 @@ impl<'d> LcdCam<'d, crate::Blocking> { lcd_cam: unsafe { lcd_cam.clone_unchecked() }, _mode: PhantomData, }, - cam: Cam { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, + cam: Cam { lcd_cam }, + } + } + + /// Reconfigures the peripheral for asynchronous operation. + pub fn into_async(mut self) -> LcdCam<'d, Async> { + self.set_interrupt_handler(interrupt_handler); + LcdCam { + lcd: Lcd { + lcd_cam: self.lcd.lcd_cam, + _mode: PhantomData, }, + cam: self.cam, } } } -impl<'d> crate::private::Sealed for LcdCam<'d, crate::Blocking> {} +impl crate::private::Sealed for LcdCam<'_, Blocking> {} // TODO: This interrupt is shared with the Camera module, we should handle this // in a similar way to the gpio::IO -impl<'d> InterruptConfigurable for LcdCam<'d, crate::Blocking> { +impl InterruptConfigurable for LcdCam<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt( - crate::peripherals::Interrupt::LCD_CAM, - handler.handler(), - ); - crate::interrupt::enable(crate::peripherals::Interrupt::LCD_CAM, handler.priority()) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::LCD_CAM); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) }; + unwrap!(crate::interrupt::enable( + Interrupt::LCD_CAM, + handler.priority() + )); } } -impl<'d> LcdCam<'d, crate::Async> { - /// Creates a new `LcdCam` instance for asynchronous operation. - pub fn new_async(lcd_cam: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(lcd_cam); - - PeripheralClockControl::enable(system::Peripheral::LcdCam); - - unsafe { - crate::interrupt::bind_interrupt( - crate::peripherals::Interrupt::LCD_CAM, - asynch::interrupt_handler.handler(), - ); - } - crate::interrupt::enable( - crate::peripherals::Interrupt::LCD_CAM, - asynch::interrupt_handler.priority(), - ) - .unwrap(); - - Self { +impl<'d> LcdCam<'d, Async> { + /// Reconfigures the peripheral for blocking operation. + pub fn into_blocking(self) -> LcdCam<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM); + LcdCam { lcd: Lcd { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, + lcd_cam: self.lcd.lcd_cam, _mode: PhantomData, }, - cam: Cam { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, - }, + cam: self.cam, } } } @@ -116,205 +115,193 @@ pub enum ByteOrder { Inverted = 1, } -#[doc(hidden)] -pub mod asynch { - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; - - use super::private::Instance; - - pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new(); +pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new(); - #[handler] - pub(crate) fn interrupt_handler() { - // TODO: this is a shared interrupt with Camera and here we ignore that! - if Instance::is_lcd_done_set() { - Instance::unlisten_lcd_done(); - LCD_DONE_WAKER.wake() - } +#[handler] +fn interrupt_handler() { + // TODO: this is a shared interrupt with Camera and here we ignore that! + if Instance::is_lcd_done_set() { + Instance::unlisten_lcd_done(); + LCD_DONE_WAKER.wake() } } -mod private { - use crate::peripherals::LCD_CAM; - - pub(crate) struct Instance; - - // NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and - // this is only implemented for the LCD side, when the Camera is implemented a - // CriticalSection will be needed to protect these shared registers. - impl Instance { - pub(crate) fn listen_lcd_done() { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_ena() - .modify(|_, w| w.lcd_trans_done_int_ena().set_bit()); - } - - pub(crate) fn unlisten_lcd_done() { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_ena() - .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit()); - } +pub(crate) struct Instance; + +// NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and +// this is only implemented for the LCD side, when the Camera is implemented a +// CriticalSection will be needed to protect these shared registers. +impl Instance { + pub(crate) fn listen_lcd_done() { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_ena() + .modify(|_, w| w.lcd_trans_done_int_ena().set_bit()); + } - pub(crate) fn is_lcd_done_set() -> bool { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_raw() - .read() - .lcd_trans_done_int_raw() - .bit() - } + pub(crate) fn unlisten_lcd_done() { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_ena() + .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit()); } - pub struct ClockDivider { - // Integral LCD clock divider value. (8 bits) - // Value 0 is treated as 256 - // Value 1 is treated as 2 - // Value N is treated as N - pub div_num: usize, - - // Fractional clock divider numerator value. (6 bits) - pub div_b: usize, - - // Fractional clock divider denominator value. (6 bits) - pub div_a: usize, + + pub(crate) fn is_lcd_done_set() -> bool { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_raw() + .read() + .lcd_trans_done_int_raw() + .bit() } +} +pub(crate) struct ClockDivider { + // Integral LCD clock divider value. (8 bits) + // Value 0 is treated as 256 + // Value 1 is treated as 2 + // Value N is treated as N + pub div_num: usize, + + // Fractional clock divider numerator value. (6 bits) + pub div_b: usize, + + // Fractional clock divider denominator value. (6 bits) + pub div_a: usize, +} - pub fn calculate_clkm( - desired_frequency: usize, - source_frequencies: &[usize], - ) -> (usize, ClockDivider) { - let mut result_freq = 0; - let mut result = None; - - for (i, &source_frequency) in source_frequencies.iter().enumerate() { - let div = calculate_closest_divider(source_frequency, desired_frequency); - if let Some(div) = div { - let freq = calculate_output_frequency(source_frequency, &div); - if result.is_none() || freq > result_freq { - result = Some((i, div)); - result_freq = freq; - } +pub(crate) fn calculate_clkm( + desired_frequency: usize, + source_frequencies: &[usize], +) -> (usize, ClockDivider) { + let mut result_freq = 0; + let mut result = None; + + for (i, &source_frequency) in source_frequencies.iter().enumerate() { + let div = calculate_closest_divider(source_frequency, desired_frequency); + if let Some(div) = div { + let freq = calculate_output_frequency(source_frequency, &div); + if result.is_none() || freq > result_freq { + result = Some((i, div)); + result_freq = freq; } } - - result.expect("Desired frequency was too low for the dividers to divide to") } - fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { - let n = match divider.div_num { - 0 => 256, - 1 => 2, - _ => divider.div_num.min(256), - }; + result.expect("Desired frequency was too low for the dividers to divide to") +} - if divider.div_b != 0 && divider.div_a != 0 { - // OUTPUT = SOURCE / (N + B/A) - // OUTPUT = SOURCE / ((NA + B)/A) - // OUTPUT = (SOURCE * A) / (NA + B) +fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { + let n = match divider.div_num { + 0 => 256, + 1 => 2, + _ => divider.div_num.min(256), + }; - // u64 is required to fit the numbers from this arithmetic. + if divider.div_b != 0 && divider.div_a != 0 { + // OUTPUT = SOURCE / (N + B/A) + // OUTPUT = SOURCE / ((NA + B)/A) + // OUTPUT = (SOURCE * A) / (NA + B) - let source = source_frequency as u64; - let n = n as u64; - let a = divider.div_b as u64; - let b = divider.div_a as u64; + // u64 is required to fit the numbers from this arithmetic. - ((source * a) / (n * a + b)) as _ - } else { - source_frequency / n - } - } + let source = source_frequency as u64; + let n = n as u64; + let a = divider.div_b as u64; + let b = divider.div_a as u64; - fn calculate_closest_divider( - source_frequency: usize, - desired_frequency: usize, - ) -> Option { - let div_num = source_frequency / desired_frequency; - if div_num < 2 { - // Source clock isn't fast enough to reach the desired frequency. - // Return max output. - return Some(ClockDivider { - div_num: 1, - div_b: 0, - div_a: 0, - }); - } - if div_num > 256 { - // Source is too fast to divide to the desired frequency. Return None. - return None; - } + ((source * a) / (n * a + b)) as _ + } else { + source_frequency / n + } +} - let div_num = if div_num == 256 { 0 } else { div_num }; +fn calculate_closest_divider( + source_frequency: usize, + desired_frequency: usize, +) -> Option { + let div_num = source_frequency / desired_frequency; + if div_num < 2 { + // Source clock isn't fast enough to reach the desired frequency. + // Return max output. + return Some(ClockDivider { + div_num: 1, + div_b: 0, + div_a: 0, + }); + } + if div_num > 256 { + // Source is too fast to divide to the desired frequency. Return None. + return None; + } - let div_fraction = { - let div_remainder = source_frequency % desired_frequency; - let gcd = hcf(div_remainder, desired_frequency); - Fraction { - numerator: div_remainder / gcd, - denominator: desired_frequency / gcd, - } - }; + let div_num = if div_num == 256 { 0 } else { div_num }; - let divider = if div_fraction.numerator == 0 { - ClockDivider { - div_num, - div_b: 0, - div_a: 0, - } - } else { - let target = div_fraction; - let closest = farey_sequence(63) - .find(|curr| { - // https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities - - let new_curr_num = curr.numerator * target.denominator; - let new_target_num = target.numerator * curr.denominator; - new_curr_num >= new_target_num - }) - .expect("The fraction must be between 0 and 1"); - - ClockDivider { - div_num, - div_b: closest.numerator, - div_a: closest.denominator, - } - }; - Some(divider) - } + let div_fraction = { + let div_remainder = source_frequency % desired_frequency; + let gcd = hcf(div_remainder, desired_frequency); + Fraction { + numerator: div_remainder / gcd, + denominator: desired_frequency / gcd, + } + }; - // https://en.wikipedia.org/wiki/Euclidean_algorithm - const fn hcf(a: usize, b: usize) -> usize { - if b != 0 { - hcf(b, a % b) - } else { - a + let divider = if div_fraction.numerator == 0 { + ClockDivider { + div_num, + div_b: 0, + div_a: 0, } - } + } else { + let target = div_fraction; + let closest = farey_sequence(63) + .find(|curr| { + // https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities + + let new_curr_num = curr.numerator * target.denominator; + let new_target_num = target.numerator * curr.denominator; + new_curr_num >= new_target_num + }) + .expect("The fraction must be between 0 and 1"); + + ClockDivider { + div_num, + div_b: closest.numerator, + div_a: closest.denominator, + } + }; + Some(divider) +} - struct Fraction { - pub numerator: usize, - pub denominator: usize, +// https://en.wikipedia.org/wiki/Euclidean_algorithm +const fn hcf(a: usize, b: usize) -> usize { + if b != 0 { + hcf(b, a % b) + } else { + a } +} - // https://en.wikipedia.org/wiki/Farey_sequence#Next_term - fn farey_sequence(denominator: usize) -> impl Iterator { - let mut a = 0; - let mut b = 1; - let mut c = 1; - let mut d = denominator; - core::iter::from_fn(move || { - if a > denominator { - return None; - } - let next = Fraction { - numerator: a, - denominator: b, - }; - let k = (denominator + b) / d; - (a, b, c, d) = (c, d, k * c - a, k * d - b); - Some(next) - }) - } +struct Fraction { + pub numerator: usize, + pub denominator: usize, +} + +// https://en.wikipedia.org/wiki/Farey_sequence#Next_term +fn farey_sequence(denominator: usize) -> impl Iterator { + let mut a = 0; + let mut b = 1; + let mut c = 1; + let mut d = denominator; + core::iter::from_fn(move || { + if a > denominator { + return None; + } + let next = Fraction { + numerator: a, + denominator: b, + }; + let k = (denominator + b) / d; + (a, b, c, d) = (c, d, k * c - a, k * d - b); + Some(next) + }) } diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index de8b0c6c861..8ff2815bc70 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -374,6 +374,21 @@ impl Cpu { pub fn current() -> Self { get_core() } + + /// Returns an iterator over the "other" cores. + #[inline(always)] + pub fn other() -> impl Iterator { + cfg_if::cfg_if! { + if #[cfg(multi_core)] { + match get_core() { + Cpu::ProCpu => [Cpu::AppCpu].into_iter(), + Cpu::AppCpu => [Cpu::ProCpu].into_iter(), + } + } else { + [].into_iter() + } + } + } } /// Which core the application is currently executing on diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 0c4229d721e..89043b088a6 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -52,7 +52,7 @@ use crate::{ gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput}, interrupt::InterruptHandler, peripheral::{self, Peripheral}, - peripherals::{self, PARL_IO}, + peripherals::{self, Interrupt, PARL_IO}, system::PeripheralClockControl, Blocking, InterruptConfigurable, @@ -923,42 +923,52 @@ where fn internal_set_interrupt_handler(handler: InterruptHandler) { #[cfg(esp32c6)] { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::PARL_IO); + } + internal_listen(EnumSet::all(), false); + internal_clear_interrupts(EnumSet::all()); unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO, + handler.priority() + )); } #[cfg(esp32h2)] { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::PARL_IO_RX); + crate::interrupt::disable(core, Interrupt::PARL_IO_TX); + } + internal_listen(EnumSet::all(), false); + internal_clear_interrupts(EnumSet::all()); unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler()); unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler()); - crate::interrupt::enable( - crate::peripherals::Interrupt::PARL_IO_TX, + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_TX, handler.priority(), - ) - .unwrap(); - crate::interrupt::enable( - crate::peripherals::Interrupt::PARL_IO_RX, + )); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_RX, handler.priority(), - ) - .unwrap(); + )); } } fn internal_listen(interrupts: EnumSet, enable: bool) { let parl_io = unsafe { PARL_IO::steal() }; - for interrupt in interrupts { - match interrupt { - ParlIoInterrupt::TxFifoReEmpty => parl_io - .int_ena() - .modify(|_, w| w.tx_fifo_rempty().bit(enable)), - ParlIoInterrupt::RxFifoWOvf => parl_io - .int_ena() - .modify(|_, w| w.rx_fifo_wovf().bit(enable)), - ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof().bit(enable)), - } - } + parl_io.int_ena().write(|w| { + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable), + ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable), + ParlIoInterrupt::TxEof => w.tx_eof().bit(enable), + }; + } + w + }); } fn internal_interrupts() -> EnumSet { @@ -980,17 +990,16 @@ fn internal_interrupts() -> EnumSet { fn internal_clear_interrupts(interrupts: EnumSet) { let parl_io = unsafe { PARL_IO::steal() }; - for interrupt in interrupts { - match interrupt { - ParlIoInterrupt::TxFifoReEmpty => parl_io - .int_clr() - .write(|w| w.tx_fifo_rempty().clear_bit_by_one()), - ParlIoInterrupt::RxFifoWOvf => parl_io - .int_clr() - .write(|w| w.rx_fifo_wovf().clear_bit_by_one()), - ParlIoInterrupt::TxEof => parl_io.int_clr().write(|w| w.tx_eof().clear_bit_by_one()), - } - } + parl_io.int_clr().write(|w| { + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(), + ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(), + ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(), + }; + } + w + }); } /// Parallel IO in full duplex mode diff --git a/esp-hal/src/pcnt/mod.rs b/esp-hal/src/pcnt/mod.rs index d7598a5e7a3..742404b3f17 100644 --- a/esp-hal/src/pcnt/mod.rs +++ b/esp-hal/src/pcnt/mod.rs @@ -113,9 +113,10 @@ impl crate::private::Sealed for Pcnt<'_> {} impl InterruptConfigurable for Pcnt<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()); - interrupt::enable(Interrupt::PCNT, handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::PCNT); } + unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) }; + unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority())); } } diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 80f0d99fe79..1ba39b3423d 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -80,17 +80,25 @@ //! //! > Note: on ESP32 and ESP32-S2 you cannot specify a base frequency other than 80 MHz -use core::marker::PhantomData; +use core::{ + marker::PhantomData, + pin::Pin, + task::{Context, Poll}, +}; +use embassy_sync::waitqueue::AtomicWaker; +use enumset::{EnumSet, EnumSetType}; use fugit::HertzU32; use crate::{ gpio::interconnect::{PeripheralInput, PeripheralOutput}, - interrupt::InterruptHandler, + macros::handler, peripheral::Peripheral, - rmt::private::CreateInstance, + peripherals::Interrupt, soc::constants, system::PeripheralClockControl, + Async, + Blocking, InterruptConfigurable, }; @@ -206,8 +214,6 @@ pub struct RxChannelConfig { pub use impl_for_chip::{ChannelCreator, Rmt}; -use self::asynch::{RxChannelAsync, TxChannelAsync}; - impl<'d, M> Rmt<'d, M> where M: crate::Mode, @@ -237,14 +243,6 @@ where Ok(me) } - pub(crate) fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::RMT, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::RMT, handler.priority()) - .unwrap(); - } - } - #[cfg(not(any(esp32, esp32s2)))] fn configure_clock(&self, frequency: HertzU32) -> Result<(), Error> { let src_clock = crate::soc::constants::RMT_CLOCK_SRC_FREQ; @@ -265,7 +263,7 @@ where } } -impl<'d> Rmt<'d, crate::Blocking> { +impl<'d> Rmt<'d, Blocking> { /// Create a new RMT instance pub fn new( peripheral: impl Peripheral

+ 'd, @@ -273,34 +271,27 @@ impl<'d> Rmt<'d, crate::Blocking> { ) -> Result { Self::new_internal(peripheral, frequency) } -} - -impl crate::private::Sealed for Rmt<'_, crate::Blocking> {} -impl InterruptConfigurable for Rmt<'_, crate::Blocking> { - fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - self.internal_set_interrupt_handler(handler); + /// Reconfigures the driver for asynchronous operation. + pub fn into_async(mut self) -> Rmt<'d, Async> { + self.set_interrupt_handler(async_interrupt_handler); + Rmt::create(self.peripheral) } } -impl<'d> Rmt<'d, crate::Async> { - /// Create a new RMT instance - pub fn new_async( - peripheral: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Result { - let mut this = Self::new_internal(peripheral, frequency)?; - this.internal_set_interrupt_handler(asynch::async_interrupt_handler); - Ok(this) +impl crate::private::Sealed for Rmt<'_, Blocking> {} + +impl InterruptConfigurable for Rmt<'_, Blocking> { + fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::RMT); + } + unsafe { crate::interrupt::bind_interrupt(Interrupt::RMT, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::RMT, handler.priority())); } } -fn configure_rx_channel< - 'd, - P: PeripheralInput, - T: private::RxChannelInternal, - M: crate::Mode, ->( +fn configure_rx_channel<'d, P: PeripheralInput, T: RxChannelInternal, M: crate::Mode>( pin: impl Peripheral

+ 'd, config: RxChannelConfig, ) -> Result { @@ -321,8 +312,8 @@ fn configure_rx_channel< } crate::into_mapped_ref!(pin); - pin.init_input(crate::gpio::Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(T::input_signal(), crate::private::Internal); + pin.init_input(crate::gpio::Pull::None, crate::Internal); + pin.connect_input_to_peripheral(T::input_signal(), crate::Internal); T::set_divider(config.clk_divider); T::set_carrier( @@ -337,18 +328,13 @@ fn configure_rx_channel< Ok(T::new()) } -fn configure_tx_channel< - 'd, - P: PeripheralOutput, - T: private::TxChannelInternal, - M: crate::Mode, ->( +fn configure_tx_channel<'d, P: PeripheralOutput, T: TxChannelInternal, M: crate::Mode>( pin: impl Peripheral

+ 'd, config: TxChannelConfig, ) -> Result { crate::into_mapped_ref!(pin); - pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(T::output_signal(), crate::private::Internal); + pin.set_to_push_pull_output(crate::Internal); + pin.connect_peripheral_to_output(T::output_signal(), crate::Internal); T::set_divider(config.clk_divider); T::set_carrier( @@ -455,7 +441,7 @@ where /// Wait for the transaction to complete pub fn wait(mut self) -> Result { loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } @@ -464,8 +450,8 @@ where } // wait for TX-THR - while !>::is_threshold_set() {} - >::reset_threshold_set(); + while !>::is_threshold_set() {} + >::reset_threshold_set(); // re-fill TX RAM let ram_index = (((self.index - constants::RMT_CHANNEL_RAM_SIZE) @@ -490,11 +476,11 @@ where } loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -517,15 +503,15 @@ where { /// Stop transaction when the current iteration ends. pub fn stop_next(self) -> Result { - >::set_continuous(false); - >::update(); + >::set_continuous(false); + >::update(); loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -535,8 +521,8 @@ where /// Stop transaction as soon as possible. pub fn stop(self) -> Result { - >::set_continuous(false); - >::update(); + >::set_continuous(false); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -548,11 +534,11 @@ where } loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -562,13 +548,14 @@ where /// Check if the `loopcount` interrupt bit is set pub fn is_loopcount_interrupt_set(&self) -> bool { - >::is_loopcount_interrupt_set() + >::is_loopcount_interrupt_set() } } macro_rules! impl_tx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + impl<'d, P> + $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::interconnect::PeripheralOutput, @@ -577,20 +564,22 @@ macro_rules! impl_tx_channel_creator { impl $crate::rmt::TxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} - impl<'d, P> $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + impl<'d, P> + $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> for ChannelCreator<$crate::Async, $channel> where P: $crate::gpio::interconnect::PeripheralOutput, { } - impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} + impl $crate::rmt::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } macro_rules! impl_rx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + impl<'d, P> + $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::interconnect::PeripheralInput, @@ -599,14 +588,15 @@ macro_rules! impl_rx_channel_creator { impl $crate::rmt::RxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} - impl<'d, P> $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> - for ChannelCreator<$crate::Async, $channel> + impl<'d, P> + $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> where P: $crate::gpio::interconnect::PeripheralInput, { } - impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} + impl $crate::rmt::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } @@ -614,7 +604,6 @@ macro_rules! impl_rx_channel_creator { mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -622,7 +611,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -634,15 +623,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -674,18 +665,17 @@ mod impl_for_chip { impl_rx_channel_creator!(2); impl_rx_channel_creator!(3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 2, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 3, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 2, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 3, 1); } #[cfg(esp32)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -693,7 +683,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -713,15 +703,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -777,30 +769,29 @@ mod impl_for_chip { impl_rx_channel_creator!(6); impl_rx_channel_creator!(7); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_4, 4); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_5, 5); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_6, 6); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_7, 7); - - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_4, 4); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_5, 5); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_6, 6); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_7, 7); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_4, 4); + super::chip_specific::impl_tx_channel!(RMT_SIG_5, 5); + super::chip_specific::impl_tx_channel!(RMT_SIG_6, 6); + super::chip_specific::impl_tx_channel!(RMT_SIG_7, 7); + + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_4, 4); + super::chip_specific::impl_rx_channel!(RMT_SIG_5, 5); + super::chip_specific::impl_rx_channel!(RMT_SIG_6, 6); + super::chip_specific::impl_rx_channel!(RMT_SIG_7, 7); } #[cfg(esp32s2)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -808,7 +799,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -820,15 +811,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -864,22 +857,21 @@ mod impl_for_chip { impl_rx_channel_creator!(2); impl_rx_channel_creator!(3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 3); } #[cfg(esp32s3)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -887,7 +879,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -907,15 +899,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -963,15 +957,15 @@ mod impl_for_chip { impl_rx_channel_creator!(6); impl_rx_channel_creator!(7); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 4, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 5, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 6, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 7, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 4, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 5, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 6, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 7, 3); } /// RMT Channel @@ -985,7 +979,7 @@ where } /// Channel in TX mode -pub trait TxChannel: private::TxChannelInternal { +pub trait TxChannel: TxChannelInternal { /// Start transmitting the given pulse code sequence. /// This returns a [`SingleShotTxTransaction`] which can be used to wait for /// the transaction to complete and get back the channel for further @@ -1052,18 +1046,18 @@ where /// Wait for the transaction to complete pub fn wait(self) -> Result { loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } - >::stop(); - >::clear_interrupts(); - >::update(); + >::stop(); + >::clear_interrupts(); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -1078,7 +1072,7 @@ where } /// Channel is RX mode -pub trait RxChannel: private::RxChannelInternal { +pub trait RxChannel: RxChannelInternal { /// Start receiving pulse codes into the given buffer. /// This returns a [RxTransaction] which can be used to wait for receive to /// complete and get back the channel for further use. @@ -1103,497 +1097,409 @@ pub trait RxChannel: private::RxChannelInternal { } } -/// Async functionality -pub mod asynch { - use core::{ - pin::Pin, - task::{Context, Poll}, - }; +#[cfg(any(esp32, esp32s3))] +const NUM_CHANNELS: usize = 8; +#[cfg(not(any(esp32, esp32s3)))] +const NUM_CHANNELS: usize = 4; + +static WAKER: [AtomicWaker; NUM_CHANNELS] = [const { AtomicWaker::new() }; NUM_CHANNELS]; - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub(crate) struct RmtTxFuture +where + T: TxChannelAsync, +{ + _phantom: PhantomData, +} - use super::{private::Event, *}; +impl RmtTxFuture +where + T: TxChannelAsync, +{ + pub fn new(_instance: &T) -> Self { + Self { + _phantom: PhantomData, + } + } +} - #[cfg(any(esp32, esp32s3))] - const NUM_CHANNELS: usize = 8; - #[cfg(not(any(esp32, esp32s3)))] - const NUM_CHANNELS: usize = 4; +impl core::future::Future for RmtTxFuture +where + T: TxChannelAsync, +{ + type Output = (); - static WAKER: [AtomicWaker; NUM_CHANNELS] = [const { AtomicWaker::new() }; NUM_CHANNELS]; + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKER[T::CHANNEL as usize].register(ctx.waker()); - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct RmtTxFuture - where - T: TxChannelAsync, - { - _phantom: PhantomData, + if T::is_error() || T::is_done() { + Poll::Ready(()) + } else { + Poll::Pending + } } +} - impl RmtTxFuture +/// TX channel in async mode +pub trait TxChannelAsync: TxChannelInternal { + /// Start transmitting the given pulse code sequence. + /// The length of sequence cannot exceed the size of the allocated RMT + /// RAM. + async fn transmit<'a, T: Into + Copy>(&mut self, data: &'a [T]) -> Result<(), Error> where - T: TxChannelAsync, + Self: Sized, { - pub fn new(_instance: &T) -> Self { - Self { - _phantom: PhantomData, - } + if data.len() > constants::RMT_CHANNEL_RAM_SIZE { + return Err(Error::InvalidArgument); } - } - impl core::future::Future for RmtTxFuture - where - T: TxChannelAsync, - { - type Output = (); + Self::clear_interrupts(); + Self::listen_interrupt(Event::End); + Self::listen_interrupt(Event::Error); + Self::send_raw(data, false, 0); - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKER[T::CHANNEL as usize].register(ctx.waker()); + RmtTxFuture::new(self).await; - if T::is_error() || T::is_done() { - Poll::Ready(()) - } else { - Poll::Pending - } + if Self::is_error() { + Err(Error::TransmissionError) + } else { + Ok(()) } } +} - /// TX channel in async mode - pub trait TxChannelAsync: private::TxChannelInternal { - /// Start transmitting the given pulse code sequence. - /// The length of sequence cannot exceed the size of the allocated RMT - /// RAM. - async fn transmit + Copy>(&mut self, data: &[T]) -> Result<(), Error> - where - Self: Sized, - { - if data.len() > constants::RMT_CHANNEL_RAM_SIZE { - return Err(Error::InvalidArgument); - } - - Self::clear_interrupts(); - Self::listen_interrupt(super::private::Event::End); - Self::listen_interrupt(super::private::Event::Error); - Self::send_raw(data, false, 0); - - RmtTxFuture::new(self).await; +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub(crate) struct RmtRxFuture +where + T: RxChannelAsync, +{ + _phantom: PhantomData, +} - if Self::is_error() { - Err(Error::TransmissionError) - } else { - Ok(()) - } +impl RmtRxFuture +where + T: RxChannelAsync, +{ + pub fn new(_instance: &T) -> Self { + Self { + _phantom: PhantomData, } } +} - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct RmtRxFuture - where - T: RxChannelAsync, - { - _phantom: PhantomData, - } +impl core::future::Future for RmtRxFuture +where + T: RxChannelAsync, +{ + type Output = (); - impl RmtRxFuture - where - T: RxChannelAsync, - { - pub fn new(_instance: &T) -> Self { - Self { - _phantom: PhantomData, - } + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKER[T::CHANNEL as usize].register(ctx.waker()); + if T::is_error() || T::is_done() { + Poll::Ready(()) + } else { + Poll::Pending } } +} - impl core::future::Future for RmtRxFuture +/// RX channel in async mode +pub trait RxChannelAsync: RxChannelInternal { + /// Start receiving a pulse code sequence. + /// The length of sequence cannot exceed the size of the allocated RMT + /// RAM. + async fn receive<'a, T: From + Copy>(&mut self, data: &'a mut [T]) -> Result<(), Error> where - T: RxChannelAsync, + Self: Sized, { - type Output = (); - - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKER[T::CHANNEL as usize].register(ctx.waker()); - if T::is_error() || T::is_done() { - Poll::Ready(()) - } else { - Poll::Pending - } + if data.len() > constants::RMT_CHANNEL_RAM_SIZE { + return Err(Error::InvalidArgument); } - } - /// RX channel in async mode - pub trait RxChannelAsync: private::RxChannelInternal { - /// Start receiving a pulse code sequence. - /// The length of sequence cannot exceed the size of the allocated RMT - /// RAM. - async fn receive + Copy>(&mut self, data: &mut [T]) -> Result<(), Error> - where - Self: Sized, - { - if data.len() > constants::RMT_CHANNEL_RAM_SIZE { - return Err(Error::InvalidArgument); - } - - Self::clear_interrupts(); - Self::listen_interrupt(super::private::Event::End); - Self::listen_interrupt(super::private::Event::Error); - Self::start_receive_raw(); - - RmtRxFuture::new(self).await; - - if Self::is_error() { - Err(Error::TransmissionError) - } else { - Self::stop(); - Self::clear_interrupts(); - Self::update(); - - let ptr = (constants::RMT_RAM_START - + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) - as *mut u32; - let len = data.len(); - for (idx, entry) in data.iter_mut().take(len).enumerate() { - *entry = unsafe { ptr.add(idx).read_volatile().into() }; - } - - Ok(()) - } - } - } + Self::clear_interrupts(); + Self::listen_interrupt(Event::End); + Self::listen_interrupt(Event::Error); + Self::start_receive_raw(); - #[cfg(not(any(esp32, esp32s2)))] - #[handler] - pub(super) fn async_interrupt_handler() { - if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { - use crate::rmt::private::{RxChannelInternal, TxChannelInternal}; - - match channel { - 0 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 1 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 2 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 3 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } + RmtRxFuture::new(self).await; - #[cfg(any(esp32, esp32s3))] - 4 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 5 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 6 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 7 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } + if Self::is_error() { + Err(Error::TransmissionError) + } else { + Self::stop(); + Self::clear_interrupts(); + Self::update(); - _ => unreachable!(), + let ptr = (constants::RMT_RAM_START + + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) + as *mut u32; + let len = data.len(); + for (idx, entry) in data.iter_mut().take(len).enumerate() { + *entry = unsafe { ptr.add(idx).read_volatile().into() }; } - WAKER[channel].wake(); + Ok(()) } } +} - #[cfg(any(esp32, esp32s2))] - #[handler] - pub(super) fn async_interrupt_handler() { - if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { - match channel { - 0 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 1 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 2 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 3 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(esp32)] - 4 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 5 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 6 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 7 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - - _ => unreachable!(), - } - - WAKER[channel].wake(); - } +#[cfg(not(any(esp32, esp32s2)))] +#[handler] +fn async_interrupt_handler() { + let Some(channel) = chip_specific::pending_interrupt_for_channel() else { + return; + }; + match channel { + 0 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 1 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 2 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 3 => Channel::::unlisten_interrupt(Event::End | Event::Error), + + #[cfg(any(esp32, esp32s3))] + 4 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 5 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 6 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 7 => Channel::::unlisten_interrupt(Event::End | Event::Error), + + _ => unreachable!(), } -} -mod private { - use crate::{peripheral::Peripheral, soc::constants}; + WAKER[channel].wake(); +} - pub enum Event { - Error, - Threshold, - End, - } +#[cfg(any(esp32, esp32s2))] +#[handler] +fn async_interrupt_handler() { + let Some(channel) = chip_specific::pending_interrupt_for_channel() else { + return; + }; + match channel { + 0 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 1 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 2 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 3 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(esp32)] + 4 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 5 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 6 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 7 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } - pub trait CreateInstance<'d> { - fn create(peripheral: impl Peripheral

+ 'd) -> Self; + _ => unreachable!(), } - pub trait TxChannelInternal - where - M: crate::Mode, - { - const CHANNEL: u8; + WAKER[channel].wake(); +} - fn new() -> Self; +#[derive(Debug, EnumSetType)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[doc(hidden)] +pub enum Event { + Error, + Threshold, + End, +} - fn output_signal() -> crate::gpio::OutputSignal; +#[doc(hidden)] +pub trait TxChannelInternal +where + M: crate::Mode, +{ + const CHANNEL: u8; - fn set_divider(divider: u8); + fn new() -> Self; - fn update(); + fn output_signal() -> crate::gpio::OutputSignal; - fn set_generate_repeat_interrupt(repeats: u16); + fn set_divider(divider: u8); - fn clear_interrupts(); + fn update(); - fn set_continuous(continuous: bool); + fn set_generate_repeat_interrupt(repeats: u16); - fn set_wrap_mode(wrap: bool); + fn clear_interrupts(); - fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); + fn set_continuous(continuous: bool); - fn set_idle_output(enable: bool, level: bool); + fn set_wrap_mode(wrap: bool); - fn set_memsize(memsize: u8); + fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); - fn start_tx(); + fn set_idle_output(enable: bool, level: bool); - fn is_done() -> bool; + fn set_memsize(memsize: u8); - fn is_error() -> bool; + fn start_tx(); - fn is_threshold_set() -> bool; + fn is_done() -> bool; - fn reset_threshold_set(); + fn is_error() -> bool; - fn set_threshold(threshold: u8); + fn is_threshold_set() -> bool; - fn is_loopcount_interrupt_set() -> bool; + fn reset_threshold_set(); - fn send_raw + Copy>(data: &[T], continuous: bool, repeat: u16) -> usize { - Self::clear_interrupts(); + fn set_threshold(threshold: u8); - let ptr = (constants::RMT_RAM_START - + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) - as *mut u32; - for (idx, entry) in data - .iter() - .take(constants::RMT_CHANNEL_RAM_SIZE) - .enumerate() - { - unsafe { - ptr.add(idx).write_volatile((*entry).into()); - } - } + fn is_loopcount_interrupt_set() -> bool; - Self::set_threshold((constants::RMT_CHANNEL_RAM_SIZE / 2) as u8); - Self::set_continuous(continuous); - Self::set_generate_repeat_interrupt(repeat); - Self::set_wrap_mode(true); - Self::set_memsize(1); - Self::update(); - Self::start_tx(); - Self::update(); + fn send_raw + Copy>(data: &[T], continuous: bool, repeat: u16) -> usize { + Self::clear_interrupts(); - if data.len() >= constants::RMT_CHANNEL_RAM_SIZE { - constants::RMT_CHANNEL_RAM_SIZE - } else { - data.len() + let ptr = (constants::RMT_RAM_START + + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) + as *mut u32; + for (idx, entry) in data + .iter() + .take(constants::RMT_CHANNEL_RAM_SIZE) + .enumerate() + { + unsafe { + ptr.add(idx).write_volatile((*entry).into()); } } - fn stop(); + Self::set_threshold((constants::RMT_CHANNEL_RAM_SIZE / 2) as u8); + Self::set_continuous(continuous); + Self::set_generate_repeat_interrupt(repeat); + Self::set_wrap_mode(true); + Self::set_memsize(1); + Self::update(); + Self::start_tx(); + Self::update(); + + if data.len() >= constants::RMT_CHANNEL_RAM_SIZE { + constants::RMT_CHANNEL_RAM_SIZE + } else { + data.len() + } + } - fn enable_listen_interrupt(event: Event, enable: bool); + fn stop(); - fn listen_interrupt(event: Event) { - Self::enable_listen_interrupt(event, true); - } + fn enable_listen_interrupt(event: EnumSet, enable: bool); - fn unlisten_interrupt(event: Event) { - Self::enable_listen_interrupt(event, false); - } + fn listen_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), true); } - pub trait RxChannelInternal - where - M: crate::Mode, - { - const CHANNEL: u8; + fn unlisten_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), false); + } +} - fn new() -> Self; +#[doc(hidden)] +pub trait RxChannelInternal +where + M: crate::Mode, +{ + const CHANNEL: u8; - fn input_signal() -> crate::gpio::InputSignal; + fn new() -> Self; - fn set_divider(divider: u8); + fn input_signal() -> crate::gpio::InputSignal; - fn update(); + fn set_divider(divider: u8); - fn clear_interrupts(); + fn update(); - fn set_wrap_mode(wrap: bool); + fn clear_interrupts(); - fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); + fn set_wrap_mode(wrap: bool); - fn set_memsize(memsize: u8); + fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); - fn start_rx(); + fn set_memsize(memsize: u8); - fn is_done() -> bool; + fn start_rx(); - fn is_error() -> bool; + fn is_done() -> bool; - fn start_receive_raw() { - Self::clear_interrupts(); - Self::set_wrap_mode(false); - Self::set_memsize(1); - Self::start_rx(); - Self::update(); - } + fn is_error() -> bool; - fn stop(); + fn start_receive_raw() { + Self::clear_interrupts(); + Self::set_wrap_mode(false); + Self::set_memsize(1); + Self::start_rx(); + Self::update(); + } - fn set_filter_threshold(value: u8); + fn stop(); - fn set_idle_threshold(value: u16); + fn set_filter_threshold(value: u8); - fn enable_listen_interrupt(event: Event, enable: bool); + fn set_idle_threshold(value: u16); - fn listen_interrupt(event: Event) { - Self::enable_listen_interrupt(event, true); - } + fn enable_listen_interrupt(event: EnumSet, enable: bool); - fn unlisten_interrupt(event: Event) { - Self::enable_listen_interrupt(event, false); - } + fn listen_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), true); + } + + fn unlisten_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), false); } } @@ -1681,9 +1587,9 @@ mod chip_specific { } macro_rules! impl_tx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { + impl $crate::rmt::TxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -1823,19 +1729,15 @@ mod chip_specific { Self::update(); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _tx_err >]().bit(enable); - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _tx_end >]().bit(enable); - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable); - } + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _tx_err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _tx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; } w }); @@ -1846,9 +1748,9 @@ mod chip_specific { } macro_rules! impl_rx_channel { - ($channel:ident, $signal:ident, $ch_num:literal, $ch_index:literal) => { + ($signal:ident, $ch_num:literal, $ch_index:literal) => { paste::paste! { - impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { + impl $crate::rmt::RxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -1943,19 +1845,15 @@ mod chip_specific { rmt.[< ch $ch_num _rx_conf0 >]().modify(|_, w| unsafe { w.idle_thres().bits(value) }); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _rx_err >]().bit(enable); - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _rx_end >]().bit(enable); - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _rx_thr_event >]().bit(enable); - } + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _rx_err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _rx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _rx_thr_event >]().bit(enable), + }; } w }); @@ -2039,9 +1937,9 @@ mod chip_specific { } macro_rules! impl_tx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::TxChannelInternal for super::$channel where M: $crate::Mode { + impl super::TxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -2171,40 +2069,28 @@ mod chip_specific { } } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_,w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _err >]().bit(enable) - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _tx_end >]().bit(enable) - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable) - } - }; + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _tx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; + } w }); } - - fn listen_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, true) - } - - fn unlisten_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, false) - } } } } } macro_rules! impl_rx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::RxChannelInternal for super::$channel where M: $crate::Mode { + impl super::RxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -2304,31 +2190,19 @@ mod chip_specific { rmt.[< ch $ch_num conf0 >]().modify(|_, w| unsafe { w.idle_thres().bits(value) }); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _err >]().bit(enable) - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _rx_end >]().bit(enable) - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable) - } - }; + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _rx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; + } w }); } - - fn listen_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, true) - } - - fn unlisten_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, false) - } } } } diff --git a/esp-hal/src/rsa/mod.rs b/esp-hal/src/rsa/mod.rs index a92c6bb51db..cde24f4e88c 100644 --- a/esp-hal/src/rsa/mod.rs +++ b/esp-hal/src/rsa/mod.rs @@ -26,8 +26,11 @@ use core::{marker::PhantomData, ptr::copy_nonoverlapping}; use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::RSA, + peripherals::{Interrupt, RSA}, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, + Async, + Blocking, + Cpu, InterruptConfigurable, }; @@ -47,29 +50,44 @@ pub struct Rsa<'d, DM: crate::Mode> { phantom: PhantomData, } -impl<'d> Rsa<'d, crate::Blocking> { +impl<'d> Rsa<'d, Blocking> { /// Create a new instance in [crate::Blocking] mode. /// /// Optionally an interrupt handler can be bound. pub fn new(rsa: impl Peripheral

+ 'd) -> Self { Self::new_internal(rsa) } + + /// Reconfigures the RSA driver to operate in asynchronous mode. + pub fn into_async(mut self) -> Rsa<'d, Async> { + self.set_interrupt_handler(asynch::rsa_interrupt_handler); + Rsa { + rsa: self.rsa, + phantom: PhantomData, + } + } } -impl crate::private::Sealed for Rsa<'_, crate::Blocking> {} +impl crate::private::Sealed for Rsa<'_, Blocking> {} -impl InterruptConfigurable for Rsa<'_, crate::Blocking> { +impl InterruptConfigurable for Rsa<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.internal_set_interrupt_handler(handler); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::RSA); + } + unsafe { crate::interrupt::bind_interrupt(Interrupt::RSA, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::RSA, handler.priority())); } } -impl<'d> Rsa<'d, crate::Async> { +impl<'d> Rsa<'d, Async> { /// Create a new instance in [crate::Blocking] mode. - pub fn new_async(rsa: impl Peripheral

+ 'd) -> Self { - let mut this = Self::new_internal(rsa); - this.internal_set_interrupt_handler(asynch::rsa_interrupt_handler); - this + pub fn into_blocking(self) -> Rsa<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::RSA); + Rsa { + rsa: self.rsa, + phantom: PhantomData, + } } } @@ -129,15 +147,6 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> { ); } } - - fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::RSA, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::RSA, handler.priority()) - .unwrap(); - } - } - fn wait_for_idle(&mut self) { while !self.is_idle() {} self.clear_interrupt(); diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 140e9c42c31..987f687cb8c 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -434,23 +434,18 @@ impl crate::private::Sealed for Rtc<'_> {} impl InterruptConfigurable for Rtc<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - interrupt::bind_interrupt( - #[cfg(any(esp32c6, esp32h2))] - Interrupt::LP_WDT, - #[cfg(not(any(esp32c6, esp32h2)))] - Interrupt::RTC_CORE, - handler.handler(), - ); - interrupt::enable( - #[cfg(any(esp32c6, esp32h2))] - Interrupt::LP_WDT, - #[cfg(not(any(esp32c6, esp32h2)))] - Interrupt::RTC_CORE, - handler.priority(), - ) - .unwrap(); + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2))] { + let interrupt = Interrupt::LP_WDT; + } else { + let interrupt = Interrupt::RTC_CORE; + } + } + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); } + unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(interrupt::enable(interrupt, handler.priority())); } } diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index b230f3b1774..48e85227628 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -62,6 +62,8 @@ use core::{borrow::BorrowMut, convert::Infallible, marker::PhantomData, mem::siz #[cfg(feature = "digest")] pub use digest::Digest; +#[cfg(not(esp32))] +use crate::peripherals::Interrupt; use crate::{ peripheral::{Peripheral, PeripheralRef}, peripherals::SHA, @@ -103,11 +105,11 @@ impl crate::private::Sealed for Sha<'_> {} #[cfg(not(esp32))] impl crate::InterruptConfigurable for Sha<'_> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::SHA, handler.priority()) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::SHA); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::SHA, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::SHA, handler.priority())); } } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 3e54ad3dd34..cd906e3fabb 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -61,6 +61,8 @@ //! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html //! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html +use core::marker::PhantomData; + pub use dma::*; #[cfg(gdma)] use enumset::EnumSet; @@ -73,7 +75,16 @@ use procmacros::ram; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use crate::{ clock::Clocks, - dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx}, + dma::{ + Channel, + DmaChannelConvert, + DmaEligible, + DmaRxBuffer, + DmaTxBuffer, + PeripheralMarker, + Rx, + Tx, + }, gpio::{ interconnect::{OutputConnection, PeripheralOutput}, InputSignal, @@ -86,6 +97,8 @@ use crate::{ private, spi::AnySpi, system::PeripheralClockControl, + Async, + Blocking, Mode, }; @@ -423,12 +436,14 @@ impl Address { } /// SPI peripheral driver -pub struct Spi<'d, T = AnySpi> { +pub struct Spi<'d, M, T = AnySpi> { spi: PeripheralRef<'d, T>, + _mode: PhantomData, } -impl<'d, T> Spi<'d, T> +impl<'d, M, T> Spi<'d, M, T> where + M: Mode, T: InstanceDma, { /// Configures the SPI instance to use DMA with the specified channel. @@ -436,19 +451,17 @@ where /// This method prepares the SPI instance for DMA transfers using SPI /// and returns an instance of `SpiDma` that supports DMA /// operations. - pub fn with_dma( - self, - channel: crate::dma::Channel<'d, CH, DmaMode>, - ) -> SpiDma<'d, DmaMode, T> + pub fn with_dma(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, - DmaMode: Mode, + DM: Mode, + Channel<'d, CH, M>: From>, { - SpiDma::new(self.spi, channel) + SpiDma::new(self.spi, channel.into()) } } -impl Spi<'_, T> +impl Spi<'_, M, T> where T: Instance, { @@ -484,18 +497,36 @@ where } } -impl<'d> Spi<'d> { +impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. pub fn new( spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d> { + ) -> Spi<'d, Blocking> { Self::new_typed(spi.map_into(), frequency, mode) } + + /// Converts the SPI instance into async mode. + pub fn into_async(self) -> Spi<'d, Async> { + Spi { + spi: self.spi, + _mode: PhantomData, + } + } } -impl<'d, T> Spi<'d, T> +impl<'d> Spi<'d, Async> { + /// Converts the SPI instance into blocking mode. + pub fn into_blocking(self) -> Spi<'d, Blocking> { + Spi { + spi: self.spi, + _mode: PhantomData, + } + } +} + +impl<'d, M, T> Spi<'d, M, T> where T: Instance, { @@ -504,10 +535,13 @@ where spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d, T> { + ) -> Spi<'d, M, T> { crate::into_ref!(spi); - let mut spi = Spi { spi }; + let mut spi = Spi { + spi, + _mode: PhantomData, + }; spi.spi.reset_peripheral(); spi.spi.enable_peripheral(); spi.spi.setup(frequency); @@ -616,7 +650,7 @@ where } } -impl<'d, T> Spi<'d, T> +impl<'d, M, T> Spi<'d, M, T> where T: QspiInstance, { @@ -663,7 +697,7 @@ where } } -impl Spi<'_, T> +impl Spi<'_, M, T> where T: Instance, { @@ -754,7 +788,7 @@ where } } -impl embedded_hal_02::spi::FullDuplex for Spi<'_, T> +impl embedded_hal_02::spi::FullDuplex for Spi<'_, M, T> where T: Instance, { @@ -769,7 +803,7 @@ where } } -impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, T> +impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, M, T> where T: Instance, { @@ -780,7 +814,7 @@ where } } -impl embedded_hal_02::blocking::spi::Write for Spi<'_, T> +impl embedded_hal_02::blocking::spi::Write for Spi<'_, M, T> where T: Instance, { @@ -812,9 +846,7 @@ mod dma { Rx, Tx, }, - Blocking, InterruptConfigurable, - Mode, }; /// A DMA capable SPI instance. @@ -837,6 +869,40 @@ mod dma { address_buffer: DmaTxBuf, } + impl<'d, T> SpiDma<'d, Blocking, T> + where + T: InstanceDma, + { + /// Converts the SPI instance into async mode. + pub fn into_async(self) -> SpiDma<'d, Async, T> { + SpiDma { + spi: self.spi, + channel: self.channel.into_async(), + tx_transfer_in_progress: self.tx_transfer_in_progress, + rx_transfer_in_progress: self.rx_transfer_in_progress, + #[cfg(all(esp32, spi_address_workaround))] + address_buffer: self.address_buffer, + } + } + } + + impl<'d, T> SpiDma<'d, Async, T> + where + T: InstanceDma, + { + /// Converts the SPI instance into async mode. + pub fn into_blocking(self) -> SpiDma<'d, Blocking, T> { + SpiDma { + spi: self.spi, + channel: self.channel.into_blocking(), + tx_transfer_in_progress: self.tx_transfer_in_progress, + rx_transfer_in_progress: self.rx_transfer_in_progress, + #[cfg(all(esp32, spi_address_workaround))] + address_buffer: self.address_buffer, + } + } + } + #[cfg(all(esp32, spi_address_workaround))] unsafe impl<'d, M, T> Send for SpiDma<'d, M, T> where @@ -868,6 +934,9 @@ mod dma { /// Interrupts are not enabled at the peripheral level here. fn set_interrupt_handler(&mut self, handler: InterruptHandler) { let interrupt = self.spi.interrupt(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; unwrap!(crate::interrupt::enable(interrupt, handler.priority())); } @@ -1180,7 +1249,7 @@ mod dma { } } - impl SpiDmaTransfer<'_, crate::Async, Buf, T> + impl SpiDmaTransfer<'_, Async, Buf, T> where T: InstanceDma, { @@ -1460,6 +1529,34 @@ mod dma { tx_buf: DmaTxBuf, } + impl<'d, T> SpiDmaBus<'d, Blocking, T> + where + T: InstanceDma, + { + /// Converts the SPI instance into async mode. + pub fn into_async(self) -> SpiDmaBus<'d, Async, T> { + SpiDmaBus { + spi_dma: self.spi_dma.into_async(), + rx_buf: self.rx_buf, + tx_buf: self.tx_buf, + } + } + } + + impl<'d, T> SpiDmaBus<'d, Async, T> + where + T: InstanceDma, + { + /// Converts the SPI instance into async mode. + pub fn into_blocking(self) -> SpiDmaBus<'d, Blocking, T> { + SpiDmaBus { + spi_dma: self.spi_dma.into_blocking(), + rx_buf: self.rx_buf, + tx_buf: self.tx_buf, + } + } + } + impl<'d, M, T> SpiDmaBus<'d, M, T> where T: InstanceDma, @@ -1699,7 +1796,7 @@ mod dma { } } - impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1711,7 +1808,7 @@ mod dma { } } - impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1731,6 +1828,7 @@ mod dma { }; use super::*; + use crate::Async; struct DropGuard { inner: ManuallyDrop, @@ -1770,7 +1868,7 @@ mod dma { } } - impl SpiDmaBus<'_, crate::Async, T> + impl SpiDmaBus<'_, Async, T> where T: InstanceDma, { @@ -1884,7 +1982,7 @@ mod dma { } } - impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T> + impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T> where T: InstanceDma, { @@ -1959,11 +2057,11 @@ mod ehal1 { use super::*; - impl embedded_hal::spi::ErrorType for Spi<'_, T> { + impl embedded_hal::spi::ErrorType for Spi<'_, M, T> { type Error = Error; } - impl FullDuplex for Spi<'_, T> + impl FullDuplex for Spi<'_, M, T> where T: Instance, { @@ -1976,7 +2074,7 @@ mod ehal1 { } } - impl SpiBus for Spi<'_, T> + impl SpiBus for Spi<'_, M, T> where T: Instance, { diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 0447c1870f7..8bea967bda6 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -70,6 +70,8 @@ //! //! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information. +use core::marker::PhantomData; + use super::{Error, SpiMode}; use crate::{ dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, @@ -83,6 +85,7 @@ use crate::{ private, spi::AnySpi, system::PeripheralClockControl, + Blocking, }; const MAX_DMA_SIZE: usize = 32768 - 32; @@ -90,13 +93,14 @@ const MAX_DMA_SIZE: usize = 32768 - 32; /// SPI peripheral driver. /// /// See the [module-level documentation][self] for more details. -pub struct Spi<'d, T = AnySpi> { +pub struct Spi<'d, M, T = AnySpi> { spi: PeripheralRef<'d, T>, #[allow(dead_code)] data_mode: SpiMode, + _mode: PhantomData, } -impl<'d> Spi<'d> { +impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. pub fn new< SCK: PeripheralInput, @@ -110,12 +114,12 @@ impl<'d> Spi<'d> { miso: impl Peripheral

+ 'd, cs: impl Peripheral

+ 'd, mode: SpiMode, - ) -> Spi<'d> { + ) -> Spi<'d, Blocking> { Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode) } } -impl<'d, T> Spi<'d, T> +impl<'d, M, T> Spi<'d, M, T> where T: Instance, { @@ -132,7 +136,7 @@ where miso: impl Peripheral

+ 'd, cs: impl Peripheral

+ 'd, mode: SpiMode, - ) -> Spi<'d, T> { + ) -> Spi<'d, M, T> { crate::into_mapped_ref!(sclk, mosi, miso, cs); let this = Self::new_internal(spi, mode); @@ -153,12 +157,13 @@ where this } - pub(crate) fn new_internal(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, T> { + pub(crate) fn new_internal(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, M, T> { crate::into_ref!(spi); let mut spi = Spi { spi, data_mode: mode, + _mode: PhantomData, }; PeripheralClockControl::reset(spi.spi.peripheral()); @@ -193,36 +198,38 @@ pub mod dma { Mode, }; - impl<'d, T> Spi<'d, T> + impl<'d, M, T> Spi<'d, M, T> where T: InstanceDma, + M: Mode, { /// Configures the SPI3 peripheral with the provided DMA channel and /// descriptors. #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] - pub fn with_dma( + pub fn with_dma( mut self, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> SpiDma<'d, DmaMode, T> + ) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, - DmaMode: Mode, + DM: Mode, + Channel<'d, CH, M>: From>, { self.spi.set_data_mode(self.data_mode, true); - SpiDma::new(self.spi, channel, rx_descriptors, tx_descriptors) + SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) } } /// A DMA capable SPI instance. - pub struct SpiDma<'d, DmaMode, T = AnySpi> + pub struct SpiDma<'d, M, T = AnySpi> where T: InstanceDma, - DmaMode: Mode, + M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, - pub(crate) channel: Channel<'d, T::Dma, DmaMode>, + pub(crate) channel: Channel<'d, T::Dma, M>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index de70e909ec3..2a666c652e3 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -549,6 +549,10 @@ pub trait Comparator { _ => unreachable!(), }; + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + #[cfg(not(esp32s2))] unsafe { interrupt::bind_interrupt(interrupt, handler.handler()); diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 1409e162066..60f4a4bc127 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -553,10 +553,11 @@ where _ => unreachable!(), }; - unsafe { - interrupt::bind_interrupt(interrupt, handler.handler()); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); } - interrupt::enable(interrupt, handler.priority()).unwrap(); + unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(interrupt::enable(interrupt, handler.priority())); } fn is_interrupt_set(&self) -> bool { diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 12f3ffd4e45..b1db036b1b7 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -840,10 +840,15 @@ where } fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()); - crate::interrupt::enable(self.twai.interrupt(), handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, self.twai.interrupt()); } + unsafe { crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()) }; + + unwrap!(crate::interrupt::enable( + self.twai.interrupt(), + handler.priority() + )); } /// Set the bitrate of the bus. @@ -1027,17 +1032,6 @@ where phantom: PhantomData, } } - - /// Convert the configuration into an async configuration. - fn into_async(self) -> TwaiConfiguration<'d, Async, T> { - let mut this = TwaiConfiguration { - twai: self.twai, - phantom: PhantomData, - mode: self.mode, - }; - this.internal_set_interrupt_handler(this.twai.async_handler()); - this - } } impl<'d> TwaiConfiguration<'d, Blocking> { @@ -1101,35 +1095,15 @@ where ) -> Self { Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode) } -} -impl<'d> TwaiConfiguration<'d, Async> { - /// Create a new instance of [TwaiConfiguration] - /// - /// You will need to use a transceiver to connect to the TWAI bus - pub fn new_async( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - Self::new_async_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode) - } - - /// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s - /// directly - /// - /// You don't need a transceiver by following the description in the - /// `twai.rs` example - pub fn new_async_no_transceiver( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode) + /// Convert the configuration into an async configuration. + pub fn into_async(mut self) -> TwaiConfiguration<'d, Async, T> { + self.set_interrupt_handler(self.twai.async_handler()); + TwaiConfiguration { + twai: self.twai, + phantom: PhantomData, + mode: self.mode, + } } } @@ -1137,33 +1111,18 @@ impl<'d, T> TwaiConfiguration<'d, Async, T> where T: Instance, { - /// Create a new instance of [TwaiConfiguration] in async mode - /// - /// You will need to use a transceiver to connect to the TWAI bus - pub fn new_async_typed( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - TwaiConfiguration::new_typed(peripheral, rx_pin, tx_pin, baud_rate, mode).into_async() - } + /// Convert the configuration into a blocking configuration. + pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking, T> { + use crate::{interrupt, Cpu}; - /// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s - /// directly in async mode - /// - /// You don't need a transceiver by following the description in the - /// `twai.rs` example - pub fn new_async_no_transceiver_typed( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - TwaiConfiguration::new_no_transceiver_typed(peripheral, rx_pin, tx_pin, baud_rate, mode) - .into_async() + interrupt::disable(Cpu::current(), self.twai.interrupt()); + + // Re-create in blocking mode + TwaiConfiguration { + twai: self.twai, + phantom: PhantomData, + mode: self.mode, + } } } diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index f7418dc721a..6a371e95b59 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -126,10 +126,11 @@ //! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/ //! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/ -use core::marker::PhantomData; +use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll}; use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; +use portable_atomic::AtomicBool; use self::config::Config; use crate::{ @@ -146,6 +147,7 @@ use crate::{ peripherals::{uart0::RegisterBlock, Interrupt}, private::Internal, system::PeripheralClockControl, + Async, Blocking, InterruptConfigurable, Mode, @@ -662,6 +664,42 @@ where Ok(uart_tx) } + + /// Reconfigures the driver to operate in [`Async`] mode. + pub fn into_async(self) -> UartTx<'d, Async, T> { + if !self.uart.state().is_rx_async.load(Ordering::Acquire) { + self.uart + .info() + .set_interrupt_handler(self.uart.info().async_handler); + } + self.uart.state().is_tx_async.store(true, Ordering::Release); + + UartTx { + uart: self.uart, + phantom: PhantomData, + } + } +} + +impl<'d, T> UartTx<'d, Async, T> +where + T: Instance, +{ + /// Reconfigures the driver to operate in [`Blocking`] mode. + pub fn into_blocking(self) -> UartTx<'d, Blocking, T> { + self.uart + .state() + .is_tx_async + .store(false, Ordering::Release); + if !self.uart.state().is_rx_async.load(Ordering::Acquire) { + self.uart.info().disable_interrupts(); + } + + UartTx { + uart: self.uart, + phantom: PhantomData, + } + } } #[inline(always)] @@ -963,6 +1001,50 @@ where Ok(uart_rx) } + + /// Reconfigures the driver to operate in [`Async`] mode. + pub fn into_async(self) -> UartRx<'d, Async, T> { + if !self.uart.state().is_tx_async.load(Ordering::Acquire) { + self.uart + .info() + .set_interrupt_handler(self.uart.info().async_handler); + } + self.uart.state().is_rx_async.store(true, Ordering::Release); + + UartRx { + uart: self.uart, + phantom: PhantomData, + at_cmd_config: self.at_cmd_config, + rx_timeout_config: self.rx_timeout_config, + #[cfg(not(esp32))] + symbol_len: self.symbol_len, + } + } +} + +impl<'d, T> UartRx<'d, Async, T> +where + T: Instance, +{ + /// Reconfigures the driver to operate in [`Blocking`] mode. + pub fn into_blocking(self) -> UartRx<'d, Blocking, T> { + self.uart + .state() + .is_rx_async + .store(false, Ordering::Release); + if !self.uart.state().is_tx_async.load(Ordering::Acquire) { + self.uart.info().disable_interrupts(); + } + + UartRx { + uart: self.uart, + phantom: PhantomData, + at_cmd_config: self.at_cmd_config, + rx_timeout_config: self.rx_timeout_config, + #[cfg(not(esp32))] + symbol_len: self.symbol_len, + } + } } impl<'d> Uart<'d, Blocking> { @@ -1010,6 +1092,27 @@ where ) -> Result { UartBuilder::new(uart).with_tx(tx).with_rx(rx).init(config) } + + /// Reconfigures the driver to operate in [`Async`] mode. + pub fn into_async(self) -> Uart<'d, Async, T> { + Uart { + rx: self.rx.into_async(), + tx: self.tx.into_async(), + } + } +} + +impl<'d, T> Uart<'d, Async, T> +where + T: Instance, +{ + /// Reconfigures the driver to operate in [`Blocking`] mode. + pub fn into_blocking(self) -> Uart<'d, Blocking, T> { + Uart { + rx: self.rx.into_blocking(), + tx: self.tx.into_blocking(), + } + } } /// List of exposed UART events. @@ -1033,15 +1136,6 @@ where T: Instance, M: Mode, { - fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) { - // `self.tx.uart` and `self.rx.uart` are the same - let interrupt = self.tx.uart.info().interrupt; - unsafe { - crate::interrupt::bind_interrupt(interrupt, handler.handler()); - unwrap!(crate::interrupt::enable(interrupt, handler.priority())); - } - } - /// Configure CTS pin pub fn with_cts(mut self, cts: impl Peripheral

+ 'd) -> Self { self.rx = self.rx.with_cts(cts); @@ -1123,66 +1217,24 @@ where self.rx.at_cmd_config = Some(config); } - /// Listen for the given interrupts - fn enable_listen(&mut self, interrupts: EnumSet, enable: bool) { - let reg_block = self.register_block(); - - reg_block.int_ena().modify(|_, w| { - for interrupt in interrupts { - match interrupt { - UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable), - UartInterrupt::TxDone => w.tx_done().bit(enable), - UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable), - }; - } - w - }); - } - /// Listen for the given interrupts pub fn listen(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), true); + self.tx.uart.info().enable_listen(interrupts.into(), true) } /// Unlisten the given interrupts pub fn unlisten(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), false); + self.tx.uart.info().enable_listen(interrupts.into(), false) } /// Gets asserted interrupts pub fn interrupts(&mut self) -> EnumSet { - let mut res = EnumSet::new(); - let reg_block = self.register_block(); - - let ints = reg_block.int_raw().read(); - - if ints.at_cmd_char_det().bit_is_set() { - res.insert(UartInterrupt::AtCmd); - } - if ints.tx_done().bit_is_set() { - res.insert(UartInterrupt::TxDone); - } - if ints.rxfifo_full().bit_is_set() { - res.insert(UartInterrupt::RxFifoFull); - } - - res + self.tx.uart.info().interrupts() } /// Resets asserted interrupts pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - let reg_block = self.register_block(); - - reg_block.int_clr().write(|w| { - for interrupt in interrupts { - match interrupt { - UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(), - UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(), - UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(), - }; - } - w - }); + self.tx.uart.info().clear_interrupts(interrupts) } /// Write a byte out over the UART @@ -1479,7 +1531,8 @@ where T: Instance, { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - self.inner_set_interrupt_handler(handler); + // `self.tx.uart` and `self.rx.uart` are the same + self.tx.uart.info().set_interrupt_handler(handler); } } @@ -1751,560 +1804,406 @@ where } } -mod asynch { - use core::task::Poll; - - use enumset::{EnumSet, EnumSetType}; +#[derive(EnumSetType, Debug)] +pub(crate) enum TxEvent { + TxDone, + TxFiFoEmpty, +} +#[derive(EnumSetType, Debug)] +pub(crate) enum RxEvent { + FifoFull, + CmdCharDetected, + FifoOvf, + FifoTout, + GlitchDetected, + FrameError, + ParityError, +} - use super::*; - use crate::Async; +/// A future that resolves when the passed interrupt is triggered, +/// or has been triggered in the meantime (flag set in INT_RAW). +/// Upon construction the future enables the passed interrupt and when it +/// is dropped it disables the interrupt again. The future returns the event +/// that was initially passed, when it resolves. +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UartRxFuture<'d> { + events: EnumSet, + uart: &'d Info, + state: &'d State, + registered: bool, +} - #[derive(EnumSetType, Debug)] - pub(crate) enum TxEvent { - TxDone, - TxFiFoEmpty, - } - #[derive(EnumSetType, Debug)] - pub(crate) enum RxEvent { - FifoFull, - CmdCharDetected, - FifoOvf, - FifoTout, - GlitchDetected, - FrameError, - ParityError, +impl<'d> UartRxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { + Self { + events: events.into(), + uart, + state, + registered: false, + } } - /// A future that resolves when the passed interrupt is triggered, - /// or has been triggered in the meantime (flag set in INT_RAW). - /// Upon construction the future enables the passed interrupt and when it - /// is dropped it disables the interrupt again. The future returns the event - /// that was initially passed, when it resolves. - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct UartRxFuture<'d> { - events: EnumSet, - uart: &'d Info, - state: &'d State, - registered: bool, - } + fn triggered_events(&self) -> EnumSet { + let interrupts_enabled = self.uart.register_block().int_ena().read(); + let mut events_triggered = EnumSet::new(); + for event in self.events { + let event_triggered = match event { + RxEvent::FifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(), + RxEvent::CmdCharDetected => interrupts_enabled.at_cmd_char_det().bit_is_clear(), - impl<'d> UartRxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { - Self { - events: events.into(), - uart, - state, - registered: false, + RxEvent::FifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(), + RxEvent::FifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(), + RxEvent::GlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(), + RxEvent::FrameError => interrupts_enabled.frm_err().bit_is_clear(), + RxEvent::ParityError => interrupts_enabled.parity_err().bit_is_clear(), + }; + if event_triggered { + events_triggered |= event; } } + events_triggered + } - fn triggered_events(&self) -> EnumSet { - let interrupts_enabled = self.uart.register_block().int_ena().read(); - let mut events_triggered = EnumSet::new(); + fn enable_listen(&self, enable: bool) { + self.uart.register_block().int_ena().modify(|_, w| { for event in self.events { - let event_triggered = match event { - RxEvent::FifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(), - RxEvent::CmdCharDetected => interrupts_enabled.at_cmd_char_det().bit_is_clear(), - - RxEvent::FifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(), - RxEvent::FifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(), - RxEvent::GlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(), - RxEvent::FrameError => interrupts_enabled.frm_err().bit_is_clear(), - RxEvent::ParityError => interrupts_enabled.parity_err().bit_is_clear(), + match event { + RxEvent::FifoFull => w.rxfifo_full().bit(enable), + RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable), + RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable), + RxEvent::FifoTout => w.rxfifo_tout().bit(enable), + RxEvent::GlitchDetected => w.glitch_det().bit(enable), + RxEvent::FrameError => w.frm_err().bit(enable), + RxEvent::ParityError => w.parity_err().bit(enable), }; - if event_triggered { - events_triggered |= event; - } } - events_triggered - } - - fn enable_listen(&self, enable: bool) { - self.uart.register_block().int_ena().modify(|_, w| { - for event in self.events { - match event { - RxEvent::FifoFull => w.rxfifo_full().bit(enable), - RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable), - RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable), - RxEvent::FifoTout => w.rxfifo_tout().bit(enable), - RxEvent::GlitchDetected => w.glitch_det().bit(enable), - RxEvent::FrameError => w.frm_err().bit(enable), - RxEvent::ParityError => w.parity_err().bit(enable), - }; - } - w - }); - } + w + }); } +} - impl core::future::Future for UartRxFuture<'_> { - type Output = EnumSet; - - fn poll( - mut self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - if !self.registered { - self.state.rx_waker.register(cx.waker()); - self.enable_listen(true); - self.registered = true; - } - let events = self.triggered_events(); - if !events.is_empty() { - Poll::Ready(events) - } else { - Poll::Pending - } +impl core::future::Future for UartRxFuture<'_> { + type Output = EnumSet; + + fn poll( + mut self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + if !self.registered { + self.state.rx_waker.register(cx.waker()); + self.enable_listen(true); + self.registered = true; + } + let events = self.triggered_events(); + if !events.is_empty() { + Poll::Ready(events) + } else { + Poll::Pending } } +} - impl Drop for UartRxFuture<'_> { - fn drop(&mut self) { - // Although the isr disables the interrupt that occurred directly, we need to - // disable the other interrupts (= the ones that did not occur), as - // soon as this future goes out of scope. - self.enable_listen(false); - } +impl Drop for UartRxFuture<'_> { + fn drop(&mut self) { + // Although the isr disables the interrupt that occurred directly, we need to + // disable the other interrupts (= the ones that did not occur), as + // soon as this future goes out of scope. + self.enable_listen(false); } +} - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct UartTxFuture<'d> { - events: EnumSet, - uart: &'d Info, - state: &'d State, - registered: bool, - } - impl<'d> UartTxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { - Self { - events: events.into(), - uart, - state, - registered: false, - } +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UartTxFuture<'d> { + events: EnumSet, + uart: &'d Info, + state: &'d State, + registered: bool, +} +impl<'d> UartTxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { + Self { + events: events.into(), + uart, + state, + registered: false, } + } - fn triggered_events(&self) -> bool { - let interrupts_enabled = self.uart.register_block().int_ena().read(); - let mut event_triggered = false; - for event in self.events { - event_triggered |= match event { - TxEvent::TxDone => interrupts_enabled.tx_done().bit_is_clear(), - TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty().bit_is_clear(), - } + fn triggered_events(&self) -> bool { + let interrupts_enabled = self.uart.register_block().int_ena().read(); + let mut event_triggered = false; + for event in self.events { + event_triggered |= match event { + TxEvent::TxDone => interrupts_enabled.tx_done().bit_is_clear(), + TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty().bit_is_clear(), } - event_triggered - } - - fn enable_listen(&self, enable: bool) { - self.uart.register_block().int_ena().modify(|_, w| { - for event in self.events { - match event { - TxEvent::TxDone => w.tx_done().bit(enable), - TxEvent::TxFiFoEmpty => w.txfifo_empty().bit(enable), - }; - } - w - }); } + event_triggered } - impl core::future::Future for UartTxFuture<'_> { - type Output = (); - - fn poll( - mut self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - if !self.registered { - self.state.tx_waker.register(cx.waker()); - self.enable_listen(true); - self.registered = true; - } - - if self.triggered_events() { - Poll::Ready(()) - } else { - Poll::Pending + fn enable_listen(&self, enable: bool) { + self.uart.register_block().int_ena().modify(|_, w| { + for event in self.events { + match event { + TxEvent::TxDone => w.tx_done().bit(enable), + TxEvent::TxFiFoEmpty => w.txfifo_empty().bit(enable), + }; } - } + w + }); } +} - impl Drop for UartTxFuture<'_> { - fn drop(&mut self) { - // Although the isr disables the interrupt that occurred directly, we need to - // disable the other interrupts (= the ones that did not occur), as - // soon as this future goes out of scope. - self.enable_listen(false); - } - } +impl core::future::Future for UartTxFuture<'_> { + type Output = (); - impl<'d> Uart<'d, Async> { - /// Create a new UART instance with defaults in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - Uart::new_async_typed(uart.map_into(), rx, tx) + fn poll( + mut self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + if !self.registered { + self.state.tx_waker.register(cx.waker()); + self.enable_listen(true); + self.registered = true; } - /// Create a new UART instance with configuration options in [`Async`] - /// mode. - pub fn new_async_with_config( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - Uart::new_async_with_config_typed(uart.map_into(), config, rx, tx) + if self.triggered_events() { + Poll::Ready(()) + } else { + Poll::Pending } } +} - impl<'d, T> Uart<'d, Async, T> - where - T: Instance, - { - /// Create a new UART instance with defaults in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - Self::new_async_with_config_typed(uart, Config::default(), rx, tx) - } - - /// Create a new UART instance with configuration options in [`Async`] - /// mode. - pub fn new_async_with_config_typed( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - // FIXME: at the time of writing, the order of the pin assignments matters: - // first binding RX, then TX makes tests fail. This is bad and needs to be - // figured out. - let mut this = UartBuilder::new(uart) - .with_tx(tx) - .with_rx(rx) - .init(config)?; - - this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); - - Ok(this) - } - } - - impl Uart<'_, Async, T> - where - T: Instance, - { - /// Asynchronously reads data from the UART receive buffer into the - /// provided buffer. - pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { - self.rx.read_async(buf).await - } - - /// Asynchronously writes data to the UART transmit buffer. - pub async fn write_async(&mut self, words: &[u8]) -> Result { - self.tx.write_async(words).await - } - - /// Asynchronously flushes the UART transmit buffer. - pub async fn flush_async(&mut self) -> Result<(), Error> { - self.tx.flush_async().await - } +impl Drop for UartTxFuture<'_> { + fn drop(&mut self) { + // Although the isr disables the interrupt that occurred directly, we need to + // disable the other interrupts (= the ones that did not occur), as + // soon as this future goes out of scope. + self.enable_listen(false); } +} - impl<'d> UartTx<'d, Async> { - /// Create a new UART TX instance in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - UartTx::new_async_typed(uart.map_into(), tx) - } - - /// Create a new UART TX instance with configuration options in - /// [`Async`] mode. - pub fn new_async_with_config( - uart: impl Peripheral

+ 'd, - config: Config, - tx: impl Peripheral

+ 'd, - ) -> Result { - UartTx::new_async_with_config_typed(uart.map_into(), config, tx) - } +impl Uart<'_, Async, T> +where + T: Instance, +{ + /// Asynchronously reads data from the UART receive buffer into the + /// provided buffer. + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { + self.rx.read_async(buf).await } - impl<'d, T> UartTx<'d, Async, T> - where - T: Instance, - { - /// Create a new UART TX instance in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - UartTx::new_async_with_config_typed(uart, Config::default(), tx) - } - - /// Create a new UART TX instance with configuration options in - /// [`Async`] mode. - pub fn new_async_with_config_typed( - uart: impl Peripheral

+ 'd, - config: Config, - tx: impl Peripheral

+ 'd, - ) -> Result { - let mut this = UartBuilder::new(uart).with_tx(tx).init(config)?; - - this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); - - let (_, uart_tx) = this.split(); - Ok(uart_tx) - } - - /// Asynchronously writes data to the UART transmit buffer in chunks. - /// - /// This function sends the contents of the provided buffer `words` over - /// the UART. Data is written in chunks to avoid overflowing the - /// transmit FIFO, and the function waits asynchronously when - /// necessary for space in the buffer to become available. - pub async fn write_async(&mut self, words: &[u8]) -> Result { - let mut count = 0; - let mut offset: usize = 0; - loop { - let mut next_offset = offset + (UART_FIFO_SIZE - self.tx_fifo_count()) as usize; - if next_offset > words.len() { - next_offset = words.len(); - } - - for byte in &words[offset..next_offset] { - self.write_byte(*byte).unwrap(); // should never fail - count += 1; - } + /// Asynchronously writes data to the UART transmit buffer. + pub async fn write_async(&mut self, words: &[u8]) -> Result { + self.tx.write_async(words).await + } - if next_offset >= words.len() { - break; - } + /// Asynchronously flushes the UART transmit buffer. + pub async fn flush_async(&mut self) -> Result<(), Error> { + self.tx.flush_async().await + } +} - offset = next_offset; - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; +impl<'d, T> UartTx<'d, Async, T> +where + T: Instance, +{ + /// Asynchronously writes data to the UART transmit buffer in chunks. + /// + /// This function sends the contents of the provided buffer `words` over + /// the UART. Data is written in chunks to avoid overflowing the + /// transmit FIFO, and the function waits asynchronously when + /// necessary for space in the buffer to become available. + pub async fn write_async(&mut self, words: &[u8]) -> Result { + let mut count = 0; + let mut offset: usize = 0; + loop { + let mut next_offset = offset + (UART_FIFO_SIZE - self.tx_fifo_count()) as usize; + if next_offset > words.len() { + next_offset = words.len(); } - Ok(count) - } + for byte in &words[offset..next_offset] { + self.write_byte(*byte).unwrap(); // should never fail + count += 1; + } - /// Asynchronously flushes the UART transmit buffer. - /// - /// This function ensures that all pending data in the transmit FIFO has - /// been sent over the UART. If the FIFO contains data, it waits - /// for the transmission to complete before returning. - pub async fn flush_async(&mut self) -> Result<(), Error> { - let count = self.tx_fifo_count(); - if count > 0 { - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; + if next_offset >= words.len() { + break; } - Ok(()) + offset = next_offset; + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; } + + Ok(count) } - impl<'d> UartRx<'d, Async> { - /// Create a new UART RX instance in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - ) -> Result { - Self::new_async_typed(uart.map_into(), rx) + /// Asynchronously flushes the UART transmit buffer. + /// + /// This function ensures that all pending data in the transmit FIFO has + /// been sent over the UART. If the FIFO contains data, it waits + /// for the transmission to complete before returning. + pub async fn flush_async(&mut self) -> Result<(), Error> { + let count = self.tx_fifo_count(); + if count > 0 { + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; } - /// Create a new UART RX instance with configuration options in - /// [`Async`] mode. - pub fn new_async_with_config( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - ) -> Result { - Self::new_async_with_config_typed(uart.map_into(), config, rx) - } + Ok(()) } +} - impl<'d, T> UartRx<'d, Async, T> - where - T: Instance, - { - /// Create a new UART RX instance in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - ) -> Result { - Self::new_async_with_config_typed(uart, Config::default(), rx) - } - - /// Create a new UART RX instance with configuration options in - /// [`Async`] mode. - pub fn new_async_with_config_typed( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - ) -> Result { - let mut this = UartBuilder::new(uart).with_rx(rx).init(config)?; - - this.inner_set_interrupt_handler(this.tx.uart.info().async_handler); - - let (uart_rx, _) = this.split(); - Ok(uart_rx) - } - - /// Read async to buffer slice `buf`. - /// Waits until at least one byte is in the Rx FiFo - /// and one of the following interrupts occurs: - /// - `RXFIFO_FULL` - /// - `RXFIFO_OVF` - /// - `AT_CMD_CHAR_DET` (only if `set_at_cmd` was called) - /// - `RXFIFO_TOUT` (only if `set_rx_timeout was called) - /// - /// The interrupts in question are enabled during the body of this - /// function. The method immediately returns when the interrupt - /// has already occurred before calling this method (e.g. status - /// bit set, but interrupt not enabled) - /// - /// # Params - /// - `buf` buffer slice to write the bytes into - /// - /// - /// # Ok - /// When successful, returns the number of bytes written to buf. - /// This method will never return Ok(0) - pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Err(Error::InvalidArgument); - } - - loop { - let mut events = RxEvent::FifoFull - | RxEvent::FifoOvf - | RxEvent::FrameError - | RxEvent::GlitchDetected - | RxEvent::ParityError; +impl<'d, T> UartRx<'d, Async, T> +where + T: Instance, +{ + /// Read async to buffer slice `buf`. + /// Waits until at least one byte is in the Rx FiFo + /// and one of the following interrupts occurs: + /// - `RXFIFO_FULL` + /// - `RXFIFO_OVF` + /// - `AT_CMD_CHAR_DET` (only if `set_at_cmd` was called) + /// - `RXFIFO_TOUT` (only if `set_rx_timeout was called) + /// + /// The interrupts in question are enabled during the body of this + /// function. The method immediately returns when the interrupt + /// has already occurred before calling this method (e.g. status + /// bit set, but interrupt not enabled) + /// + /// # Params + /// - `buf` buffer slice to write the bytes into + /// + /// + /// # Ok + /// When successful, returns the number of bytes written to buf. + /// This method will never return Ok(0) + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Err(Error::InvalidArgument); + } - if self.at_cmd_config.is_some() { - events |= RxEvent::CmdCharDetected; - } - if self.rx_timeout_config.is_some() { - events |= RxEvent::FifoTout; - } + loop { + let mut events = RxEvent::FifoFull + | RxEvent::FifoOvf + | RxEvent::FrameError + | RxEvent::GlitchDetected + | RxEvent::ParityError; + + if self.at_cmd_config.is_some() { + events |= RxEvent::CmdCharDetected; + } + if self.rx_timeout_config.is_some() { + events |= RxEvent::FifoTout; + } - let events_happened = - UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; - // always drain the fifo, if an error has occurred the data is lost - let read_bytes = self.drain_fifo(buf); - // check error events - for event_happened in events_happened { - match event_happened { - RxEvent::FifoOvf => return Err(Error::RxFifoOvf), - RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected), - RxEvent::FrameError => return Err(Error::RxFrameError), - RxEvent::ParityError => return Err(Error::RxParityError), - RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => { - continue - } - } + let events_happened = + UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; + // always drain the fifo, if an error has occurred the data is lost + let read_bytes = self.drain_fifo(buf); + // check error events + for event_happened in events_happened { + match event_happened { + RxEvent::FifoOvf => return Err(Error::RxFifoOvf), + RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected), + RxEvent::FrameError => return Err(Error::RxFrameError), + RxEvent::ParityError => return Err(Error::RxParityError), + RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => continue, } - // Unfortunately, the uart's rx-timeout counter counts up whenever there is - // data in the fifo, even if the interrupt is disabled and the status bit - // cleared. Since we do not drain the fifo in the interrupt handler, we need to - // reset the counter here, after draining the fifo. - self.register_block() - .int_clr() - .write(|w| w.rxfifo_tout().clear_bit_by_one()); + } + // Unfortunately, the uart's rx-timeout counter counts up whenever there is + // data in the fifo, even if the interrupt is disabled and the status bit + // cleared. Since we do not drain the fifo in the interrupt handler, we need to + // reset the counter here, after draining the fifo. + self.register_block() + .int_clr() + .write(|w| w.rxfifo_tout().clear_bit_by_one()); - if read_bytes > 0 { - return Ok(read_bytes); - } + if read_bytes > 0 { + return Ok(read_bytes); } } } +} - impl embedded_io_async::Read for Uart<'_, Async, T> - where - T: Instance, - { - /// In contrast to the documentation of embedded_io_async::Read, this - /// method blocks until an uart interrupt occurs. - /// See UartRx::read_async for more details. - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_async(buf).await - } +impl embedded_io_async::Read for Uart<'_, Async, T> +where + T: Instance, +{ + /// In contrast to the documentation of embedded_io_async::Read, this + /// method blocks until an uart interrupt occurs. + /// See UartRx::read_async for more details. + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_async(buf).await } +} - impl embedded_io_async::Read for UartRx<'_, Async, T> - where - T: Instance, - { - /// In contrast to the documentation of embedded_io_async::Read, this - /// method blocks until an uart interrupt occurs. - /// See UartRx::read_async for more details. - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_async(buf).await - } +impl embedded_io_async::Read for UartRx<'_, Async, T> +where + T: Instance, +{ + /// In contrast to the documentation of embedded_io_async::Read, this + /// method blocks until an uart interrupt occurs. + /// See UartRx::read_async for more details. + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_async(buf).await } +} - impl embedded_io_async::Write for Uart<'_, Async, T> - where - T: Instance, - { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_async(buf).await - } +impl embedded_io_async::Write for Uart<'_, Async, T> +where + T: Instance, +{ + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_async(buf).await + } - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_async().await - } + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_async().await } +} - impl embedded_io_async::Write for UartTx<'_, Async, T> - where - T: Instance, - { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_async(buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_async().await - } - } - - /// Interrupt handler for all UART instances - /// Clears and disables interrupts that have occurred and have their enable - /// bit set. The fact that an interrupt has been disabled is used by the - /// futures to detect that they should indeed resolve after being woken up - pub(super) fn intr_handler(uart: &Info, state: &State) { - let interrupts = uart.register_block().int_st().read(); - let interrupt_bits = interrupts.bits(); // = int_raw & int_ena - let rx_wake = interrupts.rxfifo_full().bit_is_set() - || interrupts.rxfifo_ovf().bit_is_set() - || interrupts.rxfifo_tout().bit_is_set() - || interrupts.at_cmd_char_det().bit_is_set() - || interrupts.glitch_det().bit_is_set() - || interrupts.frm_err().bit_is_set() - || interrupts.parity_err().bit_is_set(); - let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); - uart.register_block() - .int_clr() - .write(|w| unsafe { w.bits(interrupt_bits) }); - uart.register_block() - .int_ena() - .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); +impl embedded_io_async::Write for UartTx<'_, Async, T> +where + T: Instance, +{ + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_async(buf).await + } - if tx_wake { - state.tx_waker.wake(); - } - if rx_wake { - state.rx_waker.wake(); - } + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_async().await + } +} + +/// Interrupt handler for all UART instances +/// Clears and disables interrupts that have occurred and have their enable +/// bit set. The fact that an interrupt has been disabled is used by the +/// futures to detect that they should indeed resolve after being woken up +pub(super) fn intr_handler(uart: &Info, state: &State) { + let interrupts = uart.register_block().int_st().read(); + let interrupt_bits = interrupts.bits(); // = int_raw & int_ena + let rx_wake = interrupts.rxfifo_full().bit_is_set() + || interrupts.rxfifo_ovf().bit_is_set() + || interrupts.rxfifo_tout().bit_is_set() + || interrupts.at_cmd_char_det().bit_is_set() + || interrupts.glitch_det().bit_is_set() + || interrupts.frm_err().bit_is_set() + || interrupts.parity_err().bit_is_set(); + let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); + uart.register_block() + .int_clr() + .write(|w| unsafe { w.bits(interrupt_bits) }); + uart.register_block() + .int_ena() + .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); + + if tx_wake { + state.tx_waker.wake(); + } + if rx_wake { + state.rx_waker.wake(); } } @@ -2502,6 +2401,22 @@ pub mod lp_uart { } } +impl Info { + fn set_interrupt_handler(&self, handler: InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, self.interrupt); + } + self.enable_listen(EnumSet::all(), false); + self.clear_interrupts(EnumSet::all()); + unsafe { crate::interrupt::bind_interrupt(self.interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(self.interrupt, handler.priority())); + } + + fn disable_interrupts(&self) { + crate::interrupt::disable(crate::Cpu::current(), self.interrupt); + } +} + /// UART Peripheral Instance pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { /// Returns the peripheral data and state describing this UART instance. @@ -2553,6 +2468,12 @@ pub struct State { /// Waker for the asynchronous TX operations. pub tx_waker: AtomicWaker, + + /// Stores whether the TX half is configured for async operation. + pub is_rx_async: AtomicBool, + + /// Stores whether the RX half is configured for async operation. + pub is_tx_async: AtomicBool, } impl Info { @@ -2560,6 +2481,56 @@ impl Info { pub fn register_block(&self) -> &RegisterBlock { unsafe { &*self.register_block } } + + /// Listen for the given interrupts + fn enable_listen(&self, interrupts: EnumSet, enable: bool) { + let reg_block = self.register_block(); + + reg_block.int_ena().modify(|_, w| { + for interrupt in interrupts { + match interrupt { + UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable), + UartInterrupt::TxDone => w.tx_done().bit(enable), + UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable), + }; + } + w + }); + } + + fn interrupts(&self) -> EnumSet { + let mut res = EnumSet::new(); + let reg_block = self.register_block(); + + let ints = reg_block.int_raw().read(); + + if ints.at_cmd_char_det().bit_is_set() { + res.insert(UartInterrupt::AtCmd); + } + if ints.tx_done().bit_is_set() { + res.insert(UartInterrupt::TxDone); + } + if ints.rxfifo_full().bit_is_set() { + res.insert(UartInterrupt::RxFifoFull); + } + + res + } + + fn clear_interrupts(&self, interrupts: EnumSet) { + let reg_block = self.register_block(); + + reg_block.int_clr().write(|w| { + for interrupt in interrupts { + match interrupt { + UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(), + UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(), + UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(), + }; + } + w + }); + } } impl PartialEq for Info { @@ -2576,12 +2547,14 @@ macro_rules! impl_instance { fn parts(&self) -> (&Info, &State) { #[crate::macros::handler] pub(super) fn irq_handler() { - asynch::intr_handler(&PERIPHERAL, &STATE); + intr_handler(&PERIPHERAL, &STATE); } static STATE: State = State { tx_waker: AtomicWaker::new(), rx_waker: AtomicWaker::new(), + is_rx_async: AtomicBool::new(false), + is_tx_async: AtomicBool::new(false), }; static PERIPHERAL: Info = Info { diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index a2247bacab6..42c82f8aacd 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -75,14 +75,18 @@ //! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/ //! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/ -use core::{convert::Infallible, marker::PhantomData}; +use core::{convert::Infallible, marker::PhantomData, task::Poll}; + +use embassy_sync::waitqueue::AtomicWaker; +use procmacros::handler; use crate::{ - interrupt::InterruptHandler, - peripheral::Peripheral, + peripheral::{Peripheral, PeripheralRef}, peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE}, system::PeripheralClockControl, + Async, Blocking, + Cpu, InterruptConfigurable, Mode, }; @@ -98,20 +102,24 @@ pub struct UsbSerialJtag<'d, M> { /// USB Serial/JTAG (Transmit) pub struct UsbSerialJtagTx<'d, M> { - phantom: PhantomData<(&'d mut USB_DEVICE, M)>, + peripheral: PeripheralRef<'d, USB_DEVICE>, + phantom: PhantomData, } /// USB Serial/JTAG (Receive) pub struct UsbSerialJtagRx<'d, M> { - phantom: PhantomData<(&'d mut USB_DEVICE, M)>, + peripheral: PeripheralRef<'d, USB_DEVICE>, + phantom: PhantomData, } -impl UsbSerialJtagTx<'_, M> +impl<'d, M> UsbSerialJtagTx<'d, M> where M: Mode, { - fn new_inner() -> Self { + fn new_inner(peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(peripheral); Self { + peripheral, phantom: PhantomData, } } @@ -183,12 +191,14 @@ where } } -impl UsbSerialJtagRx<'_, M> +impl<'d, M> UsbSerialJtagRx<'d, M> where M: Mode, { - fn new_inner() -> Self { + fn new_inner(peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(peripheral); Self { + peripheral, phantom: PhantomData, } } @@ -263,13 +273,37 @@ impl<'d> UsbSerialJtag<'d, Blocking> { pub fn new(usb_device: impl Peripheral

+ 'd) -> Self { Self::new_inner(usb_device) } + + /// Reconfigure the USB Serial JTAG peripheral to operate in asynchronous + /// mode. + pub fn into_async(mut self) -> UsbSerialJtag<'d, Async> { + self.set_interrupt_handler(async_interrupt_handler); + + UsbSerialJtag { + rx: UsbSerialJtagRx { + peripheral: self.rx.peripheral, + phantom: PhantomData, + }, + tx: UsbSerialJtagTx { + peripheral: self.tx.peripheral, + phantom: PhantomData, + }, + } + } } impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {} impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - self.inner_set_interrupt_handler(handler); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::USB_DEVICE); + } + unsafe { crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler()) }; + unwrap!(crate::interrupt::enable( + Interrupt::USB_DEVICE, + handler.priority() + )); } } @@ -277,7 +311,7 @@ impl<'d, M> UsbSerialJtag<'d, M> where M: Mode, { - fn new_inner(_usb_device: impl Peripheral

+ 'd) -> Self { + fn new_inner(usb_device: impl Peripheral

+ 'd) -> Self { // Do NOT reset the peripheral. Doing so will result in a broken USB JTAG // connection. PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice); @@ -293,29 +327,20 @@ where // doesn't swap the pullups too, this works around that. if Efuse::read_bit(USB_EXCHG_PINS) { USB_DEVICE::register_block().conf0().modify(|_, w| { - w.pad_pull_override() - .set_bit() - .dm_pullup() - .clear_bit() - .dp_pullup() - .set_bit() + w.pad_pull_override().set_bit(); + w.dm_pullup().clear_bit(); + w.dp_pullup().set_bit() }); } } - Self { - rx: UsbSerialJtagRx::new_inner(), - tx: UsbSerialJtagTx::new_inner(), - } - } + crate::into_ref!(usb_device); - fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler()); - crate::interrupt::enable(Interrupt::USB_DEVICE, handler.priority()).unwrap(); + Self { + rx: UsbSerialJtagRx::new_inner(unsafe { usb_device.clone_unchecked() }), + tx: UsbSerialJtagTx::new_inner(usb_device), } } - /// Split the USB Serial JTAG peripheral into a transmitter and receiver, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. @@ -652,224 +677,221 @@ where } } -mod asynch { - use core::{marker::PhantomData, task::Poll}; - - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; +// Static instance of the waker for each component of the peripheral: +static WAKER_TX: AtomicWaker = AtomicWaker::new(); +static WAKER_RX: AtomicWaker = AtomicWaker::new(); - use super::{Error, Instance, UsbSerialJtag, UsbSerialJtagRx, UsbSerialJtagTx}; - use crate::{peripheral::Peripheral, peripherals::USB_DEVICE, Async}; +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UsbSerialJtagWriteFuture<'d> { + _peripheral: PeripheralRef<'d, USB_DEVICE>, +} - // Static instance of the waker for each component of the peripheral: - static WAKER_TX: AtomicWaker = AtomicWaker::new(); - static WAKER_RX: AtomicWaker = AtomicWaker::new(); +impl<'d> UsbSerialJtagWriteFuture<'d> { + fn new(_peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(_peripheral); + // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT + // interrupt + USB_DEVICE::register_block() + .int_ena() + .modify(|_, w| w.serial_in_empty().set_bit()); - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct UsbSerialJtagWriteFuture<'d> { - phantom: PhantomData<&'d mut USB_DEVICE>, + Self { _peripheral } } - impl UsbSerialJtagWriteFuture<'_> { - pub fn new() -> Self { - // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT - // interrupt - USB_DEVICE::register_block() - .int_ena() - .modify(|_, w| w.serial_in_empty().set_bit()); - - Self { - phantom: PhantomData, - } - } - - fn event_bit_is_clear(&self) -> bool { - USB_DEVICE::register_block() - .int_ena() - .read() - .serial_in_empty() - .bit_is_clear() - } + fn event_bit_is_clear(&self) -> bool { + USB_DEVICE::register_block() + .int_ena() + .read() + .serial_in_empty() + .bit_is_clear() } +} - impl core::future::Future for UsbSerialJtagWriteFuture<'_> { - type Output = (); +impl core::future::Future for UsbSerialJtagWriteFuture<'_> { + type Output = (); - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - WAKER_TX.register(cx.waker()); - if self.event_bit_is_clear() { - Poll::Ready(()) - } else { - Poll::Pending - } + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + WAKER_TX.register(cx.waker()); + if self.event_bit_is_clear() { + Poll::Ready(()) + } else { + Poll::Pending } } +} - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct UsbSerialJtagReadFuture<'d> { - phantom: PhantomData<&'d mut USB_DEVICE>, - } +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UsbSerialJtagReadFuture<'d> { + _peripheral: PeripheralRef<'d, USB_DEVICE>, +} - impl UsbSerialJtagReadFuture<'_> { - pub fn new() -> Self { - // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT - // interrupt - USB_DEVICE::register_block() - .int_ena() - .modify(|_, w| w.serial_out_recv_pkt().set_bit()); +impl<'d> UsbSerialJtagReadFuture<'d> { + fn new(_peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(_peripheral); + // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT + // interrupt + USB_DEVICE::register_block() + .int_ena() + .modify(|_, w| w.serial_out_recv_pkt().set_bit()); - Self { - phantom: PhantomData, - } - } + Self { _peripheral } + } - fn event_bit_is_clear(&self) -> bool { - USB_DEVICE::register_block() - .int_ena() - .read() - .serial_out_recv_pkt() - .bit_is_clear() - } + fn event_bit_is_clear(&self) -> bool { + USB_DEVICE::register_block() + .int_ena() + .read() + .serial_out_recv_pkt() + .bit_is_clear() } +} - impl core::future::Future for UsbSerialJtagReadFuture<'_> { - type Output = (); +impl core::future::Future for UsbSerialJtagReadFuture<'_> { + type Output = (); - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - WAKER_RX.register(cx.waker()); - if self.event_bit_is_clear() { - Poll::Ready(()) - } else { - Poll::Pending - } + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + WAKER_RX.register(cx.waker()); + if self.event_bit_is_clear() { + Poll::Ready(()) + } else { + Poll::Pending } } +} - impl<'d> UsbSerialJtag<'d, Async> { - /// Create a new USB serial/JTAG instance in asynchronous mode - pub fn new_async(usb_device: impl Peripheral

+ 'd) -> Self { - let mut this = Self::new_inner(usb_device); - this.inner_set_interrupt_handler(async_interrupt_handler); - this +impl<'d> UsbSerialJtag<'d, Async> { + /// Reconfigure the USB Serial JTAG peripheral to operate in blocking + /// mode. + pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE); + UsbSerialJtag { + rx: UsbSerialJtagRx { + peripheral: self.rx.peripheral, + phantom: PhantomData, + }, + tx: UsbSerialJtagTx { + peripheral: self.tx.peripheral, + phantom: PhantomData, + }, } } +} - impl UsbSerialJtagTx<'_, Async> { - async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { - let reg_block = USB_DEVICE::register_block(); - - for chunk in words.chunks(64) { - for byte in chunk { - reg_block - .ep1() - .write(|w| unsafe { w.rdwr_byte().bits(*byte) }); - } - reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); +impl UsbSerialJtagTx<'_, Async> { + async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { + let reg_block = USB_DEVICE::register_block(); - UsbSerialJtagWriteFuture::new().await; + for chunk in words.chunks(64) { + for byte in chunk { + reg_block + .ep1() + .write(|w| unsafe { w.rdwr_byte().bits(*byte) }); } + reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); - Ok(()) + UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await; } - async fn flush_tx_async(&mut self) -> Result<(), Error> { - if USB_DEVICE::register_block() - .jfifo_st() - .read() - .out_fifo_empty() - .bit_is_clear() - { - UsbSerialJtagWriteFuture::new().await; - } + Ok(()) + } - Ok(()) + async fn flush_tx_async(&mut self) -> Result<(), Error> { + if USB_DEVICE::register_block() + .jfifo_st() + .read() + .out_fifo_empty() + .bit_is_clear() + { + UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await; } + + Ok(()) } +} - impl UsbSerialJtagRx<'_, Async> { - async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } +impl UsbSerialJtagRx<'_, Async> { + async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } - loop { - let read_bytes = self.drain_rx_fifo(buf); - if read_bytes > 0 { - return Ok(read_bytes); - } - UsbSerialJtagReadFuture::new().await; + loop { + let read_bytes = self.drain_rx_fifo(buf); + if read_bytes > 0 { + return Ok(read_bytes); } + UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await; } } +} - impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { - async fn write(&mut self, buf: &[u8]) -> Result { - embedded_io_async::Write::write(&mut self.tx, buf).await - } +impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { + async fn write(&mut self, buf: &[u8]) -> Result { + embedded_io_async::Write::write(&mut self.tx, buf).await + } - async fn flush(&mut self) -> Result<(), Self::Error> { - embedded_io_async::Write::flush(&mut self.tx).await - } + async fn flush(&mut self) -> Result<(), Self::Error> { + embedded_io_async::Write::flush(&mut self.tx).await } +} - impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes_async(buf).await?; +impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_bytes_async(buf).await?; - Ok(buf.len()) - } + Ok(buf.len()) + } - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_tx_async().await - } + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_tx_async().await } +} - impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - embedded_io_async::Read::read(&mut self.rx, buf).await - } +impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + embedded_io_async::Read::read(&mut self.rx, buf).await } +} - impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_bytes_async(buf).await - } +impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_bytes_async(buf).await } +} - #[handler] - fn async_interrupt_handler() { - let usb = USB_DEVICE::register_block(); - let interrupts = usb.int_st().read(); +#[handler] +fn async_interrupt_handler() { + let usb = USB_DEVICE::register_block(); + let interrupts = usb.int_st().read(); - let tx = interrupts.serial_in_empty().bit_is_set(); - let rx = interrupts.serial_out_recv_pkt().bit_is_set(); + let tx = interrupts.serial_in_empty().bit_is_set(); + let rx = interrupts.serial_out_recv_pkt().bit_is_set(); - if tx { - usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit()); - } - if rx { - usb.int_ena() - .modify(|_, w| w.serial_out_recv_pkt().clear_bit()); - } + if tx { + usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit()); + } + if rx { + usb.int_ena() + .modify(|_, w| w.serial_out_recv_pkt().clear_bit()); + } - usb.int_clr().write(|w| { - w.serial_in_empty() - .clear_bit_by_one() - .serial_out_recv_pkt() - .clear_bit_by_one() - }); + usb.int_clr().write(|w| { + w.serial_in_empty() + .clear_bit_by_one() + .serial_out_recv_pkt() + .clear_bit_by_one() + }); - if rx { - WAKER_RX.wake(); - } - if tx { - WAKER_TX.wake(); - } + if rx { + WAKER_RX.wake(); + } + if tx { + WAKER_TX.wake(); } } diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index d6b10e04bf3..152369854a4 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let i2c0 = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()); + let i2c0 = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async(); let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap(); lis3dh.set_range(Range::G8).await.unwrap(); diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 737cc84ab2f..24fb3b7798c 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut i2c = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()); + let mut i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async(); loop { let mut data = [0u8; 22]; diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs index dcf0167d846..509f7183595 100644 --- a/examples/src/bin/embassy_i2s_parallel.rs +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) { let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); let mut parallel = I2sParallel::new( i2s, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), 1.MHz(), pins, clock, diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index 17c48383c48..afb796c1c42 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -52,10 +52,11 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); #[cfg(not(feature = "esp32"))] let i2s = i2s.with_mclk(io.pins.gpio0); diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index 50660d81840..2c807a4755c 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -74,10 +74,11 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); let i2s_tx = i2s .i2s_tx diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 83fccaec51d..95e28f696ee 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -42,7 +42,9 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), rx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index 9a1ca372fb3..e177ad506d9 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -55,7 +55,9 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 0befacef8ff..4ebfd23c56e 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -15,7 +15,7 @@ use esp_backtrace as _; use esp_hal::{ gpio::{Io, Level, Output}, prelude::*, - rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, + rmt::{PulseCode, Rmt, RxChannelAsync, RxChannelConfig, RxChannelCreatorAsync}, timer::timg::TimerGroup, }; use esp_println::{print, println}; @@ -54,7 +54,7 @@ async fn main(spawner: Spawner) { } }; - let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap(); + let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async(); let rx_config = RxChannelConfig { clk_divider: 255, idle_threshold: 10000, diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 04ddc45d5cf..79413f3c8b6 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -17,7 +17,7 @@ use esp_backtrace as _; use esp_hal::{ gpio::Io, prelude::*, - rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, + rmt::{PulseCode, Rmt, TxChannelAsync, TxChannelConfig, TxChannelCreatorAsync}, timer::timg::TimerGroup, }; use esp_println::println; @@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) { } }; - let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap(); + let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async(); let mut channel = rmt .channel0 diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index e03136d7f70..70728701aad 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -97,7 +97,9 @@ async fn main(spawner: Spawner) { let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16); - let mut uart0 = Uart::new_async_with_config(peripherals.UART0, config, rx_pin, tx_pin).unwrap(); + let mut uart0 = Uart::new_with_config(peripherals.UART0, config, rx_pin, tx_pin) + .unwrap() + .into_async(); uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); let (rx, tx) = uart0.split(); diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 334cd713764..2ae0afe977a 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -63,8 +63,9 @@ async fn main(_spawner: Spawner) { .with_mosi(mosi) .with_miso(miso) .with_cs(cs) - .with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7]; loop { diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 40128f04abd..b6140cd7ce4 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -103,17 +103,18 @@ async fn main(spawner: Spawner) { // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; - // !!! Use `new_async` when using a transceiver. `new_async_no_transceiver` sets TX to open-drain + // !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain // Begin configuring the TWAI peripheral. The peripheral is in a reset like // state that prevents transmission but allows configuration. - let mut twai_config = twai::TwaiConfiguration::new_async_no_transceiver( + let mut twai_config = twai::TwaiConfiguration::new_no_transceiver( peripherals.TWAI0, rx_pin, tx_pin, TWAI_BAUDRATE, TwaiMode::Normal, - ); + ) + .into_async(); // Partially filter the incoming messages to reduce overhead of receiving // undesired messages. Note that due to how the hardware filters messages, diff --git a/examples/src/bin/embassy_usb_serial_jtag.rs b/examples/src/bin/embassy_usb_serial_jtag.rs index 8944ed2dc92..f1855834d8a 100644 --- a/examples/src/bin/embassy_usb_serial_jtag.rs +++ b/examples/src/bin/embassy_usb_serial_jtag.rs @@ -68,7 +68,9 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let (rx, tx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); + let (rx, tx) = UsbSerialJtag::new(peripherals.USB_DEVICE) + .into_async() + .split(); static SIGNAL: StaticCell>> = StaticCell::new(); diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 65499ab4a5b..9ff60bfddcc 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -81,11 +81,13 @@ mod test { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_dma(dma_channel1.configure_for_async(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0) - .with_dma(dma_channel2.configure_for_async(false, DmaPriority::Priority0)); + .with_dma(dma_channel2.configure(false, DmaPriority::Priority0)) + .into_async(); let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); @@ -144,9 +146,10 @@ mod test { .with_dma( peripherals .dma_channel - .configure_for_async(false, DmaPriority::Priority0), + .configure(false, DmaPriority::Priority0), ) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]); loop { diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index b6d785879ed..b3d3a733ad5 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -143,11 +143,11 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + ctx.dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); let (_, dout) = hil_test::common_test_pins!(ctx.io); diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 85d5c8493b5..2ac4b856b1f 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -19,13 +19,14 @@ use esp_hal::{ Pcnt, }, prelude::*, + Blocking, }; use hil_test as _; const DATA_SIZE: usize = 1024 * 10; struct Context<'d> { - lcd_cam: LcdCam<'d, esp_hal::Blocking>, + lcd_cam: LcdCam<'d, Blocking>, pcnt: Pcnt<'d>, io: Io, dma: Dma<'d>, @@ -79,7 +80,8 @@ mod tests { let channel = ctx .dma .channel0 - .configure_for_async(false, DmaPriority::Priority0); + .configure(false, DmaPriority::Priority0) + .into_async(); let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let i8080 = I8080::new( diff --git a/hil-test/tests/lcd_cam_i8080_async.rs b/hil-test/tests/lcd_cam_i8080_async.rs index c5c36d209d7..df44d002289 100644 --- a/hil-test/tests/lcd_cam_i8080_async.rs +++ b/hil-test/tests/lcd_cam_i8080_async.rs @@ -15,13 +15,14 @@ use esp_hal::{ LcdCam, }, prelude::*, + Async, }; use hil_test as _; const DATA_SIZE: usize = 1024 * 10; struct Context<'d> { - lcd_cam: LcdCam<'d, esp_hal::Async>, + lcd_cam: LcdCam<'d, Async>, dma: Dma<'d>, dma_buf: DmaTxBuf, } @@ -36,7 +37,7 @@ mod tests { let peripherals = esp_hal::init(esp_hal::Config::default()); let dma = Dma::new(peripherals.DMA); - let lcd_cam = LcdCam::new_async(peripherals.LCD_CAM); + let lcd_cam = LcdCam::new(peripherals.LCD_CAM).into_async(); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE); let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); @@ -75,7 +76,8 @@ mod tests { let channel = ctx .dma .channel0 - .configure_for_async(false, DmaPriority::Priority0); + .configure(false, DmaPriority::Priority0) + .into_async(); let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let i8080 = I8080::new( diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index cdb177a4828..2557672c4aa 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -92,7 +92,8 @@ mod tests { let pio = ParlIoTxOnly::new( ctx.parl_io, ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 10.MHz(), ) @@ -159,7 +160,8 @@ mod tests { let pio = ParlIoTxOnly::new( ctx.parl_io, ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 10.MHz(), ) diff --git a/hil-test/tests/rsa_async.rs b/hil-test/tests/rsa_async.rs index 105f424e207..671c853a8f4 100644 --- a/hil-test/tests/rsa_async.rs +++ b/hil-test/tests/rsa_async.rs @@ -56,7 +56,7 @@ mod tests { #[init] fn init() -> Context<'static> { let peripherals = esp_hal::init(esp_hal::Config::default()); - let mut rsa = Rsa::new_async(peripherals.RSA); + let mut rsa = Rsa::new(peripherals.RSA).into_async(); nb::block!(rsa.ready()).unwrap(); Context { rsa } diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 1af4146fff1..326501e2351 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -18,6 +18,7 @@ use esp_hal::{ peripheral::Peripheral, prelude::*, spi::{master::Spi, SpiMode}, + Blocking, }; #[cfg(pcnt)] use esp_hal::{ @@ -35,7 +36,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static>, + spi: Spi<'static, Blocking>, dma_channel: DmaChannelCreator, // Reuse the really large buffer so we don't run out of DRAM with many tests rx_buffer: &'static mut [u8], @@ -392,11 +393,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit @@ -428,11 +427,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit @@ -557,10 +554,10 @@ mod tests { let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap(); - let spi = ctx.spi.with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ); + let spi = ctx + .spi + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .into_async(); let mut transfer = spi .transfer(dma_rx_buf, dma_tx_buf) diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index f39791b6833..76aac781884 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -13,6 +13,7 @@ use esp_hal::{ dma_buffers, gpio::{interconnect::InputSignal, Io, Level, Output}, spi::{slave::Spi, SpiMode}, + Blocking, }; use hil_test as _; @@ -25,7 +26,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static>, + spi: Spi<'static, Blocking>, dma_channel: DmaChannelCreator, bitbang_spi: BitbangSpi, } diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs index 5ebc7f00675..5adcd854ac8 100644 --- a/hil-test/tests/uart_async.rs +++ b/hil-test/tests/uart_async.rs @@ -26,7 +26,7 @@ mod tests { let (rx, tx) = hil_test::common_test_pins!(io); - let uart = Uart::new_async(peripherals.UART0, rx, tx).unwrap(); + let uart = Uart::new(peripherals.UART0, rx, tx).unwrap().into_async(); Context { uart } } diff --git a/hil-test/tests/uart_tx_rx_async.rs b/hil-test/tests/uart_tx_rx_async.rs index d02f0a38768..4122d0963e9 100644 --- a/hil-test/tests/uart_tx_rx_async.rs +++ b/hil-test/tests/uart_tx_rx_async.rs @@ -31,8 +31,8 @@ mod tests { let (rx, tx) = hil_test::common_test_pins!(io); - let tx = UartTx::new_async(peripherals.UART0, tx).unwrap(); - let rx = UartRx::new_async(peripherals.UART1, rx).unwrap(); + let tx = UartTx::new(peripherals.UART0, tx).unwrap().into_async(); + let rx = UartRx::new(peripherals.UART1, rx).unwrap().into_async(); Context { rx, tx } } diff --git a/hil-test/tests/usb_serial_jtag.rs b/hil-test/tests/usb_serial_jtag.rs index c5e5bf44556..4f7cdb32813 100644 --- a/hil-test/tests/usb_serial_jtag.rs +++ b/hil-test/tests/usb_serial_jtag.rs @@ -18,6 +18,8 @@ mod tests { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - _ = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); + _ = UsbSerialJtag::new(peripherals.USB_DEVICE) + .into_async() + .split(); } } From 177db100fbc1a5132b6169cc7b25c1345ba55e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 11:51:12 +0100 Subject: [PATCH 22/67] Remove redundant lifetimes (#2459) --- esp-hal/src/dma/m2m.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index 2fce9e40c2a..b1ff0f60bc5 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -129,7 +129,7 @@ impl<'d> Mem2Mem<'d, Blocking> { } } -impl<'d, M> Mem2Mem<'d, M> +impl Mem2Mem<'_, M> where M: Mode, { From 0c867404183e105dc14c645644b936000c4abb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 12:29:28 +0100 Subject: [PATCH 23/67] Peripheral interconnect redo, vol 2 (`split()`) (#2418) * Replace peripheral connection conversions with split * Constrain Flex conversions --- esp-hal/CHANGELOG.md | 4 + esp-hal/MIGRATING-0.21.md | 21 +- esp-hal/src/gpio/interconnect.rs | 19 +- esp-hal/src/gpio/mod.rs | 281 ++++++++++++------ esp-hal/src/uart.rs | 8 +- examples/src/bin/embassy_twai.rs | 8 +- examples/src/bin/pcnt_encoder.rs | 12 +- examples/src/bin/twai.rs | 8 +- hil-test/tests/i2s.rs | 7 +- hil-test/tests/lcd_cam_i8080.rs | 32 +- hil-test/tests/parl_io_tx.rs | 17 +- hil-test/tests/parl_io_tx_async.rs | 17 +- hil-test/tests/qspi.rs | 25 +- hil-test/tests/spi_full_duplex.rs | 2 +- hil-test/tests/spi_half_duplex_write.rs | 2 +- hil-test/tests/spi_half_duplex_write_psram.rs | 2 +- hil-test/tests/spi_slave.rs | 89 +++--- hil-test/tests/twai.rs | 6 +- hil-test/tests/uart.rs | 9 +- 19 files changed, 353 insertions(+), 216 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index e01115be039..f4ada3c3101 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DmaDescriptor` is now `Send` (#2456) - `into_async` and `into_blocking` functions for most peripherals (#2430) - API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430) +- `gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split()` to obtain peripheral interconnect signals. (#2418) +- `gpio::Input::{split(), into_peripheral_output()}` when used with output pins. (#2418) +- `gpio::Output::peripheral_input()` (#2418) ### Changed @@ -42,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) - Allow users to create DMA `Preparation`s (#2455) - The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) +- Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 70bc8386e0b..46708dfa205 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -194,7 +194,8 @@ You can now listen/unlisten multiple interrupt bits at once: -uart0.listen_at_cmd(); -uart0.listen_rx_fifo_full(); +uart0.listen(UartInterrupt::AtCmd | UartConterrupt::RxFifoFull); -```Ë› +``` + ## Circular DMA transfer's `available` returns `Result` now In case of any error you should drop the transfer and restart it. @@ -211,3 +212,21 @@ In case of any error you should drop the transfer and restart it. + }, + }; ``` + +## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types + +Creating peripheral interconnect signals now consume the GPIO pin used for the connection. + +The previous signal function have been replaced by `split`. This change affects the following APIs: + +- `GpioPin` +- `AnyPin` + +```diff +-let input_signal = gpioN.peripheral_input(); +-let output_signal = gpioN.into_peripheral_output(); ++let (input_signal, output_signal) = gpioN.split(); +``` + +`into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to +the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead. diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index 126b66394a5..4f95a927cc1 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -54,9 +54,6 @@ impl PeripheralOutput for OutputConnection {} /// A configurable input signal between a peripheral and a GPIO pin. /// -/// Obtained by calling [`super::GpioPin::peripheral_input()`], -/// [`super::Flex::peripheral_input()`] or [`super::Input::peripheral_input()`]. -/// /// Multiple input signals can be connected to one pin. pub struct InputSignal { pin: AnyPin, @@ -188,10 +185,6 @@ impl InputSignal { /// A configurable output signal between a peripheral and a GPIO pin. /// -/// Obtained by calling [`super::GpioPin::into_peripheral_output()`], -/// [`super::Flex::into_peripheral_output()`] or -/// [`super::Output::into_peripheral_output()`]. -/// /// Multiple pins can be connected to one output signal. pub struct OutputSignal { pin: AnyPin, @@ -441,9 +434,9 @@ where P: InputPin, { fn from(input: P) -> Self { - Self(InputConnectionInner::Input( - input.degrade().peripheral_input(), - )) + Self(InputConnectionInner::Input(InputSignal::new( + input.degrade(), + ))) } } @@ -534,9 +527,9 @@ where P: OutputPin, { fn from(input: P) -> Self { - Self(OutputConnectionInner::Output( - input.degrade().into_peripheral_output(), - )) + Self(OutputConnectionInner::Output(OutputSignal::new( + input.degrade(), + ))) } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 02eff2d7d57..a7311729351 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -723,13 +723,15 @@ where Self } - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input pin. - #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - interconnect::InputSignal::new(self.degrade_pin(private::Internal)) + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + ( + interconnect::InputSignal::new(self.degrade_pin(private::Internal)), + interconnect::OutputSignal::new(self.degrade_pin(private::Internal)), + ) } } @@ -777,21 +779,6 @@ where impl private::Sealed for GpioPin {} -impl GpioPin -where - Self: OutputPin, -{ - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - interconnect::OutputSignal::new(self.degrade_pin(private::Internal)) - } -} - /// General Purpose Input/Output driver pub struct Io { _io_mux: IO_MUX, @@ -1151,18 +1138,39 @@ where /// Create GPIO output driver for a [GpioPin] with the provided level #[inline] pub fn new_typed(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { - let pin = Flex::new_typed(pin); + let mut pin = Flex::new_typed(pin); + + pin.set_level(initial_output); + pin.set_as_output(); - Self::new_inner(pin, initial_output) + Self { pin } } - fn new_inner(mut pin: Flex<'d, P>, initial_output: Level) -> Self { - pin.pin - .set_output_high(initial_output.into(), private::Internal); + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } - pin.set_as_output(); + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } - Self { pin } + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. + #[inline] + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() } /// Set the output as high. @@ -1212,16 +1220,6 @@ where pub fn set_drive_strength(&mut self, strength: DriveStrength) { self.pin.set_drive_strength(strength); } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - self.pin.into_peripheral_output() - } } /// GPIO input driver. @@ -1262,6 +1260,15 @@ where Self { pin } } + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -1311,14 +1318,28 @@ where pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) { self.pin.wakeup_enable(enable, event); } +} - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. +impl

Input<'_, P> +where + P: InputPin + OutputPin, +{ + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input pin. + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } + + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - self.pin.peripheral_input() + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() } } @@ -1365,6 +1386,33 @@ where Self { pin } } + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } + + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } + + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. + #[inline] + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -1441,16 +1489,6 @@ where pub fn set_drive_strength(&mut self, strength: DriveStrength) { self.pin.set_drive_strength(strength); } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - self.pin.into_peripheral_output() - } } /// Flexible pin driver. @@ -1487,6 +1525,15 @@ where crate::into_ref!(pin); Self { pin } } + + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.degrade_pin(private::Internal).split().0 + } } impl

Flex<'_, P> @@ -1577,15 +1624,6 @@ where pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) { self.listen_with_options(event.into(), false, false, enable); } - - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. - /// - /// The input signal can be passed to peripherals in place of an input pin. - #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - interconnect::InputSignal::new(self.pin.degrade_pin(private::Internal)) - } } impl

Flex<'_, P> @@ -1646,6 +1684,20 @@ where self.pin.set_drive_strength(strength, private::Internal); } + /// Set the GPIO to open-drain mode. + pub fn set_as_open_drain(&mut self, pull: Pull) { + self.pin.set_to_open_drain_output(private::Internal); + self.pin.pull_direction(pull, private::Internal); + } + + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.degrade_pin(private::Internal).split() + } + /// Turns the pin object into a peripheral /// [output][interconnect::OutputSignal]. /// @@ -1653,18 +1705,7 @@ where /// pin. #[inline] pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - interconnect::OutputSignal::new(self.pin.degrade_pin(private::Internal)) - } -} - -impl

Flex<'_, P> -where - P: InputPin + OutputPin, -{ - /// Set the GPIO to open-drain mode. - pub fn set_as_open_drain(&mut self, pull: Pull) { - self.pin.set_to_open_drain_output(private::Internal); - self.pin.pull_direction(pull, private::Internal); + self.split().1 } } @@ -1674,24 +1715,13 @@ pub(crate) mod internal { impl private::Sealed for AnyPin {} impl AnyPin { - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input - /// pin. + /// Peripheral signals allow connecting peripherals together without + /// using external hardware. #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - handle_gpio_input!(&self.0, target, { target.peripheral_input() }) - } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - handle_gpio_output!(self.0, target, { target.into_peripheral_output() }) + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + handle_gpio_input!(self.0, target, { target.split() }) } } @@ -1717,7 +1747,7 @@ pub(crate) mod internal { } fn output_signals(&self, _: private::Internal) -> &[(AlternateFunction, OutputSignal)] { - handle_gpio_input!(&self.0, target, { + handle_gpio_output!(&self.0, target, { Pin::output_signals(target, private::Internal) }) } @@ -1736,7 +1766,74 @@ pub(crate) mod internal { } impl InputPin for AnyPin {} - impl OutputPin for AnyPin {} + + // Need to forward these one by one because not all pins support all functions. + impl OutputPin for AnyPin { + fn init_output( + &mut self, + alternate: AlternateFunction, + open_drain: bool, + _: private::Internal, + ) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::init_output(target, alternate, open_drain, private::Internal) + }) + } + + fn set_to_open_drain_output(&mut self, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_to_open_drain_output(target, private::Internal) + }) + } + + fn set_to_push_pull_output(&mut self, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_to_push_pull_output(target, private::Internal) + }) + } + + fn set_output_high(&mut self, high: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_output_high(target, high, private::Internal) + }) + } + + fn set_drive_strength(&mut self, strength: DriveStrength, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_drive_strength(target, strength, private::Internal) + }) + } + + fn enable_open_drain(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::enable_open_drain(target, on, private::Internal) + }) + } + + fn enable_output_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::enable_output_in_sleep_mode(target, on, private::Internal) + }) + } + + fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::internal_pull_up_in_sleep_mode(target, on, private::Internal) + }) + } + + fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::internal_pull_down_in_sleep_mode(target, on, private::Internal) + }) + } + + fn is_set_high(&self, _: private::Internal) -> bool { + handle_gpio_output!(&self.0, target, { + OutputPin::is_set_high(target, private::Internal) + }) + } + } #[cfg(any(xtensa, esp32c2, esp32c3, esp32c6))] impl RtcPin for AnyPin { diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 6a371e95b59..a67c4b0e6a1 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -98,12 +98,12 @@ //! //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! -//! let rx = io.pins.gpio2.peripheral_input().inverted(); -//! let tx = io.pins.gpio1.into_peripheral_output().inverted(); +//! let (rx, _) = io.pins.gpio2.split(); +//! let (_, tx) = io.pins.gpio1.split(); //! let mut uart1 = Uart::new( //! peripherals.UART1, -//! rx, -//! tx, +//! rx.inverted(), +//! tx.inverted(), //! ).unwrap(); //! # } //! ``` diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index b6140cd7ce4..36b94aa42b4 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -94,11 +94,11 @@ async fn main(spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver. - // Without an external transceiver, we only need a single line between the two MCUs. - let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver. + let (rx_pin, tx_pin) = io.pins.gpio2.split(); + // Use these if you want to use an external transceiver: + // let tx_pin = io.pins.gpio2; + // let rx_pin = io.pins.gpio0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/examples/src/bin/pcnt_encoder.rs b/examples/src/bin/pcnt_encoder.rs index 8f2344dc098..bf1b1394144 100644 --- a/examples/src/bin/pcnt_encoder.rs +++ b/examples/src/bin/pcnt_encoder.rs @@ -49,18 +49,22 @@ fn main() -> ! { println!("setup channel 0"); let ch0 = &u0.channel0; + let pin_a = Input::new(io.pins.gpio4, Pull::Up); let pin_b = Input::new(io.pins.gpio5, Pull::Up); - ch0.set_ctrl_signal(pin_a.peripheral_input()); - ch0.set_edge_signal(pin_b.peripheral_input()); + let (input_a, _) = pin_a.split(); + let (input_b, _) = pin_b.split(); + + ch0.set_ctrl_signal(input_a.clone()); + ch0.set_edge_signal(input_b.clone()); ch0.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep); ch0.set_input_mode(channel::EdgeMode::Increment, channel::EdgeMode::Decrement); println!("setup channel 1"); let ch1 = &u0.channel1; - ch1.set_ctrl_signal(pin_b.peripheral_input()); - ch1.set_edge_signal(pin_a.peripheral_input()); + ch1.set_ctrl_signal(input_b); + ch1.set_edge_signal(input_a); ch1.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep); ch1.set_input_mode(channel::EdgeMode::Decrement, channel::EdgeMode::Increment); diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index 672ab25c50c..fa0bcf9ee8e 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -42,11 +42,11 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver. - // Without an external transceiver, we only need a single line between the two MCUs. - let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver. + let (rx_pin, tx_pin) = io.pins.gpio2.split(); + // Use these if you want to use an external transceiver: + // let tx_pin = io.pins.gpio2; + // let rx_pin = io.pins.gpio0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index b3d3a733ad5..0156c26b88d 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -151,7 +151,7 @@ mod tests { let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + let (din, dout) = dout.split(); let i2s_tx = i2s .i2s_tx @@ -205,7 +205,7 @@ mod tests { let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + let (din, dout) = dout.split(); let mut i2s_tx = i2s .i2s_tx @@ -347,7 +347,8 @@ mod tests { ); let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + + let (din, dout) = dout.split(); let mut i2s_rx = i2s .i2s_rx diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 2ac4b856b1f..1d4555bfa52 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -102,20 +102,14 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let cs_signal = ctx.io.pins.gpio8; - let unit0_signal = ctx.io.pins.gpio11; - let unit1_signal = ctx.io.pins.gpio12; - let unit2_signal = ctx.io.pins.gpio16; - let unit3_signal = ctx.io.pins.gpio17; + let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); + let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); + let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); + let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); + let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); let pcnt = ctx.pcnt; - let unit_ctrl = cs_signal.peripheral_input(); - let unit0_input = unit0_signal.peripheral_input(); - let unit1_input = unit1_signal.peripheral_input(); - let unit2_input = unit2_signal.peripheral_input(); - let unit3_input = unit3_signal.peripheral_input(); - pcnt.unit0 .channel0 .set_ctrl_mode(CtrlMode::Keep, CtrlMode::Disable); @@ -219,20 +213,14 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let cs_signal = ctx.io.pins.gpio8; - let unit0_signal = ctx.io.pins.gpio11; - let unit1_signal = ctx.io.pins.gpio12; - let unit2_signal = ctx.io.pins.gpio16; - let unit3_signal = ctx.io.pins.gpio17; + let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); + let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); + let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); + let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); + let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); let pcnt = ctx.pcnt; - let unit_ctrl = cs_signal.peripheral_input(); - let unit0_input = unit0_signal.peripheral_input(); - let unit1_input = unit1_signal.peripheral_input(); - let unit2_input = unit2_signal.peripheral_input(); - let unit3_input = unit3_signal.peripheral_input(); - pcnt.unit0 .channel0 .set_ctrl_mode(CtrlMode::Keep, CtrlMode::Disable); diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index 3bec7b56c86..f2b2cceb559 100644 --- a/hil-test/tests/parl_io_tx.rs +++ b/hil-test/tests/parl_io_tx.rs @@ -8,7 +8,11 @@ use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, - gpio::{interconnect::InputSignal, AnyPin, Io, NoPin}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + NoPin, + }, parl_io::{ BitPackOrder, ClkOutPin, @@ -30,8 +34,8 @@ use hil_test as _; struct Context { parl_io: PARL_IO, dma_channel: ChannelCreator<0>, - clock: AnyPin, - valid: AnyPin, + clock: OutputSignal, + valid: OutputSignal, clock_loopback: InputSignal, valid_loopback: InputSignal, pcnt_unit: Unit<'static, 0>, @@ -50,10 +54,9 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (clock, _) = hil_test::common_test_pins!(io); - let valid = io.pins.gpio0.degrade(); - let clock_loopback = clock.peripheral_input(); - let valid_loopback = valid.peripheral_input(); - let clock = clock.degrade(); + let valid = hil_test::unconnected_pin!(io); + let (clock_loopback, clock) = clock.split(); + let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); let pcnt_unit = pcnt.unit0; let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index 2557672c4aa..2c4522f02cf 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -10,7 +10,11 @@ use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, - gpio::{interconnect::InputSignal, AnyPin, Io, NoPin}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + NoPin, + }, parl_io::{ BitPackOrder, ClkOutPin, @@ -32,8 +36,8 @@ use hil_test as _; struct Context { parl_io: PARL_IO, dma_channel: ChannelCreator<0>, - clock: AnyPin, - valid: AnyPin, + clock: OutputSignal, + valid: OutputSignal, clock_loopback: InputSignal, valid_loopback: InputSignal, pcnt_unit: Unit<'static, 0>, @@ -52,10 +56,9 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (clock, _) = hil_test::common_test_pins!(io); - let valid = io.pins.gpio0.degrade(); - let clock_loopback = clock.peripheral_input(); - let valid_loopback = valid.peripheral_input(); - let clock = clock.degrade(); + let valid = hil_test::unconnected_pin!(io); + let (clock_loopback, clock) = clock.split(); + let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); let pcnt_unit = pcnt.unit0; let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 641098f1a62..9322a7b052d 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -335,7 +335,9 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -359,12 +361,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -389,12 +394,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -419,12 +427,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 326501e2351..2d465a25b86 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -73,7 +73,7 @@ mod tests { } #[cfg(pcnt)] - let mosi_loopback_pcnt = mosi.peripheral_input(); + let (mosi_loopback_pcnt, mosi) = mosi.split(); // Need to set miso first so that mosi can overwrite the // output connection (because we are using the same pin to loop back) let spi = Spi::new(peripherals.SPI2, 10000.kHz(), SpiMode::Mode0) diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index a44dda26070..f06a80f3eaf 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -50,7 +50,7 @@ mod tests { } } - let mosi_loopback = mosi.peripheral_input(); + let (mosi_loopback, mosi) = mosi.split(); let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index eea6b6254a6..f40f81dc2db 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -62,7 +62,7 @@ mod tests { let dma_channel = dma.channel0; - let mosi_loopback = mosi.peripheral_input(); + let (mosi_loopback, mosi) = mosi.split(); let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 76aac781884..4d60f3b79cb 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -11,7 +11,10 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::{interconnect::InputSignal, Io, Level, Output}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + }, spi::{slave::Spi, SpiMode}, Blocking, }; @@ -32,19 +35,32 @@ struct Context { } struct BitbangSpi { - sclk: Output<'static>, - mosi: Output<'static>, + sclk: OutputSignal, + mosi: OutputSignal, miso: InputSignal, - cs: Output<'static>, + cs: OutputSignal, } impl BitbangSpi { fn new( - sclk: Output<'static>, - mosi: Output<'static>, - miso: InputSignal, - cs: Output<'static>, + mut sclk: OutputSignal, + mut mosi: OutputSignal, + mut miso: InputSignal, + mut cs: OutputSignal, ) -> Self { + // TODO remove this (#2273) + // FIXME: devise a public API for signals + miso.enable_input(true, unsafe { esp_hal::Internal::conjure() }); + + mosi.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + mosi.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + + cs.set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + cs.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + + sclk.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + sclk.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + Self { sclk, mosi, @@ -54,22 +70,29 @@ impl BitbangSpi { } fn assert_cs(&mut self) { - self.sclk.set_level(Level::Low); - self.cs.set_level(Level::Low); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.cs + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); } fn deassert_cs(&mut self) { - self.sclk.set_level(Level::Low); - self.cs.set_level(Level::High); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.cs + .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); } // Mode 1, so sampled on the rising edge and set on the falling edge. fn shift_bit(&mut self, bit: bool) -> bool { - self.mosi.set_level(Level::from(bit)); - self.sclk.set_level(Level::High); + self.mosi + .set_output_high(bit, unsafe { esp_hal::Internal::conjure() }); + self.sclk + .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); let miso = self.miso.get_level().into(); - self.sclk.set_level(Level::Low); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); miso } @@ -105,7 +128,7 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (mosi_pin, miso_pin) = hil_test::i2c_pins!(io); - let (sclk_pin, sclk_gpio) = hil_test::common_test_pins!(io); + let (sclk_pin, _) = hil_test::common_test_pins!(io); let cs_pin = hil_test::unconnected_pin!(io); let dma = Dma::new(peripherals.DMA); @@ -118,30 +141,22 @@ mod tests { } } - let cs = cs_pin.peripheral_input(); - let mosi = mosi_pin.peripheral_input(); - let mut miso = miso_pin.peripheral_input(); - let sclk_signal = sclk_pin.peripheral_input(); - - let mosi_gpio = Output::new(mosi_pin, Level::Low); - let cs_gpio = Output::new(cs_pin, Level::High); - let sclk_gpio = Output::new(sclk_gpio, Level::Low); - - let spi = Spi::new( - peripherals.SPI2, - sclk_signal, - mosi, - miso_pin, - cs, - SpiMode::Mode1, - ); - - miso.enable_input(true, unsafe { esp_hal::Internal::conjure() }); + let (cs, cs_pin) = cs_pin.split(); + let (mosi, mosi_pin) = mosi_pin.split(); + let (miso, miso_pin) = miso_pin.split(); + let (sclk_signal, sclk_pin) = sclk_pin.split(); Context { - spi, + spi: Spi::new( + peripherals.SPI2, + sclk_signal, + mosi, + miso_pin, + cs, + SpiMode::Mode1, + ), + bitbang_spi: BitbangSpi::new(sclk_pin, mosi_pin, miso, cs_pin), dma_channel, - bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso, cs_gpio), } } diff --git a/hil-test/tests/twai.rs b/hil-test/tests/twai.rs index da41f1dc258..a1be5524ef9 100644 --- a/hil-test/tests/twai.rs +++ b/hil-test/tests/twai.rs @@ -32,10 +32,12 @@ mod tests { let (loopback_pin, _) = hil_test::common_test_pins!(io); + let (rx, tx) = loopback_pin.split(); + let mut config = twai::TwaiConfiguration::new( peripherals.TWAI0, - loopback_pin.peripheral_input(), - loopback_pin, + rx, + tx, twai::BaudRate::B1000K, TwaiMode::SelfTest, ); diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index f653873cfd1..5b1a74cb888 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -32,12 +32,9 @@ mod tests { let (_, pin) = hil_test::common_test_pins!(io); - let uart = Uart::new( - peripherals.UART1, - pin.peripheral_input(), - pin.into_peripheral_output(), - ) - .unwrap(); + let (rx, tx) = pin.split(); + + let uart = Uart::new(peripherals.UART1, rx, tx).unwrap(); Context { uart } } From 1e6820d1a7405c738c402aef639f9e49072ff246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 12:36:34 +0100 Subject: [PATCH 24/67] Systimer improvements (#2451) * Do not read to set update bit * Deduplicate * Try to bind interrupts to the correct core * Inline poll_count into read_count * Clean up * Make sure only a single update is done at a time * Changelog * Fix docs * Correct the channel count * Assign enough timers for HIL test * Use a lock to prevent re-update * Remove locking, use esp-idf implementation * Document timer count requirement --- esp-hal-embassy/CHANGELOG.md | 2 + esp-hal-embassy/src/lib.rs | 3 + esp-hal-embassy/src/time_driver.rs | 96 ++++++++------ esp-hal/CHANGELOG.md | 1 + esp-hal/src/timer/systimer.rs | 129 +++++++------------ hil-test/tests/embassy_interrupt_executor.rs | 29 ++++- hil-test/tests/embassy_interrupt_spi_dma.rs | 43 ++++++- 7 files changed, 169 insertions(+), 134 deletions(-) diff --git a/esp-hal-embassy/CHANGELOG.md b/esp-hal-embassy/CHANGELOG.md index 95d69b3ddc4..3449b640ed2 100644 --- a/esp-hal-embassy/CHANGELOG.md +++ b/esp-hal-embassy/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Alarm interrupts are now handled on the core that allocated them. (For executors created on the second core after calling `esp_hal_embassy::init`) (#2451) + ### Removed ## 0.4.0 - 2024-10-10 diff --git a/esp-hal-embassy/src/lib.rs b/esp-hal-embassy/src/lib.rs index 9b8a8980a0c..795f4cf13b3 100644 --- a/esp-hal-embassy/src/lib.rs +++ b/esp-hal-embassy/src/lib.rs @@ -149,6 +149,9 @@ impl_array!(4); /// - A mutable static array of `OneShotTimer` instances /// - A 2, 3, 4 element array of `AnyTimer` instances /// +/// Note that if you use the `integrated-timers` feature, +/// you need to pass as many timers as you start executors. +/// /// # Examples /// /// ```rust, no_run diff --git a/esp-hal-embassy/src/time_driver.rs b/esp-hal-embassy/src/time_driver.rs index 99708077812..6b73f800104 100644 --- a/esp-hal-embassy/src/time_driver.rs +++ b/esp-hal-embassy/src/time_driver.rs @@ -49,48 +49,20 @@ impl EmbassyTimer { ); } - static HANDLERS: [InterruptHandler; MAX_SUPPORTED_ALARM_COUNT] = [ - handler0, handler1, handler2, handler3, handler4, handler5, handler6, - ]; - critical_section::with(|cs| { timers.iter_mut().enumerate().for_each(|(n, timer)| { timer.enable_interrupt(false); timer.stop(); - timer.set_interrupt_handler(HANDLERS[n]); + + if DRIVER.alarms.borrow(cs)[n].allocated.get() { + // FIXME: we should track which core allocated an alarm and bind the interrupt + // to that core. + timer.set_interrupt_handler(HANDLERS[n]); + } }); TIMERS.replace(cs, Some(timers)); }); - - #[handler(priority = Priority::max())] - fn handler0() { - DRIVER.on_interrupt(0); - } - #[handler(priority = Priority::max())] - fn handler1() { - DRIVER.on_interrupt(1); - } - #[handler(priority = Priority::max())] - fn handler2() { - DRIVER.on_interrupt(2); - } - #[handler(priority = Priority::max())] - fn handler3() { - DRIVER.on_interrupt(3); - } - #[handler(priority = Priority::max())] - fn handler4() { - DRIVER.on_interrupt(4); - } - #[handler(priority = Priority::max())] - fn handler5() { - DRIVER.on_interrupt(5); - } - #[handler(priority = Priority::max())] - fn handler6() { - DRIVER.on_interrupt(6); - } } fn on_interrupt(&self, id: usize) { @@ -128,11 +100,26 @@ impl Driver for EmbassyTimer { unsafe fn allocate_alarm(&self) -> Option { critical_section::with(|cs| { for (i, alarm) in self.alarms.borrow(cs).iter().enumerate() { - if !alarm.allocated.get() { - // set alarm so it is not overwritten - alarm.allocated.set(true); - return Some(AlarmHandle::new(i as u8)); + if alarm.allocated.get() { + continue; } + let mut timer = TIMERS.borrow_ref_mut(cs); + // `allocate_alarm` may be called before `esp_hal_embassy::init()`, so + // we need to check if we have timers. + if let Some(timer) = &mut *timer { + // If we do, bind the interrupt handler to the timer. + // This ensures that alarms allocated after init are correctly bound to the + // core that created the executor. + let timer = unwrap!( + timer.get_mut(i), + "There are not enough timers to allocate a new alarm. Call `esp_hal_embassy::init()` with the correct number of timers." + ); + timer.set_interrupt_handler(HANDLERS[i]); + } + + // set alarm so it is not overwritten + alarm.allocated.set(true); + return Some(AlarmHandle::new(i as u8)); } None }) @@ -172,3 +159,36 @@ impl Driver for EmbassyTimer { true } } + +static HANDLERS: [InterruptHandler; MAX_SUPPORTED_ALARM_COUNT] = [ + handler0, handler1, handler2, handler3, handler4, handler5, handler6, +]; + +#[handler(priority = Priority::max())] +fn handler0() { + DRIVER.on_interrupt(0); +} +#[handler(priority = Priority::max())] +fn handler1() { + DRIVER.on_interrupt(1); +} +#[handler(priority = Priority::max())] +fn handler2() { + DRIVER.on_interrupt(2); +} +#[handler(priority = Priority::max())] +fn handler3() { + DRIVER.on_interrupt(3); +} +#[handler(priority = Priority::max())] +fn handler4() { + DRIVER.on_interrupt(4); +} +#[handler(priority = Priority::max())] +fn handler5() { + DRIVER.on_interrupt(5); +} +#[handler(priority = Priority::max())] +fn handler6() { + DRIVER.on_interrupt(6); +} diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f4ada3c3101..f742791b5d3 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue where interrupts enabled before `esp_hal::init` were disabled. This issue caused the executor created by `#[esp_hal_embassy::main]` to behave incorrectly in multi-core applications. (#2377) - Fixed `TWAI::transmit_async`: bus-off state is not reached when CANH and CANL are shorted. (#2421) - ESP32: added UART-specific workaround for https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html (#2441) +- Fixed some SysTimer race conditions and panics (#2451) ### Removed diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 2a666c652e3..fb3fdcb19d0 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -170,13 +170,7 @@ impl<'d> SystemTimer<'d> { // an older time stamp let unit = unsafe { SpecificUnit::<'_, 0>::conjure() }; - - unit.update(); - loop { - if let Some(value) = unit.poll_count() { - break value; - } - } + unit.read_count() } } @@ -248,37 +242,29 @@ pub trait Unit { _ => unreachable!(), }, UnitConfig::DisabledIfCpuIsStalled(cpu) => match self.channel() { - 0 => w - .timer_unit0_work_en() - .set_bit() - .timer_unit0_core0_stall_en() - .bit(cpu == Cpu::ProCpu) - .timer_unit0_core1_stall_en() - .bit(cpu != Cpu::ProCpu), - 1 => w - .timer_unit1_work_en() - .set_bit() - .timer_unit1_core0_stall_en() - .bit(cpu == Cpu::ProCpu) - .timer_unit1_core1_stall_en() - .bit(cpu != Cpu::ProCpu), + 0 => { + w.timer_unit0_work_en().set_bit(); + w.timer_unit0_core0_stall_en().bit(cpu == Cpu::ProCpu); + w.timer_unit0_core1_stall_en().bit(cpu != Cpu::ProCpu) + } + 1 => { + w.timer_unit1_work_en().set_bit(); + w.timer_unit1_core0_stall_en().bit(cpu == Cpu::ProCpu); + w.timer_unit1_core1_stall_en().bit(cpu != Cpu::ProCpu) + } _ => unreachable!(), }, UnitConfig::Enabled => match self.channel() { - 0 => w - .timer_unit0_work_en() - .set_bit() - .timer_unit0_core0_stall_en() - .clear_bit() - .timer_unit0_core1_stall_en() - .clear_bit(), - 1 => w - .timer_unit1_work_en() - .set_bit() - .timer_unit1_core0_stall_en() - .clear_bit() - .timer_unit1_core1_stall_en() - .clear_bit(), + 0 => { + w.timer_unit0_work_en().set_bit(); + w.timer_unit0_core0_stall_en().clear_bit(); + w.timer_unit0_core1_stall_en().clear_bit() + } + 1 => { + w.timer_unit1_work_en().set_bit(); + w.timer_unit1_core0_stall_en().clear_bit(); + w.timer_unit1_core1_stall_en().clear_bit() + } _ => unreachable!(), }, }); @@ -317,48 +303,30 @@ pub trait Unit { } } - /// Update the value returned by [Self::poll_count] to be the current value - /// of the counter. - /// - /// This can be used to read the current value of the timer. - fn update(&self) { - let systimer = unsafe { &*SYSTIMER::ptr() }; - systimer - .unit_op(self.channel() as _) - .modify(|_, w| w.update().set_bit()); - } - - /// Return the count value at the time of the last call to [Self::update]. - /// - /// Returns None if the update isn't ready to read if update has never been - /// called. - fn poll_count(&self) -> Option { - let systimer = unsafe { &*SYSTIMER::ptr() }; - if systimer - .unit_op(self.channel() as _) - .read() - .value_valid() - .bit_is_set() - { - let unit_value = systimer.unit_value(self.channel() as _); - - let lo = unit_value.lo().read().bits(); - let hi = unit_value.hi().read().bits(); - - Some(((hi as u64) << 32) | lo as u64) - } else { - None - } - } - - /// Convenience method to call [Self::update] and [Self::poll_count]. + /// Reads the current counter value. fn read_count(&self) -> u64 { // This can be a shared reference as long as this type isn't Sync. - self.update(); + let channel = self.channel() as usize; + let systimer = unsafe { SYSTIMER::steal() }; + + systimer.unit_op(channel).write(|w| w.update().set_bit()); + while !systimer.unit_op(channel).read().value_valid().bit_is_set() {} + + // Read LO, HI, then LO again, check that LO returns the same value. + // This accounts for the case when an interrupt may happen between reading + // HI and LO values (or the other core updates the counter mid-read), and this + // function may get called from the ISR. In this case, the repeated read + // will return consistent values. + let unit_value = systimer.unit_value(channel); + let mut lo_prev = unit_value.lo().read().bits(); loop { - if let Some(count) = self.poll_count() { - break count; + let lo = lo_prev; + let hi = unit_value.hi().read().bits(); + lo_prev = unit_value.lo().read().bits(); + + if lo == lo_prev { + return ((hi as u64) << 32) | lo as u64; } } } @@ -895,13 +863,7 @@ where // This should be safe to access from multiple contexts; worst case // scenario the second accessor ends up reading an older time stamp. - self.unit.update(); - - let ticks = loop { - if let Some(value) = self.unit.poll_count() { - break value; - } - }; + let ticks = self.unit.read_count(); let us = ticks / (SystemTimer::ticks_per_second() / 1_000_000); @@ -933,11 +895,6 @@ where } else { // Target mode - self.unit.update(); - while self.unit.poll_count().is_none() { - // Wait for value registers to update - } - // The counters/comparators are 52-bits wide (except on ESP32-S2, // which is 64-bits), so we must ensure that the provided value // is not too wide: @@ -946,7 +903,7 @@ where return Err(Error::InvalidTimeout); } - let v = self.unit.poll_count().unwrap(); + let v = self.unit.read_count(); let t = v + ticks; self.comparator.set_target(t); diff --git a/hil-test/tests/embassy_interrupt_executor.rs b/hil-test/tests/embassy_interrupt_executor.rs index 4aad1a38650..c21fed86dc4 100644 --- a/hil-test/tests/embassy_interrupt_executor.rs +++ b/hil-test/tests/embassy_interrupt_executor.rs @@ -16,7 +16,7 @@ use esp_hal::{ software::{SoftwareInterrupt, SoftwareInterruptControl}, Priority, }, - timer::timg::TimerGroup, + timer::AnyTimer, }; use esp_hal_embassy::InterruptExecutor; use hil_test as _; @@ -56,8 +56,31 @@ mod test { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let timg0 = TimerGroup::new(peripherals.TIMG0); - esp_hal_embassy::init(timg0.timer0); + cfg_if::cfg_if! { + if #[cfg(timg_timer1)] { + use esp_hal::timer::timg::TimerGroup; + let timg0 = TimerGroup::new(peripherals.TIMG0); + esp_hal_embassy::init([ + AnyTimer::from(timg0.timer0), + AnyTimer::from(timg0.timer1), + ]); + } else if #[cfg(timg1)] { + use esp_hal::timer::timg::TimerGroup; + let timg0 = TimerGroup::new(peripherals.TIMG0); + let timg1 = TimerGroup::new(peripherals.TIMG1); + esp_hal_embassy::init([ + AnyTimer::from(timg0.timer0), + AnyTimer::from(timg1.timer0), + ]); + } else if #[cfg(systimer)] { + use esp_hal::timer::systimer::{SystemTimer, Target}; + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); + esp_hal_embassy::init([ + AnyTimer::from(systimer.alarm0), + AnyTimer::from(systimer.alarm1), + ]); + } + } let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); Context { diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 9ff60bfddcc..fc6580a12f8 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -17,7 +17,7 @@ use esp_hal::{ master::{Spi, SpiDma}, SpiMode, }, - timer::{timg::TimerGroup, AnyTimer}, + timer::AnyTimer, Async, }; use esp_hal_embassy::InterruptExecutor; @@ -60,12 +60,26 @@ mod test { #[timeout(3)] async fn dma_does_not_lock_up_when_used_in_different_executors() { let peripherals = esp_hal::init(esp_hal::Config::default()); - - let timg0 = TimerGroup::new(peripherals.TIMG0); - esp_hal_embassy::init([AnyTimer::from(timg0.timer0), AnyTimer::from(timg0.timer1)]); - let dma = Dma::new(peripherals.DMA); + cfg_if::cfg_if! { + if #[cfg(systimer)] { + use esp_hal::timer::systimer::{SystemTimer, Target}; + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); + esp_hal_embassy::init([ + AnyTimer::from(systimer.alarm0), + AnyTimer::from(systimer.alarm1), + ]); + } else { + use esp_hal::timer::timg::TimerGroup; + let timg0 = TimerGroup::new(peripherals.TIMG0); + esp_hal_embassy::init([ + AnyTimer::from(timg0.timer0), + AnyTimer::from(timg0.timer1), + ]); + } + } + cfg_if::cfg_if! { if #[cfg(pdma)] { let dma_channel1 = dma.spi2channel; @@ -164,8 +178,23 @@ mod test { let peripherals = esp_hal::init(esp_hal::Config::default()); let dma = Dma::new(peripherals.DMA); - let timg0 = TimerGroup::new(peripherals.TIMG0); - esp_hal_embassy::init(timg0.timer0); + cfg_if::cfg_if! { + if #[cfg(systimer)] { + use esp_hal::timer::systimer::{SystemTimer, Target}; + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); + esp_hal_embassy::init([ + AnyTimer::from(systimer.alarm0), + AnyTimer::from(systimer.alarm1), + ]); + } else { + use esp_hal::timer::timg::TimerGroup; + let timg0 = TimerGroup::new(peripherals.TIMG0); + esp_hal_embassy::init([ + AnyTimer::from(timg0.timer0), + AnyTimer::from(timg0.timer1), + ]); + } + } cfg_if::cfg_if! { if #[cfg(pdma)] { From ca9ee23b5e8ea059078af49a8365f328589aa3ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Mon, 4 Nov 2024 16:55:23 +0100 Subject: [PATCH 25/67] Prefer ROM-fns over custom impl (#2462) * Prefer ROM-fns over custom impl * PR number --- esp-hal/ld/esp32/rom/additional.ld | 9 ++ esp-hal/ld/esp32c2/rom/additional.ld | 9 ++ esp-hal/ld/esp32c3/rom/additional.ld | 9 ++ esp-hal/ld/esp32c6/rom/additional.ld | 9 ++ esp-hal/ld/esp32h2/rom/additional.ld | 9 ++ esp-hal/ld/esp32s2/rom/additional.ld | 8 ++ esp-hal/ld/esp32s3/rom/additional.ld | 9 ++ esp-wifi/CHANGELOG.md | 2 + esp-wifi/Cargo.toml | 3 - esp-wifi/src/compat/misc.rs | 139 +-------------------------- 10 files changed, 67 insertions(+), 139 deletions(-) diff --git a/esp-hal/ld/esp32/rom/additional.ld b/esp-hal/ld/esp32/rom/additional.ld index ee815fb3970..d8afbed1267 100644 --- a/esp-hal/ld/esp32/rom/additional.ld +++ b/esp-hal/ld/esp32/rom/additional.ld @@ -9,3 +9,12 @@ PROVIDE ( strncpy = 0x400015d4 ); PROVIDE ( strncmp = 0x4000c5f4 ); PROVIDE ( bzero = 0x4000c1f4 ); + +PROVIDE ( strcat = 0x4000c518 ); +PROVIDE ( strcmp = 0x40001274 ); +PROVIDE ( strchr = 0x4000c53c ); +PROVIDE ( strlcpy = 0x4000c584 ); +PROVIDE ( strstr = 0x4000c674 ); +PROVIDE ( strcasecmp = 0x400011cc ); +PROVIDE ( strdup = 0x4000143c ); +PROVIDE ( atoi = 0x400566c4 ); \ No newline at end of file diff --git a/esp-hal/ld/esp32c2/rom/additional.ld b/esp-hal/ld/esp32c2/rom/additional.ld index 15f88e99bdc..46ef79d8f36 100644 --- a/esp-hal/ld/esp32c2/rom/additional.ld +++ b/esp-hal/ld/esp32c2/rom/additional.ld @@ -6,3 +6,12 @@ memcmp = 0x40000494; strcpy = 0x40000498; strncpy = 0x4000049c; strncmp = 0x400004a4; + +PROVIDE ( strcat = 0x4000050c ); +PROVIDE ( strcmp = 0x400004a0 ); +PROVIDE ( strchr = 0x40000514 ); +PROVIDE ( strlcpy = 0x40000524 ); +PROVIDE ( strstr = 0x400004ac ); +PROVIDE ( strcasecmp = 0x40000504 ); +PROVIDE ( strdup = 0x40000510 ); +PROVIDE ( atoi = 0x40000580 ); diff --git a/esp-hal/ld/esp32c3/rom/additional.ld b/esp-hal/ld/esp32c3/rom/additional.ld index 70032e9e921..f45bec9b54e 100644 --- a/esp-hal/ld/esp32c3/rom/additional.ld +++ b/esp-hal/ld/esp32c3/rom/additional.ld @@ -10,3 +10,12 @@ strcpy = 0x40000364; abs = 0x40000424; PROVIDE(cache_dbus_mmu_set = 0x40000564); + +PROVIDE( strcat = 0x400003d8 ); +PROVIDE( strcmp = 0x4000036c ); +PROVIDE( strchr = 0x400003e0 ); +PROVIDE( strlcpy = 0x400003f0 ); +PROVIDE( strstr = 0x40000378 ); +PROVIDE( strcasecmp = 0x400003d0 ); +PROVIDE( strdup = 0x400003dc ); +PROVIDE( atoi = 0x4000044c ); \ No newline at end of file diff --git a/esp-hal/ld/esp32c6/rom/additional.ld b/esp-hal/ld/esp32c6/rom/additional.ld index 315c01f769a..a9c1801e3a8 100644 --- a/esp-hal/ld/esp32c6/rom/additional.ld +++ b/esp-hal/ld/esp32c6/rom/additional.ld @@ -8,3 +8,12 @@ strncpy = 0x400004bc; strcpy = 0x400004b8; abs = 0x40000578; + +PROVIDE(strcat = 0x4000052c); +PROVIDE(strcmp = 0x400004c0); +PROVIDE(strchr = 0x40000534); +PROVIDE(strlcpy = 0x40000544); +PROVIDE(strstr = 0x400004cc); +PROVIDE(strcasecmp = 0x40000524); +PROVIDE(strdup = 0x40000530); +PROVIDE(atoi = 0x400005a0); diff --git a/esp-hal/ld/esp32h2/rom/additional.ld b/esp-hal/ld/esp32h2/rom/additional.ld index ae1a956ca95..7c1c27ace8e 100644 --- a/esp-hal/ld/esp32h2/rom/additional.ld +++ b/esp-hal/ld/esp32h2/rom/additional.ld @@ -8,3 +8,12 @@ strncpy = 0x400004b4; strcpy = 0x400004b0; abs = 0x40000570; + +PROVIDE( strcat = 0x40000524 ); +PROVIDE( strcmp = 0x400004b8 ); +PROVIDE( strchr = 0x4000052c ); +PROVIDE( strlcpy = 0x4000053c ); +PROVIDE( strstr = 0x400004c4 ); +PROVIDE( strcasecmp = 0x4000051c ); +PROVIDE( strdup = 0x40000528 ); +PROVIDE( atoi = 0x40000598 ); diff --git a/esp-hal/ld/esp32s2/rom/additional.ld b/esp-hal/ld/esp32s2/rom/additional.ld index 41f18abbe25..ea535add6f0 100644 --- a/esp-hal/ld/esp32s2/rom/additional.ld +++ b/esp-hal/ld/esp32s2/rom/additional.ld @@ -10,3 +10,11 @@ strncmp = 0x4001ae64; bzero = 0x400078c8; PROVIDE ( cache_dbus_mmu_set = 0x40018eb0 ); + +PROVIDE ( strcat = 0x4001ad90 ); +PROVIDE ( strcmp = 0x40007be4 ); +PROVIDE ( strchr = 0x4001adb0 ); +PROVIDE ( strlcpy = 0x4001adf8 ); +PROVIDE ( strstr = 0x4001aee8 ); +PROVIDE ( strcasecmp = 0x40007b38 ); +PROVIDE ( strdup = 0x40007d84 ); diff --git a/esp-hal/ld/esp32s3/rom/additional.ld b/esp-hal/ld/esp32s3/rom/additional.ld index 4d8c27b5974..4e926c8adde 100644 --- a/esp-hal/ld/esp32s3/rom/additional.ld +++ b/esp-hal/ld/esp32s3/rom/additional.ld @@ -12,3 +12,12 @@ bzero = 0x40001260; PROVIDE(cache_dbus_mmu_set = 0x400019b0); PROVIDE( Cache_Suspend_DCache_Autoload = 0x40001734 ); PROVIDE( Cache_Suspend_DCache = 0x400018b4 ); + +PROVIDE( strcat = 0x40001374 ); +PROVIDE( strcmp = 0x40001230 ); +PROVIDE( strchr = 0x4000138c ); +PROVIDE( strlcpy = 0x400013bc ); +PROVIDE( strstr = 0x40001254 ); +PROVIDE( strcasecmp = 0x4000135c ); +PROVIDE( strdup = 0x40001380 ); +PROVIDE( atoi = 0x400014d0 ); diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 24189dc5a6e..fcf7d07bb3b 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +- Feature `have-strchr` is removed (#2462) + ## 0.10.1 - 2024-10-10 ### Changed diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 0b448583c2a..4ac482a6a88 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -180,9 +180,6 @@ log = ["dep:log", "esp-hal/log", "esp-wifi-sys/log"] ## Enable sniffer mode support sniffer = ["wifi"] -# Don't include `strchr` - not shown in docs -have-strchr = [] - # Implement serde Serialize / Deserialize serde = ["dep:serde", "enumset?/serde", "heapless/serde"] diff --git a/esp-wifi/src/compat/misc.rs b/esp-wifi/src/compat/misc.rs index 783fd5f5993..8e586cb2cdc 100644 --- a/esp-wifi/src/compat/misc.rs +++ b/esp-wifi/src/compat/misc.rs @@ -1,4 +1,4 @@ -use crate::compat::malloc::*; +// these are not called but needed for linking #[no_mangle] unsafe extern "C" fn fwrite(ptr: *const (), size: usize, count: usize, stream: *const ()) -> usize { @@ -20,141 +20,8 @@ unsafe extern "C" fn fclose(stream: *const ()) -> i32 { todo!("fclose {:?}", stream); } -#[no_mangle] -unsafe extern "C" fn strcat(destination: *mut u8, source: *const u8) -> *const u8 { - trace!("strcat {:?} {:?}", destination, source); - - let dst: *mut u8 = strchr(destination.cast(), 0) as *mut u8; - let len = strchr(source.cast(), 0) as usize - source as usize; - core::ptr::copy(source, dst, len); - destination -} - -#[no_mangle] -unsafe extern "C" fn strcmp(str1: *const i8, str2: *const i8) -> i32 { - trace!("strcmp {:?} {:?}", str1, str2); - - // TODO: unwrap!() when defmt supports it - let s1 = core::ffi::CStr::from_ptr(str1).to_str().unwrap(); - let s2 = core::ffi::CStr::from_ptr(str2).to_str().unwrap(); - - let x = s1.cmp(s2); - - match x { - core::cmp::Ordering::Less => -1, - core::cmp::Ordering::Equal => 0, - core::cmp::Ordering::Greater => 1, - } -} - -#[cfg(feature = "have-strchr")] -extern "C" { - fn strchr(str: *const i8, c: i32) -> *const i8; -} - -#[cfg(not(feature = "have-strchr"))] -#[no_mangle] -unsafe extern "C" fn strchr(str: *const i8, c: i32) -> *const i8 { - trace!("strchr {:?} {}", str, c); - - unsafe { - let mut p = str; - loop { - if *p == c as i8 { - return p; - } - - if *p == 0 { - return core::ptr::null(); - } - - p = p.add(1); - } - } -} - -#[no_mangle] -unsafe extern "C" fn strlcpy(dst: *mut u8, src: *const u8, size: usize) -> usize { - trace!("strlcpy {:?} {:?} {}", dst, src, size); - - let mut dst = dst; - let mut src = src; - let mut cnt = 0; - loop { - dst.write_volatile(0); - - let c = src.read_volatile(); - - if c == 0 || cnt >= size { - break; - } - - dst.write_volatile(c); - dst = dst.add(1); - src = src.add(1); - cnt += 1; - } - - cnt -} - -#[no_mangle] -unsafe extern "C" fn strstr(str1: *const i8, str2: *const i8) -> *const i8 { - trace!("strstr {:?} {:?}", str1, str2); - - let s1 = core::ffi::CStr::from_ptr(str1).to_str().unwrap(); - let s2 = core::ffi::CStr::from_ptr(str2).to_str().unwrap(); - - let idx = s1.find(s2); - - match idx { - Some(offset) => str1.add(offset), - None => core::ptr::null(), - } -} - -#[no_mangle] -unsafe extern "C" fn strcasecmp(str1: *const u8, str2: *const u8) -> i32 { - trace!("strcasecmp {:?} {:?}", str1, str2); - - let mut str1 = str1; - let mut str2 = str2; - - let mut c1 = *str1 as char; - let mut c2 = *str2 as char; - - while c1 != '\0' && c2 != '\0' { - c1 = c1.to_ascii_lowercase(); - c2 = c2.to_ascii_lowercase(); - - if c1 != c2 { - return c1 as i32 - c2 as i32; - } - - str1 = str1.add(1); - str2 = str2.add(1); - - c1 = *str1 as char; - c2 = *str2 as char; - } - - c1 as i32 - c2 as i32 -} - -#[no_mangle] -unsafe extern "C" fn strdup(str: *const i8) -> *const u8 { - trace!("strdup {:?}", str); - - unsafe { - let s = core::ffi::CStr::from_ptr(str); - let s = s.to_str().unwrap(); // TODO when defmt supports it - - let p = malloc(s.len() + 1); - core::ptr::copy_nonoverlapping(str, p as *mut i8, s.len() + 1); - p as *const u8 - } -} - +// not available in ROM on ESP32-S2 +#[cfg(feature = "esp32s2")] #[no_mangle] unsafe extern "C" fn atoi(str: *const i8) -> i32 { trace!("atoi {:?}", str); From ed7960ce8b00c753975653eb433e01fb6d23263e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 17:00:21 +0100 Subject: [PATCH 26/67] Also add into_async for ParlIO (#2461) --- esp-hal/CHANGELOG.md | 4 +-- esp-hal/src/parl_io.rs | 59 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f742791b5d3..3c8eede3867 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - I2S Parallel output driver for ESP32. (#2348, #2436) - Add an option to configure `WDT` action (#2330) - `DmaDescriptor` is now `Send` (#2456) -- `into_async` and `into_blocking` functions for most peripherals (#2430) +- `into_async` and `into_blocking` functions for most peripherals (#2430, #2461) - API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430) - `gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split()` to obtain peripheral interconnect signals. (#2418) - `gpio::Input::{split(), into_peripheral_output()}` when used with output pins. (#2418) @@ -43,7 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Circular DMA transfers now correctly error, `available` returns `Result` now (#2409) - Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442) - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) -- Allow users to create DMA `Preparation`s (#2455) +- Allow users to create DMA `Preparation`s (#2455) - The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) - Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 89043b088a6..c552a3c197c 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -54,6 +54,7 @@ use crate::{ peripheral::{self, Peripheral}, peripherals::{self, Interrupt, PARL_IO}, system::PeripheralClockControl, + Async, Blocking, InterruptConfigurable, Mode, @@ -1017,12 +1018,9 @@ where pub rx: RxCreatorFullDuplex<'d, DM>, } -impl<'d, DM> ParlIoFullDuplex<'d, DM> -where - DM: Mode, -{ +impl<'d> ParlIoFullDuplex<'d, Blocking> { /// Create a new instance of [ParlIoFullDuplex] - pub fn new( + pub fn new( _parl_io: impl Peripheral

+ 'd, dma_channel: Channel<'d, CH, DM>, tx_descriptors: &'static mut [DmaDescriptor], @@ -1030,8 +1028,11 @@ where frequency: HertzU32, ) -> Result where + DM: Mode, CH: DmaChannelConvert<::Dma>, + Channel<'d, CH, Blocking>: From>, { + let dma_channel = Channel::<'d, CH, Blocking>::from(dma_channel); internal_init(frequency)?; Ok(Self { @@ -1047,9 +1048,29 @@ where }, }) } -} -impl ParlIoFullDuplex<'_, Blocking> { + /// Convert to an async version. + pub fn into_async(self) -> ParlIoFullDuplex<'d, Async> { + let channel = Channel { + tx: self.tx.tx_channel, + rx: self.rx.rx_channel, + phantom: PhantomData::, + }; + let channel = channel.into_async(); + ParlIoFullDuplex { + tx: TxCreatorFullDuplex { + tx_channel: channel.tx, + descriptors: self.tx.descriptors, + phantom: PhantomData, + }, + rx: RxCreatorFullDuplex { + rx_channel: channel.rx, + descriptors: self.rx.descriptors, + phantom: PhantomData, + }, + } + } + /// Sets the interrupt handler, enables it with /// [crate::interrupt::Priority::min()] /// @@ -1087,6 +1108,30 @@ impl InterruptConfigurable for ParlIoFullDuplex<'_, Blocking> { } } +impl<'d> ParlIoFullDuplex<'d, Async> { + /// Convert to a blocking version. + pub fn into_blocking(self) -> ParlIoFullDuplex<'d, Blocking> { + let channel = Channel { + tx: self.tx.tx_channel, + rx: self.rx.rx_channel, + phantom: PhantomData::, + }; + let channel = channel.into_blocking(); + ParlIoFullDuplex { + tx: TxCreatorFullDuplex { + tx_channel: channel.tx, + descriptors: self.tx.descriptors, + phantom: PhantomData, + }, + rx: RxCreatorFullDuplex { + rx_channel: channel.rx, + descriptors: self.rx.descriptors, + phantom: PhantomData, + }, + } + } +} + /// Parallel IO in half duplex / TX only mode pub struct ParlIoTxOnly<'d, DM> where From 665fb0e27838e8d5743a51364dda0afdd43888f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 5 Nov 2024 10:56:14 +0100 Subject: [PATCH 27/67] Flatten Uart module, remove unnecessary data, replace methods with `apply_config` (#2449) * Flatten uart config * Do not remember at_command config * Don't save config values in memory * Move config implementations to Info * Changelog * Remove unused methods * apply_config, SetConfig * Fix test * simplify futures * Update esp-hal/CHANGELOG.md Co-authored-by: Sergio Gasquez Arcos --------- Co-authored-by: Sergio Gasquez Arcos --- esp-hal/CHANGELOG.md | 4 + esp-hal/Cargo.toml | 1 + esp-hal/MIGRATING-0.21.md | 14 + esp-hal/src/uart.rs | 1252 +++++++++++++------------ examples/src/bin/embassy_serial.rs | 7 +- examples/src/bin/lp_core_uart.rs | 2 +- examples/src/bin/serial_interrupts.rs | 6 +- hil-test/tests/uart.rs | 12 +- 8 files changed, 678 insertions(+), 620 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 3c8eede3867..46cc9ce3806 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split()` to obtain peripheral interconnect signals. (#2418) - `gpio::Input::{split(), into_peripheral_output()}` when used with output pins. (#2418) - `gpio::Output::peripheral_input()` (#2418) +- `{Uart, UartRx, UartTx}::apply_config()` (#2449) +- `{Uart, UartRx, UartTx}` now implement `embassy_embedded_hal::SetConfig` (#2449) ### Changed @@ -46,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow users to create DMA `Preparation`s (#2455) - The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) - Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) +- UART configuration types have been moved to `esp_hal::uart` (#2449) ### Fixed @@ -74,6 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388) - Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430) - The `configure_for_async` DMA functions have been removed (#2430) +- The `Uart::{change_baud, change_stop_bits}` functions have been removed (#2449) ## [0.21.1] diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 71f0a184cc8..307ec0c9181 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -25,6 +25,7 @@ defmt = { version = "0.3.8", optional = true } delegate = "0.12.0" digest = { version = "0.10.7", default-features = false, optional = true } document-features = "0.2.10" +embassy-embedded-hal = "0.2.0" embassy-futures = "0.1.1" embassy-sync = "0.6.0" embassy-usb-driver = { version = "0.1.0", optional = true } diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 46708dfa205..edb86927383 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -230,3 +230,17 @@ The previous signal function have been replaced by `split`. This change affects `into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead. + +## Changes to peripheral configuration + +### The `uart::config` module has been removed + +The module's contents have been moved into `uart`. + +```diff +-use esp_hal::uart::config::Config; ++use esp_hal::uart::Config; +``` + +If you work with multiple configurable peripherals, you may want to import the `uart` module and +refer to the `Config` struct as `uart::Config`. diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index a67c4b0e6a1..f37c16a568c 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -55,7 +55,7 @@ //! ### Sending and Receiving Data //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::uart::{config::Config, Uart}; +//! # use esp_hal::uart::{Config, Uart}; //! # use esp_hal::gpio::Io; //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( @@ -72,7 +72,7 @@ //! ### Splitting the UART into RX and TX Components //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::uart::{config::Config, Uart}; +//! # use esp_hal::uart::{Config, Uart}; //! # use esp_hal::gpio::Io; //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( @@ -128,11 +128,11 @@ use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll}; +use embassy_embedded_hal::SetConfig; use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; use portable_atomic::AtomicBool; -use self::config::Config; use crate::{ clock::Clocks, dma::PeripheralMarker, @@ -221,224 +221,220 @@ pub enum ClockSource { RefTick, } -/// UART Configuration -pub mod config { +// see +const UART_FULL_THRESH_DEFAULT: u16 = 120; +// see +const UART_TOUT_THRESH_DEFAULT: u8 = 10; - // see - const UART_FULL_THRESH_DEFAULT: u16 = 120; - // see - const UART_TOUT_THRESH_DEFAULT: u8 = 10; +/// Number of data bits +/// +/// This enum represents the various configurations for the number of data +/// bits used in UART communication. The number of data bits defines the +/// length of each transmitted or received data frame. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum DataBits { + /// 5 data bits per frame. + DataBits5 = 0, + /// 6 data bits per frame. + DataBits6 = 1, + /// 7 data bits per frame. + DataBits7 = 2, + /// 8 data bits per frame (most common). + DataBits8 = 3, +} + +/// Parity check +/// +/// Parity is a form of error detection in UART communication, used to +/// ensure that the data has not been corrupted during transmission. The +/// parity bit is added to the data bits to make the number of 1-bits +/// either even or odd. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Parity { + /// No parity bit is used (most common). + ParityNone, + /// Even parity: the parity bit is set to make the total number of + /// 1-bits even. + ParityEven, + /// Odd parity: the parity bit is set to make the total number of 1-bits + /// odd. + ParityOdd, +} + +/// Number of stop bits +/// +/// The stop bit(s) signal the end of a data packet in UART communication. +/// This enum defines the possible configurations for the number of stop +/// bits. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum StopBits { + /// 1 stop bit. + STOP1 = 1, + /// 1.5 stop bits. + STOP1P5 = 2, + /// 2 stop bits. + STOP2 = 3, +} - /// Number of data bits - /// - /// This enum represents the various configurations for the number of data - /// bits used in UART communication. The number of data bits defines the - /// length of each transmitted or received data frame. - #[derive(PartialEq, Eq, Copy, Clone, Debug)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum DataBits { - /// 5 data bits per frame. - DataBits5 = 0, - /// 6 data bits per frame. - DataBits6 = 1, - /// 7 data bits per frame. - DataBits7 = 2, - /// 8 data bits per frame (most common). - DataBits8 = 3, - } - - /// Parity check - /// - /// Parity is a form of error detection in UART communication, used to - /// ensure that the data has not been corrupted during transmission. The - /// parity bit is added to the data bits to make the number of 1-bits - /// either even or odd. - #[derive(PartialEq, Eq, Copy, Clone, Debug)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum Parity { - /// No parity bit is used (most common). - ParityNone, - /// Even parity: the parity bit is set to make the total number of - /// 1-bits even. - ParityEven, - /// Odd parity: the parity bit is set to make the total number of 1-bits - /// odd. - ParityOdd, - } - - /// Number of stop bits - /// - /// The stop bit(s) signal the end of a data packet in UART communication. - /// This enum defines the possible configurations for the number of stop - /// bits. - #[derive(PartialEq, Eq, Copy, Clone, Debug)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum StopBits { - /// 1 stop bit. - STOP1 = 1, - /// 1.5 stop bits. - STOP1P5 = 2, - /// 2 stop bits. - STOP2 = 3, - } - - /// UART Configuration - #[derive(Debug, Copy, Clone)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub struct Config { - /// The baud rate (speed) of the UART communication in bits per second - /// (bps). - pub baudrate: u32, - /// Number of data bits in each frame (5, 6, 7, or 8 bits). - pub data_bits: DataBits, - /// Parity setting (None, Even, or Odd). - pub parity: Parity, - /// Number of stop bits in each frame (1, 1.5, or 2 bits). - pub stop_bits: StopBits, - /// Clock source used by the UART peripheral. - pub clock_source: super::ClockSource, - /// Threshold level at which the RX FIFO is considered full. - pub rx_fifo_full_threshold: u16, - /// Optional timeout value for RX operations. - pub rx_timeout: Option, - } - - impl Config { - /// Sets the baud rate for the UART configuration. - pub fn baudrate(mut self, baudrate: u32) -> Self { - self.baudrate = baudrate; - self - } +/// UART Configuration +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Config { + /// The baud rate (speed) of the UART communication in bits per second + /// (bps). + pub baudrate: u32, + /// Number of data bits in each frame (5, 6, 7, or 8 bits). + pub data_bits: DataBits, + /// Parity setting (None, Even, or Odd). + pub parity: Parity, + /// Number of stop bits in each frame (1, 1.5, or 2 bits). + pub stop_bits: StopBits, + /// Clock source used by the UART peripheral. + pub clock_source: ClockSource, + /// Threshold level at which the RX FIFO is considered full. + pub rx_fifo_full_threshold: u16, + /// Optional timeout value for RX operations. + pub rx_timeout: Option, +} + +impl Config { + /// Sets the baud rate for the UART configuration. + pub fn baudrate(mut self, baudrate: u32) -> Self { + self.baudrate = baudrate; + self + } - /// Configures the UART to use no parity check. - pub fn parity_none(mut self) -> Self { - self.parity = Parity::ParityNone; - self - } + /// Configures the UART to use no parity check. + pub fn parity_none(mut self) -> Self { + self.parity = Parity::ParityNone; + self + } - /// Configures the UART to use even parity check. - pub fn parity_even(mut self) -> Self { - self.parity = Parity::ParityEven; - self - } + /// Configures the UART to use even parity check. + pub fn parity_even(mut self) -> Self { + self.parity = Parity::ParityEven; + self + } - /// Configures the UART to use odd parity check. - pub fn parity_odd(mut self) -> Self { - self.parity = Parity::ParityOdd; - self - } + /// Configures the UART to use odd parity check. + pub fn parity_odd(mut self) -> Self { + self.parity = Parity::ParityOdd; + self + } - /// Sets the number of data bits for the UART configuration. - pub fn data_bits(mut self, data_bits: DataBits) -> Self { - self.data_bits = data_bits; - self - } + /// Sets the number of data bits for the UART configuration. + pub fn data_bits(mut self, data_bits: DataBits) -> Self { + self.data_bits = data_bits; + self + } - /// Sets the number of stop bits for the UART configuration. - pub fn stop_bits(mut self, stop_bits: StopBits) -> Self { - self.stop_bits = stop_bits; - self - } + /// Sets the number of stop bits for the UART configuration. + pub fn stop_bits(mut self, stop_bits: StopBits) -> Self { + self.stop_bits = stop_bits; + self + } - /// Sets the clock source for the UART configuration. - pub fn clock_source(mut self, source: super::ClockSource) -> Self { - self.clock_source = source; - self - } + /// Sets the clock source for the UART configuration. + pub fn clock_source(mut self, source: ClockSource) -> Self { + self.clock_source = source; + self + } - /// Calculates the total symbol length in bits based on the configured - /// data bits, parity, and stop bits. - pub fn symbol_length(&self) -> u8 { - let mut length: u8 = 1; // start bit - length += match self.data_bits { - DataBits::DataBits5 => 5, - DataBits::DataBits6 => 6, - DataBits::DataBits7 => 7, - DataBits::DataBits8 => 8, - }; - length += match self.parity { - Parity::ParityNone => 0, - _ => 1, - }; - length += match self.stop_bits { - StopBits::STOP1 => 1, - _ => 2, // esp-idf also counts 2 bits for settings 1.5 and 2 stop bits - }; - length - } + /// Calculates the total symbol length in bits based on the configured + /// data bits, parity, and stop bits. + pub fn symbol_length(&self) -> u8 { + let mut length: u8 = 1; // start bit + length += match self.data_bits { + DataBits::DataBits5 => 5, + DataBits::DataBits6 => 6, + DataBits::DataBits7 => 7, + DataBits::DataBits8 => 8, + }; + length += match self.parity { + Parity::ParityNone => 0, + _ => 1, + }; + length += match self.stop_bits { + StopBits::STOP1 => 1, + _ => 2, // esp-idf also counts 2 bits for settings 1.5 and 2 stop bits + }; + length + } - /// Sets the RX FIFO full threshold for the UART configuration. - pub fn rx_fifo_full_threshold(mut self, threshold: u16) -> Self { - self.rx_fifo_full_threshold = threshold; - self - } + /// Sets the RX FIFO full threshold for the UART configuration. + pub fn rx_fifo_full_threshold(mut self, threshold: u16) -> Self { + self.rx_fifo_full_threshold = threshold; + self + } - /// Sets the RX timeout for the UART configuration. - pub fn rx_timeout(mut self, timeout: Option) -> Self { - self.rx_timeout = timeout; - self - } + /// Sets the RX timeout for the UART configuration. + pub fn rx_timeout(mut self, timeout: Option) -> Self { + self.rx_timeout = timeout; + self } +} - impl Default for Config { - fn default() -> Config { - Config { - baudrate: 115_200, - data_bits: DataBits::DataBits8, - parity: Parity::ParityNone, - stop_bits: StopBits::STOP1, - clock_source: { - cfg_if::cfg_if! { - if #[cfg(any(esp32c6, esp32h2, lp_uart))] { - super::ClockSource::Xtal - } else { - super::ClockSource::Apb - } +impl Default for Config { + fn default() -> Config { + Config { + baudrate: 115_200, + data_bits: DataBits::DataBits8, + parity: Parity::ParityNone, + stop_bits: StopBits::STOP1, + clock_source: { + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2, lp_uart))] { + ClockSource::Xtal + } else { + ClockSource::Apb } - }, - rx_fifo_full_threshold: UART_FULL_THRESH_DEFAULT, - rx_timeout: Some(UART_TOUT_THRESH_DEFAULT), - } + } + }, + rx_fifo_full_threshold: UART_FULL_THRESH_DEFAULT, + rx_timeout: Some(UART_TOUT_THRESH_DEFAULT), } } +} - /// Configuration for the AT-CMD detection functionality - pub struct AtCmdConfig { - /// Optional idle time before the AT command detection begins, in clock - /// cycles. - pub pre_idle_count: Option, - /// Optional idle time after the AT command detection ends, in clock - /// cycles. - pub post_idle_count: Option, - /// Optional timeout between characters in the AT command, in clock - /// cycles. - pub gap_timeout: Option, - /// The character that triggers the AT command detection. - pub cmd_char: u8, - /// Optional number of characters to detect as part of the AT command. - pub char_num: Option, - } - - impl AtCmdConfig { - /// Creates a new `AtCmdConfig` with the specified configuration. - /// - /// This function sets up the AT command detection parameters, including - /// pre- and post-idle times, a gap timeout, the triggering command - /// character, and the number of characters to detect. - pub fn new( - pre_idle_count: Option, - post_idle_count: Option, - gap_timeout: Option, - cmd_char: u8, - char_num: Option, - ) -> AtCmdConfig { - Self { - pre_idle_count, - post_idle_count, - gap_timeout, - cmd_char, - char_num, - } +/// Configuration for the AT-CMD detection functionality +pub struct AtCmdConfig { + /// Optional idle time before the AT command detection begins, in clock + /// cycles. + pub pre_idle_count: Option, + /// Optional idle time after the AT command detection ends, in clock + /// cycles. + pub post_idle_count: Option, + /// Optional timeout between characters in the AT command, in clock + /// cycles. + pub gap_timeout: Option, + /// The character that triggers the AT command detection. + pub cmd_char: u8, + /// Optional number of characters to detect as part of the AT command. + pub char_num: Option, +} + +impl AtCmdConfig { + /// Creates a new `AtCmdConfig` with the specified configuration. + /// + /// This function sets up the AT command detection parameters, including + /// pre- and post-idle times, a gap timeout, the triggering command + /// character, and the number of characters to detect. + pub fn new( + pre_idle_count: Option, + post_idle_count: Option, + gap_timeout: Option, + cmd_char: u8, + char_num: Option, + ) -> AtCmdConfig { + Self { + pre_idle_count, + post_idle_count, + gap_timeout, + cmd_char, + char_num, } } } @@ -484,10 +480,6 @@ where rx: UartRx { uart: unsafe { self.uart.clone_unchecked() }, phantom: PhantomData, - at_cmd_config: None, - rx_timeout_config: None, - #[cfg(not(esp32))] - symbol_len: config.symbol_length(), }, tx: UartTx { uart: self.uart, @@ -516,10 +508,45 @@ pub struct UartTx<'d, M, T = AnyUart> { pub struct UartRx<'d, M, T = AnyUart> { uart: PeripheralRef<'d, T>, phantom: PhantomData, - at_cmd_config: Option, - rx_timeout_config: Option, - #[cfg(not(esp32))] - symbol_len: u8, +} + +impl SetConfig for Uart<'_, M, T> +where + T: Instance, + M: Mode, +{ + type Config = Config; + type ConfigError = Error; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } +} + +impl SetConfig for UartRx<'_, M, T> +where + T: Instance, + M: Mode, +{ + type Config = Config; + type ConfigError = Error; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } +} + +impl SetConfig for UartTx<'_, M, T> +where + T: Instance, + M: Mode, +{ + type Config = Config; + type ConfigError = Error; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } } impl<'d, M, T> UartTx<'d, M, T> @@ -536,6 +563,14 @@ where self } + /// Change the configuration. + /// + /// Note that this also changes the configuration of the RX half. + pub fn apply_config(&mut self, config: &Config) -> Result<(), Error> { + self.uart.info().apply_config(config)?; + Ok(()) + } + /// Writes bytes pub fn write_bytes(&mut self, data: &[u8]) -> Result { let count = data.len(); @@ -736,6 +771,14 @@ where self } + /// Change the configuration. + /// + /// Note that this also changes the configuration of the TX half. + pub fn apply_config(&mut self, config: &Config) -> Result<(), Error> { + self.uart.info().apply_config(config)?; + Ok(()) + } + /// Fill a buffer with received bytes pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { cfg_if::cfg_if! { @@ -840,98 +883,6 @@ where fifo_cnt } - /// Configures the RX-FIFO threshold - /// - /// # Errors - /// `Err(Error::InvalidArgument)` if provided value exceeds maximum value - /// for SOC : - /// - `esp32` **0x7F** - /// - `esp32c6`, `esp32h2` **0xFF** - /// - `esp32c3`, `esp32c2`, `esp32s2` **0x1FF** - /// - `esp32s3` **0x3FF** - fn set_rx_fifo_full_threshold(&mut self, threshold: u16) -> Result<(), Error> { - #[cfg(esp32)] - const MAX_THRHD: u16 = 0x7F; - #[cfg(any(esp32c6, esp32h2))] - const MAX_THRHD: u16 = 0xFF; - #[cfg(any(esp32c3, esp32c2, esp32s2))] - const MAX_THRHD: u16 = 0x1FF; - #[cfg(esp32s3)] - const MAX_THRHD: u16 = 0x3FF; - - if threshold > MAX_THRHD { - return Err(Error::InvalidArgument); - } - - self.register_block() - .conf1() - .modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold as _) }); - - Ok(()) - } - - /// Configures the Receive Timeout detection setting - /// - /// # Arguments - /// `timeout` - the number of symbols ("bytes") to wait for before - /// triggering a timeout. Pass None to disable the timeout. - /// - /// # Errors - /// `Err(Error::InvalidArgument)` if the provided value exceeds the maximum - /// value for SOC : - /// - `esp32`: Symbol size is fixed to 8, do not pass a value > **0x7F**. - /// - `esp32c2`, `esp32c3`, `esp32c6`, `esp32h2`, esp32s2`, esp32s3`: The - /// value you pass times the symbol size must be <= **0x3FF** - fn set_rx_timeout(&mut self, timeout: Option) -> Result<(), Error> { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - const MAX_THRHD: u8 = 0x7F; // 7 bits - } else { - const MAX_THRHD: u16 = 0x3FF; // 10 bits - } - } - - let register_block = self.register_block(); - - if let Some(timeout) = timeout { - // the esp32 counts directly in number of symbols (symbol len fixed to 8) - #[cfg(esp32)] - let timeout_reg = timeout; - // all other count in bits, so we need to multiply by the symbol len. - #[cfg(not(esp32))] - let timeout_reg = timeout as u16 * self.symbol_len as u16; - - if timeout_reg > MAX_THRHD { - return Err(Error::InvalidArgument); - } - - cfg_if::cfg_if! { - if #[cfg(esp32)] { - let reg_thrhd = register_block.conf1(); - } else if #[cfg(any(esp32c6, esp32h2))] { - let reg_thrhd = register_block.tout_conf(); - } else { - let reg_thrhd = register_block.mem_conf(); - } - } - reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) }); - } - - cfg_if::cfg_if! { - if #[cfg(any(esp32c6, esp32h2))] { - let reg_en = register_block.tout_conf(); - } else { - let reg_en = register_block.conf1(); - } - } - reg_en.modify(|_, w| w.rx_tout_en().bit(timeout.is_some())); - - sync_regs(register_block); - self.rx_timeout_config = timeout; - - Ok(()) - } - /// Disables all RX-related interrupts for this UART instance. /// /// This function clears and disables the `receive FIFO full` interrupt, @@ -1014,10 +965,6 @@ where UartRx { uart: self.uart, phantom: PhantomData, - at_cmd_config: self.at_cmd_config, - rx_timeout_config: self.rx_timeout_config, - #[cfg(not(esp32))] - symbol_len: self.symbol_len, } } } @@ -1039,10 +986,6 @@ where UartRx { uart: self.uart, phantom: PhantomData, - at_cmd_config: self.at_cmd_config, - rx_timeout_config: self.rx_timeout_config, - #[cfg(not(esp32))] - symbol_len: self.symbol_len, } } } @@ -1153,10 +1096,6 @@ where self.tx.uart.info().register_block() } - fn sync_regs(&self) { - sync_regs(self.register_block()); - } - /// Split the UART into a transmitter and receiver /// /// This is particularly useful when having two tasks correlating to @@ -1176,7 +1115,7 @@ where } /// Configures the AT-CMD detection settings - pub fn set_at_cmd(&mut self, config: config::AtCmdConfig) { + pub fn set_at_cmd(&mut self, config: AtCmdConfig) { let register_block = self.register_block(); #[cfg(not(any(esp32, esp32s2)))] @@ -1212,9 +1151,7 @@ where .clk_conf() .modify(|_, w| w.sclk_en().set_bit()); - self.sync_regs(); - - self.rx.at_cmd_config = Some(config); + sync_regs(register_block); } /// Listen for the given interrupts @@ -1252,227 +1189,54 @@ where self.rx.read_byte() } - /// Change the number of stop bits - pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { - #[cfg(esp32)] - { - // workaround for hardware issue, when UART stop bit set as 2-bit mode. - if stop_bits == config::StopBits::STOP2 { - self.register_block() - .rs485_conf() - .modify(|_, w| w.dl1_en().bit(stop_bits == config::StopBits::STOP2)); + /// Change the configuration. + pub fn apply_config(&mut self, config: &Config) -> Result<(), Error> { + self.rx.apply_config(config)?; + Ok(()) + } - self.register_block().conf0().modify(|_, w| { - if stop_bits == config::StopBits::STOP2 { - unsafe { w.stop_bit_num().bits(1) } - } else { - unsafe { w.stop_bit_num().bits(stop_bits as u8) } - } - }); + #[inline(always)] + fn init(&mut self, config: Config) -> Result<(), Error> { + cfg_if::cfg_if! { + if #[cfg(any(esp32, esp32s2))] { + // Nothing to do + } else if #[cfg(any(esp32c2, esp32c3, esp32s3))] { + unsafe { crate::peripherals::SYSTEM::steal() } + .perip_clk_en0() + .modify(|_, w| w.uart_mem_clk_en().set_bit()); + } else { + self.register_block() + .conf0() + .modify(|_, w| w.mem_clk_en().set_bit()); } - } + }; - #[cfg(not(esp32))] + PeripheralClockControl::enable(self.tx.uart.peripheral()); + self.uart_peripheral_reset(); + self.rx.disable_rx_interrupts(); + self.tx.disable_tx_interrupts(); + + self.rx.uart.info().apply_config(&config)?; + + // Setting err_wr_mask stops uart from storing data when data is wrong according + // to reference manual self.register_block() .conf0() - .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); + .modify(|_, w| w.err_wr_mask().set_bit()); - self - } + crate::rom::ets_delay_us(15); - fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { + // Make sure we are starting in a "clean state" - previous operations might have + // run into error conditions self.register_block() - .conf0() - .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); + .int_clr() + .write(|w| unsafe { w.bits(u32::MAX) }); - self + Ok(()) } - fn change_parity(&mut self, parity: config::Parity) -> &mut Self { - self.register_block().conf0().modify(|_, w| match parity { - config::Parity::ParityNone => w.parity_en().clear_bit(), - config::Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), - config::Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), - }); - - self - } - - #[cfg(any(esp32c2, esp32c3, esp32s3))] - fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource) { - let clocks = Clocks::get(); - let clk = match clock_source { - ClockSource::Apb => clocks.apb_clock.to_Hz(), - ClockSource::Xtal => clocks.xtal_clock.to_Hz(), - ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), - }; - - if clock_source == ClockSource::RcFast { - unsafe { crate::peripherals::RTC_CNTL::steal() } - .clk_conf() - .modify(|_, w| w.dig_clk8m_en().variant(true)); - // esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH); - crate::rom::ets_delay_us(5); - } - - let max_div = 0b1111_1111_1111 - 1; - let clk_div = clk.div_ceil(max_div * baudrate); - self.register_block().clk_conf().write(|w| unsafe { - w.sclk_sel().bits(match clock_source { - ClockSource::Apb => 1, - ClockSource::RcFast => 2, - ClockSource::Xtal => 3, - }); - w.sclk_div_a().bits(0); - w.sclk_div_b().bits(0); - w.sclk_div_num().bits(clk_div as u8 - 1); - w.rx_sclk_en().bit(true); - w.tx_sclk_en().bit(true) - }); - - let divider = (clk << 4) / (baudrate * clk_div); - let divider_integer = (divider >> 4) as u16; - let divider_frag = (divider & 0xf) as u8; - self.register_block() - .clkdiv() - .write(|w| unsafe { w.clkdiv().bits(divider_integer).frag().bits(divider_frag) }); - } - - #[cfg(any(esp32c6, esp32h2))] - fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource) { - let clocks = Clocks::get(); - let clk = match clock_source { - ClockSource::Apb => clocks.apb_clock.to_Hz(), - ClockSource::Xtal => clocks.xtal_clock.to_Hz(), - ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), - }; - - let max_div = 0b1111_1111_1111 - 1; - let clk_div = clk.div_ceil(max_div * baudrate); - - // UART clocks are configured via PCR - let pcr = unsafe { crate::peripherals::PCR::steal() }; - - if self.is_instance(unsafe { crate::peripherals::UART0::steal() }) { - pcr.uart0_conf() - .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); - - pcr.uart0_sclk_conf().modify(|_, w| unsafe { - w.uart0_sclk_div_a().bits(0); - w.uart0_sclk_div_b().bits(0); - w.uart0_sclk_div_num().bits(clk_div as u8 - 1); - w.uart0_sclk_sel().bits(match clock_source { - ClockSource::Apb => 1, - ClockSource::RcFast => 2, - ClockSource::Xtal => 3, - }); - w.uart0_sclk_en().set_bit() - }); - } else { - pcr.uart1_conf() - .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); - - pcr.uart1_sclk_conf().modify(|_, w| unsafe { - w.uart1_sclk_div_a().bits(0); - w.uart1_sclk_div_b().bits(0); - w.uart1_sclk_div_num().bits(clk_div as u8 - 1); - w.uart1_sclk_sel().bits(match clock_source { - ClockSource::Apb => 1, - ClockSource::RcFast => 2, - ClockSource::Xtal => 3, - }); - w.uart1_sclk_en().set_bit() - }); - } - - let clk = clk / clk_div; - let divider = clk / baudrate; - let divider = divider as u16; - - self.register_block() - .clkdiv() - .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); - - self.sync_regs(); - } - - #[cfg(any(esp32, esp32s2))] - fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource) { - let clk = match clock_source { - ClockSource::Apb => Clocks::get().apb_clock.to_Hz(), - // ESP32(/-S2) TRM, section 3.2.4.2 (6.2.4.2 for S2) - ClockSource::RefTick => crate::soc::constants::REF_TICK.to_Hz(), - }; - - self.register_block() - .conf0() - .modify(|_, w| w.tick_ref_always_on().bit(clock_source == ClockSource::Apb)); - - let divider = clk / baudrate; - - self.register_block() - .clkdiv() - .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); - } - - /// Modify UART baud rate and reset TX/RX fifo. - pub fn change_baud(&mut self, baudrate: u32, clock_source: ClockSource) { - self.change_baud_internal(baudrate, clock_source); - self.txfifo_reset(); - self.rxfifo_reset(); - } - - #[inline(always)] - fn init(&mut self, config: Config) -> Result<(), Error> { - cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { - // Nothing to do - } else if #[cfg(any(esp32c2, esp32c3, esp32s3))] { - unsafe { crate::peripherals::SYSTEM::steal() } - .perip_clk_en0() - .modify(|_, w| w.uart_mem_clk_en().set_bit()); - } else { - self.register_block() - .conf0() - .modify(|_, w| w.mem_clk_en().set_bit()); - } - }; - - PeripheralClockControl::enable(self.tx.uart.peripheral()); - self.uart_peripheral_reset(); - self.rx.disable_rx_interrupts(); - self.tx.disable_tx_interrupts(); - - self.rx - .set_rx_fifo_full_threshold(config.rx_fifo_full_threshold)?; - self.rx.set_rx_timeout(config.rx_timeout)?; - self.change_baud_internal(config.baudrate, config.clock_source); - self.change_data_bits(config.data_bits); - self.change_parity(config.parity); - self.change_stop_bits(config.stop_bits); - - // Setting err_wr_mask stops uart from storing data when data is wrong according - // to reference manual - self.register_block() - .conf0() - .modify(|_, w| w.err_wr_mask().set_bit()); - - // Reset Tx/Rx FIFOs - self.rxfifo_reset(); - self.txfifo_reset(); - crate::rom::ets_delay_us(15); - - // Make sure we are starting in a "clean state" - previous operations might have - // run into error conditions - self.register_block() - .int_clr() - .write(|w| unsafe { w.bits(u32::MAX) }); - - Ok(()) - } - - fn is_instance(&self, other: impl Instance) -> bool { - self.tx.uart.info() == other.info() + fn is_instance(&self, other: impl Instance) -> bool { + self.tx.uart.info().is_instance(other) } #[inline(always)] @@ -1502,26 +1266,6 @@ where PeripheralClockControl::reset(self.tx.uart.peripheral()); rst_core(self.register_block(), false); } - - fn rxfifo_reset(&mut self) { - fn rxfifo_rst(reg_block: &RegisterBlock, enable: bool) { - reg_block.conf0().modify(|_, w| w.rxfifo_rst().bit(enable)); - sync_regs(reg_block); - } - - rxfifo_rst(self.register_block(), true); - rxfifo_rst(self.register_block(), false); - } - - fn txfifo_reset(&mut self) { - fn txfifo_rst(reg_block: &RegisterBlock, enable: bool) { - reg_block.conf0().modify(|_, w| w.txfifo_rst().bit(enable)); - sync_regs(reg_block); - } - - txfifo_rst(self.register_block(), true); - txfifo_rst(self.register_block(), false); - } } impl crate::private::Sealed for Uart<'_, Blocking, T> where T: Instance {} @@ -1826,19 +1570,20 @@ pub(crate) enum RxEvent { /// is dropped it disables the interrupt again. The future returns the event /// that was initially passed, when it resolves. #[must_use = "futures do nothing unless you `.await` or poll them"] -struct UartRxFuture<'d> { +struct UartRxFuture { events: EnumSet, - uart: &'d Info, - state: &'d State, + uart: &'static Info, + state: &'static State, registered: bool, } -impl<'d> UartRxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { +impl UartRxFuture { + fn new(uart: impl Peripheral

, events: impl Into>) -> Self { + crate::into_ref!(uart); Self { events: events.into(), - uart, - state, + uart: uart.info(), + state: uart.state(), registered: false, } } @@ -1882,7 +1627,7 @@ impl<'d> UartRxFuture<'d> { } } -impl core::future::Future for UartRxFuture<'_> { +impl core::future::Future for UartRxFuture { type Output = EnumSet; fn poll( @@ -1903,7 +1648,7 @@ impl core::future::Future for UartRxFuture<'_> { } } -impl Drop for UartRxFuture<'_> { +impl Drop for UartRxFuture { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as @@ -1913,18 +1658,19 @@ impl Drop for UartRxFuture<'_> { } #[must_use = "futures do nothing unless you `.await` or poll them"] -struct UartTxFuture<'d> { +struct UartTxFuture { events: EnumSet, - uart: &'d Info, - state: &'d State, + uart: &'static Info, + state: &'static State, registered: bool, } -impl<'d> UartTxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { +impl UartTxFuture { + fn new(uart: impl Peripheral

, events: impl Into>) -> Self { + crate::into_ref!(uart); Self { events: events.into(), - uart, - state, + uart: uart.info(), + state: uart.state(), registered: false, } } @@ -1954,7 +1700,7 @@ impl<'d> UartTxFuture<'d> { } } -impl core::future::Future for UartTxFuture<'_> { +impl core::future::Future for UartTxFuture { type Output = (); fn poll( @@ -1975,7 +1721,7 @@ impl core::future::Future for UartTxFuture<'_> { } } -impl Drop for UartTxFuture<'_> { +impl Drop for UartTxFuture { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as @@ -2005,7 +1751,7 @@ where } } -impl<'d, T> UartTx<'d, Async, T> +impl UartTx<'_, Async, T> where T: Instance, { @@ -2034,7 +1780,7 @@ where } offset = next_offset; - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; + UartTxFuture::new(self.uart.reborrow(), TxEvent::TxFiFoEmpty).await; } Ok(count) @@ -2048,14 +1794,14 @@ where pub async fn flush_async(&mut self) -> Result<(), Error> { let count = self.tx_fifo_count(); if count > 0 { - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; + UartTxFuture::new(self.uart.reborrow(), TxEvent::TxDone).await; } Ok(()) } } -impl<'d, T> UartRx<'d, Async, T> +impl UartRx<'_, Async, T> where T: Instance, { @@ -2091,15 +1837,23 @@ where | RxEvent::GlitchDetected | RxEvent::ParityError; - if self.at_cmd_config.is_some() { + let register_block = self.uart.info().register_block(); + if register_block.at_cmd_char().read().char_num().bits() > 0 { events |= RxEvent::CmdCharDetected; } - if self.rx_timeout_config.is_some() { + + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2))] { + let reg_en = register_block.tout_conf(); + } else { + let reg_en = register_block.conf1(); + } + }; + if reg_en.read().rx_tout_en().bit_is_set() { events |= RxEvent::FifoTout; } - let events_happened = - UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; + let events_happened = UartRxFuture::new(self.uart.reborrow(), events).await; // always drain the fifo, if an error has occurred the data is lost let read_bytes = self.drain_fifo(buf); // check error events @@ -2213,7 +1967,7 @@ pub mod lp_uart { use crate::{ gpio::lp_io::{LowPowerInput, LowPowerOutput}, peripherals::{LP_CLKRST, LP_UART}, - uart::config::{self, Config}, + uart::{Config, DataBits, Parity, StopBits}, }; /// LP-UART driver /// @@ -2355,23 +2109,23 @@ pub mod lp_uart { self.rxfifo_reset(); } - fn change_parity(&mut self, parity: config::Parity) -> &mut Self { - if parity != config::Parity::ParityNone { + fn change_parity(&mut self, parity: Parity) -> &mut Self { + if parity != Parity::ParityNone { self.uart .conf0() .modify(|_, w| w.parity().bit((parity as u8 & 0x1) != 0)); } self.uart.conf0().modify(|_, w| match parity { - config::Parity::ParityNone => w.parity_en().clear_bit(), - config::Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), - config::Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), + Parity::ParityNone => w.parity_en().clear_bit(), + Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), + Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), }); self } - fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { + fn change_data_bits(&mut self, data_bits: DataBits) -> &mut Self { self.uart .conf0() .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); @@ -2381,7 +2135,7 @@ pub mod lp_uart { self } - fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { + fn change_stop_bits(&mut self, stop_bits: StopBits) -> &mut Self { self.uart .conf0() .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); @@ -2401,36 +2155,20 @@ pub mod lp_uart { } } -impl Info { - fn set_interrupt_handler(&self, handler: InterruptHandler) { - for core in crate::Cpu::other() { - crate::interrupt::disable(core, self.interrupt); - } - self.enable_listen(EnumSet::all(), false); - self.clear_interrupts(EnumSet::all()); - unsafe { crate::interrupt::bind_interrupt(self.interrupt, handler.handler()) }; - unwrap!(crate::interrupt::enable(self.interrupt, handler.priority())); - } - - fn disable_interrupts(&self) { - crate::interrupt::disable(crate::Cpu::current(), self.interrupt); - } -} - /// UART Peripheral Instance pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { /// Returns the peripheral data and state describing this UART instance. - fn parts(&self) -> (&Info, &State); + fn parts(&self) -> (&'static Info, &'static State); /// Returns the peripheral data describing this UART instance. #[inline(always)] - fn info(&self) -> &Info { + fn info(&self) -> &'static Info { self.parts().0 } /// Returns the peripheral state for this UART instance. #[inline(always)] - fn state(&self) -> &State { + fn state(&self) -> &'static State { self.parts().1 } } @@ -2531,6 +2269,310 @@ impl Info { w }); } + + fn set_interrupt_handler(&self, handler: InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, self.interrupt); + } + self.enable_listen(EnumSet::all(), false); + self.clear_interrupts(EnumSet::all()); + unsafe { crate::interrupt::bind_interrupt(self.interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(self.interrupt, handler.priority())); + } + + fn disable_interrupts(&self) { + crate::interrupt::disable(crate::Cpu::current(), self.interrupt); + } + + fn apply_config(&self, config: &Config) -> Result<(), Error> { + self.set_rx_fifo_full_threshold(config.rx_fifo_full_threshold)?; + self.set_rx_timeout(config.rx_timeout, config.symbol_length())?; + self.change_baud(config.baudrate, config.clock_source); + self.change_data_bits(config.data_bits); + self.change_parity(config.parity); + self.change_stop_bits(config.stop_bits); + + // Reset Tx/Rx FIFOs + self.rxfifo_reset(); + self.txfifo_reset(); + + Ok(()) + } + + /// Configures the RX-FIFO threshold + /// + /// # Errors + /// `Err(Error::InvalidArgument)` if provided value exceeds maximum value + /// for SOC : + /// - `esp32` **0x7F** + /// - `esp32c6`, `esp32h2` **0xFF** + /// - `esp32c3`, `esp32c2`, `esp32s2` **0x1FF** + /// - `esp32s3` **0x3FF** + fn set_rx_fifo_full_threshold(&self, threshold: u16) -> Result<(), Error> { + #[cfg(esp32)] + const MAX_THRHD: u16 = 0x7F; + #[cfg(any(esp32c6, esp32h2))] + const MAX_THRHD: u16 = 0xFF; + #[cfg(any(esp32c3, esp32c2, esp32s2))] + const MAX_THRHD: u16 = 0x1FF; + #[cfg(esp32s3)] + const MAX_THRHD: u16 = 0x3FF; + + if threshold > MAX_THRHD { + return Err(Error::InvalidArgument); + } + + self.register_block() + .conf1() + .modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold as _) }); + + Ok(()) + } + + /// Configures the Receive Timeout detection setting + /// + /// # Arguments + /// `timeout` - the number of symbols ("bytes") to wait for before + /// triggering a timeout. Pass None to disable the timeout. + /// + /// # Errors + /// `Err(Error::InvalidArgument)` if the provided value exceeds the maximum + /// value for SOC : + /// - `esp32`: Symbol size is fixed to 8, do not pass a value > **0x7F**. + /// - `esp32c2`, `esp32c3`, `esp32c6`, `esp32h2`, esp32s2`, esp32s3`: The + /// value you pass times the symbol size must be <= **0x3FF** + fn set_rx_timeout(&self, timeout: Option, _symbol_len: u8) -> Result<(), Error> { + cfg_if::cfg_if! { + if #[cfg(esp32)] { + const MAX_THRHD: u8 = 0x7F; // 7 bits + } else { + const MAX_THRHD: u16 = 0x3FF; // 10 bits + } + } + + let register_block = self.register_block(); + + if let Some(timeout) = timeout { + // the esp32 counts directly in number of symbols (symbol len fixed to 8) + #[cfg(esp32)] + let timeout_reg = timeout; + // all other count in bits, so we need to multiply by the symbol len. + #[cfg(not(esp32))] + let timeout_reg = timeout as u16 * _symbol_len as u16; + + if timeout_reg > MAX_THRHD { + return Err(Error::InvalidArgument); + } + + cfg_if::cfg_if! { + if #[cfg(esp32)] { + let reg_thrhd = register_block.conf1(); + } else if #[cfg(any(esp32c6, esp32h2))] { + let reg_thrhd = register_block.tout_conf(); + } else { + let reg_thrhd = register_block.mem_conf(); + } + } + reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) }); + } + + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2))] { + let reg_en = register_block.tout_conf(); + } else { + let reg_en = register_block.conf1(); + } + } + reg_en.modify(|_, w| w.rx_tout_en().bit(timeout.is_some())); + + self.sync_regs(); + + Ok(()) + } + + #[cfg(any(esp32c2, esp32c3, esp32s3))] + fn change_baud(&self, baudrate: u32, clock_source: ClockSource) { + let clocks = Clocks::get(); + let clk = match clock_source { + ClockSource::Apb => clocks.apb_clock.to_Hz(), + ClockSource::Xtal => clocks.xtal_clock.to_Hz(), + ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), + }; + + if clock_source == ClockSource::RcFast { + unsafe { crate::peripherals::RTC_CNTL::steal() } + .clk_conf() + .modify(|_, w| w.dig_clk8m_en().variant(true)); + // esp_rom_delay_us(SOC_DELAY_RC_FAST_DIGI_SWITCH); + crate::rom::ets_delay_us(5); + } + + let max_div = 0b1111_1111_1111 - 1; + let clk_div = clk.div_ceil(max_div * baudrate); + self.register_block().clk_conf().write(|w| unsafe { + w.sclk_sel().bits(match clock_source { + ClockSource::Apb => 1, + ClockSource::RcFast => 2, + ClockSource::Xtal => 3, + }); + w.sclk_div_a().bits(0); + w.sclk_div_b().bits(0); + w.sclk_div_num().bits(clk_div as u8 - 1); + w.rx_sclk_en().bit(true); + w.tx_sclk_en().bit(true) + }); + + let divider = (clk << 4) / (baudrate * clk_div); + let divider_integer = (divider >> 4) as u16; + let divider_frag = (divider & 0xf) as u8; + self.register_block() + .clkdiv() + .write(|w| unsafe { w.clkdiv().bits(divider_integer).frag().bits(divider_frag) }); + } + + fn is_instance(&self, other: impl Instance) -> bool { + self == other.info() + } + + fn sync_regs(&self) { + sync_regs(self.register_block()); + } + + #[cfg(any(esp32c6, esp32h2))] + fn change_baud(&self, baudrate: u32, clock_source: ClockSource) { + let clocks = Clocks::get(); + let clk = match clock_source { + ClockSource::Apb => clocks.apb_clock.to_Hz(), + ClockSource::Xtal => clocks.xtal_clock.to_Hz(), + ClockSource::RcFast => crate::soc::constants::RC_FAST_CLK.to_Hz(), + }; + + let max_div = 0b1111_1111_1111 - 1; + let clk_div = clk.div_ceil(max_div * baudrate); + + // UART clocks are configured via PCR + let pcr = unsafe { crate::peripherals::PCR::steal() }; + + if self.is_instance(unsafe { crate::peripherals::UART0::steal() }) { + pcr.uart0_conf() + .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); + + pcr.uart0_sclk_conf().modify(|_, w| unsafe { + w.uart0_sclk_div_a().bits(0); + w.uart0_sclk_div_b().bits(0); + w.uart0_sclk_div_num().bits(clk_div as u8 - 1); + w.uart0_sclk_sel().bits(match clock_source { + ClockSource::Apb => 1, + ClockSource::RcFast => 2, + ClockSource::Xtal => 3, + }); + w.uart0_sclk_en().set_bit() + }); + } else { + pcr.uart1_conf() + .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); + + pcr.uart1_sclk_conf().modify(|_, w| unsafe { + w.uart1_sclk_div_a().bits(0); + w.uart1_sclk_div_b().bits(0); + w.uart1_sclk_div_num().bits(clk_div as u8 - 1); + w.uart1_sclk_sel().bits(match clock_source { + ClockSource::Apb => 1, + ClockSource::RcFast => 2, + ClockSource::Xtal => 3, + }); + w.uart1_sclk_en().set_bit() + }); + } + + let clk = clk / clk_div; + let divider = clk / baudrate; + let divider = divider as u16; + + self.register_block() + .clkdiv() + .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); + + self.sync_regs(); + } + + #[cfg(any(esp32, esp32s2))] + fn change_baud(&self, baudrate: u32, clock_source: ClockSource) { + let clk = match clock_source { + ClockSource::Apb => Clocks::get().apb_clock.to_Hz(), + // ESP32(/-S2) TRM, section 3.2.4.2 (6.2.4.2 for S2) + ClockSource::RefTick => crate::soc::constants::REF_TICK.to_Hz(), + }; + + self.register_block() + .conf0() + .modify(|_, w| w.tick_ref_always_on().bit(clock_source == ClockSource::Apb)); + + let divider = clk / baudrate; + + self.register_block() + .clkdiv() + .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); + } + + fn change_data_bits(&self, data_bits: DataBits) { + self.register_block() + .conf0() + .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); + } + + fn change_parity(&self, parity: Parity) { + self.register_block().conf0().modify(|_, w| match parity { + Parity::ParityNone => w.parity_en().clear_bit(), + Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), + Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), + }); + } + + fn change_stop_bits(&self, stop_bits: StopBits) { + #[cfg(esp32)] + { + // workaround for hardware issue, when UART stop bit set as 2-bit mode. + if stop_bits == StopBits::STOP2 { + self.register_block() + .rs485_conf() + .modify(|_, w| w.dl1_en().bit(stop_bits == StopBits::STOP2)); + + self.register_block().conf0().modify(|_, w| { + if stop_bits == StopBits::STOP2 { + unsafe { w.stop_bit_num().bits(1) } + } else { + unsafe { w.stop_bit_num().bits(stop_bits as u8) } + } + }); + } + } + + #[cfg(not(esp32))] + self.register_block() + .conf0() + .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); + } + + fn rxfifo_reset(&self) { + fn rxfifo_rst(reg_block: &RegisterBlock, enable: bool) { + reg_block.conf0().modify(|_, w| w.rxfifo_rst().bit(enable)); + sync_regs(reg_block); + } + + rxfifo_rst(self.register_block(), true); + rxfifo_rst(self.register_block(), false); + } + + fn txfifo_reset(&self) { + fn txfifo_rst(reg_block: &RegisterBlock, enable: bool) { + reg_block.conf0().modify(|_, w| w.txfifo_rst().bit(enable)); + sync_regs(reg_block); + } + + txfifo_rst(self.register_block(), true); + txfifo_rst(self.register_block(), false); + } } impl PartialEq for Info { @@ -2544,7 +2586,7 @@ unsafe impl Sync for Info {} macro_rules! impl_instance { ($inst:ident, $txd:ident, $rxd:ident, $cts:ident, $rts:ident) => { impl Instance for crate::peripherals::$inst { - fn parts(&self) -> (&Info, &State) { + fn parts(&self) -> (&'static Info, &'static State) { #[crate::macros::handler] pub(super) fn irq_handler() { intr_handler(&PERIPHERAL, &STATE); @@ -2591,7 +2633,7 @@ crate::any_peripheral! { impl Instance for AnyUart { #[inline] - fn parts(&self) -> (&Info, &State) { + fn parts(&self) -> (&'static Info, &'static State) { match &self.0 { #[cfg(uart0)] AnyUartInner::Uart0(uart) => uart.parts(), diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index 70728701aad..40d25ef0cfd 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -15,12 +15,7 @@ use esp_backtrace as _; use esp_hal::{ gpio::Io, timer::timg::TimerGroup, - uart::{ - config::{AtCmdConfig, Config}, - Uart, - UartRx, - UartTx, - }, + uart::{AtCmdConfig, Config, Uart, UartRx, UartTx}, Async, }; use static_cell::StaticCell; diff --git a/examples/src/bin/lp_core_uart.rs b/examples/src/bin/lp_core_uart.rs index 4ebe0ff1560..9ecb0de7507 100644 --- a/examples/src/bin/lp_core_uart.rs +++ b/examples/src/bin/lp_core_uart.rs @@ -22,7 +22,7 @@ use esp_hal::{ }, lp_core::{LpCore, LpCoreWakeupSource}, prelude::*, - uart::{config::Config, lp_uart::LpUart, Uart}, + uart::{lp_uart::LpUart, Config, Uart}, }; use esp_println::println; diff --git a/examples/src/bin/serial_interrupts.rs b/examples/src/bin/serial_interrupts.rs index 1ccfb60eda5..daabb9ff27f 100644 --- a/examples/src/bin/serial_interrupts.rs +++ b/examples/src/bin/serial_interrupts.rs @@ -15,11 +15,7 @@ use esp_hal::{ delay::Delay, gpio::Io, prelude::*, - uart::{ - config::{AtCmdConfig, Config}, - Uart, - UartInterrupt, - }, + uart::{AtCmdConfig, Config, Uart, UartInterrupt}, Blocking, }; diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index 5b1a74cb888..00e8be5f739 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -9,7 +9,7 @@ use embedded_hal_02::serial::{Read, Write}; use esp_hal::{ gpio::Io, prelude::*, - uart::{ClockSource, Uart}, + uart::{self, ClockSource, Uart}, Blocking, }; use hil_test as _; @@ -91,8 +91,14 @@ mod tests { ]; let mut byte_to_write = 0xA5; - for (baud, clock_source) in &configs { - ctx.uart.change_baud(*baud, *clock_source); + for (baudrate, clock_source) in configs { + ctx.uart + .apply_config(&uart::Config { + baudrate, + clock_source, + ..Default::default() + }) + .unwrap(); ctx.uart.write(byte_to_write).ok(); let read = block!(ctx.uart.read()); assert_eq!(read, Ok(byte_to_write)); From eabb6fb1c6380bc87a588118ba8f8ec8b539119e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 5 Nov 2024 14:39:19 +0100 Subject: [PATCH 28/67] ETM improvements (#2427) * ETM simplifications * Work with GPIO signals * Fix changelog --- esp-hal/CHANGELOG.md | 7 + esp-hal/MIGRATING-0.21.md | 10 +- esp-hal/src/etm.rs | 20 +- esp-hal/src/gpio/etm.rs | 385 ++++++++++-------------- esp-hal/src/gpio/interconnect.rs | 40 ++- esp-hal/src/timer/systimer.rs | 14 +- esp-hal/src/timer/timg.rs | 56 ++-- examples/src/bin/etm_blinky_systimer.rs | 10 +- examples/src/bin/etm_gpio.rs | 11 +- examples/src/bin/etm_timer.rs | 4 +- 10 files changed, 257 insertions(+), 300 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 46cc9ce3806..af6fddbed60 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `gpio::Output::peripheral_input()` (#2418) - `{Uart, UartRx, UartTx}::apply_config()` (#2449) - `{Uart, UartRx, UartTx}` now implement `embassy_embedded_hal::SetConfig` (#2449) +- GPIO ETM tasks and events now accept `InputSignal` and `OutputSignal` (#2427) ### Changed @@ -78,6 +79,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430) - The `configure_for_async` DMA functions have been removed (#2430) - The `Uart::{change_baud, change_stop_bits}` functions have been removed (#2449) +- `gpio::{Input, Output, OutputOpenDrain, Flex, GpioPin}::{peripheral_input, into_peripheral_output}` have been removed. (#2418) +- The `GpioEtm` prefix has been removed from `gpio::etm` types (#2427) +- The `TimerEtm` prefix has been removed from `timer::timg::etm` types (#2427) +- The `SysTimerEtm` prefix has been removed from `timer::systimer::etm` types (#2427) +- The `GpioEtmEventRising`, `GpioEtmEventFalling`, `GpioEtmEventAny` types have been replaced with `Event` (#2427) +- The `TaskSet`, `TaskClear`, `TaskToggle` types have been replaced with `Task` (#2427) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index edb86927383..9391c1b324b 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -231,6 +231,14 @@ The previous signal function have been replaced by `split`. This change affects `into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead. +## ETM changes + +- The types are no longer prefixed with `GpioEtm`, `TimerEtm` or `SysTimerEtm`. You can still use + import aliasses in case you need to differentiate due to name collisions + (e.g. `use esp_hal::gpio::etm::Event as GpioEtmEvent`). +- The old task and event types have been replaced by `Task` and `Event`. +- GPIO tasks and events are no longer generic. + ## Changes to peripheral configuration ### The `uart::config` module has been removed @@ -243,4 +251,4 @@ The module's contents have been moved into `uart`. ``` If you work with multiple configurable peripherals, you may want to import the `uart` module and -refer to the `Config` struct as `uart::Config`. +refer to the `Config` struct as `uart::Config`. \ No newline at end of file diff --git a/esp-hal/src/etm.rs b/esp-hal/src/etm.rs index 692594c924a..f2c603a67e7 100644 --- a/esp-hal/src/etm.rs +++ b/esp-hal/src/etm.rs @@ -24,10 +24,8 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::gpio::Io; -//! # use esp_hal::gpio::etm::GpioEtmChannels; +//! # use esp_hal::gpio::etm::{Channels, InputConfig, OutputConfig}; //! # use esp_hal::etm::Etm; -//! # use esp_hal::gpio::etm::GpioEtmInputConfig; -//! # use esp_hal::gpio::etm::GpioEtmOutputConfig; //! # use esp_hal::gpio::Pull; //! # use esp_hal::gpio::Level; //! @@ -36,18 +34,18 @@ //! let button = io.pins.gpio9; //! //! // setup ETM -//! let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD); +//! let gpio_ext = Channels::new(peripherals.GPIO_SD); //! let led_task = gpio_ext.channel0_task.toggle( -//! &mut led, -//! GpioEtmOutputConfig { -//! open_drain: false, -//! pull: Pull::None, -//! initial_state: Level::Low, -//! }, +//! &mut led, +//! OutputConfig { +//! open_drain: false, +//! pull: Pull::None, +//! initial_state: Level::Low, +//! }, //! ); //! let button_event = gpio_ext //! .channel0_event -//! .falling_edge(button, GpioEtmInputConfig { pull: Pull::Down }); +//! .falling_edge(button, InputConfig { pull: Pull::Down }); //! //! let etm = Etm::new(peripherals.SOC_ETM); //! let channel0 = etm.channel0; diff --git a/esp-hal/src/gpio/etm.rs b/esp-hal/src/gpio/etm.rs index 262536ad1ee..1cae2982a79 100644 --- a/esp-hal/src/gpio/etm.rs +++ b/esp-hal/src/gpio/etm.rs @@ -26,21 +26,21 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::gpio::Io; -//! # use esp_hal::gpio::etm::GpioEtmChannels; +//! # use esp_hal::gpio::etm::Channels; //! # use esp_hal::etm::Etm; -//! # use esp_hal::gpio::etm::GpioEtmInputConfig; -//! # use esp_hal::gpio::etm::GpioEtmOutputConfig; +//! # use esp_hal::gpio::etm::InputConfig; +//! # use esp_hal::gpio::etm::OutputConfig; //! # use esp_hal::gpio::Pull; //! # use esp_hal::gpio::Level; -//! +//! # //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut led = io.pins.gpio1; //! # let button = io.pins.gpio9; //! -//! let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD); +//! let gpio_ext = Channels::new(peripherals.GPIO_SD); //! let led_task = gpio_ext.channel0_task.toggle( //! &mut led, -//! GpioEtmOutputConfig { +//! OutputConfig { //! open_drain: false, //! pull: Pull::None, //! initial_state: Level::Low, @@ -48,77 +48,84 @@ //! ); //! let button_event = gpio_ext //! .channel0_event -//! .falling_edge(button, GpioEtmInputConfig { pull: Pull::Down }); +//! .falling_edge(button, InputConfig { pull: Pull::Down }); //! # } //! ``` +use core::marker::PhantomData; + use crate::{ - gpio::{Level, Pull}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Level, + Pull, + }, peripheral::{Peripheral, PeripheralRef}, + peripherals::GPIO_SD, private, }; /// All the GPIO ETM channels #[non_exhaustive] -pub struct GpioEtmChannels<'d> { - _gpio_sd: PeripheralRef<'d, crate::peripherals::GPIO_SD>, +pub struct Channels<'d> { + _gpio_sd: PeripheralRef<'d, GPIO_SD>, /// Task channel 0 for triggering GPIO tasks. - pub channel0_task: GpioEtmTaskChannel<0>, + pub channel0_task: TaskChannel<0>, /// Event channel 0 for handling GPIO events. - pub channel0_event: GpioEtmEventChannel<0>, + pub channel0_event: EventChannel<0>, /// Task channel 1 for triggering GPIO tasks. - pub channel1_task: GpioEtmTaskChannel<1>, + pub channel1_task: TaskChannel<1>, /// Event channel 1 for handling GPIO events. - pub channel1_event: GpioEtmEventChannel<1>, + pub channel1_event: EventChannel<1>, /// Task channel 2 for triggering GPIO tasks. - pub channel2_task: GpioEtmTaskChannel<2>, + pub channel2_task: TaskChannel<2>, /// Event channel 2 for handling GPIO events. - pub channel2_event: GpioEtmEventChannel<2>, + pub channel2_event: EventChannel<2>, /// Task channel 3 for triggering GPIO tasks. - pub channel3_task: GpioEtmTaskChannel<3>, + pub channel3_task: TaskChannel<3>, /// Event channel 3 for handling GPIO events. - pub channel3_event: GpioEtmEventChannel<3>, + pub channel3_event: EventChannel<3>, /// Task channel 4 for triggering GPIO tasks. - pub channel4_task: GpioEtmTaskChannel<4>, + pub channel4_task: TaskChannel<4>, /// Event channel 4 for handling GPIO events. - pub channel4_event: GpioEtmEventChannel<4>, + pub channel4_event: EventChannel<4>, /// Task channel 5 for triggering GPIO tasks. - pub channel5_task: GpioEtmTaskChannel<5>, + pub channel5_task: TaskChannel<5>, /// Event channel 5 for handling GPIO events. - pub channel5_event: GpioEtmEventChannel<5>, + pub channel5_event: EventChannel<5>, /// Task channel 6 for triggering GPIO tasks. - pub channel6_task: GpioEtmTaskChannel<6>, + pub channel6_task: TaskChannel<6>, /// Event channel 6 for handling GPIO events. - pub channel6_event: GpioEtmEventChannel<6>, + pub channel6_event: EventChannel<6>, /// Task channel 7 for triggering GPIO tasks. - pub channel7_task: GpioEtmTaskChannel<7>, + pub channel7_task: TaskChannel<7>, /// Event channel 7 for handling GPIO events. - pub channel7_event: GpioEtmEventChannel<7>, + pub channel7_event: EventChannel<7>, } -impl<'d> GpioEtmChannels<'d> { +impl<'d> Channels<'d> { /// Create a new instance - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { + pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _gpio_sd: peripheral, - channel0_task: GpioEtmTaskChannel {}, - channel0_event: GpioEtmEventChannel {}, - channel1_task: GpioEtmTaskChannel {}, - channel1_event: GpioEtmEventChannel {}, - channel2_task: GpioEtmTaskChannel {}, - channel2_event: GpioEtmEventChannel {}, - channel3_task: GpioEtmTaskChannel {}, - channel3_event: GpioEtmEventChannel {}, - channel4_task: GpioEtmTaskChannel {}, - channel4_event: GpioEtmEventChannel {}, - channel5_task: GpioEtmTaskChannel {}, - channel5_event: GpioEtmEventChannel {}, - channel6_task: GpioEtmTaskChannel {}, - channel6_event: GpioEtmEventChannel {}, - channel7_task: GpioEtmTaskChannel {}, - channel7_event: GpioEtmEventChannel {}, + channel0_task: TaskChannel {}, + channel0_event: EventChannel {}, + channel1_task: TaskChannel {}, + channel1_event: EventChannel {}, + channel2_task: TaskChannel {}, + channel2_event: EventChannel {}, + channel3_task: TaskChannel {}, + channel3_event: EventChannel {}, + channel4_task: TaskChannel {}, + channel4_event: EventChannel {}, + channel5_task: TaskChannel {}, + channel5_event: EventChannel {}, + channel6_task: TaskChannel {}, + channel6_event: EventChannel {}, + channel7_task: TaskChannel {}, + channel7_event: EventChannel {}, } } } @@ -126,143 +133,102 @@ impl<'d> GpioEtmChannels<'d> { /// Configuration for an ETM controlled GPIO input pin #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GpioEtmInputConfig { +pub struct InputConfig { /// Configuration for the internal pull-up resistors pub pull: Pull, } -impl Default for GpioEtmInputConfig { +impl Default for InputConfig { fn default() -> Self { Self { pull: Pull::None } } } /// An ETM controlled GPIO event -pub struct GpioEtmEventChannel {} +pub struct EventChannel {} -impl GpioEtmEventChannel { +impl EventChannel { /// Trigger at rising edge - pub fn rising_edge<'d, PIN>( + pub fn rising_edge<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmInputConfig, - ) -> GpioEtmEventChannelRising<'d, PIN, C> - where - PIN: super::InputPin, - { - crate::into_ref!(pin); - - pin.init_input(pin_config.pull, private::Internal); - - enable_event_channel(C, pin.number()); - GpioEtmEventChannelRising { _pin: pin } + pin: impl Peripheral

> + 'd, + pin_config: InputConfig, + ) -> Event<'d> { + self.into_event(pin, pin_config, EventKind::Rising) } /// Trigger at falling edge - pub fn falling_edge<'d, PIN>( + pub fn falling_edge<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmInputConfig, - ) -> GpioEtmEventChannelFalling<'d, PIN, C> - where - PIN: super::InputPin, - { - crate::into_ref!(pin); - - pin.init_input(pin_config.pull, private::Internal); - - enable_event_channel(C, pin.number()); - GpioEtmEventChannelFalling { _pin: pin } + pin: impl Peripheral

> + 'd, + pin_config: InputConfig, + ) -> Event<'d> { + self.into_event(pin, pin_config, EventKind::Falling) } /// Trigger at any edge - pub fn any_edge<'d, PIN>( + pub fn any_edge<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmInputConfig, - ) -> GpioEtmEventChannelAny<'d, PIN, C> - where - PIN: super::InputPin, - { - crate::into_ref!(pin); - - pin.init_input(pin_config.pull, private::Internal); - - enable_event_channel(C, pin.number()); - GpioEtmEventChannelAny { _pin: pin } + pin: impl Peripheral

> + 'd, + pin_config: InputConfig, + ) -> Event<'d> { + self.into_event(pin, pin_config, EventKind::Any) } -} -/// Event for rising edge -#[non_exhaustive] -pub struct GpioEtmEventChannelRising<'d, PIN, const C: u8> -where - PIN: super::Pin, -{ - _pin: PeripheralRef<'d, PIN>, -} + fn into_event<'d>( + self, + pin: impl Peripheral

> + 'd, + pin_config: InputConfig, + kind: EventKind, + ) -> Event<'d> { + crate::into_mapped_ref!(pin); -impl private::Sealed for GpioEtmEventChannelRising<'_, PIN, C> where - PIN: super::Pin -{ -} + pin.init_input(pin_config.pull, private::Internal); -impl crate::etm::EtmEvent for GpioEtmEventChannelRising<'_, PIN, C> -where - PIN: super::Pin, -{ - fn id(&self) -> u8 { - 1 + C + enable_event_channel(C, pin.number()); + Event { + id: kind.id() + C, + _pin: PhantomData, + } } } -/// Event for falling edge -#[non_exhaustive] -pub struct GpioEtmEventChannelFalling<'d, PIN, const C: u8> -where - PIN: super::Pin, -{ - _pin: PeripheralRef<'d, PIN>, -} - -impl private::Sealed for GpioEtmEventChannelFalling<'_, PIN, C> where - PIN: super::Pin -{ +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum EventKind { + Rising, + Falling, + Any, } -impl crate::etm::EtmEvent for GpioEtmEventChannelFalling<'_, PIN, C> -where - PIN: super::Pin, -{ +impl EventKind { fn id(&self) -> u8 { - 9 + C + match self { + EventKind::Rising => 1, + EventKind::Falling => 9, + EventKind::Any => 17, + } } } -/// Event for any edge -#[non_exhaustive] -pub struct GpioEtmEventChannelAny<'d, PIN, const C: u8> -where - PIN: super::Pin, -{ - _pin: PeripheralRef<'d, PIN>, +/// Event for rising edge +pub struct Event<'d> { + _pin: PhantomData<&'d mut ()>, + id: u8, } -impl private::Sealed for GpioEtmEventChannelAny<'_, PIN, C> where PIN: super::Pin {} +impl private::Sealed for Event<'_> {} -impl crate::etm::EtmEvent for GpioEtmEventChannelAny<'_, PIN, C> -where - PIN: super::Pin, -{ +impl crate::etm::EtmEvent for Event<'_> { fn id(&self) -> u8 { - 17 + C + self.id } } /// Configuration for an ETM controlled GPIO output pin #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct GpioEtmOutputConfig { +pub struct OutputConfig { /// Set to open-drain output pub open_drain: bool, /// Only used when open-drain @@ -271,7 +237,7 @@ pub struct GpioEtmOutputConfig { pub initial_state: Level, } -impl Default for GpioEtmOutputConfig { +impl Default for OutputConfig { fn default() -> Self { Self { open_drain: false, @@ -282,70 +248,48 @@ impl Default for GpioEtmOutputConfig { } /// An ETM controlled GPIO task -pub struct GpioEtmTaskChannel {} +pub struct TaskChannel {} -impl GpioEtmTaskChannel { +impl TaskChannel { // In theory we could have multiple pins assigned to the same task. Not sure how // useful that would be. If we want to support it, the easiest would be // to offer additional functions like `set2`, `set3` etc. where the // number is the pin-count /// Task to set a high level - pub fn set<'d, PIN>( + pub fn set<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmOutputConfig, - ) -> GpioEtmTaskSet<'d, PIN, C> - where - PIN: super::OutputPin, - { - crate::into_ref!(pin); - - pin.set_output_high(pin_config.initial_state.into(), private::Internal); - if pin_config.open_drain { - pin.pull_direction(pin_config.pull, private::Internal); - pin.set_to_open_drain_output(private::Internal); - } else { - pin.set_to_push_pull_output(private::Internal); - } - - enable_task_channel(C, pin.number()); - GpioEtmTaskSet { _pin: pin } + pin: impl Peripheral

> + 'd, + pin_config: OutputConfig, + ) -> Task<'d> { + self.into_task(pin, pin_config, TaskKind::Set) } /// Task to set a low level - pub fn clear<'d, PIN>( + pub fn clear<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmOutputConfig, - ) -> GpioEtmTaskClear<'d, PIN, C> - where - PIN: super::OutputPin, - { - crate::into_ref!(pin); - - pin.set_output_high(pin_config.initial_state.into(), private::Internal); - if pin_config.open_drain { - pin.pull_direction(pin_config.pull, private::Internal); - pin.set_to_open_drain_output(private::Internal); - } else { - pin.set_to_push_pull_output(private::Internal); - } - - enable_task_channel(C, pin.number()); - GpioEtmTaskClear { _pin: pin } + pin: impl Peripheral

> + 'd, + pin_config: OutputConfig, + ) -> Task<'d> { + self.into_task(pin, pin_config, TaskKind::Clear) } /// Task to toggle the level - pub fn toggle<'d, PIN>( + pub fn toggle<'d>( + self, + pin: impl Peripheral

> + 'd, + pin_config: OutputConfig, + ) -> Task<'d> { + self.into_task(pin, pin_config, TaskKind::Toggle) + } + + fn into_task<'d>( self, - pin: impl Peripheral

+ 'd, - pin_config: GpioEtmOutputConfig, - ) -> GpioEtmTaskToggle<'d, PIN, C> - where - PIN: super::OutputPin, - { - crate::into_ref!(pin); + pin: impl Peripheral

> + 'd, + pin_config: OutputConfig, + kind: TaskKind, + ) -> Task<'d> { + crate::into_mapped_ref!(pin); pin.set_output_high(pin_config.initial_state.into(), private::Internal); if pin_config.open_drain { @@ -356,66 +300,47 @@ impl GpioEtmTaskChannel { } enable_task_channel(C, pin.number()); - GpioEtmTaskToggle { _pin: pin } - } -} - -/// Task for set operation -#[non_exhaustive] -pub struct GpioEtmTaskSet<'d, PIN, const C: u8> -where - PIN: super::Pin, -{ - _pin: PeripheralRef<'d, PIN>, -} - -impl private::Sealed for GpioEtmTaskSet<'_, PIN, C> where PIN: super::Pin {} - -impl crate::etm::EtmTask for GpioEtmTaskSet<'_, PIN, C> -where - PIN: super::Pin, -{ - fn id(&self) -> u8 { - 1 + C + Task { + id: kind.id() + C, + _pin: PhantomData, + } } } -/// Task for clear operation -#[non_exhaustive] -pub struct GpioEtmTaskClear<'d, PIN, const C: u8> { - _pin: PeripheralRef<'d, PIN>, +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +enum TaskKind { + Set, + Clear, + Toggle, } -impl private::Sealed for GpioEtmTaskClear<'_, PIN, C> where PIN: super::Pin {} - -impl crate::etm::EtmTask for GpioEtmTaskClear<'_, PIN, C> -where - PIN: super::Pin, -{ +impl TaskKind { fn id(&self) -> u8 { - 9 + C + match self { + TaskKind::Set => 1, + TaskKind::Clear => 9, + TaskKind::Toggle => 17, + } } } -/// Task for toggle operation -#[non_exhaustive] -pub struct GpioEtmTaskToggle<'d, PIN, const C: u8> { - _pin: PeripheralRef<'d, PIN>, +/// Task for set operation +pub struct Task<'d> { + _pin: PhantomData<&'d mut ()>, + id: u8, } -impl private::Sealed for GpioEtmTaskToggle<'_, PIN, C> where PIN: super::Pin {} +impl private::Sealed for Task<'_> {} -impl crate::etm::EtmTask for GpioEtmTaskToggle<'_, PIN, C> -where - PIN: super::Pin, -{ +impl crate::etm::EtmTask for Task<'_> { fn id(&self) -> u8 { - 17 + C + self.id } } fn enable_task_channel(channel: u8, pin: u8) { - let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; + let gpio_sd = unsafe { GPIO_SD::steal() }; let ptr = unsafe { gpio_sd.etm_task_p0_cfg().as_ptr().add(pin as usize / 4) }; let shift = 8 * (pin as usize % 4); // bit 0 = en, bit 1-3 = channel @@ -427,7 +352,7 @@ fn enable_task_channel(channel: u8, pin: u8) { } fn enable_event_channel(channel: u8, pin: u8) { - let gpio_sd = unsafe { crate::peripherals::GPIO_SD::steal() }; + let gpio_sd = unsafe { GPIO_SD::steal() }; gpio_sd .etm_event_ch_cfg(channel as usize) .modify(|_, w| w.event_en().clear_bit()); diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index 4f95a927cc1..b86b76c2ae1 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -60,6 +60,15 @@ pub struct InputSignal { is_inverted: bool, } +impl

From

for InputSignal +where + P: InputPin, +{ + fn from(input: P) -> Self { + Self::new(input.degrade()) + } +} + impl Clone for InputSignal { fn clone(&self) -> Self { Self { @@ -87,6 +96,11 @@ impl InputSignal { } } + /// Returns the GPIO number of the underlying pin. + pub fn number(&self) -> u8 { + self.pin.number() + } + /// Returns the current signal level. pub fn get_level(&self) -> Level { self.is_input_high(private::Internal).into() @@ -120,9 +134,7 @@ impl InputSignal { w.in_sel().bits(input) }); } -} -impl InputSignal { /// Connect the pin to a peripheral input signal. /// /// Since there can only be one input signal connected to a peripheral at a @@ -191,6 +203,15 @@ pub struct OutputSignal { is_inverted: bool, } +impl

From

for OutputSignal +where + P: OutputPin, +{ + fn from(input: P) -> Self { + Self::new(input.degrade()) + } +} + impl Peripheral for OutputSignal { type P = Self; @@ -212,6 +233,11 @@ impl OutputSignal { } } + /// Returns the GPIO number of the underlying pin. + pub fn number(&self) -> u8 { + self.pin.number() + } + /// Inverts the peripheral's output signal. /// /// Calling this function multiple times toggles the setting. @@ -268,9 +294,7 @@ impl OutputSignal { w.oen_inv_sel().bit(invert_enable) }); } -} -impl OutputSignal { /// Connect the pin to a peripheral input signal. /// /// Since there can only be one signal connected to a peripheral input at a @@ -434,9 +458,7 @@ where P: InputPin, { fn from(input: P) -> Self { - Self(InputConnectionInner::Input(InputSignal::new( - input.degrade(), - ))) + Self(InputConnectionInner::Input(InputSignal::from(input))) } } @@ -527,9 +549,7 @@ where P: OutputPin, { fn from(input: P) -> Self { - Self(OutputConnectionInner::Output(OutputSignal::new( - input.degrade(), - ))) + Self(OutputConnectionInner::Output(OutputSignal::from(input))) } } diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index fb3fdcb19d0..d2bac3ddf19 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -1104,27 +1104,25 @@ pub mod etm { //! ## Example //! ```rust, no_run #![doc = crate::before_snippet!()] - //! # use esp_hal::timer::systimer::{etm::SysTimerEtmEvent, SystemTimer}; + //! # use esp_hal::timer::systimer::{etm::Event, SystemTimer}; //! # use fugit::ExtU32; //! let syst = SystemTimer::new(peripherals.SYSTIMER); //! let syst_alarms = syst.split(); //! let mut alarm0 = syst_alarms.alarm0.into_periodic(); //! alarm0.set_period(1u32.secs()); //! - //! let timer_event = SysTimerEtmEvent::new(&mut alarm0); + //! let timer_event = Event::new(&mut alarm0); //! # } //! ``` use super::*; /// An ETM controlled SYSTIMER event - pub struct SysTimerEtmEvent<'a, 'd, M, DM: crate::Mode, COMP, UNIT> { + pub struct Event<'a, 'd, M, DM: crate::Mode, COMP, UNIT> { alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>, } - impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> - SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> - { + impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> Event<'a, 'd, M, DM, COMP, UNIT> { /// Creates an ETM event from the given [Alarm] pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>) -> Self { Self { alarm } @@ -1138,12 +1136,12 @@ pub mod etm { } impl crate::private::Sealed - for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT> + for Event<'_, '_, M, DM, COMP, UNIT> { } impl crate::etm::EtmEvent - for SysTimerEtmEvent<'_, '_, M, DM, COMP, UNIT> + for Event<'_, '_, M, DM, COMP, UNIT> { fn id(&self) -> u8 { 50 + self.alarm.comparator.channel() diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 60f4a4bc127..8f67b33db23 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -1349,87 +1349,87 @@ pub mod etm { use crate::etm::{EtmEvent, EtmTask}; /// Event Task Matrix event for a timer. - pub struct TimerEtmEvent { + pub struct Event { id: u8, } /// Event Task Matrix task for a timer. - pub struct TimerEtmTask { + pub struct Task { id: u8, } - impl EtmEvent for TimerEtmEvent { + impl EtmEvent for Event { fn id(&self) -> u8 { self.id } } - impl Sealed for TimerEtmEvent {} + impl Sealed for Event {} - impl EtmTask for TimerEtmTask { + impl EtmTask for Task { fn id(&self) -> u8 { self.id } } - impl Sealed for TimerEtmTask {} + impl Sealed for Task {} /// General purpose timer ETM events. - pub trait TimerEtmEvents { + pub trait Events { /// ETM event triggered on alarm - fn on_alarm(&self) -> TimerEtmEvent; + fn on_alarm(&self) -> Event; } /// General purpose timer ETM tasks - pub trait TimerEtmTasks { + pub trait Tasks { /// ETM task to start the counter - fn cnt_start(&self) -> TimerEtmTask; + fn cnt_start(&self) -> Task; /// ETM task to start the alarm - fn cnt_stop(&self) -> TimerEtmTask; + fn cnt_stop(&self) -> Task; /// ETM task to stop the counter - fn cnt_reload(&self) -> TimerEtmTask; + fn cnt_reload(&self) -> Task; /// ETM task to reload the counter - fn cnt_cap(&self) -> TimerEtmTask; + fn cnt_cap(&self) -> Task; /// ETM task to load the counter with the value stored when the last /// `now()` was called - fn alarm_start(&self) -> TimerEtmTask; + fn alarm_start(&self) -> Task; } - impl TimerEtmEvents for Timer0 + impl Events for Timer0 where TG: TimerGroupInstance, { - fn on_alarm(&self) -> TimerEtmEvent { - TimerEtmEvent { id: 48 + TG::id() } + fn on_alarm(&self) -> Event { + Event { id: 48 + TG::id() } } } - impl TimerEtmTasks for Timer0 + impl Tasks for Timer0 where TG: TimerGroupInstance, { - fn cnt_start(&self) -> TimerEtmTask { - TimerEtmTask { id: 88 + TG::id() } + fn cnt_start(&self) -> Task { + Task { id: 88 + TG::id() } } - fn alarm_start(&self) -> TimerEtmTask { - TimerEtmTask { id: 90 + TG::id() } + fn alarm_start(&self) -> Task { + Task { id: 90 + TG::id() } } - fn cnt_stop(&self) -> TimerEtmTask { - TimerEtmTask { id: 92 + TG::id() } + fn cnt_stop(&self) -> Task { + Task { id: 92 + TG::id() } } - fn cnt_reload(&self) -> TimerEtmTask { - TimerEtmTask { id: 94 + TG::id() } + fn cnt_reload(&self) -> Task { + Task { id: 94 + TG::id() } } - fn cnt_cap(&self) -> TimerEtmTask { - TimerEtmTask { id: 96 + TG::id() } + fn cnt_cap(&self) -> Task { + Task { id: 96 + TG::id() } } } } diff --git a/examples/src/bin/etm_blinky_systimer.rs b/examples/src/bin/etm_blinky_systimer.rs index 0a295c14ab1..65b141bfb51 100644 --- a/examples/src/bin/etm_blinky_systimer.rs +++ b/examples/src/bin/etm_blinky_systimer.rs @@ -12,13 +12,13 @@ use esp_backtrace as _; use esp_hal::{ etm::Etm, gpio::{ - etm::{GpioEtmChannels, GpioEtmOutputConfig}, + etm::{Channels, OutputConfig}, Io, Level, Pull, }, prelude::*, - timer::systimer::{etm::SysTimerEtmEvent, Periodic, SystemTimer}, + timer::systimer::{etm::Event, Periodic, SystemTimer}, }; use fugit::ExtU32; @@ -35,17 +35,17 @@ fn main() -> ! { let mut led = io.pins.gpio1; // setup ETM - let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD); + let gpio_ext = Channels::new(peripherals.GPIO_SD); let led_task = gpio_ext.channel0_task.toggle( &mut led, - GpioEtmOutputConfig { + OutputConfig { open_drain: false, pull: Pull::None, initial_state: Level::High, }, ); - let timer_event = SysTimerEtmEvent::new(&mut alarm0); + let timer_event = Event::new(&mut alarm0); let etm = Etm::new(peripherals.SOC_ETM); let channel0 = etm.channel0; diff --git a/examples/src/bin/etm_gpio.rs b/examples/src/bin/etm_gpio.rs index 112fa2db789..83cf726c4ab 100644 --- a/examples/src/bin/etm_gpio.rs +++ b/examples/src/bin/etm_gpio.rs @@ -12,7 +12,7 @@ use esp_backtrace as _; use esp_hal::{ etm::Etm, gpio::{ - etm::{GpioEtmChannels, GpioEtmInputConfig, GpioEtmOutputConfig}, + etm::{Channels, InputConfig, OutputConfig}, Io, Level, Output, @@ -26,16 +26,17 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let mut led = Output::new(io.pins.gpio1, Level::Low); let button = io.pins.gpio9; led.set_high(); // setup ETM - let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD); + let gpio_ext = Channels::new(peripherals.GPIO_SD); let led_task = gpio_ext.channel0_task.toggle( - &mut led, - GpioEtmOutputConfig { + led, + OutputConfig { open_drain: false, pull: Pull::None, initial_state: Level::Low, @@ -43,7 +44,7 @@ fn main() -> ! { ); let button_event = gpio_ext .channel0_event - .falling_edge(button, GpioEtmInputConfig { pull: Pull::Down }); + .falling_edge(button, InputConfig { pull: Pull::Down }); let etm = Etm::new(peripherals.SOC_ETM); let channel0 = etm.channel0; diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index d382c2755d3..34552926236 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -1,5 +1,5 @@ //! This shows how to use the general purpose timers ETM tasks and events -//! Notice you need to import the traits esp_hal::timer::etm::{TimerEtmEvents, TimerEtmTasks} +//! Notice you need to import the traits esp_hal::timer::etm::{Events, Tasks} //% CHIPS: esp32c6 esp32h2 @@ -16,7 +16,7 @@ use esp_hal::{ peripherals::TIMG0, prelude::*, timer::timg::{ - etm::{TimerEtmEvents, TimerEtmTasks}, + etm::{Events, Tasks}, Timer, Timer0, TimerGroup, From 8860aba9b2acf7de731ea169919ea215227f31b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 10:03:43 +0100 Subject: [PATCH 29/67] Spi master: remove public hidden APIs, add Config/apply_config (#2448) * Remove hidden public SPI API * Fix in_progress flags not being set * Remove redundant checks, fix full-duplex flag * Remove now-redundant Send impl * apply_config * SetConfig * Return ConfigError * Unwrap config result in ctor --- esp-hal/CHANGELOG.md | 4 + esp-hal/MIGRATING-0.21.md | 26 +- esp-hal/src/dma/mod.rs | 11 +- esp-hal/src/spi/master.rs | 823 +++++++++--------- esp-hal/src/spi/slave.rs | 3 +- examples/src/bin/embassy_spi.rs | 28 +- examples/src/bin/qspi_flash.rs | 25 +- .../spi_halfduplex_read_manufacturer_id.rs | 23 +- examples/src/bin/spi_loopback.rs | 22 +- examples/src/bin/spi_loopback_dma.rs | 24 +- examples/src/bin/spi_loopback_dma_psram.rs | 24 +- hil-test/tests/embassy_interrupt_spi_dma.rs | 55 +- hil-test/tests/qspi.rs | 59 +- hil-test/tests/spi_full_duplex.rs | 31 +- hil-test/tests/spi_half_duplex_read.rs | 17 +- hil-test/tests/spi_half_duplex_write.rs | 17 +- hil-test/tests/spi_half_duplex_write_psram.rs | 17 +- 17 files changed, 670 insertions(+), 539 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index af6fddbed60..1733b3b9b7f 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `{Uart, UartRx, UartTx}::apply_config()` (#2449) - `{Uart, UartRx, UartTx}` now implement `embassy_embedded_hal::SetConfig` (#2449) - GPIO ETM tasks and events now accept `InputSignal` and `OutputSignal` (#2427) +- `spi::master::Config` and `{Spi, SpiDma, SpiDmaBus}::apply_config` (#2448) +- `embassy_embedded_hal::SetConfig` is now implemented for `{Spi, SpiDma, SpiDmaBus}` (#2448) ### Changed @@ -50,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) - Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) - UART configuration types have been moved to `esp_hal::uart` (#2449) +- `spi::master::Spi::new()` no longer takes `frequency` and `mode` as a parameter. (#2448) ### Fixed @@ -85,6 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `SysTimerEtm` prefix has been removed from `timer::systimer::etm` types (#2427) - The `GpioEtmEventRising`, `GpioEtmEventFalling`, `GpioEtmEventAny` types have been replaced with `Event` (#2427) - The `TaskSet`, `TaskClear`, `TaskToggle` types have been replaced with `Task` (#2427) +- `{Spi, SpiDma, SpiDmaBus}` configuration methods (#2448) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 9391c1b324b..d490ce16778 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -251,4 +251,28 @@ The module's contents have been moved into `uart`. ``` If you work with multiple configurable peripherals, you may want to import the `uart` module and -refer to the `Config` struct as `uart::Config`. \ No newline at end of file +refer to the `Config` struct as `uart::Config`. + +### SPI drivers can now be configured using `spi::master::Config` + +- The old methods to change configuration have been removed. +- The `new` and `new_typed` constructor no longer takes `frequency` and `mode`. +- The default configuration is now: + - bus frequency: 1 MHz + - bit order: MSB first + - mode: SPI mode 0 +- There are new constructors (`new_with_config`, `new_typed_with_config`) and a new `apply_config` method to apply custom configuration. + +```diff +-use esp_hal::spi::{master::Spi, SpiMode}; ++use esp_hal::spi::{master::{Config, Spi}, SpiMode}; +-Spi::new(SPI2, 100.kHz(), SpiMode::Mode1); ++Spi::new_with_config( ++ SPI2, ++ Config { ++ frequency: 100.kHz(), ++ mode: SpiMode::Mode0, ++ ..Config::default() ++ }, ++) +``` \ No newline at end of file diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index df652f9ff2b..f91b18d1dad 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -19,7 +19,7 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::dma_buffers; //! # use esp_hal::gpio::Io; -//! # use esp_hal::spi::{master::Spi, SpiMode}; +//! # use esp_hal::spi::{master::{Config, Spi}, SpiMode}; //! # use esp_hal::dma::{Dma, DmaPriority}; //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = dma.spi2channel;")] @@ -30,10 +30,13 @@ //! let mosi = io.pins.gpio4; //! let cs = io.pins.gpio5; //! -//! let mut spi = Spi::new( +//! let mut spi = Spi::new_with_config( //! peripherals.SPI2, -//! 100.kHz(), -//! SpiMode::Mode0, +//! Config { +//! frequency: 100.kHz(), +//! mode: SpiMode::Mode0, +//! ..Config::default() +//! }, //! ) //! .with_sck(sclk) //! .with_mosi(mosi) diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index cd906e3fabb..bab494fa82b 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -24,8 +24,9 @@ //! ### Shared SPI access //! //! If you have multiple devices on the same SPI bus that each have their own CS -//! line, you may want to have a look at the implementations provided by -//! [`embedded-hal-bus`] and [`embassy-embedded-hal`]. +//! line (and optionally, configuration), you may want to have a look at the +//! implementations provided by [`embedded-hal-bus`] and +//! [`embassy-embedded-hal`]. //! //! ## Usage //! @@ -38,7 +39,7 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::spi::SpiMode; -//! # use esp_hal::spi::master::Spi; +//! # use esp_hal::spi::master::{Config, Spi}; //! # use esp_hal::gpio::Io; //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! let sclk = io.pins.gpio0; @@ -46,10 +47,13 @@ //! let mosi = io.pins.gpio1; //! let cs = io.pins.gpio5; //! -//! let mut spi = Spi::new( +//! let mut spi = Spi::new_with_config( //! peripherals.SPI2, -//! 100.kHz(), -//! SpiMode::Mode0, +//! Config { +//! frequency: 100.kHz(), +//! mode: SpiMode::Mode0, +//! ..Config::default() +//! }, //! ) //! .with_sck(sclk) //! .with_mosi(mosi) @@ -64,6 +68,7 @@ use core::marker::PhantomData; pub use dma::*; +use embassy_embedded_hal::SetConfig; #[cfg(gdma)] use enumset::EnumSet; #[cfg(gdma)] @@ -435,6 +440,40 @@ impl Address { } } +/// SPI peripheral configuration +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Config { + /// SPI clock frequency + pub frequency: HertzU32, + + /// SPI mode + pub mode: SpiMode, + + /// Bit order of the read data. + pub read_bit_order: SpiBitOrder, + + /// Bit order of the written data. + pub write_bit_order: SpiBitOrder, +} + +impl Default for Config { + fn default() -> Self { + use fugit::RateExtU32; + Config { + frequency: 1_u32.MHz(), + mode: SpiMode::Mode0, + read_bit_order: SpiBitOrder::MSBFirst, + write_bit_order: SpiBitOrder::MSBFirst, + } + } +} + +/// Configuration errors. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConfigError {} + /// SPI peripheral driver pub struct Spi<'d, M, T = AnySpi> { spi: PeripheralRef<'d, T>, @@ -444,7 +483,7 @@ pub struct Spi<'d, M, T = AnySpi> { impl<'d, M, T> Spi<'d, M, T> where M: Mode, - T: InstanceDma, + T: Instance, { /// Configures the SPI instance to use DMA with the specified channel. /// @@ -465,18 +504,22 @@ impl Spi<'_, M, T> where T: Instance, { + fn driver(&self) -> &'static Info { + self.spi.info() + } + /// Read a byte from SPI. /// /// Sends out a stuffing byte for every byte to read. This function doesn't /// perform flushing. If you want to read the response to something you /// have written before, consider using [`Self::transfer`] instead. pub fn read_byte(&mut self) -> nb::Result { - self.spi.read_byte() + self.driver().read_byte() } /// Write a byte to SPI. pub fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { - self.spi.write_byte(word) + self.driver().write_byte(word) } /// Write bytes to SPI. @@ -485,26 +528,30 @@ where /// transmission FIFO. If `words` is longer than 64 bytes, multiple /// sequential transfers are performed. pub fn write_bytes(&mut self, words: &[u8]) -> Result<(), Error> { - self.spi.write_bytes(words)?; - self.spi.flush()?; + self.driver().write_bytes(words)?; + self.driver().flush()?; Ok(()) } /// Sends `words` to the slave. Returns the `words` received from the slave pub fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Error> { - self.spi.transfer(words) + self.driver().transfer(words) } } impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. - pub fn new( + pub fn new(spi: impl Peripheral

+ 'd) -> Spi<'d, Blocking> { + Self::new_with_config(spi, Config::default()) + } + + /// Constructs an SPI instance in 8bit dataframe mode. + pub fn new_with_config( spi: impl Peripheral

+ 'd, - frequency: HertzU32, - mode: SpiMode, + config: Config, ) -> Spi<'d, Blocking> { - Self::new_typed(spi.map_into(), frequency, mode) + Self::new_typed_with_config(spi.map_into(), config) } /// Converts the SPI instance into async mode. @@ -531,52 +578,53 @@ where T: Instance, { /// Constructs an SPI instance in 8bit dataframe mode. - pub fn new_typed( + pub fn new_typed(spi: impl Peripheral

+ 'd) -> Spi<'d, M, T> { + Self::new_typed_with_config(spi, Config::default()) + } + + /// Constructs an SPI instance in 8bit dataframe mode. + pub fn new_typed_with_config( spi: impl Peripheral

+ 'd, - frequency: HertzU32, - mode: SpiMode, + config: Config, ) -> Spi<'d, M, T> { crate::into_ref!(spi); - let mut spi = Spi { + let mut this = Spi { spi, _mode: PhantomData, }; - spi.spi.reset_peripheral(); - spi.spi.enable_peripheral(); - spi.spi.setup(frequency); - spi.spi.init(); - spi.spi.set_data_mode(mode); - let spi = spi + PeripheralClockControl::enable(this.spi.peripheral()); + PeripheralClockControl::reset(this.spi.peripheral()); + + this.driver().init(); + unwrap!(this.apply_config(&config)); // FIXME: update based on the resolution of https://github.com/esp-rs/esp-hal/issues/2416 + + let this = this .with_mosi(NoPin) .with_miso(NoPin) .with_sck(NoPin) .with_cs(NoPin); - let is_qspi = spi.spi.sio2_input_signal().is_some(); + let is_qspi = this.driver().sio2_input.is_some(); if is_qspi { let mut signal = OutputConnection::from(NoPin); - signal.connect_input_to_peripheral( - unwrap!(spi.spi.sio2_input_signal()), - private::Internal, - ); + signal + .connect_input_to_peripheral(unwrap!(this.driver().sio2_input), private::Internal); signal.connect_peripheral_to_output( - unwrap!(spi.spi.sio2_output_signal()), - private::Internal, - ); - signal.connect_input_to_peripheral( - unwrap!(spi.spi.sio3_input_signal()), + unwrap!(this.driver().sio2_output), private::Internal, ); + signal + .connect_input_to_peripheral(unwrap!(this.driver().sio3_input), private::Internal); signal.connect_peripheral_to_output( - unwrap!(spi.spi.sio3_output_signal()), + unwrap!(this.driver().sio3_output), private::Internal, ); } - spi + this } /// Assign the MOSI (Master Out Slave In) pin for the SPI instance. @@ -586,10 +634,10 @@ where pub fn with_mosi(self, mosi: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(mosi); mosi.enable_output(true, private::Internal); - mosi.connect_peripheral_to_output(self.spi.mosi_signal(), private::Internal); + mosi.connect_peripheral_to_output(self.driver().mosi, private::Internal); mosi.enable_input(true, private::Internal); - mosi.connect_input_to_peripheral(self.spi.sio0_input_signal(), private::Internal); + mosi.connect_input_to_peripheral(self.driver().sio0_input, private::Internal); self } @@ -601,10 +649,10 @@ where pub fn with_miso(self, miso: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(miso); miso.enable_input(true, private::Internal); - miso.connect_input_to_peripheral(self.spi.miso_signal(), private::Internal); + miso.connect_input_to_peripheral(self.driver().miso, private::Internal); miso.enable_output(true, private::Internal); - miso.connect_peripheral_to_output(self.spi.sio1_output_signal(), private::Internal); + miso.connect_peripheral_to_output(self.driver().sio1_output, private::Internal); self } @@ -616,7 +664,7 @@ where pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(sclk); sclk.set_to_push_pull_output(private::Internal); - sclk.connect_peripheral_to_output(self.spi.sclk_signal(), private::Internal); + sclk.connect_peripheral_to_output(self.driver().sclk, private::Internal); self } @@ -628,25 +676,27 @@ where pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cs); cs.set_to_push_pull_output(private::Internal); - cs.connect_peripheral_to_output(self.spi.cs_signal(), private::Internal); + cs.connect_peripheral_to_output(self.driver().cs, private::Internal); self } - /// Change the bus frequency of the SPI instance in half-duplex mode. - /// - /// This method allows you to update the bus frequency for the SPI - /// communication after the instance has been created. - pub fn change_bus_frequency(&mut self, frequency: HertzU32) { - self.spi.ch_bus_freq(frequency); + /// Change the bus configuration. + pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.driver().apply_config(config) } +} - /// Set the bit order for the SPI instance. - /// - /// The default is MSB first for both read and write. - pub fn with_bit_order(mut self, read_order: SpiBitOrder, write_order: SpiBitOrder) -> Self { - self.spi.set_bit_order(read_order, write_order); - self +impl SetConfig for Spi<'_, M, T> +where + T: Instance, + M: Mode, +{ + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) } } @@ -666,11 +716,8 @@ where sio2.enable_input(true, private::Internal); sio2.enable_output(true, private::Internal); - sio2.connect_input_to_peripheral(unwrap!(self.spi.sio2_input_signal()), private::Internal); - sio2.connect_peripheral_to_output( - unwrap!(self.spi.sio2_output_signal()), - private::Internal, - ); + sio2.connect_input_to_peripheral(unwrap!(self.driver().sio2_input), private::Internal); + sio2.connect_peripheral_to_output(unwrap!(self.driver().sio2_output), private::Internal); self } @@ -687,11 +734,8 @@ where sio3.enable_input(true, private::Internal); sio3.enable_output(true, private::Internal); - sio3.connect_input_to_peripheral(unwrap!(self.spi.sio3_input_signal()), private::Internal); - sio3.connect_peripheral_to_output( - unwrap!(self.spi.sio3_output_signal()), - private::Internal, - ); + sio3.connect_input_to_peripheral(unwrap!(self.driver().sio3_input), private::Internal); + sio3.connect_peripheral_to_output(unwrap!(self.driver().sio3_output), private::Internal); self } @@ -718,7 +762,7 @@ where return Err(Error::Unsupported); } - self.spi.setup_half_duplex( + self.driver().setup_half_duplex( false, cmd, address, @@ -728,10 +772,10 @@ where data_mode, ); - self.spi.configure_datalen(buffer.len(), 0); - self.spi.start_operation(); - self.spi.flush()?; - self.spi.read_bytes_from_fifo(buffer) + self.driver().configure_datalen(buffer.len(), 0); + self.driver().start_operation(); + self.driver().flush()?; + self.driver().read_bytes_from_fifo(buffer) } /// Half-duplex write. @@ -767,7 +811,7 @@ where } } - self.spi.setup_half_duplex( + self.driver().setup_half_duplex( true, cmd, address, @@ -779,12 +823,12 @@ where if !buffer.is_empty() { // re-using the full-duplex write here - self.spi.write_bytes(buffer)?; + self.driver().write_bytes(buffer)?; } else { - self.spi.start_operation(); + self.driver().start_operation(); } - self.spi.flush() + self.driver().flush() } } @@ -822,7 +866,7 @@ where fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { self.write_bytes(words)?; - self.spi.flush() + self.driver().flush() } } @@ -858,7 +902,7 @@ mod dma { /// embedded-hal traits. pub struct SpiDma<'d, M, T = AnySpi> where - T: InstanceDma, + T: Instance, M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, @@ -869,9 +913,16 @@ mod dma { address_buffer: DmaTxBuf, } + impl crate::private::Sealed for SpiDma<'_, M, T> + where + T: Instance, + M: Mode, + { + } + impl<'d, T> SpiDma<'d, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Converts the SPI instance into async mode. pub fn into_async(self) -> SpiDma<'d, Async, T> { @@ -888,7 +939,7 @@ mod dma { impl<'d, T> SpiDma<'d, Async, T> where - T: InstanceDma, + T: Instance, { /// Converts the SPI instance into async mode. pub fn into_blocking(self) -> SpiDma<'d, Blocking, T> { @@ -903,17 +954,9 @@ mod dma { } } - #[cfg(all(esp32, spi_address_workaround))] - unsafe impl<'d, M, T> Send for SpiDma<'d, M, T> - where - T: InstanceDma, - M: Mode, - { - } - impl core::fmt::Debug for SpiDma<'_, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { /// Formats the `SpiDma` instance for debugging purposes. @@ -927,13 +970,13 @@ mod dma { impl InterruptConfigurable for SpiDma<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Sets the interrupt handler /// /// Interrupts are not enabled at the peripheral level here. fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - let interrupt = self.spi.interrupt(); + let interrupt = self.driver().interrupt; for core in crate::Cpu::other() { crate::interrupt::disable(core, interrupt); } @@ -945,32 +988,32 @@ mod dma { #[cfg(gdma)] impl SpiDma<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Listen for the given interrupts pub fn listen(&mut self, interrupts: impl Into>) { - self.spi.enable_listen(interrupts.into(), true); + self.driver().enable_listen(interrupts.into(), true); } /// Unlisten the given interrupts pub fn unlisten(&mut self, interrupts: impl Into>) { - self.spi.enable_listen(interrupts.into(), false); + self.driver().enable_listen(interrupts.into(), false); } /// Gets asserted interrupts pub fn interrupts(&mut self) -> EnumSet { - self.spi.interrupts() + self.driver().interrupts() } /// Resets asserted interrupts pub fn clear_interrupts(&mut self, interrupts: impl Into>) { - self.spi.clear_interrupts(interrupts.into()); + self.driver().clear_interrupts(interrupts.into()); } } impl<'d, M, T> SpiDma<'d, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, CH, M>) -> Self @@ -986,7 +1029,11 @@ mod dma { [[DmaDescriptor::EMPTY]; SPI_NUM]; static mut BUFFERS: [[u32; 1]; SPI_NUM] = [[0; 1]; SPI_NUM]; - let id = spi.spi_num() as usize - 2; + let id = if spi.info() == unsafe { crate::peripherals::SPI2::steal().info() } { + 0 + } else { + 1 + }; unwrap!(DmaTxBuf::new( unsafe { &mut DESCRIPTORS[id] }, @@ -1004,11 +1051,22 @@ mod dma { } } + fn driver(&self) -> &'static Info { + self.spi.info() + } + + fn dma_driver(&self) -> DmaDriver { + DmaDriver { + info: self.driver(), + dma_peripheral: self.spi.dma_peripheral(), + } + } + fn is_done(&self) -> bool { if self.tx_transfer_in_progress && !self.channel.tx.is_done() { return false; } - if self.spi.busy() { + if self.driver().busy() { return false; } if self.rx_transfer_in_progress { @@ -1070,10 +1128,17 @@ mod dma { rx_buffer: &mut RX, tx_buffer: &mut TX, ) -> Result<(), Error> { - self.rx_transfer_in_progress = rx_buffer.length() > 0; - self.tx_transfer_in_progress = tx_buffer.length() > 0; + let bytes_to_read = rx_buffer.length(); + let bytes_to_write = tx_buffer.length(); + + if bytes_to_read > MAX_DMA_SIZE || bytes_to_write > MAX_DMA_SIZE { + return Err(Error::MaxDmaTransferSizeExceeded); + } + + self.rx_transfer_in_progress = bytes_to_read > 0; + self.tx_transfer_in_progress = bytes_to_write > 0; unsafe { - self.spi.start_transfer_dma( + self.dma_driver().start_transfer_dma( full_duplex, rx_buffer, tx_buffer, @@ -1097,7 +1162,7 @@ mod dma { let addr_bytes = &addr_bytes[4 - bytes_to_write..][..bytes_to_write]; self.address_buffer.fill(addr_bytes); - self.spi.setup_half_duplex( + self.driver().setup_half_duplex( true, cmd, Address::None, @@ -1107,9 +1172,11 @@ mod dma { address.mode(), ); + // FIXME: we could use self.start_transfer_dma if the address buffer was part of + // the (yet-to-be-created) State struct. self.tx_transfer_in_progress = true; unsafe { - self.spi.start_transfer_dma( + self.dma_driver().start_transfer_dma( false, &mut EmptyBuf, &mut self.address_buffer, @@ -1127,8 +1194,7 @@ mod dma { // 1 seems to stop after transmitting the current byte which is somewhat less // impolite. if self.tx_transfer_in_progress || self.rx_transfer_in_progress { - self.spi.configure_datalen(1, 1); - self.spi.update(); + self.dma_driver().abort_transfer(); // We need to stop the DMA transfer, too. if self.tx_transfer_in_progress { @@ -1141,23 +1207,10 @@ mod dma { } } } - } - impl crate::private::Sealed for SpiDma<'_, M, T> - where - T: InstanceDma, - M: Mode, - { - } - - impl<'d, M, T> SpiDma<'d, M, T> - where - T: InstanceDma, - M: Mode, - { - /// Changes the SPI bus frequency for the DMA-enabled SPI instance. - pub fn change_bus_frequency(&mut self, frequency: HertzU32) { - self.spi.ch_bus_freq(frequency); + /// Change the bus configuration. + pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.driver().apply_config(config) } /// Configures the DMA buffers for the SPI instance. @@ -1174,13 +1227,26 @@ mod dma { } } + impl SetConfig for SpiDma<'_, M, T> + where + T: Instance, + M: Mode, + { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } + } + /// A structure representing a DMA transfer for SPI. /// /// This structure holds references to the SPI instance, DMA buffers, and /// transfer status. pub struct SpiDmaTransfer<'d, M, Buf, T = AnySpi> where - T: InstanceDma, + T: Instance, M: Mode, { spi_dma: ManuallyDrop>, @@ -1189,7 +1255,7 @@ mod dma { impl<'d, M, T, Buf> SpiDmaTransfer<'d, M, Buf, T> where - T: InstanceDma, + T: Instance, M: Mode, { fn new(spi_dma: SpiDma<'d, M, T>, dma_buf: Buf) -> Self { @@ -1233,7 +1299,7 @@ mod dma { impl Drop for SpiDmaTransfer<'_, M, Buf, T> where - T: InstanceDma, + T: Instance, M: Mode, { fn drop(&mut self) { @@ -1251,7 +1317,7 @@ mod dma { impl SpiDmaTransfer<'_, Async, Buf, T> where - T: InstanceDma, + T: Instance, { /// Waits for the DMA transfer to complete asynchronously. /// @@ -1263,7 +1329,7 @@ mod dma { impl<'d, M, T> SpiDma<'d, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { /// # Safety: @@ -1272,18 +1338,7 @@ mod dma { /// transfer is in progress. Moving the buffers is allowed. #[cfg_attr(place_spi_driver_in_ram, ram)] unsafe fn start_dma_write(&mut self, buffer: &mut impl DmaTxBuffer) -> Result<(), Error> { - let bytes_to_write = buffer.length(); - if bytes_to_write > MAX_DMA_SIZE { - return Err(Error::MaxDmaTransferSizeExceeded); - } - - self.spi.start_transfer_dma( - true, - &mut EmptyBuf, - buffer, - &mut self.channel.rx, - &mut self.channel.tx, - ) + self.start_dma_transfer(&mut EmptyBuf, buffer) } /// Perform a DMA write. @@ -1311,18 +1366,7 @@ mod dma { /// transfer is in progress. Moving the buffers is allowed. #[cfg_attr(place_spi_driver_in_ram, ram)] unsafe fn start_dma_read(&mut self, buffer: &mut impl DmaRxBuffer) -> Result<(), Error> { - let bytes_to_read = buffer.length(); - if bytes_to_read > MAX_DMA_SIZE { - return Err(Error::MaxDmaTransferSizeExceeded); - } - - self.spi.start_transfer_dma( - false, - buffer, - &mut EmptyBuf, - &mut self.channel.rx, - &mut self.channel.tx, - ) + self.start_dma_transfer(buffer, &mut EmptyBuf) } /// Perform a DMA read. @@ -1353,13 +1397,6 @@ mod dma { rx_buffer: &mut impl DmaRxBuffer, tx_buffer: &mut impl DmaTxBuffer, ) -> Result<(), Error> { - let bytes_to_read = rx_buffer.length(); - let bytes_to_write = tx_buffer.length(); - - if bytes_to_write > MAX_DMA_SIZE || bytes_to_read > MAX_DMA_SIZE { - return Err(Error::MaxDmaTransferSizeExceeded); - } - self.start_transfer_dma(true, rx_buffer, tx_buffer) } @@ -1381,13 +1418,7 @@ mod dma { Err(e) => Err((e, self, rx_buffer, tx_buffer)), } } - } - impl<'d, M, T> SpiDma<'d, M, T> - where - T: InstanceDma, - M: Mode, - { /// # Safety: /// /// The caller must ensure that the buffers are not accessed while the @@ -1402,11 +1433,8 @@ mod dma { buffer: &mut impl DmaRxBuffer, ) -> Result<(), Error> { let bytes_to_read = buffer.length(); - if bytes_to_read > MAX_DMA_SIZE { - return Err(Error::MaxDmaTransferSizeExceeded); - } - self.spi.setup_half_duplex( + self.driver().setup_half_duplex( false, cmd, address, @@ -1416,13 +1444,7 @@ mod dma { data_mode, ); - self.spi.start_transfer_dma( - false, - buffer, - &mut EmptyBuf, - &mut self.channel.rx, - &mut self.channel.tx, - ) + self.start_transfer_dma(false, buffer, &mut EmptyBuf) } /// Perform a half-duplex read operation using DMA. @@ -1460,9 +1482,6 @@ mod dma { buffer: &mut impl DmaTxBuffer, ) -> Result<(), Error> { let bytes_to_write = buffer.length(); - if bytes_to_write > MAX_DMA_SIZE { - return Err(Error::MaxDmaTransferSizeExceeded); - } #[cfg(all(esp32, spi_address_workaround))] { @@ -1473,7 +1492,7 @@ mod dma { } } - self.spi.setup_half_duplex( + self.driver().setup_half_duplex( true, cmd, address, @@ -1483,13 +1502,7 @@ mod dma { data_mode, ); - self.spi.start_transfer_dma( - false, - &mut EmptyBuf, - buffer, - &mut self.channel.rx, - &mut self.channel.tx, - ) + self.start_transfer_dma(false, &mut EmptyBuf, buffer) } /// Perform a half-duplex write operation using DMA. @@ -1520,7 +1533,7 @@ mod dma { /// buffers. pub struct SpiDmaBus<'d, M, T = AnySpi> where - T: InstanceDma, + T: Instance, M: Mode, { @@ -1529,9 +1542,16 @@ mod dma { tx_buf: DmaTxBuf, } + impl crate::private::Sealed for SpiDmaBus<'_, M, T> + where + T: Instance, + M: Mode, + { + } + impl<'d, T> SpiDmaBus<'d, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Converts the SPI instance into async mode. pub fn into_async(self) -> SpiDmaBus<'d, Async, T> { @@ -1545,7 +1565,7 @@ mod dma { impl<'d, T> SpiDmaBus<'d, Async, T> where - T: InstanceDma, + T: Instance, { /// Converts the SPI instance into async mode. pub fn into_blocking(self) -> SpiDmaBus<'d, Blocking, T> { @@ -1559,7 +1579,7 @@ mod dma { impl<'d, M, T> SpiDmaBus<'d, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { /// Creates a new `SpiDmaBus` with the specified SPI instance and DMA @@ -1571,20 +1591,11 @@ mod dma { tx_buf, } } - - fn wait_for_idle(&mut self) { - self.spi_dma.wait_for_idle(); - } - - /// Changes the SPI bus frequency for the DMA-enabled SPI instance. - pub fn change_bus_frequency(&mut self, frequency: HertzU32) { - self.spi_dma.change_bus_frequency(frequency); - } } impl InterruptConfigurable for SpiDmaBus<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Sets the interrupt handler /// @@ -1597,7 +1608,7 @@ mod dma { #[cfg(gdma)] impl SpiDmaBus<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { /// Listen for the given interrupts pub fn listen(&mut self, interrupts: impl Into>) { @@ -1620,18 +1631,20 @@ mod dma { } } - impl crate::private::Sealed for SpiDmaBus<'_, M, T> - where - T: InstanceDma, - M: Mode, - { - } - impl SpiDmaBus<'_, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { + fn wait_for_idle(&mut self) { + self.spi_dma.wait_for_idle(); + } + + /// Change the bus configuration. + pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.spi_dma.apply_config(config) + } + /// Reads data from the SPI bus using DMA. pub fn read(&mut self, words: &mut [u8]) -> Result<(), Error> { self.wait_for_idle(); @@ -1725,13 +1738,7 @@ mod dma { Ok(()) } - } - impl SpiDmaBus<'_, M, T> - where - T: InstanceDma, - M: Mode, - { /// Half-duplex read. pub fn half_duplex_read( &mut self, @@ -1796,9 +1803,22 @@ mod dma { } } + impl SetConfig for SpiDmaBus<'_, M, T> + where + T: Instance, + M: Mode, + { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } + } + impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { type Error = Error; @@ -1810,7 +1830,7 @@ mod dma { impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, Blocking, T> where - T: InstanceDma, + T: Instance, { type Error = Error; @@ -1870,7 +1890,7 @@ mod dma { impl SpiDmaBus<'_, Async, T> where - T: InstanceDma, + T: Instance, { /// Fill the given buffer with data from the bus. pub async fn read_async(&mut self, words: &mut [u8]) -> Result<(), Error> { @@ -1984,7 +2004,7 @@ mod dma { impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T> where - T: InstanceDma, + T: Instance, { async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { self.read_async(words).await @@ -2016,7 +2036,7 @@ mod dma { impl ErrorType for SpiDmaBus<'_, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { type Error = Error; @@ -2024,7 +2044,7 @@ mod dma { impl SpiBus for SpiDmaBus<'_, M, T> where - T: InstanceDma, + T: Instance, M: Mode, { fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { @@ -2066,11 +2086,11 @@ mod ehal1 { T: Instance, { fn read(&mut self) -> nb::Result { - self.spi.read_byte() + self.driver().read_byte() } fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { - self.spi.write_byte(word) + self.driver().write_byte(word) } } @@ -2079,11 +2099,11 @@ mod ehal1 { T: Instance, { fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { - self.spi.read_bytes(words) + self.driver().read_bytes(words) } fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.spi.write_bytes(words) + self.driver().write_bytes(words) } fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { @@ -2122,7 +2142,7 @@ mod ehal1 { if read_inc > 0 { SpiBus::flush(self)?; - self.spi + self.driver() .read_bytes_from_fifo(&mut read[read_from..read_to])?; } @@ -2137,29 +2157,90 @@ mod ehal1 { for chunk in words.chunks_mut(FIFO_SIZE) { SpiBus::write(self, chunk)?; SpiBus::flush(self)?; - self.spi.read_bytes_from_fifo(chunk)?; + self.driver().read_bytes_from_fifo(chunk)?; } Ok(()) } fn flush(&mut self) -> Result<(), Self::Error> { - self.spi.flush() + self.driver().flush() } } } -#[doc(hidden)] -pub trait InstanceDma: Instance + DmaEligible { +/// SPI peripheral instance. +pub trait Instance: + private::Sealed + PeripheralMarker + Into + DmaEligible + 'static +{ + /// Returns the peripheral data describing this SPI instance. + fn info(&self) -> &'static Info; +} + +/// Marker trait for QSPI-capable SPI peripherals. +pub trait QspiInstance: Instance {} + +/// Peripheral data describing a particular SPI instance. +pub struct Info { + /// Pointer to the register block for this SPI instance. + /// + /// Use [Self::register_block] to access the register block. + pub register_block: *const RegisterBlock, + + /// Interrupt for this SPI instance. + pub interrupt: crate::peripherals::Interrupt, + + /// SCLK signal. + pub sclk: OutputSignal, + + /// MOSI signal. + pub mosi: OutputSignal, + + /// MISO signal. + pub miso: InputSignal, + + /// Chip select signal. + pub cs: OutputSignal, + + /// SIO0 (MOSI) input signal for half-duplex mode. + pub sio0_input: InputSignal, + + /// SIO1 (MISO) output signal for half-duplex mode. + pub sio1_output: OutputSignal, + + /// SIO2 output signal for QSPI mode. + pub sio2_output: Option, + + /// SIO2 input signal for QSPI mode. + pub sio2_input: Option, + + /// SIO3 output signal for QSPI mode. + pub sio3_output: Option, + + /// SIO3 input signal for QSPI mode. + pub sio3_input: Option, +} + +struct DmaDriver { + info: &'static Info, + dma_peripheral: crate::dma::DmaPeripheral, +} + +impl DmaDriver { + fn abort_transfer(&self) { + self.info.configure_datalen(1, 1); + self.info.update(); + } + #[cfg_attr(place_spi_driver_in_ram, ram)] unsafe fn start_transfer_dma( - &mut self, + &self, _full_duplex: bool, rx_buffer: &mut impl DmaRxBuffer, tx_buffer: &mut impl DmaTxBuffer, rx: &mut RX, tx: &mut TX, ) -> Result<(), Error> { - let reg_block = self.register_block(); + let reg_block = self.info.register_block(); #[cfg(esp32s2)] { @@ -2170,7 +2251,7 @@ pub trait InstanceDma: Instance + DmaEligible { let rx_len = rx_buffer.length(); let tx_len = tx_buffer.length(); - self.configure_datalen(rx_len, tx_len); + self.info.configure_datalen(rx_len, tx_len); // enable the MISO and MOSI if needed reg_block @@ -2180,7 +2261,7 @@ pub trait InstanceDma: Instance + DmaEligible { self.enable_dma(); if rx_len > 0 { - rx.prepare_transfer(self.dma_peripheral(), rx_buffer) + rx.prepare_transfer(self.dma_peripheral, rx_buffer) .and_then(|_| rx.start_transfer())?; } else { #[cfg(esp32)] @@ -2198,14 +2279,14 @@ pub trait InstanceDma: Instance + DmaEligible { } } if tx_len > 0 { - tx.prepare_transfer(self.dma_peripheral(), tx_buffer) + tx.prepare_transfer(self.dma_peripheral, tx_buffer) .and_then(|_| tx.start_transfer())?; } #[cfg(gdma)] self.reset_dma(); - self.start_operation(); + self.info.start_operation(); Ok(()) } @@ -2214,7 +2295,7 @@ pub trait InstanceDma: Instance + DmaEligible { #[cfg(gdma)] { // for non GDMA this is done in `assign_tx_device` / `assign_rx_device` - let reg_block = self.register_block(); + let reg_block = self.info.register_block(); reg_block.dma_conf().modify(|_, w| { w.dma_tx_ena().set_bit(); w.dma_rx_ena().set_bit() @@ -2240,7 +2321,7 @@ pub trait InstanceDma: Instance + DmaEligible { w.dma_afifo_rst().bit(bit) }); } - let reg_block = self.register_block(); + let reg_block = self.info.register_block(); set_reset_bit(reg_block, true); set_reset_bit(reg_block, false); self.clear_dma_interrupts(); @@ -2248,7 +2329,7 @@ pub trait InstanceDma: Instance + DmaEligible { #[cfg(gdma)] fn clear_dma_interrupts(&self) { - let reg_block = self.register_block(); + let reg_block = self.info.register_block(); reg_block.dma_int_clr().write(|w| { w.dma_infifo_full_err().clear_bit_by_one(); w.dma_outfifo_empty_err().clear_bit_by_one(); @@ -2260,7 +2341,7 @@ pub trait InstanceDma: Instance + DmaEligible { #[cfg(pdma)] fn clear_dma_interrupts(&self) { - let reg_block = self.register_block(); + let reg_block = self.info.register_block(); reg_block.dma_int_clr().write(|w| { w.inlink_dscr_empty().clear_bit_by_one(); w.outlink_dscr_error().clear_bit_by_one(); @@ -2275,43 +2356,16 @@ pub trait InstanceDma: Instance + DmaEligible { } } -impl InstanceDma for crate::peripherals::SPI2 {} - -#[cfg(spi3)] -impl InstanceDma for crate::peripherals::SPI3 {} - -#[doc(hidden)] -pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static { - fn register_block(&self) -> &RegisterBlock; - - fn sclk_signal(&self) -> OutputSignal; - fn mosi_signal(&self) -> OutputSignal; - fn miso_signal(&self) -> InputSignal; - fn cs_signal(&self) -> OutputSignal; - - fn sio0_input_signal(&self) -> InputSignal; - fn sio1_output_signal(&self) -> OutputSignal; - fn sio2_output_signal(&self) -> Option; - fn sio2_input_signal(&self) -> Option; - fn sio3_output_signal(&self) -> Option; - fn sio3_input_signal(&self) -> Option; - - fn interrupt(&self) -> crate::peripherals::Interrupt; - - #[inline(always)] - fn enable_peripheral(&self) { - PeripheralClockControl::enable(self.peripheral()); +// private implementation bits +// FIXME: split this up into peripheral versions +impl Info { + /// Returns the register block for this SPI instance. + pub fn register_block(&self) -> &RegisterBlock { + unsafe { &*self.register_block } } - #[inline(always)] - fn reset_peripheral(&self) { - PeripheralClockControl::reset(self.peripheral()); - } - - fn spi_num(&self) -> u8; - /// Initialize for full-duplex 1 bit mode - fn init(&mut self) { + fn init(&self) { let reg_block = self.register_block(); reg_block.user().modify(|_, w| { w.usr_miso_highpart().clear_bit(); @@ -2336,7 +2390,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static unsafe { // use default clock source PLL_F80M_CLK (ESP32-C6) and // PLL_F48M_CLK (ESP32-H2) - (*crate::peripherals::PCR::PTR) + crate::peripherals::PCR::steal() .spi2_clkm_conf() .modify(|_, w| w.spi2_clkm_sel().bits(1)); } @@ -2366,7 +2420,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static #[cfg(not(esp32))] fn init_spi_data_mode( - &mut self, + &self, cmd_mode: SpiDataMode, address_mode: SpiDataMode, data_mode: SpiDataMode, @@ -2388,7 +2442,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static #[cfg(esp32)] fn init_spi_data_mode( - &mut self, + &self, cmd_mode: SpiDataMode, address_mode: SpiDataMode, data_mode: SpiDataMode, @@ -2436,7 +2490,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } // taken from https://github.com/apache/incubator-nuttx/blob/8267a7618629838231256edfa666e44b5313348e/arch/risc-v/src/esp32c3/esp32c3_spi.c#L496 - fn setup(&mut self, frequency: HertzU32) { + fn setup(&self, frequency: HertzU32) { let clocks = Clocks::get(); cfg_if::cfg_if! { if #[cfg(esp32h2)] { @@ -2525,7 +2579,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// Enable or disable listening for the given interrupts. #[cfg(gdma)] - fn enable_listen(&mut self, interrupts: EnumSet, enable: bool) { + fn enable_listen(&self, interrupts: EnumSet, enable: bool) { let reg_block = self.register_block(); reg_block.dma_int_ena().modify(|_, w| { @@ -2540,7 +2594,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// Gets asserted interrupts #[cfg(gdma)] - fn interrupts(&mut self) -> EnumSet { + fn interrupts(&self) -> EnumSet { let mut res = EnumSet::new(); let reg_block = self.register_block(); @@ -2555,7 +2609,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// Resets asserted interrupts #[cfg(gdma)] - fn clear_interrupts(&mut self, interrupts: EnumSet) { + fn clear_interrupts(&self, interrupts: EnumSet) { let reg_block = self.register_block(); reg_block.dma_int_clr().write(|w| { @@ -2568,7 +2622,14 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static }); } - fn set_data_mode(&mut self, data_mode: SpiMode) -> &mut Self { + fn apply_config(&self, config: &Config) -> Result<(), ConfigError> { + self.ch_bus_freq(config.frequency); + self.set_bit_order(config.read_bit_order, config.write_bit_order); + self.set_data_mode(config.mode); + Ok(()) + } + + fn set_data_mode(&self, data_mode: SpiMode) { let reg_block = self.register_block(); cfg_if::cfg_if! { @@ -2587,11 +2648,9 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static w.ck_out_edge() .bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode2)) }); - - self } - fn ch_bus_freq(&mut self, frequency: HertzU32) { + fn ch_bus_freq(&self, frequency: HertzU32) { fn enable_clocks(_reg_block: &RegisterBlock, _enable: bool) { #[cfg(gdma)] _reg_block.clk_gate().modify(|_, w| { @@ -2610,7 +2669,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } #[cfg(not(any(esp32, esp32c3, esp32s2)))] - fn set_bit_order(&mut self, read_order: SpiBitOrder, write_order: SpiBitOrder) { + fn set_bit_order(&self, read_order: SpiBitOrder, write_order: SpiBitOrder) { let reg_block = self.register_block(); let read_value = match read_order { @@ -2627,8 +2686,9 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static w }); } + #[cfg(any(esp32, esp32c3, esp32s2))] - fn set_bit_order(&mut self, read_order: SpiBitOrder, write_order: SpiBitOrder) { + fn set_bit_order(&self, read_order: SpiBitOrder, write_order: SpiBitOrder) { let reg_block = self.register_block(); let read_value = match read_order { @@ -2646,7 +2706,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static }); } - fn read_byte(&mut self) -> nb::Result { + fn read_byte(&self) -> nb::Result { if self.busy() { return Err(nb::Error::WouldBlock); } @@ -2655,7 +2715,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static Ok(u32::try_into(reg_block.w(0).read().bits()).unwrap_or_default()) } - fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { + fn write_byte(&self, word: u8) -> nb::Result<(), Error> { if self.busy() { return Err(nb::Error::WouldBlock); } @@ -2679,7 +2739,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// you must ensure that the whole messages was written correctly, use /// [`Self::flush`]. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn write_bytes(&mut self, words: &[u8]) -> Result<(), Error> { + fn write_bytes(&self, words: &[u8]) -> Result<(), Error> { let num_chunks = words.len() / FIFO_SIZE; // Flush in case previous writes have not completed yet, required as per @@ -2736,7 +2796,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// perform flushing. If you want to read the response to something you /// have written before, consider using [`Self::transfer`] instead. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn read_bytes(&mut self, words: &mut [u8]) -> Result<(), Error> { + fn read_bytes(&self, words: &mut [u8]) -> Result<(), Error> { let empty_array = [EMPTY_WRITE_PAD; FIFO_SIZE]; for chunk in words.chunks_mut(FIFO_SIZE) { @@ -2754,7 +2814,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static /// something you have written before, consider using [`Self::transfer`] /// instead. #[cfg_attr(place_spi_driver_in_ram, ram)] - fn read_bytes_from_fifo(&mut self, words: &mut [u8]) -> Result<(), Error> { + fn read_bytes_from_fifo(&self, words: &mut [u8]) -> Result<(), Error> { let reg_block = self.register_block(); for chunk in words.chunks_mut(FIFO_SIZE) { @@ -2778,7 +2838,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } // Check if the bus is busy and if it is wait for it to be idle - fn flush(&mut self) -> Result<(), Error> { + fn flush(&self) -> Result<(), Error> { while self.busy() { // wait for bus to be clear } @@ -2786,7 +2846,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } #[cfg_attr(place_spi_driver_in_ram, ram)] - fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Error> { + fn transfer<'w>(&self, words: &'w mut [u8]) -> Result<&'w [u8], Error> { for chunk in words.chunks_mut(FIFO_SIZE) { self.write_bytes(chunk)?; self.flush()?; @@ -2804,7 +2864,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static #[allow(clippy::too_many_arguments)] fn setup_half_duplex( - &mut self, + &self, is_write: bool, cmd: Command, address: Address, @@ -2838,7 +2898,7 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static #[cfg(any(esp32c6, esp32h2))] unsafe { - let pcr = &*crate::peripherals::PCR::PTR; + let pcr = crate::peripherals::PCR::steal(); // use default clock source PLL_F80M_CLK pcr.spi2_clkm_conf() @@ -2853,7 +2913,37 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static self.update(); // set cmd, address, dummy cycles - set_up_common_phases(reg_block, cmd, address, dummy); + self.set_up_common_phases(cmd, address, dummy); + } + + fn set_up_common_phases(&self, cmd: Command, address: Address, dummy: u8) { + let reg_block = self.register_block(); + if !cmd.is_none() { + reg_block.user2().modify(|_, w| unsafe { + w.usr_command_bitlen().bits((cmd.width() - 1) as u8); + w.usr_command_value().bits(cmd.value()) + }); + } + + if !address.is_none() { + reg_block + .user1() + .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) }); + + let addr = address.value() << (32 - address.width()); + #[cfg(not(esp32))] + reg_block + .addr() + .write(|w| unsafe { w.usr_addr_value().bits(addr) }); + #[cfg(esp32)] + reg_block.addr().write(|w| unsafe { w.bits(addr) }); + } + + if dummy > 0 { + reg_block + .user1() + .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) }); + } } fn update(&self) { @@ -2911,38 +3001,14 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } } -#[doc(hidden)] -pub trait QspiInstance: Instance {} - -fn set_up_common_phases(reg_block: &RegisterBlock, cmd: Command, address: Address, dummy: u8) { - if !cmd.is_none() { - reg_block.user2().modify(|_, w| unsafe { - w.usr_command_bitlen().bits((cmd.width() - 1) as u8); - w.usr_command_value().bits(cmd.value()) - }); - } - - if !address.is_none() { - reg_block - .user1() - .modify(|_, w| unsafe { w.usr_addr_bitlen().bits((address.width() - 1) as u8) }); - - let addr = address.value() << (32 - address.width()); - #[cfg(not(esp32))] - reg_block - .addr() - .write(|w| unsafe { w.usr_addr_value().bits(addr) }); - #[cfg(esp32)] - reg_block.addr().write(|w| unsafe { w.bits(addr) }); - } - - if dummy > 0 { - reg_block - .user1() - .modify(|_, w| unsafe { w.usr_dummy_cyclelen().bits(dummy - 1) }); +impl PartialEq for Info { + fn eq(&self, other: &Self) -> bool { + self.register_block == other.register_block } } +unsafe impl Sync for Info {} + macro_rules! spi_instance { (@ignore $sio2:ident) => {}; @@ -2950,68 +3016,23 @@ macro_rules! spi_instance { paste::paste! { impl Instance for crate::peripherals::[] { #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } - - #[inline(always)] - fn spi_num(&self) -> u8 { - $num - } - - #[inline(always)] - fn interrupt(&self) -> crate::peripherals::Interrupt { - crate::peripherals::Interrupt::[] - } - - #[inline(always)] - fn sclk_signal(&self) -> OutputSignal { - OutputSignal::$sclk - } - - #[inline(always)] - fn mosi_signal(&self) -> OutputSignal { - OutputSignal::$mosi - } - - #[inline(always)] - fn miso_signal(&self) -> InputSignal { - InputSignal::$miso - } - - #[inline(always)] - fn cs_signal(&self) -> OutputSignal { - OutputSignal::$cs - } - - #[inline(always)] - fn sio0_input_signal(&self) -> InputSignal { - InputSignal::$mosi - } - - #[inline(always)] - fn sio1_output_signal(&self) -> OutputSignal { - OutputSignal::$miso - } - - #[inline(always)] - fn sio2_output_signal(&self) -> Option { - if_set!($(Some(OutputSignal::$sio2))?, None) - } - - #[inline(always)] - fn sio2_input_signal(&self) -> Option { - if_set!($(Some(InputSignal::$sio2))?, None) - } - - #[inline(always)] - fn sio3_output_signal(&self) -> Option { - if_set!($(Some(OutputSignal::$sio3))?, None) - } - - #[inline(always)] - fn sio3_input_signal(&self) -> Option { - if_set!($(Some(InputSignal::$sio3))?, None) + fn info(&self) -> &'static Info { + static INFO: Info = Info { + register_block: crate::peripherals::[]::PTR, + interrupt: crate::peripherals::Interrupt::[], + sclk: OutputSignal::$sclk, + mosi: OutputSignal::$mosi, + miso: InputSignal::$miso, + cs: OutputSignal::$cs, + sio0_input: InputSignal::$mosi, + sio1_output: OutputSignal::$miso, + sio2_output: if_set!($(Some(OutputSignal::$sio2))?, None), + sio2_input: if_set!($(Some(InputSignal::$sio2))?, None), + sio3_output: if_set!($(Some(OutputSignal::$sio3))?, None), + sio3_input: if_set!($(Some(InputSignal::$sio3))?, None), + }; + + &INFO } } @@ -3064,35 +3085,9 @@ impl Instance for super::AnySpi { #[cfg(spi3)] super::AnySpiInner::Spi3(spi) => spi, } { - fn register_block(&self) -> &RegisterBlock; - fn spi_num(&self) -> u8; - fn sclk_signal(&self) -> OutputSignal; - fn mosi_signal(&self) -> OutputSignal; - fn miso_signal(&self) -> InputSignal; - fn cs_signal(&self) -> OutputSignal; - - fn sio0_input_signal(&self) -> InputSignal; - fn sio1_output_signal(&self) -> OutputSignal; - fn sio2_output_signal(&self) -> Option; - fn sio2_input_signal(&self) -> Option; - fn sio3_output_signal(&self) -> Option; - fn sio3_input_signal(&self) -> Option; - - fn interrupt(&self) -> crate::peripherals::Interrupt; + fn info(&self) -> &'static Info; } } } impl QspiInstance for super::AnySpi {} - -impl InstanceDma for super::AnySpi { - delegate::delegate! { - to match &self.0 { - super::AnySpiInner::Spi2(spi) => spi, - #[cfg(spi3)] - super::AnySpiInner::Spi3(spi) => spi, - } { - fn clear_dma_interrupts(&self); - } - } -} diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 8bea967bda6..a4e190ecd5a 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -31,7 +31,8 @@ //! let cs = io.pins.gpio3; //! //! let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = -//! dma_buffers!(32000); let mut spi = Spi::new( +//! dma_buffers!(32000); +//! let mut spi = Spi::new( //! peripherals.SPI2, //! sclk, //! mosi, diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 2ae0afe977a..702b30046de 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -26,7 +26,10 @@ use esp_hal::{ dma_buffers, gpio::Io, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{Config, Spi}, + SpiMode, + }, timer::timg::TimerGroup, }; @@ -58,14 +61,21 @@ async fn main(_spawner: Spawner) { let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_miso(miso) - .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf) - .into_async(); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_cs(cs) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7]; loop { diff --git a/examples/src/bin/qspi_flash.rs b/examples/src/bin/qspi_flash.rs index 687b28ba18f..cd901df7c31 100644 --- a/examples/src/bin/qspi_flash.rs +++ b/examples/src/bin/qspi_flash.rs @@ -35,7 +35,7 @@ use esp_hal::{ gpio::Io, prelude::*, spi::{ - master::{Address, Command, Spi}, + master::{Address, Command, Config, Spi}, SpiDataMode, SpiMode, }, @@ -79,14 +79,21 @@ fn main() -> ! { let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_miso(miso) - .with_sio2(sio2) - .with_sio3(sio3) - .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_sio2(sio2) + .with_sio3(sio3) + .with_cs(cs) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); let delay = Delay::new(); diff --git a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs index c6dba002afc..28266b67e93 100644 --- a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs +++ b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs @@ -33,7 +33,7 @@ use esp_hal::{ gpio::Io, prelude::*, spi::{ - master::{Address, Command, Spi}, + master::{Address, Command, Config, Spi}, SpiDataMode, SpiMode, }, @@ -63,13 +63,20 @@ fn main() -> ! { } } - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_miso(miso) - .with_sio2(sio2) - .with_sio3(sio3) - .with_cs(cs); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_sio2(sio2) + .with_sio3(sio3) + .with_cs(cs); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback.rs b/examples/src/bin/spi_loopback.rs index 0900d031d9f..38e9d6f1ed6 100644 --- a/examples/src/bin/spi_loopback.rs +++ b/examples/src/bin/spi_loopback.rs @@ -21,7 +21,10 @@ use esp_hal::{ gpio::Io, peripheral::Peripheral, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{Config, Spi}, + SpiMode, + }, }; use esp_println::println; @@ -36,11 +39,18 @@ fn main() -> ! { let miso = unsafe { miso_mosi.clone_unchecked() }; - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(miso_mosi) - .with_miso(miso) - .with_cs(cs); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(miso_mosi) + .with_miso(miso) + .with_cs(cs); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback_dma.rs b/examples/src/bin/spi_loopback_dma.rs index f081478da36..e9bc827ff7a 100644 --- a/examples/src/bin/spi_loopback_dma.rs +++ b/examples/src/bin/spi_loopback_dma.rs @@ -25,7 +25,10 @@ use esp_hal::{ dma_buffers, gpio::Io, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{Config, Spi}, + SpiMode, + }, }; use esp_println::println; @@ -53,12 +56,19 @@ fn main() -> ! { let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_miso(miso) - .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_cs(cs) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback_dma_psram.rs b/examples/src/bin/spi_loopback_dma_psram.rs index 1ae30408518..0ee76893cd8 100644 --- a/examples/src/bin/spi_loopback_dma_psram.rs +++ b/examples/src/bin/spi_loopback_dma_psram.rs @@ -29,7 +29,10 @@ use esp_hal::{ gpio::Io, peripheral::Peripheral, prelude::*, - spi::{master::Spi, SpiMode}, + spi::{ + master::{Config, Spi}, + SpiMode, + }, }; extern crate alloc; use log::*; @@ -90,12 +93,19 @@ fn main() -> ! { let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); // Need to set miso first so that mosi can overwrite the // output connection (because we are using the same pin to loop back) - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_miso(miso) - .with_mosi(mosi) - .with_cs(cs) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_miso(miso) + .with_mosi(mosi) + .with_cs(cs) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); delay.delay_millis(100); // delay to let the above messages display diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index fc6580a12f8..85dc6edacf8 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -14,7 +14,7 @@ use esp_hal::{ interrupt::{software::SoftwareInterruptControl, Priority}, prelude::*, spi::{ - master::{Spi, SpiDma}, + master::{Config, Spi, SpiDma}, SpiMode, }, timer::AnyTimer, @@ -94,14 +94,28 @@ mod test { let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf) - .into_async(); - - let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0) - .with_dma(dma_channel2.configure(false, DmaPriority::Priority0)) - .into_async(); + let mut spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); + + let spi2 = Spi::new_with_config( + peripherals.SPI3, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_dma(dma_channel2.configure(false, DmaPriority::Priority0)) + .into_async(); let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); @@ -156,14 +170,21 @@ mod test { let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new(peripherals.spi, 100.kHz(), SpiMode::Mode0) - .with_dma( - peripherals - .dma_channel - .configure(false, DmaPriority::Priority0), - ) - .with_buffers(dma_rx_buf, dma_tx_buf) - .into_async(); + let mut spi = Spi::new_with_config( + peripherals.spi, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_dma( + peripherals + .dma_channel + .configure(false, DmaPriority::Priority0), + ) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]); loop { diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 9322a7b052d..8b61a26dd57 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -13,7 +13,7 @@ use esp_hal::{ gpio::{AnyPin, Input, Io, Level, Output, Pull}, prelude::*, spi::{ - master::{Address, Command, Spi, SpiDma}, + master::{Address, Command, Config, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -40,7 +40,7 @@ cfg_if::cfg_if! { type SpiUnderTest = SpiDma<'static, Blocking>; struct Context { - spi: esp_hal::peripherals::SPI2, + spi: Spi<'static, Blocking>, #[cfg(pcnt)] pcnt: esp_hal::peripherals::PCNT, dma_channel: Channel<'static, DmaChannel0, Blocking>, @@ -205,9 +205,17 @@ mod tests { } let dma_channel = dma_channel.configure(false, DmaPriority::Priority0); + let spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ); Context { - spi: peripherals.SPI2, + spi, #[cfg(pcnt)] pcnt: peripherals.PCNT, dma_channel, @@ -225,9 +233,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_mosi(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_mosi(pin).with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0001_0001); } @@ -238,9 +244,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_miso(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_miso(pin).with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0010_0010); } @@ -251,9 +255,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_sio2(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_sio2(pin).with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0100_0100); } @@ -264,9 +266,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_sio3(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_sio3(pin).with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b1000_1000); } @@ -277,9 +277,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_mosi(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_mosi(pin).with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0001_0001); } @@ -290,9 +288,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_miso(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_miso(pin).with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0010_0010); } @@ -303,9 +299,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_sio2(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_sio2(pin).with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0100_0100); } @@ -316,9 +310,7 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_sio3(pin) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_sio3(pin).with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b1000_1000); } @@ -342,9 +334,7 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_mosi(mosi) - .with_dma(ctx.dma_channel); + let spi = ctx.spi.with_mosi(mosi).with_dma(ctx.dma_channel); super::execute_write(unit0, unit1, spi, 0b0000_0001, false); } @@ -374,7 +364,8 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + let spi = ctx + .spi .with_mosi(mosi) .with_miso(gpio) .with_dma(ctx.dma_channel); @@ -407,7 +398,8 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + let spi = ctx + .spi .with_mosi(mosi) .with_sio2(gpio) .with_dma(ctx.dma_channel); @@ -440,7 +432,8 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + let spi = ctx + .spi .with_mosi(mosi) .with_sio3(gpio) .with_dma(ctx.dma_channel); diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 2d465a25b86..a4211f71991 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -17,7 +17,7 @@ use esp_hal::{ gpio::{Io, Level, NoPin}, peripheral::Peripheral, prelude::*, - spi::{master::Spi, SpiMode}, + spi::master::{Config, Spi}, Blocking, }; #[cfg(pcnt)] @@ -76,10 +76,16 @@ mod tests { let (mosi_loopback_pcnt, mosi) = mosi.split(); // Need to set miso first so that mosi can overwrite the // output connection (because we are using the same pin to loop back) - let spi = Spi::new(peripherals.SPI2, 10000.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_miso(unsafe { mosi.clone_unchecked() }) - .with_mosi(mosi); + let spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 10.MHz(), + ..Config::default() + }, + ) + .with_sck(sclk) + .with_miso(unsafe { mosi.clone_unchecked() }) + .with_mosi(mosi); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(32000); @@ -491,7 +497,10 @@ mod tests { // Slow down. At 80kHz, the transfer is supposed to take a bit over 3 seconds. // This means that without working cancellation, the test case should // fail. - ctx.spi.change_bus_frequency(80.kHz()); + ctx.spi.apply_config(&Config { + frequency: 80.kHz(), + ..Config::default() + }); // Set up a large buffer that would trigger a timeout let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); @@ -514,7 +523,10 @@ mod tests { #[timeout(3)] fn can_transmit_after_cancel(mut ctx: Context) { // Slow down. At 80kHz, the transfer is supposed to take a bit over 3 seconds. - ctx.spi.change_bus_frequency(80.kHz()); + ctx.spi.apply_config(&Config { + frequency: 80.kHz(), + ..Config::default() + }); // Set up a large buffer that would trigger a timeout let mut dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); @@ -532,7 +544,10 @@ mod tests { transfer.cancel(); (spi, (dma_rx_buf, dma_tx_buf)) = transfer.wait(); - spi.change_bus_frequency(10000.kHz()); + spi.apply_config(&Config { + frequency: 10.MHz(), + ..Config::default() + }); let transfer = spi .transfer(dma_rx_buf, dma_tx_buf) diff --git a/hil-test/tests/spi_half_duplex_read.rs b/hil-test/tests/spi_half_duplex_read.rs index a50fa0dc807..dc83a638ce0 100644 --- a/hil-test/tests/spi_half_duplex_read.rs +++ b/hil-test/tests/spi_half_duplex_read.rs @@ -11,7 +11,7 @@ use esp_hal::{ gpio::{Io, Level, Output}, prelude::*, spi::{ - master::{Address, Command, Spi, SpiDma}, + master::{Address, Command, Config, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -49,10 +49,17 @@ mod tests { } } - let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_miso(miso) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_miso(miso) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); Context { spi, miso_mirror } } diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index f06a80f3eaf..88a51641e41 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -12,7 +12,7 @@ use esp_hal::{ pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ - master::{Address, Command, Spi, SpiDma}, + master::{Address, Command, Config, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -52,10 +52,17 @@ mod tests { let (mosi_loopback, mosi) = mosi.split(); - let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); Context { spi, diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index f40f81dc2db..aaf9fb7b979 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -14,7 +14,7 @@ use esp_hal::{ pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ - master::{Address, Command, Spi, SpiDma}, + master::{Address, Command, Config, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -64,10 +64,17 @@ mod tests { let (mosi_loopback, mosi) = mosi.split(); - let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_sck(sclk) - .with_mosi(mosi) - .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); + let spi = Spi::new_with_config( + peripherals.SPI2, + Config { + frequency: 100.kHz(), + mode: SpiMode::Mode0, + ..Config::default() + }, + ) + .with_sck(sclk) + .with_mosi(mosi) + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); Context { spi, From ccb3a1ba40c0a4ae88abe6e449d25833432be3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 6 Nov 2024 12:43:25 +0100 Subject: [PATCH 30/67] Use `diagnostic` on `DmaChannelConvert` (#2465) * Use `diagnostic` on `DmaChannelConvert` * Typo --- esp-hal/src/dma/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index f91b18d1dad..c759f6a6cc0 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1593,6 +1593,11 @@ pub trait DmaChannelExt: DmaChannel { fn get_tx_interrupts() -> impl InterruptAccess; } +#[diagnostic::on_unimplemented( + message = "The DMA channel isn't suitable for this peripheral", + label = "This DMA channel", + note = "Not all channels are useable with all peripherals" +)] #[doc(hidden)] pub trait DmaChannelConvert: DmaChannel { fn degrade_rx(rx: Self::Rx) -> DEG::Rx; From 4c5be2c907509d78e682376781a3d8cd3b790c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 14:55:34 +0100 Subject: [PATCH 31/67] Interconnect: force signals through GPIO matrix if split (#2419) * Allow splitting off of gpio drivers * Extract and correct low level connection bits * Add Input/OutputSignal::connect_to * Remove unnecessary public API * Fix typos * Remove unused private methods * Add separate Direct signals that do bypass the GPIO matrix * Do not disable stage input * Clean up spi_slave test * Constrain to static Flex * Improve docs * Separate input_enable and open_drain parameters * Link to the chapter * Changelog * Clarify --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio/interconnect.rs | 544 +++++++++++++++++++------------ esp-hal/src/gpio/mod.rs | 170 ++++++---- esp-hal/src/gpio/placeholder.rs | 38 +-- esp-hal/src/i2c.rs | 8 +- esp-hal/src/i2s.rs | 14 +- esp-hal/src/i2s_parallel.rs | 14 +- esp-hal/src/lcd_cam/cam.rs | 24 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 14 +- esp-hal/src/ledc/channel.rs | 3 +- esp-hal/src/macros.rs | 17 + esp-hal/src/mcpwm/operator.rs | 4 +- esp-hal/src/otg_fs.rs | 9 +- esp-hal/src/parl_io.rs | 27 +- esp-hal/src/pcnt/channel.rs | 4 +- esp-hal/src/rmt.rs | 8 +- esp-hal/src/soc/esp32/gpio.rs | 7 +- esp-hal/src/soc/esp32/mod.rs | 6 + esp-hal/src/soc/esp32c2/gpio.rs | 7 +- esp-hal/src/soc/esp32c2/mod.rs | 6 + esp-hal/src/soc/esp32c3/gpio.rs | 7 +- esp-hal/src/soc/esp32c3/mod.rs | 6 + esp-hal/src/soc/esp32c6/gpio.rs | 7 +- esp-hal/src/soc/esp32c6/mod.rs | 6 + esp-hal/src/soc/esp32h2/gpio.rs | 7 +- esp-hal/src/soc/esp32h2/mod.rs | 6 + esp-hal/src/soc/esp32s2/gpio.rs | 7 +- esp-hal/src/soc/esp32s2/mod.rs | 6 + esp-hal/src/soc/esp32s3/gpio.rs | 10 +- esp-hal/src/soc/esp32s3/mod.rs | 6 + esp-hal/src/spi/master.rs | 49 +-- esp-hal/src/spi/slave.rs | 8 +- esp-hal/src/twai/mod.rs | 4 +- esp-hal/src/uart.rs | 8 +- hil-test/tests/spi_slave.rs | 80 ++--- 35 files changed, 648 insertions(+), 494 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 1733b3b9b7f..d112b9a9f65 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) - UART configuration types have been moved to `esp_hal::uart` (#2449) - `spi::master::Spi::new()` no longer takes `frequency` and `mode` as a parameter. (#2448) +- Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419) ### Fixed diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index b86b76c2ae1..e07e8d97ec8 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -5,7 +5,9 @@ use crate::{ self, AlternateFunction, AnyPin, + Flex, InputPin, + InputSignalType, Level, NoPin, OutputPin, @@ -34,24 +36,179 @@ pub trait PeripheralInput: Into + 'static {} /// [`PeripheralInput`] as arguments instead of pin types. pub trait PeripheralOutput: Into + 'static {} +// Pins impl PeripheralInput for P {} impl PeripheralOutput for P {} -impl PeripheralInput for InputSignal {} -impl PeripheralInput for OutputSignal {} -impl PeripheralOutput for OutputSignal {} +// Pin drivers +impl PeripheralInput for Flex<'static, P> {} +impl PeripheralOutput for Flex<'static, P> {} +// Placeholders impl PeripheralInput for NoPin {} impl PeripheralOutput for NoPin {} impl PeripheralInput for Level {} impl PeripheralOutput for Level {} -impl PeripheralInput for InputConnection {} +// Split signals +impl PeripheralInput for InputSignal {} +impl PeripheralInput for OutputSignal {} +impl PeripheralOutput for OutputSignal {} +// Type-erased signals +impl PeripheralInput for InputConnection {} impl PeripheralInput for OutputConnection {} impl PeripheralOutput for OutputConnection {} +impl gpio::InputSignal { + fn can_use_gpio_matrix(self) -> bool { + self as InputSignalType <= INPUT_SIGNAL_MAX + } + + /// Connects a peripheral input signal to a GPIO or a constant level. + /// + /// Note that connecting multiple GPIOs to a single peripheral input is not + /// possible and the previous connection will be replaced. + /// + /// Also note that a peripheral input must always be connected to something, + /// so if you want to disconnect it from GPIOs, you should connect it to a + /// constant level. + #[inline] + pub fn connect_to(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.connect_input_to_peripheral(self); + } +} + +impl gpio::OutputSignal { + fn can_use_gpio_matrix(self) -> bool { + self as OutputSignalType <= OUTPUT_SIGNAL_MAX + } + + /// Connects a peripheral output signal to a GPIO. + /// + /// Note that connecting multiple output signals to a single GPIO is not + /// possible and the previous connection will be replaced. + /// + /// Also note that it is possible to connect a peripheral output signal to + /// multiple GPIOs, and old connections will not be cleared automatically. + #[inline] + pub fn connect_to(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.connect_peripheral_to_output(self); + } + + /// Disconnects a peripheral output signal from a GPIO. + #[inline] + pub fn disconnect_from(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.disconnect_from_peripheral_output(self); + } +} + +/// Connects a peripheral input (`signal`, e.g. SPI MISO) to a GPIO or a +/// constant level (`input`). +/// +/// - `signal`: The input signal to connect to the pin +/// - `input`: The GPIO (or constant level) number to connect to the input +/// signal. +/// - `invert`: Configures whether or not to invert the input value +/// - `use_gpio_matrix`: true to route through the GPIO matrix +pub(crate) fn connect_input_signal( + signal: gpio::InputSignal, + input: u8, + invert: bool, + use_gpio_matrix: bool, +) { + assert!( + signal.can_use_gpio_matrix() || !use_gpio_matrix, + "{:?} cannot be routed through the GPIO matrix", + signal + ); + unsafe { GPIO::steal() } + .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) + .write(|w| unsafe { + w.sel().bit(use_gpio_matrix); + w.in_inv_sel().bit(invert); + w.in_sel().bits(input) // Connect to GPIO or constant level + }); +} + +fn connect_pin_to_input_signal( + pin: &mut AnyPin, + signal: gpio::InputSignal, + is_inverted: bool, + force_gpio: bool, +) { + let af = if is_inverted || force_gpio { + GPIO_FUNCTION + } else { + pin.input_signals(private::Internal) + .iter() + .find(|(_af, s)| *s == signal) + .map(|(af, _)| *af) + .unwrap_or(GPIO_FUNCTION) + }; + + pin.set_alternate_function(af, private::Internal); + + connect_input_signal(signal, pin.number(), is_inverted, af == GPIO_FUNCTION); +} + +fn connect_peripheral_to_output( + pin: &mut AnyPin, + signal: gpio::OutputSignal, + is_inverted: bool, + force_gpio: bool, + peripheral_control_output_enable: bool, + invert_output_enable: bool, +) { + let af = if is_inverted || force_gpio { + GPIO_FUNCTION + } else { + pin.output_signals(private::Internal) + .iter() + .find(|(_af, s)| *s == signal) + .map(|(af, _)| *af) + .unwrap_or(GPIO_FUNCTION) + }; + + assert!( + signal.can_use_gpio_matrix() || af != GPIO_FUNCTION, + "{:?} cannot be routed through the GPIO matrix", + signal + ); + + pin.set_alternate_function(af, private::Internal); + + // Inlined because output signals can only be connected to pins or nothing, so + // there is no other user. + unsafe { GPIO::steal() } + .func_out_sel_cfg(pin.number() as usize) + .write(|w| unsafe { + if af == GPIO_FUNCTION { + // Ignored if the signal is not routed through the GPIO matrix - alternate + // function selects peripheral signal directly. + w.out_sel().bits(signal as _); + w.inv_sel().bit(is_inverted); + } + w.oen_sel().bit(!peripheral_control_output_enable); + w.oen_inv_sel().bit(invert_output_enable) + }); +} + +fn disconnect_peripheral_output_from_pin(pin: &mut AnyPin, signal: gpio::OutputSignal) { + pin.set_alternate_function(GPIO_FUNCTION, private::Internal); + + unsafe { GPIO::steal() } + .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) + .write(|w| w.sel().clear_bit()); +} + /// A configurable input signal between a peripheral and a GPIO pin. /// /// Multiple input signals can be connected to one pin. @@ -69,6 +226,15 @@ where } } +impl

From> for InputSignal +where + P: InputPin, +{ + fn from(input: Flex<'static, P>) -> Self { + Self::new(input.degrade()) + } +} + impl Clone for InputSignal { fn clone(&self) -> Self { Self { @@ -113,7 +279,7 @@ impl InputSignal { self.is_inverted = !self.is_inverted; } - /// Consumed the signal and returns a new one that inverts the peripheral's + /// Consumes the signal and returns a new one that inverts the peripheral's /// input signal. /// /// Calling this function multiple times toggles the setting. @@ -122,64 +288,13 @@ impl InputSignal { self } - /// - signal: The input signal to connect to the pin - /// - invert: Configures whether or not to invert the input value - /// - input: The GPIO number to connect to the input signal - fn connect(&self, signal: usize, invert: bool, input: u8) { - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(invert); - w.in_sel().bits(input) - }); - } - /// Connect the pin to a peripheral input signal. /// /// Since there can only be one input signal connected to a peripheral at a /// time, this function will disconnect any previously connected input /// signals. - fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal, _: private::Internal) { - let signal_nr = signal as usize; - - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.input_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - if af == GPIO_FUNCTION && signal_nr > INPUT_SIGNAL_MAX as usize { - panic!("Cannot connect GPIO to this peripheral"); - } - - self.pin.set_alternate_function(af, private::Internal); - - if signal_nr <= INPUT_SIGNAL_MAX as usize { - self.connect(signal_nr, self.is_inverted, self.pin.number()); - } - } - - /// Remove this pin from a connected peripheral input. - /// - /// Clears the entry in the GPIO matrix / Io mux that associates this input - /// pin with the given [input `signal`](`InputSignal`). Any other - /// connected signals remain intact. - fn disconnect_input_from_peripheral( - &mut self, - signal: gpio::InputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal) { + connect_pin_to_input_signal(&mut self.pin, signal, self.is_inverted, true); } delegate::delegate! { @@ -190,7 +305,44 @@ impl InputSignal { pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + } + } +} + +/// A limited, private version of [InputSignal] that allows bypassing the GPIO +/// matrix. This is only usable when the GPIO pin connected to the signal is not +/// split. +struct DirectInputSignal { + pin: AnyPin, +} + +impl Clone for DirectInputSignal { + fn clone(&self) -> Self { + Self::new(unsafe { self.pin.clone_unchecked() }) + } +} + +impl DirectInputSignal { + pub(crate) fn new(pin: AnyPin) -> Self { + Self { pin } + } + + /// Connect the pin to a peripheral input signal. + /// + /// Since there can only be one input signal connected to a peripheral at a + /// time, this function will disconnect any previously connected input + /// signals. + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal) { + connect_pin_to_input_signal(&mut self.pin, signal, false, false); + } + + delegate::delegate! { + to self.pin { + fn pull_direction(&self, pull: Pull, _internal: private::Internal); + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + fn init_input(&self, pull: Pull, _internal: private::Internal); + fn is_input_high(&self, _internal: private::Internal) -> bool; + fn enable_input(&mut self, on: bool, _internal: private::Internal); } } } @@ -212,6 +364,15 @@ where } } +impl

From> for OutputSignal +where + P: OutputPin, +{ + fn from(input: Flex<'static, P>) -> Self { + Self::new(input.degrade()) + } +} + impl Peripheral for OutputSignal { type P = Self; @@ -245,7 +406,7 @@ impl OutputSignal { self.is_inverted = !self.is_inverted; } - /// Consumed the signal and returns a new one that inverts the peripheral's + /// Consumes the signal and returns a new one that inverts the peripheral's /// output signal. /// /// Calling this function multiple times toggles the setting. @@ -254,139 +415,18 @@ impl OutputSignal { self } - /// - signal: The input signal to connect to the pin - /// - invert: Configures whether or not to invert the input value - /// - input: The GPIO number to connect to the input signal - fn connect_input(&self, signal: usize, invert: bool, input: u8) { - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(invert); - w.in_sel().bits(input) - }); - } - - /// - signal: The output signal to connect to the pin - /// - invert: Configures whether or not to invert the output value - /// - invert_enable: Configures whether or not to invert the output enable - /// signal - /// - enable_from_gpio: Configures to select the source of output enable - /// signal. - /// - false: Use output enable signal from peripheral - /// - true: Force the output enable signal to be sourced from bit n of - /// GPIO_ENABLE_REG - /// - output: The GPIO number to connect to the output signal - fn connect_output( - &self, - signal: OutputSignalType, - invert: bool, - invert_enable: bool, - enable_from_gpio: bool, - output: u8, - ) { - unsafe { GPIO::steal() } - .func_out_sel_cfg(output as usize) - .modify(|_, w| unsafe { - w.out_sel().bits(signal); - w.inv_sel().bit(invert); - w.oen_sel().bit(enable_from_gpio); - w.oen_inv_sel().bit(invert_enable) - }); - } - - /// Connect the pin to a peripheral input signal. - /// - /// Since there can only be one signal connected to a peripheral input at a - /// time, this function will disconnect any previously connected input - /// signals. - fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal, _: private::Internal) { - let signal_nr = signal as usize; - - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.input_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - if af == GPIO_FUNCTION && signal_nr > INPUT_SIGNAL_MAX as usize { - panic!("Cannot connect GPIO to this peripheral"); - } - - self.pin.set_alternate_function(af, private::Internal); - - if signal_nr <= INPUT_SIGNAL_MAX as usize { - self.connect_input(signal_nr, self.is_inverted, self.pin.number()); - } - } - - /// Remove this pin from a connected peripheral input. - /// - /// Clears the entry in the GPIO matrix / Io mux that associates this input - /// pin with the given [input `signal`](`InputSignal`). Any other - /// connected signals remain intact. - fn disconnect_input_from_peripheral( - &mut self, - signal: gpio::InputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + /// Connect the pin to a peripheral output signal. + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal) { + connect_peripheral_to_output(&mut self.pin, signal, self.is_inverted, true, true, false); } - /// Connect the pin to a peripheral output signal. - fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal, _: private::Internal) { - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.output_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - self.pin.set_alternate_function(af, private::Internal); - - let clipped_signal = if signal as usize <= OUTPUT_SIGNAL_MAX as usize { - signal as OutputSignalType - } else { - OUTPUT_SIGNAL_MAX - }; - - self.connect_output( - clipped_signal, - self.is_inverted, - false, - false, - self.pin.number(), - ); - } - - /// Remove this output pin from a connected [signal](`OutputSignal`). + /// Remove this output pin from a connected [signal](`gpio::OutputSignal`). /// /// Clears the entry in the GPIO matrix / Io mux that associates this output - /// pin with a previously connected [signal](`OutputSignal`). Any other - /// outputs connected to the peripheral remain intact. - fn disconnect_from_peripheral_output( - &mut self, - signal: gpio::OutputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + /// pin with a previously connected [signal](`gpio::OutputSignal`). Any + /// other outputs connected to the peripheral remain intact. + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal) { + disconnect_peripheral_output_from_pin(&mut self.pin, signal); } delegate::delegate! { @@ -397,7 +437,6 @@ impl OutputSignal { pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; pub fn set_to_open_drain_output(&mut self, _internal: private::Internal); @@ -406,7 +445,6 @@ impl OutputSignal { pub fn set_output_high(&mut self, on: bool, _internal: private::Internal); pub fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); pub fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); - pub fn enable_output_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn is_set_high(&self, _internal: private::Internal) -> bool; @@ -414,13 +452,62 @@ impl OutputSignal { } } +/// A limited, private version of [OutputSignal] that allows bypassing the GPIO +/// matrix. This is only usable when the GPIO pin connected to the signal is not +/// split. +struct DirectOutputSignal { + pin: AnyPin, +} + +impl DirectOutputSignal { + pub(crate) fn new(pin: AnyPin) -> Self { + Self { pin } + } + + /// Connect the pin to a peripheral output signal. + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal) { + connect_peripheral_to_output(&mut self.pin, signal, false, false, true, false); + } + + /// Remove this output pin from a connected [signal](`gpio::OutputSignal`). + /// + /// Clears the entry in the GPIO matrix / Io mux that associates this output + /// pin with a previously connected [signal](`gpio::OutputSignal`). Any + /// other outputs connected to the peripheral remain intact. + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal) { + disconnect_peripheral_output_from_pin(&mut self.pin, signal); + } + + delegate::delegate! { + to self.pin { + fn pull_direction(&self, pull: Pull, _internal: private::Internal); + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + fn init_input(&self, pull: Pull, _internal: private::Internal); + fn is_input_high(&self, _internal: private::Internal) -> bool; + fn enable_input(&mut self, on: bool, _internal: private::Internal); + + fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; + fn set_to_open_drain_output(&mut self, _internal: private::Internal); + fn set_to_push_pull_output(&mut self, _internal: private::Internal); + fn enable_output(&mut self, on: bool, _internal: private::Internal); + fn set_output_high(&mut self, on: bool, _internal: private::Internal); + fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); + fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); + fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + fn is_set_high(&self, _internal: private::Internal) -> bool; + } + } +} + #[derive(Clone)] enum InputConnectionInner { Input(InputSignal), + DirectInput(DirectInputSignal), Constant(Level), } -/// A type-erased peripheral input signal connection. +/// A peripheral input signal connection. /// /// This is mainly intended for internal use, but it can be used to connect /// peripherals within the MCU without external hardware. @@ -471,15 +558,33 @@ impl From for InputConnection { } } +impl From for InputConnection { + fn from(output_signal: DirectOutputSignal) -> Self { + Self(InputConnectionInner::DirectInput(DirectInputSignal::new( + output_signal.pin, + ))) + } +} + impl From for InputConnection { fn from(conn: OutputConnection) -> Self { match conn.0 { OutputConnectionInner::Output(inner) => inner.into(), + OutputConnectionInner::DirectOutput(inner) => inner.into(), OutputConnectionInner::Constant(inner) => inner.into(), } } } +impl

From> for InputConnection +where + P: InputPin, +{ + fn from(pin: Flex<'static, P>) -> Self { + pin.peripheral_input().into() + } +} + impl Sealed for InputConnection {} impl InputConnection { @@ -487,6 +592,7 @@ impl InputConnection { #[doc(hidden)] to match &self.0 { InputConnectionInner::Input(pin) => pin, + InputConnectionInner::DirectInput(pin) => pin, InputConnectionInner::Constant(level) => level, } { pub fn pull_direction(&self, pull: Pull, _internal: private::Internal); @@ -498,22 +604,22 @@ impl InputConnection { #[doc(hidden)] to match &mut self.0 { InputConnectionInner::Input(pin) => pin, + InputConnectionInner::DirectInput(pin) => pin, InputConnectionInner::Constant(level) => level, } { pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_input_to_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - pub fn disconnect_input_from_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal); } } } enum OutputConnectionInner { Output(OutputSignal), + DirectOutput(DirectOutputSignal), Constant(Level), } -/// A type-erased peripheral (input and) output signal connection. +/// A peripheral (input and) output signal connection. /// /// This is mainly intended for internal use, but it can be used to connect /// peripherals within the MCU without external hardware. @@ -527,6 +633,9 @@ impl Peripheral for OutputConnection { unsafe fn clone_unchecked(&self) -> Self::P { match self { Self(OutputConnectionInner::Output(signal)) => Self::from(signal.clone_unchecked()), + Self(OutputConnectionInner::DirectOutput(signal)) => { + Self::from(DirectOutputSignal::new(signal.pin.clone_unchecked())) + } Self(OutputConnectionInner::Constant(level)) => Self::from(*level), } } @@ -559,54 +668,55 @@ impl From for OutputConnection { } } +impl

From> for OutputConnection +where + P: OutputPin, +{ + fn from(pin: Flex<'static, P>) -> Self { + pin.into_peripheral_output().into() + } +} + +impl From for OutputConnection { + fn from(signal: DirectOutputSignal) -> Self { + Self(OutputConnectionInner::DirectOutput(signal)) + } +} + impl OutputConnection { delegate::delegate! { #[doc(hidden)] to match &self.0 { OutputConnectionInner::Output(pin) => pin, + OutputConnectionInner::DirectOutput(pin) => pin, OutputConnectionInner::Constant(level) => level, } { pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + + pub fn is_set_high(&self, _internal: private::Internal) -> bool; + pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; } #[doc(hidden)] to match &mut self.0 { OutputConnectionInner::Output(pin) => pin, + OutputConnectionInner::DirectOutput(pin) => pin, OutputConnectionInner::Constant(level) => level, } { pub fn pull_direction(&mut self, pull: Pull, _internal: private::Internal); pub fn init_input(&mut self, pull: Pull, _internal: private::Internal); pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_input_to_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - pub fn disconnect_input_from_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - } - #[doc(hidden)] - to match &self.0 { - OutputConnectionInner::Output(pin) => pin, - OutputConnectionInner::Constant(level) => level, - } { - pub fn is_set_high(&self, _internal: private::Internal) -> bool; - pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; - } - - #[doc(hidden)] - to match &mut self.0 { - OutputConnectionInner::Output(pin) => pin, - OutputConnectionInner::Constant(level) => level, - } { pub fn set_to_open_drain_output(&mut self, _internal: private::Internal); pub fn set_to_push_pull_output(&mut self, _internal: private::Internal); pub fn enable_output(&mut self, on: bool, _internal: private::Internal); pub fn set_output_high(&mut self, on: bool, _internal: private::Internal); pub fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); pub fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); - pub fn enable_output_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal, _internal: private::Internal); - pub fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal, _internal: private::Internal); + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal); + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal); } } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index a7311729351..4186dc4d719 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -1,39 +1,49 @@ -//! # General Purpose I/Os (GPIO) +//! # General Purpose Input/Output (GPIO) //! //! ## Overview //! //! Each pin can be used as a general-purpose I/O, or be connected to one or //! more internal peripheral signals. +#![cfg_attr( + soc_etm, + doc = "The GPIO pins also provide tasks and events via the ETM interconnect system. For more information, see the [etm] module." +)] +#![doc = ""] +//! ## Working with pins //! -//! ## Configuration +//! Before use, the GPIO module must be initialized by creating an instance of +//! the [`Io`] struct. This struct provides access to the pins on the chip. //! -//! This driver supports various operations on GPIO pins, including setting the -//! pin mode, direction, and manipulating the pin state (setting high/low, -//! toggling). It provides an interface to interact with GPIO pins on ESP chips, -//! allowing developers to control and read the state of the pins. +//! The [`Io`] struct can also be used to configure the interrupt handler for +//! GPIO interrupts. For more information, see the +//! [`Io::set_interrupt_handler`]. //! -//! ## Usage +//! The pins are accessible via [`Io::pins`]. These pins can then be passed to +//! peripherals (such as SPI, UART, I2C, etc.), to pin drivers or can be +//! [`GpioPin::split`] into peripheral signals. //! -//! This module also implements a number of traits from [embedded-hal] to -//! provide a common interface for GPIO pins. +//! Each pin is a different type initially. Internally, `esp-hal` will often +//! erase their types automatically, but they can also be converted into +//! [`AnyPin`] manually by calling [`Pin::degrade`]. //! -//! To get access to the pins, you first need to convert them into a HAL -//! designed struct from the pac struct `GPIO` and `IO_MUX` using [`Io::new`]. +//! Pin drivers can be created using [`Flex::new`], [`Input::new`], +//! [`Output::new`] and [`OutputOpenDrain::new`]. If you need the pin drivers to +//! carry the type of the pin, you can use the [`Flex::new_typed`], +//! [`Input::new_typed`], [`Output::new_typed`], and +//! [`OutputOpenDrain::new_typed`] functions. //! -//! ### Pin Types +//! ## GPIO interconnect //! -//! - [Input] pins can be used as digital inputs. -//! - [Output] and [OutputOpenDrain] pins can be used as digital outputs. -//! - [Flex] pin is a pin that can be used as an input and output pin. -//! - [AnyPin] is a type-erased GPIO pin with support for inverted signalling. -//! - [NoPin] is a useful for cases where peripheral driver requires a pin, but -//! real pin cannot be used. +//! Sometimes you may want to connect peripherals together without using +//! external hardware. The [`interconnect`] module provides tools to achieve +//! this using GPIO pins. //! -//! ### GPIO interconnect -//! -//! Each GPIO can be connected to one output signal and any number of input -//! signals. This allows connections inside of the MCU without allocating and -//! connecting multiple pins for loopback functionality. +//! To obtain peripheral signals, use the [`GpioPin::split`] method to split a +//! pin into an input and output signal. Alternatively, you may use +//! [`Flex::split`], [`Flex::into_peripheral_output`], +//! [`Flex::peripheral_input`], and similar methods to split a pin driver into +//! an input and output signal. You can then pass these signals to the +//! peripheral drivers similar to how you would pass a pin. //! //! ## Examples //! @@ -49,14 +59,14 @@ //! //! ### Blink an LED //! -//! See the [Blinky] section of the crate documentation. +//! See the [Blinky][crate#blinky] section of the crate documentation. +//! +//! ### Inverting peripheral signals //! -//! ### Inverting a signal using `AnyPin` //! See the [Inverting TX and RX Pins] example of the UART documentation. //! //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ -//! [Blinky]: ../index.html#blinky -//! [Inverting TX and RX Pins]: ../uart/index.html#inverting-tx-and-rx-pins +//! [Inverting TX and RX Pins]: crate::uart#inverting-rx-and-tx-pins use portable_atomic::{AtomicPtr, Ordering}; use procmacros::ram; @@ -217,9 +227,13 @@ pub enum DriveStrength { /// /// GPIO pins can be configured for various functions, such as GPIO /// or being directly connected to a peripheral's signal like UART, SPI, etc. -/// The `AlternateFunction` enum allows to select one of several functions that +/// The `AlternateFunction` enum allows selecting one of several functions that /// a pin can perform, rather than using it as a general-purpose input or /// output. +/// +/// The different variants correspond to different functionality depending on +/// the chip and the specific pin. For more information, refer to your chip's +#[doc = crate::trm_markdown_link!("iomuxgpio")] #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AlternateFunction { @@ -384,12 +398,6 @@ pub trait InputPin: Pin + Into + 'static { }); } - /// Enable input in sleep mode for the pin - #[doc(hidden)] - fn enable_input_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_ie().bit(on)); - } - /// The current state of the input #[doc(hidden)] fn is_input_high(&self, _: private::Internal) -> bool { @@ -405,6 +413,7 @@ pub trait OutputPin: Pin + Into + 'static { &mut self, alternate: AlternateFunction, open_drain: bool, + input_enable: Option, _: private::Internal, ) { self.enable_output(true, private::Internal); @@ -422,7 +431,9 @@ pub trait OutputPin: Pin + Into + 'static { get_io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8); - w.fun_ie().bit(open_drain); + if let Some(input_enable) = input_enable { + w.fun_ie().bit(input_enable); + } w.fun_drv().bits(DriveStrength::I20mA as u8); w.slp_sel().clear_bit() }); @@ -431,13 +442,13 @@ pub trait OutputPin: Pin + Into + 'static { /// Configure open-drain mode #[doc(hidden)] fn set_to_open_drain_output(&mut self, _: private::Internal) { - self.init_output(GPIO_FUNCTION, true, private::Internal); + self.init_output(GPIO_FUNCTION, true, Some(true), private::Internal); } /// Configure output mode #[doc(hidden)] fn set_to_push_pull_output(&mut self, _: private::Internal) { - self.init_output(GPIO_FUNCTION, false, private::Internal); + self.init_output(GPIO_FUNCTION, false, None, private::Internal); } /// Set the pin's level to high or low @@ -461,12 +472,6 @@ pub trait OutputPin: Pin + Into + 'static { .modify(|_, w| w.pad_driver().bit(on)); } - /// Enable/disable output in sleep mode - #[doc(hidden)] - fn enable_output_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_oe().bit(on)); - } - /// Configure internal pull-up resistor in sleep mode #[doc(hidden)] fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { @@ -1115,9 +1120,9 @@ pub struct Output<'d, P = AnyPin> { impl

private::Sealed for Output<'_, P> {} -impl

Peripheral for Output<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for Output<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1229,9 +1234,9 @@ pub struct Input<'d, P = AnyPin> { impl

private::Sealed for Input<'_, P> {} -impl

Peripheral for Input<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for Input<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1350,9 +1355,9 @@ pub struct OutputOpenDrain<'d, P = AnyPin> { impl

private::Sealed for OutputOpenDrain<'_, P> {} -impl

Peripheral for OutputOpenDrain<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for OutputOpenDrain<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1498,10 +1503,12 @@ pub struct Flex<'d, P = AnyPin> { impl

private::Sealed for Flex<'_, P> {} -impl

Peripheral for Flex<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { - core::ptr::read(&*self.pin as *const _) +impl<'d, P> Peripheral for Flex<'d, P> { + type P = Self; + unsafe fn clone_unchecked(&self) -> Self::P { + Self { + pin: PeripheralRef::new(core::ptr::read(&*self.pin as *const P)), + } } } @@ -1709,6 +1716,42 @@ where } } +// Unfortunate implementation details responsible for: +// - making pin drivers work with the peripheral signal system +// - making the pin drivers work with the sleep API +impl Pin for Flex<'_, P> { + delegate::delegate! { + to self.pin { + fn number(&self) -> u8; + fn degrade_pin(&self, _internal: private::Internal) -> AnyPin; + fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, OutputSignal)]; + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, InputSignal)]; + fn gpio_bank(&self, _internal: private::Internal) -> GpioRegisterAccess; + } + } +} +impl RtcPin for Flex<'_, P> { + delegate::delegate! { + to self.pin { + #[cfg(xtensa)] + fn rtc_number(&self) -> u8; + #[cfg(any(xtensa, esp32c6))] + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: RtcFunction); + fn rtcio_pad_hold(&mut self, enable: bool); + #[cfg(any(esp32c3, esp32c2, esp32c6))] + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8); + } + } +} +impl RtcPinWithResistors for Flex<'_, P> { + delegate::delegate! { + to self.pin { + fn rtcio_pullup(&mut self, enable: bool); + fn rtcio_pulldown(&mut self, enable: bool); + } + } +} + pub(crate) mod internal { use super::*; @@ -1773,10 +1816,17 @@ pub(crate) mod internal { &mut self, alternate: AlternateFunction, open_drain: bool, + input_enable: Option, _: private::Internal, ) { handle_gpio_output!(&mut self.0, target, { - OutputPin::init_output(target, alternate, open_drain, private::Internal) + OutputPin::init_output( + target, + alternate, + open_drain, + input_enable, + private::Internal, + ) }) } @@ -1810,12 +1860,6 @@ pub(crate) mod internal { }) } - fn enable_output_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - handle_gpio_output!(&mut self.0, target, { - OutputPin::enable_output_in_sleep_mode(target, on, private::Internal) - }) - } - fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { handle_gpio_output!(&mut self.0, target, { OutputPin::internal_pull_up_in_sleep_mode(target, on, private::Internal) diff --git a/esp-hal/src/gpio/placeholder.rs b/esp-hal/src/gpio/placeholder.rs index 84c918fce76..bf269c4d262 100644 --- a/esp-hal/src/gpio/placeholder.rs +++ b/esp-hal/src/gpio/placeholder.rs @@ -6,6 +6,7 @@ // polluting the main module. use super::*; +use crate::gpio::interconnect::connect_input_signal; impl crate::peripheral::Peripheral for Level { type P = Self; @@ -29,45 +30,26 @@ impl Level { pub(crate) fn enable_input(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn enable_input_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn is_input_high(&self, _: private::Internal) -> bool { *self == Level::High } #[doc(hidden)] - pub(crate) fn connect_input_to_peripheral( - &mut self, - signal: InputSignal, - _: private::Internal, - ) { + pub(crate) fn connect_input_to_peripheral(&mut self, signal: InputSignal) { let value = match self { Level::High => ONE_INPUT, Level::Low => ZERO_INPUT, }; - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(false); - w.in_sel().bits(value) - }); + connect_input_signal(signal, value, false, true); } - pub(crate) fn disconnect_input_from_peripheral( - &mut self, - _signal: InputSignal, - _: private::Internal, - ) { - } pub(crate) fn set_to_open_drain_output(&mut self, _: private::Internal) {} pub(crate) fn set_to_push_pull_output(&mut self, _: private::Internal) {} pub(crate) fn enable_output(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn set_output_high(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn set_drive_strength(&mut self, _strength: DriveStrength, _: private::Internal) {} pub(crate) fn enable_open_drain(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn enable_output_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn internal_pull_up_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn internal_pull_down_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} @@ -82,19 +64,9 @@ impl Level { &[] } - pub(crate) fn connect_peripheral_to_output( - &mut self, - _signal: OutputSignal, - _: private::Internal, - ) { - } + pub(crate) fn connect_peripheral_to_output(&mut self, _signal: OutputSignal) {} - pub(crate) fn disconnect_from_peripheral_output( - &mut self, - _signal: OutputSignal, - _: private::Internal, - ) { - } + pub(crate) fn disconnect_from_peripheral_output(&mut self, _signal: OutputSignal) {} } /// Placeholder pin, used when no pin is required when using a peripheral. diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 452369252f4..0e636efe22d 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -336,15 +336,15 @@ where scl.enable_input(true, crate::private::Internal); scl.pull_direction(Pull::Up, crate::private::Internal); - scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal); - scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal); + i2c.i2c.scl_input_signal().connect_to(&mut scl); + i2c.i2c.scl_output_signal().connect_to(&mut scl); sda.set_to_open_drain_output(crate::private::Internal); sda.enable_input(true, crate::private::Internal); sda.pull_direction(Pull::Up, crate::private::Internal); - sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal); - sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal); + i2c.i2c.sda_input_signal().connect_to(&mut sda); + i2c.i2c.sda_output_signal().connect_to(&mut sda); i2c.i2c.setup(frequency, None); i2c diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index c5b2c1bbc34..0a44a75fa6d 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -469,7 +469,7 @@ where pub fn with_mclk(self, pin: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(self.i2s_tx.i2s.mclk_signal(), crate::private::Internal); + self.i2s_tx.i2s.mclk_signal().connect_to(pin); self } @@ -826,7 +826,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.bclk_signal(), private::Internal); + self.i2s.bclk_signal().connect_to(pin); self } @@ -837,7 +837,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.ws_signal(), private::Internal); + self.i2s.ws_signal().connect_to(pin); self } @@ -848,7 +848,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.dout_signal(), private::Internal); + self.i2s.dout_signal().connect_to(pin); self } @@ -885,7 +885,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.bclk_rx_signal(), private::Internal); + self.i2s.bclk_rx_signal().connect_to(pin); self } @@ -896,7 +896,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.ws_rx_signal(), private::Internal); + self.i2s.ws_rx_signal().connect_to(pin); self } @@ -907,7 +907,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.init_input(crate::gpio::Pull::None, private::Internal); - pin.connect_input_to_peripheral(self.i2s.din_signal(), private::Internal); + self.i2s.din_signal().connect_to(pin); self } diff --git a/esp-hal/src/i2s_parallel.rs b/esp-hal/src/i2s_parallel.rs index 556ccc00ecb..37fd6585d43 100644 --- a/esp-hal/src/i2s_parallel.rs +++ b/esp-hal/src/i2s_parallel.rs @@ -61,7 +61,7 @@ use crate::{ }, peripheral::{Peripheral, PeripheralRef}, peripherals::{i2s0::RegisterBlock, I2S0, I2S1}, - private, + private::Internal, system::PeripheralClockControl, Async, Mode, @@ -123,8 +123,8 @@ impl<'d> TxPins<'d> for TxSixteenBits<'d> { crate::into_ref!(instance); let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); + pin.set_to_push_pull_output(Internal); + instance.data_out_signal(i, bits).connect_to(pin); } } } @@ -165,8 +165,8 @@ impl<'d> TxPins<'d> for TxEightBits<'d> { crate::into_ref!(instance); let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); + pin.set_to_push_pull_output(Internal); + instance.data_out_signal(i, bits).connect_to(pin); } } } @@ -228,8 +228,8 @@ where // configure the I2S peripheral for parallel mode i2s.setup(frequency, pins.bus_width()); // setup the clock pin - clock_pin.set_to_push_pull_output(private::Internal); - clock_pin.connect_peripheral_to_output(i2s.ws_signal(), private::Internal); + clock_pin.set_to_push_pull_output(Internal); + i2s.ws_signal().connect_to(clock_pin); pins.configure(i2s.reborrow()); Self { diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index dee3a375949..5cb3b9cf263 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -243,8 +243,10 @@ impl<'d> Camera<'d> { mclk: impl Peripheral

+ 'd, ) -> Self { crate::into_mapped_ref!(mclk); + mclk.set_to_push_pull_output(crate::private::Internal); - mclk.connect_peripheral_to_output(OutputSignal::CAM_CLK, crate::private::Internal); + OutputSignal::CAM_CLK.connect_to(mclk); + self } @@ -256,7 +258,7 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(pclk); pclk.init_input(Pull::None, crate::private::Internal); - pclk.connect_input_to_peripheral(InputSignal::CAM_PCLK, crate::private::Internal); + InputSignal::CAM_PCLK.connect_to(pclk); self } @@ -271,9 +273,9 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(vsync, h_enable); vsync.init_input(Pull::None, crate::private::Internal); - vsync.connect_input_to_peripheral(InputSignal::CAM_V_SYNC, crate::private::Internal); + InputSignal::CAM_V_SYNC.connect_to(vsync); h_enable.init_input(Pull::None, crate::private::Internal); - h_enable.connect_input_to_peripheral(InputSignal::CAM_H_ENABLE, crate::private::Internal); + InputSignal::CAM_H_ENABLE.connect_to(h_enable); self.lcd_cam .cam_ctrl1() @@ -297,11 +299,11 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(vsync, hsync, h_enable); vsync.init_input(Pull::None, crate::private::Internal); - vsync.connect_input_to_peripheral(InputSignal::CAM_V_SYNC, crate::private::Internal); + InputSignal::CAM_V_SYNC.connect_to(vsync); hsync.init_input(Pull::None, crate::private::Internal); - hsync.connect_input_to_peripheral(InputSignal::CAM_H_SYNC, crate::private::Internal); + InputSignal::CAM_H_SYNC.connect_to(hsync); h_enable.init_input(Pull::None, crate::private::Internal); - h_enable.connect_input_to_peripheral(InputSignal::CAM_H_ENABLE, crate::private::Internal); + InputSignal::CAM_H_ENABLE.connect_to(h_enable); self.lcd_cam .cam_ctrl1() @@ -514,9 +516,9 @@ impl RxEightBits { (pin_7, InputSignal::CAM_DATA_7), ]; - for (mut pin, signal) in pairs.into_iter() { + for (pin, signal) in pairs.into_iter() { pin.init_input(Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(pin); } Self { _pins: () } @@ -591,9 +593,9 @@ impl RxSixteenBits { (pin_15, InputSignal::CAM_DATA_15), ]; - for (mut pin, signal) in pairs.into_iter() { + for (pin, signal) in pairs.into_iter() { pin.init_input(Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(pin); } Self { _pins: () } diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 2017f4d07cb..6c9d3e614d3 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -239,7 +239,7 @@ impl<'d, DM: Mode> I8080<'d, DM> { pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cs); cs.set_to_push_pull_output(crate::private::Internal); - cs.connect_peripheral_to_output(OutputSignal::LCD_CS, crate::private::Internal); + OutputSignal::LCD_CS.connect_to(cs); self } @@ -253,10 +253,10 @@ impl<'d, DM: Mode> I8080<'d, DM> { crate::into_mapped_ref!(dc, wrx); dc.set_to_push_pull_output(crate::private::Internal); - dc.connect_peripheral_to_output(OutputSignal::LCD_DC, crate::private::Internal); + OutputSignal::LCD_DC.connect_to(dc); wrx.set_to_push_pull_output(crate::private::Internal); - wrx.connect_peripheral_to_output(OutputSignal::LCD_PCLK, crate::private::Internal); + OutputSignal::LCD_PCLK.connect_to(wrx); self } @@ -628,9 +628,9 @@ impl<'d> TxPins for TxEightBits<'d> { OutputSignal::LCD_DATA_7, ]; - for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.iter()) { + for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.into_iter()) { pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(*signal, crate::private::Internal); + signal.connect_to(pin); } } } @@ -697,9 +697,9 @@ impl<'d> TxPins for TxSixteenBits<'d> { OutputSignal::LCD_DATA_15, ]; - for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.iter()) { + for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.into_iter()) { pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(*signal, crate::private::Internal); + signal.connect_to(pin); } } } diff --git a/esp-hal/src/ledc/channel.rs b/esp-hal/src/ledc/channel.rs index a1f18c5ba41..67b43e3f289 100644 --- a/esp-hal/src/ledc/channel.rs +++ b/esp-hal/src/ledc/channel.rs @@ -610,8 +610,7 @@ where Number::Channel7 => OutputSignal::LEDC_LS_SIG7, }; - self.output_pin - .connect_peripheral_to_output(signal, crate::private::Internal); + signal.connect_to(&mut self.output_pin); } else { return Err(Error::Timer); } diff --git a/esp-hal/src/macros.rs b/esp-hal/src/macros.rs index 4f2fa8748b1..c22b5a44a6b 100644 --- a/esp-hal/src/macros.rs +++ b/esp-hal/src/macros.rs @@ -26,6 +26,23 @@ macro_rules! before_snippet { }; } +#[doc(hidden)] +#[macro_export] +macro_rules! trm_markdown_link { + () => { + concat!("[Technical Reference Manual](", $crate::trm_link!(), ")") + }; + ($anchor:literal) => { + concat!( + "[Technical Reference Manual](", + $crate::trm_link!(), + "#", + $anchor, + ")" + ) + }; +} + #[doc(hidden)] /// Shorthand to define enums with From implementations. #[macro_export] diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index d2df0a68ec9..f467d9f32fc 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -298,9 +298,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, pin.set_actions(config.actions); pin.set_update_method(config.update_method); - let output_signal = PWM::output_signal::(); - pin.pin - .connect_peripheral_to_output(output_signal, private::Internal); + PWM::output_signal::().connect_to(&mut pin.pin); pin.pin.enable_output(true, private::Internal); pin diff --git a/esp-hal/src/otg_fs.rs b/esp-hal/src/otg_fs.rs index 095126468dd..97e0d246f0c 100644 --- a/esp-hal/src/otg_fs.rs +++ b/esp-hal/src/otg_fs.rs @@ -43,7 +43,6 @@ use crate::{ gpio::InputSignal, peripheral::{Peripheral, PeripheralRef}, peripherals, - private::Internal, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, }; @@ -99,10 +98,10 @@ impl<'d> Usb<'d> { use crate::gpio::Level; - Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_IDDIG, Internal); // connected connector is mini-B side - Level::High.connect_input_to_peripheral(InputSignal::USB_SRP_BVALID, Internal); // HIGH to force USB device mode - Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_VBUSVALID, Internal); // receiving a valid Vbus from device - Level::Low.connect_input_to_peripheral(InputSignal::USB_OTG_AVALID, Internal); + InputSignal::USB_OTG_IDDIG.connect_to(Level::High); // connected connector is mini-B side + InputSignal::USB_SRP_BVALID.connect_to(Level::High); // HIGH to force USB device mode + InputSignal::USB_OTG_VBUSVALID.connect_to(Level::High); // receiving a valid Vbus from device + InputSignal::USB_OTG_AVALID.connect_to(Level::Low); } } diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index c552a3c197c..57b558cc5ff 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -292,10 +292,7 @@ impl<'d> ClkOutPin<'d> { impl TxClkPin for ClkOutPin<'_> { fn configure(&mut self) { self.pin.set_to_push_pull_output(crate::private::Internal); - self.pin.connect_peripheral_to_output( - crate::gpio::OutputSignal::PARL_TX_CLK, - crate::private::Internal, - ); + crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(&mut self.pin); } } @@ -318,10 +315,7 @@ impl TxClkPin for ClkInPin<'_> { self.pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.pin.connect_input_to_peripheral( - crate::gpio::InputSignal::PARL_TX_CLK, - crate::private::Internal, - ); + crate::gpio::InputSignal::PARL_TX_CLK.connect_to(&mut self.pin); } } @@ -348,10 +342,7 @@ impl RxClkPin for RxClkInPin<'_> { self.pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.pin.connect_input_to_peripheral( - crate::gpio::InputSignal::PARL_RX_CLK, - crate::private::Internal, - ); + crate::gpio::InputSignal::PARL_RX_CLK.connect_to(&mut self.pin); Instance::set_rx_clk_edge_sel(self.sample_edge); } @@ -390,10 +381,7 @@ where self.tx_pins.configure()?; self.valid_pin .set_to_push_pull_output(crate::private::Internal); - self.valid_pin.connect_peripheral_to_output( - Instance::tx_valid_pin_signal(), - crate::private::Internal, - ); + Instance::tx_valid_pin_signal().connect_to(&mut self.valid_pin); Instance::set_tx_hw_valid_en(true); Ok(()) } @@ -464,7 +452,7 @@ macro_rules! tx_pins { fn configure(&mut self) -> Result<(), Error>{ $( self.[< pin_ $pin:lower >].set_to_push_pull_output(crate::private::Internal); - self.[< pin_ $pin:lower >].connect_peripheral_to_output(crate::gpio::OutputSignal::$signal, crate::private::Internal); + crate::gpio::OutputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]); )+ private::Instance::set_tx_bit_width( private::WidSel::[< Bits $width >]); @@ -584,8 +572,7 @@ where self.rx_pins.configure()?; self.valid_pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.valid_pin - .connect_input_to_peripheral(Instance::rx_valid_pin_signal(), crate::private::Internal); + Instance::rx_valid_pin_signal().connect_to(&mut self.valid_pin); Instance::set_rx_sw_en(false); if let Some(sel) = self.enable_mode.pulse_submode_sel() { Instance::set_rx_pulse_submode_sel(sel); @@ -684,7 +671,7 @@ macro_rules! rx_pins { fn configure(&mut self) -> Result<(), Error> { $( self.[< pin_ $pin:lower >].init_input(crate::gpio::Pull::None, crate::private::Internal); - self.[< pin_ $pin:lower >].connect_input_to_peripheral(crate::gpio::InputSignal::$signal, crate::private::Internal); + crate::gpio::InputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]); )+ private::Instance::set_rx_bit_width( private::WidSel::[< Bits $width >]); diff --git a/esp-hal/src/pcnt/channel.rs b/esp-hal/src/pcnt/channel.rs index b85a4b05f0d..c1c565b38e2 100644 --- a/esp-hal/src/pcnt/channel.rs +++ b/esp-hal/src/pcnt/channel.rs @@ -118,7 +118,7 @@ impl Channel<'_, UNIT, NUM> { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { crate::into_mapped_ref!(source); source.enable_input(true, crate::private::Internal); - source.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(source); } self } @@ -176,7 +176,7 @@ impl Channel<'_, UNIT, NUM> { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { crate::into_mapped_ref!(source); source.enable_input(true, crate::private::Internal); - source.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(source); } self } diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 1ba39b3423d..984d621cf54 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -312,8 +312,8 @@ fn configure_rx_channel<'d, P: PeripheralInput, T: RxChannelInternal, M: crat } crate::into_mapped_ref!(pin); - pin.init_input(crate::gpio::Pull::None, crate::Internal); - pin.connect_input_to_peripheral(T::input_signal(), crate::Internal); + pin.init_input(crate::gpio::Pull::None, crate::private::Internal); + T::input_signal().connect_to(pin); T::set_divider(config.clk_divider); T::set_carrier( @@ -333,8 +333,8 @@ fn configure_tx_channel<'d, P: PeripheralOutput, T: TxChannelInternal, M: cra config: TxChannelConfig, ) -> Result { crate::into_mapped_ref!(pin); - pin.set_to_push_pull_output(crate::Internal); - pin.connect_peripheral_to_output(T::output_signal(), crate::Internal); + pin.set_to_push_pull_output(crate::private::Internal); + T::output_signal().connect_to(pin); T::set_divider(config.clk_divider); T::set_carrier( diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index f5899cbd209..b2e34a52ff3 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -53,6 +53,7 @@ pub const NUM_PINS: usize = 40; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 548; pub(crate) const INPUT_SIGNAL_MAX: u16 = 539; @@ -119,7 +120,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPICLK = 0, @@ -310,7 +312,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPICLK = 0, diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 6ce747d8335..513675bc8ab 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -26,6 +26,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/soc/esp32c2/gpio.rs b/esp-hal/src/soc/esp32c2/gpio.rs index f639d54fd71..5304cc66c1b 100644 --- a/esp-hal/src/soc/esp32c2/gpio.rs +++ b/esp-hal/src/soc/esp32c2/gpio.rs @@ -45,6 +45,7 @@ pub const NUM_PINS: usize = 21; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; @@ -64,7 +65,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -104,7 +106,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32c2/mod.rs b/esp-hal/src/soc/esp32c2/mod.rs index f479a7e767c..da4a41fa440 100644 --- a/esp-hal/src/soc/esp32c2/mod.rs +++ b/esp-hal/src/soc/esp32c2/mod.rs @@ -19,6 +19,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32c3/gpio.rs b/esp-hal/src/soc/esp32c3/gpio.rs index 5139199f0c2..80af84bb36f 100644 --- a/esp-hal/src/soc/esp32c3/gpio.rs +++ b/esp-hal/src/soc/esp32c3/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 22; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -114,7 +116,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32c3/mod.rs b/esp-hal/src/soc/esp32c3/mod.rs index 0b3d43f1b60..6955b5c78c7 100644 --- a/esp-hal/src/soc/esp32c3/mod.rs +++ b/esp-hal/src/soc/esp32c3/mod.rs @@ -23,6 +23,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32c6/gpio.rs b/esp-hal/src/soc/esp32c6/gpio.rs index 5844ec08eb8..32c73525600 100644 --- a/esp-hal/src/soc/esp32c6/gpio.rs +++ b/esp-hal/src/soc/esp32c6/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 31; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { EXT_ADC_START = 0, @@ -169,7 +171,8 @@ pub enum InputSignal { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { LEDC_LS_SIG0 = 0, diff --git a/esp-hal/src/soc/esp32c6/mod.rs b/esp-hal/src/soc/esp32c6/mod.rs index 461b5e55163..1ed7e74db87 100644 --- a/esp-hal/src/soc/esp32c6/mod.rs +++ b/esp-hal/src/soc/esp32c6/mod.rs @@ -25,6 +25,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32h2/gpio.rs b/esp-hal/src/soc/esp32h2/gpio.rs index 44d7c4ce6cd..fba6b839dd2 100644 --- a/esp-hal/src/soc/esp32h2/gpio.rs +++ b/esp-hal/src/soc/esp32h2/gpio.rs @@ -47,6 +47,7 @@ pub const NUM_PINS: usize = 28; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; @@ -66,7 +67,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { EXT_ADC_START = 0, @@ -151,7 +153,8 @@ pub enum InputSignal { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { LEDC_LS_SIG0 = 0, diff --git a/esp-hal/src/soc/esp32h2/mod.rs b/esp-hal/src/soc/esp32h2/mod.rs index d87720b4247..9997f73fb2e 100644 --- a/esp-hal/src/soc/esp32h2/mod.rs +++ b/esp-hal/src/soc/esp32h2/mod.rs @@ -24,6 +24,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32s2/gpio.rs b/esp-hal/src/soc/esp32s2/gpio.rs index a90998f2c8f..faa6b8bcd6d 100644 --- a/esp-hal/src/soc/esp32s2/gpio.rs +++ b/esp-hal/src/soc/esp32s2/gpio.rs @@ -59,6 +59,7 @@ pub const NUM_PINS: usize = 47; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const INPUT_SIGNAL_MAX: u16 = 204; @@ -126,7 +127,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -212,7 +214,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index 476b4b99c5e..ca2dd1dfa38 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -31,6 +31,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/soc/esp32s3/gpio.rs b/esp-hal/src/soc/esp32s3/gpio.rs index 8bcb487987d..2822ec1cfa0 100644 --- a/esp-hal/src/soc/esp32s3/gpio.rs +++ b/esp-hal/src/soc/esp32s3/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 49; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const INPUT_SIGNAL_MAX: u16 = 189; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -203,8 +205,10 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] -#[doc(hidden)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[doc(hidden)] // TODO connection operations are now public on these, we might want to publish + // them pub enum OutputSignal { SPIQ = 0, SPID = 1, diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index be34da1364b..0d1dbde1b85 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -32,6 +32,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index bab494fa82b..141a348a836 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -90,12 +90,7 @@ use crate::{ Rx, Tx, }, - gpio::{ - interconnect::{OutputConnection, PeripheralOutput}, - InputSignal, - NoPin, - OutputSignal, - }, + gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, peripherals::spi2::RegisterBlock, @@ -608,20 +603,10 @@ where let is_qspi = this.driver().sio2_input.is_some(); if is_qspi { - let mut signal = OutputConnection::from(NoPin); - - signal - .connect_input_to_peripheral(unwrap!(this.driver().sio2_input), private::Internal); - signal.connect_peripheral_to_output( - unwrap!(this.driver().sio2_output), - private::Internal, - ); - signal - .connect_input_to_peripheral(unwrap!(this.driver().sio3_input), private::Internal); - signal.connect_peripheral_to_output( - unwrap!(this.driver().sio3_output), - private::Internal, - ); + unwrap!(this.driver().sio2_input).connect_to(NoPin); + unwrap!(this.driver().sio2_output).connect_to(NoPin); + unwrap!(this.driver().sio3_input).connect_to(NoPin); + unwrap!(this.driver().sio3_output).connect_to(NoPin); } this @@ -634,10 +619,10 @@ where pub fn with_mosi(self, mosi: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(mosi); mosi.enable_output(true, private::Internal); - mosi.connect_peripheral_to_output(self.driver().mosi, private::Internal); - mosi.enable_input(true, private::Internal); - mosi.connect_input_to_peripheral(self.driver().sio0_input, private::Internal); + + self.driver().mosi.connect_to(&mut mosi); + self.driver().sio0_input.connect_to(&mut mosi); self } @@ -649,10 +634,10 @@ where pub fn with_miso(self, miso: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(miso); miso.enable_input(true, private::Internal); - miso.connect_input_to_peripheral(self.driver().miso, private::Internal); - miso.enable_output(true, private::Internal); - miso.connect_peripheral_to_output(self.driver().sio1_output, private::Internal); + + self.driver().miso.connect_to(&mut miso); + self.driver().sio1_output.connect_to(&mut miso); self } @@ -664,7 +649,7 @@ where pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(sclk); sclk.set_to_push_pull_output(private::Internal); - sclk.connect_peripheral_to_output(self.driver().sclk, private::Internal); + self.driver().sclk.connect_to(sclk); self } @@ -676,7 +661,7 @@ where pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cs); cs.set_to_push_pull_output(private::Internal); - cs.connect_peripheral_to_output(self.driver().cs, private::Internal); + self.driver().cs.connect_to(cs); self } @@ -716,8 +701,8 @@ where sio2.enable_input(true, private::Internal); sio2.enable_output(true, private::Internal); - sio2.connect_input_to_peripheral(unwrap!(self.driver().sio2_input), private::Internal); - sio2.connect_peripheral_to_output(unwrap!(self.driver().sio2_output), private::Internal); + unwrap!(self.driver().sio2_input).connect_to(&mut sio2); + unwrap!(self.driver().sio2_output).connect_to(&mut sio2); self } @@ -734,8 +719,8 @@ where sio3.enable_input(true, private::Internal); sio3.enable_output(true, private::Internal); - sio3.connect_input_to_peripheral(unwrap!(self.driver().sio3_input), private::Internal); - sio3.connect_peripheral_to_output(unwrap!(self.driver().sio3_output), private::Internal); + unwrap!(self.driver().sio3_input).connect_to(&mut sio3); + unwrap!(self.driver().sio3_output).connect_to(&mut sio3); self } diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index a4e190ecd5a..675d66b2d36 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -144,16 +144,16 @@ where // TODO: with_pins et. al. sclk.enable_input(true, private::Internal); - sclk.connect_input_to_peripheral(this.spi.sclk_signal(), private::Internal); + this.spi.sclk_signal().connect_to(sclk); mosi.enable_input(true, private::Internal); - mosi.connect_input_to_peripheral(this.spi.mosi_signal(), private::Internal); + this.spi.mosi_signal().connect_to(mosi); miso.set_to_push_pull_output(private::Internal); - miso.connect_peripheral_to_output(this.spi.miso_signal(), private::Internal); + this.spi.miso_signal().connect_to(miso); cs.enable_input(true, private::Internal); - cs.connect_input_to_peripheral(this.spi.cs_signal(), private::Internal); + this.spi.cs_signal().connect_to(cs); this } diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index b1db036b1b7..5739ffd6d85 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -806,13 +806,13 @@ where tx_pin.set_to_push_pull_output(crate::private::Internal); Pull::None }; - tx_pin.connect_peripheral_to_output(this.twai.output_signal(), crate::private::Internal); + this.twai.output_signal().connect_to(tx_pin); // Setting up RX pin later allows us to use a single pin in tests. // `set_to_push_pull_output` disables input, here we re-enable it if rx_pin // uses the same GPIO. rx_pin.init_input(rx_pull, crate::private::Internal); - rx_pin.connect_input_to_peripheral(this.twai.input_signal(), crate::private::Internal); + this.twai.input_signal().connect_to(rx_pin); // Freeze REC by changing to LOM mode this.set_mode(TwaiMode::ListenOnly); diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index f37c16a568c..812b4abd134 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -460,7 +460,7 @@ where fn with_rx(self, rx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rx); rx.init_input(Pull::Up, Internal); - rx.connect_input_to_peripheral(self.uart.info().rx_signal, Internal); + self.uart.info().rx_signal.connect_to(rx); self } @@ -470,7 +470,7 @@ where // Make sure we don't cause an unexpected low pulse on the pin. tx.set_output_high(true, Internal); tx.set_to_push_pull_output(Internal); - tx.connect_peripheral_to_output(self.uart.info().tx_signal, Internal); + self.uart.info().tx_signal.connect_to(tx); self } @@ -558,7 +558,7 @@ where pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rts); rts.set_to_push_pull_output(Internal); - rts.connect_peripheral_to_output(self.uart.info().rts_signal, Internal); + self.uart.info().rts_signal.connect_to(rts); self } @@ -766,7 +766,7 @@ where pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cts); cts.init_input(Pull::None, Internal); - cts.connect_input_to_peripheral(self.uart.info().cts_signal, Internal); + self.uart.info().cts_signal.connect_to(cts); self } diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 4d60f3b79cb..6d8c1aeaf14 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -11,10 +11,8 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::{ - interconnect::{InputSignal, OutputSignal}, - Io, - }, + gpio::{Input, Io, Level, Output, Pull}, + peripheral::Peripheral, spi::{slave::Spi, SpiMode}, Blocking, }; @@ -35,32 +33,19 @@ struct Context { } struct BitbangSpi { - sclk: OutputSignal, - mosi: OutputSignal, - miso: InputSignal, - cs: OutputSignal, + sclk: Output<'static>, + mosi: Output<'static>, + miso: Input<'static>, + cs: Output<'static>, } impl BitbangSpi { fn new( - mut sclk: OutputSignal, - mut mosi: OutputSignal, - mut miso: InputSignal, - mut cs: OutputSignal, + sclk: Output<'static>, + mosi: Output<'static>, + miso: Input<'static>, + cs: Output<'static>, ) -> Self { - // TODO remove this (#2273) - // FIXME: devise a public API for signals - miso.enable_input(true, unsafe { esp_hal::Internal::conjure() }); - - mosi.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - mosi.enable_output(true, unsafe { esp_hal::Internal::conjure() }); - - cs.set_output_high(true, unsafe { esp_hal::Internal::conjure() }); - cs.enable_output(true, unsafe { esp_hal::Internal::conjure() }); - - sclk.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - sclk.enable_output(true, unsafe { esp_hal::Internal::conjure() }); - Self { sclk, mosi, @@ -70,29 +55,22 @@ impl BitbangSpi { } fn assert_cs(&mut self) { - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - self.cs - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); + self.cs.set_level(Level::Low); } fn deassert_cs(&mut self) { - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - self.cs - .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); + self.cs.set_level(Level::High); } // Mode 1, so sampled on the rising edge and set on the falling edge. fn shift_bit(&mut self, bit: bool) -> bool { - self.mosi - .set_output_high(bit, unsafe { esp_hal::Internal::conjure() }); - self.sclk - .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + self.mosi.set_level(Level::from(bit)); + self.sclk.set_level(Level::High); let miso = self.miso.get_level().into(); - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); miso } @@ -141,21 +119,19 @@ mod tests { } } - let (cs, cs_pin) = cs_pin.split(); - let (mosi, mosi_pin) = mosi_pin.split(); - let (miso, miso_pin) = miso_pin.split(); - let (sclk_signal, sclk_pin) = sclk_pin.split(); + let mosi_gpio = Output::new(mosi_pin, Level::Low); + let cs_gpio = Output::new(cs_pin, Level::High); + let sclk_gpio = Output::new(sclk_pin, Level::Low); + let miso_gpio = Input::new(miso_pin, Pull::None); + + let cs = cs_gpio.peripheral_input(); + let sclk = sclk_gpio.peripheral_input(); + let mosi = mosi_gpio.peripheral_input(); + let miso = unsafe { miso_gpio.clone_unchecked() }.into_peripheral_output(); Context { - spi: Spi::new( - peripherals.SPI2, - sclk_signal, - mosi, - miso_pin, - cs, - SpiMode::Mode1, - ), - bitbang_spi: BitbangSpi::new(sclk_pin, mosi_pin, miso, cs_pin), + spi: Spi::new(peripherals.SPI2, sclk, mosi, miso, cs, SpiMode::Mode1), + bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso_gpio, cs_gpio), dma_channel, } } From 255f5e7c73cc3724506f107e3a622f322ca2745a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 15:11:49 +0100 Subject: [PATCH 32/67] TWAI: Always configure a default filter (#2467) --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/twai/mod.rs | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d112b9a9f65..4f19140fa13 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -62,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed `TWAI::transmit_async`: bus-off state is not reached when CANH and CANL are shorted. (#2421) - ESP32: added UART-specific workaround for https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html (#2441) - Fixed some SysTimer race conditions and panics (#2451) +- TWAI: accept all messages by default (#2467) ### Removed diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 5739ffd6d85..7d6b25c21b9 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -140,6 +140,7 @@ use crate::{ peripheral::{Peripheral, PeripheralRef}, peripherals::twai0::RegisterBlock, system::PeripheralClockControl, + twai::filter::SingleStandardFilter, Async, Blocking, InterruptConfigurable, @@ -752,6 +753,7 @@ impl BaudRate { /// An inactive TWAI peripheral in the "Reset"/configuration state. pub struct TwaiConfiguration<'d, DM: crate::Mode, T = AnyTwai> { twai: PeripheralRef<'d, T>, + filter: Option<(FilterType, [u8; 8])>, phantom: PhantomData, mode: TwaiMode, } @@ -778,10 +780,16 @@ where let mut this = TwaiConfiguration { twai, + filter: None, // We'll immediately call `set_filter` phantom: PhantomData, mode, }; + // Accept all messages by default. + this.set_filter( + const { SingleStandardFilter::new(b"xxxxxxxxxxx", b"x", [b"xxxxxxxx", b"xxxxxxxx"]) }, + ); + // Set RESET bit to 1 this.twai .register_block() @@ -936,22 +944,30 @@ where /// You may use a `const {}` block to ensure that the filter is parsed /// during program compilation. /// + /// The filter is not applied to the peripheral until [`Self::start`] is + /// called. + /// /// [ESP32C3 Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf#subsubsection.29.4.6) pub fn set_filter(&mut self, filter: impl Filter) { + // Convert the filter into values for the registers and store them for later + // use. + self.filter = Some((filter.filter_type(), filter.to_registers())); + } + + fn apply_filter(&self) { + let Some((filter_type, registers)) = self.filter.as_ref() else { + return; + }; + + let register_block = self.twai.register_block(); // Set or clear the rx filter mode bit depending on the filter type. - let filter_mode_bit = filter.filter_type() == FilterType::Single; - self.twai - .register_block() + register_block .mode() - .modify(|_, w| w.rx_filter_mode().bit(filter_mode_bit)); - - // Convert the filter into values for the registers and store them to the - // registers. - let registers = filter.to_registers(); + .modify(|_, w| w.rx_filter_mode().bit(*filter_type == FilterType::Single)); // Copy the filter to the peripheral. unsafe { - copy_to_data_register(self.twai.register_block().data_0().as_ptr(), ®isters); + copy_to_data_register(register_block.data_0().as_ptr(), registers); } } @@ -980,6 +996,7 @@ where /// Put the peripheral into Operation Mode, allowing the transmission and /// reception of packets using the new object. pub fn start(self) -> Twai<'d, DM, T> { + self.apply_filter(); self.set_mode(self.mode); // Clear the TEC and REC @@ -1101,6 +1118,7 @@ where self.set_interrupt_handler(self.twai.async_handler()); TwaiConfiguration { twai: self.twai, + filter: self.filter, phantom: PhantomData, mode: self.mode, } @@ -1120,6 +1138,7 @@ where // Re-create in blocking mode TwaiConfiguration { twai: self.twai, + filter: self.filter, phantom: PhantomData, mode: self.mode, } @@ -1179,6 +1198,7 @@ where TwaiConfiguration { twai: self.twai, + filter: None, // filter already applied, no need to restore it phantom: PhantomData, mode, } From feac6f17c38c89f61732ff3dffc37727524d08bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 7 Nov 2024 10:37:56 +0100 Subject: [PATCH 33/67] Mark State/Info as #[non_exhaustive] (#2471) --- esp-hal/src/spi/master.rs | 1 + esp-hal/src/uart.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 141a348a836..6720f6d9082 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -2165,6 +2165,7 @@ pub trait Instance: pub trait QspiInstance: Instance {} /// Peripheral data describing a particular SPI instance. +#[non_exhaustive] pub struct Info { /// Pointer to the register block for this SPI instance. /// diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 812b4abd134..142c2f8c9b6 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -2174,6 +2174,7 @@ pub trait Instance: Peripheral

+ PeripheralMarker + Into + 's } /// Peripheral data describing a particular UART instance. +#[non_exhaustive] pub struct Info { /// Pointer to the register block for this UART instance. /// @@ -2200,6 +2201,7 @@ pub struct Info { } /// Peripheral state for a UART instance. +#[non_exhaustive] pub struct State { /// Waker for the asynchronous RX operations. pub rx_waker: AtomicWaker, From 0da6eec089d95dfd19d5e4cc51332573713ccd62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 7 Nov 2024 10:39:08 +0100 Subject: [PATCH 34/67] Move I2S drivers to i2s::master and i2s::parallel (#2472) * Move I2S drivers to i2s::master and i2s::parallel * Remove mention of master mode --- esp-hal/CHANGELOG.md | 3 +- esp-hal/MIGRATING-0.21.md | 59 +++++++++++-------- esp-hal/src/{i2s.rs => i2s/master.rs} | 6 +- esp-hal/src/i2s/mod.rs | 6 ++ .../src/{i2s_parallel.rs => i2s/parallel.rs} | 2 +- esp-hal/src/lib.rs | 2 - examples/src/bin/embassy_i2s_parallel.rs | 2 +- examples/src/bin/embassy_i2s_read.rs | 2 +- examples/src/bin/embassy_i2s_sound.rs | 2 +- examples/src/bin/i2s_parallel.rs | 2 +- examples/src/bin/i2s_read.rs | 2 +- examples/src/bin/i2s_sound.rs | 2 +- hil-test/tests/i2s.rs | 2 +- 13 files changed, 52 insertions(+), 40 deletions(-) rename esp-hal/src/{i2s.rs => i2s/master.rs} (99%) create mode 100644 esp-hal/src/i2s/mod.rs rename esp-hal/src/{i2s_parallel.rs => i2s/parallel.rs} (99%) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 4f19140fa13..f9a8a744da1 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373) - `Cpu::COUNT` and `Cpu::current()` (#2411) - `UartInterrupt` and related functions (#2406) -- I2S Parallel output driver for ESP32. (#2348, #2436) +- I2S Parallel output driver for ESP32. (#2348, #2436, #2472) - Add an option to configure `WDT` action (#2330) - `DmaDescriptor` is now `Send` (#2456) - `into_async` and `into_blocking` functions for most peripherals (#2430, #2461) @@ -54,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - UART configuration types have been moved to `esp_hal::uart` (#2449) - `spi::master::Spi::new()` no longer takes `frequency` and `mode` as a parameter. (#2448) - Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419) +- The I2S driver has been moved to `i2s::master` (#2472) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index d490ce16778..e803f1377e9 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -1,28 +1,5 @@ # Migration Guide from 0.21.x to v0.22.x -## Removed `i2s` traits - -The following traits have been removed: - -- `I2sWrite` -- `I2sWriteDma` -- `I2sRead` -- `I2sReadDma` -- `I2sWriteDmaAsync` -- `I2sReadDmaAsync` - -You no longer have to import these to access their respective APIs. If you used these traits -in your functions as generic parameters, you can use the `I2s` type directly instead. - -For example: - -```diff --fn foo(i2s: &mut impl I2sWrite) { -+fn foo(i2s: &mut I2s<'_, I2S0, Blocking>) { - // ... - } -``` - ## Removed `async`-specific constructors The following async-specific constuctors have been removed: @@ -55,8 +32,8 @@ You can use the blocking counterparts, then call `into_async` on the returned pe Some drivers were implicitly configured to the asyncness of the DMA channel used to construct them. This is no longer the case, and the following drivers will always be created in blocking mode: -- `I2s` -- `master::SpiDma` and `master::SpiDmaBus` +- `i2s::master::I2s` +- `spi::master::SpiDma` and `spi::master::SpiDmaBus` ## Peripheral types are now optional @@ -196,6 +173,38 @@ You can now listen/unlisten multiple interrupt bits at once: +uart0.listen(UartInterrupt::AtCmd | UartConterrupt::RxFifoFull); ``` +## I2S changes + +### The I2S driver has been moved to `i2s::master` + +```diff +-use esp_hal::i2s::{DataFormat, I2s, Standard}; ++use esp_hal::i2s::master::{DataFormat, I2s, Standard}; +``` + +### Removed `i2s` traits + +The following traits have been removed: + +- `I2sWrite` +- `I2sWriteDma` +- `I2sRead` +- `I2sReadDma` +- `I2sWriteDmaAsync` +- `I2sReadDmaAsync` + +You no longer have to import these to access their respective APIs. If you used these traits +in your functions as generic parameters, you can use the `I2s` type directly instead. + +For example: + +```diff +-fn foo(i2s: &mut impl I2sWrite) { ++fn foo(i2s: &mut I2s<'_, I2S0, Blocking>) { + // ... + } +``` + ## Circular DMA transfer's `available` returns `Result` now In case of any error you should drop the transfer and restart it. diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s/master.rs similarity index 99% rename from esp-hal/src/i2s.rs rename to esp-hal/src/i2s/master.rs index 0a44a75fa6d..78728ac36a2 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s/master.rs @@ -29,9 +29,7 @@ //! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::i2s::I2s; -//! # use esp_hal::i2s::Standard; -//! # use esp_hal::i2s::DataFormat; +//! # use esp_hal::i2s::master::{I2s, Standard, DataFormat}; //! # use esp_hal::gpio::Io; //! # use esp_hal::dma_buffers; //! # use esp_hal::dma::{Dma, DmaPriority}; @@ -75,7 +73,7 @@ //! ``` //! //! ## Implementation State -//! - Only master mode is supported. +//! //! - Only TDM Philips standard is supported. use core::marker::PhantomData; diff --git a/esp-hal/src/i2s/mod.rs b/esp-hal/src/i2s/mod.rs new file mode 100644 index 00000000000..2b0bfd6eb6a --- /dev/null +++ b/esp-hal/src/i2s/mod.rs @@ -0,0 +1,6 @@ +//! # Inter-IC Sound (I2S) + +pub mod master; + +#[cfg(esp32)] +pub mod parallel; diff --git a/esp-hal/src/i2s_parallel.rs b/esp-hal/src/i2s/parallel.rs similarity index 99% rename from esp-hal/src/i2s_parallel.rs rename to esp-hal/src/i2s/parallel.rs index 37fd6585d43..d8888f25379 100644 --- a/esp-hal/src/i2s_parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -395,7 +395,7 @@ fn calculate_clock(sample_rate: impl Into, data_bits: u8) -> I2 } else { let mut min: u32 = !0; - for a in 2..=crate::i2s::I2S_LL_MCLK_DIVIDER_MAX { + for a in 2..=crate::i2s::master::I2S_LL_MCLK_DIVIDER_MAX { let b = (a as u64) * (freq_diff as u64 * 10000u64 / mclk as u64) + 5000; ma = ((freq_diff as u64 * 10000u64 * a as u64) / 10000) as u32; mb = (mclk as u64 * (b / 10000)) as u32; diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 8ff2815bc70..aa8dda2a86c 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -191,8 +191,6 @@ pub mod hmac; pub mod i2c; #[cfg(any(i2s0, i2s1))] pub mod i2s; -#[cfg(esp32)] -pub mod i2s_parallel; #[cfg(any(dport, interrupt_core0, interrupt_core1))] pub mod interrupt; #[cfg(lcd_cam)] diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs index 509f7183595..322b5e4a95b 100644 --- a/examples/src/bin/embassy_i2s_parallel.rs +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -21,7 +21,7 @@ use esp_hal::{ dma::{Dma, DmaPriority, DmaTxBuf}, dma_buffers, gpio::Io, - i2s_parallel::{I2sParallel, TxEightBits}, + i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, timer::timg::TimerGroup, }; diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index afb796c1c42..196793e9c23 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -23,7 +23,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::Io, - i2s::{DataFormat, I2s, Standard}, + i2s::master::{DataFormat, I2s, Standard}, prelude::*, timer::timg::TimerGroup, }; diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index 2c807a4755c..dd48f782738 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -37,7 +37,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::Io, - i2s::{DataFormat, I2s, Standard}, + i2s::master::{DataFormat, I2s, Standard}, prelude::*, timer::timg::TimerGroup, }; diff --git a/examples/src/bin/i2s_parallel.rs b/examples/src/bin/i2s_parallel.rs index 0634b8cbe9a..4effbf654f0 100644 --- a/examples/src/bin/i2s_parallel.rs +++ b/examples/src/bin/i2s_parallel.rs @@ -19,7 +19,7 @@ use esp_hal::{ dma::{Dma, DmaPriority, DmaTxBuf}, dma_buffers, gpio::Io, - i2s_parallel::{I2sParallel, TxEightBits}, + i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, }; use log::info; diff --git a/examples/src/bin/i2s_read.rs b/examples/src/bin/i2s_read.rs index 8274fb69d71..4e2278ff632 100644 --- a/examples/src/bin/i2s_read.rs +++ b/examples/src/bin/i2s_read.rs @@ -21,7 +21,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::Io, - i2s::{DataFormat, I2s, Standard}, + i2s::master::{DataFormat, I2s, Standard}, prelude::*, }; use esp_println::println; diff --git a/examples/src/bin/i2s_sound.rs b/examples/src/bin/i2s_sound.rs index 72e2d7b8e12..8058ef82361 100644 --- a/examples/src/bin/i2s_sound.rs +++ b/examples/src/bin/i2s_sound.rs @@ -35,7 +35,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::Io, - i2s::{DataFormat, I2s, Standard}, + i2s::master::{DataFormat, I2s, Standard}, prelude::*, }; diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 0156c26b88d..7610e7791ff 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -15,7 +15,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::{Io, NoPin}, - i2s::{DataFormat, I2s, I2sTx, Standard}, + i2s::master::{DataFormat, I2s, I2sTx, Standard}, peripherals::I2S0, prelude::*, Async, From 8782429e9f5f451d807884688a0132334af95d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 7 Nov 2024 10:41:16 +0100 Subject: [PATCH 35/67] SPI slave: remove public hidden API (#2470) * Redo declaration as macro * Add Info * Move impl out of Instance traits * Publish traits --- esp-hal/src/spi/slave.rs | 459 ++++++++++++++++++--------------------- 1 file changed, 217 insertions(+), 242 deletions(-) diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 675d66b2d36..3921532456c 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -75,7 +75,7 @@ use core::marker::PhantomData; use super::{Error, SpiMode}; use crate::{ - dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, + dma::{DmaChannelConvert, DmaEligible, PeripheralMarker}, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -144,16 +144,16 @@ where // TODO: with_pins et. al. sclk.enable_input(true, private::Internal); - this.spi.sclk_signal().connect_to(sclk); + this.spi.info().sclk.connect_to(sclk); mosi.enable_input(true, private::Internal); - this.spi.mosi_signal().connect_to(mosi); + this.spi.info().mosi.connect_to(mosi); miso.set_to_push_pull_output(private::Internal); - this.spi.miso_signal().connect_to(miso); + this.spi.info().miso.connect_to(miso); cs.enable_input(true, private::Internal); - this.spi.cs_signal().connect_to(cs); + this.spi.info().cs.connect_to(cs); this } @@ -161,7 +161,7 @@ where pub(crate) fn new_internal(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, M, T> { crate::into_ref!(spi); - let mut spi = Spi { + let spi = Spi { spi, data_mode: mode, _mode: PhantomData, @@ -170,8 +170,8 @@ where PeripheralClockControl::reset(spi.spi.peripheral()); PeripheralClockControl::enable(spi.spi.peripheral()); - spi.spi.init(); - spi.spi.set_data_mode(mode, false); + spi.spi.info().init(); + spi.spi.info().set_data_mode(mode, false); spi } @@ -208,7 +208,7 @@ pub mod dma { /// descriptors. #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] pub fn with_dma( - mut self, + self, channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -218,7 +218,7 @@ pub mod dma { DM: Mode, Channel<'d, CH, M>: From>, { - self.spi.set_data_mode(self.data_mode, true); + self.spi.info().set_data_mode(self.data_mode, true); SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors) } } @@ -253,10 +253,10 @@ pub mod dma { fn peripheral_wait_dma(&mut self, is_rx: bool, is_tx: bool) { while !((!is_tx || self.channel.tx.is_done()) && (!is_rx || self.channel.rx.is_done()) - && !self.spi.is_bus_busy()) + && !self.spi.info().is_bus_busy()) {} - self.spi.flush().ok(); + self.spi.info().flush().ok(); } fn peripheral_dma_stop(&mut self) { @@ -318,6 +318,14 @@ pub mod dma { tx_chain: DescriptorChain::new(tx_descriptors), } } + + fn driver(&self) -> DmaDriver { + DmaDriver { + info: self.spi.info(), + dma_peripheral: self.spi.dma_peripheral(), + } + } + /// Register a buffer for a DMA write. /// /// This will return a [DmaTransferTx]. The maximum amount of data to be @@ -338,7 +346,7 @@ pub mod dma { } unsafe { - self.spi + self.driver() .start_transfer_dma( &mut self.rx_chain, &mut self.tx_chain, @@ -373,7 +381,7 @@ pub mod dma { } unsafe { - self.spi + self.driver() .start_transfer_dma( &mut self.rx_chain, &mut self.tx_chain, @@ -412,7 +420,7 @@ pub mod dma { } unsafe { - self.spi + self.driver() .start_transfer_dma( &mut self.rx_chain, &mut self.tx_chain, @@ -427,163 +435,197 @@ pub mod dma { } } } -} -#[doc(hidden)] -pub trait InstanceDma: Instance + DmaEligible { - #[allow(clippy::too_many_arguments)] - unsafe fn start_transfer_dma( - &mut self, - rx_chain: &mut DescriptorChain, - tx_chain: &mut DescriptorChain, - read_buffer_ptr: *mut u8, - read_buffer_len: usize, - write_buffer_ptr: *const u8, - write_buffer_len: usize, - rx: &mut RX, - tx: &mut TX, - ) -> Result<(), Error> - where - RX: Rx, - TX: Tx, - { - let reg_block = self.register_block(); + struct DmaDriver { + info: &'static Info, + dma_peripheral: crate::dma::DmaPeripheral, + } - self.enable_dma(); + impl DmaDriver { + #[allow(clippy::too_many_arguments)] + unsafe fn start_transfer_dma( + &self, + rx_chain: &mut DescriptorChain, + tx_chain: &mut DescriptorChain, + read_buffer_ptr: *mut u8, + read_buffer_len: usize, + write_buffer_ptr: *const u8, + write_buffer_len: usize, + rx: &mut RX, + tx: &mut TX, + ) -> Result<(), Error> + where + RX: Rx, + TX: Tx, + { + self.enable_dma(); - reset_spi(reg_block); + self.info.reset_spi(); - if read_buffer_len > 0 { - rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?; - rx.prepare_transfer_without_start(self.dma_peripheral(), rx_chain)?; - } + if read_buffer_len > 0 { + rx_chain.fill_for_rx(false, read_buffer_ptr, read_buffer_len)?; + rx.prepare_transfer_without_start(self.dma_peripheral, rx_chain)?; + } - if write_buffer_len > 0 { - tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?; - tx.prepare_transfer_without_start(self.dma_peripheral(), tx_chain)?; - } + if write_buffer_len > 0 { + tx_chain.fill_for_tx(false, write_buffer_ptr, write_buffer_len)?; + tx.prepare_transfer_without_start(self.dma_peripheral, tx_chain)?; + } - #[cfg(esp32)] - self.prepare_length_and_lines(read_buffer_len, write_buffer_len); + #[cfg(esp32)] + self.info + .prepare_length_and_lines(read_buffer_len, write_buffer_len); - reset_dma_before_usr_cmd(reg_block); + self.reset_dma_before_usr_cmd(); - #[cfg(not(esp32))] - reg_block - .dma_conf() - .modify(|_, w| w.dma_slv_seg_trans_en().clear_bit()); + let reg_block = self.info.register_block(); + #[cfg(not(esp32))] + reg_block + .dma_conf() + .modify(|_, w| w.dma_slv_seg_trans_en().clear_bit()); - self.clear_dma_interrupts(); - self.setup_for_flush(); - reg_block.cmd().modify(|_, w| w.usr().set_bit()); + self.clear_dma_interrupts(); + self.info.setup_for_flush(); + reg_block.cmd().modify(|_, w| w.usr().set_bit()); - if read_buffer_len > 0 { - rx.start_transfer()?; - } + if read_buffer_len > 0 { + rx.start_transfer()?; + } - if write_buffer_len > 0 { - tx.start_transfer()?; - } + if write_buffer_len > 0 { + tx.start_transfer()?; + } - Ok(()) - } + Ok(()) + } - fn enable_dma(&self) { - let reg_block = self.register_block(); - #[cfg(gdma)] - { + fn reset_dma_before_usr_cmd(&self) { + let reg_block = self.info.register_block(); + #[cfg(gdma)] reg_block.dma_conf().modify(|_, w| { - w.dma_tx_ena().set_bit(); - w.dma_rx_ena().set_bit(); - w.rx_eof_en().clear_bit() + w.rx_afifo_rst().set_bit(); + w.buf_afifo_rst().set_bit(); + w.dma_afifo_rst().set_bit() }); + + #[cfg(pdma)] + let _ = reg_block; } - #[cfg(pdma)] - { - fn set_rst_bit(reg_block: &RegisterBlock, bit: bool) { + fn enable_dma(&self) { + let reg_block = self.info.register_block(); + #[cfg(gdma)] + { reg_block.dma_conf().modify(|_, w| { - w.in_rst().bit(bit); - w.out_rst().bit(bit); - w.ahbm_fifo_rst().bit(bit); - w.ahbm_rst().bit(bit) + w.dma_tx_ena().set_bit(); + w.dma_rx_ena().set_bit(); + w.rx_eof_en().clear_bit() }); + } - #[cfg(esp32s2)] - reg_block - .dma_conf() - .modify(|_, w| w.dma_infifo_full_clr().bit(bit)); + #[cfg(pdma)] + { + fn set_rst_bit(reg_block: &RegisterBlock, bit: bool) { + reg_block.dma_conf().modify(|_, w| { + w.in_rst().bit(bit); + w.out_rst().bit(bit); + w.ahbm_fifo_rst().bit(bit); + w.ahbm_rst().bit(bit) + }); + + #[cfg(esp32s2)] + reg_block + .dma_conf() + .modify(|_, w| w.dma_infifo_full_clr().bit(bit)); + } + set_rst_bit(reg_block, true); + set_rst_bit(reg_block, false); } - set_rst_bit(reg_block, true); - set_rst_bit(reg_block, false); } - } - fn clear_dma_interrupts(&self) { - let reg_block = self.register_block(); + fn clear_dma_interrupts(&self) { + let reg_block = self.info.register_block(); - #[cfg(gdma)] - reg_block.dma_int_clr().write(|w| { - w.dma_infifo_full_err().clear_bit_by_one(); - w.dma_outfifo_empty_err().clear_bit_by_one(); - w.trans_done().clear_bit_by_one(); - w.mst_rx_afifo_wfull_err().clear_bit_by_one(); - w.mst_tx_afifo_rempty_err().clear_bit_by_one() - }); + #[cfg(gdma)] + reg_block.dma_int_clr().write(|w| { + w.dma_infifo_full_err().clear_bit_by_one(); + w.dma_outfifo_empty_err().clear_bit_by_one(); + w.trans_done().clear_bit_by_one(); + w.mst_rx_afifo_wfull_err().clear_bit_by_one(); + w.mst_tx_afifo_rempty_err().clear_bit_by_one() + }); - #[cfg(pdma)] - reg_block.dma_int_clr().write(|w| { - w.inlink_dscr_empty().clear_bit_by_one(); - w.outlink_dscr_error().clear_bit_by_one(); - w.inlink_dscr_error().clear_bit_by_one(); - w.in_done().clear_bit_by_one(); - w.in_err_eof().clear_bit_by_one(); - w.in_suc_eof().clear_bit_by_one(); - w.out_done().clear_bit_by_one(); - w.out_eof().clear_bit_by_one(); - w.out_total_eof().clear_bit_by_one() - }); + #[cfg(pdma)] + reg_block.dma_int_clr().write(|w| { + w.inlink_dscr_empty().clear_bit_by_one(); + w.outlink_dscr_error().clear_bit_by_one(); + w.inlink_dscr_error().clear_bit_by_one(); + w.in_done().clear_bit_by_one(); + w.in_err_eof().clear_bit_by_one(); + w.in_suc_eof().clear_bit_by_one(); + w.out_done().clear_bit_by_one(); + w.out_eof().clear_bit_by_one(); + w.out_total_eof().clear_bit_by_one() + }); + } } } -fn reset_spi(reg_block: &RegisterBlock) { - #[cfg(esp32)] - { - reg_block.slave().modify(|_, w| w.sync_reset().set_bit()); - reg_block.slave().modify(|_, w| w.sync_reset().clear_bit()); - } - - #[cfg(not(esp32))] - { - reg_block.slave().modify(|_, w| w.soft_reset().set_bit()); - reg_block.slave().modify(|_, w| w.soft_reset().clear_bit()); - } +/// SPI peripheral instance. +pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'static { + /// Returns the peripheral data describing this SPI instance. + fn info(&self) -> &'static Info; } -fn reset_dma_before_usr_cmd(reg_block: &RegisterBlock) { - #[cfg(gdma)] - reg_block.dma_conf().modify(|_, w| { - w.rx_afifo_rst().set_bit(); - w.buf_afifo_rst().set_bit(); - w.dma_afifo_rst().set_bit() - }); - - #[cfg(pdma)] - let _ = reg_block; -} +/// A marker for DMA-capable SPI peripheral instances. +pub trait InstanceDma: Instance + DmaEligible {} impl InstanceDma for crate::peripherals::SPI2 {} #[cfg(spi3)] impl InstanceDma for crate::peripherals::SPI3 {} -#[doc(hidden)] -pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'static { - fn register_block(&self) -> &RegisterBlock; +/// Peripheral data describing a particular SPI instance. +#[non_exhaustive] +pub struct Info { + /// Pointer to the register block for this SPI instance. + /// + /// Use [Self::register_block] to access the register block. + pub register_block: *const RegisterBlock, + + /// SCLK signal. + pub sclk: InputSignal, + + /// MOSI signal. + pub mosi: InputSignal, + + /// MISO signal. + pub miso: OutputSignal, + + /// Chip select signal. + pub cs: InputSignal, +} + +impl Info { + /// Returns the register block for this SPI instance. + pub fn register_block(&self) -> &RegisterBlock { + unsafe { &*self.register_block } + } + + fn reset_spi(&self) { + let reg_block = self.register_block(); + + #[cfg(esp32)] + { + reg_block.slave().modify(|_, w| w.sync_reset().set_bit()); + reg_block.slave().modify(|_, w| w.sync_reset().clear_bit()); + } - fn sclk_signal(&self) -> InputSignal; - fn mosi_signal(&self) -> InputSignal; - fn miso_signal(&self) -> OutputSignal; - fn cs_signal(&self) -> InputSignal; + #[cfg(not(esp32))] + { + reg_block.slave().modify(|_, w| w.soft_reset().set_bit()); + reg_block.slave().modify(|_, w| w.soft_reset().clear_bit()); + } + } #[cfg(esp32)] fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) { @@ -604,7 +646,7 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st } /// Initialize for full-duplex 1 bit mode - fn init(&mut self) { + fn init(&self) { let reg_block = self.register_block(); reg_block.clock().write(|w| unsafe { w.bits(0) }); @@ -617,7 +659,7 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st w.mode().set_bit() }); - reset_spi(reg_block); + self.reset_spi(); reg_block.user().modify(|_, w| { w.doutdin().set_bit(); @@ -628,7 +670,7 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st reg_block.misc().write(|w| unsafe { w.bits(0) }); } - fn set_data_mode(&mut self, data_mode: SpiMode, dma: bool) -> &mut Self { + fn set_data_mode(&self, data_mode: SpiMode, dma: bool) { let reg_block = self.register_block(); #[cfg(esp32)] { @@ -699,8 +741,6 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st .bit(matches!(data_mode, SpiMode::Mode1 | SpiMode::Mode3)) }); } - - self } fn is_bus_busy(&self) -> bool { @@ -717,7 +757,7 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st } // Check if the bus is busy and if it is wait for it to be idle - fn flush(&mut self) -> Result<(), Error> { + fn flush(&self) -> Result<(), Error> { while self.is_bus_busy() { // Wait for bus to be clear } @@ -738,107 +778,46 @@ pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'st } } -#[cfg(spi2)] -impl Instance for crate::peripherals::SPI2 { - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } - - #[inline(always)] - fn sclk_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPICLK - } else { - InputSignal::FSPICLK - } - } - } - - #[inline(always)] - fn mosi_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPID - } else { - InputSignal::FSPID - } - } - } - - #[inline(always)] - fn miso_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIQ - } else { - OutputSignal::FSPIQ - } - } - } - - #[inline(always)] - fn cs_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPICS0 - } else { - InputSignal::FSPICS0 - } - } +impl PartialEq for Info { + fn eq(&self, other: &Self) -> bool { + self.register_block == other.register_block } } -#[cfg(spi3)] -impl Instance for crate::peripherals::SPI3 { - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } - - #[inline(always)] - fn sclk_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::VSPICLK - } else { - InputSignal::SPI3_CLK - } - } - } - - #[inline(always)] - fn mosi_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::VSPID - } else { - InputSignal::SPI3_D - } - } - } - - #[inline(always)] - fn miso_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::VSPIQ - } else { - OutputSignal::SPI3_Q +unsafe impl Sync for Info {} + +macro_rules! spi_instance { + ($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident) => { + paste::paste! { + impl Instance for crate::peripherals::[] { + #[inline(always)] + fn info(&self) -> &'static Info { + static INFO: Info = Info { + register_block: crate::peripherals::[]::PTR, + sclk: InputSignal::$sclk, + mosi: InputSignal::$mosi, + miso: OutputSignal::$miso, + cs: InputSignal::$cs, + }; + + &INFO + } } } - } + }; +} - #[inline(always)] - fn cs_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::VSPICS0 - } else { - InputSignal::SPI3_CS0 - } - } +cfg_if::cfg_if! { + if #[cfg(esp32)] { + #[cfg(spi2)] + spi_instance!(2, HSPICLK, HSPID, HSPIQ, HSPICS0); + #[cfg(spi3)] + spi_instance!(3, VSPICLK, VSPID, VSPIQ, VSPICS0); + } else { + #[cfg(spi2)] + spi_instance!(2, FSPICLK, FSPID, FSPIQ, FSPICS0); + #[cfg(spi3)] + spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0); } } @@ -849,11 +828,7 @@ impl Instance for super::AnySpi { #[cfg(spi3)] super::AnySpiInner::Spi3(spi) => spi, } { - fn register_block(&self) -> &RegisterBlock; - fn sclk_signal(&self) -> InputSignal; - fn mosi_signal(&self) -> InputSignal; - fn miso_signal(&self) -> OutputSignal; - fn cs_signal(&self) -> InputSignal; + fn info(&self) -> &'static Info; } } } From ac819fb42fc9c4529712ec73412aef5fc9aa8279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 7 Nov 2024 14:51:48 +0100 Subject: [PATCH 36/67] Remove PeripheralMarker (#2468) * Redo DMA compatibility check using DmaEligible * Remove PeripheralMarker --- esp-hal/src/dma/gdma.rs | 5 +---- esp-hal/src/dma/mod.rs | 8 +------ esp-hal/src/dma/pdma.rs | 30 ++++++++++++++------------ esp-hal/src/i2c.rs | 15 ++++++------- esp-hal/src/i2s/master.rs | 23 ++++++++++---------- esp-hal/src/i2s/parallel.rs | 15 +++++++++---- esp-hal/src/macros.rs | 12 ----------- esp-hal/src/peripheral.rs | 20 ++++------------- esp-hal/src/soc/esp32/peripherals.rs | 16 +++++++------- esp-hal/src/soc/esp32c2/peripherals.rs | 6 +++--- esp-hal/src/soc/esp32c3/peripherals.rs | 10 ++++----- esp-hal/src/soc/esp32c6/peripherals.rs | 12 +++++------ esp-hal/src/soc/esp32h2/peripherals.rs | 10 ++++----- esp-hal/src/soc/esp32s2/peripherals.rs | 12 +++++------ esp-hal/src/soc/esp32s3/peripherals.rs | 18 ++++++++-------- esp-hal/src/spi/master.rs | 23 +++++++------------- esp-hal/src/spi/slave.rs | 12 +++++++---- esp-hal/src/twai/mod.rs | 15 +++++++++++-- esp-hal/src/uart.rs | 19 +++++++++------- 19 files changed, 133 insertions(+), 148 deletions(-) diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 769b570e278..bff710a2ec8 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -475,10 +475,7 @@ pub struct ChannelCreator {} impl Channel<'_, CH, M> { /// Asserts that the channel is compatible with the given peripheral. - pub fn runtime_ensure_compatible( - &self, - _peripheral: &PeripheralRef<'_, P>, - ) { + pub fn runtime_ensure_compatible(&self, _peripheral: &PeripheralRef<'_, P>) { // No runtime checks; GDMA channels are compatible with any peripheral } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index c759f6a6cc0..0cfbb2e5269 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -949,12 +949,6 @@ macro_rules! impl_dma_eligible { }; } -/// Marker trait -#[doc(hidden)] -pub trait PeripheralMarker { - fn peripheral(&self) -> crate::system::Peripheral; -} - #[doc(hidden)] #[derive(Debug)] pub struct DescriptorChain { @@ -2111,7 +2105,7 @@ pub trait RegisterAccess: crate::private::Sealed { fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize); #[cfg(pdma)] - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; /// Configure the channel. fn configure(&self, burst_mode: bool, priority: DmaPriority) { diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index ab18f2387c0..1659eb5f95d 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -31,7 +31,7 @@ pub trait PdmaChannel: crate::private::Sealed { fn register_block(&self) -> &Self::RegisterBlock; fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; } #[doc(hidden)] @@ -92,7 +92,7 @@ impl> RegisterAccess for SpiDma } } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { self.0.is_compatible_with(peripheral) } } @@ -236,7 +236,7 @@ impl> RegisterAccess for SpiDma } } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { self.0.is_compatible_with(peripheral) } } @@ -390,8 +390,8 @@ macro_rules! ImplSpiChannel { &WAKER } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { - peripheral.peripheral() == crate::system::Peripheral::[] + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { + peripheral == DmaPeripheral::[] } } @@ -497,7 +497,7 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true))); } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { self.0.is_compatible_with(peripheral) } } @@ -653,7 +653,7 @@ impl> RegisterAccess for I2sDma .modify(|_, w| w.check_owner().bit(check_owner.unwrap_or(true))); } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { self.0.is_compatible_with(peripheral) } } @@ -802,8 +802,8 @@ macro_rules! ImplI2sChannel { static WAKER: embassy_sync::waitqueue::AtomicWaker = embassy_sync::waitqueue::AtomicWaker::new(); &WAKER } - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool { - peripheral.peripheral() == crate::system::Peripheral::[] + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool { + peripheral == DmaPeripheral::[] } } @@ -909,11 +909,13 @@ where C: DmaChannel, { /// Asserts that the channel is compatible with the given peripheral. - pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl PeripheralMarker>) { + pub fn runtime_ensure_compatible(&self, peripheral: &PeripheralRef<'_, impl DmaEligible>) { assert!( - self.tx.tx_impl.is_compatible_with(&**peripheral), + self.tx + .tx_impl + .is_compatible_with(peripheral.dma_peripheral()), "This DMA channel is not compatible with {:?}", - peripheral.peripheral() + peripheral.dma_peripheral() ); } } @@ -963,7 +965,7 @@ impl PdmaChannel for AnySpiDmaChannelInner { fn register_block(&self) -> &SpiRegisterBlock; fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; } } } @@ -1017,7 +1019,7 @@ impl PdmaChannel for AnyI2sDmaChannelInner { fn register_block(&self) -> &I2sRegisterBlock; fn tx_waker(&self) -> &'static AtomicWaker; fn rx_waker(&self) -> &'static AtomicWaker; - fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; + fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool; } } } diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 0e636efe22d..62f342d6eac 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -66,7 +66,6 @@ use procmacros::handler; use crate::{ clock::Clocks, - dma::PeripheralMarker, gpio::{interconnect::PeripheralOutput, InputSignal, OutputSignal, Pull}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, @@ -1176,7 +1175,9 @@ pub(super) fn i2c1_handler() { /// I2C Peripheral Instance #[doc(hidden)] -pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { +pub trait Instance: Peripheral

+ Into + 'static { + fn peripheral(&self) -> crate::system::Peripheral; + /// Returns the interrupt associated with this I2C peripheral. fn interrupt(&self) -> crate::peripherals::Interrupt; @@ -2204,14 +2205,12 @@ fn write_fifo(register_block: &RegisterBlock, data: u8) { } } -impl PeripheralMarker for crate::peripherals::I2C0 { +impl Instance for crate::peripherals::I2C0 { #[inline(always)] fn peripheral(&self) -> crate::system::Peripheral { crate::system::Peripheral::I2cExt0 } -} -impl Instance for crate::peripherals::I2C0 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { i2c0_handler @@ -2254,15 +2253,12 @@ impl Instance for crate::peripherals::I2C0 { } #[cfg(i2c1)] -impl PeripheralMarker for crate::peripherals::I2C1 { +impl Instance for crate::peripherals::I2C1 { #[inline(always)] fn peripheral(&self) -> crate::system::Peripheral { crate::system::Peripheral::I2cExt1 } -} -#[cfg(i2c1)] -impl Instance for crate::peripherals::I2C1 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { i2c1_handler @@ -2322,6 +2318,7 @@ impl Instance for AnyI2c { AnyI2cInner::I2c1(i2c) => i2c, } { fn interrupt(&self) -> crate::peripherals::Interrupt; + fn peripheral(&self) -> crate::system::Peripheral; fn async_handler(&self) -> InterruptHandler; fn scl_output_signal(&self) -> OutputSignal; fn scl_input_signal(&self) -> InputSignal; diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 78728ac36a2..6a418b966e8 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -773,14 +773,7 @@ mod private { #[cfg(i2s1)] use crate::peripherals::{i2s1::RegisterBlock, I2S1}; use crate::{ - dma::{ - ChannelRx, - ChannelTx, - DescriptorChain, - DmaDescriptor, - DmaEligible, - PeripheralMarker, - }, + dma::{ChannelRx, ChannelTx, DescriptorChain, DmaDescriptor, DmaEligible}, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -911,10 +904,9 @@ mod private { } } - pub trait RegBlock: - Peripheral

+ PeripheralMarker + DmaEligible + Into + 'static - { + pub trait RegBlock: Peripheral

+ DmaEligible + Into + 'static { fn register_block(&self) -> &RegisterBlock; + fn peripheral(&self) -> crate::system::Peripheral; } pub trait Signals: RegBlock { @@ -1609,6 +1601,10 @@ mod private { fn register_block(&self) -> &RegisterBlock { unsafe { &*I2S0::PTR.cast::() } } + + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s0 + } } impl RegisterAccessPrivate for I2S0 { @@ -1713,6 +1709,10 @@ mod private { fn register_block(&self) -> &RegisterBlock { unsafe { &*I2S1::PTR.cast::() } } + + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s1 + } } #[cfg(i2s1)] @@ -1786,6 +1786,7 @@ mod private { super::AnyI2sInner::I2s1(i2s) => i2s, } { fn register_block(&self) -> &RegisterBlock; + fn peripheral(&self) -> crate::system::Peripheral; } } } diff --git a/esp-hal/src/i2s/parallel.rs b/esp-hal/src/i2s/parallel.rs index d8888f25379..865346fb648 100644 --- a/esp-hal/src/i2s/parallel.rs +++ b/esp-hal/src/i2s/parallel.rs @@ -52,7 +52,6 @@ use crate::{ DmaError, DmaPeripheral, DmaTxBuffer, - PeripheralMarker, Tx, }, gpio::{ @@ -424,10 +423,9 @@ fn calculate_clock(sample_rate: impl Into, data_bits: u8) -> I2 } #[doc(hidden)] -pub trait Instance: - Peripheral

+ PeripheralMarker + DmaEligible + Into + 'static -{ +pub trait Instance: Peripheral

+ DmaEligible + Into + 'static { fn register_block(&self) -> &RegisterBlock; + fn peripheral(&self) -> crate::system::Peripheral; fn ws_signal(&self) -> OutputSignal; fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal; @@ -614,6 +612,10 @@ impl Instance for I2S0 { unsafe { &*I2S0::PTR.cast::() } } + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s0 + } + fn ws_signal(&self) -> OutputSignal { OutputSignal::I2S0O_WS } @@ -661,6 +663,10 @@ impl Instance for I2S1 { unsafe { &*I2S1::PTR.cast::() } } + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::I2s1 + } + fn ws_signal(&self) -> OutputSignal { OutputSignal::I2S1O_WS } @@ -729,6 +735,7 @@ impl Instance for AnyI2s { AnyI2sInner::I2s1(i2s) => i2s, } { fn register_block(&self) -> &RegisterBlock; + fn peripheral(&self) -> crate::system::Peripheral; fn ws_signal(&self) -> OutputSignal; fn data_out_signal(&self, i: usize, bits: u8) -> OutputSignal ; } diff --git a/esp-hal/src/macros.rs b/esp-hal/src/macros.rs index c22b5a44a6b..f4274d8033d 100644 --- a/esp-hal/src/macros.rs +++ b/esp-hal/src/macros.rs @@ -87,18 +87,6 @@ macro_rules! any_peripheral { $vis struct $name([< $name Inner >]); impl $crate::private::Sealed for $name {} - impl $crate::dma::PeripheralMarker for $name { - #[inline(always)] - fn peripheral(&self) -> $crate::system::Peripheral { - match &self.0 { - $( - $(#[cfg($variant_meta)])* - [<$name Inner>]::$variant(inner) => inner.peripheral(), - )* - } - } - } - impl $crate::peripheral::Peripheral for $name { type P = $name; diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index 9b3c230e3a9..6883d2caecc 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -210,10 +210,7 @@ mod peripheral_macros { /// Creates a new `Peripherals` struct and its associated methods. /// /// The macro has a few fields doing different things, in the form of - /// `[first] second <= third (fourth)`. - /// - The first field is the name of the `Peripherals` enum variant. This is - /// optional and used to create `PeripheralMarker` implementations for - /// DMA-eligible peripherals. + /// `second <= third (fourth)`. /// - The second field is the name of the peripheral, as it appears in the /// `Peripherals` struct. /// - The third field is the name of the peripheral as it appears in the @@ -226,7 +223,7 @@ mod peripheral_macros { macro_rules! peripherals { ( $( - $([$enum_variant:ident])? $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? + $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? ), *$(,)? ) => { @@ -234,7 +231,7 @@ mod peripheral_macros { mod peripherals { pub use super::pac::*; $( - $crate::create_peripheral!($([$enum_variant])? $name <= $from_pac); + $crate::create_peripheral!($name <= $from_pac); )* } @@ -327,7 +324,7 @@ mod peripheral_macros { #[macro_export] /// Macro to create a peripheral structure. macro_rules! create_peripheral { - ($([$enum_variant:ident])? $name:ident <= virtual) => { + ($name:ident <= virtual) => { #[derive(Debug)] #[allow(non_camel_case_types)] /// Represents a virtual peripheral with no associated hardware. @@ -358,15 +355,6 @@ mod peripheral_macros { } impl $crate::private::Sealed for $name {} - - $( - impl $crate::dma::PeripheralMarker for $crate::peripherals::$name { - #[inline(always)] - fn peripheral(&self) -> $crate::system::Peripheral { - $crate::system::Peripheral::$enum_variant - } - } - )? }; ($([$enum_variant:ident])? $name:ident <= $base:ident) => { diff --git a/esp-hal/src/soc/esp32/peripherals.rs b/esp-hal/src/soc/esp32/peripherals.rs index c0bd6f2732b..ab9b31ce6d1 100644 --- a/esp-hal/src/soc/esp32/peripherals.rs +++ b/esp-hal/src/soc/esp32/peripherals.rs @@ -38,8 +38,8 @@ crate::peripherals! { HINF <= HINF, I2C0 <= I2C0, I2C1 <= I2C1, - [I2s0] I2S0 <= I2S0 (I2S0), - [I2s1] I2S1 <= I2S1 (I2S1), + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), IO_MUX <= IO_MUX, LEDC <= LEDC, MCPWM0 <= MCPWM0, @@ -60,17 +60,17 @@ crate::peripherals! { SLCHOST <= SLCHOST, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2_DMA, SPI2), - [Spi3] SPI3 <= SPI3 (SPI3_DMA, SPI3), + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), SYSTEM <= DPORT, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, TOUCH <= virtual, - [Twai0] TWAI0 <= TWAI0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, - [Uart2] UART2 <= UART2, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, UHCI0 <= UHCI0, UHCI1 <= UHCI1, WIFI <= virtual, diff --git a/esp-hal/src/soc/esp32c2/peripherals.rs b/esp-hal/src/soc/esp32c2/peripherals.rs index 310c62416dc..3cd86959d96 100644 --- a/esp-hal/src/soc/esp32c2/peripherals.rs +++ b/esp-hal/src/soc/esp32c2/peripherals.rs @@ -40,13 +40,13 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2), + SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, + UART0 <= UART0, + UART1 <= UART1, WIFI <= virtual, XTS_AES <= XTS_AES, MEM2MEM1 <= virtual, diff --git a/esp-hal/src/soc/esp32c3/peripherals.rs b/esp-hal/src/soc/esp32c3/peripherals.rs index 12296386d6a..dd5308df0c2 100644 --- a/esp-hal/src/soc/esp32c3/peripherals.rs +++ b/esp-hal/src/soc/esp32c3/peripherals.rs @@ -34,7 +34,7 @@ crate::peripherals! { GPIO_SD <= GPIO_SD, HMAC <= HMAC, I2C0 <= I2C0, - [I2s0] I2S0 <= I2S0 (I2S0), + I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, IO_MUX <= IO_MUX, LEDC <= LEDC, @@ -47,15 +47,15 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2), + SPI2 <= SPI2 (SPI2), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, - [Twai0] TWAI0 <= TWAI0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, UHCI0 <= UHCI0, UHCI1 <= UHCI1, USB_DEVICE <= USB_DEVICE, diff --git a/esp-hal/src/soc/esp32c6/peripherals.rs b/esp-hal/src/soc/esp32c6/peripherals.rs index 8c5e2de92c7..ef74459ed22 100644 --- a/esp-hal/src/soc/esp32c6/peripherals.rs +++ b/esp-hal/src/soc/esp32c6/peripherals.rs @@ -37,7 +37,7 @@ crate::peripherals! { HP_APM <= HP_APM, HP_SYS <= HP_SYS, I2C0 <= I2C0, - [I2s0] I2S0 <= I2S0 (I2S0), + I2S0 <= I2S0 (I2S0), IEEE802154 <= IEEE802154, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, @@ -73,7 +73,7 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2), + SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, @@ -81,10 +81,10 @@ crate::peripherals! { TIMG0 <= TIMG0, TIMG1 <= TIMG1, TRACE0 <= TRACE, - [Twai0] TWAI0 <= TWAI0, - [Twai1] TWAI1 <= TWAI1, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, + TWAI0 <= TWAI0, + TWAI1 <= TWAI1, + UART0 <= UART0, + UART1 <= UART1, UHCI0 <= UHCI0, USB_DEVICE <= USB_DEVICE, WIFI <= virtual, diff --git a/esp-hal/src/soc/esp32h2/peripherals.rs b/esp-hal/src/soc/esp32h2/peripherals.rs index 37eb1285f68..7fbda39c981 100644 --- a/esp-hal/src/soc/esp32h2/peripherals.rs +++ b/esp-hal/src/soc/esp32h2/peripherals.rs @@ -35,7 +35,7 @@ crate::peripherals! { HP_SYS <= HP_SYS, I2C0 <= I2C0, I2C1 <= I2C1, - [I2s0] I2S0 <= I2S0 (I2S0), + I2S0 <= I2S0 (I2S0), IEEE802154 <= IEEE802154, INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTPRI <= INTPRI, @@ -65,7 +65,7 @@ crate::peripherals! { SOC_ETM <= SOC_ETM, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2), + SPI2 <= SPI2 (SPI2), SYSTEM <= PCR, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, @@ -73,9 +73,9 @@ crate::peripherals! { TIMG0 <= TIMG0, TIMG1 <= TIMG1, TRACE0 <= TRACE, - [Twai0] TWAI0 <= TWAI0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, UHCI0 <= UHCI0, USB_DEVICE <= USB_DEVICE, MEM2MEM1 <= virtual, diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs index d6bfb5b831f..c96d1c7b171 100644 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ b/esp-hal/src/soc/esp32s2/peripherals.rs @@ -35,7 +35,7 @@ crate::peripherals! { HMAC <= HMAC, I2C0 <= I2C0, I2C1 <= I2C1, - [I2s0] I2S0 <= I2S0 (I2S0), + I2S0 <= I2S0 (I2S0), INTERRUPT_CORE0 <= INTERRUPT_CORE0, IO_MUX <= IO_MUX, LEDC <= LEDC, @@ -52,17 +52,17 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2_DMA, SPI2), - [Spi3] SPI3 <= SPI3 (SPI3_DMA, SPI3), + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), SYSCON <= SYSCON, SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, - [Twai0] TWAI0 <= TWAI0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, UHCI0 <= UHCI0, ULP_RISCV_CORE <= virtual, USB0 <= USB0, diff --git a/esp-hal/src/soc/esp32s3/peripherals.rs b/esp-hal/src/soc/esp32s3/peripherals.rs index 30159a65367..9e0592abf52 100644 --- a/esp-hal/src/soc/esp32s3/peripherals.rs +++ b/esp-hal/src/soc/esp32s3/peripherals.rs @@ -36,12 +36,12 @@ crate::peripherals! { HMAC <= HMAC, I2C0 <= I2C0, I2C1 <= I2C1, - [I2s0] I2S0 <= I2S0 (I2S0), - [I2s1] I2S1 <= I2S1 (I2S1), + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), INTERRUPT_CORE0 <= INTERRUPT_CORE0, INTERRUPT_CORE1 <= INTERRUPT_CORE1, IO_MUX <= IO_MUX, - [LcdCam] LCD_CAM <= LCD_CAM, + LCD_CAM <= LCD_CAM, LEDC <= LEDC, LPWR <= RTC_CNTL, PCNT <= PCNT, @@ -59,17 +59,17 @@ crate::peripherals! { SHA <= SHA, SPI0 <= SPI0, SPI1 <= SPI1, - [Spi2] SPI2 <= SPI2 (SPI2), - [Spi3] SPI3 <= SPI3 (SPI3), + SPI2 <= SPI2 (SPI2), + SPI3 <= SPI3 (SPI3), SYSTEM <= SYSTEM, SYSTIMER <= SYSTIMER, SW_INTERRUPT <= virtual, TIMG0 <= TIMG0, TIMG1 <= TIMG1, - [Twai0] TWAI0 <= TWAI0, - [Uart0] UART0 <= UART0, - [Uart1] UART1 <= UART1, - [Uart2] UART2 <= UART2, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, UHCI0 <= UHCI0, UHCI1 <= UHCI1, ULP_RISCV_CORE <= virtual, diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 6720f6d9082..1609c7c2909 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -80,16 +80,7 @@ use procmacros::ram; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use crate::{ clock::Clocks, - dma::{ - Channel, - DmaChannelConvert, - DmaEligible, - DmaRxBuffer, - DmaTxBuffer, - PeripheralMarker, - Rx, - Tx, - }, + dma::{Channel, DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, Rx, Tx}, gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, @@ -589,8 +580,8 @@ where _mode: PhantomData, }; - PeripheralClockControl::enable(this.spi.peripheral()); - PeripheralClockControl::reset(this.spi.peripheral()); + PeripheralClockControl::enable(this.driver().peripheral); + PeripheralClockControl::reset(this.driver().peripheral); this.driver().init(); unwrap!(this.apply_config(&config)); // FIXME: update based on the resolution of https://github.com/esp-rs/esp-hal/issues/2416 @@ -2154,9 +2145,7 @@ mod ehal1 { } /// SPI peripheral instance. -pub trait Instance: - private::Sealed + PeripheralMarker + Into + DmaEligible + 'static -{ +pub trait Instance: private::Sealed + Into + DmaEligible + 'static { /// Returns the peripheral data describing this SPI instance. fn info(&self) -> &'static Info; } @@ -2172,6 +2161,9 @@ pub struct Info { /// Use [Self::register_block] to access the register block. pub register_block: *const RegisterBlock, + /// The system peripheral marker. + pub peripheral: crate::system::Peripheral, + /// Interrupt for this SPI instance. pub interrupt: crate::peripherals::Interrupt, @@ -3005,6 +2997,7 @@ macro_rules! spi_instance { fn info(&self) -> &'static Info { static INFO: Info = Info { register_block: crate::peripherals::[]::PTR, + peripheral: crate::system::Peripheral::[], interrupt: crate::peripherals::Interrupt::[], sclk: OutputSignal::$sclk, mosi: OutputSignal::$mosi, diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 3921532456c..0ffad8f7c9d 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -75,7 +75,7 @@ use core::marker::PhantomData; use super::{Error, SpiMode}; use crate::{ - dma::{DmaChannelConvert, DmaEligible, PeripheralMarker}, + dma::{DmaChannelConvert, DmaEligible}, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -167,8 +167,8 @@ where _mode: PhantomData, }; - PeripheralClockControl::reset(spi.spi.peripheral()); - PeripheralClockControl::enable(spi.spi.peripheral()); + PeripheralClockControl::reset(spi.spi.info().peripheral); + PeripheralClockControl::enable(spi.spi.info().peripheral); spi.spi.info().init(); spi.spi.info().set_data_mode(mode, false); @@ -572,7 +572,7 @@ pub mod dma { } /// SPI peripheral instance. -pub trait Instance: Peripheral

+ Into + PeripheralMarker + 'static { +pub trait Instance: Peripheral

+ Into + 'static { /// Returns the peripheral data describing this SPI instance. fn info(&self) -> &'static Info; } @@ -592,6 +592,9 @@ pub struct Info { /// Use [Self::register_block] to access the register block. pub register_block: *const RegisterBlock, + /// System peripheral marker. + pub peripheral: crate::system::Peripheral, + /// SCLK signal. pub sclk: InputSignal, @@ -794,6 +797,7 @@ macro_rules! spi_instance { fn info(&self) -> &'static Info { static INFO: Info = Info { register_block: crate::peripherals::[]::PTR, + peripheral: crate::system::Peripheral::[], sclk: InputSignal::$sclk, mosi: InputSignal::$mosi, miso: OutputSignal::$miso, diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 7d6b25c21b9..a89d5cfda3d 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -129,7 +129,6 @@ use core::marker::PhantomData; use self::filter::{Filter, FilterType}; use crate::{ - dma::PeripheralMarker, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -1472,10 +1471,13 @@ where } /// TWAI peripheral instance. -pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { +pub trait Instance: Peripheral

+ Into + 'static { /// The identifier number for this TWAI instance. fn number(&self) -> usize; + /// Returns the system peripheral marker for this instance. + fn peripheral(&self) -> crate::system::Peripheral; + /// Input signal. fn input_signal(&self) -> InputSignal; /// Output signal. @@ -1660,6 +1662,10 @@ impl Instance for crate::peripherals::TWAI0 { 0 } + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::Twai0 + } + fn input_signal(&self) -> InputSignal { cfg_if::cfg_if! { if #[cfg(any(esp32, esp32c3, esp32s2, esp32s3))] { @@ -1705,6 +1711,10 @@ impl Instance for crate::peripherals::TWAI1 { 1 } + fn peripheral(&self) -> crate::system::Peripheral { + crate::system::Peripheral::Twai1 + } + fn input_signal(&self) -> InputSignal { InputSignal::TWAI1_RX } @@ -1751,6 +1761,7 @@ impl Instance for AnyTwai { AnyTwaiInner::Twai1(twai) => twai, } { fn number(&self) -> usize; + fn peripheral(&self) -> crate::system::Peripheral; fn input_signal(&self) -> InputSignal; fn output_signal(&self) -> OutputSignal; fn interrupt(&self) -> crate::peripherals::Interrupt; diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 142c2f8c9b6..ef1ccb9e3b0 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -135,7 +135,6 @@ use portable_atomic::AtomicBool; use crate::{ clock::Clocks, - dma::PeripheralMarker, gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, @@ -1211,7 +1210,7 @@ where } }; - PeripheralClockControl::enable(self.tx.uart.peripheral()); + PeripheralClockControl::enable(self.tx.uart.info().peripheral); self.uart_peripheral_reset(); self.rx.disable_rx_interrupts(); self.tx.disable_tx_interrupts(); @@ -1263,7 +1262,7 @@ where } rst_core(self.register_block(), true); - PeripheralClockControl::reset(self.tx.uart.peripheral()); + PeripheralClockControl::reset(self.tx.uart.info().peripheral); rst_core(self.register_block(), false); } } @@ -2156,7 +2155,7 @@ pub mod lp_uart { } /// UART Peripheral Instance -pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { +pub trait Instance: Peripheral

+ Into + 'static { /// Returns the peripheral data and state describing this UART instance. fn parts(&self) -> (&'static Info, &'static State); @@ -2181,6 +2180,9 @@ pub struct Info { /// Use [Self::register_block] to access the register block. pub register_block: *const RegisterBlock, + /// The system peripheral marker. + pub peripheral: crate::system::Peripheral, + /// Interrupt handler for the asynchronous operations of this UART instance. pub async_handler: InterruptHandler, @@ -2586,7 +2588,7 @@ impl PartialEq for Info { unsafe impl Sync for Info {} macro_rules! impl_instance { - ($inst:ident, $txd:ident, $rxd:ident, $cts:ident, $rts:ident) => { + ($inst:ident, $peri:ident, $txd:ident, $rxd:ident, $cts:ident, $rts:ident) => { impl Instance for crate::peripherals::$inst { fn parts(&self) -> (&'static Info, &'static State) { #[crate::macros::handler] @@ -2603,6 +2605,7 @@ macro_rules! impl_instance { static PERIPHERAL: Info = Info { register_block: crate::peripherals::$inst::ptr(), + peripheral: crate::system::Peripheral::$peri, async_handler: irq_handler, interrupt: Interrupt::$inst, tx_signal: OutputSignal::$txd, @@ -2616,10 +2619,10 @@ macro_rules! impl_instance { }; } -impl_instance!(UART0, U0TXD, U0RXD, U0CTS, U0RTS); -impl_instance!(UART1, U1TXD, U1RXD, U1CTS, U1RTS); +impl_instance!(UART0, Uart0, U0TXD, U0RXD, U0CTS, U0RTS); +impl_instance!(UART1, Uart1, U1TXD, U1RXD, U1CTS, U1RTS); #[cfg(uart2)] -impl_instance!(UART2, U2TXD, U2RXD, U2CTS, U2RTS); +impl_instance!(UART2, Uart2, U2TXD, U2RXD, U2CTS, U2RTS); crate::any_peripheral! { /// Any UART peripheral. From 639853ede9c292ca8de621011e1343f8f44f3d5f Mon Sep 17 00:00:00 2001 From: yanshay Date: Thu, 7 Nov 2024 15:58:32 +0200 Subject: [PATCH 37/67] Add MultiwriteNorFlash trait to FlashStorage (#2478) * Add MultiwriteNorFlash trait to FlashStorage * add PR number * Revert "add PR number" This reverts commit 28bf0acd2468acfeb96a6537d6270c220fbccda1. * Added changelog with PR number --- esp-storage/CHANGELOG.md | 2 ++ esp-storage/src/nor_flash.rs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/esp-storage/CHANGELOG.md b/esp-storage/CHANGELOG.md index 54b50d25c1c..e23c880369b 100644 --- a/esp-storage/CHANGELOG.md +++ b/esp-storage/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added trait MultiwriteNorFlash to FlashStorage (#2478) + ### Changed ### Fixed diff --git a/esp-storage/src/nor_flash.rs b/esp-storage/src/nor_flash.rs index 16190bc8eea..6c37234f48f 100644 --- a/esp-storage/src/nor_flash.rs +++ b/esp-storage/src/nor_flash.rs @@ -2,6 +2,7 @@ use core::mem::MaybeUninit; use embedded_storage::nor_flash::{ ErrorType, + MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, @@ -203,6 +204,8 @@ impl NorFlash for FlashStorage { } } +impl MultiwriteNorFlash for FlashStorage {} + #[cfg(test)] mod test { use core::mem::MaybeUninit; From 4233bddf23c3c65f4023cd980dac03f715101e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 7 Nov 2024 16:05:49 +0100 Subject: [PATCH 38/67] Fix test warnings (#2483) --- hil-test/tests/spi_full_duplex.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index a4211f71991..2b445303124 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -497,10 +497,12 @@ mod tests { // Slow down. At 80kHz, the transfer is supposed to take a bit over 3 seconds. // This means that without working cancellation, the test case should // fail. - ctx.spi.apply_config(&Config { - frequency: 80.kHz(), - ..Config::default() - }); + ctx.spi + .apply_config(&Config { + frequency: 80.kHz(), + ..Config::default() + }) + .unwrap(); // Set up a large buffer that would trigger a timeout let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); @@ -523,10 +525,12 @@ mod tests { #[timeout(3)] fn can_transmit_after_cancel(mut ctx: Context) { // Slow down. At 80kHz, the transfer is supposed to take a bit over 3 seconds. - ctx.spi.apply_config(&Config { - frequency: 80.kHz(), - ..Config::default() - }); + ctx.spi + .apply_config(&Config { + frequency: 80.kHz(), + ..Config::default() + }) + .unwrap(); // Set up a large buffer that would trigger a timeout let mut dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); @@ -547,7 +551,8 @@ mod tests { spi.apply_config(&Config { frequency: 10.MHz(), ..Config::default() - }); + }) + .unwrap(); let transfer = spi .transfer(dma_rx_buf, dma_tx_buf) From d5e6ba5ceba52fc3e46665248bc2f549940e593f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 08:29:37 +0100 Subject: [PATCH 39/67] SPI slave with_pin functions (#2485) --- esp-hal/CHANGELOG.md | 2 + esp-hal/MIGRATING-0.21.md | 23 +++++- esp-hal/src/spi/slave.rs | 119 ++++++++++++++---------------- examples/src/bin/spi_slave_dma.rs | 23 +++--- hil-test/tests/spi_slave.rs | 6 +- 5 files changed, 96 insertions(+), 77 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f9a8a744da1..05e71fa05d5 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - GPIO ETM tasks and events now accept `InputSignal` and `OutputSignal` (#2427) - `spi::master::Config` and `{Spi, SpiDma, SpiDmaBus}::apply_config` (#2448) - `embassy_embedded_hal::SetConfig` is now implemented for `{Spi, SpiDma, SpiDmaBus}` (#2448) +- `slave::Spi::{with_mosi(), with_miso(), with_sclk(), with_cs()}` functions (#2485) ### Changed @@ -55,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `spi::master::Spi::new()` no longer takes `frequency` and `mode` as a parameter. (#2448) - Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419) - The I2S driver has been moved to `i2s::master` (#2472) +- `slave::Spi` constructors no longer take pins (#2485) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index e803f1377e9..9fbad463a33 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -84,7 +84,6 @@ drivers. It is now possible to execute half-duplex and full-duplex operations on - The `Spi::new_half_duplex` constructor has been removed. Use `new` (or `new_typed`) instead. - The `with_pins` methods have been removed. Use the individual `with_*` functions instead. - The `with_mosi` and `with_miso` functions now take input-output peripheral signals to support half-duplex mode. - > TODO(danielb): this means they are currently only usable with GPIO pins, but upcoming GPIO changes should allow using any output signal. ```diff - let mut spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) @@ -131,6 +130,28 @@ The `Spi<'_, SPI, HalfDuplexMode>::read` and `Spi<'_, SPI, HalfDuplexMode>::writ .unwrap(); ``` +## Slave-mode SPI + +### Driver construction + +The constructors no longer accept pins. Use the `with_pin_name` setters instead. + +```diff + let mut spi = Spi::new( + peripherals.SPI2, +- sclk, +- mosi, +- miso, +- cs, + SpiMode::Mode0, +-); ++) ++.with_sclk(sclk) ++.with_mosi(mosi) ++.with_miso(miso) ++.with_cs(cs); +``` + ## UART event listening The following functions have been removed: diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 0ffad8f7c9d..86a80ffdca4 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -34,16 +34,20 @@ //! dma_buffers!(32000); //! let mut spi = Spi::new( //! peripherals.SPI2, -//! sclk, -//! mosi, -//! miso, -//! cs, //! SpiMode::Mode0, //! ) -//! .with_dma(dma_channel.configure( -//! false, -//! DmaPriority::Priority0, -//! ), rx_descriptors, tx_descriptors); +//! .with_sck(sclk) +//! .with_mosi(mosi) +//! .with_miso(miso) +//! .with_cs(cs) +//! .with_dma( +//! dma_channel.configure( +//! false, +//! DmaPriority::Priority0, +//! ), +//! rx_descriptors, +//! tx_descriptors, +//! ); //! //! let mut receive = rx_buffer; //! let mut send = tx_buffer; @@ -79,6 +83,7 @@ use crate::{ gpio::{ interconnect::{PeripheralInput, PeripheralOutput}, InputSignal, + NoPin, OutputSignal, }, peripheral::{Peripheral, PeripheralRef}, @@ -103,20 +108,8 @@ pub struct Spi<'d, M, T = AnySpi> { impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. - pub fn new< - SCK: PeripheralInput, - MOSI: PeripheralInput, - MISO: PeripheralOutput, - CS: PeripheralInput, - >( - spi: impl Peripheral

+ 'd, - sclk: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - cs: impl Peripheral

+ 'd, - mode: SpiMode, - ) -> Spi<'d, Blocking> { - Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode) + pub fn new(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, Blocking> { + Self::new_typed(spi.map_into(), mode) } } @@ -125,55 +118,57 @@ where T: Instance, { /// Constructs an SPI instance in 8bit dataframe mode. - pub fn new_typed< - SCK: PeripheralInput, - MOSI: PeripheralInput, - MISO: PeripheralOutput, - CS: PeripheralInput, - >( - spi: impl Peripheral

+ 'd, - sclk: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - cs: impl Peripheral

+ 'd, - mode: SpiMode, - ) -> Spi<'d, M, T> { - crate::into_mapped_ref!(sclk, mosi, miso, cs); - - let this = Self::new_internal(spi, mode); - - // TODO: with_pins et. al. - sclk.enable_input(true, private::Internal); - this.spi.info().sclk.connect_to(sclk); - - mosi.enable_input(true, private::Internal); - this.spi.info().mosi.connect_to(mosi); - - miso.set_to_push_pull_output(private::Internal); - this.spi.info().miso.connect_to(miso); - - cs.enable_input(true, private::Internal); - this.spi.info().cs.connect_to(cs); - - this - } - - pub(crate) fn new_internal(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, M, T> { + pub fn new_typed(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, M, T> { crate::into_ref!(spi); - let spi = Spi { + let this = Spi { spi, data_mode: mode, _mode: PhantomData, }; - PeripheralClockControl::reset(spi.spi.info().peripheral); - PeripheralClockControl::enable(spi.spi.info().peripheral); + PeripheralClockControl::reset(this.spi.info().peripheral); + PeripheralClockControl::enable(this.spi.info().peripheral); + + this.spi.info().init(); + this.spi.info().set_data_mode(mode, false); - spi.spi.info().init(); - spi.spi.info().set_data_mode(mode, false); + this.with_mosi(NoPin) + .with_miso(NoPin) + .with_sck(NoPin) + .with_cs(NoPin) + } + + /// Assign the SCK (Serial Clock) pin for the SPI instance. + pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { + crate::into_mapped_ref!(sclk); + sclk.enable_input(true, private::Internal); + self.spi.info().sclk.connect_to(sclk); + self + } - spi + /// Assign the MOSI (Master Out Slave In) pin for the SPI instance. + pub fn with_mosi(self, mosi: impl Peripheral

+ 'd) -> Self { + crate::into_mapped_ref!(mosi); + mosi.enable_input(true, private::Internal); + self.spi.info().mosi.connect_to(mosi); + self + } + + /// Assign the MISO (Master In Slave Out) pin for the SPI instance. + pub fn with_miso(self, miso: impl Peripheral

+ 'd) -> Self { + crate::into_mapped_ref!(miso); + miso.set_to_push_pull_output(private::Internal); + self.spi.info().miso.connect_to(miso); + self + } + + /// Assign the CS (Chip Select) pin for the SPI instance. + pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { + crate::into_mapped_ref!(cs); + cs.enable_input(true, private::Internal); + self.spi.info().cs.connect_to(cs); + self } } diff --git a/examples/src/bin/spi_slave_dma.rs b/examples/src/bin/spi_slave_dma.rs index 5352c71db8b..44b2d4871fd 100644 --- a/examples/src/bin/spi_slave_dma.rs +++ b/examples/src/bin/spi_slave_dma.rs @@ -67,19 +67,16 @@ fn main() -> ! { let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(32000); - let mut spi = Spi::new( - peripherals.SPI2, - slave_sclk, - slave_mosi, - slave_miso, - slave_cs, - SpiMode::Mode0, - ) - .with_dma( - dma_channel.configure(false, DmaPriority::Priority0), - tx_descriptors, - rx_descriptors, - ); + let mut spi = Spi::new(peripherals.SPI2, SpiMode::Mode0) + .with_sck(slave_sclk) + .with_mosi(slave_mosi) + .with_miso(slave_miso) + .with_cs(slave_cs) + .with_dma( + dma_channel.configure(false, DmaPriority::Priority0), + rx_descriptors, + tx_descriptors, + ); let delay = Delay::new(); diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 6d8c1aeaf14..72cd12de3d6 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -130,7 +130,11 @@ mod tests { let miso = unsafe { miso_gpio.clone_unchecked() }.into_peripheral_output(); Context { - spi: Spi::new(peripherals.SPI2, sclk, mosi, miso, cs, SpiMode::Mode1), + spi: Spi::new(peripherals.SPI2, SpiMode::Mode1) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_cs(cs), bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso_gpio, cs_gpio), dma_channel, } From d6f63d67a945dc90ba70c2bca7ac8b2c2d326782 Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Fri, 8 Nov 2024 08:01:36 +0000 Subject: [PATCH 40/67] Fix I8080.set_byte_order() (#2487) Co-authored-by: Dominic Fischer Co-authored-by: Jesse Braham --- esp-hal/CHANGELOG.md | 2 ++ esp-hal/MIGRATING-0.21.md | 15 ++++++++++++++- esp-hal/src/lcd_cam/lcd/i8080.rs | 22 +++++++++++++++++----- esp-hal/src/lcd_cam/mod.rs | 2 +- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 05e71fa05d5..f26f56e2ad1 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `spi::master::Config` and `{Spi, SpiDma, SpiDmaBus}::apply_config` (#2448) - `embassy_embedded_hal::SetConfig` is now implemented for `{Spi, SpiDma, SpiDmaBus}` (#2448) - `slave::Spi::{with_mosi(), with_miso(), with_sclk(), with_cs()}` functions (#2485) +- I8080: Added `set_8bits_order()` to set the byte order in 8-bit mode (#2487) ### Changed @@ -66,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ESP32: added UART-specific workaround for https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32/03-errata-description/esp32/cpu-subsequent-access-halted-when-get-interrupted.html (#2441) - Fixed some SysTimer race conditions and panics (#2451) - TWAI: accept all messages by default (#2467) +- I8080: `set_byte_order()` now works correctly in 16-bit mode (#2487) ### Removed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 9fbad463a33..20a9b22ef7d 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -305,4 +305,17 @@ refer to the `Config` struct as `uart::Config`. + ..Config::default() + }, +) -``` \ No newline at end of file +``` + +## I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`. + +If you were using an 8-bit bus. +```diff +- i8080.set_byte_order(ByteOrder::default()); ++ i8080.set_8bits_order(ByteOrder::default()); +``` + +If you were using an 16-bit bus, you don't need to change anything, `set_byte_order()` now works correctly. + +If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when +you switch between devices. Be sure to read the documentation of the new methods. diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 6c9d3e614d3..754c5f0e413 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -217,13 +217,25 @@ impl<'d, DM: Mode> I8080<'d, DM> { } impl<'d, DM: Mode> I8080<'d, DM> { - /// Configures the byte order for data transmission. + /// Configures the byte order for data transmission in 16-bit mode. + /// This must be set to [ByteOrder::default()] when transmitting in 8-bit + /// mode. pub fn set_byte_order(&mut self, byte_order: ByteOrder) -> &mut Self { let is_inverted = byte_order != ByteOrder::default(); - self.lcd_cam.lcd_user().modify(|_, w| { - w.lcd_byte_order().bit(is_inverted); - w.lcd_8bits_order().bit(is_inverted) - }); + self.lcd_cam + .lcd_user() + .modify(|_, w| w.lcd_byte_order().bit(is_inverted)); + self + } + + /// Configures the byte order for data transmission in 8-bit mode. + /// This must be set to [ByteOrder::default()] when transmitting in 16-bit + /// mode. + pub fn set_8bits_order(&mut self, byte_order: ByteOrder) -> &mut Self { + let is_inverted = byte_order != ByteOrder::default(); + self.lcd_cam + .lcd_user() + .modify(|_, w| w.lcd_8bits_order().bit(is_inverted)); self } diff --git a/esp-hal/src/lcd_cam/mod.rs b/esp-hal/src/lcd_cam/mod.rs index b7172260d3f..b442b2450ef 100644 --- a/esp-hal/src/lcd_cam/mod.rs +++ b/esp-hal/src/lcd_cam/mod.rs @@ -108,7 +108,7 @@ pub enum BitOrder { #[derive(Debug, Clone, Copy, PartialEq, Default)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ByteOrder { - /// Do not change bit order. + /// Do not change byte order. #[default] Native = 0, /// Invert byte order. From ac4679a1aeb7302c30f63896e65a1ba1bc431446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 11:37:13 +0100 Subject: [PATCH 41/67] Remove public hidden I2C APIs (#2474) --- esp-hal/src/i2c.rs | 731 ++++++++++++++++++++++----------------------- 1 file changed, 360 insertions(+), 371 deletions(-) diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 62f342d6eac..a802ad2a3f4 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -62,14 +62,17 @@ use core::{ use embassy_sync::waitqueue::AtomicWaker; use embedded_hal::i2c::Operation as EhalOperation; use fugit::HertzU32; -use procmacros::handler; use crate::{ clock::Clocks, gpio::{interconnect::PeripheralOutput, InputSignal, OutputSignal, Pull}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::i2c0::{RegisterBlock, COMD}, + peripherals::{ + i2c0::{RegisterBlock, COMD}, + Interrupt, + }, + private, system::PeripheralClockControl, Async, Blocking, @@ -307,10 +310,10 @@ impl<'d, T, DM: Mode> I2c<'d, DM, T> where T: Instance, { - fn new_internal( + fn new_internal( i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, frequency: HertzU32, ) -> Self { crate::into_ref!(i2c); @@ -323,37 +326,24 @@ where timeout: None, }; - PeripheralClockControl::reset(i2c.i2c.peripheral()); - PeripheralClockControl::enable(i2c.i2c.peripheral()); - - // TODO: implement with_pins et. al. - // avoid SCL/SDA going low during configuration - scl.set_output_high(true, crate::private::Internal); - sda.set_output_high(true, crate::private::Internal); - - scl.set_to_open_drain_output(crate::private::Internal); - scl.enable_input(true, crate::private::Internal); - scl.pull_direction(Pull::Up, crate::private::Internal); + PeripheralClockControl::reset(i2c.info().peripheral); + PeripheralClockControl::enable(i2c.info().peripheral); - i2c.i2c.scl_input_signal().connect_to(&mut scl); - i2c.i2c.scl_output_signal().connect_to(&mut scl); + let i2c = i2c.with_sda(sda).with_scl(scl); - sda.set_to_open_drain_output(crate::private::Internal); - sda.enable_input(true, crate::private::Internal); - sda.pull_direction(Pull::Up, crate::private::Internal); - - i2c.i2c.sda_input_signal().connect_to(&mut sda); - i2c.i2c.sda_output_signal().connect_to(&mut sda); - - i2c.i2c.setup(frequency, None); + i2c.info().setup(frequency, None); i2c } + fn info(&self) -> &Info { + self.i2c.info() + } + fn internal_recover(&self) { - PeripheralClockControl::reset(self.i2c.peripheral()); - PeripheralClockControl::enable(self.i2c.peripheral()); + PeripheralClockControl::reset(self.info().peripheral); + PeripheralClockControl::enable(self.info().peripheral); - self.i2c.setup(self.frequency, self.timeout); + self.info().setup(self.frequency, self.timeout); } /// Set the I2C timeout. @@ -361,7 +351,7 @@ where // timeout, and just what exactly is a timeout in this context? pub fn with_timeout(mut self, timeout: Option) -> Self { self.timeout = timeout; - self.i2c.setup(self.frequency, self.timeout); + self.info().setup(self.frequency, self.timeout); self } @@ -380,15 +370,15 @@ where let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one - self.i2c + self.info() .write_operation( address, buffer, @@ -403,7 +393,7 @@ where // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one // - will_continue is true if there is another read operation next - self.i2c + self.info() .read_operation( address, buffer, @@ -421,16 +411,50 @@ where Ok(()) } + + fn with_sda(self, sda: impl Peripheral

+ 'd) -> Self { + let info = self.info(); + let input = info.sda_input; + let output = info.sda_output; + self.with_pin(sda, input, output) + } + + fn with_scl(self, scl: impl Peripheral

+ 'd) -> Self { + let info = self.info(); + let input = info.scl_input; + let output = info.scl_output; + self.with_pin(scl, input, output) + } + + fn with_pin( + self, + pin: impl Peripheral

+ 'd, + input: InputSignal, + output: OutputSignal, + ) -> Self { + crate::into_mapped_ref!(pin); + // avoid the pin going low during configuration + pin.set_output_high(true, private::Internal); + + pin.set_to_open_drain_output(private::Internal); + pin.enable_input(true, private::Internal); + pin.pull_direction(Pull::Up, private::Internal); + + input.connect_to(&mut pin); + output.connect_to(&mut pin); + + self + } } impl<'d> I2c<'d, Blocking> { /// Create a new I2C instance /// This will enable the peripheral but the peripheral won't get /// automatically disabled when this gets dropped. - pub fn new( + pub fn new( i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, frequency: HertzU32, ) -> Self { Self::new_typed(i2c.map_into(), sda, scl, frequency) @@ -444,10 +468,10 @@ where /// Create a new I2C instance /// This will enable the peripheral but the peripheral won't get /// automatically disabled when this gets dropped. - pub fn new_typed( + pub fn new_typed( i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, frequency: HertzU32, ) -> Self { Self::new_internal(i2c, sda, scl, frequency) @@ -457,7 +481,7 @@ where /// Configures the I2C peripheral to operate in asynchronous mode. pub fn into_async(mut self) -> I2c<'d, Async, T> { - self.set_interrupt_handler(self.i2c.async_handler()); + self.set_interrupt_handler(self.info().async_handler); I2c { i2c: self.i2c, @@ -472,11 +496,11 @@ where let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); - self.i2c + self.info() .read_operation( address, chunk, @@ -496,11 +520,11 @@ where let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); - self.i2c + self.info() .write_operation( address, chunk, @@ -527,11 +551,11 @@ where for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); - self.i2c + self.info() .write_operation( address, chunk, @@ -544,11 +568,11 @@ where for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); - self.i2c + self.info() .read_operation( address, chunk, @@ -590,27 +614,22 @@ where } } -impl crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} +impl private::Sealed for I2c<'_, Blocking, T> where T: Instance {} impl InterruptConfigurable for I2c<'_, Blocking, T> where T: Instance, { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { + let interrupt = self.info().interrupt; for core in Cpu::other() { - crate::interrupt::disable(core, self.i2c.interrupt()); + crate::interrupt::disable(core, interrupt); } - unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) }; - unwrap!(crate::interrupt::enable( - self.i2c.interrupt(), - handler.priority() - )); + unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(crate::interrupt::enable(interrupt, handler.priority())); } } -const NUM_I2C: usize = 1 + cfg!(i2c1) as usize; -static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C]; - #[cfg_attr(esp32, allow(dead_code))] pub(crate) enum Event { EndDetect, @@ -621,21 +640,16 @@ pub(crate) enum Event { #[cfg(not(esp32))] #[must_use = "futures do nothing unless you `.await` or poll them"] -struct I2cFuture<'a, T> -where - T: Instance, -{ +struct I2cFuture<'a> { event: Event, - instance: &'a T, + info: &'a Info, + state: &'a State, } #[cfg(not(esp32))] -impl<'a, T> I2cFuture<'a, T> -where - T: Instance, -{ - pub fn new(event: Event, instance: &'a T) -> Self { - instance.register_block().int_ena().modify(|_, w| { +impl<'a> I2cFuture<'a> { + pub fn new(event: Event, instance: &'a impl Instance) -> Self { + instance.info().register_block().int_ena().modify(|_, w| { let w = match event { Event::EndDetect => w.end_detect().set_bit(), Event::TxComplete => w.trans_complete().set_bit(), @@ -654,11 +668,15 @@ where w }); - Self { event, instance } + Self { + event, + state: instance.state(), + info: instance.info(), + } } fn event_bit_is_clear(&self) -> bool { - let r = self.instance.register_block().int_ena().read(); + let r = self.info.register_block().int_ena().read(); match self.event { Event::EndDetect => r.end_detect().bit_is_clear(), @@ -669,7 +687,7 @@ where } fn check_error(&self) -> Result<(), Error> { - let r = self.instance.register_block().int_raw().read(); + let r = self.info.register_block().int_raw().read(); if r.arbitration_lost().bit_is_set() { return Err(Error::ArbitrationLost); @@ -692,7 +710,7 @@ where #[cfg(not(esp32))] if r.trans_complete().bit_is_set() && self - .instance + .info .register_block() .sr() .read() @@ -707,14 +725,11 @@ where } #[cfg(not(esp32))] -impl<'a, T> core::future::Future for I2cFuture<'a, T> -where - T: Instance, -{ +impl core::future::Future for I2cFuture<'_> { type Output = Result<(), Error>; fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKERS[self.instance.i2c_number()].register(ctx.waker()); + self.state.waker.register(ctx.waker()); let error = self.check_error(); @@ -736,7 +751,7 @@ where { /// Configure the I2C peripheral to operate in blocking mode. pub fn into_blocking(self) -> I2c<'d, Blocking, T> { - crate::interrupt::disable(Cpu::current(), self.i2c.interrupt()); + crate::interrupt::disable(Cpu::current(), self.info().interrupt); I2c { i2c: self.i2c, @@ -755,7 +770,7 @@ where self.wait_for_completion(false).await?; for byte in buffer.iter_mut() { - *byte = read_fifo(self.i2c.register_block()); + *byte = read_fifo(self.info().register_block()); } Ok(()) @@ -763,7 +778,7 @@ where #[cfg(not(any(esp32, esp32s2)))] async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - self.i2c.read_all_from_fifo(buffer) + self.info().read_all_from_fifo(buffer) } #[cfg(any(esp32, esp32s2))] @@ -773,8 +788,8 @@ where } for b in bytes { - write_fifo(self.i2c.register_block(), *b); - self.i2c.check_errors()?; + write_fifo(self.info().register_block(), *b); + self.info().check_errors()?; } Ok(()) @@ -784,11 +799,11 @@ where async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { let mut index = start_index; loop { - self.i2c.check_errors()?; + self.info().check_errors()?; I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - self.i2c + self.info() .register_block() .int_clr() .write(|w| w.txfifo_wm().clear_bit_by_one()); @@ -799,14 +814,14 @@ where break Ok(()); } - write_fifo(self.i2c.register_block(), bytes[index]); + write_fifo(self.info().register_block(), bytes[index]); index += 1; } } #[cfg(not(esp32))] async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - self.i2c.check_errors()?; + self.info().check_errors()?; if end_only { I2cFuture::new(Event::EndDetect, &*self.i2c).await?; @@ -822,7 +837,7 @@ where embassy_futures::select::Either::Second(res) => res?, } } - self.i2c.check_all_commands_done()?; + self.info().check_all_commands_done()?; Ok(()) } @@ -834,9 +849,9 @@ where let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop loop { - let interrupts = self.i2c.register_block().int_raw().read(); + let interrupts = self.info().register_block().int_raw().read(); - self.i2c.check_errors()?; + self.info().check_errors()?; // Handle completion cases // A full transmission was completed (either a STOP condition or END was @@ -854,7 +869,7 @@ where embassy_futures::yield_now().await; } - self.i2c.check_all_commands_done()?; + self.info().check_all_commands_done()?; Ok(()) } @@ -884,18 +899,20 @@ where } // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); + self.info().reset_fifo(); + self.info().reset_command_list(); if start { add_cmd(cmd_iterator, Command::Start)?; } - self.i2c.setup_write(address, bytes, start, cmd_iterator)?; + self.i2c + .info() + .setup_write(address, bytes, start, cmd_iterator)?; add_cmd( cmd_iterator, if stop { Command::Stop } else { Command::End }, )?; - let index = self.i2c.fill_tx_fifo(bytes); - self.i2c.start_transmission(); + let index = self.info().fill_tx_fifo(bytes); + self.info().start_transmission(); // Fill the FIFO with the remaining bytes: self.write_remaining_tx_fifo(index, bytes).await?; @@ -932,18 +949,19 @@ where } // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); + self.info().reset_fifo(); + self.info().reset_command_list(); if start { add_cmd(cmd_iterator, Command::Start)?; } self.i2c + .info() .setup_read(address, buffer, start, will_continue, cmd_iterator)?; add_cmd( cmd_iterator, if stop { Command::Stop } else { Command::End }, )?; - self.i2c.start_transmission(); + self.info().start_transmission(); self.read_all_from_fifo(buffer).await?; self.wait_for_completion(!stop).await?; Ok(()) @@ -954,9 +972,9 @@ where let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); self.write_operation( address, @@ -976,9 +994,9 @@ where let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); self.read_operation( address, @@ -1006,9 +1024,9 @@ where let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); self.write_operation( address, @@ -1022,9 +1040,9 @@ where for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); self.read_operation( address, @@ -1083,9 +1101,9 @@ where let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); + self.info().clear_all_interrupts(); - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + let cmd_iterator = &mut self.info().register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: @@ -1138,65 +1156,184 @@ where } } -fn handler(regs: &RegisterBlock) { +fn async_handler(info: &Info, state: &State) { + let regs = info.register_block(); regs.int_ena().modify(|_, w| { w.end_detect().clear_bit(); w.trans_complete().clear_bit(); w.arbitration_lost().clear_bit(); - w.time_out().clear_bit() - }); + w.time_out().clear_bit(); - #[cfg(not(any(esp32, esp32s2)))] - regs.int_ena().modify(|_, w| w.txfifo_wm().clear_bit()); + #[cfg(not(any(esp32, esp32s2)))] + w.txfifo_wm().clear_bit(); - #[cfg(not(esp32))] - regs.int_ena().modify(|_, w| w.nack().clear_bit()); + cfg_if::cfg_if! { + if #[cfg(esp32)] { + w.ack_err().clear_bit() + } else { + w.nack().clear_bit() + } + } + }); - #[cfg(esp32)] - regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); + state.waker.wake(); } -#[handler] -pub(super) fn i2c0_handler() { - let regs = unsafe { crate::peripherals::I2C0::steal() }; - handler(regs.register_block()); - - WAKERS[0].wake(); +/// Sets the filter with a supplied threshold in clock cycles for which a +/// pulse must be present to pass the filter +fn set_filter( + register_block: &RegisterBlock, + sda_threshold: Option, + scl_threshold: Option, +) { + cfg_if::cfg_if! { + if #[cfg(any(esp32, esp32s2))] { + register_block.sda_filter_cfg().modify(|_, w| { + if let Some(threshold) = sda_threshold { + unsafe { w.sda_filter_thres().bits(threshold) }; + } + w.sda_filter_en().bit(sda_threshold.is_some()) + }); + register_block.scl_filter_cfg().modify(|_, w| { + if let Some(threshold) = scl_threshold { + unsafe { w.scl_filter_thres().bits(threshold) }; + } + w.scl_filter_en().bit(scl_threshold.is_some()) + }); + } else { + register_block.filter_cfg().modify(|_, w| { + if let Some(threshold) = sda_threshold { + unsafe { w.sda_filter_thres().bits(threshold) }; + } + if let Some(threshold) = scl_threshold { + unsafe { w.scl_filter_thres().bits(threshold) }; + } + w.sda_filter_en().bit(sda_threshold.is_some()); + w.scl_filter_en().bit(scl_threshold.is_some()) + }); + } + } } -#[cfg(i2c1)] -#[handler] -pub(super) fn i2c1_handler() { - let regs = unsafe { crate::peripherals::I2C1::steal() }; - handler(regs.register_block()); +#[allow(clippy::too_many_arguments, unused)] +/// Configures the clock and timing parameters for the I2C peripheral. +fn configure_clock( + register_block: &RegisterBlock, + sclk_div: u32, + scl_low_period: u32, + scl_high_period: u32, + scl_wait_high_period: u32, + sda_hold_time: u32, + sda_sample_time: u32, + scl_rstart_setup_time: u32, + scl_stop_setup_time: u32, + scl_start_hold_time: u32, + scl_stop_hold_time: u32, + time_out_value: u32, + time_out_en: bool, +) { + unsafe { + // divider + #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] + register_block.clk_conf().modify(|_, w| { + w.sclk_sel().clear_bit(); + w.sclk_div_num().bits((sclk_div - 1) as u8) + }); + + // scl period + register_block + .scl_low_period() + .write(|w| w.scl_low_period().bits(scl_low_period as u16)); + + register_block.scl_high_period().write(|w| { + #[cfg(not(esp32))] // ESP32 does not have a wait_high field + w.scl_wait_high_period() + .bits(scl_wait_high_period.try_into().unwrap()); + w.scl_high_period().bits(scl_high_period as u16) + }); + + // sda sample + register_block + .sda_hold() + .write(|w| w.time().bits(sda_hold_time as u16)); + register_block + .sda_sample() + .write(|w| w.time().bits(sda_sample_time as u16)); - WAKERS[1].wake(); + // setup + register_block + .scl_rstart_setup() + .write(|w| w.time().bits(scl_rstart_setup_time as u16)); + register_block + .scl_stop_setup() + .write(|w| w.time().bits(scl_stop_setup_time as u16)); + + // hold + register_block + .scl_start_hold() + .write(|w| w.time().bits(scl_start_hold_time as u16)); + register_block + .scl_stop_hold() + .write(|w| w.time().bits(scl_stop_hold_time as u16)); + + // The ESP32 variant does not have an enable flag for the + // timeout mechanism + cfg_if::cfg_if! { + if #[cfg(esp32)] { + // timeout + register_block + .to() + .write(|w| w.time_out().bits(time_out_value)); + } else { + // timeout + // FIXME: Enable timout for other chips! + #[allow(clippy::useless_conversion)] + register_block + .to() + .write(|w| w.time_out_en().bit(time_out_en) + .time_out_value() + .bits(time_out_value.try_into().unwrap()) + ); + } + } + } } -/// I2C Peripheral Instance -#[doc(hidden)] -pub trait Instance: Peripheral

+ Into + 'static { - fn peripheral(&self) -> crate::system::Peripheral; +/// Peripheral data describing a particular I2C instance. +#[non_exhaustive] +pub struct Info { + /// Pointer to the register block for this I2C instance. + /// + /// Use [Self::register_block] to access the register block. + pub register_block: *const RegisterBlock, + + /// System peripheral marker. + pub peripheral: crate::system::Peripheral, + + /// Interrupt handler for the asynchronous operations of this I2C instance. + pub async_handler: InterruptHandler, - /// Returns the interrupt associated with this I2C peripheral. - fn interrupt(&self) -> crate::peripherals::Interrupt; + /// Interrupt for this I2C instance. + pub interrupt: Interrupt, - fn async_handler(&self) -> InterruptHandler; + /// SCL output signal. + pub scl_output: OutputSignal, - /// Returns the SCL output signal for this I2C peripheral. - fn scl_output_signal(&self) -> OutputSignal; - /// Returns the SCL input signal for this I2C peripheral. - fn scl_input_signal(&self) -> InputSignal; - /// Returns the SDA output signal for this I2C peripheral. - fn sda_output_signal(&self) -> OutputSignal; - /// Returns the SDA input signal for this I2C peripheral. - fn sda_input_signal(&self) -> InputSignal; + /// SCL input signal. + pub scl_input: InputSignal, - /// Returns a reference to the register block of the I2C peripheral. - fn register_block(&self) -> &RegisterBlock; + /// SDA output signal. + pub sda_output: OutputSignal, - /// Returns the I2C peripheral's index number. - fn i2c_number(&self) -> usize; + /// SDA input signal. + pub sda_input: InputSignal, +} + +impl Info { + /// Returns the register block for this I2C instance. + pub fn register_block(&self) -> &RegisterBlock { + unsafe { &*self.register_block } + } /// Configures the I2C peripheral with the specified frequency, clocks, and /// optional timeout. @@ -1221,7 +1358,7 @@ pub trait Instance: Peripheral

+ Into + 'static { // Configure filter // FIXME if we ever change this we need to adapt `set_frequency` for ESP32 - self.set_filter(Some(7), Some(7)); + set_filter(self.register_block(), Some(7), Some(7)); // Configure frequency let clocks = Clocks::get(); @@ -1272,36 +1409,6 @@ pub trait Instance: Peripheral

+ Into + 'static { } } - /// Sets the filter with a supplied threshold in clock cycles for which a - /// pulse must be present to pass the filter - fn set_filter(&self, sda_threshold: Option, scl_threshold: Option) { - cfg_if::cfg_if! { - if #[cfg(any(esp32, esp32s2))] { - let sda_register = &self.register_block().sda_filter_cfg(); - let scl_register = &self.register_block().scl_filter_cfg(); - } else { - let sda_register = &self.register_block().filter_cfg(); - let scl_register = &self.register_block().filter_cfg(); - } - } - - match sda_threshold { - Some(threshold) => { - sda_register.modify(|_, w| unsafe { w.sda_filter_thres().bits(threshold) }); - sda_register.modify(|_, w| w.sda_filter_en().set_bit()); - } - None => sda_register.modify(|_, w| w.sda_filter_en().clear_bit()), - } - - match scl_threshold { - Some(threshold) => { - scl_register.modify(|_, w| unsafe { w.scl_filter_thres().bits(threshold) }); - scl_register.modify(|_, w| w.scl_filter_en().set_bit()); - } - None => scl_register.modify(|_, w| w.scl_filter_en().clear_bit()), - } - } - #[cfg(esp32)] /// Sets the frequency of the I2C interface by calculating and applying the /// associated timings - corresponds to i2c_ll_cal_bus_clk and @@ -1359,7 +1466,8 @@ pub trait Instance: Peripheral

+ Into + 'static { let scl_start_hold_time = hold; let scl_stop_hold_time = hold; - self.configure_clock( + configure_clock( + self.register_block(), 0, scl_low_period, scl_high_period, @@ -1412,7 +1520,8 @@ pub trait Instance: Peripheral

+ Into + 'static { let scl_stop_hold_time = hold; let time_out_en = true; - self.configure_clock( + configure_clock( + self.register_block(), 0, scl_low_period, scl_high_period, @@ -1485,7 +1594,8 @@ pub trait Instance: Peripheral

+ Into + 'static { let scl_stop_hold_time = hold - 1; let time_out_en = true; - self.configure_clock( + configure_clock( + self.register_block(), clkm_div, scl_low_period, scl_high_period, @@ -1501,91 +1611,6 @@ pub trait Instance: Peripheral

+ Into + 'static { ); } - #[allow(clippy::too_many_arguments, unused)] - /// Configures the clock and timing parameters for the I2C peripheral. - fn configure_clock( - &self, - sclk_div: u32, - scl_low_period: u32, - scl_high_period: u32, - scl_wait_high_period: u32, - sda_hold_time: u32, - sda_sample_time: u32, - scl_rstart_setup_time: u32, - scl_stop_setup_time: u32, - scl_start_hold_time: u32, - scl_stop_hold_time: u32, - time_out_value: u32, - time_out_en: bool, - ) { - let register_block = self.register_block(); - unsafe { - // divider - #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] - register_block.clk_conf().modify(|_, w| { - w.sclk_sel().clear_bit(); - w.sclk_div_num().bits((sclk_div - 1) as u8) - }); - - // scl period - register_block - .scl_low_period() - .write(|w| w.scl_low_period().bits(scl_low_period as u16)); - - register_block.scl_high_period().write(|w| { - #[cfg(not(esp32))] // ESP32 does not have a wait_high field - w.scl_wait_high_period() - .bits(scl_wait_high_period.try_into().unwrap()); - w.scl_high_period().bits(scl_high_period as u16) - }); - - // sda sample - register_block - .sda_hold() - .write(|w| w.time().bits(sda_hold_time as u16)); - register_block - .sda_sample() - .write(|w| w.time().bits(sda_sample_time as u16)); - - // setup - register_block - .scl_rstart_setup() - .write(|w| w.time().bits(scl_rstart_setup_time as u16)); - register_block - .scl_stop_setup() - .write(|w| w.time().bits(scl_stop_setup_time as u16)); - - // hold - register_block - .scl_start_hold() - .write(|w| w.time().bits(scl_start_hold_time as u16)); - register_block - .scl_stop_hold() - .write(|w| w.time().bits(scl_stop_hold_time as u16)); - - // The ESP32 variant does not have an enable flag for the - // timeout mechanism - cfg_if::cfg_if! { - if #[cfg(esp32)] { - // timeout - register_block - .to() - .write(|w| w.time_out().bits(time_out_value)); - } else { - // timeout - // FIXME: Enable timout for other chips! - #[allow(clippy::useless_conversion)] - register_block - .to() - .write(|w| w.time_out_en().bit(time_out_en) - .time_out_value() - .bits(time_out_value.try_into().unwrap()) - ); - } - } - } - } - /// Configures the I2C peripheral for a write operation. /// - `addr` is the address of the slave device. /// - `bytes` is the data two be sent. @@ -2136,6 +2161,39 @@ pub trait Instance: Peripheral

+ Into + 'static { } } +impl PartialEq for Info { + fn eq(&self, other: &Self) -> bool { + self.register_block == other.register_block + } +} + +unsafe impl Sync for Info {} + +/// Peripheral state for an I2C instance. +#[non_exhaustive] +pub struct State { + /// Waker for the asynchronous operations. + pub waker: AtomicWaker, +} + +/// I2C Peripheral Instance +pub trait Instance: Peripheral

+ Into + 'static { + /// Returns the peripheral data and state describing this instance. + fn parts(&self) -> (&Info, &State); + + /// Returns the peripheral data describing this instance. + #[inline(always)] + fn info(&self) -> &Info { + self.parts().0 + } + + /// Returns the peripheral state for this instance. + #[inline(always)] + fn state(&self) -> &State { + self.parts().1 + } +} + /// Adds a command to the I2C command sequence. fn add_cmd<'a, I>(cmd_iterator: &mut I, command: Command) -> Result<(), Error> where @@ -2205,100 +2263,39 @@ fn write_fifo(register_block: &RegisterBlock, data: u8) { } } -impl Instance for crate::peripherals::I2C0 { - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::I2cExt0 - } - - #[inline(always)] - fn async_handler(&self) -> InterruptHandler { - i2c0_handler - } - - #[inline(always)] - fn scl_output_signal(&self) -> OutputSignal { - OutputSignal::I2CEXT0_SCL - } - - #[inline(always)] - fn scl_input_signal(&self) -> InputSignal { - InputSignal::I2CEXT0_SCL - } - - #[inline(always)] - fn sda_output_signal(&self) -> OutputSignal { - OutputSignal::I2CEXT0_SDA - } - - #[inline(always)] - fn sda_input_signal(&self) -> InputSignal { - InputSignal::I2CEXT0_SDA - } - - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } +macro_rules! instance { + ($inst:ident, $peri:ident, $scl:ident, $sda:ident, $interrupt:ident) => { + impl Instance for crate::peripherals::$inst { + fn parts(&self) -> (&Info, &State) { + #[crate::macros::handler] + pub(super) fn irq_handler() { + async_handler(&PERIPHERAL, &STATE); + } - #[inline(always)] - fn i2c_number(&self) -> usize { - 0 - } + static STATE: State = State { + waker: AtomicWaker::new(), + }; - #[inline(always)] - fn interrupt(&self) -> crate::peripherals::Interrupt { - crate::peripherals::Interrupt::I2C_EXT0 - } + static PERIPHERAL: Info = Info { + register_block: crate::peripherals::$inst::ptr(), + peripheral: crate::system::Peripheral::$peri, + async_handler: irq_handler, + interrupt: Interrupt::$interrupt, + scl_output: OutputSignal::$scl, + scl_input: InputSignal::$scl, + sda_output: OutputSignal::$sda, + sda_input: InputSignal::$sda, + }; + (&PERIPHERAL, &STATE) + } + } + }; } +#[cfg(i2c0)] +instance!(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA, I2C_EXT0); #[cfg(i2c1)] -impl Instance for crate::peripherals::I2C1 { - #[inline(always)] - fn peripheral(&self) -> crate::system::Peripheral { - crate::system::Peripheral::I2cExt1 - } - - #[inline(always)] - fn async_handler(&self) -> InterruptHandler { - i2c1_handler - } - - #[inline(always)] - fn scl_output_signal(&self) -> OutputSignal { - OutputSignal::I2CEXT1_SCL - } - - #[inline(always)] - fn scl_input_signal(&self) -> InputSignal { - InputSignal::I2CEXT1_SCL - } - - #[inline(always)] - fn sda_output_signal(&self) -> OutputSignal { - OutputSignal::I2CEXT1_SDA - } - - #[inline(always)] - fn sda_input_signal(&self) -> InputSignal { - InputSignal::I2CEXT1_SDA - } - - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } - - #[inline(always)] - fn i2c_number(&self) -> usize { - 1 - } - - #[inline(always)] - fn interrupt(&self) -> crate::peripherals::Interrupt { - crate::peripherals::Interrupt::I2C_EXT1 - } -} +instance!(I2C1, I2cExt1, I2CEXT1_SCL, I2CEXT1_SDA, I2C_EXT1); crate::any_peripheral! { /// Represents any I2C peripheral. @@ -2317,15 +2314,7 @@ impl Instance for AnyI2c { #[cfg(i2c1)] AnyI2cInner::I2c1(i2c) => i2c, } { - fn interrupt(&self) -> crate::peripherals::Interrupt; - fn peripheral(&self) -> crate::system::Peripheral; - fn async_handler(&self) -> InterruptHandler; - fn scl_output_signal(&self) -> OutputSignal; - fn scl_input_signal(&self) -> InputSignal; - fn sda_output_signal(&self) -> OutputSignal; - fn sda_input_signal(&self) -> InputSignal; - fn register_block(&self) -> &RegisterBlock; - fn i2c_number(&self) -> usize; + fn parts(&self) -> (&Info, &State); } } } From 31d714a1568e03b4ba92b508d24addb065bdc17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 12:50:52 +0100 Subject: [PATCH 42/67] Tweak guidelines (#2482) * Tweak guidelines * Restore builder rule * Address review comments --- documentation/API-GUIDELINES.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/documentation/API-GUIDELINES.md b/documentation/API-GUIDELINES.md index b2e18e13eda..c0336070789 100644 --- a/documentation/API-GUIDELINES.md +++ b/documentation/API-GUIDELINES.md @@ -15,9 +15,21 @@ The following paragraphs contain additional recommendations. ## Construction and Destruction of Drivers -- Drivers take peripherals and pins via the `PeripheralRef` pattern - they don't consume peripherals/pins. +- Drivers should take peripherals via the `PeripheralRef` pattern - they don't consume peripherals directly. +- If a driver requires pins, those pins should be configured using `fn with_signal_name(self, pin: impl Peripheral

+ 'd) -> Self)` or `fn with_signal_name(self, pin: impl Peripheral

+ 'd) -> Self)` +- If a driver supports multiple peripheral instances (for example, I2C0 is one such instance): + - The peripheral instance type should be positioned as the last type parameter of the driver type. + - The peripheral instance type should default to a type that supports any of the peripheral instances. + - The author is encouraged to use `crate::any_peripheral` to define the "any" peripheral instance type. + - The driver should implement a `new` constructor that automatically converts the peripheral instance into the any type, and a `new_typed` that preserves the peripheral type. +- If a driver only supports a single peripheral instance, no instance type parameter is necessary. +- If a driver implements both blocking and async operations, or only implements blocking operations, but may support asynchronous ones in the future, the driver's type signature should include a `crate::Mode` type parameter. +- By default, constructors should configure the driver for blocking mode. The driver should implement `into_async` (and a matching `into_blocking`) function that reconfigures the driver. + - `into_async` should configure the driver and/or the associated DMA channels. This most often means enabling an interrupt handler. + - `into_blocking` should undo the configuration done by `into_async`. +- The asynchronous driver implemntation should also expose the blocking methods (except for interrupt related functions). - Consider adding a `Drop` implementation resetting the peripheral to idle state. -- Consider using a builder-like pattern for configuration which must be done during initialization. +- Consider using a builder-like pattern for driver construction. ## Interoperability @@ -25,6 +37,7 @@ The following paragraphs contain additional recommendations. - see [this example](https://github.com/esp-rs/esp-hal/blob/df2b7bd8472cc1d18db0d9441156575570f59bb3/esp-hal/src/spi/mod.rs#L15) - e.g. `#[cfg_attr(feature = "defmt", derive(defmt::Format))]` - Don't use `log::XXX!` macros directly - use the wrappers in `fmt.rs` (e.g. just `info!` instead of `log::info!` or importing `log::*`)! +- Consider implementing common ecosystem traits, like the ones in `embedded-hal` or `embassy-embedded-hal`. ## API Surface @@ -45,6 +58,9 @@ The following paragraphs contain additional recommendations. - For example starting a timer is fine for `&self`, worst case a timer will be started twice if two parts of the program call it. You can see a real example of this [here](https://github.com/esp-rs/esp-hal/pull/1500#pullrequestreview-2015911974) - Maintain order consistency in the API, such as in the case of pairs like RX/TX. - If your driver provides a way to listen for interrupts, the interrupts should be listed in a `derive(EnumSetType)` enum as opposed to one function per interrupt flag. +- If a driver only implements a subset of a peripheral's capabilities, it should be placed in the `peripheral::subcategory` module. + - For example, if a driver implements the slave-mode I2C driver, it should be placed into `i2c::slave`. + - This helps us reducing the need of introducing breaking changes if we implement additional functionalities. ## Maintainability @@ -56,6 +72,15 @@ The following paragraphs contain additional recommendations. - All `Future` objects (public or private) must be marked with ``#[must_use = "futures do nothing unless you `.await` or poll them"]``. - Prefer `cfg_if!` over multiple exclusive `#[cfg]` attributes. `cfg_if!` visually divides the options, often results in simpler conditions and simplifies adding new branches in the future. +## Driver implementation + +- If a common `Instance` trait is used for multiple peripherals, those traits should not have any logic implemented in them. +- The `Instance` traits should only be used to access information about a peripheral instance. +- The internal implementation of the driver should be non-generic over the peripheral instance. This helps the compiler produce smaller code. +- The author is encouraged to return a static shared reference to an `Info` and a `State` structure from the `Instance` trait. + - The `Info` struct should describe the peripheral. Do not use any interior mutability. + - The `State` struct should contain counters, wakers and other, mutable state. As this is accessed via a shared reference, interior mutability and atomic variables are preferred. + ## Modules Documentation Modules should have the following documentation format: @@ -88,4 +113,5 @@ Modules should have the following documentation format: ``` #![doc = concat!("[ESP-IDF documentation](https://docs.espressif.com/projects/esp-idf/en/latest/", crate::soc::chip!(), "/api-reference/peripherals/etm.html)")] ``` -- Documentation examples should be short and basic, for more complex scenarios, create an example. + - In case of referencing a TRM chapter, use the `crate::trm_markdown_link!()` macro. If you are referring to a particular chapter, you may use `crate::trm_markdown_link!("#chapter_anchor")`. +- Documentation examples should be short and basic. For more complex scenarios, create an example. From 6d6f6a7baa954ed984bdcc433b215a579954c8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 13:28:53 +0100 Subject: [PATCH 43/67] Move I2C driver to `i2c::master` (#2476) * Move I2C driver to i2c::master * Update esp-hal/CHANGELOG.md Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --------- Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 4 +- esp-hal/src/i2c/lp_i2c.rs | 341 +++++++++++++++++ esp-hal/src/{i2c.rs => i2c/master/mod.rs} | 362 +----------------- esp-hal/src/i2c/mod.rs | 11 + esp-hal/src/prelude.rs | 2 +- examples/src/bin/embassy_i2c.rs | 2 +- .../embassy_i2c_bmp180_calibration_data.rs | 2 +- .../src/bin/i2c_bmp180_calibration_data.rs | 2 +- examples/src/bin/i2c_display.rs | 2 +- examples/src/bin/lcd_cam_ov2640.rs | 11 +- hil-test/tests/i2c.rs | 2 +- 12 files changed, 369 insertions(+), 373 deletions(-) create mode 100644 esp-hal/src/i2c/lp_i2c.rs rename esp-hal/src/{i2c.rs => i2c/master/mod.rs} (84%) create mode 100644 esp-hal/src/i2c/mod.rs diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f26f56e2ad1..3f12da94ae0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419) - The I2S driver has been moved to `i2s::master` (#2472) - `slave::Spi` constructors no longer take pins (#2485) +- The `I2c` master driver has been moved from `esp_hal::i2c` to `esp_hal::i2c::master`. (#2476) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 20a9b22ef7d..ca14b32d0e7 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -65,7 +65,9 @@ the peripheral instance has been moved to the last generic parameter position. let spi: Spi<'static, FullDuplexMode, SPI2> = Spi::new_typed(peripherals.SPI2, 1.MHz(), SpiMode::Mode0); ``` -## I2C constructor changes +## I2C changes + +The I2C master driver and related types have been moved to `esp_hal::i2c::master`. The `with_timeout` constructors have been removed in favour of `set_timeout` or `with_timeout`. diff --git a/esp-hal/src/i2c/lp_i2c.rs b/esp-hal/src/i2c/lp_i2c.rs new file mode 100644 index 00000000000..2a16c94809e --- /dev/null +++ b/esp-hal/src/i2c/lp_i2c.rs @@ -0,0 +1,341 @@ +//! Low-power I2C driver + +use fugit::HertzU32; + +use crate::{ + gpio::lp_io::LowPowerOutputOpenDrain, + peripherals::{LP_CLKRST, LP_I2C0}, +}; + +const LP_I2C_FILTER_CYC_NUM_DEF: u8 = 7; + +/// I2C-specific transmission errors +#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// The transmission exceeded the FIFO size. + ExceedingFifo, + /// The acknowledgment check failed. + AckCheckFailed, + /// A timeout occurred during transmission. + TimeOut, + /// The arbitration for the bus was lost. + ArbitrationLost, + /// The execution of the I2C command was incomplete. + ExecIncomplete, + /// The number of commands issued exceeded the limit. + CommandNrExceeded, + /// The response received from the I2C device was invalid. + InvalidResponse, +} + +#[allow(unused)] +enum OperationType { + Write = 0, + Read = 1, +} + +#[allow(unused)] +#[derive(Eq, PartialEq, Copy, Clone)] +enum Ack { + Ack, + Nack, +} + +#[derive(PartialEq)] +#[allow(unused)] +enum Command { + Start, + Stop, + End, + Write { + /// This bit is to set an expected ACK value for the transmitter. + ack_exp: Ack, + /// Enables checking the ACK value received against the ack_exp + /// value. + ack_check_en: bool, + /// Length of data (in bytes) to be written. The maximum length is + /// 255, while the minimum is 1. + length: u8, + }, + Read { + /// Indicates whether the receiver will send an ACK after this byte + /// has been received. + ack_value: Ack, + /// Length of data (in bytes) to be read. The maximum length is 255, + /// while the minimum is 1. + length: u8, + }, +} + +// https://github.com/espressif/esp-idf/blob/master/components/ulp/lp_core/lp_core_i2c.c#L122 +// TX/RX RAM size is 16*8 bit +// TX RX FIFO has 16 bit depth +// The clock source of APB_CLK in LP_I2C is CLK_AON_FAST. +// Configure LP_I2C_SCLK_SEL to select the clock source for I2C_SCLK. +// When LP_I2C_SCLK_SEL is 0, select CLK_ROOT_FAST as clock source, +// and when LP_I2C_SCLK_SEL is 1, select CLK _XTALD2 as the clock source. +// Configure LP_EXT_I2C_CK_EN high to enable the clock source of I2C_SCLK. +// Adjust the timing registers accordingly when the clock frequency changes. + +/// Represents a Low-Power I2C peripheral. +pub struct LpI2c { + i2c: LP_I2C0, +} + +impl LpI2c { + /// Creates a new instance of the `LpI2c` peripheral. + pub fn new( + i2c: LP_I2C0, + _sda: LowPowerOutputOpenDrain<'_, 6>, + _scl: LowPowerOutputOpenDrain<'_, 7>, + frequency: HertzU32, + ) -> Self { + let me = Self { i2c }; + + // Configure LP I2C GPIOs + // Initialize IO Pins + let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; + let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; + let lp_peri = unsafe { &*crate::peripherals::LP_PERI::PTR }; + + unsafe { + // FIXME: use GPIO APIs to configure pins + lp_aon + .gpio_mux() + .modify(|r, w| w.sel().bits(r.sel().bits() | (1 << 6))); + lp_aon + .gpio_mux() + .modify(|r, w| w.sel().bits(r.sel().bits() | (1 << 7))); + lp_io.gpio(6).modify(|_, w| w.mcu_sel().bits(1)); // TODO + + lp_io.gpio(7).modify(|_, w| w.mcu_sel().bits(1)); + + // Set output mode to Normal + lp_io.pin(6).modify(|_, w| w.pad_driver().set_bit()); + // Enable output (writing to write-1-to-set register, then internally the + // `GPIO_OUT_REG` will be set) + lp_io + .out_enable_w1ts() + .write(|w| w.enable_w1ts().bits(1 << 6)); + // Enable input + lp_io.gpio(6).modify(|_, w| w.fun_ie().set_bit()); + + // Disable pulldown (enable internal weak pull-down) + lp_io.gpio(6).modify(|_, w| w.fun_wpd().clear_bit()); + // Enable pullup + lp_io.gpio(6).modify(|_, w| w.fun_wpu().set_bit()); + + // Same process for SCL pin + lp_io.pin(7).modify(|_, w| w.pad_driver().set_bit()); + // Enable output (writing to write-1-to-set register, then internally the + // `GPIO_OUT_REG` will be set) + lp_io + .out_enable_w1ts() + .write(|w| w.enable_w1ts().bits(1 << 7)); + // Enable input + lp_io.gpio(7).modify(|_, w| w.fun_ie().set_bit()); + // Disable pulldown (enable internal weak pull-down) + lp_io.gpio(7).modify(|_, w| w.fun_wpd().clear_bit()); + // Enable pullup + lp_io.gpio(7).modify(|_, w| w.fun_wpu().set_bit()); + + // Select LP I2C function for the SDA and SCL pins + lp_io.gpio(6).modify(|_, w| w.mcu_sel().bits(1)); + lp_io.gpio(7).modify(|_, w| w.mcu_sel().bits(1)); + } + + // Initialize LP I2C HAL */ + me.i2c.clk_conf().modify(|_, w| w.sclk_active().set_bit()); + + // Enable LP I2C controller clock + lp_peri + .clk_en() + .modify(|_, w| w.lp_ext_i2c_ck_en().set_bit()); + + lp_peri + .reset_en() + .modify(|_, w| w.lp_ext_i2c_reset_en().set_bit()); + lp_peri + .reset_en() + .modify(|_, w| w.lp_ext_i2c_reset_en().clear_bit()); + + // Set LP I2C source clock + unsafe { &*LP_CLKRST::PTR } + .lpperi() + .modify(|_, w| w.lp_i2c_clk_sel().clear_bit()); + + // Initialize LP I2C Master mode + me.i2c.ctr().modify(|_, w| unsafe { + // Clear register + w.bits(0); + // Use open drain output for SDA and SCL + w.sda_force_out().set_bit(); + w.scl_force_out().set_bit(); + // Ensure that clock is enabled + w.clk_en().set_bit() + }); + + // First, reset the fifo buffers + me.i2c.fifo_conf().modify(|_, w| w.nonfifo_en().clear_bit()); + + me.i2c.ctr().modify(|_, w| { + w.tx_lsb_first().clear_bit(); + w.rx_lsb_first().clear_bit() + }); + + me.reset_fifo(); + + // Set LP I2C source clock + unsafe { &*LP_CLKRST::PTR } + .lpperi() + .modify(|_, w| w.lp_i2c_clk_sel().clear_bit()); + + // Configure LP I2C timing paramters. source_clk is ignored for LP_I2C in this + // call + + let source_clk = 16_000_000; + let bus_freq = frequency.raw(); + + let clkm_div: u32 = source_clk / (bus_freq * 1024) + 1; + let sclk_freq: u32 = source_clk / clkm_div; + let half_cycle: u32 = sclk_freq / bus_freq / 2; + + // SCL + let scl_low = half_cycle; + // default, scl_wait_high < scl_high + // Make 80KHz as a boundary here, because when working at lower frequency, too + // much scl_wait_high will faster the frequency according to some + // hardware behaviors. + let scl_wait_high = if bus_freq >= 80 * 1000 { + half_cycle / 2 - 2 + } else { + half_cycle / 4 + }; + let scl_high = half_cycle - scl_wait_high; + let sda_hold = half_cycle / 4; + let sda_sample = half_cycle / 2; // TODO + scl_wait_high; + let setup = half_cycle; + let hold = half_cycle; + // default we set the timeout value to about 10 bus cycles + // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) + let tout = (4 * 8 - (5 * half_cycle).leading_zeros()) + 2; + + // According to the Technical Reference Manual, the following timings must be + // subtracted by 1. However, according to the practical measurement and + // some hardware behaviour, if wait_high_period and scl_high minus one. + // The SCL frequency would be a little higher than expected. Therefore, the + // solution here is not to minus scl_high as well as scl_wait high, and + // the frequency will be absolutely accurate to all frequency + // to some extent. + let scl_low_period = scl_low - 1; + let scl_high_period = scl_high; + let scl_wait_high_period = scl_wait_high; + // sda sample + let sda_hold_time = sda_hold - 1; + let sda_sample_time = sda_sample - 1; + // setup + let scl_rstart_setup_time = setup - 1; + let scl_stop_setup_time = setup - 1; + // hold + let scl_start_hold_time = hold - 1; + let scl_stop_hold_time = hold - 1; + let time_out_value = tout; + let time_out_en = true; + + // Write data to registers + unsafe { + me.i2c.clk_conf().modify(|_, w| { + w.sclk_sel().clear_bit(); + w.sclk_div_num().bits((clkm_div - 1) as u8) + }); + + // scl period + me.i2c + .scl_low_period() + .write(|w| w.scl_low_period().bits(scl_low_period as u16)); + + me.i2c.scl_high_period().write(|w| { + w.scl_high_period().bits(scl_high_period as u16); + w.scl_wait_high_period().bits(scl_wait_high_period as u8) + }); + // sda sample + me.i2c + .sda_hold() + .write(|w| w.time().bits(sda_hold_time as u16)); + me.i2c + .sda_sample() + .write(|w| w.time().bits(sda_sample_time as u16)); + + // setup + me.i2c + .scl_rstart_setup() + .write(|w| w.time().bits(scl_rstart_setup_time as u16)); + me.i2c + .scl_stop_setup() + .write(|w| w.time().bits(scl_stop_setup_time as u16)); + + // hold + me.i2c + .scl_start_hold() + .write(|w| w.time().bits(scl_start_hold_time as u16)); + me.i2c + .scl_stop_hold() + .write(|w| w.time().bits(scl_stop_hold_time as u16)); + + me.i2c.to().write(|w| { + w.time_out_en().bit(time_out_en); + w.time_out_value().bits(time_out_value.try_into().unwrap()) + }); + } + + // Enable SDA and SCL filtering. This configuration matches the HP I2C filter + // config + + me.i2c + .filter_cfg() + .modify(|_, w| unsafe { w.sda_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) }); + me.i2c + .filter_cfg() + .modify(|_, w| unsafe { w.scl_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) }); + + me.i2c + .filter_cfg() + .modify(|_, w| w.sda_filter_en().set_bit()); + me.i2c + .filter_cfg() + .modify(|_, w| w.scl_filter_en().set_bit()); + + // Configure the I2C master to send a NACK when the Rx FIFO count is full + me.i2c.ctr().modify(|_, w| w.rx_full_ack_level().set_bit()); + + // Synchronize the config register values to the LP I2C peripheral clock + me.lp_i2c_update(); + + me + } + + /// Update I2C configuration + fn lp_i2c_update(&self) { + self.i2c.ctr().modify(|_, w| w.conf_upgate().set_bit()); + } + + /// Resets the transmit and receive FIFO buffers. + fn reset_fifo(&self) { + self.i2c + .fifo_conf() + .modify(|_, w| w.tx_fifo_rst().set_bit()); + + self.i2c + .fifo_conf() + .modify(|_, w| w.tx_fifo_rst().clear_bit()); + + self.i2c + .fifo_conf() + .modify(|_, w| w.rx_fifo_rst().set_bit()); + + self.i2c + .fifo_conf() + .modify(|_, w| w.rx_fifo_rst().clear_bit()); + } +} diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c/master/mod.rs similarity index 84% rename from esp-hal/src/i2c.rs rename to esp-hal/src/i2c/master/mod.rs index a802ad2a3f4..036e2099d63 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -1,17 +1,4 @@ -//! # Inter-Integrated Circuit (I2C) -//! -//! I2C is a serial, synchronous, multi-device, half-duplex communication -//! protocol that allows co-existence of multiple masters and slaves on the -//! same bus. I2C uses two bidirectional open-drain lines: serial data line -//! (SDA) and serial clock line (SCL), pulled up by resistors. -//! -//! Espressif devices sometimes have more than one I2C controller, responsible -//! for handling communication on the I2C bus. A single I2C controller can be -//! a master or a slave. -//! -//! Typically, an I2C slave device has a 7-bit address or 10-bit address. -//! Devices supports both I2C Standard-mode (Sm) and Fast-mode (Fm) which can -//! go up to 100KHz and 400KHz respectively. +//! # Inter-Integrated Circuit (I2C) - Master mode //! //! ## Configuration //! @@ -31,7 +18,7 @@ //! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::i2c::I2c; +//! # use esp_hal::i2c::master::I2c; //! # use esp_hal::gpio::Io; //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! @@ -2318,348 +2305,3 @@ impl Instance for AnyI2c { } } } - -#[cfg(lp_i2c0)] -pub mod lp_i2c { - //! Low-power I2C driver - - use fugit::HertzU32; - - use crate::{ - gpio::lp_io::LowPowerOutputOpenDrain, - peripherals::{LP_CLKRST, LP_I2C0}, - }; - - const LP_I2C_FILTER_CYC_NUM_DEF: u8 = 7; - - /// I2C-specific transmission errors - #[derive(Debug, Clone, Copy, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum Error { - /// The transmission exceeded the FIFO size. - ExceedingFifo, - /// The acknowledgment check failed. - AckCheckFailed, - /// A timeout occurred during transmission. - TimeOut, - /// The arbitration for the bus was lost. - ArbitrationLost, - /// The execution of the I2C command was incomplete. - ExecIncomplete, - /// The number of commands issued exceeded the limit. - CommandNrExceeded, - /// The response received from the I2C device was invalid. - InvalidResponse, - } - - #[allow(unused)] - enum OperationType { - Write = 0, - Read = 1, - } - - #[allow(unused)] - #[derive(Eq, PartialEq, Copy, Clone)] - enum Ack { - Ack, - Nack, - } - - #[derive(PartialEq)] - #[allow(unused)] - enum Command { - Start, - Stop, - End, - Write { - /// This bit is to set an expected ACK value for the transmitter. - ack_exp: Ack, - /// Enables checking the ACK value received against the ack_exp - /// value. - ack_check_en: bool, - /// Length of data (in bytes) to be written. The maximum length is - /// 255, while the minimum is 1. - length: u8, - }, - Read { - /// Indicates whether the receiver will send an ACK after this byte - /// has been received. - ack_value: Ack, - /// Length of data (in bytes) to be read. The maximum length is 255, - /// while the minimum is 1. - length: u8, - }, - } - - // https://github.com/espressif/esp-idf/blob/master/components/ulp/lp_core/lp_core_i2c.c#L122 - // TX/RX RAM size is 16*8 bit - // TX RX FIFO has 16 bit depth - // The clock source of APB_CLK in LP_I2C is CLK_AON_FAST. - // Configure LP_I2C_SCLK_SEL to select the clock source for I2C_SCLK. - // When LP_I2C_SCLK_SEL is 0, select CLK_ROOT_FAST as clock source, - // and when LP_I2C_SCLK_SEL is 1, select CLK _XTALD2 as the clock source. - // Configure LP_EXT_I2C_CK_EN high to enable the clock source of I2C_SCLK. - // Adjust the timing registers accordingly when the clock frequency changes. - - /// Represents a Low-Power I2C peripheral. - pub struct LpI2c { - i2c: LP_I2C0, - } - - impl LpI2c { - /// Creates a new instance of the `LpI2c` peripheral. - pub fn new( - i2c: LP_I2C0, - _sda: LowPowerOutputOpenDrain<'_, 6>, - _scl: LowPowerOutputOpenDrain<'_, 7>, - frequency: HertzU32, - ) -> Self { - let me = Self { i2c }; - - // Configure LP I2C GPIOs - // Initialize IO Pins - let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; - let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; - let lp_peri = unsafe { &*crate::peripherals::LP_PERI::PTR }; - - unsafe { - // FIXME: use GPIO APIs to configure pins - lp_aon - .gpio_mux() - .modify(|r, w| w.sel().bits(r.sel().bits() | (1 << 6))); - lp_aon - .gpio_mux() - .modify(|r, w| w.sel().bits(r.sel().bits() | (1 << 7))); - lp_io.gpio(6).modify(|_, w| w.mcu_sel().bits(1)); // TODO - - lp_io.gpio(7).modify(|_, w| w.mcu_sel().bits(1)); - - // Set output mode to Normal - lp_io.pin(6).modify(|_, w| w.pad_driver().set_bit()); - // Enable output (writing to write-1-to-set register, then internally the - // `GPIO_OUT_REG` will be set) - lp_io - .out_enable_w1ts() - .write(|w| w.enable_w1ts().bits(1 << 6)); - // Enable input - lp_io.gpio(6).modify(|_, w| w.fun_ie().set_bit()); - - // Disable pulldown (enable internal weak pull-down) - lp_io.gpio(6).modify(|_, w| w.fun_wpd().clear_bit()); - // Enable pullup - lp_io.gpio(6).modify(|_, w| w.fun_wpu().set_bit()); - - // Same process for SCL pin - lp_io.pin(7).modify(|_, w| w.pad_driver().set_bit()); - // Enable output (writing to write-1-to-set register, then internally the - // `GPIO_OUT_REG` will be set) - lp_io - .out_enable_w1ts() - .write(|w| w.enable_w1ts().bits(1 << 7)); - // Enable input - lp_io.gpio(7).modify(|_, w| w.fun_ie().set_bit()); - // Disable pulldown (enable internal weak pull-down) - lp_io.gpio(7).modify(|_, w| w.fun_wpd().clear_bit()); - // Enable pullup - lp_io.gpio(7).modify(|_, w| w.fun_wpu().set_bit()); - - // Select LP I2C function for the SDA and SCL pins - lp_io.gpio(6).modify(|_, w| w.mcu_sel().bits(1)); - lp_io.gpio(7).modify(|_, w| w.mcu_sel().bits(1)); - } - - // Initialize LP I2C HAL */ - me.i2c.clk_conf().modify(|_, w| w.sclk_active().set_bit()); - - // Enable LP I2C controller clock - lp_peri - .clk_en() - .modify(|_, w| w.lp_ext_i2c_ck_en().set_bit()); - - lp_peri - .reset_en() - .modify(|_, w| w.lp_ext_i2c_reset_en().set_bit()); - lp_peri - .reset_en() - .modify(|_, w| w.lp_ext_i2c_reset_en().clear_bit()); - - // Set LP I2C source clock - unsafe { &*LP_CLKRST::PTR } - .lpperi() - .modify(|_, w| w.lp_i2c_clk_sel().clear_bit()); - - // Initialize LP I2C Master mode - me.i2c.ctr().modify(|_, w| unsafe { - // Clear register - w.bits(0); - // Use open drain output for SDA and SCL - w.sda_force_out().set_bit(); - w.scl_force_out().set_bit(); - // Ensure that clock is enabled - w.clk_en().set_bit() - }); - - // First, reset the fifo buffers - me.i2c.fifo_conf().modify(|_, w| w.nonfifo_en().clear_bit()); - - me.i2c.ctr().modify(|_, w| { - w.tx_lsb_first().clear_bit(); - w.rx_lsb_first().clear_bit() - }); - - me.reset_fifo(); - - // Set LP I2C source clock - unsafe { &*LP_CLKRST::PTR } - .lpperi() - .modify(|_, w| w.lp_i2c_clk_sel().clear_bit()); - - // Configure LP I2C timing paramters. source_clk is ignored for LP_I2C in this - // call - - let source_clk = 16_000_000; - let bus_freq = frequency.raw(); - - let clkm_div: u32 = source_clk / (bus_freq * 1024) + 1; - let sclk_freq: u32 = source_clk / clkm_div; - let half_cycle: u32 = sclk_freq / bus_freq / 2; - - // SCL - let scl_low = half_cycle; - // default, scl_wait_high < scl_high - // Make 80KHz as a boundary here, because when working at lower frequency, too - // much scl_wait_high will faster the frequency according to some - // hardware behaviors. - let scl_wait_high = if bus_freq >= 80 * 1000 { - half_cycle / 2 - 2 - } else { - half_cycle / 4 - }; - let scl_high = half_cycle - scl_wait_high; - let sda_hold = half_cycle / 4; - let sda_sample = half_cycle / 2; // TODO + scl_wait_high; - let setup = half_cycle; - let hold = half_cycle; - // default we set the timeout value to about 10 bus cycles - // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) - let tout = (4 * 8 - (5 * half_cycle).leading_zeros()) + 2; - - // According to the Technical Reference Manual, the following timings must be - // subtracted by 1. However, according to the practical measurement and - // some hardware behaviour, if wait_high_period and scl_high minus one. - // The SCL frequency would be a little higher than expected. Therefore, the - // solution here is not to minus scl_high as well as scl_wait high, and - // the frequency will be absolutely accurate to all frequency - // to some extent. - let scl_low_period = scl_low - 1; - let scl_high_period = scl_high; - let scl_wait_high_period = scl_wait_high; - // sda sample - let sda_hold_time = sda_hold - 1; - let sda_sample_time = sda_sample - 1; - // setup - let scl_rstart_setup_time = setup - 1; - let scl_stop_setup_time = setup - 1; - // hold - let scl_start_hold_time = hold - 1; - let scl_stop_hold_time = hold - 1; - let time_out_value = tout; - let time_out_en = true; - - // Write data to registers - unsafe { - me.i2c.clk_conf().modify(|_, w| { - w.sclk_sel().clear_bit(); - w.sclk_div_num().bits((clkm_div - 1) as u8) - }); - - // scl period - me.i2c - .scl_low_period() - .write(|w| w.scl_low_period().bits(scl_low_period as u16)); - - me.i2c.scl_high_period().write(|w| { - w.scl_high_period().bits(scl_high_period as u16); - w.scl_wait_high_period().bits(scl_wait_high_period as u8) - }); - // sda sample - me.i2c - .sda_hold() - .write(|w| w.time().bits(sda_hold_time as u16)); - me.i2c - .sda_sample() - .write(|w| w.time().bits(sda_sample_time as u16)); - - // setup - me.i2c - .scl_rstart_setup() - .write(|w| w.time().bits(scl_rstart_setup_time as u16)); - me.i2c - .scl_stop_setup() - .write(|w| w.time().bits(scl_stop_setup_time as u16)); - - // hold - me.i2c - .scl_start_hold() - .write(|w| w.time().bits(scl_start_hold_time as u16)); - me.i2c - .scl_stop_hold() - .write(|w| w.time().bits(scl_stop_hold_time as u16)); - - me.i2c.to().write(|w| { - w.time_out_en().bit(time_out_en); - w.time_out_value().bits(time_out_value.try_into().unwrap()) - }); - } - - // Enable SDA and SCL filtering. This configuration matches the HP I2C filter - // config - - me.i2c - .filter_cfg() - .modify(|_, w| unsafe { w.sda_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) }); - me.i2c - .filter_cfg() - .modify(|_, w| unsafe { w.scl_filter_thres().bits(LP_I2C_FILTER_CYC_NUM_DEF) }); - - me.i2c - .filter_cfg() - .modify(|_, w| w.sda_filter_en().set_bit()); - me.i2c - .filter_cfg() - .modify(|_, w| w.scl_filter_en().set_bit()); - - // Configure the I2C master to send a NACK when the Rx FIFO count is full - me.i2c.ctr().modify(|_, w| w.rx_full_ack_level().set_bit()); - - // Synchronize the config register values to the LP I2C peripheral clock - me.lp_i2c_update(); - - me - } - - /// Update I2C configuration - fn lp_i2c_update(&self) { - self.i2c.ctr().modify(|_, w| w.conf_upgate().set_bit()); - } - - /// Resets the transmit and receive FIFO buffers. - fn reset_fifo(&self) { - self.i2c - .fifo_conf() - .modify(|_, w| w.tx_fifo_rst().set_bit()); - - self.i2c - .fifo_conf() - .modify(|_, w| w.tx_fifo_rst().clear_bit()); - - self.i2c - .fifo_conf() - .modify(|_, w| w.rx_fifo_rst().set_bit()); - - self.i2c - .fifo_conf() - .modify(|_, w| w.rx_fifo_rst().clear_bit()); - } - } -} diff --git a/esp-hal/src/i2c/mod.rs b/esp-hal/src/i2c/mod.rs new file mode 100644 index 00000000000..69d84bc5576 --- /dev/null +++ b/esp-hal/src/i2c/mod.rs @@ -0,0 +1,11 @@ +//! # Inter-Integrated Circuit (I2C) +//! +//! I2C is a serial, synchronous, multi-device, half-duplex communication +//! protocol that allows co-existence of multiple masters and slaves on the +//! same bus. I2C uses two bidirectional open-drain lines: serial data line +//! (SDA) and serial clock line (SCL), pulled up by resistors. + +pub mod master; + +#[cfg(lp_i2c0)] +pub mod lp_i2c; diff --git a/esp-hal/src/prelude.rs b/esp-hal/src/prelude.rs index 06dd5855cad..5a4d41a8505 100644 --- a/esp-hal/src/prelude.rs +++ b/esp-hal/src/prelude.rs @@ -26,7 +26,7 @@ mod imp { Pin as _esp_hal_gpio_Pin, }; #[cfg(any(i2c0, i2c1))] - pub use crate::i2c::Instance as _esp_hal_i2c_Instance; + pub use crate::i2c::master::Instance as _esp_hal_i2c_master_Instance; #[cfg(ledc)] pub use crate::ledc::{ channel::{ diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index 152369854a4..0f757be363e 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -19,7 +19,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::I2c, prelude::*, timer::timg::TimerGroup}; +use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*, timer::timg::TimerGroup}; use lis3dh_async::{Lis3dh, Range, SlaveAddr}; #[esp_hal_embassy::main] diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 24fb3b7798c..14c1a3f52b8 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -20,7 +20,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::I2c, prelude::*, timer::timg::TimerGroup}; +use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*, timer::timg::TimerGroup}; #[esp_hal_embassy::main] async fn main(_spawner: Spawner) { diff --git a/examples/src/bin/i2c_bmp180_calibration_data.rs b/examples/src/bin/i2c_bmp180_calibration_data.rs index 582a9454ae8..88fc52fa0aa 100644 --- a/examples/src/bin/i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/i2c_bmp180_calibration_data.rs @@ -12,7 +12,7 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::I2c, prelude::*}; +use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*}; use esp_println::println; #[entry] diff --git a/examples/src/bin/i2c_display.rs b/examples/src/bin/i2c_display.rs index f31a1a84c7e..bb1270dc468 100644 --- a/examples/src/bin/i2c_display.rs +++ b/examples/src/bin/i2c_display.rs @@ -22,7 +22,7 @@ use embedded_graphics::{ text::{Alignment, Text}, }; use esp_backtrace as _; -use esp_hal::{delay::Delay, gpio::Io, i2c::I2c, prelude::*}; +use esp_hal::{delay::Delay, gpio::Io, i2c::master::I2c, prelude::*}; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; #[entry] diff --git a/examples/src/bin/lcd_cam_ov2640.rs b/examples/src/bin/lcd_cam_ov2640.rs index cdc6d64c1b2..03290740bcd 100644 --- a/examples/src/bin/lcd_cam_ov2640.rs +++ b/examples/src/bin/lcd_cam_ov2640.rs @@ -29,8 +29,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_rx_stream_buffer, gpio::Io, - i2c, - i2c::I2c, + i2c::{self, master::I2c}, lcd_cam::{ cam::{Camera, RxEightBits}, LcdCam, @@ -170,17 +169,17 @@ pub struct Sccb<'d, T> { impl<'d, T> Sccb<'d, T> where - T: i2c::Instance, + T: i2c::master::Instance, { pub fn new(i2c: I2c<'d, Blocking, T>) -> Self { Self { i2c } } - pub fn probe(&mut self, address: u8) -> Result<(), i2c::Error> { + pub fn probe(&mut self, address: u8) -> Result<(), i2c::master::Error> { self.i2c.write(address, &[]) } - pub fn read(&mut self, address: u8, reg: u8) -> Result { + pub fn read(&mut self, address: u8, reg: u8) -> Result { self.i2c.write(address, &[reg])?; let mut bytes = [0u8; 1]; @@ -188,7 +187,7 @@ where Ok(bytes[0]) } - pub fn write(&mut self, address: u8, reg: u8, data: u8) -> Result<(), i2c::Error> { + pub fn write(&mut self, address: u8, reg: u8, data: u8) -> Result<(), i2c::master::Error> { self.i2c.write(address, &[reg, data]) } } diff --git a/hil-test/tests/i2c.rs b/hil-test/tests/i2c.rs index b0d37c72470..2106897f071 100644 --- a/hil-test/tests/i2c.rs +++ b/hil-test/tests/i2c.rs @@ -7,7 +7,7 @@ use esp_hal::{ gpio::Io, - i2c::{I2c, Operation}, + i2c::master::{I2c, Operation}, prelude::*, Async, Blocking, From 50d8187e393ccb55f141e4438f5dd0ed3a42ec60 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 8 Nov 2024 13:30:33 +0000 Subject: [PATCH 44/67] esp-wifi: Remove unneeded features (#2446) * remove async features * phy-usb config * modem powersaving * Fix examples * make ps a runtime config * fix linting * changelog and migration guide * revert esp-config changes * remove blanklines after doc comments * cfg away ps API --- .github/workflows/ci.yml | 14 +- esp-wifi/CHANGELOG.md | 7 + esp-wifi/Cargo.toml | 58 +++------ esp-wifi/MIGRATING-0.10.md | 9 ++ esp-wifi/build.rs | 2 + esp-wifi/src/ble/btdm.rs | 1 - esp-wifi/src/ble/controller/mod.rs | 1 - esp-wifi/src/ble/mod.rs | 3 +- esp-wifi/src/ble/npl.rs | 2 - esp-wifi/src/ble/os_adapter_esp32.rs | 2 - .../common_adapter/common_adapter_esp32.rs | 1 - .../common_adapter/common_adapter_esp32c3.rs | 2 +- .../common_adapter/common_adapter_esp32c6.rs | 2 +- .../common_adapter/common_adapter_esp32h2.rs | 2 +- .../common_adapter/common_adapter_esp32s3.rs | 2 +- esp-wifi/src/config.rs | 47 +++++++ esp-wifi/src/esp_now/mod.rs | 31 ++--- esp-wifi/src/lib.rs | 42 +----- esp-wifi/src/wifi/mod.rs | 121 ++++++++---------- esp-wifi/src/wifi/os_adapter.rs | 2 - esp-wifi/src/wifi/state.rs | 2 - examples/src/bin/wifi_80211_tx.rs | 2 +- examples/src/bin/wifi_access_point.rs | 2 +- .../src/bin/wifi_access_point_with_sta.rs | 2 +- examples/src/bin/wifi_bench.rs | 2 +- examples/src/bin/wifi_coex.rs | 2 +- examples/src/bin/wifi_dhcp.rs | 2 +- examples/src/bin/wifi_embassy_access_point.rs | 6 +- .../bin/wifi_embassy_access_point_with_sta.rs | 8 +- examples/src/bin/wifi_embassy_bench.rs | 8 +- examples/src/bin/wifi_embassy_ble.rs | 2 +- examples/src/bin/wifi_embassy_dhcp.rs | 7 +- examples/src/bin/wifi_embassy_esp_now.rs | 2 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 2 +- examples/src/bin/wifi_embassy_trouble.rs | 2 +- examples/src/bin/wifi_sniffer.rs | 2 +- examples/src/bin/wifi_static_ip.rs | 2 +- extras/esp-wifishark/README.md | 4 +- hil-test/Cargo.toml | 4 - xtask/src/main.rs | 5 +- 40 files changed, 187 insertions(+), 232 deletions(-) create mode 100644 esp-wifi/src/config.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79f6b994eb0..e8bef8ccac6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -137,10 +137,10 @@ jobs: - name: msrv RISCV (esp-wifi) run: | - cargo xtask build-package --features=esp32c2,wifi,ble,async --target=riscv32imc-unknown-none-elf esp-wifi - cargo xtask build-package --features=esp32c3,wifi,ble,async --target=riscv32imc-unknown-none-elf esp-wifi - cargo xtask build-package --features=esp32c6,wifi,ble,async --target=riscv32imac-unknown-none-elf esp-wifi - cargo xtask build-package --features=esp32h2,ble,async --target=riscv32imac-unknown-none-elf esp-wifi + cargo xtask build-package --features=esp32c2,wifi,ble --target=riscv32imc-unknown-none-elf esp-wifi + cargo xtask build-package --features=esp32c3,wifi,ble --target=riscv32imc-unknown-none-elf esp-wifi + cargo xtask build-package --features=esp32c6,wifi,ble --target=riscv32imac-unknown-none-elf esp-wifi + cargo xtask build-package --features=esp32h2,ble --target=riscv32imac-unknown-none-elf esp-wifi # Verify the MSRV for all Xtensa chips: - name: msrv Xtensa (esp-hal) @@ -151,9 +151,9 @@ jobs: - name: msrv Xtensa (esp-wifi) run: | - cargo xtask build-package --toolchain=esp --features=esp32,wifi,ble,async --target=xtensa-esp32-none-elf esp-wifi - cargo xtask build-package --toolchain=esp --features=esp32s2,wifi,async --target=xtensa-esp32s2-none-elf esp-wifi - cargo xtask build-package --toolchain=esp --features=esp32s3,wifi,ble,async --target=xtensa-esp32s3-none-elf esp-wifi + cargo xtask build-package --toolchain=esp --features=esp32,wifi,ble --target=xtensa-esp32-none-elf esp-wifi + cargo xtask build-package --toolchain=esp --features=esp32s2,wifi --target=xtensa-esp32s2-none-elf esp-wifi + cargo xtask build-package --toolchain=esp --features=esp32s3,wifi,ble --target=xtensa-esp32s3-none-elf esp-wifi - name: msrv (esp-lp-hal) run: | diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index fcf7d07bb3b..7351d11a835 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -10,12 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added `serde` support through the `serde` feature (#2346) +- Added `PowerSaveMode` and `set_power_saving` methods on `EspNowManager` & `WifiController` (#2446) ### Changed - `esp_wifi::init` no longer requires `EspWifiInitFor`, and now returns `EspWifiController`, see the migration guide for more details (#2301) - No need to add `rom_functions.x` manually anymore (#2374) - esp-now: Data is now private in `ReceivedData` - use `data()`(#2396) +- Changed the async APIs to have a `_async` postfix to avoid name collisions (#2446) +- `phy_enable_usb` is enabled by default (#2446) ### Fixed @@ -25,6 +28,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - Feature `have-strchr` is removed (#2462) +- Features `async`, `embassy-net` have been removed (#2446) +- Features `phy-enable-usb` & `dump-packets` have been turned into configuration options `phy_enable_usb` & `dump_packets` (#2446) +- Features `ps-min-modem` & `ps-max-modem` have been removed in favour of a runtime config (#2446) + ## 0.10.1 - 2024-10-10 diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 4ac482a6a88..65d1beb2443 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -25,7 +25,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [ critical-section = "1.1.3" enumset = { version = "1.1.5", default-features = false, optional = true } embedded-io = { version = "0.6.1", default-features = false } -embedded-io-async = { version = "0.6.1", optional = true } +embedded-io-async = { version = "0.6.1" } fugit = "0.3.7" heapless = { version = "0.8.0", default-features = false, features = [ "portable-atomic", @@ -101,48 +101,35 @@ esp32s3 = [ "xtensa-lx-rt/float-save-restore", ] -## Enable Async support -async = [ - "dep:embassy-sync", - "dep:embedded-io-async", - "dep:bt-hci", -] - -## Enable `embassy-net` support -embassy-net = ["dep:embassy-net-driver", "async"] - ## Enable WiFi-BLE coexistence support coex = [] ## Logs the WiFi logs from the driver at log level info (needs a nightly-compiler) sys-logs = ["esp-wifi-sys/sys-logs"] -## Dumps packet info at log level info -dump-packets = [] - -## Provide implementations of smoltcp traits -smoltcp = ["dep:smoltcp"] +## Enable support for `defmt` +defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt", "bt-hci?/defmt", "esp-wifi-sys/defmt"] -## Provide utilities for smoltcp initialization. Adds smoltcp dependency -utils = ["smoltcp"] +## Enable support for the `log` crate +log = ["dep:log", "esp-hal/log", "esp-wifi-sys/log"] ## Enable WiFi support -wifi = ["dep:enumset"] +wifi = ["dep:enumset", "dep:embassy-net-driver", "dep:embassy-sync"] -## Enable BLE support -ble = ["esp-hal/bluetooth"] +## Enable esp-now support +esp-now = ["wifi"] -## See USB-SERIAL-JTAG below -phy-enable-usb = [] +## Enable sniffer mode support +sniffer = ["wifi"] -## Enable minimum modem sleep. Only affects STA mode -ps-min-modem = [] +## Enable BLE support +ble = ["esp-hal/bluetooth", "dep:bt-hci", "dep:embassy-sync"] -## Enable maximum modem sleep. Only affects STA mode -ps-max-modem = [] +## Provide implementations of smoltcp traits +smoltcp = ["dep:smoltcp"] -## Enable esp-now support -esp-now = ["wifi"] +## Provide utilities for smoltcp initialization. Adds smoltcp dependency +utils = ["smoltcp"] ## IPv6 support. Includes utils feature ipv6 = ["wifi", "utils", "smoltcp?/proto-ipv6"] @@ -171,15 +158,6 @@ dhcpv4 = ["wifi", "utils", "smoltcp?/proto-dhcpv4", "smoltcp?/socket-dhcpv4"] ## Convenience to enable "ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4" wifi-default = ["ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4"] -## Enable support for `defmt` -defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt", "bt-hci?/defmt", "esp-wifi-sys/defmt"] - -## Enable support for the `log` crate -log = ["dep:log", "esp-hal/log", "esp-wifi-sys/log"] - -## Enable sniffer mode support -sniffer = ["wifi"] - # Implement serde Serialize / Deserialize serde = ["dep:serde", "enumset?/serde", "heapless/serde"] @@ -189,8 +167,6 @@ features = [ "wifi", "ble", "coex", - "async", - "embassy-net", "esp-hal/default", ] -default-target = "riscv32imc-unknown-none-elf" +default-target = "riscv32imc-unknown-none-elf" \ No newline at end of file diff --git a/esp-wifi/MIGRATING-0.10.md b/esp-wifi/MIGRATING-0.10.md index 0bf1d4c5c73..d2763ba21fb 100644 --- a/esp-wifi/MIGRATING-0.10.md +++ b/esp-wifi/MIGRATING-0.10.md @@ -33,3 +33,12 @@ rustflags = [ Previously `data` and `len` were public - use the previously already existing `data()` function. Accessing `data` or `len` was never encouraged. + +## Async features have been removed and async functionality is always available + +The cost of this is that we need to rename the various `async` methods on `WifiController`. + +```diff +- controller.start().await.unwrap(); ++ controller.start_async().await.unwrap(); +``` diff --git a/esp-wifi/build.rs b/esp-wifi/build.rs index 5197c6ffb41..23be6c6ab3b 100644 --- a/esp-wifi/build.rs +++ b/esp-wifi/build.rs @@ -127,6 +127,8 @@ fn main() -> Result<(), Box> { ("ap_beacon_timeout", Value::UnsignedInteger(300), "For SoftAP, If the SoftAP doesn’t receive any data from the connected STA during inactive time, the SoftAP will force deauth the STA. Default is 300s"), ("failure_retry_cnt", Value::UnsignedInteger(1), "Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config. Note: Enabling this may cause connection time to increase incase best AP doesn't behave properly. Defaults to 1"), ("scan_method", Value::UnsignedInteger(0), "0 = WIFI_FAST_SCAN, 1 = WIFI_ALL_CHANNEL_SCAN, defaults to 0"), + ("dump_packets", Value::Bool(false), "Dump packets via an info log statement"), + ("phy_enable_usb", Value::Bool(true), "Keeps USB running when using WiFi. This allows debugging and log messages via USB Serial JTAG. Turn off for best WiFi performance."), ], true ); diff --git a/esp-wifi/src/ble/btdm.rs b/esp-wifi/src/ble/btdm.rs index c6ca321db35..6d444c2d464 100644 --- a/esp-wifi/src/ble/btdm.rs +++ b/esp-wifi/src/ble/btdm.rs @@ -79,7 +79,6 @@ extern "C" fn notify_host_recv(data: *mut u8, len: u16) -> i32 { super::dump_packet_info(data); - #[cfg(feature = "async")] crate::ble::controller::asynch::hci_read_data_available(); 0 diff --git a/esp-wifi/src/ble/controller/mod.rs b/esp-wifi/src/ble/controller/mod.rs index bd2b58c92f9..7667a187982 100644 --- a/esp-wifi/src/ble/controller/mod.rs +++ b/esp-wifi/src/ble/controller/mod.rs @@ -83,7 +83,6 @@ impl Write for BleConnector<'_> { } /// Async Interface -#[cfg(feature = "async")] pub(crate) mod asynch { use core::task::Poll; diff --git a/esp-wifi/src/ble/mod.rs b/esp-wifi/src/ble/mod.rs index 7246ffbcb8b..22994478b53 100644 --- a/esp-wifi/src/ble/mod.rs +++ b/esp-wifi/src/ble/mod.rs @@ -117,7 +117,6 @@ impl defmt::Format for ReceivedPacket { } } -#[cfg(feature = "async")] pub fn have_hci_read_data() -> bool { critical_section::with(|cs| { let queue = BT_RECEIVE_QUEUE.borrow_ref_mut(cs); @@ -160,7 +159,7 @@ pub fn read_hci(data: &mut [u8]) -> usize { } fn dump_packet_info(_buffer: &[u8]) { - #[cfg(feature = "dump-packets")] + #[cfg(dump_packets)] critical_section::with(|_cs| { info!("@HCIFRAME {:?}", _buffer); }); diff --git a/esp-wifi/src/ble/npl.rs b/esp-wifi/src/ble/npl.rs index 3d8696966b5..f08516f95da 100644 --- a/esp-wifi/src/ble/npl.rs +++ b/esp-wifi/src/ble/npl.rs @@ -1298,7 +1298,6 @@ unsafe extern "C" fn ble_hs_hci_rx_evt(cmd: *const u8, arg: *const c_void) -> i3 r_ble_hci_trans_buf_free(cmd); - #[cfg(feature = "async")] crate::ble::controller::asynch::hci_read_data_available(); 0 @@ -1327,7 +1326,6 @@ unsafe extern "C" fn ble_hs_rx_data(om: *const OsMbuf, arg: *const c_void) -> i3 r_os_mbuf_free_chain(om as *mut _); - #[cfg(feature = "async")] crate::ble::controller::asynch::hci_read_data_available(); 0 diff --git a/esp-wifi/src/ble/os_adapter_esp32.rs b/esp-wifi/src/ble/os_adapter_esp32.rs index 39f55cadc2b..f49c2ac05ba 100644 --- a/esp-wifi/src/ble/os_adapter_esp32.rs +++ b/esp-wifi/src/ble/os_adapter_esp32.rs @@ -586,7 +586,6 @@ const BTDM_ASYNC_WAKEUP_REQ_COEX: i32 = 1; /// true if request lock is needed, false otherwise /// /// ************************************************************************* - #[cfg(coex)] fn async_wakeup_request(event: i32) -> bool { let mut do_wakeup_request = false; @@ -623,7 +622,6 @@ fn async_wakeup_request(event: i32) -> bool { /// true if request lock is needed, false otherwise /// /// ************************************************************************* - #[cfg(coex)] fn async_wakeup_request_end(event: i32) { let request_lock = match event { diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32.rs b/esp-wifi/src/common_adapter/common_adapter_esp32.rs index 26a05931a95..268311fe81c 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32.rs @@ -155,7 +155,6 @@ pub(crate) unsafe fn phy_disable_clock() { /// Register value /// /// ************************************************************************* - #[ram] #[no_mangle] unsafe extern "C" fn esp_dport_access_reg_read(reg: u32) -> u32 { diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs b/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs index 8a4bf0ab044..eaa7903a1fe 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32c3.rs @@ -76,7 +76,7 @@ pub(crate) unsafe fn phy_enable() { let init_data = &PHY_INIT_DATA_DEFAULT; - #[cfg(feature = "phy-enable-usb")] + #[cfg(phy_enable_usb)] { extern "C" { fn phy_bbpll_en_usb(param: bool); diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs b/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs index 74f3d76cecd..bd0e30cfe66 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32c6.rs @@ -41,7 +41,7 @@ pub(crate) unsafe fn phy_enable() { let init_data = &PHY_INIT_DATA_DEFAULT; - #[cfg(feature = "phy-enable-usb")] + #[cfg(phy_enable_usb)] { extern "C" { fn phy_bbpll_en_usb(param: bool); diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs b/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs index 1cb0b537589..0186c2759fa 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32h2.rs @@ -44,7 +44,7 @@ pub(crate) unsafe fn phy_enable() { // this would cause linker errors when the feature is activated - see https://github.com/esp-rs/esp-wifi/issues/457 - // #[cfg(feature = "phy-enable-usb")] + // #[cfg(phy_enable_usb)] // { // extern "C" { // pub fn phy_bbpll_en_usb(param: bool); diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs b/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs index 249370caa1f..f4213be87dd 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32s3.rs @@ -72,7 +72,7 @@ pub(crate) unsafe fn phy_enable() { let init_data = &PHY_INIT_DATA_DEFAULT; - #[cfg(feature = "phy-enable-usb")] + #[cfg(phy_enable_usb)] { extern "C" { fn phy_bbpll_en_usb(param: bool); diff --git a/esp-wifi/src/config.rs b/esp-wifi/src/config.rs new file mode 100644 index 00000000000..92f2a97e167 --- /dev/null +++ b/esp-wifi/src/config.rs @@ -0,0 +1,47 @@ +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Tunable parameters for the WiFi driver +#[allow(unused)] // currently there are no ble tunables +pub(crate) struct EspWifiConfig { + pub(crate) rx_queue_size: usize, + pub(crate) tx_queue_size: usize, + pub(crate) static_rx_buf_num: usize, + pub(crate) dynamic_rx_buf_num: usize, + pub(crate) static_tx_buf_num: usize, + pub(crate) dynamic_tx_buf_num: usize, + pub(crate) ampdu_rx_enable: bool, + pub(crate) ampdu_tx_enable: bool, + pub(crate) amsdu_tx_enable: bool, + pub(crate) rx_ba_win: usize, + pub(crate) max_burst_size: usize, + pub(crate) country_code: &'static str, + pub(crate) country_code_operating_class: u8, + pub(crate) mtu: usize, + pub(crate) tick_rate_hz: u32, + pub(crate) listen_interval: u16, + pub(crate) beacon_timeout: u16, + pub(crate) ap_beacon_timeout: u16, + pub(crate) failure_retry_cnt: u8, + pub(crate) scan_method: u32, +} + +#[cfg(not(coex))] +#[non_exhaustive] +#[derive(Default)] +pub enum PowerSaveMode { + None, + #[default] + Minimum, + Maximum, +} + +#[cfg(not(coex))] +impl From for esp_wifi_sys::include::wifi_ps_type_t { + fn from(s: PowerSaveMode) -> Self { + match s { + PowerSaveMode::None => esp_wifi_sys::include::wifi_ps_type_t_WIFI_PS_NONE, + PowerSaveMode::Minimum => esp_wifi_sys::include::wifi_ps_type_t_WIFI_PS_MIN_MODEM, + PowerSaveMode::Maximum => esp_wifi_sys::include::wifi_ps_type_t_WIFI_PS_MAX_MODEM, + } + } +} diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index febd478bf30..cc65c355577 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -16,6 +16,8 @@ use critical_section::Mutex; use enumset::EnumSet; use portable_atomic::{AtomicBool, AtomicU8, Ordering}; +#[cfg(not(coex))] +use crate::config::PowerSaveMode; use crate::{ binary::include::*, hal::peripheral::{Peripheral, PeripheralRef}, @@ -335,6 +337,12 @@ impl EspNowManager<'_> { Ok(()) } + #[cfg(not(coex))] + /// Configures modem power saving + pub fn set_power_saving(&self, ps: PowerSaveMode) -> Result<(), WifiError> { + crate::wifi::apply_power_saving(ps) + } + /// Set primary WiFi channel. /// Should only be used when using ESP-NOW without AP or STA. pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> { @@ -682,25 +690,6 @@ impl<'d> EspNow<'d> { check_error!({ esp_wifi_set_inactive_time(wifi_interface_t_WIFI_IF_STA, crate::CONFIG.beacon_timeout) })?; - cfg_if::cfg_if! { - if #[cfg(feature = "ps-min-modem")] { - check_error!({esp_wifi_set_ps( - crate::binary::include::wifi_ps_type_t_WIFI_PS_MIN_MODEM - )})?; - } else if #[cfg(feature = "ps-max-modem")] { - check_error!({esp_wifi_set_ps( - crate::binary::include::wifi_ps_type_t_WIFI_PS_MAX_MODEM - )})?; - } else if #[cfg(coex)] { - check_error!({esp_wifi_set_ps( - crate::binary::include::wifi_ps_type_t_WIFI_PS_MIN_MODEM - )})?; - } else { - check_error!({esp_wifi_set_ps( - crate::binary::include::wifi_ps_type_t_WIFI_PS_NONE - )})?; - } - }; check_error!({ esp_now_init() })?; check_error!({ esp_now_register_recv_cb(Some(rcv_cb)) })?; check_error!({ esp_now_register_send_cb(Some(send_cb)) })?; @@ -824,7 +813,6 @@ unsafe extern "C" fn send_cb(_mac_addr: *const u8, status: esp_now_send_status_t ESP_NOW_SEND_CB_INVOKED.store(true, Ordering::Release); - #[cfg(feature = "async")] asynch::ESP_NOW_TX_WAKER.wake(); }) } @@ -871,15 +859,12 @@ unsafe extern "C" fn rcv_cb( queue.push_back(ReceivedData { data, info }); - #[cfg(feature = "async")] asynch::ESP_NOW_RX_WAKER.wake(); }); } -#[cfg(feature = "async")] pub use asynch::SendFuture; -#[cfg(feature = "async")] mod asynch { use core::task::{Context, Poll}; diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index e96f3c41769..3a7d1e195b5 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -48,19 +48,12 @@ //! Within this crate, `CCOMPARE0` CPU timer is used for timing, ensure that in //! your application you are not using this CPU timer. //! -//! ## USB-SERIAL-JTAG -//! -//! When using USB-SERIAL-JTAG (for example by selecting `jtag-serial` in [`esp-println`](https://crates.io/crates/esp-println)) you have to activate the feature `phy-enable-usb`. -//! -//! Don't use this feature if you are _not_ using USB-SERIAL-JTAG as it might -//! reduce WiFi performance. -//! //! # Features flags //! //! Note that not all features are available on every MCU. For example, `ble` //! (and thus, `coex`) is not available on ESP32-S2. //! -//! When using the `dump-packets` feature you can use the extcap in +//! When using the `dump_packets` config you can use the extcap in //! `extras/esp-wifishark` to analyze the frames in Wireshark. //! For more information see //! [extras/esp-wifishark/README.md](../extras/esp-wifishark/README.md) @@ -134,6 +127,8 @@ pub mod ble; #[cfg(feature = "esp-now")] pub mod esp_now; +pub mod config; + pub(crate) mod common_adapter; #[doc(hidden)] @@ -169,34 +164,7 @@ const _: () = { }; }; -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Tunable parameters for the WiFi driver -#[allow(unused)] // currently there are no ble tunables -struct Config { - rx_queue_size: usize, - tx_queue_size: usize, - static_rx_buf_num: usize, - dynamic_rx_buf_num: usize, - static_tx_buf_num: usize, - dynamic_tx_buf_num: usize, - ampdu_rx_enable: bool, - ampdu_tx_enable: bool, - amsdu_tx_enable: bool, - rx_ba_win: usize, - max_burst_size: usize, - country_code: &'static str, - country_code_operating_class: u8, - mtu: usize, - tick_rate_hz: u32, - listen_interval: u16, - beacon_timeout: u16, - ap_beacon_timeout: u16, - failure_retry_cnt: u8, - scan_method: u32, -} - -pub(crate) const CONFIG: Config = Config { +pub(crate) const CONFIG: config::EspWifiConfig = config::EspWifiConfig { rx_queue_size: esp_config_int!(usize, "ESP_WIFI_RX_QUEUE_SIZE"), tx_queue_size: esp_config_int!(usize, "ESP_WIFI_TX_QUEUE_SIZE"), static_rx_buf_num: esp_config_int!(usize, "ESP_WIFI_STATIC_RX_BUF_NUM"), @@ -371,11 +339,9 @@ impl private::Sealed for Trng<'_> {} /// ```rust, no_run #[doc = esp_hal::before_snippet!()] /// use esp_hal::{rng::Rng, timg::TimerGroup}; -/// use esp_wifi::EspWifiInitFor; /// /// let timg0 = TimerGroup::new(peripherals.TIMG0); /// let init = esp_wifi::init( -/// EspWifiInitFor::Wifi, /// timg0.timer0, /// Rng::new(peripherals.RNG), /// peripherals.RADIO_CLK, diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index 33df1bcefee..cfc22ef2ddb 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -50,7 +50,6 @@ use esp_wifi_sys::include::{ wifi_promiscuous_pkt_type_t, }; use num_derive::FromPrimitive; -use num_traits::FromPrimitive; #[doc(hidden)] pub(crate) use os_adapter::*; #[cfg(feature = "sniffer")] @@ -62,6 +61,8 @@ use serde::{Deserialize, Serialize}; use smoltcp::phy::{Device, DeviceCapabilities, RxToken, TxToken}; pub use state::*; +#[cfg(not(coex))] +use crate::config::PowerSaveMode; use crate::{ common_adapter::*, esp_wifi_result, @@ -105,7 +106,6 @@ use crate::binary::{ esp_wifi_set_country, esp_wifi_set_mode, esp_wifi_set_protocol, - esp_wifi_set_ps, esp_wifi_set_tx_done_cb, esp_wifi_start, esp_wifi_stop, @@ -1623,7 +1623,6 @@ unsafe extern "C" fn recv_cb_sta( false } }) { - #[cfg(feature = "embassy-net")] embassy::STA_RECEIVE_WAKER.wake(); include::ESP_OK as esp_err_t } else { @@ -1653,7 +1652,6 @@ unsafe extern "C" fn recv_cb_ap( false } }) { - #[cfg(feature = "embassy-net")] embassy::AP_RECEIVE_WAKER.wake(); include::ESP_OK as esp_err_t } else { @@ -1683,7 +1681,6 @@ unsafe extern "C" fn esp_wifi_tx_done_cb( decrement_inflight_counter(); - #[cfg(feature = "embassy-net")] embassy::TRANSMIT_WAKER.wake(); } @@ -1707,20 +1704,6 @@ pub(crate) fn wifi_start() -> Result<(), WifiError> { ))?; }; - cfg_if::cfg_if! { - if #[cfg(feature = "ps-min-modem")] { - let ps_mode = include::wifi_ps_type_t_WIFI_PS_MIN_MODEM; - } else if #[cfg(feature = "ps-max-modem")] { - let ps_mode = include::wifi_ps_type_t_WIFI_PS_MAX_MODEM; - } else if #[cfg(coex)] { - let ps_mode = include::wifi_ps_type_t_WIFI_PS_MIN_MODEM; - } else { - let ps_mode = include::wifi_ps_type_t_WIFI_PS_NONE; - } - }; - - esp_wifi_result!(esp_wifi_set_ps(ps_mode))?; - let mut cntry_code = [0u8; 3]; cntry_code[..crate::CONFIG.country_code.len()] .copy_from_slice(crate::CONFIG.country_code.as_bytes()); @@ -2041,18 +2024,14 @@ mod sealed { fn interface(self) -> wifi_interface_t; - #[cfg(feature = "embassy-net")] fn register_transmit_waker(self, cx: &mut core::task::Context) { embassy::TRANSMIT_WAKER.register(cx.waker()) } - #[cfg(feature = "embassy-net")] fn register_receive_waker(self, cx: &mut core::task::Context); - #[cfg(feature = "embassy-net")] fn register_link_state_waker(self, cx: &mut core::task::Context); - #[cfg(feature = "embassy-net")] fn link_state(self) -> embassy_net_driver::LinkState; } @@ -2075,17 +2054,14 @@ mod sealed { wifi_interface_t_WIFI_IF_STA } - #[cfg(feature = "embassy-net")] fn register_receive_waker(self, cx: &mut core::task::Context) { embassy::STA_RECEIVE_WAKER.register(cx.waker()); } - #[cfg(feature = "embassy-net")] fn register_link_state_waker(self, cx: &mut core::task::Context) { embassy::STA_LINK_STATE_WAKER.register(cx.waker()); } - #[cfg(feature = "embassy-net")] fn link_state(self) -> embassy_net_driver::LinkState { if matches!(get_sta_state(), WifiState::StaConnected) { embassy_net_driver::LinkState::Up @@ -2114,17 +2090,14 @@ mod sealed { wifi_interface_t_WIFI_IF_AP } - #[cfg(feature = "embassy-net")] fn register_receive_waker(self, cx: &mut core::task::Context) { embassy::AP_RECEIVE_WAKER.register(cx.waker()); } - #[cfg(feature = "embassy-net")] fn register_link_state_waker(self, cx: &mut core::task::Context) { embassy::AP_LINK_STATE_WAKER.register(cx.waker()); } - #[cfg(feature = "embassy-net")] fn link_state(self) -> embassy_net_driver::LinkState { if matches!(get_ap_state(), WifiState::ApStarted) { embassy_net_driver::LinkState::Up @@ -2619,6 +2592,12 @@ impl<'d> WifiController<'d> { Ok(()) } + #[cfg(not(coex))] + /// Configures modem power saving + pub fn set_power_saving(&mut self, ps: PowerSaveMode) -> Result<(), WifiError> { + apply_power_saving(ps) + } + /// Checks if Wi-Fi is enabled as a station. pub fn is_sta_enabled(&self) -> Result { WifiMode::try_from(&self.config).map(|m| m.is_sta()) @@ -2684,6 +2663,33 @@ impl<'d> WifiController<'d> { Ok(scanned) } + + /// A blocking wifi network scan with default scanning options. + pub fn scan_n( + &mut self, + ) -> Result<(heapless::Vec, usize), WifiError> { + self.scan_with_config_sync(Default::default()) + } + + /// Starts the WiFi controller. + pub fn start(&mut self) -> Result<(), WifiError> { + crate::wifi::wifi_start() + } + + /// Stops the WiFi controller. + pub fn stop(&mut self) -> Result<(), WifiError> { + self.stop_impl() + } + + /// Connects the WiFi controller to a network. + pub fn connect(&mut self) -> Result<(), WifiError> { + self.connect_impl() + } + + /// Disconnects the WiFi controller from a network. + pub fn disconnect(&mut self) -> Result<(), WifiError> { + self.disconnect_impl() + } } // see https://docs.rs/smoltcp/0.7.1/smoltcp/phy/index.html @@ -3155,38 +3161,8 @@ impl WifiController<'_> { } } -#[cfg(not(feature = "async"))] -impl WifiController<'_> { - /// A blocking wifi network scan with default scanning options. - pub fn scan_n( - &mut self, - ) -> Result<(heapless::Vec, usize), WifiError> { - self.scan_with_config_sync(Default::default()) - } - - /// Starts the WiFi controller. - pub fn start(&mut self) -> Result<(), WifiError> { - crate::wifi::wifi_start() - } - - /// Stops the WiFi controller. - pub fn stop(&mut self) -> Result<(), WifiError> { - self.stop_impl() - } - - /// Connects the WiFi controller to a network. - pub fn connect(&mut self) -> Result<(), WifiError> { - self.connect_impl() - } - - /// Disconnects the WiFi controller from a network. - pub fn disconnect(&mut self) -> Result<(), WifiError> { - self.disconnect_impl() - } -} - fn dump_packet_info(_buffer: &[u8]) { - #[cfg(feature = "dump-packets")] + #[cfg(dump_packets)] { info!("@WIFIFRAME {:?}", _buffer); } @@ -3196,8 +3172,9 @@ fn dump_packet_info(_buffer: &[u8]) { #[macro_export] macro_rules! esp_wifi_result { ($value:expr) => {{ + use num_traits::FromPrimitive; let result = $value; - if result != include::ESP_OK as i32 { + if result != esp_wifi_sys::include::ESP_OK as i32 { warn!("{} returned an error: {}", stringify!($value), result); Err(WifiError::InternalError(unwrap!(FromPrimitive::from_i32( result @@ -3208,7 +3185,6 @@ macro_rules! esp_wifi_result { }}; } -#[cfg(feature = "embassy-net")] pub(crate) mod embassy { use embassy_net_driver::{Capabilities, Driver, HardwareAddress, RxToken, TxToken}; use embassy_sync::waitqueue::AtomicWaker; @@ -3289,7 +3265,12 @@ pub(crate) mod embassy { } } -#[cfg(feature = "async")] +#[cfg(not(coex))] +pub(crate) fn apply_power_saving(ps: PowerSaveMode) -> Result<(), WifiError> { + esp_wifi_result!(unsafe { esp_wifi_sys::include::esp_wifi_set_ps(ps.into()) })?; + Ok(()) +} + mod asynch { use core::task::Poll; @@ -3300,14 +3281,14 @@ mod asynch { // TODO assumes STA mode only impl WifiController<'_> { /// Async version of [`crate::wifi::WifiController`]'s `scan_n` method - pub async fn scan_n( + pub async fn scan_n_async( &mut self, ) -> Result<(heapless::Vec, usize), WifiError> { - self.scan_with_config(Default::default()).await + self.scan_with_config_async(Default::default()).await } /// An async wifi network scan with caller-provided scanning options. - pub async fn scan_with_config( + pub async fn scan_with_config_async( &mut self, config: ScanConfig<'_>, ) -> Result<(heapless::Vec, usize), WifiError> { @@ -3327,7 +3308,7 @@ mod asynch { } /// Async version of [`crate::wifi::WifiController`]'s `start` method - pub async fn start(&mut self) -> Result<(), WifiError> { + pub async fn start_async(&mut self) -> Result<(), WifiError> { let mode = WifiMode::try_from(&self.config)?; let mut events = enumset::enum_set! {}; @@ -3348,7 +3329,7 @@ mod asynch { } /// Async version of [`crate::wifi::WifiController`]'s `stop` method - pub async fn stop(&mut self) -> Result<(), WifiError> { + pub async fn stop_async(&mut self) -> Result<(), WifiError> { let mode = WifiMode::try_from(&self.config)?; let mut events = enumset::enum_set! {}; @@ -3372,7 +3353,7 @@ mod asynch { } /// Async version of [`crate::wifi::WifiController`]'s `connect` method - pub async fn connect(&mut self) -> Result<(), WifiError> { + pub async fn connect_async(&mut self) -> Result<(), WifiError> { Self::clear_events(WifiEvent::StaConnected | WifiEvent::StaDisconnected); let err = crate::wifi::WifiController::connect_impl(self).err(); @@ -3389,7 +3370,7 @@ mod asynch { /// Async version of [`crate::wifi::WifiController`]'s `Disconnect` /// method - pub async fn disconnect(&mut self) -> Result<(), WifiError> { + pub async fn disconnect_async(&mut self) -> Result<(), WifiError> { // If not connected, this will do nothing. // It will also wait forever for a `StaDisconnected` event that will never come. // Return early instead of hanging. diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index c059c8c1a5f..cd87ab6633d 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -870,10 +870,8 @@ pub unsafe extern "C" fn event_post( super::state::update_state(event); - #[cfg(feature = "async")] event.waker().wake(); - #[cfg(feature = "embassy-net")] match event { WifiEvent::StaConnected | WifiEvent::StaDisconnected => { crate::wifi::embassy::STA_LINK_STATE_WAKER.wake(); diff --git a/esp-wifi/src/wifi/state.rs b/esp-wifi/src/wifi/state.rs index 58d8d4441f9..e11f584f576 100644 --- a/esp-wifi/src/wifi/state.rs +++ b/esp-wifi/src/wifi/state.rs @@ -62,12 +62,10 @@ pub(crate) fn update_state(event: WifiEvent) { } } -#[cfg(feature = "async")] pub(crate) fn reset_ap_state() { AP_STATE.store(WifiState::Invalid, Ordering::Relaxed) } -#[cfg(feature = "async")] pub(crate) fn reset_sta_state() { STA_STATE.store(WifiState::Invalid, Ordering::Relaxed) } diff --git a/examples/src/bin/wifi_80211_tx.rs b/examples/src/bin/wifi_80211_tx.rs index c073ce12789..3b33456fd09 100644 --- a/examples/src/bin/wifi_80211_tx.rs +++ b/examples/src/bin/wifi_80211_tx.rs @@ -1,7 +1,7 @@ //! WiFi frame injection example //! //! Periodically transmits a beacon frame. -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index a4e8032851f..94c5b182105 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -6,7 +6,7 @@ //! Open http://192.168.2.1:8080/ in your browser //! //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index 36e17512864..f9c3e0792e5 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -7,7 +7,7 @@ //! Open http://192.168.2.1:8080/ in your browser - the example will perform an HTTP get request to some "random" server //! //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index 06a474b8f70..511773ee705 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -6,7 +6,7 @@ //! cargo run --release //! ``` //! Ensure you have set the IP of your local machine in the `HOST_IP` env variable. E.g `HOST_IP="192.168.0.24"` and also set SSID and PASSWORD env variable before running this example. -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index a8c779d117f..002ea35e8f3 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -6,7 +6,7 @@ //! - does BLE advertising (you cannot connect to it - it's just not implemented in the example) //! //! Note: On ESP32-C2 and ESP32-C3 you need a wifi-heap size of 70000, on ESP32-C6 you need 80000 and a tx_queue_size of 10 -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/ble esp-wifi/coex //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index 68f642c3d38..fd756e4478c 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -4,7 +4,7 @@ //! Set SSID and PASSWORD env variable before running this example. //! //! This gets an ip address via DHCP then performs an HTTP get request to some "random" server -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index 748df8ccba5..ca86dc2d078 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -7,9 +7,9 @@ //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -220,7 +220,7 @@ async fn connection(mut controller: WifiController<'static>) { }); controller.set_configuration(&client_config).unwrap(); println!("Starting wifi"); - controller.start().await.unwrap(); + controller.start_async().await.unwrap(); println!("Wifi started!"); } } diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 82f74805509..6ce2d859052 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -10,9 +10,9 @@ //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -315,7 +315,7 @@ async fn connection(mut controller: WifiController<'static>) { println!("Device capabilities: {:?}", controller.get_capabilities()); println!("Starting wifi"); - controller.start().await.unwrap(); + controller.start_async().await.unwrap(); println!("Wifi started!"); loop { @@ -323,7 +323,7 @@ async fn connection(mut controller: WifiController<'static>) { WifiState::ApStarted => { println!("About to connect..."); - match controller.connect().await { + match controller.connect_async().await { Ok(_) => { // wait until we're no longer connected controller.wait_for_event(WifiEvent::StaDisconnected).await; diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 80334b862db..d33289a4218 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -8,9 +8,9 @@ //! Ensure you have set the IP of your local machine in the `HOST_IP` env variable. E.g `HOST_IP="192.168.0.24"` and also set SSID and PASSWORD env variable before running this example. //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 and ESP32-C2 -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 #![allow(static_mut_refs)] @@ -193,12 +193,12 @@ async fn connection(mut controller: WifiController<'static>) { }); controller.set_configuration(&client_config).unwrap(); println!("Starting wifi"); - controller.start().await.unwrap(); + controller.start_async().await.unwrap(); println!("Wifi started!"); } println!("About to connect..."); - match controller.connect().await { + match controller.connect_async().await { Ok(_) => println!("Wifi connected!"), Err(e) => { println!("Failed to connect to wifi: {e:?}"); diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index 3fb6d0dd181..5ba16b69863 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -4,7 +4,7 @@ //! - offers one service with three characteristics (one is read/write, one is write only, one is read/write/notify) //! - pressing the boot-button on a dev-board will send a notification if it is subscribed -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/ble +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/ble //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 #![no_std] diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 5ee5bb322ba..67bea7f3ada 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -6,9 +6,8 @@ //! This gets an ip address via DHCP then performs an HTTP get request to some "random" server //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//! When using USB-SERIAL-JTAG you have to activate the feature `phy-enable-usb` in the esp-wifi crate. -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -186,12 +185,12 @@ async fn connection(mut controller: WifiController<'static>) { }); controller.set_configuration(&client_config).unwrap(); println!("Starting wifi"); - controller.start().await.unwrap(); + controller.start_async().await.unwrap(); println!("Wifi started!"); } println!("About to connect..."); - match controller.connect().await { + match controller.connect_async().await { Ok(_) => println!("Wifi connected!"), Err(e) => { println!("Failed to connect to wifi: {e:?}"); diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index 3b7aecd43e8..3828ec9a9e8 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 1eeec3a88a5..600aca964c9 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_trouble.rs b/examples/src/bin/wifi_embassy_trouble.rs index 45253463ae6..a5f55a02750 100644 --- a/examples/src/bin/wifi_embassy_trouble.rs +++ b/examples/src/bin/wifi_embassy_trouble.rs @@ -5,7 +5,7 @@ //! - automatically notifies subscribers every second //! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/ble +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/ble //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 #![no_std] diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 4e56d6338ef..69256e326bc 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -1,7 +1,7 @@ //! WiFi sniffer example //! //! Sniffs for beacon frames. -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index e9a91fe1fac..af7f14d2674 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -5,7 +5,7 @@ //! - might be necessary to configure your WiFi access point accordingly //! - uses the given static IP //! - responds with some HTML content when connecting to port 8080 -//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. +//! //% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 diff --git a/extras/esp-wifishark/README.md b/extras/esp-wifishark/README.md index 1a10a828f45..887a3e057c2 100644 --- a/extras/esp-wifishark/README.md +++ b/extras/esp-wifishark/README.md @@ -1,6 +1,6 @@ # esp-wifishark -This is an extcap to be used with esp-wifi and the `dump-packets` feature. +This is an extcap to be used with esp-wifi and the `dump_packets` config option. To use it build via `cargo build --release` and copy the resulting executable to the Wireshark's `extcap` folder. @@ -8,6 +8,6 @@ Then you should see two new capture interfaces in Wireshark - esp-wifi HCI capture (for Bluetooth HCI) - esp-wifi Ethernet capture (for WiFi traffic) -If you are running an application using esp-wifi's `dump-packets` feature and logging at INFO level active these capture interfaces can connect via serialport to give you insights on what is going on. +If you are running an application using esp-wifi's `dump_packets` config and logging at INFO level active these capture interfaces can connect via serialport to give you insights on what is going on. By default it tries to identify exactly one serialport. If that doesn't work for you, you can configure the serialport via the Wireshark UI. diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 980d53dce0e..112d87941bb 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -249,21 +249,18 @@ esp32c3 = [ "esp-hal/esp32c3", "esp-hal-embassy?/esp32c3", "esp-wifi?/esp32c3", - "esp-wifi?/phy-enable-usb", ] esp32c6 = [ "esp-backtrace/esp32c6", "esp-hal/esp32c6", "esp-hal-embassy?/esp32c6", "esp-wifi?/esp32c6", - "esp-wifi?/phy-enable-usb", ] esp32h2 = [ "esp-backtrace/esp32h2", "esp-hal/esp32h2", "esp-hal-embassy?/esp32h2", "esp-wifi?/esp32h2", - "esp-wifi?/phy-enable-usb", ] esp32s2 = [ "embedded-test/xtensa-semihosting", @@ -278,7 +275,6 @@ esp32s3 = [ "esp-hal/esp32s3", "esp-hal-embassy?/esp32s3", "esp-wifi?/esp32s3", - "esp-wifi?/phy-enable-usb", ] # Async & Embassy: embassy = [ diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 4a43062fab2..9a4488c6dab 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -697,11 +697,10 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> { } Package::EspWifi => { - let mut features = - format!("--features={chip},async,ps-min-modem,defmt,dump-packets,sys-logs"); + let mut features = format!("--features={chip},defmt,sys-logs"); if device.contains("wifi") { - features.push_str(",wifi-default,esp-now,embassy-net,sniffer") + features.push_str(",wifi-default,esp-now,sniffer") } if device.contains("bt") { features.push_str(",ble") From 3c4b7f0f6649cfd381350b77fde4cbe91be63e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Fri, 8 Nov 2024 14:43:34 +0100 Subject: [PATCH 45/67] Test more embassy interrupt spi dma (#2490) * Add C3,C6 and H2 for `embassy_interrupt_spi_dma` * Test more * Don't require physically connected pins --- hil-test/tests/embassy_interrupt_spi_dma.rs | 74 +++++++++++++++++++-- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 85dc6edacf8..d5394ff9ba5 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -1,6 +1,6 @@ //! Reproduction and regression test for a sneaky issue. -//% CHIPS: esp32 esp32s2 esp32s3 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 esp32h2 //% FEATURES: integrated-timers //% FEATURES: generic-queue @@ -11,10 +11,12 @@ use embassy_time::{Duration, Instant, Ticker}; use esp_hal::{ dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, + gpio::Io, interrupt::{software::SoftwareInterruptControl, Priority}, + peripheral::Peripheral, prelude::*, spi::{ - master::{Config, Spi, SpiDma}, + master::{Config, Spi}, SpiMode, }, timer::AnyTimer, @@ -22,6 +24,7 @@ use esp_hal::{ }; use esp_hal_embassy::InterruptExecutor; use hil_test as _; +use portable_atomic::AtomicBool; macro_rules! mk_static { ($t:ty,$val:expr) => {{ @@ -32,8 +35,11 @@ macro_rules! mk_static { }}; } +static INTERRUPT_TASK_WORKING: AtomicBool = AtomicBool::new(false); + +#[cfg(any(esp32, esp32s2, esp32s3))] #[embassy_executor::task] -async fn interrupt_driven_task(spi: SpiDma<'static, Async>) { +async fn interrupt_driven_task(spi: esp_hal::spi::master::SpiDma<'static, Async>) { let mut ticker = Ticker::every(Duration::from_millis(1)); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(128); @@ -45,7 +51,25 @@ async fn interrupt_driven_task(spi: SpiDma<'static, Async>) { loop { let mut buffer: [u8; 8] = [0; 8]; + INTERRUPT_TASK_WORKING.fetch_not(portable_atomic::Ordering::Release); spi.transfer_in_place_async(&mut buffer).await.unwrap(); + INTERRUPT_TASK_WORKING.fetch_not(portable_atomic::Ordering::Acquire); + + ticker.next().await; + } +} + +#[cfg(not(any(esp32, esp32s2, esp32s3)))] +#[embassy_executor::task] +async fn interrupt_driven_task(mut i2s_tx: esp_hal::i2s::master::I2sTx<'static, Async>) { + let mut ticker = Ticker::every(Duration::from_millis(1)); + + loop { + let mut buffer: [u8; 8] = [0; 8]; + + INTERRUPT_TASK_WORKING.fetch_not(portable_atomic::Ordering::Release); + i2s_tx.write_dma_async(&mut buffer).await.unwrap(); + INTERRUPT_TASK_WORKING.fetch_not(portable_atomic::Ordering::Acquire); ticker.next().await; } @@ -94,6 +118,9 @@ mod test { let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let (_, mosi) = hil_test::common_test_pins!(io); + let mut spi = Spi::new_with_config( peripherals.SPI2, Config { @@ -102,11 +129,14 @@ mod test { ..Config::default() }, ) + .with_miso(unsafe { mosi.clone_unchecked() }) + .with_mosi(mosi) .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) .with_buffers(dma_rx_buf, dma_tx_buf) .into_async(); - let spi2 = Spi::new_with_config( + #[cfg(any(esp32, esp32s2, esp32s3))] + let other_peripheral = Spi::new_with_config( peripherals.SPI3, Config { frequency: 100.kHz(), @@ -117,6 +147,26 @@ mod test { .with_dma(dma_channel2.configure(false, DmaPriority::Priority0)) .into_async(); + #[cfg(not(any(esp32, esp32s2, esp32s3)))] + let other_peripheral = { + let (_, rx_descriptors, _, tx_descriptors) = dma_buffers!(128); + + let other_peripheral = esp_hal::i2s::master::I2s::new( + peripherals.I2S0, + esp_hal::i2s::master::Standard::Philips, + esp_hal::i2s::master::DataFormat::Data8Channel8, + 8u32.kHz(), + dma_channel2.configure(false, DmaPriority::Priority0), + rx_descriptors, + tx_descriptors, + ) + .into_async() + .i2s_tx + .build(); + + other_peripheral + }; + let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); let interrupt_executor = mk_static!( @@ -126,16 +176,28 @@ mod test { let spawner = interrupt_executor.start(Priority::Priority3); - spawner.spawn(interrupt_driven_task(spi2)).unwrap(); + spawner + .spawn(interrupt_driven_task(other_peripheral)) + .unwrap(); let start = Instant::now(); let mut buffer: [u8; 1024] = [0; 1024]; + let mut dst_buffer: [u8; 1024] = [0; 1024]; + let mut i = 0; loop { - spi.transfer_in_place_async(&mut buffer).await.unwrap(); + buffer.fill(i); + dst_buffer.fill(i.wrapping_add(1)); + spi.transfer_async(&mut dst_buffer, &buffer).await.unwrap(); + // make sure the transfer didn't end prematurely + assert!(dst_buffer.iter().all(|&v| v == i)); if start.elapsed() > Duration::from_secs(1) { + // make sure the other peripheral didn't get stuck + while INTERRUPT_TASK_WORKING.load(portable_atomic::Ordering::Acquire) {} break; } + + i = i.wrapping_add(1); } } From 7402ad61ed726df7c4db458671fb42b91d6a9e28 Mon Sep 17 00:00:00 2001 From: Sergio Gasquez Arcos Date: Fri, 8 Nov 2024 17:33:13 +0100 Subject: [PATCH 46/67] Expose CSI API in esp-wifi (#2422) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: (WIP) add CSI api * feat: Enable G_CONFIG.csi_enable and update example * fix: Allow user to set the dessired cb method * fix: Clippy warnings * fix: Add missing doccomments * feat: Add csi_enable config * refactor: Update CsiConfiguration c6 struct * feat: Create set_csi WifiController and EspNowManager methods * docs: Update changelog * refactor: Rename CsiConfig struct * docs: Document c6 version of CsiConfig * feat: impl From for crate::include::wifi_csi_config_t * style: Rustfmt * docs: Fix comment Co-authored-by: Dániel Buga * docs: Fix typo Co-authored-by: Juraj Sadel * feat: Enable CSI on examples by default * feat: Handle errors * style: Rustfmt * feat: Update error * feat: Panic if csi config is not enabled * feat: Cfg CSI stuff when CSI is disabled instead of panicing * fix: Clippy lints * feat: Fix signed bitfields * feat: Pass the cb via ctx * feat: Update CSI callback to use closures * refactor: Rename promiscuous_csi_rx_cb to csi_rx_cb * feat: Move extra boxing inside set_receive_cb * feat: Refactor CSI callback to use generic types * refactor: Remove Sized bound from CsiCallback trait * feat: Add csi_enable field to EspWifiConfig and update CsiCallback trait for conditional compilation * feat: Remove unnecessary boxes * feat: Update callback type in set_csi to require Send trait Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --------- Co-authored-by: Dániel Buga Co-authored-by: Juraj Sadel Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --- esp-wifi/CHANGELOG.md | 1 + esp-wifi/build.rs | 1 + esp-wifi/src/config.rs | 1 + esp-wifi/src/esp_now/mod.rs | 16 +++ esp-wifi/src/lib.rs | 29 +++++ esp-wifi/src/wifi/mod.rs | 212 ++++++++++++++++++++++++++++++++++- examples/.cargo/config.toml | 1 + examples/src/bin/wifi_csi.rs | 133 ++++++++++++++++++++++ 8 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 examples/src/bin/wifi_csi.rs diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 7351d11a835..96050adf2da 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `serde` support through the `serde` feature (#2346) - Added `PowerSaveMode` and `set_power_saving` methods on `EspNowManager` & `WifiController` (#2446) +- Added CSI support (#2422) ### Changed diff --git a/esp-wifi/build.rs b/esp-wifi/build.rs index 23be6c6ab3b..4384034181b 100644 --- a/esp-wifi/build.rs +++ b/esp-wifi/build.rs @@ -105,6 +105,7 @@ fn main() -> Result<(), Box> { ("dynamic_rx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), ("static_tx_buf_num", Value::UnsignedInteger(0), "WiFi static TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), ("dynamic_tx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), + ("csi_enable", Value::Bool(false), "WiFi channel state information enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), ("ampdu_rx_enable", Value::Bool(true), "WiFi AMPDU RX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), ("ampdu_tx_enable", Value::Bool(true), "WiFi AMPDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), ("amsdu_tx_enable", Value::Bool(false), "WiFi AMSDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), diff --git a/esp-wifi/src/config.rs b/esp-wifi/src/config.rs index 92f2a97e167..0b9c77fecb4 100644 --- a/esp-wifi/src/config.rs +++ b/esp-wifi/src/config.rs @@ -9,6 +9,7 @@ pub(crate) struct EspWifiConfig { pub(crate) dynamic_rx_buf_num: usize, pub(crate) static_tx_buf_num: usize, pub(crate) dynamic_tx_buf_num: usize, + pub(crate) csi_enable: bool, pub(crate) ampdu_rx_enable: bool, pub(crate) ampdu_tx_enable: bool, pub(crate) amsdu_tx_enable: bool, diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index cc65c355577..d4f26fdb6fe 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -18,6 +18,8 @@ use portable_atomic::{AtomicBool, AtomicU8, Ordering}; #[cfg(not(coex))] use crate::config::PowerSaveMode; +#[cfg(csi_enable)] +use crate::wifi::CsiConfig; use crate::{ binary::include::*, hal::peripheral::{Peripheral, PeripheralRef}, @@ -369,6 +371,20 @@ impl EspNowManager<'_> { check_error!({ esp_now_add_peer(&raw_peer as *const _) }) } + /// Set CSI configuration and register the receiving callback. + #[cfg(csi_enable)] + pub fn set_csi( + &mut self, + mut csi: CsiConfig, + cb: impl FnMut(crate::wifi::wifi_csi_info_t) + Send, + ) -> Result<(), WifiError> { + csi.apply_config()?; + csi.set_receive_cb(cb)?; + csi.set_csi(true)?; + + Ok(()) + } + /// Remove the given peer. pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> { check_error!({ esp_now_del_peer(peer_address.as_ptr()) }) diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 3a7d1e195b5..2d5849da440 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -164,6 +164,34 @@ const _: () = { }; }; +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Tunable parameters for the WiFi driver +#[allow(unused)] // currently there are no ble tunables +struct Config { + rx_queue_size: usize, + tx_queue_size: usize, + static_rx_buf_num: usize, + dynamic_rx_buf_num: usize, + static_tx_buf_num: usize, + dynamic_tx_buf_num: usize, + csi_enable: bool, + ampdu_rx_enable: bool, + ampdu_tx_enable: bool, + amsdu_tx_enable: bool, + rx_ba_win: usize, + max_burst_size: usize, + country_code: &'static str, + country_code_operating_class: u8, + mtu: usize, + tick_rate_hz: u32, + listen_interval: u16, + beacon_timeout: u16, + ap_beacon_timeout: u16, + failure_retry_cnt: u8, + scan_method: u32, +} + pub(crate) const CONFIG: config::EspWifiConfig = config::EspWifiConfig { rx_queue_size: esp_config_int!(usize, "ESP_WIFI_RX_QUEUE_SIZE"), tx_queue_size: esp_config_int!(usize, "ESP_WIFI_TX_QUEUE_SIZE"), @@ -171,6 +199,7 @@ pub(crate) const CONFIG: config::EspWifiConfig = config::EspWifiConfig { dynamic_rx_buf_num: esp_config_int!(usize, "ESP_WIFI_DYNAMIC_RX_BUF_NUM"), static_tx_buf_num: esp_config_int!(usize, "ESP_WIFI_STATIC_TX_BUF_NUM"), dynamic_tx_buf_num: esp_config_int!(usize, "ESP_WIFI_DYNAMIC_TX_BUF_NUM"), + csi_enable: esp_config_bool!("ESP_WIFI_CSI_ENABLE"), ampdu_rx_enable: esp_config_bool!("ESP_WIFI_AMPDU_RX_ENABLE"), ampdu_tx_enable: esp_config_bool!("ESP_WIFI_AMPDU_TX_ENABLE"), amsdu_tx_enable: esp_config_bool!("ESP_WIFI_AMSDU_TX_ENABLE"), diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index cfc22ef2ddb..e5b4f494268 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -83,6 +83,17 @@ pub mod utils; #[cfg(coex)] use include::{coex_adapter_funcs_t, coex_pre_init, esp_coex_adapter_register}; +#[cfg(all(csi_enable, esp32c6))] +use crate::binary::include::wifi_csi_acquire_config_t; +#[cfg(csi_enable)] +pub use crate::binary::include::wifi_csi_info_t; +#[cfg(csi_enable)] +use crate::binary::include::{ + esp_wifi_set_csi, + esp_wifi_set_csi_config, + esp_wifi_set_csi_rx_cb, + wifi_csi_config_t, +}; use crate::binary::{ c_types, include::{ @@ -340,6 +351,191 @@ impl Default for ClientConfiguration { } } +#[cfg(csi_enable)] +pub(crate) trait CsiCallback: FnMut(crate::binary::include::wifi_csi_info_t) {} + +#[cfg(csi_enable)] +impl CsiCallback for T where T: FnMut(crate::binary::include::wifi_csi_info_t) {} + +#[cfg(csi_enable)] +unsafe extern "C" fn csi_rx_cb( + ctx: *mut crate::wifi::c_types::c_void, + data: *mut crate::binary::include::wifi_csi_info_t, +) { + let csi_callback = unsafe { &mut *(ctx as *mut C) }; + csi_callback(*data); +} + +#[derive(Clone, PartialEq, Eq)] +// https://github.com/esp-rs/esp-wifi-sys/blob/main/esp-wifi-sys/headers/local/esp_wifi_types_native.h#L94 +/// Channel state information(CSI) configuration +#[cfg(all(not(esp32c6), csi_enable))] +pub struct CsiConfig { + /// Enable to receive legacy long training field(lltf) data. + pub lltf_en: bool, + /// Enable to receive HT long training field(htltf) data. + pub htltf_en: bool, + /// Enable to receive space time block code HT long training + /// field(stbc-htltf2) data. + pub stbc_htltf2_en: bool, + /// Enable to generate htlft data by averaging lltf and ht_ltf data when + /// receiving HT packet. Otherwise, use ht_ltf data directly. + pub ltf_merge_en: bool, + /// Enable to turn on channel filter to smooth adjacent sub-carrier. Disable + /// it to keep independence of adjacent sub-carrier. + pub channel_filter_en: bool, + /// Manually scale the CSI data by left shifting or automatically scale the + /// CSI data. If set true, please set the shift bits. false: automatically. + /// true: manually. + pub manu_scale: bool, + /// Manually left shift bits of the scale of the CSI data. The range of the + /// left shift bits is 0~15. + pub shift: u8, + /// Enable to dump 802.11 ACK frame. + pub dump_ack_en: bool, +} + +#[derive(Clone, PartialEq, Eq)] +#[cfg(all(esp32c6, csi_enable))] +// See https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/src/include/esp32c6.rs#L5702-L5705 +pub struct CsiConfig { + /// Enable to acquire CSI. + pub enable: u32, + /// Enable to acquire L-LTF when receiving a 11g PPDU. + pub acquire_csi_legacy: u32, + /// Enable to acquire HT-LTF when receiving an HT20 PPDU. + pub acquire_csi_ht20: u32, + /// Enable to acquire HT-LTF when receiving an HT40 PPDU. + pub acquire_csi_ht40: u32, + /// Enable to acquire HE-LTF when receiving an HE20 SU PPDU. + pub acquire_csi_su: u32, + /// Enable to acquire HE-LTF when receiving an HE20 MU PPDU. + pub acquire_csi_mu: u32, + /// Enable to acquire HE-LTF when receiving an HE20 DCM applied PPDU. + pub acquire_csi_dcm: u32, + /// Enable to acquire HE-LTF when receiving an HE20 Beamformed applied PPDU. + pub acquire_csi_beamformed: u32, + /// Wwhen receiving an STBC applied HE PPDU, 0- acquire the complete + /// HE-LTF1, 1- acquire the complete HE-LTF2, 2- sample evenly among the + /// HE-LTF1 and HE-LTF2. + pub acquire_csi_he_stbc: u32, + /// Vvalue 0-3. + pub val_scale_cfg: u32, + /// Enable to dump 802.11 ACK frame, default disabled. + pub dump_ack_en: u32, + /// Reserved. + pub reserved: u32, +} + +#[cfg(csi_enable)] +impl Default for CsiConfig { + #[cfg(not(esp32c6))] + fn default() -> Self { + Self { + lltf_en: true, + htltf_en: true, + stbc_htltf2_en: true, + ltf_merge_en: true, + channel_filter_en: true, + manu_scale: false, + shift: 0, + dump_ack_en: false, + } + } + + #[cfg(esp32c6)] + fn default() -> Self { + // https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/headers/esp_wifi_he_types.h#L67-L82 + Self { + enable: 1, + acquire_csi_legacy: 1, + acquire_csi_ht20: 1, + acquire_csi_ht40: 1, + acquire_csi_su: 1, + acquire_csi_mu: 1, + acquire_csi_dcm: 1, + acquire_csi_beamformed: 1, + acquire_csi_he_stbc: 2, + val_scale_cfg: 2, + dump_ack_en: 1, + reserved: 19, + } + } +} + +#[cfg(csi_enable)] +impl From for wifi_csi_config_t { + fn from(config: CsiConfig) -> Self { + #[cfg(not(esp32c6))] + { + wifi_csi_config_t { + lltf_en: config.lltf_en, + htltf_en: config.htltf_en, + stbc_htltf2_en: config.stbc_htltf2_en, + ltf_merge_en: config.ltf_merge_en, + channel_filter_en: config.channel_filter_en, + manu_scale: config.manu_scale, + shift: config.shift, + dump_ack_en: config.dump_ack_en, + } + } + #[cfg(esp32c6)] + { + wifi_csi_acquire_config_t { + _bitfield_align_1: [0; 0], + _bitfield_1: wifi_csi_acquire_config_t::new_bitfield_1( + config.enable, + config.acquire_csi_legacy, + config.acquire_csi_ht20, + config.acquire_csi_ht40, + config.acquire_csi_su, + config.acquire_csi_mu, + config.acquire_csi_dcm, + config.acquire_csi_beamformed, + config.acquire_csi_he_stbc, + config.val_scale_cfg, + config.dump_ack_en, + config.reserved, + ), + } + } + } +} + +#[cfg(csi_enable)] +impl CsiConfig { + /// Set CSI data configuration + pub(crate) fn apply_config(&self) -> Result<(), WifiError> { + let conf: wifi_csi_config_t = self.clone().into(); + + unsafe { + esp_wifi_result!(esp_wifi_set_csi_config(&conf))?; + } + Ok(()) + } + + /// Register the RX callback function of CSI data. Each time a CSI data is + /// received, the callback function will be called. + pub(crate) fn set_receive_cb(&mut self, cb: C) -> Result<(), WifiError> { + let cb = alloc::boxed::Box::new(cb); + let cb_ptr = alloc::boxed::Box::into_raw(cb) as *mut crate::wifi::c_types::c_void; + + unsafe { + esp_wifi_result!(esp_wifi_set_csi_rx_cb(Some(csi_rx_cb::), cb_ptr))?; + } + Ok(()) + } + + /// Enable or disable CSI + pub(crate) fn set_csi(&self, enable: bool) -> Result<(), WifiError> { + // https://github.com/esp-rs/esp-wifi-sys/blob/2a466d96fe8119d49852fc794aea0216b106ba7b/esp-wifi-sys/headers/esp_wifi.h#L1241 + unsafe { + esp_wifi_result!(esp_wifi_set_csi(enable))?; + } + Ok(()) + } +} + /// Configuration for EAP-FAST authentication protocol. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1524,7 +1720,7 @@ static mut G_CONFIG: wifi_init_config_t = wifi_init_config_t { rx_mgmt_buf_type: esp_wifi_sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF as i32, rx_mgmt_buf_num: esp_wifi_sys::include::CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF as i32, cache_tx_buf_num: esp_wifi_sys::include::WIFI_CACHE_TX_BUFFER_NUM as i32, - csi_enable: esp_wifi_sys::include::WIFI_CSI_ENABLED as i32, + csi_enable: crate::CONFIG.csi_enable as i32, ampdu_rx_enable: crate::CONFIG.ampdu_rx_enable as i32, ampdu_tx_enable: crate::CONFIG.ampdu_tx_enable as i32, amsdu_tx_enable: crate::CONFIG.amsdu_tx_enable as i32, @@ -2536,6 +2732,20 @@ impl<'d> WifiController<'d> { } } + /// Set CSI configuration and register the receiving callback. + #[cfg(csi_enable)] + pub fn set_csi( + &mut self, + mut csi: CsiConfig, + cb: impl FnMut(crate::wifi::wifi_csi_info_t) + Send, + ) -> Result<(), WifiError> { + csi.apply_config()?; + csi.set_receive_cb(cb)?; + csi.set_csi(true)?; + + Ok(()) + } + /// Set the wifi protocol. /// /// This will set the wifi protocol to the desired protocol, the default for diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml index 7fcbcbfad75..600f74b2ea4 100644 --- a/examples/.cargo/config.toml +++ b/examples/.cargo/config.toml @@ -33,6 +33,7 @@ PASSWORD = "PASSWORD" STATIC_IP = "1.1.1.1 " GATEWAY_IP = "1.1.1.1" HOST_IP = "1.1.1.1" +ESP_WIFI_CSI_ENABLE = "true" [unstable] build-std = ["alloc", "core"] diff --git a/examples/src/bin/wifi_csi.rs b/examples/src/bin/wifi_csi.rs new file mode 100644 index 00000000000..e330c3d6cf8 --- /dev/null +++ b/examples/src/bin/wifi_csi.rs @@ -0,0 +1,133 @@ +//! CSI Example +//! +//! +//! Set SSID and PASSWORD env variable before running this example. +//! + +//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/log +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 + +#![no_std] +#![no_main] + +extern crate alloc; + +use esp_alloc as _; +use esp_backtrace as _; +use esp_hal::{ + prelude::*, + rng::Rng, + time::{self}, + timer::timg::TimerGroup, +}; +use esp_println::println; +use esp_wifi::{ + init, + wifi::{ + utils::create_network_interface, + AccessPointInfo, + ClientConfiguration, + Configuration, + CsiConfig, + WifiError, + WifiStaDevice, + }, + wifi_interface::WifiStack, + // EspWifiInitFor, +}; +use smoltcp::iface::SocketStorage; + +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); + +#[entry] +fn main() -> ! { + esp_println::logger::init_logger_from_env(); + let peripherals = esp_hal::init({ + let mut config = esp_hal::Config::default(); + config.cpu_clock = CpuClock::max(); + config + }); + + esp_alloc::heap_allocator!(72 * 1024); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + let init = init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap(); + + let mut wifi = peripherals.WIFI; + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let (iface, device, mut controller, sockets) = + create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let now = || time::now().duration_since_epoch().to_millis(); + let wifi_stack = WifiStack::new(iface, device, sockets, now); + + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.try_into().unwrap(), + password: PASSWORD.try_into().unwrap(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); + + let csi = CsiConfig::default(); + controller + .set_csi(csi, |data: esp_wifi::wifi::wifi_csi_info_t| { + let rx_ctrl = data.rx_ctrl; + // Signed bitfields are broken in rust-bingen, see https://github.com/esp-rs/esp-wifi-sys/issues/482 + let rssi = if rx_ctrl.rssi() > 127 { + rx_ctrl.rssi() - 256 + } else { + rx_ctrl.rssi() + }; + println!("rssi: {:?} rate: {}", rssi, rx_ctrl.rate()); + }) + .unwrap(); + + println!("Waiting for CSI data..."); + println!("Start Wifi Scan"); + let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); + if let Ok((res, _count)) = res { + for ap in res { + println!("{:?}", ap); + } + } + + println!("{:?}", controller.get_capabilities()); + println!("wifi_connect {:?}", controller.connect()); + + // wait to get connected + println!("Wait to get connected"); + loop { + match controller.is_connected() { + Ok(true) => break, + Ok(false) => {} + Err(err) => { + println!("{:?}", err); + loop {} + } + } + } + println!("{:?}", controller.is_connected()); + + // wait for getting an ip address + println!("Wait to get an ip address"); + loop { + wifi_stack.work(); + + if wifi_stack.is_iface_up() { + println!("got ip {:?}", wifi_stack.get_ip_info()); + break; + } + } + + println!("Start busy loop on main"); + loop {} +} From e10ae2ddff9d861dd59dc587ad99aef12fd7a166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 18:04:06 +0100 Subject: [PATCH 47/67] GPIO: do not overwrite interrupt handler (#2486) * Prefer defmt unwrap * Auto-bind the GPIO interrupt handler * Changelog * Bind interrupt handler when initializing the hal * Remove user handler overhead unless user handler is bound * Add tests * Try to preserve direct-bound handlers * Fix match * Don't rely on the vector table to check direct binding * Fix comment --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio/mod.rs | 74 ++++++++++++-------- esp-hal/src/interrupt/riscv.rs | 24 +++++-- esp-hal/src/interrupt/xtensa.rs | 63 ++++++++++++++++- esp-hal/src/lib.rs | 2 + hil-test/Cargo.toml | 4 ++ hil-test/tests/gpio_custom_handler.rs | 99 +++++++++++++++++++++++++++ 7 files changed, 231 insertions(+), 36 deletions(-) create mode 100644 hil-test/tests/gpio_custom_handler.rs diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 3f12da94ae0..06a7b6b40d8 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -97,6 +97,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `GpioEtmEventRising`, `GpioEtmEventFalling`, `GpioEtmEventAny` types have been replaced with `Event` (#2427) - The `TaskSet`, `TaskClear`, `TaskToggle` types have been replaced with `Task` (#2427) - `{Spi, SpiDma, SpiDmaBus}` configuration methods (#2448) +- `Io::new_with_priority` and `Io::new_no_bind_interrupt`. (#2486) ## [0.21.1] diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 4186dc4d719..672021f9df0 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -73,11 +73,12 @@ use procmacros::ram; pub use crate::soc::gpio::*; use crate::{ - interrupt::InterruptHandler, + interrupt::{self, InterruptHandler, Priority}, peripheral::{Peripheral, PeripheralRef}, - peripherals::{GPIO, IO_MUX}, + peripherals::{Interrupt, GPIO, IO_MUX}, private::{self, Sealed}, InterruptConfigurable, + DEFAULT_INTERRUPT_HANDLER, }; pub mod interconnect; @@ -784,6 +785,31 @@ where impl private::Sealed for GpioPin {} +pub(crate) fn bind_default_interrupt_handler() { + // We first check if a handler is set in the vector table. + if let Some(handler) = interrupt::bound_handler(Interrupt::GPIO) { + let handler = handler as *const unsafe extern "C" fn(); + + // We only allow binding the default handler if nothing else is bound. + // This prevents silently overwriting RTIC's interrupt handler, if using GPIO. + if !core::ptr::eq(handler, DEFAULT_INTERRUPT_HANDLER.handler() as _) { + // The user has configured an interrupt handler they wish to use. + info!("Not using default GPIO interrupt handler: already bound in vector table"); + return; + } + } + // The vector table doesn't contain a custom entry.Still, the + // peripheral interrupt may already be bound to something else. + if interrupt::bound_cpu_interrupt_for(crate::Cpu::current(), Interrupt::GPIO).is_some() { + info!("Not using default GPIO interrupt handler: peripheral interrupt already in use"); + return; + } + + unsafe { interrupt::bind_interrupt(Interrupt::GPIO, default_gpio_interrupt_handler) }; + // By default, we use lowest priority + unwrap!(interrupt::enable(Interrupt::GPIO, Priority::min())); +} + /// General Purpose Input/Output driver pub struct Io { _io_mux: IO_MUX, @@ -793,36 +819,17 @@ pub struct Io { impl Io { /// Initialize the I/O driver. - pub fn new(gpio: GPIO, io_mux: IO_MUX) -> Self { - Self::new_with_priority(gpio, io_mux, crate::interrupt::Priority::min()) - } - - /// Initialize the I/O driver with a interrupt priority. - /// - /// This decides the priority for the interrupt when using async. - pub fn new_with_priority( - mut gpio: GPIO, - io_mux: IO_MUX, - prio: crate::interrupt::Priority, - ) -> Self { - gpio.bind_gpio_interrupt(gpio_interrupt_handler); - crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, prio).unwrap(); - - Self::new_no_bind_interrupt(gpio, io_mux) - } - - /// Initialize the I/O driver without enabling the GPIO interrupt or - /// binding an interrupt handler to it. - /// - /// *Note:* You probably don't want to use this, it is intended to be used - /// in very specific use cases. Async GPIO functionality will not work - /// when instantiating `Io` using this constructor. - pub fn new_no_bind_interrupt(_gpio: GPIO, _io_mux: IO_MUX) -> Self { + pub fn new(_gpio: GPIO, _io_mux: IO_MUX) -> Self { Io { _io_mux, pins: unsafe { Pins::steal() }, } } + + /// Set the interrupt priority for GPIO interrupts. + pub fn set_interrupt_priority(&self, prio: Priority) { + unwrap!(interrupt::enable(Interrupt::GPIO, prio)); + } } impl crate::private::Sealed for Io {} @@ -840,15 +847,24 @@ impl InterruptConfigurable for Io { /// corresponding pin's async API. /// - You will not be notified if you make a mistake. fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - crate::interrupt::enable(crate::peripherals::Interrupt::GPIO, handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::GPIO); + } + self.set_interrupt_priority(handler.priority()); + unsafe { interrupt::bind_interrupt(Interrupt::GPIO, user_gpio_interrupt_handler) }; USER_INTERRUPT_HANDLER.store(handler.handler()); } } #[ram] -extern "C" fn gpio_interrupt_handler() { +extern "C" fn user_gpio_interrupt_handler() { USER_INTERRUPT_HANDLER.call(); + default_gpio_interrupt_handler(); +} + +#[ram] +extern "C" fn default_gpio_interrupt_handler() { handle_pin_interrupts(on_pin_irq); } diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index 151fa622471..de55b303e8f 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -346,7 +346,7 @@ unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option 0 { + if cpu_intr > 0 && cpu_intr != DISABLED_CPU_INTERRUPT { Some(core::mem::transmute::( cpu_intr - EXTERNAL_INTERRUPT_OFFSET, )) @@ -355,6 +355,10 @@ unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option Option { + unsafe { get_assigned_cpu_interrupt(interrupt) } +} + mod vectored { use procmacros::ram; @@ -423,17 +427,29 @@ mod vectored { Ok(()) } - /// Bind the given interrupt to the given handler + /// Binds the given interrupt to the given handler. /// /// # Safety /// /// This will replace any previously bound interrupt handler - pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) { + pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) { let ptr = &peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler as *const _ - as *mut unsafe extern "C" fn() -> (); + as *mut unsafe extern "C" fn(); ptr.write_volatile(handler); } + /// Returns the currently bound interrupt handler. + pub fn bound_handler(interrupt: Interrupt) -> Option { + unsafe { + let addr = peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler; + if addr as usize == 0 { + return None; + } + + Some(addr) + } + } + #[no_mangle] #[ram] unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 5ed4138c440..c83d1e75011 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -94,6 +94,32 @@ pub enum CpuInterrupt { Interrupt31EdgePriority5, } +impl CpuInterrupt { + fn from_u32(n: u32) -> Option { + if n < 32 { + Some(unsafe { core::mem::transmute::(n) }) + } else { + None + } + } + + fn is_internal(self) -> bool { + matches!( + self, + Self::Interrupt6Timer0Priority1 + | Self::Interrupt7SoftwarePriority1 + | Self::Interrupt11ProfilingPriority3 + | Self::Interrupt15Timer1Priority3 + | Self::Interrupt16Timer2Priority5 + | Self::Interrupt29SoftwarePriority3 + ) + } + + fn is_peripheral(self) -> bool { + !self.is_internal() + } +} + /// The interrupts reserved by the HAL #[cfg_attr(place_switch_tables_in_ram, link_section = ".rwtext")] pub static RESERVED_INTERRUPTS: &[usize] = &[ @@ -160,6 +186,25 @@ pub unsafe fn map(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { .write_volatile(cpu_interrupt_number as u32); } +/// Get cpu interrupt assigned to peripheral interrupt +pub(crate) fn bound_cpu_interrupt_for(cpu: Cpu, interrupt: Interrupt) -> Option { + let interrupt_number = interrupt as isize; + + let intr_map_base = match cpu { + Cpu::ProCpu => unsafe { (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr() }, + #[cfg(multi_core)] + Cpu::AppCpu => unsafe { (*core1_interrupt_peripheral()).app_mac_intr_map().as_ptr() }, + }; + let cpu_intr = unsafe { intr_map_base.offset(interrupt_number).read_volatile() }; + let cpu_intr = CpuInterrupt::from_u32(cpu_intr)?; + + if cpu_intr.is_peripheral() { + Some(cpu_intr) + } else { + None + } +} + /// Disable the given peripheral interrupt pub fn disable(core: Cpu, interrupt: Interrupt) { unsafe { @@ -415,17 +460,29 @@ mod vectored { Ok(()) } - /// Bind the given interrupt to the given handler + /// Binds the given interrupt to the given handler. /// /// # Safety /// /// This will replace any previously bound interrupt handler - pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) { + pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn()) { let ptr = &peripherals::__INTERRUPTS[interrupt as usize]._handler as *const _ - as *mut unsafe extern "C" fn() -> (); + as *mut unsafe extern "C" fn(); ptr.write_volatile(handler); } + /// Returns the currently bound interrupt handler. + pub fn bound_handler(interrupt: Interrupt) -> Option { + unsafe { + let addr = peripherals::__INTERRUPTS[interrupt as usize]._handler; + if addr as usize == 0 { + return None; + } + + Some(addr) + } + } + fn interrupt_level_to_cpu_interrupt( level: Priority, is_edge: bool, diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index aa8dda2a86c..f0c28132f68 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -560,5 +560,7 @@ pub fn init(config: Config) -> Peripherals { #[cfg(esp32)] crate::time::time_init(); + crate::gpio::bind_default_interrupt_handler(); + peripherals } diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 112d87941bb..0915ffed01e 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -55,6 +55,10 @@ harness = false name = "gpio" harness = false +[[test]] +name = "gpio_custom_handler" +harness = false + [[test]] name = "interrupt" harness = false diff --git a/hil-test/tests/gpio_custom_handler.rs b/hil-test/tests/gpio_custom_handler.rs new file mode 100644 index 00000000000..334c9f53101 --- /dev/null +++ b/hil-test/tests/gpio_custom_handler.rs @@ -0,0 +1,99 @@ +//! GPIO interrupt handler tests +//! +//! This test checks that during HAL initialization we do not overwrite custom +//! GPIO interrupt handlers. We also check that binding a custom interrupt +//! handler explicitly overwrites the handler set by the user, as well as the +//! async API works for user handlers automatically. + +//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 +//% FEATURES: integrated-timers + +#![no_std] +#![no_main] + +use embassy_time::{Duration, Timer}; +use esp_hal::{ + gpio::{AnyPin, Input, Io, Level, Output, Pull}, + macros::handler, + timer::timg::TimerGroup, + InterruptConfigurable, +}; +use hil_test as _; +use portable_atomic::{AtomicUsize, Ordering}; + +#[no_mangle] +unsafe extern "C" fn GPIO() { + // do nothing, prevents binding the default handler +} + +#[handler] +pub fn interrupt_handler() { + // Do nothing +} + +async fn drive_pins(gpio1: impl Into, gpio2: impl Into) -> usize { + let counter = AtomicUsize::new(0); + let mut test_gpio1 = Input::new(gpio1.into(), Pull::Down); + let mut test_gpio2 = Output::new(gpio2.into(), Level::Low); + embassy_futures::select::select( + async { + loop { + test_gpio1.wait_for_rising_edge().await; + counter.fetch_add(1, Ordering::SeqCst); + } + }, + async { + for _ in 0..5 { + test_gpio2.set_high(); + Timer::after(Duration::from_millis(25)).await; + test_gpio2.set_low(); + Timer::after(Duration::from_millis(25)).await; + } + }, + ) + .await; + + counter.load(Ordering::SeqCst) +} + +#[cfg(test)] +#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())] +mod tests { + + use super::*; + + #[test] + async fn default_handler_does_not_run_because_gpio_is_defined() { + let peripherals = esp_hal::init(esp_hal::Config::default()); + + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + + let (gpio1, gpio2) = hil_test::common_test_pins!(io); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + esp_hal_embassy::init(timg0.timer0); + + let counter = drive_pins(gpio1, gpio2).await; + + // GPIO is bound to something else, so we don't expect the async API to work. + assert_eq!(counter, 0); + } + + #[test] + async fn default_handler_runs_because_handler_is_set() { + let peripherals = esp_hal::init(esp_hal::Config::default()); + + let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + io.set_interrupt_handler(interrupt_handler); + + let (gpio1, gpio2) = hil_test::common_test_pins!(io); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + esp_hal_embassy::init(timg0.timer0); + + let counter = drive_pins(gpio1, gpio2).await; + + // We expect the async API to keep working even if a user handler is set. + assert_eq!(counter, 5); + } +} From 2c14e595dbc853b23a085a48aff7105eaef71652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 8 Nov 2024 23:51:42 +0100 Subject: [PATCH 48/67] I2C: add `apply_config`, implement `SetConfig`, add `with_sda` and `with_scl` (#2477) * Implement apply_config, SetConfig * Remove pins from constructors * Implement timeout changes, document them * Fix up changelog --- esp-hal/CHANGELOG.md | 5 +- esp-hal/MIGRATING-0.21.md | 33 ++- esp-hal/src/i2c/master/mod.rs | 195 ++++++++++-------- examples/src/bin/embassy_i2c.rs | 16 +- .../embassy_i2c_bmp180_calibration_data.rs | 16 +- .../src/bin/i2c_bmp180_calibration_data.rs | 10 +- examples/src/bin/i2c_display.rs | 11 +- examples/src/bin/lcd_cam_ov2640.rs | 9 +- hil-test/tests/i2c.rs | 7 +- 9 files changed, 195 insertions(+), 107 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 06a7b6b40d8..224d81239b0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -33,9 +33,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `{Uart, UartRx, UartTx}` now implement `embassy_embedded_hal::SetConfig` (#2449) - GPIO ETM tasks and events now accept `InputSignal` and `OutputSignal` (#2427) - `spi::master::Config` and `{Spi, SpiDma, SpiDmaBus}::apply_config` (#2448) -- `embassy_embedded_hal::SetConfig` is now implemented for `{Spi, SpiDma, SpiDmaBus}` (#2448) +- `embassy_embedded_hal::SetConfig` is now implemented for `spi::master::{Spi, SpiDma, SpiDmaBus}`, `i2c::master::I2c` (#2448, #2477) - `slave::Spi::{with_mosi(), with_miso(), with_sclk(), with_cs()}` functions (#2485) - I8080: Added `set_8bits_order()` to set the byte order in 8-bit mode (#2487) +- `I2c::{apply_config(), with_sda(), with_scl()}` (#2477) ### Changed @@ -59,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The I2S driver has been moved to `i2s::master` (#2472) - `slave::Spi` constructors no longer take pins (#2485) - The `I2c` master driver has been moved from `esp_hal::i2c` to `esp_hal::i2c::master`. (#2476) +- `I2c` SCL timeout is now defined in bus clock cycles. (#2477) ### Fixed @@ -75,6 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `i2s::{I2sWrite, I2sWriteDma, I2sRead, I2sReadDma, I2sWriteDmaAsync, I2sReadDmaAsync}` traits have been removed. (#2316) - The `ledc::ChannelHW` trait is no longer generic. (#2387) - The `I2c::new_with_timeout` constructors have been removed (#2361) +- `I2c::new()` no longer takes `frequency` and pins as parameters. (#2477) - The `spi::master::HalfDuplexReadWrite` trait has been removed. (#2373) - The `Spi::with_pins` methods have been removed. (#2373) - The `Spi::new_half_duplex` constructor have been removed. (#2373) diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index ca14b32d0e7..57460bd8037 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -69,13 +69,42 @@ let spi: Spi<'static, FullDuplexMode, SPI2> = Spi::new_typed(peripherals.SPI2, 1 The I2C master driver and related types have been moved to `esp_hal::i2c::master`. -The `with_timeout` constructors have been removed in favour of `set_timeout` or `with_timeout`. +The `with_timeout` constructors have been removed. `new` and `new_typed` now take a `Config` struct +with the available configuration options. + +- The default configuration is now: + - bus frequency: 100 kHz + - timeout: about 10 bus clock cycles + +The constructors no longer take pins. Use `with_sda` and `with_scl` instead. ```diff +-use esp_hal::i2c::I2c; ++use esp_hal::i2c::{Config, I2c}; -let i2c = I2c::new_with_timeout(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz(), timeout); -+let i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz()).with_timeout(timeout); ++I2c::new_with_config( ++ peripherals.I2C0, ++ { ++ let mut config = Config::default(); ++ config.frequency = 100.kHz(); ++ config.timeout = timeout; ++ config ++ }, ++) ++.with_sda(io.pins.gpio4) ++.with_scl(io.pins.gpio5); ``` +### The calculation of I2C timeout has changed + +Previously, I2C timeouts were counted in increments of I2C peripheral clock cycles. This meant that +the configure value meant different lengths of time depending on the device. With this update, the +I2C configuration now expects the timeout value in number of bus clock cycles, which is consistent +between devices. + +ESP32 and ESP32-S2 use an exact number of clock cycles for its timeout. Other MCUs, however, use +the `2^timeout` value internally, and the HAL rounds up the timeout to the next appropriate value. + ## Changes to half-duplex SPI The `HalfDuplexMode` and `FullDuplexMode` type parameters have been removed from SPI master and slave diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 036e2099d63..01135959dbe 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -18,7 +18,7 @@ //! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::i2c::master::I2c; +//! # use esp_hal::i2c::master::{Config, I2c}; //! # use esp_hal::gpio::Io; //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! @@ -26,10 +26,10 @@ //! // and standard I2C clock speed. //! let mut i2c = I2c::new( //! peripherals.I2C0, -//! io.pins.gpio1, -//! io.pins.gpio2, -//! 100.kHz(), -//! ); +//! Config::default(), +//! ) +//! .with_sda(io.pins.gpio1) +//! .with_scl(io.pins.gpio2); //! //! loop { //! let mut data = [0u8; 22]; @@ -46,6 +46,7 @@ use core::{ task::{Context, Poll}, }; +use embassy_embedded_hal::SetConfig; use embassy_sync::waitqueue::AtomicWaker; use embedded_hal::i2c::Operation as EhalOperation; use fugit::HertzU32; @@ -106,6 +107,11 @@ pub enum Error { InvalidZeroLength, } +/// I2C-specific configuration errors +#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ConfigError {} + #[derive(PartialEq)] // This enum is used to keep track of the last/next operation that was/will be // performed in an embedded-hal(-async) I2c::transaction. It is used to @@ -230,12 +236,54 @@ impl From for u32 { } } +/// I2C driver configuration +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Config { + /// The I2C clock frequency. + pub frequency: HertzU32, + + /// I2C SCL timeout period. + /// + /// When the level of SCL remains unchanged for more than `timeout` bus + /// clock cycles, the bus goes to idle state. + /// + /// The default value is about 10 bus clock cycles. + #[doc = ""] + #[cfg_attr( + not(esp32), + doc = "Note that the effective timeout may be longer than the value configured here." + )] + #[cfg_attr(not(esp32), doc = "Configuring `None` disables timeout control.")] + #[cfg_attr(esp32, doc = "Configuring `None` equals to the maximum timeout value.")] + // TODO: when supporting interrupts, document that SCL = high also triggers an interrupt. + pub timeout: Option, +} + +impl Default for Config { + fn default() -> Self { + use fugit::RateExtU32; + Config { + frequency: 100.kHz(), + timeout: Some(10), + } + } +} + /// I2C driver pub struct I2c<'d, DM: Mode, T = AnyI2c> { i2c: PeripheralRef<'d, T>, phantom: PhantomData, - frequency: HertzU32, - timeout: Option, + config: Config, +} + +impl SetConfig for I2c<'_, DM, T> { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.apply_config(config) + } } impl embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T> @@ -297,31 +345,6 @@ impl<'d, T, DM: Mode> I2c<'d, DM, T> where T: Instance, { - fn new_internal( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - crate::into_ref!(i2c); - crate::into_mapped_ref!(sda, scl); - - let i2c = I2c { - i2c, - phantom: PhantomData, - frequency, - timeout: None, - }; - - PeripheralClockControl::reset(i2c.info().peripheral); - PeripheralClockControl::enable(i2c.info().peripheral); - - let i2c = i2c.with_sda(sda).with_scl(scl); - - i2c.info().setup(frequency, None); - i2c - } - fn info(&self) -> &Info { self.i2c.info() } @@ -330,16 +353,15 @@ where PeripheralClockControl::reset(self.info().peripheral); PeripheralClockControl::enable(self.info().peripheral); - self.info().setup(self.frequency, self.timeout); + // We know the configuration is valid, we can ignore the result. + _ = self.info().setup(&self.config); } - /// Set the I2C timeout. - // TODO: explain this function better - what's the unit, what happens on - // timeout, and just what exactly is a timeout in this context? - pub fn with_timeout(mut self, timeout: Option) -> Self { - self.timeout = timeout; - self.info().setup(self.frequency, self.timeout); - self + /// Applies a new configuration. + pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> { + self.info().setup(config)?; + self.config = *config; + Ok(()) } fn transaction_impl<'a>( @@ -399,14 +421,16 @@ where Ok(()) } - fn with_sda(self, sda: impl Peripheral

+ 'd) -> Self { + /// Connect a pin to the I2C SDA signal. + pub fn with_sda(self, sda: impl Peripheral

+ 'd) -> Self { let info = self.info(); let input = info.sda_input; let output = info.sda_output; self.with_pin(sda, input, output) } - fn with_scl(self, scl: impl Peripheral

+ 'd) -> Self { + /// Connect a pin to the I2C SCL signal. + pub fn with_scl(self, scl: impl Peripheral

+ 'd) -> Self { let info = self.info(); let input = info.scl_input; let output = info.scl_output; @@ -438,13 +462,8 @@ impl<'d> I2c<'d, Blocking> { /// Create a new I2C instance /// This will enable the peripheral but the peripheral won't get /// automatically disabled when this gets dropped. - pub fn new( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_typed(i2c.map_into(), sda, scl, frequency) + pub fn new(i2c: impl Peripheral

+ 'd, config: Config) -> Self { + Self::new_typed(i2c.map_into(), config) } } @@ -455,13 +474,20 @@ where /// Create a new I2C instance /// This will enable the peripheral but the peripheral won't get /// automatically disabled when this gets dropped. - pub fn new_typed( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_internal(i2c, sda, scl, frequency) + pub fn new_typed(i2c: impl Peripheral

+ 'd, config: Config) -> Self { + crate::into_ref!(i2c); + + let i2c = I2c { + i2c, + phantom: PhantomData, + config, + }; + + PeripheralClockControl::reset(i2c.info().peripheral); + PeripheralClockControl::enable(i2c.info().peripheral); + + unwrap!(i2c.info().setup(&i2c.config)); + i2c } // TODO: missing interrupt APIs @@ -473,8 +499,7 @@ where I2c { i2c: self.i2c, phantom: PhantomData, - frequency: self.frequency, - timeout: self.timeout, + config: self.config, } } @@ -743,8 +768,7 @@ where I2c { i2c: self.i2c, phantom: PhantomData, - frequency: self.frequency, - timeout: self.timeout, + config: self.config, } } @@ -1216,8 +1240,7 @@ fn configure_clock( scl_stop_setup_time: u32, scl_start_hold_time: u32, scl_stop_hold_time: u32, - time_out_value: u32, - time_out_en: bool, + timeout: Option, ) { unsafe { // divider @@ -1267,19 +1290,15 @@ fn configure_clock( // timeout mechanism cfg_if::cfg_if! { if #[cfg(esp32)] { - // timeout register_block .to() - .write(|w| w.time_out().bits(time_out_value)); + .write(|w| w.time_out().bits(unwrap!(timeout))); } else { - // timeout - // FIXME: Enable timout for other chips! - #[allow(clippy::useless_conversion)] register_block .to() - .write(|w| w.time_out_en().bit(time_out_en) + .write(|w| w.time_out_en().bit(timeout.is_some()) .time_out_value() - .bits(time_out_value.try_into().unwrap()) + .bits(timeout.unwrap_or(1) as _) ); } } @@ -1324,7 +1343,7 @@ impl Info { /// Configures the I2C peripheral with the specified frequency, clocks, and /// optional timeout. - fn setup(&self, frequency: HertzU32, timeout: Option) { + fn setup(&self, config: &Config) -> Result<(), ConfigError> { self.register_block().ctr().write(|w| { // Set I2C controller to master mode w.ms_mode().set_bit(); @@ -1358,12 +1377,14 @@ impl Info { let clock = clocks.xtal_clock.convert(); } } - self.set_frequency(clock, frequency, timeout); + self.set_frequency(clock, config.frequency, config.timeout); self.update_config(); // Reset entire peripheral (also resets fifo) self.reset(); + + Ok(()) } /// Resets the I2C controller (FIFO + FSM + command list) @@ -1411,8 +1432,9 @@ impl Info { let sda_sample = scl_high / 2; let setup = half_cycle; let hold = half_cycle; - // default we set the timeout value to 10 bus cycles - let time_out_value = timeout.unwrap_or(half_cycle * 20); + let timeout = timeout.map_or(Some(0xF_FFFF), |to_bus| { + Some((to_bus * 2 * half_cycle).min(0xF_FFFF)) + }); // SCL period. According to the TRM, we should always subtract 1 to SCL low // period @@ -1465,8 +1487,7 @@ impl Info { scl_stop_setup_time, scl_start_hold_time, scl_stop_hold_time, - time_out_value, - true, + timeout, ); } @@ -1489,8 +1510,6 @@ impl Info { let sda_sample = half_cycle / 2 - 1; let setup = half_cycle; let hold = half_cycle; - // default we set the timeout value to 10 bus cycles - let time_out_value = timeout.unwrap_or(half_cycle * 20); // scl period let scl_low_period = scl_low - 1; @@ -1505,7 +1524,6 @@ impl Info { // hold let scl_start_hold_time = hold - 1; let scl_stop_hold_time = hold; - let time_out_en = true; configure_clock( self.register_block(), @@ -1519,8 +1537,7 @@ impl Info { scl_stop_setup_time, scl_start_hold_time, scl_stop_hold_time, - time_out_value, - time_out_en, + timeout.map(|to_bus| (to_bus * 2 * half_cycle).min(0xFF_FFFF)), ); } @@ -1552,14 +1569,6 @@ impl Info { let setup = half_cycle; let hold = half_cycle; - let time_out_value = if let Some(timeout) = timeout { - timeout - } else { - // default we set the timeout value to about 10 bus cycles - // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) - (4 * 8 - (5 * half_cycle).leading_zeros()) + 2 - }; - // According to the Technical Reference Manual, the following timings must be // subtracted by 1. However, according to the practical measurement and // some hardware behaviour, if wait_high_period and scl_high minus one. @@ -1579,7 +1588,6 @@ impl Info { // hold let scl_start_hold_time = hold - 1; let scl_stop_hold_time = hold - 1; - let time_out_en = true; configure_clock( self.register_block(), @@ -1593,8 +1601,13 @@ impl Info { scl_stop_setup_time, scl_start_hold_time, scl_stop_hold_time, - time_out_value, - time_out_en, + timeout.map(|to_bus| { + let to_peri = (to_bus * 2 * half_cycle).max(1); + let log2 = to_peri.ilog2(); + // Round up so that we don't shorten timeouts. + let raw = if to_peri != 1 << log2 { log2 + 1 } else { log2 }; + raw.min(0x1F) + }), ); } diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index 0f757be363e..64c046695a7 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -19,7 +19,12 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*, timer::timg::TimerGroup}; +use esp_hal::{ + gpio::Io, + i2c::master::{Config, I2c}, + prelude::*, + timer::timg::TimerGroup, +}; use lis3dh_async::{Lis3dh, Range, SlaveAddr}; #[esp_hal_embassy::main] @@ -31,7 +36,14 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let i2c0 = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async(); + let i2c0 = I2c::new(peripherals.I2C0, { + let mut config = Config::default(); + config.frequency = 400.kHz(); + config + }) + .with_sda(io.pins.gpio4) + .with_scl(io.pins.gpio5) + .into_async(); let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap(); lis3dh.set_range(Range::G8).await.unwrap(); diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 14c1a3f52b8..204f9e61f38 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -20,7 +20,12 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*, timer::timg::TimerGroup}; +use esp_hal::{ + gpio::Io, + i2c::master::{Config, I2c}, + prelude::*, + timer::timg::TimerGroup, +}; #[esp_hal_embassy::main] async fn main(_spawner: Spawner) { @@ -31,7 +36,14 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async(); + let mut i2c = I2c::new(peripherals.I2C0, { + let mut config = Config::default(); + config.frequency = 400.kHz(); + config + }) + .with_sda(io.pins.gpio4) + .with_scl(io.pins.gpio5) + .into_async(); loop { let mut data = [0u8; 22]; diff --git a/examples/src/bin/i2c_bmp180_calibration_data.rs b/examples/src/bin/i2c_bmp180_calibration_data.rs index 88fc52fa0aa..7d75aa73adc 100644 --- a/examples/src/bin/i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/i2c_bmp180_calibration_data.rs @@ -12,7 +12,11 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{gpio::Io, i2c::master::I2c, prelude::*}; +use esp_hal::{ + gpio::Io, + i2c::master::{Config, I2c}, + prelude::*, +}; use esp_println::println; #[entry] @@ -23,7 +27,9 @@ fn main() -> ! { // Create a new peripheral object with the described wiring and standard // I2C clock speed: - let mut i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz()); + let mut i2c = I2c::new(peripherals.I2C0, Config::default()) + .with_sda(io.pins.gpio4) + .with_scl(io.pins.gpio5); loop { let mut data = [0u8; 22]; diff --git a/examples/src/bin/i2c_display.rs b/examples/src/bin/i2c_display.rs index bb1270dc468..cf17fa0a02e 100644 --- a/examples/src/bin/i2c_display.rs +++ b/examples/src/bin/i2c_display.rs @@ -22,7 +22,12 @@ use embedded_graphics::{ text::{Alignment, Text}, }; use esp_backtrace as _; -use esp_hal::{delay::Delay, gpio::Io, i2c::master::I2c, prelude::*}; +use esp_hal::{ + delay::Delay, + gpio::Io, + i2c::master::{Config, I2c}, + prelude::*, +}; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; #[entry] @@ -34,7 +39,9 @@ fn main() -> ! { // Create a new peripheral object with the described wiring // and standard I2C clock speed - let i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz()); + let i2c = I2c::new(peripherals.I2C0, Config::default()) + .with_sda(io.pins.gpio4) + .with_scl(io.pins.gpio5); // Initialize display let interface = I2CDisplayInterface::new(i2c); diff --git a/examples/src/bin/lcd_cam_ov2640.rs b/examples/src/bin/lcd_cam_ov2640.rs index 03290740bcd..6b9198f97bf 100644 --- a/examples/src/bin/lcd_cam_ov2640.rs +++ b/examples/src/bin/lcd_cam_ov2640.rs @@ -29,7 +29,10 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_rx_stream_buffer, gpio::Io, - i2c::{self, master::I2c}, + i2c::{ + self, + master::{Config, I2c}, + }, lcd_cam::{ cam::{Camera, RxEightBits}, LcdCam, @@ -79,7 +82,9 @@ fn main() -> ! { delay.delay_millis(500u32); - let i2c = I2c::new(peripherals.I2C0, cam_siod, cam_sioc, 100u32.kHz()); + let i2c = I2c::new(peripherals.I2C0, Config::default()) + .with_sda(cam_siod) + .with_scl(cam_sioc); let mut sccb = Sccb::new(i2c); diff --git a/hil-test/tests/i2c.rs b/hil-test/tests/i2c.rs index 2106897f071..09718abf151 100644 --- a/hil-test/tests/i2c.rs +++ b/hil-test/tests/i2c.rs @@ -7,8 +7,7 @@ use esp_hal::{ gpio::Io, - i2c::master::{I2c, Operation}, - prelude::*, + i2c::master::{Config, I2c, Operation}, Async, Blocking, }; @@ -40,7 +39,9 @@ mod tests { // Create a new peripheral object with the described wiring and standard // I2C clock speed: - let i2c = I2c::new(peripherals.I2C0, sda, scl, 100.kHz()); + let i2c = I2c::new(peripherals.I2C0, Config::default()) + .with_sda(sda) + .with_scl(scl); Context { i2c } } From 4af44b14986b8b7d99969c436d3265e61654e06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 11 Nov 2024 16:43:07 +0100 Subject: [PATCH 49/67] Introduce Driver and move implementation into it (#2480) --- esp-hal/src/i2c/master/mod.rs | 350 ++++++++++++++++++---------------- 1 file changed, 187 insertions(+), 163 deletions(-) diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 01135959dbe..494a085f629 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -345,21 +345,24 @@ impl<'d, T, DM: Mode> I2c<'d, DM, T> where T: Instance, { - fn info(&self) -> &Info { - self.i2c.info() + fn driver(&self) -> Driver<'_> { + Driver { + info: self.i2c.info(), + state: self.i2c.state(), + } } fn internal_recover(&self) { - PeripheralClockControl::reset(self.info().peripheral); - PeripheralClockControl::enable(self.info().peripheral); + PeripheralClockControl::reset(self.driver().info.peripheral); + PeripheralClockControl::enable(self.driver().info.peripheral); // We know the configuration is valid, we can ignore the result. - _ = self.info().setup(&self.config); + _ = self.driver().setup(&self.config); } /// Applies a new configuration. pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> { - self.info().setup(config)?; + self.driver().setup(config)?; self.config = *config; Ok(()) } @@ -369,6 +372,7 @@ where address: u8, operations: impl Iterator>, ) -> Result<(), Error> { + let driver = self.driver(); let mut last_op: Option = None; // filter out 0 length read operations let mut op_iter = operations @@ -379,15 +383,15 @@ where let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one - self.info() + driver .write_operation( address, buffer, @@ -402,7 +406,7 @@ where // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one // - will_continue is true if there is another read operation next - self.info() + driver .read_operation( address, buffer, @@ -423,7 +427,7 @@ where /// Connect a pin to the I2C SDA signal. pub fn with_sda(self, sda: impl Peripheral

+ 'd) -> Self { - let info = self.info(); + let info = self.driver().info; let input = info.sda_input; let output = info.sda_output; self.with_pin(sda, input, output) @@ -431,7 +435,7 @@ where /// Connect a pin to the I2C SCL signal. pub fn with_scl(self, scl: impl Peripheral

+ 'd) -> Self { - let info = self.info(); + let info = self.driver().info; let input = info.scl_input; let output = info.scl_output; self.with_pin(scl, input, output) @@ -483,10 +487,10 @@ where config, }; - PeripheralClockControl::reset(i2c.info().peripheral); - PeripheralClockControl::enable(i2c.info().peripheral); + PeripheralClockControl::reset(i2c.driver().info.peripheral); + PeripheralClockControl::enable(i2c.driver().info.peripheral); - unwrap!(i2c.info().setup(&i2c.config)); + unwrap!(i2c.driver().setup(&i2c.config)); i2c } @@ -494,7 +498,7 @@ where /// Configures the I2C peripheral to operate in asynchronous mode. pub fn into_async(mut self) -> I2c<'d, Async, T> { - self.set_interrupt_handler(self.info().async_handler); + self.set_interrupt_handler(self.driver().info.async_handler); I2c { i2c: self.i2c, @@ -505,14 +509,15 @@ where /// Reads enough bytes from slave with `address` to fill `buffer` pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + let driver = self.driver(); let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); - self.info() + driver .read_operation( address, chunk, @@ -529,14 +534,15 @@ where /// Writes bytes to slave with address `address` pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + let driver = self.driver(); let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); - self.info() + driver .write_operation( address, chunk, @@ -558,16 +564,17 @@ where write_buffer: &[u8], read_buffer: &mut [u8], ) -> Result<(), Error> { + let driver = self.driver(); let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); - self.info() + self.driver() .write_operation( address, chunk, @@ -580,11 +587,11 @@ where for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); - self.info() + self.driver() .read_operation( address, chunk, @@ -633,7 +640,7 @@ where T: Instance, { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - let interrupt = self.info().interrupt; + let interrupt = self.driver().info.interrupt; for core in Cpu::other() { crate::interrupt::disable(core, interrupt); } @@ -660,8 +667,8 @@ struct I2cFuture<'a> { #[cfg(not(esp32))] impl<'a> I2cFuture<'a> { - pub fn new(event: Event, instance: &'a impl Instance) -> Self { - instance.info().register_block().int_ena().modify(|_, w| { + pub fn new(event: Event, info: &'a Info, state: &'a State) -> Self { + info.register_block().int_ena().modify(|_, w| { let w = match event { Event::EndDetect => w.end_detect().set_bit(), Event::TxComplete => w.trans_complete().set_bit(), @@ -680,11 +687,7 @@ impl<'a> I2cFuture<'a> { w }); - Self { - event, - state: instance.state(), - info: instance.info(), - } + Self { event, state, info } } fn event_bit_is_clear(&self) -> bool { @@ -763,7 +766,7 @@ where { /// Configure the I2C peripheral to operate in blocking mode. pub fn into_blocking(self) -> I2c<'d, Blocking, T> { - crate::interrupt::disable(Cpu::current(), self.info().interrupt); + crate::interrupt::disable(Cpu::current(), self.driver().info.interrupt); I2c { i2c: self.i2c, @@ -778,10 +781,10 @@ where panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); } - self.wait_for_completion(false).await?; + self.driver().wait_for_completion(false).await?; for byte in buffer.iter_mut() { - *byte = read_fifo(self.info().register_block()); + *byte = read_fifo(self.driver().register_block()); } Ok(()) @@ -789,99 +792,7 @@ where #[cfg(not(any(esp32, esp32s2)))] async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - self.info().read_all_from_fifo(buffer) - } - - #[cfg(any(esp32, esp32s2))] - async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { - if start_index >= bytes.len() { - return Ok(()); - } - - for b in bytes { - write_fifo(self.info().register_block(), *b); - self.info().check_errors()?; - } - - Ok(()) - } - - #[cfg(not(any(esp32, esp32s2)))] - async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { - let mut index = start_index; - loop { - self.info().check_errors()?; - - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - - self.info() - .register_block() - .int_clr() - .write(|w| w.txfifo_wm().clear_bit_by_one()); - - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - - if index >= bytes.len() { - break Ok(()); - } - - write_fifo(self.info().register_block(), bytes[index]); - index += 1; - } - } - - #[cfg(not(esp32))] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - self.info().check_errors()?; - - if end_only { - I2cFuture::new(Event::EndDetect, &*self.i2c).await?; - } else { - let res = embassy_futures::select::select( - I2cFuture::new(Event::TxComplete, &*self.i2c), - I2cFuture::new(Event::EndDetect, &*self.i2c), - ) - .await; - - match res { - embassy_futures::select::Either::First(res) => res?, - embassy_futures::select::Either::Second(res) => res?, - } - } - self.info().check_all_commands_done()?; - - Ok(()) - } - - #[cfg(esp32)] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - // for ESP32 we need a timeout here but wasting a timer seems unnecessary - // given the short time we spend here - - let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop - loop { - let interrupts = self.info().register_block().int_raw().read(); - - self.info().check_errors()?; - - // Handle completion cases - // A full transmission was completed (either a STOP condition or END was - // processed) - if (!end_only && interrupts.trans_complete().bit_is_set()) - || interrupts.end_detect().bit_is_set() - { - break; - } - - tout -= 1; - if tout == 0 { - return Err(Error::TimeOut); - } - - embassy_futures::yield_now().await; - } - self.info().check_all_commands_done()?; - Ok(()) + self.driver().read_all_from_fifo(buffer) } /// Executes an async I2C write operation. @@ -910,24 +821,23 @@ where } // Reset FIFO and command list - self.info().reset_fifo(); - self.info().reset_command_list(); + self.driver().reset_fifo(); + self.driver().reset_command_list(); if start { add_cmd(cmd_iterator, Command::Start)?; } - self.i2c - .info() + self.driver() .setup_write(address, bytes, start, cmd_iterator)?; add_cmd( cmd_iterator, if stop { Command::Stop } else { Command::End }, )?; - let index = self.info().fill_tx_fifo(bytes); - self.info().start_transmission(); + let index = self.driver().fill_tx_fifo(bytes); + self.driver().start_transmission(); // Fill the FIFO with the remaining bytes: - self.write_remaining_tx_fifo(index, bytes).await?; - self.wait_for_completion(!stop).await?; + self.driver().write_remaining_tx_fifo(index, bytes).await?; + self.driver().wait_for_completion(!stop).await?; Ok(()) } @@ -960,32 +870,32 @@ where } // Reset FIFO and command list - self.info().reset_fifo(); - self.info().reset_command_list(); + self.driver().reset_fifo(); + self.driver().reset_command_list(); if start { add_cmd(cmd_iterator, Command::Start)?; } - self.i2c - .info() + self.driver() .setup_read(address, buffer, start, will_continue, cmd_iterator)?; add_cmd( cmd_iterator, if stop { Command::Stop } else { Command::End }, )?; - self.info().start_transmission(); + self.driver().start_transmission(); self.read_all_from_fifo(buffer).await?; - self.wait_for_completion(!stop).await?; + self.driver().wait_for_completion(!stop).await?; Ok(()) } /// Writes bytes to slave with address `address` pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + let driver = self.driver(); let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); self.write_operation( address, @@ -1002,12 +912,13 @@ where /// Reads enough bytes from slave with `address` to fill `buffer` pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + let driver = self.driver(); let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); self.read_operation( address, @@ -1031,13 +942,14 @@ where write_buffer: &[u8], read_buffer: &mut [u8], ) -> Result<(), Error> { + let driver = self.driver(); let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); self.write_operation( address, @@ -1051,9 +963,9 @@ where for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); self.read_operation( address, @@ -1102,6 +1014,7 @@ where address: u8, operations: impl Iterator>, ) -> Result<(), Error> { + let driver = self.driver(); let mut last_op: Option = None; // filter out 0 length read operations let mut op_iter = operations @@ -1112,9 +1025,9 @@ where let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); // Clear all I2C interrupts - self.info().clear_all_interrupts(); + driver.clear_all_interrupts(); - let cmd_iterator = &mut self.info().register_block().comd_iter(); + let cmd_iterator = &mut driver.register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: @@ -1340,6 +1253,18 @@ impl Info { pub fn register_block(&self) -> &RegisterBlock { unsafe { &*self.register_block } } +} + +#[allow(dead_code)] // Some versions don't need `state` +struct Driver<'a> { + info: &'a Info, + state: &'a State, +} + +impl Driver<'_> { + fn register_block(&self) -> &RegisterBlock { + self.info.register_block() + } /// Configures the I2C peripheral with the specified frequency, clocks, and /// optional timeout. @@ -1773,7 +1698,7 @@ impl Info { // wait for completion - then we can just read the data from FIFO // once we change to non-fifo mode to support larger transfers that // won't work anymore - self.wait_for_completion(false)?; + self.wait_for_completion_blocking(false)?; // Read bytes from FIFO // FIXME: Handle case where less data has been provided by the slave than @@ -1792,8 +1717,99 @@ impl Info { .write(|w| unsafe { w.bits(I2C_LL_INTR_MASK) }); } + #[cfg(any(esp32, esp32s2))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + if start_index >= bytes.len() { + return Ok(()); + } + + for b in bytes { + write_fifo(self.register_block(), *b); + self.check_errors()?; + } + + Ok(()) + } + + #[cfg(not(any(esp32, esp32s2)))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + let mut index = start_index; + loop { + self.check_errors()?; + + I2cFuture::new(Event::TxFifoWatermark, self.info, self.state).await?; + + self.register_block() + .int_clr() + .write(|w| w.txfifo_wm().clear_bit_by_one()); + + I2cFuture::new(Event::TxFifoWatermark, self.info, self.state).await?; + + if index >= bytes.len() { + break Ok(()); + } + + write_fifo(self.register_block(), bytes[index]); + index += 1; + } + } + + #[cfg(not(esp32))] + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + self.check_errors()?; + + if end_only { + I2cFuture::new(Event::EndDetect, self.info, self.state).await?; + } else { + let res = embassy_futures::select::select( + I2cFuture::new(Event::TxComplete, self.info, self.state), + I2cFuture::new(Event::EndDetect, self.info, self.state), + ) + .await; + + match res { + embassy_futures::select::Either::First(res) => res?, + embassy_futures::select::Either::Second(res) => res?, + } + } + self.check_all_commands_done()?; + + Ok(()) + } + + #[cfg(esp32)] + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + // for ESP32 we need a timeout here but wasting a timer seems unnecessary + // given the short time we spend here + + let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop + loop { + let interrupts = self.register_block().int_raw().read(); + + self.check_errors()?; + + // Handle completion cases + // A full transmission was completed (either a STOP condition or END was + // processed) + if (!end_only && interrupts.trans_complete().bit_is_set()) + || interrupts.end_detect().bit_is_set() + { + break; + } + + tout -= 1; + if tout == 0 { + return Err(Error::TimeOut); + } + + embassy_futures::yield_now().await; + } + self.check_all_commands_done()?; + Ok(()) + } + /// Waits for the completion of an I2C transaction. - fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + fn wait_for_completion_blocking(&self, end_only: bool) -> Result<(), Error> { let mut tout = MAX_ITERATIONS; loop { let interrupts = self.register_block().int_raw().read(); @@ -1940,7 +1956,11 @@ impl Info { #[cfg(not(any(esp32, esp32s2)))] /// Writes remaining data from byte slice to the TX FIFO from the specified /// index. - fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + fn write_remaining_tx_fifo_blocking( + &self, + start_index: usize, + bytes: &[u8], + ) -> Result<(), Error> { let mut index = start_index; loop { self.check_errors()?; @@ -1999,7 +2019,11 @@ impl Info { #[cfg(any(esp32, esp32s2))] /// Writes remaining data from byte slice to the TX FIFO from the specified /// index. - fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + fn write_remaining_tx_fifo_blocking( + &self, + start_index: usize, + bytes: &[u8], + ) -> Result<(), Error> { // on ESP32/ESP32-S2 we currently don't support I2C transactions larger than the // FIFO apparently it would be possible by using non-fifo mode // see https://github.com/espressif/arduino-esp32/blob/7e9afe8c5ed7b5bf29624a5cd6e07d431c027b97/cores/esp32/esp32-hal-i2c.c#L615 @@ -2107,8 +2131,8 @@ impl Info { self.start_transmission(); // Fill the FIFO with the remaining bytes: - self.write_remaining_tx_fifo(index, bytes)?; - self.wait_for_completion(!stop)?; + self.write_remaining_tx_fifo_blocking(index, bytes)?; + self.wait_for_completion_blocking(!stop)?; Ok(()) } @@ -2156,7 +2180,7 @@ impl Info { )?; self.start_transmission(); self.read_all_from_fifo(buffer)?; - self.wait_for_completion(!stop)?; + self.wait_for_completion_blocking(!stop)?; Ok(()) } } From 33659380ddcd9030ae6ba8013c6f51e4d2476c46 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 11 Nov 2024 13:27:50 -0800 Subject: [PATCH 50/67] Update revision of PACs and fix all build errors (#2515) --- esp-hal/Cargo.toml | 14 ++++++------- esp-hal/src/aes/esp32.rs | 2 +- esp-hal/src/aes/esp32cX.rs | 4 ++-- esp-hal/src/aes/esp32s2.rs | 4 ++-- esp-hal/src/aes/esp32s3.rs | 4 ++-- esp-hal/src/clock/clocks_ll/esp32c6.rs | 2 +- esp-hal/src/dma/gdma.rs | 6 +++--- esp-hal/src/dma/pdma.rs | 16 +++++++-------- esp-hal/src/i2c/master/mod.rs | 10 ++-------- esp-hal/src/interrupt/software.rs | 4 ++-- esp-hal/src/mcpwm/operator.rs | 12 ++++++------ esp-hal/src/rsa/esp32cX.rs | 6 +++--- esp-hal/src/rsa/esp32sX.rs | 6 +++--- esp-hal/src/rtc_cntl/mod.rs | 8 ++++---- esp-hal/src/rtc_cntl/rtc/esp32c6.rs | 27 ++++++++++++++------------ esp-hal/src/rtc_cntl/rtc/esp32h2.rs | 23 ++++++++++++---------- esp-hal/src/soc/esp32c6/lp_core.rs | 4 ++-- esp-hal/src/soc/esp32s3/psram.rs | 14 ++++++------- esp-hal/src/timer/timg.rs | 4 ++-- esp-hal/src/usb_serial_jtag.rs | 6 +++--- esp-ieee802154/src/hal.rs | 6 +++--- 21 files changed, 91 insertions(+), 91 deletions(-) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 307ec0c9181..6291fb2fe2f 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -56,13 +56,13 @@ xtensa-lx = { version = "0.9.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { version = "0.33.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32c2 = { version = "0.22.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32c3 = { version = "0.25.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32c6 = { version = "0.16.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32h2 = { version = "0.12.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32s2 = { version = "0.24.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } -esp32s3 = { version = "0.28.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "390c88b", features = ["critical-section", "rt"], optional = true } +esp32 = { version = "0.33.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32c2 = { version = "0.22.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32c3 = { version = "0.25.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32c6 = { version = "0.16.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32h2 = { version = "0.12.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32s2 = { version = "0.24.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32s3 = { version = "0.28.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] esp-riscv-rt = { version = "0.9.0", path = "../esp-riscv-rt" } diff --git a/esp-hal/src/aes/esp32.rs b/esp-hal/src/aes/esp32.rs index f9920a9a4d3..dd69d4c5439 100644 --- a/esp-hal/src/aes/esp32.rs +++ b/esp-hal/src/aes/esp32.rs @@ -56,7 +56,7 @@ impl<'d> Aes<'d> { } pub(super) fn write_start(&mut self) { - self.aes.start().write(|w| w.start().set_bit()) + self.aes.start().write(|w| w.start().set_bit()); } pub(super) fn read_idle(&mut self) -> bool { diff --git a/esp-hal/src/aes/esp32cX.rs b/esp-hal/src/aes/esp32cX.rs index b20923cc9e3..9477b17579b 100644 --- a/esp-hal/src/aes/esp32cX.rs +++ b/esp-hal/src/aes/esp32cX.rs @@ -13,7 +13,7 @@ impl Aes<'_> { match enable_dma { true => self.aes.dma_enable().write(|w| w.dma_enable().set_bit()), false => self.aes.dma_enable().write(|w| w.dma_enable().clear_bit()), - } + }; } pub(super) fn write_key(&mut self, key: &[u8]) { @@ -34,7 +34,7 @@ impl Aes<'_> { } pub(super) fn write_start(&mut self) { - self.aes.trigger().write(|w| w.trigger().set_bit()) + self.aes.trigger().write(|w| w.trigger().set_bit()); } pub(super) fn read_idle(&mut self) -> bool { diff --git a/esp-hal/src/aes/esp32s2.rs b/esp-hal/src/aes/esp32s2.rs index 926612821c4..d00c34d20e8 100644 --- a/esp-hal/src/aes/esp32s2.rs +++ b/esp-hal/src/aes/esp32s2.rs @@ -21,7 +21,7 @@ impl<'d> Aes<'d> { match enable_dma { true => self.aes.dma_enable().write(|w| w.dma_enable().set_bit()), false => self.aes.dma_enable().write(|w| w.dma_enable().clear_bit()), - } + }; } pub(super) fn write_key(&mut self, key: &[u8]) { @@ -67,7 +67,7 @@ impl<'d> Aes<'d> { } pub(super) fn write_start(&mut self) { - self.aes.trigger().write(|w| w.trigger().set_bit()) + self.aes.trigger().write(|w| w.trigger().set_bit()); } pub(super) fn read_idle(&mut self) -> bool { diff --git a/esp-hal/src/aes/esp32s3.rs b/esp-hal/src/aes/esp32s3.rs index 6adc108449f..3e8085348a8 100644 --- a/esp-hal/src/aes/esp32s3.rs +++ b/esp-hal/src/aes/esp32s3.rs @@ -13,7 +13,7 @@ impl<'d> Aes<'d> { match enable_dma { true => self.aes.dma_enable().write(|w| w.dma_enable().set_bit()), false => self.aes.dma_enable().write(|w| w.dma_enable().clear_bit()), - } + }; } pub(super) fn write_key(&mut self, key: &[u8]) { @@ -39,7 +39,7 @@ impl<'d> Aes<'d> { } pub(super) fn write_start(&mut self) { - self.aes.trigger().write(|w| w.trigger().set_bit()) + self.aes.trigger().write(|w| w.trigger().set_bit()); } pub(super) fn read_idle(&mut self) -> bool { diff --git a/esp-hal/src/clock/clocks_ll/esp32c6.rs b/esp-hal/src/clock/clocks_ll/esp32c6.rs index ef349384ba7..71cec2c84f9 100644 --- a/esp-hal/src/clock/clocks_ll/esp32c6.rs +++ b/esp-hal/src/clock/clocks_ll/esp32c6.rs @@ -244,7 +244,7 @@ fn clk_ll_mspi_fast_set_hs_divider(divider: u32) { .mspi_clk_conf() .modify(|_, w| w.mspi_fast_hs_div_num().bits(5)), _ => panic!("Unsupported HS MSPI_FAST divider"), - } + }; } } diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index bff710a2ec8..8b5c387eadf 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -216,7 +216,7 @@ impl InterruptAccess for ChannelTxImpl { }; } w - }) + }); } fn is_listening(&self) -> EnumSet { @@ -250,7 +250,7 @@ impl InterruptAccess for ChannelTxImpl { }; } w - }) + }); } fn pending_interrupts(&self) -> EnumSet { @@ -438,7 +438,7 @@ impl InterruptAccess for ChannelRxImpl { }; } w - }) + }); } fn pending_interrupts(&self) -> EnumSet { diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 1659eb5f95d..098da68add1 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -124,7 +124,7 @@ impl> InterruptAccess EnumSet { @@ -160,7 +160,7 @@ impl> InterruptAccess EnumSet { @@ -259,7 +259,7 @@ impl> InterruptAccess EnumSet { @@ -299,7 +299,7 @@ impl> InterruptAccess EnumSet { @@ -535,7 +535,7 @@ impl> InterruptAccess EnumSet { @@ -592,7 +592,7 @@ impl> InterruptAccess &'static AtomicWaker { @@ -676,7 +676,7 @@ impl> InterruptAccess EnumSet { @@ -740,7 +740,7 @@ impl> InterruptAccess &'static AtomicWaker { diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 494a085f629..b6e07e3f97f 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -1091,13 +1091,7 @@ fn async_handler(info: &Info, state: &State) { #[cfg(not(any(esp32, esp32s2)))] w.txfifo_wm().clear_bit(); - cfg_if::cfg_if! { - if #[cfg(esp32)] { - w.ack_err().clear_bit() - } else { - w.nack().clear_bit() - } - } + w.nack().clear_bit() }); state.waker.wake(); @@ -1867,7 +1861,7 @@ impl Driver<'_> { // Handle error cases let retval = if interrupts.time_out().bit_is_set() { Err(Error::TimeOut) - } else if interrupts.ack_err().bit_is_set() { + } else if interrupts.nack().bit_is_set() { Err(Error::AckCheckFailed) } else if interrupts.arbitration_lost().bit_is_set() { Err(Error::ArbitrationLost) diff --git a/esp-hal/src/interrupt/software.rs b/esp-hal/src/interrupt/software.rs index 8b4284f7b33..92dfb32d4fa 100644 --- a/esp-hal/src/interrupt/software.rs +++ b/esp-hal/src/interrupt/software.rs @@ -93,7 +93,7 @@ impl SoftwareInterrupt { .cpu_intr_from_cpu_3() .write(|w| w.cpu_intr_from_cpu_3().set_bit()), _ => unreachable!(), - } + }; } /// Resets this software-interrupt @@ -120,7 +120,7 @@ impl SoftwareInterrupt { .cpu_intr_from_cpu_3() .write(|w| w.cpu_intr_from_cpu_3().clear_bit()), _ => unreachable!(), - } + }; } /// Unsafely create an instance of this peripheral out of thin air. diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index f467d9f32fc..6bb4e3e366e 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -313,7 +313,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, // SAFETY: // `bits` is a valid bit pattern - ch.gen((!IS_A) as usize).write(|w| unsafe { w.bits(bits) }) + ch.gen((!IS_A) as usize).write(|w| unsafe { w.bits(bits) }); } /// Set how a new timestamp syncs with the timer @@ -334,7 +334,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, } else { w.b_upmethod().bits(bits) } - }) + }); } /// Write a new timestamp. @@ -347,16 +347,16 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, #[cfg(esp32s3)] if IS_A { - ch.cmpr_value0().write(|w| unsafe { w.a().bits(value) }) + ch.cmpr_value0().write(|w| unsafe { w.a().bits(value) }); } else { - ch.cmpr_value1().write(|w| unsafe { w.b().bits(value) }) + ch.cmpr_value1().write(|w| unsafe { w.b().bits(value) }); } #[cfg(any(esp32, esp32c6, esp32h2))] if IS_A { - ch.gen_tstmp_a().write(|w| unsafe { w.a().bits(value) }) + ch.gen_tstmp_a().write(|w| unsafe { w.a().bits(value) }); } else { - ch.gen_tstmp_b().write(|w| unsafe { w.b().bits(value) }) + ch.gen_tstmp_b().write(|w| unsafe { w.b().bits(value) }); } } diff --git a/esp-hal/src/rsa/esp32cX.rs b/esp-hal/src/rsa/esp32cX.rs index 88f4bf99a50..e74eac7fd7f 100644 --- a/esp-hal/src/rsa/esp32cX.rs +++ b/esp-hal/src/rsa/esp32cX.rs @@ -26,7 +26,7 @@ impl Rsa<'_, DM> { /// When enabled rsa peripheral would generate an interrupt when a operation /// is finished. pub fn enable_disable_interrupt(&mut self, enable: bool) { - self.rsa.int_ena().write(|w| w.int_ena().bit(enable)) + self.rsa.int_ena().write(|w| w.int_ena().bit(enable)); } fn write_mode(&mut self, mode: u32) { @@ -52,7 +52,7 @@ impl Rsa<'_, DM> { .rsa .search_enable() .write(|w| w.search_enable().clear_bit()), - } + }; } /// Checks if the search functionality is enabled in the RSA hardware. @@ -87,7 +87,7 @@ impl Rsa<'_, DM> { .rsa .constant_time() .write(|w| w.constant_time().set_bit()), - } + }; } /// Starts the modular exponentiation operation. diff --git a/esp-hal/src/rsa/esp32sX.rs b/esp-hal/src/rsa/esp32sX.rs index bbdad42cac4..f4404bfa471 100644 --- a/esp-hal/src/rsa/esp32sX.rs +++ b/esp-hal/src/rsa/esp32sX.rs @@ -27,7 +27,7 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> { /// When enabled rsa peripheral would generate an interrupt when a operation /// is finished. pub fn enable_disable_interrupt(&mut self, enable: bool) { - self.rsa.int_ena().write(|w| w.int_ena().bit(enable)) + self.rsa.int_ena().write(|w| w.int_ena().bit(enable)); } fn write_mode(&mut self, mode: u32) { @@ -53,7 +53,7 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> { .rsa .search_enable() .write(|w| w.search_enable().clear_bit()), - } + }; } /// Checks if the search functionality is enabled in the RSA hardware. @@ -88,7 +88,7 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> { .rsa .constant_time() .write(|w| w.constant_time().set_bit()), - } + }; } /// Starts the modular exponentiation operation. diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 987f687cb8c..71797a64a26 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -983,7 +983,7 @@ impl Rwdt { RwdtStage::Stage3 => rtc_cntl .wdtconfig4() .modify(|_, w| w.wdt_stg3_hold().bits(timeout_raw)), - } + }; #[cfg(any(esp32c6, esp32h2))] match stage { @@ -1003,7 +1003,7 @@ impl Rwdt { w.wdt_stg3_hold() .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) }), - } + }; #[cfg(not(any(esp32, esp32c6, esp32h2)))] match stage { @@ -1023,7 +1023,7 @@ impl Rwdt { w.wdt_stg3_hold() .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) }), - } + }; } self.set_write_protection(true); @@ -1048,7 +1048,7 @@ impl Rwdt { RwdtStage::Stage3 => rtc_cntl .wdtconfig0() .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) }), - } + }; self.set_write_protection(true); } diff --git a/esp-hal/src/rtc_cntl/rtc/esp32c6.rs b/esp-hal/src/rtc_cntl/rtc/esp32c6.rs index a30929f62a6..ff7efe0ed22 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32c6.rs @@ -267,7 +267,7 @@ fn modem_clock_hal_deselect_all_wifi_lpclk_source() { .clear_bit() .clk_wifipwr_lp_sel_xtal() .clear_bit() - }) + }); } } @@ -299,7 +299,7 @@ fn modem_lpcon_ll_set_wifi_lpclk_divisor_value(divider: u16) { unsafe { modem_lpcon() .wifi_lp_clk_conf() - .modify(|_, w| w.clk_wifipwr_lp_div_num().bits(divider)) + .modify(|_, w| w.clk_wifipwr_lp_div_num().bits(divider)); } } @@ -1534,16 +1534,19 @@ impl RtcClock { } else { cali_clk_sel = RtcCaliClkSel::CaliClk32k; match cal_clk { - RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => (), - RtcCalSel::RtcCal32kRc => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) }), - RtcCalSel::RtcCal32kXtal => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) }), - RtcCalSel::RtcCal32kOscSlow => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) }), + RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {} + RtcCalSel::RtcCal32kRc => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) }); + } + RtcCalSel::RtcCal32kXtal => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) }); + } + RtcCalSel::RtcCal32kOscSlow => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) }); + } } } diff --git a/esp-hal/src/rtc_cntl/rtc/esp32h2.rs b/esp-hal/src/rtc_cntl/rtc/esp32h2.rs index 61301d68131..5419df84ebe 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32h2.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32h2.rs @@ -383,16 +383,19 @@ impl RtcClock { } else { cali_clk_sel = RtcCaliClkSel::CaliClk32k; match cal_clk { - RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => (), - RtcCalSel::RtcCal32kRc => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) }), - RtcCalSel::RtcCal32kXtal => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) }), - RtcCalSel::RtcCal32kOscSlow => pcr - .ctrl_32k_conf() - .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) }), + RtcCalSel::RtcCalRtcMux | RtcCalSel::RtcCalRcSlow | RtcCalSel::RtcCalRcFast => {} + RtcCalSel::RtcCal32kRc => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(0) }); + } + RtcCalSel::RtcCal32kXtal => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(1) }); + } + RtcCalSel::RtcCal32kOscSlow => { + pcr.ctrl_32k_conf() + .modify(|_, w| unsafe { w.clk_32k_sel().bits(2) }); + } } } diff --git a/esp-hal/src/soc/esp32c6/lp_core.rs b/esp-hal/src/soc/esp32c6/lp_core.rs index 151e47268f1..ac7674071fc 100644 --- a/esp-hal/src/soc/esp32c6/lp_core.rs +++ b/esp-hal/src/soc/esp32c6/lp_core.rs @@ -63,12 +63,12 @@ impl<'d> LpCore<'d> { LpCoreClockSource::RcFastClk => unsafe { (*crate::soc::peripherals::LP_CLKRST::PTR) .lp_clk_conf() - .modify(|_, w| w.fast_clk_sel().clear_bit()) + .modify(|_, w| w.fast_clk_sel().clear_bit()); }, LpCoreClockSource::XtalD2Clk => unsafe { (*crate::soc::peripherals::LP_CLKRST::PTR) .lp_clk_conf() - .modify(|_, w| w.fast_clk_sel().set_bit()) + .modify(|_, w| w.fast_clk_sel().set_bit()); }, } diff --git a/esp-hal/src/soc/esp32s3/psram.rs b/esp-hal/src/soc/esp32s3/psram.rs index 27067c93724..1083b5ac896 100644 --- a/esp-hal/src/soc/esp32s3/psram.rs +++ b/esp-hal/src/soc/esp32s3/psram.rs @@ -708,7 +708,7 @@ pub(crate) mod utils { let iomux = &*esp32s3::IO_MUX::PTR; iomux .gpio(cs1_io as usize) - .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1)) + .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1)); } } else { unsafe { @@ -717,7 +717,7 @@ pub(crate) mod utils { let iomux = &*esp32s3::IO_MUX::PTR; iomux .gpio(cs1_io as usize) - .modify(|_, w| w.mcu_sel().bits(PIN_FUNC_GPIO)) + .modify(|_, w| w.mcu_sel().bits(PIN_FUNC_GPIO)); } } @@ -1156,7 +1156,7 @@ pub(crate) mod utils { spi.sram_cmd().modify(|_, w| w.sdout_oct().set_bit()); spi.sram_cmd().modify(|_, w| w.sdin_oct().set_bit()); - spi.cache_sctrl().modify(|_, w| w.sram_oct().set_bit()) + spi.cache_sctrl().modify(|_, w| w.sram_oct().set_bit()); } } @@ -1164,7 +1164,7 @@ pub(crate) mod utils { fn spi_flash_set_rom_required_regs() { // Disable the variable dummy mode when doing timing tuning let spi = unsafe { &*crate::peripherals::SPI1::PTR }; - spi.ddr().modify(|_, w| w.spi_fmem_var_dummy().clear_bit()) + spi.ddr().modify(|_, w| w.spi_fmem_var_dummy().clear_bit()); // STR /DTR mode setting is done every time when // `esp_rom_opiflash_exec_cmd` is called // @@ -1199,7 +1199,7 @@ pub(crate) mod utils { let pins = &[27usize, 28, 31, 32, 33, 34, 35, 36, 37]; for pin in pins { let iomux = &*esp32s3::IO_MUX::PTR; - iomux.gpio(*pin).modify(|_, w| w.fun_drv().bits(3)) + iomux.gpio(*pin).modify(|_, w| w.fun_drv().bits(3)); } } } @@ -1287,7 +1287,7 @@ pub(crate) mod utils { let iomux = &*esp32s3::IO_MUX::PTR; iomux .gpio(OCT_PSRAM_CS1_IO as usize) - .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1)) + .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1)); } // Set mspi cs1 drive strength @@ -1295,7 +1295,7 @@ pub(crate) mod utils { let iomux = &*esp32s3::IO_MUX::PTR; iomux .gpio(OCT_PSRAM_CS1_IO as usize) - .modify(|_, w| w.fun_drv().bits(3)) + .modify(|_, w| w.fun_drv().bits(3)); } // Set psram clock pin drive strength diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 8f67b33db23..40be2cd2bf8 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -804,7 +804,7 @@ where fn set_divider(&self, divider: u16) { unsafe { Self::t() } .config() - .modify(|_, w| unsafe { w.divider().bits(divider) }) + .modify(|_, w| unsafe { w.divider().bits(divider) }); } } @@ -1074,7 +1074,7 @@ where MwdtStage::Stage3 => reg_block .wdtconfig5() .write(|w| w.wdt_stg3_hold().bits(timeout_raw)), - } + }; } #[cfg(any(esp32c2, esp32c3, esp32c6))] diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index 42c82f8aacd..c94c2be6c93 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -264,7 +264,7 @@ where pub fn reset_rx_packet_recv_interrupt(&mut self) { USB_DEVICE::register_block() .int_clr() - .write(|w| w.serial_out_recv_pkt().clear_bit_by_one()) + .write(|w| w.serial_out_recv_pkt().clear_bit_by_one()); } } @@ -408,7 +408,7 @@ pub trait Instance: crate::private::Sealed { Self::register_block() .int_clr() - .write(|w| w.serial_in_empty().clear_bit_by_one()) + .write(|w| w.serial_in_empty().clear_bit_by_one()); } /// Disable all receive interrupts for the peripheral @@ -419,7 +419,7 @@ pub trait Instance: crate::private::Sealed { Self::register_block() .int_clr() - .write(|w| w.serial_out_recv_pkt().clear_bit_by_one()) + .write(|w| w.serial_out_recv_pkt().clear_bit_by_one()); } } diff --git a/esp-ieee802154/src/hal.rs b/esp-ieee802154/src/hal.rs index c43cb379adf..dd116715977 100644 --- a/esp-ieee802154/src/hal.rs +++ b/esp-ieee802154/src/hal.rs @@ -244,7 +244,7 @@ pub(crate) fn set_tx_addr(addr: *const u8) { pub(crate) fn set_cmd(cmd: Command) { unsafe { &*IEEE802154::PTR } .command() - .modify(|_, w| unsafe { w.opcode().bits(cmd as u8) }) + .modify(|_, w| unsafe { w.opcode().bits(cmd as u8) }); } #[inline(always)] @@ -271,7 +271,7 @@ pub(crate) fn set_multipan_enable_mask(mask: u8) { // apparently the REGS are garbage and the struct is right? unsafe { &*IEEE802154::PTR } .ctrl_cfg() - .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1111 << 29) | (mask as u32) << 29) }) + .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1111 << 29) | (mask as u32) << 29) }); } #[inline(always)] @@ -333,7 +333,7 @@ pub(crate) fn set_cca_mode(cca_mode: CcaMode) { pub(crate) fn set_cca_threshold(cca_threshold: i8) { unsafe { &*IEEE802154::PTR } .ed_scan_cfg() - .modify(|_, w| unsafe { w.cca_ed_threshold().bits(cca_threshold as u8) }) + .modify(|_, w| unsafe { w.cca_ed_threshold().bits(cca_threshold as u8) }); } #[inline(always)] From 57fc5df858e7526108a8b7df46ed245f09f8ce2f Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 11 Nov 2024 23:08:32 -0800 Subject: [PATCH 51/67] Modify `bump-version` subcommand to also bump dependent packages' dependencies (#2514) --- xtask/src/lib.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 043cdda2e77..c807586a4a9 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -433,6 +433,33 @@ pub fn bump_version(workspace: &Path, package: Package, amount: Version) -> Resu manifest["package"]["version"] = toml_edit::value(version.to_string()); fs::write(manifest_path, manifest.to_string())?; + for pkg in + Package::iter().filter(|p| ![package, Package::Examples, Package::HilTest].contains(p)) + { + let manifest_path = workspace.join(pkg.to_string()).join("Cargo.toml"); + let manifest = fs::read_to_string(&manifest_path) + .with_context(|| format!("Could not read {}", manifest_path.display()))?; + + let mut manifest = manifest.parse::()?; + + if manifest["dependencies"] + .as_table() + .unwrap() + .contains_key(&package.to_string()) + { + log::info!( + " Bumping {package} version for package {pkg}: ({prev_version} -> {version})" + ); + + manifest["dependencies"].as_table_mut().map(|table| { + table[&package.to_string()]["version"] = toml_edit::value(version.to_string()) + }); + + fs::write(&manifest_path, manifest.to_string()) + .with_context(|| format!("Could not write {}", manifest_path.display()))?; + } + } + Ok(()) } From cf10f07a9e053d5062d081bd31c9311b921801fe Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Tue, 12 Nov 2024 02:14:14 -0800 Subject: [PATCH 52/67] Add validation to `esp-config` (#2475) * Clean up and re-organize `lib.rs` a bit (sorry) * Add configuration validation, some other refactoring/improvements * Add a built-in range validator, re-document the `generate_config` function * Update build scripts to reflect new configuration API --- esp-config/src/generate.rs | 536 ++++++++++++++++++++++++++++--------- esp-config/src/lib.rs | 61 +++-- esp-hal-embassy/build.rs | 3 +- esp-hal/build.rs | 12 +- esp-ieee802154/build.rs | 5 +- esp-wifi/build.rs | 145 ++++++++-- 6 files changed, 581 insertions(+), 181 deletions(-) diff --git a/esp-config/src/generate.rs b/esp-config/src/generate.rs index 1afa1c92591..ede216f5d27 100644 --- a/esp-config/src/generate.rs +++ b/esp-config/src/generate.rs @@ -1,77 +1,246 @@ -use core::fmt::Write; -use std::{collections::HashMap, env, fs, path::PathBuf}; +use std::{ + collections::HashMap, + env, + fmt::{self, Write as _}, + fs, + ops::Range, + path::PathBuf, +}; const DOC_TABLE_HEADER: &str = r#" | Name | Description | Default value | |------|-------------|---------------| "#; -const CHOSEN_TABLE_HEADER: &str = r#" + +const SELECTED_TABLE_HEADER: &str = r#" | Name | Selected value | |------|----------------| "#; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ParseError(String); +/// Configuration errors. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Error { + /// Parse errors. + Parse(String), + /// Validation errors. + Validation(String), +} + +impl Error { + /// Convenience function for creating parse errors. + pub fn parse(message: S) -> Self + where + S: Into, + { + Self::Parse(message.into()) + } + + /// Convenience function for creating validation errors. + pub fn validation(message: S) -> Self + where + S: Into, + { + Self::Validation(message.into()) + } +} -#[derive(Clone, Debug, PartialEq, Eq)] +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Parse(message) => write!(f, "{message}"), + Error::Validation(message) => write!(f, "{message}"), + } + } +} + +/// Supported configuration value types. +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Value { - SignedInteger(isize), - UnsignedInteger(usize), + /// Booleans. Bool(bool), + /// Integers. + Integer(i128), + /// Strings. String(String), } +// TODO: Do we want to handle negative values for non-decimal values? impl Value { - fn parse_in_place(&mut self, s: &str) -> Result<(), ParseError> { + fn parse_in_place(&mut self, s: &str) -> Result<(), Error> { *self = match self { - Value::Bool(_) => match s.to_lowercase().as_ref() { - "false" | "no" | "n" | "f" => Value::Bool(false), - "true" | "yes" | "y" | "t" => Value::Bool(true), - _ => return Err(ParseError(format!("Invalid boolean value: {}", s))), - }, - Value::SignedInteger(_) => Value::SignedInteger( - match s.as_bytes() { - [b'0', b'x', ..] => isize::from_str_radix(&s[2..], 16), - [b'0', b'o', ..] => isize::from_str_radix(&s[2..], 8), - [b'0', b'b', ..] => isize::from_str_radix(&s[2..], 2), - _ => isize::from_str_radix(&s, 10), + Value::Bool(_) => match s { + "true" => Value::Bool(true), + "false" => Value::Bool(false), + _ => { + return Err(Error::parse(format!( + "Expected 'true' or 'false', found: '{s}'" + ))) } - .map_err(|_| ParseError(format!("Invalid signed numerical value: {}", s)))?, - ), - Value::UnsignedInteger(_) => Value::UnsignedInteger( - match s.as_bytes() { - [b'0', b'x', ..] => usize::from_str_radix(&s[2..], 16), - [b'0', b'o', ..] => usize::from_str_radix(&s[2..], 8), - [b'0', b'b', ..] => usize::from_str_radix(&s[2..], 2), - _ => usize::from_str_radix(&s, 10), + }, + Value::Integer(_) => { + let inner = match s.as_bytes() { + [b'0', b'x', ..] => i128::from_str_radix(&s[2..], 16), + [b'0', b'o', ..] => i128::from_str_radix(&s[2..], 8), + [b'0', b'b', ..] => i128::from_str_radix(&s[2..], 2), + _ => i128::from_str_radix(&s, 10), } - .map_err(|_| ParseError(format!("Invalid unsigned numerical value: {}", s)))?, - ), - Value::String(_) => Value::String(String::from(s)), + .map_err(|_| Error::parse(format!("Expected valid intger value, found: '{s}'")))?; + + Value::Integer(inner) + } + Value::String(_) => Value::String(s.into()), }; + Ok(()) } - fn as_string(&self) -> String { + /// Convert the value to a [bool]. + pub fn as_bool(&self) -> bool { + match self { + Value::Bool(value) => *value, + _ => panic!("attempted to convert non-bool value to a bool"), + } + } + + /// Convert the value to an [i128]. + pub fn as_integer(&self) -> i128 { + match self { + Value::Integer(value) => *value, + _ => panic!("attempted to convert non-integer value to an integer"), + } + } + + /// Convert the value to a [String]. + pub fn as_string(&self) -> String { + match self { + Value::String(value) => value.to_owned(), + _ => panic!("attempted to convert non-string value to a string"), + } + } + + /// Is the value a bool? + pub fn is_bool(&self) -> bool { + matches!(self, Value::Bool(_)) + } + + /// Is the value an integer? + pub fn is_integer(&self) -> bool { + matches!(self, Value::Integer(_)) + } + + /// Is the value a string? + pub fn is_string(&self) -> bool { + matches!(self, Value::String(_)) + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Value::Bool(b) => write!(f, "{b}"), + Value::Integer(i) => write!(f, "{i}"), + Value::String(s) => write!(f, "{s}"), + } + } +} + +/// Configuration value validation functions. +pub enum Validator { + /// Only allow negative integers, i.e. any values less than 0. + NegativeInteger, + /// Only allow non-negative integers, i.e. any values greater than or equal + /// to 0. + NonNegativeInteger, + /// Only allow positive integers, i.e. any values greater than to 0. + PositiveInteger, + /// Ensure that an integer value falls within the specified range. + IntegerInRange(Range), + /// A custom validation function to run against any supported value type. + Custom(Box Result<(), Error>>), +} + +impl Validator { + fn validate(&self, value: &Value) -> Result<(), Error> { match self { - Value::Bool(value) => String::from(if *value { "true" } else { "false" }), - Value::SignedInteger(value) => format!("{}", value), - Value::UnsignedInteger(value) => format!("{}", value), - Value::String(value) => value.clone(), + Validator::NegativeInteger => negative_integer(value)?, + Validator::NonNegativeInteger => non_negative_integer(value)?, + Validator::PositiveInteger => positive_integer(value)?, + Validator::IntegerInRange(range) => integer_in_range(range, value)?, + Validator::Custom(validator_fn) => validator_fn(value)?, } + + Ok(()) } } -/// Generate and parse config from a prefix, and array of key, default, -/// description tuples. +fn negative_integer(value: &Value) -> Result<(), Error> { + if !value.is_integer() { + return Err(Error::validation( + "Validator::NegativeInteger can only be used with integer values", + )); + } else if value.as_integer() >= 0 { + return Err(Error::validation(format!( + "Expected negative integer, found '{}'", + value.as_integer() + ))); + } + + Ok(()) +} + +fn non_negative_integer(value: &Value) -> Result<(), Error> { + if !value.is_integer() { + return Err(Error::validation( + "Validator::NonNegativeInteger can only be used with integer values", + )); + } else if value.as_integer() < 0 { + return Err(Error::validation(format!( + "Expected non-negative integer, found '{}'", + value.as_integer() + ))); + } + + Ok(()) +} + +fn positive_integer(value: &Value) -> Result<(), Error> { + if !value.is_integer() { + return Err(Error::validation( + "Validator::PositiveInteger can only be used with integer values", + )); + } else if value.as_integer() <= 0 { + return Err(Error::validation(format!( + "Expected positive integer, found '{}'", + value.as_integer() + ))); + } + + Ok(()) +} + +fn integer_in_range(range: &Range, value: &Value) -> Result<(), Error> { + if !value.is_integer() || !range.contains(&value.as_integer()) { + Err(Error::validation(format!( + "Value '{}' does not fall within range '{:?}'", + value, range + ))) + } else { + Ok(()) + } +} + +/// Generate and parse config from a prefix, and an array tuples containing the +/// name, description, default value, and an optional validator. /// /// This function will parse any `SCREAMING_SNAKE_CASE` environment variables -/// that match the given prefix. It will then attempt to parse the [`Value`]. +/// that match the given prefix. It will then attempt to parse the [`Value`] and +/// run any validators which have been specified. +/// /// Once the config has been parsed, this function will emit `snake_case` cfg's /// _without_ the prefix which can be used in the dependant crate. After that, /// it will create a markdown table in the `OUT_DIR` under the name -/// `{prefix}_config_table.md` where prefix has also been converted -/// to `snake_case`. This can be included in crate documentation to outline the +/// `{prefix}_config_table.md` where prefix has also been converted to +/// `snake_case`. This can be included in crate documentation to outline the /// available configuration options for the crate. /// /// Passing a value of true for the `emit_md_tables` argument will create and @@ -81,22 +250,46 @@ impl Value { /// Unknown keys with the supplied prefix will cause this function to panic. pub fn generate_config( prefix: &str, - config: &[(&str, Value, &str)], + config: &[(&str, &str, Value, Option)], emit_md_tables: bool, ) -> HashMap { - // only rebuild if build.rs changed. Otherwise Cargo will rebuild if any + // Only rebuild if `build.rs` changed. Otherwise, Cargo will rebuild if any // other file changed. println!("cargo:rerun-if-changed=build.rs"); + #[cfg(not(test))] env_change_work_around(); - // ensure that the prefix is `SCREAMING_SNAKE_CASE` - let prefix = format!("{}_", screaming_snake_case(prefix)); let mut doc_table = String::from(DOC_TABLE_HEADER); - let mut selected_config = String::from(CHOSEN_TABLE_HEADER); + let mut selected_config = String::from(SELECTED_TABLE_HEADER); + + // Ensure that the prefix is `SCREAMING_SNAKE_CASE`: + let prefix = screaming_snake_case(prefix); + + // Build a lookup table for any provided validators; we must prefix the + // name of the config and transform it to SCREAMING_SNAKE_CASE so that + // it matches the keys in the hash table produced by `create_config`. + let config_validators = config + .iter() + .flat_map(|(name, _description, _default, validator)| { + if let Some(validator) = validator { + let name = format!("{prefix}_{}", screaming_snake_case(name)); + Some((name, validator)) + } else { + None + } + }) + .collect::>(); let mut configs = create_config(&prefix, config, &mut doc_table); capture_from_env(&prefix, &mut configs); + + for (name, value) in configs.iter() { + if let Some(validator) = config_validators.get(name) { + validator.validate(value).unwrap(); + } + } + emit_configuration(&prefix, &configs, &mut selected_config); if emit_md_tables { @@ -118,8 +311,7 @@ fn env_change_work_around() { // target while !out_dir.ends_with("target") { if !out_dir.pop() { - // We ran out of directories... - return; + return; // We ran out of directories... } } out_dir.pop(); @@ -141,44 +333,42 @@ fn env_change_work_around() { } } -fn emit_configuration( +fn create_config( prefix: &str, - configs: &HashMap, - selected_config: &mut String, -) { - // emit cfgs and set envs - for (name, value) in configs.into_iter() { - let cfg_name = snake_case(name.trim_start_matches(prefix)); - println!("cargo:rustc-check-cfg=cfg({cfg_name})"); - match value { - Value::Bool(true) => { - println!("cargo:rustc-cfg={cfg_name}") - } - _ => {} - } + config: &[(&str, &str, Value, Option)], + doc_table: &mut String, +) -> HashMap { + let mut configs = HashMap::new(); - let value = value.as_string(); - // values that haven't been seen will be output here with the default value - println!("cargo:rustc-env={}={}", name, value); + for (name, description, default, _validator) in config { + let name = format!("{prefix}_{}", screaming_snake_case(name)); + configs.insert(name.clone(), default.clone()); - writeln!(selected_config, "|**{name}**|{value}|").unwrap(); + // Write documentation table line: + let default = default.to_string(); + writeln!(doc_table, "|**{name}**|{description}|{default}|").unwrap(); + + // Rebuild if config environment variable changed: + println!("cargo:rerun-if-env-changed={name}"); } + + configs } fn capture_from_env(prefix: &str, configs: &mut HashMap) { let mut unknown = Vec::new(); let mut failed = Vec::new(); - // Try and capture input from the environment + // Try and capture input from the environment: for (var, value) in env::vars() { - if let Some(_) = var.strip_prefix(prefix) { + if var.strip_prefix(prefix).is_some() { let Some(cfg) = configs.get_mut(&var) else { unknown.push(var); continue; }; if let Err(e) = cfg.parse_in_place(&value) { - failed.push(format!("{}: {e:?}", var)); + failed.push(format!("{var}: {e}")); } } } @@ -192,61 +382,54 @@ fn capture_from_env(prefix: &str, configs: &mut HashMap) { } } -fn create_config( +fn emit_configuration( prefix: &str, - config: &[(&str, Value, &str)], - doc_table: &mut String, -) -> HashMap { - // Generate the template for the config - let mut configs = HashMap::new(); - for (name, default, desc) in config { - let name = format!("{prefix}{}", screaming_snake_case(&name)); - configs.insert(name.clone(), default.clone()); + configs: &HashMap, + selected_config: &mut String, +) { + for (name, value) in configs.iter() { + let cfg_name = snake_case(name.trim_start_matches(&format!("{prefix}_"))); + println!("cargo:rustc-check-cfg=cfg({cfg_name})"); - // write doc table line - let default = default.as_string(); - writeln!(doc_table, "|**{name}**|{desc}|{default}|").unwrap(); + if let Value::Bool(true) = value { + println!("cargo:rustc-cfg={cfg_name}"); + } - // Rebuild if config envvar changed. - println!("cargo:rerun-if-env-changed={name}"); - } + let value = value.to_string(); - configs + // Values that haven't been seen will be output here with the default value: + println!("cargo:rustc-env={}={}", name, value); + writeln!(selected_config, "|**{name}**|{value}|").unwrap(); + } } fn write_config_tables(prefix: &str, doc_table: String, selected_config: String) { let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir - .join(format!("{prefix}config_table.md")) - .to_string_lossy() + .join(format!("{prefix}_config_table.md")) + .display() .to_string(); fs::write(out_file, doc_table).unwrap(); - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir - .join(format!("{prefix}selected_config.md")) - .to_string_lossy() + .join(format!("{prefix}_selected_config.md")) + .display() .to_string(); fs::write(out_file, selected_config).unwrap(); } -// Converts a symbol name like -// "PLACE-spi_DRIVER-IN_ram" -// to -// "place_spi_driver_in_ram" fn snake_case(name: &str) -> String { let mut name = name.replace("-", "_"); name.make_ascii_lowercase(); + name } -// Converts a symbol name like -// "PLACE-spi_DRIVER-IN_ram" -// to -// "PLACE_SPI_DRIVER_IN_RAM" fn screaming_snake_case(name: &str) -> String { let mut name = name.replace("-", "_"); name.make_ascii_uppercase(); + name } @@ -257,32 +440,24 @@ mod test { #[test] fn value_number_formats() { const INPUTS: &[&str] = &["0xAA", "0o252", "0b0000000010101010", "170"]; - let mut v = Value::SignedInteger(0); + let mut v = Value::Integer(0); for input in INPUTS { v.parse_in_place(input).unwrap(); // no matter the input format, the output format should be decimal - assert_eq!(v.as_string(), "170"); + assert_eq!(format!("{v}"), "170"); } } #[test] fn value_bool_inputs() { - const TRUE_INPUTS: &[&str] = &["true", "y", "yes"]; - const FALSE_INPUTS: &[&str] = &["false", "n", "no"]; let mut v = Value::Bool(false); - for input in TRUE_INPUTS { - v.parse_in_place(input).unwrap(); - // no matter the input variant, the output format should be "true" - assert_eq!(v.as_string(), "true"); - } + v.parse_in_place("true").unwrap(); + assert_eq!(format!("{v}"), "true"); - for input in FALSE_INPUTS { - v.parse_in_place(input).unwrap(); - // no matter the input variant, the output format should be "false" - assert_eq!(v.as_string(), "false"); - } + v.parse_in_place("false").unwrap(); + assert_eq!(format!("{v}"), "false"); } #[test] @@ -298,13 +473,18 @@ mod test { let configs = generate_config( "esp-test", &[ - ("number", Value::UnsignedInteger(999), "NA"), - ("number_signed", Value::SignedInteger(-777), "NA"), - ("string", Value::String("Demo".to_owned()), "NA"), - ("bool", Value::Bool(false), "NA"), - ("number_default", Value::UnsignedInteger(999), "NA"), - ("string_default", Value::String("Demo".to_owned()), "NA"), - ("bool_default", Value::Bool(false), "NA"), + ("number", "NA", Value::Integer(999), None), + ("number_signed", "NA", Value::Integer(-777), None), + ("string", "NA", Value::String("Demo".to_owned()), None), + ("bool", "NA", Value::Bool(false), None), + ("number_default", "NA", Value::Integer(999), None), + ( + "string_default", + "NA", + Value::String("Demo".to_owned()), + None, + ), + ("bool_default", "NA", Value::Bool(false), None), ], false, ); @@ -312,14 +492,14 @@ mod test { // some values have changed assert_eq!( match configs.get("ESP_TEST_NUMBER").unwrap() { - Value::UnsignedInteger(num) => *num, + Value::Integer(num) => *num, _ => unreachable!(), }, 0xaa ); assert_eq!( match configs.get("ESP_TEST_NUMBER_SIGNED").unwrap() { - Value::SignedInteger(num) => *num, + Value::Integer(num) => *num, _ => unreachable!(), }, -999 @@ -342,7 +522,7 @@ mod test { // the rest are the defaults assert_eq!( match configs.get("ESP_TEST_NUMBER_DEFAULT").unwrap() { - Value::UnsignedInteger(num) => *num, + Value::Integer(num) => *num, _ => unreachable!(), }, 999 @@ -365,6 +545,114 @@ mod test { ) } + #[test] + fn builtin_validation_passes() { + temp_env::with_vars( + [ + ("ESP_TEST_POSITIVE_NUMBER", Some("7")), + ("ESP_TEST_NEGATIVE_NUMBER", Some("-1")), + ("ESP_TEST_NON_NEGATIVE_NUMBER", Some("0")), + ("ESP_TEST_RANGE", Some("9")), + ], + || { + generate_config( + "esp-test", + &[ + ( + "positive_number", + "NA", + Value::Integer(-1), + Some(Validator::PositiveInteger), + ), + ( + "negative_number", + "NA", + Value::Integer(1), + Some(Validator::NegativeInteger), + ), + ( + "non_negative_number", + "NA", + Value::Integer(-1), + Some(Validator::NonNegativeInteger), + ), + ( + "range", + "NA", + Value::Integer(0), + Some(Validator::IntegerInRange(5..10)), + ), + ], + false, + ) + }, + ); + } + + #[test] + fn custom_validation_passes() { + temp_env::with_vars([("ESP_TEST_NUMBER", Some("13"))], || { + generate_config( + "esp-test", + &[( + "number", + "NA", + Value::Integer(-1), + Some(Validator::Custom(Box::new(|value| { + let range = 10..20; + if !value.is_integer() || !range.contains(&value.as_integer()) { + Err(Error::validation("value does not fall within range")) + } else { + Ok(()) + } + }))), + )], + false, + ) + }); + } + + #[test] + #[should_panic] + fn builtin_validation_bails() { + temp_env::with_vars([("ESP_TEST_POSITIVE_NUMBER", Some("-99"))], || { + generate_config( + "esp-test", + &[( + "positive_number", + "NA", + Value::Integer(-1), + Some(Validator::PositiveInteger), + )], + false, + ) + }); + } + + #[test] + #[should_panic] + fn custom_validation_bails() { + temp_env::with_vars([("ESP_TEST_NUMBER", Some("37"))], || { + generate_config( + "esp-test", + &[( + "number", + "NA", + Value::Integer(-1), + Some(Validator::Custom(Box::new(|value| { + let range = 10..20; + if !value.is_integer() || !range.contains(&value.as_integer()) { + Err(Error::validation("value does not fall within range")) + } else { + Ok(()) + } + }))), + )], + false, + ) + }); + } + #[test] #[should_panic] fn env_unknown_bails() { @@ -376,7 +664,7 @@ mod test { || { generate_config( "esp-test", - &[("number", Value::UnsignedInteger(999), "NA")], + &[("number", "NA", Value::Integer(999), None)], false, ); }, @@ -389,7 +677,7 @@ mod test { temp_env::with_vars([("ESP_TEST_NUMBER", Some("Hello world"))], || { generate_config( "esp-test", - &[("number", Value::UnsignedInteger(999), "NA")], + &[("number", "NA", Value::Integer(999), None)], false, ); }); diff --git a/esp-config/src/lib.rs b/esp-config/src/lib.rs index 941c420692e..2ef0c18f9a9 100644 --- a/esp-config/src/lib.rs +++ b/esp-config/src/lib.rs @@ -3,17 +3,30 @@ #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![cfg_attr(not(feature = "build"), no_std)] +#![deny(missing_docs, rust_2018_idioms)] #[cfg(feature = "build")] mod generate; #[cfg(feature = "build")] -pub use generate::*; +pub use generate::{generate_config, Error, Validator, Value}; +/// Parse the value of an environment variable as a [bool] at compile time. +#[macro_export] +macro_rules! esp_config_bool { + ( $var:expr ) => { + match env!($var).as_bytes() { + b"true" => true, + b"false" => false, + _ => ::core::panic!("boolean value must be either 'true' or 'false'"), + } + }; +} + +// TODO: From 1.82 on, we can use `<$ty>::from_str_radix(env!($var), 10)` +/// Parse the value of an environment variable as an integer at compile time. #[macro_export] -// TODO from 1.82 we can use <$ty>::from_str_radix(env!($var), 10) instead -/// Parse the value of a `env` variable as an integer at compile time macro_rules! esp_config_int { - ($ty:ty, $var:expr) => { + ( $ty:ty, $var:expr ) => { const { const BYTES: &[u8] = env!($var).as_bytes(); esp_config_int_parse!($ty, BYTES) @@ -21,63 +34,53 @@ macro_rules! esp_config_int { }; } +/// Get the string value of an environment variable at compile time. #[macro_export] -/// Get the string value of an `env` variable at compile time macro_rules! esp_config_str { - ($var:expr) => { + ( $var:expr ) => { env!($var) }; } -#[macro_export] -/// Parse the value of a `env` variable as an bool at compile time -macro_rules! esp_config_bool { - ($var:expr) => { - match env!($var).as_bytes() { - b"false" => false, - _ => true, - } - }; -} - -#[macro_export] -#[doc(hidden)] // to avoid confusion with esp_config_int, let's hide this /// Parse a string like "777" into an integer, which _can_ be used in a `const` /// context +#[doc(hidden)] // To avoid confusion with `esp_config_int`, hide this in the docs +#[macro_export] macro_rules! esp_config_int_parse { - ($ty:ty, $bytes:expr) => {{ + ( $ty:ty, $bytes:expr ) => {{ let mut bytes = $bytes; let mut val: $ty = 0; let mut sign_seen = false; let mut is_negative = false; + while let [byte, rest @ ..] = bytes { match *byte { b'0'..=b'9' => { val = val * 10 + (*byte - b'0') as $ty; } b'-' | b'+' if !sign_seen => { - if *byte == b'-' { - is_negative = true; - } + is_negative = *byte == b'-'; sign_seen = true; } - _ => ::core::panic!("invalid digit"), + _ => ::core::panic!("invalid character encountered while parsing integer"), } + bytes = rest; } + if is_negative { let original = val; - // subtract twice to get the negative + // Subtract the value twice to get a negative: val -= original; val -= original; } + val }}; } #[cfg(test)] mod test { - // We can only test success in the const context const _: () = { core::assert!(esp_config_int_parse!(i64, "-77777".as_bytes()) == -77777); @@ -98,4 +101,10 @@ mod test { fn test_expect_positive() { esp_config_int_parse!(u8, "-5".as_bytes()); } + + #[test] + #[should_panic] + fn test_invalid_digit() { + esp_config_int_parse!(u32, "a".as_bytes()); + } } diff --git a/esp-hal-embassy/build.rs b/esp-hal-embassy/build.rs index ff1606cbeef..5a4cf918864 100644 --- a/esp-hal-embassy/build.rs +++ b/esp-hal-embassy/build.rs @@ -43,8 +43,9 @@ fn main() -> Result<(), Box> { "esp_hal_embassy", &[( "low-power-wait", - Value::Bool(true), "Enables the lower-power wait if no tasks are ready to run on the thread-mode executor. This allows the MCU to use less power if the workload allows. Recommended for battery-powered systems. May impact analog performance.", + Value::Bool(true), + None )], true, ); diff --git a/esp-hal/build.rs b/esp-hal/build.rs index c507a97bd13..9e0f49684c0 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -80,23 +80,27 @@ fn main() -> Result<(), Box> { &[ ( "place-spi-driver-in-ram", - Value::Bool(false), "Places the SPI driver in RAM for better performance", + Value::Bool(false), + None ), ( "spi-address-workaround", - Value::Bool(true), "(ESP32 only) Enables a workaround for the issue where SPI in half-duplex mode incorrectly transmits the address on a single line if the data buffer is empty.", + Value::Bool(true), + None ), ( "place-switch-tables-in-ram", - Value::Bool(true), "Places switch-tables, some lookup tables and constants related to interrupt handling into RAM - resulting in better performance but slightly more RAM consumption.", + Value::Bool(true), + None ), ( "place-anon-in-ram", - Value::Bool(false), "Places anonymous symbols into RAM - resulting in better performance at the cost of significant more RAM consumption. Best to be combined with `place-switch-tables-in-ram`.", + Value::Bool(false), + None ), ], true, diff --git a/esp-ieee802154/build.rs b/esp-ieee802154/build.rs index f20eeeab3aa..ee788fa6433 100644 --- a/esp-ieee802154/build.rs +++ b/esp-ieee802154/build.rs @@ -1,6 +1,6 @@ use std::{env, path::PathBuf}; -use esp_config::{generate_config, Value}; +use esp_config::{generate_config, Validator, Value}; fn main() { let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); @@ -11,8 +11,9 @@ fn main() { "esp_ieee802154", &[( "rx_queue_size", - Value::UnsignedInteger(50), "Size of the RX queue in frames", + Value::Integer(50), + Some(Validator::PositiveInteger), )], true, ); diff --git a/esp-wifi/build.rs b/esp-wifi/build.rs index 4384034181b..e552a8e2ec4 100644 --- a/esp-wifi/build.rs +++ b/esp-wifi/build.rs @@ -1,7 +1,7 @@ use std::{error::Error, str::FromStr}; use esp_build::assert_unique_used_features; -use esp_config::{generate_config, Value}; +use esp_config::{generate_config, Validator, Value}; use esp_metadata::{Chip, Config}; fn main() -> Result<(), Box> { @@ -99,37 +99,134 @@ fn main() -> Result<(), Box> { generate_config( "esp_wifi", &[ - ("rx_queue_size", Value::UnsignedInteger(5), "Size of the RX queue in frames"), - ("tx_queue_size", Value::UnsignedInteger(3), "Size of the TX queue in frames"), - ("static_rx_buf_num", Value::UnsignedInteger(10), "WiFi static RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("dynamic_rx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("static_tx_buf_num", Value::UnsignedInteger(0), "WiFi static TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("dynamic_tx_buf_num", Value::UnsignedInteger(32), "WiFi dynamic TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("csi_enable", Value::Bool(false), "WiFi channel state information enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("ampdu_rx_enable", Value::Bool(true), "WiFi AMPDU RX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("ampdu_tx_enable", Value::Bool(true), "WiFi AMPDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("amsdu_tx_enable", Value::Bool(false), "WiFi AMSDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("rx_ba_win", Value::UnsignedInteger(6), "WiFi Block Ack RX window size. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)"), - ("max_burst_size", Value::UnsignedInteger(1), "See [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_burst_size)"), + ("rx_queue_size", "Size of the RX queue in frames", Value::Integer(5), Some(Validator::PositiveInteger)), + ("tx_queue_size", "Size of the TX queue in frames", Value::Integer(3), Some(Validator::PositiveInteger)), + ( + "static_rx_buf_num", + "WiFi static RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Integer(10), + None + ), + ( + "dynamic_rx_buf_num", + "WiFi dynamic RX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Integer(32), + None + ), + ( + "static_tx_buf_num", + "WiFi static TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Integer(0), + None + ), + ( + "dynamic_tx_buf_num", + "WiFi dynamic TX buffer number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Integer(32), + None + ), + ( + "csi_enable", + "WiFi channel state information enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Bool(false), + None + ), + ( + "ampdu_rx_enable", + "WiFi AMPDU RX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Bool(true), + None + ), + ( + "ampdu_tx_enable", + "WiFi AMPDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Bool(true), + None + ), + ( + "amsdu_tx_enable", + "WiFi AMSDU TX feature enable flag. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Bool(false), + None + ), + ( + "rx_ba_win", + "WiFi Block Ack RX window size. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html#_CPPv418wifi_init_config_t)", + Value::Integer(6), + None + ), + ( + "max_burst_size", + "See [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_burst_size)", + Value::Integer(1), + None + ), ( "country_code", - Value::String("CN".to_owned()), "Country code. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)", + Value::String("CN".to_owned()), + None ), ( "country_code_operating_class", - Value::UnsignedInteger(0), "If not 0: Operating Class table number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)", + Value::Integer(0), + None + ), + ( + "mtu", + "MTU, see [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_transmission_unit)", + Value::Integer(1492), + None + ), + ( + "tick_rate_hz", + "Tick rate of the internal task scheduler in hertz", + Value::Integer(100), + None + ), + ( + "listen_interval", + "Interval for station to listen to beacon from AP. The unit of listen interval is one beacon interval. For example, if beacon interval is 100 ms and listen interval is 3, the interval for station to listen to beacon is 300 ms", + Value::Integer(3), + None + ), + ( + "beacon_timeout", + "For Station, If the station does not receive a beacon frame from the connected SoftAP during the inactive time, disconnect from SoftAP. Default 6s. Range 6-30", + Value::Integer(6), + None + ), + ( + "ap_beacon_timeout", + "For SoftAP, If the SoftAP doesn't receive any data from the connected STA during inactive time, the SoftAP will force deauth the STA. Default is 300s", + Value::Integer(300), + None + ), + ( + "failure_retry_cnt", + "Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config. Note: Enabling this may cause connection time to increase incase best AP doesn't behave properly. Defaults to 1", + Value::Integer(1), + None + ), + ( + "scan_method", + "0 = WIFI_FAST_SCAN, 1 = WIFI_ALL_CHANNEL_SCAN, defaults to 0", + Value::Integer(0), + None + ), + ( + "dump_packets", + "Dump packets via an info log statement", + Value::Bool(false), + None + ), + ( + "phy_enable_usb", + "Keeps USB running when using WiFi. This allows debugging and log messages via USB Serial JTAG. Turn off for best WiFi performance.", + Value::Bool(true), + None ), - ("mtu", Value::UnsignedInteger(1492), "MTU, see [smoltcp's documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_transmission_unit)"), - ("tick_rate_hz", Value::UnsignedInteger(100), "Tick rate of the internal task scheduler in hertz"), - ("listen_interval", Value::UnsignedInteger(3), "Interval for station to listen to beacon from AP. The unit of listen interval is one beacon interval. For example, if beacon interval is 100 ms and listen interval is 3, the interval for station to listen to beacon is 300 ms"), - ("beacon_timeout", Value::UnsignedInteger(6), "For Station, If the station does not receive a beacon frame from the connected SoftAP during the inactive time, disconnect from SoftAP. Default 6s. Range 6-30"), - ("ap_beacon_timeout", Value::UnsignedInteger(300), "For SoftAP, If the SoftAP doesn’t receive any data from the connected STA during inactive time, the SoftAP will force deauth the STA. Default is 300s"), - ("failure_retry_cnt", Value::UnsignedInteger(1), "Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config. Note: Enabling this may cause connection time to increase incase best AP doesn't behave properly. Defaults to 1"), - ("scan_method", Value::UnsignedInteger(0), "0 = WIFI_FAST_SCAN, 1 = WIFI_ALL_CHANNEL_SCAN, defaults to 0"), - ("dump_packets", Value::Bool(false), "Dump packets via an info log statement"), - ("phy_enable_usb", Value::Bool(true), "Keeps USB running when using WiFi. This allows debugging and log messages via USB Serial JTAG. Turn off for best WiFi performance."), ], true ); From 321ca2f1311fc1ae86879dc6aecfa245427a957b Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Tue, 12 Nov 2024 02:17:11 -0800 Subject: [PATCH 53/67] Add `CHANGELOG.md` for remaining packages which do not have one (#2518) * Add `CHANGELOG.md` for remaining packages which do not have it * Update `changelog` workflow to check all relevant packages --- .github/workflows/changelog.yml | 63 ++++++++++++++++++++++++++++----- esp-build/CHANGELOG.md | 24 +++++++++++++ esp-config/CHANGELOG.md | 22 ++++++++++++ esp-hal-procmacros/CHANGELOG.md | 48 +++++++++++++++++++++++++ esp-metadata/CHANGELOG.md | 30 ++++++++++++++++ xtensa-lx/CHANGELOG.md | 32 +++++++++++++++++ 6 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 esp-build/CHANGELOG.md create mode 100644 esp-config/CHANGELOG.md create mode 100644 esp-hal-procmacros/CHANGELOG.md create mode 100644 esp-metadata/CHANGELOG.md create mode 100644 xtensa-lx/CHANGELOG.md diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 4a7d24d845d..2f59525cc2f 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -2,16 +2,13 @@ name: Changelog check on: pull_request: - # We will not track changes for the following packages. + # We will not track changes for the following packages/directories. paths-ignore: - - "/xtask/" - - "/esp-build/" - - "/esp-hal-procmacros/" - - "/esp-metadata/" - "/examples/" - - "/hil-tests/" - "/extras/" + - "/hil-tests/" - "/resources/" + - "/xtask/" # Run on labeled/unlabeled in addition to defaults to detect # adding/removing skip-changelog labels. types: [opened, reopened, labeled, unlabeled, synchronize] @@ -33,24 +30,34 @@ jobs: - 'esp-alloc/**' esp-backtrace: - 'esp-backtrace/**' + esp-build: + - 'esp-build/**' + esp-config: + - 'esp-config/**' esp-hal: - 'esp-hal/**' esp-hal-embassy: - 'esp-hal-embassy/**' + esp-hal-procmacros: + - 'esp-hal-procmacros/**' esp-ieee802154: - 'esp-ieee802154/**' esp-lp-hal: - 'esp-lp-hal/**' + esp-metadata: + - 'esp-metadata/**' esp-println: - 'esp-println/**' esp-riscv-rt: - 'esp-riscv-rt/**' - xtensa-lx-rt: - - 'xtensa-lx-rt/**' esp-storage: - 'esp-storage/**' esp-wifi: - 'esp-wifi/**' + xtensa-lx: + - 'xtensa-lx/**' + xtensa-lx-rt: + - 'xtensa-lx-rt/**' - name: Check that changelog updated (esp-alloc) if: steps.changes.outputs.esp-alloc == 'true' @@ -68,6 +75,22 @@ jobs: skipLabels: "skip-changelog" missingUpdateErrorMessage: "Please add a changelog entry in the esp-backtrace/CHANGELOG.md file." + - name: Check that changelog updated (esp-build) + if: steps.changes.outputs.esp-build == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: esp-build/CHANGELOG.md + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the esp-build/CHANGELOG.md file." + + - name: Check that changelog updated (esp-config) + if: steps.changes.outputs.esp-config == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: esp-config/CHANGELOG.md + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the esp-config/CHANGELOG.md file." + - name: Check that changelog updated (esp-hal) if: steps.changes.outputs.esp-hal == 'true' uses: dangoslen/changelog-enforcer@v3 @@ -84,6 +107,14 @@ jobs: skipLabels: "skip-changelog" missingUpdateErrorMessage: "Please add a changelog entry in the esp-hal-embassy/CHANGELOG.md file." + - name: Check that changelog updated (esp-hal-procmacros) + if: steps.changes.outputs.esp-hal-procmacros == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: esp-hal-procmacros/CHANGELOG.md + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the esp-hal-procmacros/CHANGELOG.md file." + - name: Check that changelog updated (esp-ieee802154) if: steps.changes.outputs.esp-ieee802154 == 'true' uses: dangoslen/changelog-enforcer@v3 @@ -131,3 +162,19 @@ jobs: changeLogPath: esp-wifi/CHANGELOG.md skipLabels: "skip-changelog" missingUpdateErrorMessage: "Please add a changelog entry in the esp-wifi/CHANGELOG.md file." + + - name: Check that changelog updated (xtensa-lx) + if: steps.changes.outputs.xtensa-lx == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: xtensa-lx/CHANGELOG.md + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the xtensa-lx/CHANGELOG.md file." + + - name: Check that changelog updated (xtensa-lx-rt) + if: steps.changes.outputs.xtensa-lx-rt == 'true' + uses: dangoslen/changelog-enforcer@v3 + with: + changeLogPath: xtensa-lx-rt/CHANGELOG.md + skipLabels: "skip-changelog" + missingUpdateErrorMessage: "Please add a changelog entry in the xtensa-lx-rt/CHANGELOG.md file." diff --git a/esp-build/CHANGELOG.md b/esp-build/CHANGELOG.md new file mode 100644 index 00000000000..50b75908901 --- /dev/null +++ b/esp-build/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog + +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.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Fixed + +### Changed + +- Use `panic` instead of `process::exit` in esp-build (#2402 ) + +### Removed + +## [0.1.0] - 2024-04-17 + +- Initial release + +[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-build?since=2024-04-17 diff --git a/esp-config/CHANGELOG.md b/esp-config/CHANGELOG.md new file mode 100644 index 00000000000..4066e9b0323 --- /dev/null +++ b/esp-config/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +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.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Fixed + +### Changed + +### Removed + +## [0.1.0] - 2024-10-10 + +- Initial release + +[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-config?since=2024-10-10 diff --git a/esp-hal-procmacros/CHANGELOG.md b/esp-hal-procmacros/CHANGELOG.md new file mode 100644 index 00000000000..84d7f1c0ed0 --- /dev/null +++ b/esp-hal-procmacros/CHANGELOG.md @@ -0,0 +1,48 @@ +# Changelog + +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.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Fixed + +### Changed + +### Removed + +## [0.14.0] - 2024-10-10 + +## [0.13.0] - 2024-08-29 + +## [0.12.0] - 2024-07-15 + +## [0.11.0] - 2024-06-04 + +## [0.10.0] - 2024-04-18 + +## [0.9.0] - 2024-03-18 + +## [0.8.0] - 2023-12-12 + +## [0.7.0] - 2023-10-31 + +## [0.6.1] - 2023-09-05 + +## [0.6.0] - 2023-07-04 + +## [0.5.0] - 2023-03-27 + +## [0.4.0] - 2023-02-21 + +## [0.2.0] - 2023-01-26 + +## [0.1.0] - 2022-08-25 + +- Initial release + +[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-hal-procmacros?since=2024-10-10 diff --git a/esp-metadata/CHANGELOG.md b/esp-metadata/CHANGELOG.md new file mode 100644 index 00000000000..ea6930f68c0 --- /dev/null +++ b/esp-metadata/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +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.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Fixed + +### Changed + +### Removed + +## [0.4.0] - 2024-10-10 + +## [0.3.0] - 2024-08-29 + +## [0.2.0] - 2024-07-15 + +## [0.1.1] - 2024-06-04 + +## [0.1.0] - 2024-04-17 + +- Initial release + +[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/esp-metadata?since=2024-10-10 diff --git a/xtensa-lx/CHANGELOG.md b/xtensa-lx/CHANGELOG.md new file mode 100644 index 00000000000..4161f06a347 --- /dev/null +++ b/xtensa-lx/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +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.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Fixed + +### Changed + +### Removed + +## [0.9.0] - 2024-02-21 + +## [0.8.0] - 2023-02-23 + +## [0.7.0] - 2022-04-20 + +## [0.6.0] - 2022-01-16 + +## [0.5.0] - 2022-01-15 + +## [0.4.0] - 2021-08-11 + +## [0.3.0] - 2020-09-19 + +[Unreleased]: https://github.com/esp-rs/esp-hal/commits/main/xtensa-lx?since=2024-02-21 From fbc57542a8f4b71e30f0dcea4045c508ce753139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 11:36:25 +0100 Subject: [PATCH 54/67] Remove pins from `Io` (#2508) * Split pins off of Io * Remove the GPIO peripheral * p.GPIO --- esp-hal/CHANGELOG.md | 2 + esp-hal/MIGRATING-0.21.md | 18 ++ esp-hal/src/analog/adc/mod.rs | 8 +- esp-hal/src/analog/dac.rs | 7 +- esp-hal/src/dma/mod.rs | 10 +- esp-hal/src/etm.rs | 6 +- esp-hal/src/gpio/etm.rs | 6 +- esp-hal/src/gpio/lp_io.rs | 7 +- esp-hal/src/gpio/mod.rs | 104 ++++------ esp-hal/src/gpio/rtc_io.rs | 4 +- esp-hal/src/i2c/master/mod.rs | 6 +- esp-hal/src/i2s/master.rs | 10 +- esp-hal/src/lcd_cam/cam.rs | 26 ++- esp-hal/src/lcd_cam/lcd/i8080.rs | 20 +- esp-hal/src/ledc/mod.rs | 4 +- esp-hal/src/lib.rs | 3 +- esp-hal/src/mcpwm/mod.rs | 5 +- esp-hal/src/mcpwm/operator.rs | 6 +- esp-hal/src/peripheral.rs | 99 +++++---- esp-hal/src/rmt.rs | 4 +- esp-hal/src/rng.rs | 16 +- esp-hal/src/rom/md5.rs | 8 +- esp-hal/src/rtc_cntl/sleep/esp32c6.rs | 34 ++-- esp-hal/src/soc/esp32/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32/gpio.rs | 47 +---- esp-hal/src/soc/esp32/peripherals.rs | 147 +++++++++----- esp-hal/src/soc/esp32c2/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32c2/gpio.rs | 17 -- esp-hal/src/soc/esp32c2/peripherals.rs | 89 +++++---- esp-hal/src/soc/esp32c3/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32c3/gpio.rs | 25 --- esp-hal/src/soc/esp32c3/peripherals.rs | 107 ++++++---- esp-hal/src/soc/esp32c6/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32c6/gpio.rs | 34 ---- esp-hal/src/soc/esp32c6/peripherals.rs | 188 +++++++++++------- esp-hal/src/soc/esp32h2/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32h2/gpio.rs | 36 +--- esp-hal/src/soc/esp32h2/peripherals.rs | 165 ++++++++------- esp-hal/src/soc/esp32s2/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32s2/gpio.rs | 47 ----- esp-hal/src/soc/esp32s2/peripherals.rs | 145 +++++++++----- esp-hal/src/soc/esp32s3/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32s3/gpio.rs | 48 ----- esp-hal/src/soc/esp32s3/peripherals.rs | 166 ++++++++++------ esp-hal/src/spi/master.rs | 10 +- esp-hal/src/spi/slave.rs | 10 +- esp-hal/src/touch.rs | 4 +- esp-hal/src/twai/mod.rs | 12 +- esp-hal/src/uart.rs | 33 +-- examples/src/bin/adc.rs | 8 +- examples/src/bin/adc_cal.rs | 6 +- examples/src/bin/advanced_serial.rs | 6 +- examples/src/bin/blinky.rs | 6 +- examples/src/bin/blinky_erased_pins.rs | 14 +- examples/src/bin/dac.rs | 12 +- examples/src/bin/embassy_i2c.rs | 7 +- .../embassy_i2c_bmp180_calibration_data.rs | 7 +- examples/src/bin/embassy_i2s_parallel.rs | 20 +- examples/src/bin/embassy_i2s_read.rs | 11 +- examples/src/bin/embassy_i2s_sound.rs | 9 +- examples/src/bin/embassy_multicore.rs | 6 +- .../src/bin/embassy_multicore_interrupt.rs | 6 +- examples/src/bin/embassy_parl_io_rx.rs | 10 +- examples/src/bin/embassy_parl_io_tx.rs | 14 +- examples/src/bin/embassy_rmt_rx.rs | 12 +- examples/src/bin/embassy_rmt_tx.rs | 5 +- examples/src/bin/embassy_serial.rs | 15 +- examples/src/bin/embassy_spi.rs | 10 +- examples/src/bin/embassy_touch.rs | 6 +- examples/src/bin/embassy_twai.rs | 9 +- examples/src/bin/embassy_usb_serial.rs | 5 +- examples/src/bin/embassy_wait.rs | 8 +- examples/src/bin/etm_blinky_systimer.rs | 4 +- examples/src/bin/etm_gpio.rs | 7 +- examples/src/bin/gpio_interrupt.rs | 8 +- examples/src/bin/hello_world.rs | 16 +- .../src/bin/i2c_bmp180_calibration_data.rs | 7 +- examples/src/bin/i2c_display.rs | 6 +- examples/src/bin/i2s_parallel.rs | 20 +- examples/src/bin/i2s_read.rs | 11 +- examples/src/bin/i2s_sound.rs | 9 +- examples/src/bin/ieee802154_sniffer.rs | 8 +- examples/src/bin/lcd_cam_ov2640.rs | 31 ++- examples/src/bin/lcd_i8080.rs | 30 ++- examples/src/bin/ledc.rs | 4 +- examples/src/bin/lp_core_basic.rs | 6 +- examples/src/bin/lp_core_i2c.rs | 8 +- examples/src/bin/lp_core_uart.rs | 15 +- examples/src/bin/mcpwm.rs | 4 +- examples/src/bin/parl_io_rx.rs | 10 +- examples/src/bin/parl_io_tx.rs | 14 +- examples/src/bin/pcnt_encoder.rs | 8 +- examples/src/bin/qspi_flash.rs | 26 ++- examples/src/bin/rmt_rx.rs | 11 +- examples/src/bin/rmt_tx.rs | 8 +- examples/src/bin/serial_interrupts.rs | 15 +- examples/src/bin/sleep_timer_ext0.rs | 5 +- examples/src/bin/sleep_timer_ext1.rs | 7 +- examples/src/bin/sleep_timer_lpio.rs | 7 +- examples/src/bin/sleep_timer_rtcio.rs | 11 +- .../spi_halfduplex_read_manufacturer_id.rs | 26 ++- examples/src/bin/spi_loopback.rs | 8 +- examples/src/bin/spi_loopback_dma.rs | 10 +- examples/src/bin/spi_loopback_dma_psram.rs | 8 +- examples/src/bin/spi_slave_dma.rs | 20 +- examples/src/bin/touch.rs | 8 +- examples/src/bin/twai.rs | 9 +- examples/src/bin/ulp_riscv_core_basic.rs | 9 +- examples/src/bin/usb_serial.rs | 5 +- examples/src/bin/wifi_ble.rs | 8 +- examples/src/bin/wifi_embassy_ble.rs | 7 +- hil-test/src/lib.rs | 34 ++-- hil-test/tests/embassy_interrupt_spi_dma.rs | 4 +- hil-test/tests/gpio.rs | 8 +- hil-test/tests/gpio_custom_handler.rs | 8 +- hil-test/tests/i2c.rs | 4 +- hil-test/tests/i2s.rs | 28 +-- hil-test/tests/lcd_cam_i8080.rs | 43 ++-- hil-test/tests/parl_io_tx.rs | 6 +- hil-test/tests/parl_io_tx_async.rs | 6 +- hil-test/tests/pcnt.rs | 6 +- hil-test/tests/qspi.rs | 8 +- hil-test/tests/rmt.rs | 5 +- hil-test/tests/spi_full_duplex.rs | 7 +- hil-test/tests/spi_half_duplex_read.rs | 7 +- hil-test/tests/spi_half_duplex_write.rs | 7 +- hil-test/tests/spi_half_duplex_write_psram.rs | 7 +- hil-test/tests/spi_slave.rs | 10 +- hil-test/tests/twai.rs | 5 +- hil-test/tests/uart.rs | 5 +- hil-test/tests/uart_async.rs | 6 +- hil-test/tests/uart_regression.rs | 5 +- hil-test/tests/uart_tx_rx.rs | 5 +- hil-test/tests/uart_tx_rx_async.rs | 5 +- 134 files changed, 1217 insertions(+), 1429 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 224d81239b0..b056d84a6de 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -171,6 +171,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPI transactions are now cancelled if the transfer object (or async Future) is dropped. (#2216) - The DMA channel types have been removed from peripherals (#2261) - `I2C` driver renamed to `I2c` (#2320) +- The GPIO pins are now accessible via `Peripherals` and are no longer part of the `Io` struct (#2508) ### Fixed @@ -215,6 +216,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `esp_hal::spi::slave::WithDmaSpiN` traits (#2260) - The `WithDmaAes` trait has been removed (#2261) - The `I2s::new_i2s1` constructor has been removed (#2261) +- `Peripherals.GPIO` has been removed (#2508) ## [0.20.1] - 2024-08-30 diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 57460bd8037..9304bddd0b6 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -1,5 +1,23 @@ # Migration Guide from 0.21.x to v0.22.x +## IO changes + +### GPIO pins are now accessible via `Peripherals` + +```diff + let peripherals = esp_hal::init(Default::default()); +-let io = Io::new(peripherals.GPIO, peripherals.IOMUX); +-let pin = io.pins.gpio5; ++let pin = peripherals.GPIO5; +``` + +### `Io` constructor changes + +- `new_with_priority` and `new_no_bind_interrupts` have been removed. + Use `set_priority` to configure the GPIO interrupt priority. + We no longer overwrite interrupt handlers set by user code during initialization. +- `new` no longer takes `peripherals.GPIO` + ## Removed `async`-specific constructors The following async-specific constuctors have been removed: diff --git a/esp-hal/src/analog/adc/mod.rs b/esp-hal/src/analog/adc/mod.rs index b7d4e58d2a8..0f8f76067c5 100644 --- a/esp-hal/src/analog/adc/mod.rs +++ b/esp-hal/src/analog/adc/mod.rs @@ -31,13 +31,11 @@ //! # use esp_hal::analog::adc::Attenuation; //! # use esp_hal::analog::adc::Adc; //! # use esp_hal::delay::Delay; -//! # use esp_hal::gpio::Io; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -#![cfg_attr(esp32, doc = "let analog_pin = io.pins.gpio32;")] -#![cfg_attr(any(esp32s2, esp32s3), doc = "let analog_pin = io.pins.gpio3;")] +#![cfg_attr(esp32, doc = "let analog_pin = peripherals.GPIO32;")] +#![cfg_attr(any(esp32s2, esp32s3), doc = "let analog_pin = peripherals.GPIO3;")] #![cfg_attr( not(any(esp32, esp32s2, esp32s3)), - doc = "let analog_pin = io.pins.gpio2;" + doc = "let analog_pin = peripherals.GPIO2;" )] //! let mut adc1_config = AdcConfig::new(); //! let mut pin = adc1_config.enable_pin( diff --git a/esp-hal/src/analog/dac.rs b/esp-hal/src/analog/dac.rs index 8cb1e859db3..246dfa796c0 100644 --- a/esp-hal/src/analog/dac.rs +++ b/esp-hal/src/analog/dac.rs @@ -17,14 +17,11 @@ //! ### Write a value to a DAC channel //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::gpio::Io; //! # use esp_hal::analog::dac::Dac; //! # use esp_hal::delay::Delay; //! # use embedded_hal::delay::DelayNs; -//! -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -#![cfg_attr(esp32, doc = "let dac1_pin = io.pins.gpio25;")] -#![cfg_attr(esp32s2, doc = "let dac1_pin = io.pins.gpio17;")] +#![cfg_attr(esp32, doc = "let dac1_pin = peripherals.GPIO25;")] +#![cfg_attr(esp32s2, doc = "let dac1_pin = peripherals.GPIO17;")] //! let mut dac1 = Dac::new(peripherals.DAC1, dac1_pin); //! //! let mut delay = Delay::new(); diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 0cfbb2e5269..e88776e423b 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -18,17 +18,15 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::dma_buffers; -//! # use esp_hal::gpio::Io; //! # use esp_hal::spi::{master::{Config, Spi}, SpiMode}; //! # use esp_hal::dma::{Dma, DmaPriority}; //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = dma.spi2channel;")] #![cfg_attr(not(any(esp32, esp32s2)), doc = "let dma_channel = dma.channel0;")] -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let sclk = io.pins.gpio0; -//! let miso = io.pins.gpio2; -//! let mosi = io.pins.gpio4; -//! let cs = io.pins.gpio5; +//! let sclk = peripherals.GPIO0; +//! let miso = peripherals.GPIO2; +//! let mosi = peripherals.GPIO4; +//! let cs = peripherals.GPIO5; //! //! let mut spi = Spi::new_with_config( //! peripherals.SPI2, diff --git a/esp-hal/src/etm.rs b/esp-hal/src/etm.rs index f2c603a67e7..5276eadcccf 100644 --- a/esp-hal/src/etm.rs +++ b/esp-hal/src/etm.rs @@ -23,15 +23,13 @@ //! ## Examples //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::gpio::Io; //! # use esp_hal::gpio::etm::{Channels, InputConfig, OutputConfig}; //! # use esp_hal::etm::Etm; //! # use esp_hal::gpio::Pull; //! # use esp_hal::gpio::Level; //! -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let mut led = io.pins.gpio1; -//! let button = io.pins.gpio9; +//! let mut led = peripherals.GPIO1; +//! let button = peripherals.GPIO9; //! //! // setup ETM //! let gpio_ext = Channels::new(peripherals.GPIO_SD); diff --git a/esp-hal/src/gpio/etm.rs b/esp-hal/src/gpio/etm.rs index 1cae2982a79..4ff74e67804 100644 --- a/esp-hal/src/gpio/etm.rs +++ b/esp-hal/src/gpio/etm.rs @@ -25,7 +25,6 @@ //! ### Toggle an LED When a Button is Pressed //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::gpio::Io; //! # use esp_hal::gpio::etm::Channels; //! # use esp_hal::etm::Etm; //! # use esp_hal::gpio::etm::InputConfig; @@ -33,9 +32,8 @@ //! # use esp_hal::gpio::Pull; //! # use esp_hal::gpio::Level; //! # -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut led = io.pins.gpio1; -//! # let button = io.pins.gpio9; +//! # let mut led = peripherals.GPIO1; +//! # let button = peripherals.GPIO9; //! //! let gpio_ext = Channels::new(peripherals.GPIO_SD); //! let led_task = gpio_ext.channel0_task.toggle( diff --git a/esp-hal/src/gpio/lp_io.rs b/esp-hal/src/gpio/lp_io.rs index 4eb849f83c0..947a9efc7e8 100644 --- a/esp-hal/src/gpio/lp_io.rs +++ b/esp-hal/src/gpio/lp_io.rs @@ -15,14 +15,15 @@ //! chip from Deep-sleep. //! //! # Example +//! //! ## Configure a LP Pin as Output +//! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! use esp_hal::gpio::Io; //! use esp_hal::gpio::lp_io::LowPowerOutput; -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! // configure GPIO 1 as LP output pin -//! let lp_pin: LowPowerOutput<'_, 1> = LowPowerOutput::new(io.pins.gpio1); +//! let lp_pin: LowPowerOutput<'_, 1> = +//! LowPowerOutput::new(peripherals.GPIO1); //! # } //! ``` diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 672021f9df0..c15dacbe529 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -18,9 +18,10 @@ //! GPIO interrupts. For more information, see the //! [`Io::set_interrupt_handler`]. //! -//! The pins are accessible via [`Io::pins`]. These pins can then be passed to -//! peripherals (such as SPI, UART, I2C, etc.), to pin drivers or can be -//! [`GpioPin::split`] into peripheral signals. +//! The pins are accessible via the [`crate::Peripherals`] struct returned by +//! [`crate::init`]. These pins can then be passed to peripherals (such as +//! SPI, UART, I2C, etc.), to pin drivers or can be [`GpioPin::split`] into +//! peripheral signals. //! //! Each pin is a different type initially. Internally, `esp-hal` will often //! erase their types automatically, but they can also be converted into @@ -52,8 +53,7 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::gpio::{Io, Level, Output}; -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let mut led = Output::new(io.pins.gpio5, Level::High); +//! let mut led = Output::new(peripherals.GPIO5, Level::High); //! # } //! ``` //! @@ -71,11 +71,18 @@ use portable_atomic::{AtomicPtr, Ordering}; use procmacros::ram; +#[cfg(any(lp_io, rtc_cntl))] +use crate::peripherals::gpio::{handle_rtcio, handle_rtcio_with_resistors}; pub use crate::soc::gpio::*; use crate::{ interrupt::{self, InterruptHandler, Priority}, peripheral::{Peripheral, PeripheralRef}, - peripherals::{Interrupt, GPIO, IO_MUX}, + peripherals::{ + gpio::{handle_gpio_input, handle_gpio_output, AnyPinInner}, + Interrupt, + GPIO, + IO_MUX, + }, private::{self, Sealed}, InterruptConfigurable, DEFAULT_INTERRUPT_HANDLER, @@ -716,6 +723,9 @@ impl Bank1GpioRegisterAccess { /// GPIO pin pub struct GpioPin; +/// Type-erased GPIO pin +pub struct AnyPin(pub(crate) AnyPinInner); + impl GpioPin where Self: Pin, @@ -813,17 +823,12 @@ pub(crate) fn bind_default_interrupt_handler() { /// General Purpose Input/Output driver pub struct Io { _io_mux: IO_MUX, - /// The pins available on this chip - pub pins: Pins, } impl Io { /// Initialize the I/O driver. - pub fn new(_gpio: GPIO, _io_mux: IO_MUX) -> Self { - Io { - _io_mux, - pins: unsafe { Pins::steal() }, - } + pub fn new(_io_mux: IO_MUX) -> Self { + Io { _io_mux } } /// Set the interrupt priority for GPIO interrupts. @@ -911,20 +916,20 @@ macro_rules! if_rtcio_pin { #[macro_export] macro_rules! io_type { (Input, $gpionum:literal) => { - impl $crate::gpio::InputPin for GpioPin<$gpionum> {} + impl $crate::gpio::InputPin for $crate::gpio::GpioPin<$gpionum> {} }; (Output, $gpionum:literal) => { - impl $crate::gpio::OutputPin for GpioPin<$gpionum> {} + impl $crate::gpio::OutputPin for $crate::gpio::GpioPin<$gpionum> {} }; (Analog, $gpionum:literal) => { // FIXME: the implementation shouldn't be in the GPIO module #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))] - impl $crate::gpio::AnalogPin for GpioPin<$gpionum> { + impl $crate::gpio::AnalogPin for $crate::gpio::GpioPin<$gpionum> { /// Configures the pin for analog mode. fn set_analog(&self, _: $crate::private::Internal) { use $crate::peripherals::GPIO; - get_io_mux_reg($gpionum).modify(|_, w| unsafe { + $crate::gpio::get_io_mux_reg($gpionum).modify(|_, w| unsafe { w.mcu_sel().bits(1); w.fun_ie().clear_bit(); w.fun_wpu().clear_bit(); @@ -956,91 +961,70 @@ macro_rules! gpio { )+ ) => { paste::paste! { - /// Pins available on this chip - pub struct Pins { - $( - #[doc = concat!("GPIO pin number ", $gpionum, ".")] - pub [< gpio $gpionum >] : GpioPin<$gpionum>, - )+ - } - - impl Pins { - /// Unsafely create GPIO pins. - /// - /// # Safety - /// - /// The caller must ensure that only one instance of a pin is in use at one time. - pub unsafe fn steal() -> Self { - Self { - $( - [< gpio $gpionum >]: GpioPin::steal(), - )+ - } - } - } - $( $( $crate::io_type!($type, $gpionum); )* - impl $crate::gpio::Pin for GpioPin<$gpionum> { + impl $crate::gpio::Pin for $crate::gpio::GpioPin<$gpionum> { fn number(&self) -> u8 { $gpionum } - fn degrade_pin(&self, _: $crate::private::Internal) -> AnyPin { - AnyPin($crate::gpio::AnyPinInner::[< Gpio $gpionum >](unsafe { Self::steal() })) + fn degrade_pin(&self, _: $crate::private::Internal) -> $crate::gpio::AnyPin { + $crate::gpio::AnyPin(AnyPinInner::[< Gpio $gpionum >](unsafe { Self::steal() })) } fn gpio_bank(&self, _: $crate::private::Internal) -> $crate::gpio::GpioRegisterAccess { $crate::gpio::GpioRegisterAccess::from($gpionum) } - fn output_signals(&self, _: $crate::private::Internal) -> &[(AlternateFunction, OutputSignal)] { + fn output_signals(&self, _: $crate::private::Internal) -> &[($crate::gpio::AlternateFunction, $crate::gpio::OutputSignal)] { &[ $( $( - (AlternateFunction::[< Function $af_output_num >], OutputSignal::$af_output_signal ), + ( + $crate::gpio::AlternateFunction::[< Function $af_output_num >], + $crate::gpio::OutputSignal::$af_output_signal + ), )* )? ] } - fn input_signals(&self, _: $crate::private::Internal) -> &[(AlternateFunction, InputSignal)] { + fn input_signals(&self, _: $crate::private::Internal) -> &[($crate::gpio::AlternateFunction, $crate::gpio::InputSignal)] { &[ $( $( - (AlternateFunction::[< Function $af_input_num >], InputSignal::$af_input_signal ), + ( + $crate::gpio::AlternateFunction::[< Function $af_input_num >], + $crate::gpio::InputSignal::$af_input_signal + ), )* )? ] } } - impl From> for AnyPin { - fn from(pin: GpioPin<$gpionum>) -> Self { - use $crate::gpio::Pin; - pin.degrade() + impl From<$crate::gpio::GpioPin<$gpionum>> for $crate::gpio::AnyPin { + fn from(pin: $crate::gpio::GpioPin<$gpionum>) -> Self { + $crate::gpio::Pin::degrade(pin) } } )+ pub(crate) enum AnyPinInner { $( - [](GpioPin<$gpionum>), + []($crate::gpio::GpioPin<$gpionum>), )+ } - /// Type-erased GPIO pin - pub struct AnyPin(pub(crate) AnyPinInner); - - impl $crate::peripheral::Peripheral for AnyPin { - type P = AnyPin; + impl $crate::peripheral::Peripheral for $crate::gpio::AnyPin { + type P = $crate::gpio::AnyPin; unsafe fn clone_unchecked(&self) -> Self { match self.0 { $(AnyPinInner::[](_) => { - Self(AnyPinInner::[< Gpio $gpionum >](unsafe { GpioPin::steal() })) + Self(AnyPinInner::[< Gpio $gpionum >](unsafe { $crate::gpio::GpioPin::steal() })) })+ } } @@ -1049,7 +1033,6 @@ macro_rules! gpio { // These macros call the code block on the actually contained GPIO pin. #[doc(hidden)] - #[macro_export] macro_rules! handle_gpio_output { ($this:expr, $inner:ident, $code:tt) => { match $this { @@ -1066,7 +1049,6 @@ macro_rules! gpio { } #[doc(hidden)] - #[macro_export] macro_rules! handle_gpio_input { ($this:expr, $inner:ident, $code:tt) => { match $this { @@ -1083,7 +1065,6 @@ macro_rules! gpio { cfg_if::cfg_if! { if #[cfg(any(lp_io, rtc_cntl))] { #[doc(hidden)] - #[macro_export] macro_rules! handle_rtcio { ($this:expr, $inner:ident, $code:tt) => { match $this { @@ -1100,7 +1081,6 @@ macro_rules! gpio { } #[doc(hidden)] - #[macro_export] macro_rules! handle_rtcio_with_resistors { ($this:expr, $inner:ident, $code:tt) => { match $this { diff --git a/esp-hal/src/gpio/rtc_io.rs b/esp-hal/src/gpio/rtc_io.rs index 2eb87a1714e..beebc37e3d4 100644 --- a/esp-hal/src/gpio/rtc_io.rs +++ b/esp-hal/src/gpio/rtc_io.rs @@ -23,10 +23,8 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::gpio::rtc_io::LowPowerOutput; -//! # use esp_hal::gpio::Io; -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! // configure GPIO 1 as ULP output pin -//! let lp_pin = LowPowerOutput::<'static, 1>::new(io.pins.gpio1); +//! let lp_pin = LowPowerOutput::<'static, 1>::new(peripherals.GPIO1); //! # } //! ``` diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index b6e07e3f97f..681eeab1f5c 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -19,8 +19,6 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::i2c::master::{Config, I2c}; -//! # use esp_hal::gpio::Io; -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! // Create a new peripheral object with the described wiring //! // and standard I2C clock speed. @@ -28,8 +26,8 @@ //! peripherals.I2C0, //! Config::default(), //! ) -//! .with_sda(io.pins.gpio1) -//! .with_scl(io.pins.gpio2); +//! .with_sda(peripherals.GPIO1) +//! .with_scl(peripherals.GPIO2); //! //! loop { //! let mut data = [0u8; 22]; diff --git a/esp-hal/src/i2s/master.rs b/esp-hal/src/i2s/master.rs index 6a418b966e8..95a33d62399 100644 --- a/esp-hal/src/i2s/master.rs +++ b/esp-hal/src/i2s/master.rs @@ -30,10 +30,8 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::i2s::master::{I2s, Standard, DataFormat}; -//! # use esp_hal::gpio::Io; //! # use esp_hal::dma_buffers; //! # use esp_hal::dma::{Dma, DmaPriority}; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(any(esp32, esp32s2), doc = "let dma_channel = dma.i2s0channel;")] #![cfg_attr(not(any(esp32, esp32s2)), doc = "let dma_channel = dma.channel0;")] @@ -52,11 +50,11 @@ //! rx_descriptors, //! tx_descriptors, //! ); -#![cfg_attr(not(esp32), doc = "let i2s = i2s.with_mclk(io.pins.gpio0);")] +#![cfg_attr(not(esp32), doc = "let i2s = i2s.with_mclk(peripherals.GPIO0);")] //! let mut i2s_rx = i2s.i2s_rx -//! .with_bclk(io.pins.gpio1) -//! .with_ws(io.pins.gpio2) -//! .with_din(io.pins.gpio5) +//! .with_bclk(peripherals.GPIO1) +//! .with_ws(peripherals.GPIO2) +//! .with_din(peripherals.GPIO5) //! .build(); //! //! let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap(); diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index 5cb3b9cf263..5125d8b343d 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -16,12 +16,10 @@ //! master mode. //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::gpio::Io; //! # use esp_hal::lcd_cam::{cam::{Camera, RxEightBits}, LcdCam}; //! # use fugit::RateExtU32; //! # use esp_hal::dma_rx_stream_buffer; //! # use esp_hal::dma::{Dma, DmaPriority}; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! # let dma = Dma::new(peripherals.DMA); //! # let channel = dma.channel0; @@ -33,19 +31,19 @@ //! # DmaPriority::Priority0, //! # ); //! -//! let mclk_pin = io.pins.gpio15; -//! let vsync_pin = io.pins.gpio6; -//! let href_pin = io.pins.gpio7; -//! let pclk_pin = io.pins.gpio13; +//! let mclk_pin = peripherals.GPIO15; +//! let vsync_pin = peripherals.GPIO6; +//! let href_pin = peripherals.GPIO7; +//! let pclk_pin = peripherals.GPIO13; //! let data_pins = RxEightBits::new( -//! io.pins.gpio11, -//! io.pins.gpio9, -//! io.pins.gpio8, -//! io.pins.gpio10, -//! io.pins.gpio12, -//! io.pins.gpio18, -//! io.pins.gpio17, -//! io.pins.gpio16, +//! peripherals.GPIO11, +//! peripherals.GPIO9, +//! peripherals.GPIO8, +//! peripherals.GPIO10, +//! peripherals.GPIO12, +//! peripherals.GPIO18, +//! peripherals.GPIO17, +//! peripherals.GPIO16, //! ); //! //! let lcd_cam = LcdCam::new(peripherals.LCD_CAM); diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 754c5f0e413..109b658aa39 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -15,11 +15,9 @@ //! //! ```rust, no_run #![doc = crate::before_snippet!()] -//! # use esp_hal::gpio::Io; //! # use esp_hal::lcd_cam::{LcdCam, lcd::i8080::{Config, I8080, TxEightBits}}; //! # use esp_hal::dma_tx_buffer; //! # use esp_hal::dma::{Dma, DmaPriority, DmaTxBuf}; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! # let dma = Dma::new(peripherals.DMA); //! # let channel = dma.channel0; @@ -32,14 +30,14 @@ //! # ); //! //! let tx_pins = TxEightBits::new( -//! io.pins.gpio9, -//! io.pins.gpio46, -//! io.pins.gpio3, -//! io.pins.gpio8, -//! io.pins.gpio18, -//! io.pins.gpio17, -//! io.pins.gpio16, -//! io.pins.gpio15, +//! peripherals.GPIO9, +//! peripherals.GPIO46, +//! peripherals.GPIO3, +//! peripherals.GPIO8, +//! peripherals.GPIO18, +//! peripherals.GPIO17, +//! peripherals.GPIO16, +//! peripherals.GPIO15, //! ); //! let lcd_cam = LcdCam::new(peripherals.LCD_CAM); //! @@ -50,7 +48,7 @@ //! 20.MHz(), //! Config::default(), //! ) -//! .with_ctrl_pins(io.pins.gpio0, io.pins.gpio47); +//! .with_ctrl_pins(peripherals.GPIO0, peripherals.GPIO47); //! //! dma_buf.fill(&[0x55]); //! let transfer = i8080.send(0x3Au8, 0, dma_buf).unwrap(); // RGB565 diff --git a/esp-hal/src/ledc/mod.rs b/esp-hal/src/ledc/mod.rs index 3b0a61cfefc..54797a42880 100644 --- a/esp-hal/src/ledc/mod.rs +++ b/esp-hal/src/ledc/mod.rs @@ -29,9 +29,7 @@ //! # use esp_hal::ledc::timer; //! # use esp_hal::ledc::LowSpeed; //! # use esp_hal::ledc::channel; -//! # use esp_hal::gpio::Io; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let led = io.pins.gpio0; +//! # let led = peripherals.GPIO0; //! //! let mut ledc = Ledc::new(peripherals.LEDC); //! ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index f0c28132f68..21e2c6cd0cc 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -81,8 +81,7 @@ //! }); //! //! // Set GPIO0 as an output, and set its state high initially. -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let mut led = Output::new(io.pins.gpio0, Level::High); +//! let mut led = Output::new(peripherals.GPIO0, Level::High); //! //! let delay = Delay::new(); //! diff --git a/esp-hal/src/mcpwm/mod.rs b/esp-hal/src/mcpwm/mod.rs index a4907be376f..dc981794a96 100644 --- a/esp-hal/src/mcpwm/mod.rs +++ b/esp-hal/src/mcpwm/mod.rs @@ -52,10 +52,7 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::mcpwm::{operator::{DeadTimeCfg, PWMStream, PwmPinConfig}, timer::PwmWorkingMode, McPwm, PeripheralClockConfig}; -//! # use esp_hal::gpio::Io; -//! -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let pin = io.pins.gpio0; +//! # let pin = peripherals.GPIO0; //! //! // initialize peripheral #![cfg_attr( diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index 6bb4e3e366e..5edbb02ccb4 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -479,8 +479,6 @@ impl embedded_hal::pwm::SetD /// # use esp_hal::{mcpwm, prelude::*}; /// # use esp_hal::mcpwm::{McPwm, PeripheralClockConfig}; /// # use esp_hal::mcpwm::operator::{DeadTimeCfg, PwmPinConfig, PWMStream}; -/// # use esp_hal::gpio::Io; -/// # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); /// // active high complementary using PWMA input /// let bridge_active = DeadTimeCfg::new_ahc(); /// // use PWMB as input for both outputs @@ -497,9 +495,9 @@ impl embedded_hal::pwm::SetD /// let mut mcpwm = McPwm::new(peripherals.MCPWM0, clock_cfg); /// /// let mut pins = mcpwm.operator0.with_linked_pins( -/// io.pins.gpio0, +/// peripherals.GPIO0, /// PwmPinConfig::UP_DOWN_ACTIVE_HIGH, // use PWMA as our main input -/// io.pins.gpio1, +/// peripherals.GPIO1, /// PwmPinConfig::EMPTY, // keep PWMB "low" /// bridge_off, /// ); diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index 6883d2caecc..c2c10a417fe 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -121,14 +121,14 @@ impl DerefMut for PeripheralRef<'_, T> { /// live forever (`'static`): /// /// ```rust, ignore -/// let mut uart: Uart<'static, ...> = Uart::new(p.UART0, pins.gpio0, pins.gpio1); +/// let mut uart: Uart<'static, ...> = Uart::new(p.UART0, p.GPIO0, p.GPIO1); /// ``` /// /// Or you may call it with borrowed peripherals, which yields an instance that /// can only live for as long as the borrows last: /// /// ```rust, ignore -/// let mut uart: Uart<'_, ...> = Uart::new(&mut p.UART0, &mut pins.gpio0, &mut pins.gpio1); +/// let mut uart: Uart<'_, ...> = Uart::new(&mut p.UART0, &mut p.GPIO0, &mut p.GPIO1); /// ``` /// /// # Implementation details, for HAL authors @@ -222,9 +222,14 @@ mod peripheral_macros { #[macro_export] macro_rules! peripherals { ( - $( - $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? - ), *$(,)? + peripherals: [ + $( + $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? + ), *$(,)? + ], + pins: [ + $( ( $pin:literal, $($pin_tokens:tt)* ) )* + ] ) => { /// Contains the generated peripherals which implement [`Peripheral`] @@ -235,42 +240,59 @@ mod peripheral_macros { )* } - /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip. - #[allow(non_snake_case)] - pub struct Peripherals { - $( - /// Each field represents a hardware peripheral. - pub $name: peripherals::$name, - )* + pub(crate) mod gpio { + $crate::gpio! { + $( ($pin, $($pin_tokens)* ) )* + } } - impl Peripherals { - /// Returns all the peripherals *once* - #[inline] - pub(crate) fn take() -> Self { - #[no_mangle] - static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false; - - critical_section::with(|_| unsafe { - if _ESP_HAL_DEVICE_PERIPHERALS { - panic!("init called more than once!") - } - _ESP_HAL_DEVICE_PERIPHERALS = true; - Self::steal() - }) + paste::paste! { + /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip. + #[allow(non_snake_case)] + pub struct Peripherals { + $( + #[doc = concat!("The ", stringify!($name), " peripheral.")] + pub $name: peripherals::$name, + )* + + $( + #[doc = concat!("GPIO", stringify!($pin))] + pub []: $crate::gpio::GpioPin<$pin>, + )* } - /// Unsafely create an instance of this peripheral out of thin air. - /// - /// # Safety - /// - /// You must ensure that you're only using one instance of this type at a time. - #[inline] - pub unsafe fn steal() -> Self { - Self { - $( - $name: peripherals::$name::steal(), - )* + impl Peripherals { + /// Returns all the peripherals *once* + #[inline] + pub(crate) fn take() -> Self { + #[no_mangle] + static mut _ESP_HAL_DEVICE_PERIPHERALS: bool = false; + + critical_section::with(|_| unsafe { + if _ESP_HAL_DEVICE_PERIPHERALS { + panic!("init called more than once!") + } + _ESP_HAL_DEVICE_PERIPHERALS = true; + Self::steal() + }) + } + + /// Unsafely create an instance of this peripheral out of thin air. + /// + /// # Safety + /// + /// You must ensure that you're only using one instance of this type at a time. + #[inline] + pub unsafe fn steal() -> Self { + Self { + $( + $name: peripherals::$name::steal(), + )* + + $( + []: $crate::gpio::GpioPin::<$pin>::steal(), + )* + } } } } @@ -294,8 +316,7 @@ mod peripheral_macros { } )* )* - - } + }; } #[doc(hidden)] diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 984d621cf54..ef6f4b1063a 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -54,16 +54,14 @@ //! # use esp_hal::peripherals::Peripherals; //! # use esp_hal::rmt::TxChannelConfig; //! # use esp_hal::rmt::Rmt; -//! # use esp_hal::gpio::Io; //! # use crate::esp_hal::rmt::TxChannelCreator; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); #![cfg_attr(esp32h2, doc = "let freq = 32.MHz();")] #![cfg_attr(not(esp32h2), doc = "let freq = 80.MHz();")] //! let rmt = Rmt::new(peripherals.RMT, freq).unwrap(); //! let mut channel = rmt //! .channel0 //! .configure( -//! io.pins.gpio1, +//! peripherals.GPIO1, //! TxChannelConfig { //! clk_divider: 1, //! idle_output_level: false, diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index d0875012a13..6266b9fddc9 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -138,9 +138,7 @@ impl rand_core::RngCore for Rng { /// # use esp_hal::peripherals::Peripherals; /// # use esp_hal::peripherals::ADC1; /// # use esp_hal::analog::adc::{AdcConfig, Attenuation, Adc}; -/// # use esp_hal::gpio::Io; /// -/// let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); /// let mut buf = [0u8; 16]; /// /// // ADC is not available from now @@ -149,13 +147,15 @@ impl rand_core::RngCore for Rng { /// let mut true_rand = trng.random(); /// let mut rng = trng.downgrade(); /// // ADC is available now -#[cfg_attr(esp32, doc = "let analog_pin = io.pins.gpio32;")] -#[cfg_attr(not(esp32), doc = "let analog_pin = io.pins.gpio3;")] +#[cfg_attr(esp32, doc = "let analog_pin = peripherals.GPIO32;")] +#[cfg_attr(not(esp32), doc = "let analog_pin = peripherals.GPIO3;")] /// let mut adc1_config = AdcConfig::new(); -/// let mut adc1_pin = adc1_config.enable_pin(analog_pin, -/// Attenuation::Attenuation11dB); let mut adc1 = -/// Adc::::new(peripherals.ADC1, adc1_config); let pin_value: u16 = -/// nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); +/// let mut adc1_pin = adc1_config.enable_pin( +/// analog_pin, +/// Attenuation::Attenuation11dB +/// ); +/// let mut adc1 = Adc::::new(peripherals.ADC1, adc1_config); +/// let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); /// rng.read(&mut buf); /// true_rand = rng.random(); /// let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); diff --git a/esp-hal/src/rom/md5.rs b/esp-hal/src/rom/md5.rs index 985334104d0..1eb3e9a7480 100644 --- a/esp-hal/src/rom/md5.rs +++ b/esp-hal/src/rom/md5.rs @@ -32,11 +32,9 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::rom::md5; //! # use esp_hal::uart::Uart; -//! # use esp_hal::gpio::Io; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut uart0 = Uart::new(peripherals.UART0, io.pins.gpio1, io.pins.gpio2).unwrap(); +//! # let mut uart0 = Uart::new(peripherals.UART0, peripherals.GPIO1, peripherals.GPIO2).unwrap(); //! # let data = "Dummy"; //! let d: md5::Digest = md5::compute(&data); //! writeln!(uart0, "{}", d); @@ -48,11 +46,9 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::rom::md5; //! # use esp_hal::uart::Uart; -//! # use esp_hal::gpio::Io; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut uart0 = Uart::new(peripherals.UART0, io.pins.gpio1, io.pins.gpio2).unwrap(); +//! # let mut uart0 = Uart::new(peripherals.UART0, peripherals.GPIO1, peripherals.GPIO2).unwrap(); //! # let data0 = "Dummy"; //! # let data1 = "Dummy"; //! # diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs index 19e737c487c..4692513c992 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs @@ -3,7 +3,7 @@ use core::ops::Not; use crate::{ clock::Clock, efuse::Efuse, - gpio::{Pins, RtcFunction}, + gpio::RtcFunction, rtc_cntl::{ rtc::{ rtc_clk_cpu_freq_set_xtal, @@ -71,10 +71,10 @@ impl Ext1WakeupSource<'_, '_> { unsafe { lp_aon().ext_wakeup_cntl().read().ext_wakeup_sel().bits() } } - fn wake_io_reset(pins: &mut Pins) { - use crate::gpio::RtcPin; + fn wake_io_reset() { + use crate::gpio::{GpioPin, RtcPin}; - fn uninit_pin(pin: &mut impl RtcPin, wakeup_pins: u8) { + fn uninit_pin(mut pin: impl RtcPin, wakeup_pins: u8) { if wakeup_pins & (1 << pin.number()) != 0 { pin.rtcio_pad_hold(false); pin.rtc_set_config(false, false, RtcFunction::Rtc); @@ -82,14 +82,14 @@ impl Ext1WakeupSource<'_, '_> { } let wakeup_pins = Ext1WakeupSource::wakeup_pins(); - uninit_pin(&mut pins.gpio0, wakeup_pins); - uninit_pin(&mut pins.gpio1, wakeup_pins); - uninit_pin(&mut pins.gpio2, wakeup_pins); - uninit_pin(&mut pins.gpio3, wakeup_pins); - uninit_pin(&mut pins.gpio4, wakeup_pins); - uninit_pin(&mut pins.gpio5, wakeup_pins); - uninit_pin(&mut pins.gpio6, wakeup_pins); - uninit_pin(&mut pins.gpio7, wakeup_pins); + uninit_pin(unsafe { GpioPin::<0>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<1>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<2>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<3>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<4>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<5>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<6>::steal() }, wakeup_pins); + uninit_pin(unsafe { GpioPin::<7>::steal() }, wakeup_pins); } } @@ -898,15 +898,7 @@ impl RtcSleepConfig { fn wake_io_reset() { // loosely based on esp_deep_sleep_wakeup_io_reset - - let mut pins = unsafe { - // We're stealing pins to do some uninitialization after waking up from - // deep sleep. We have to be careful to only touch settings that were enabled - // by deep sleep setup. - Pins::steal() - }; - - Ext1WakeupSource::wake_io_reset(&mut pins); + Ext1WakeupSource::wake_io_reset(); } /// Finalize power-down flags, apply configuration based on the flags. diff --git a/esp-hal/src/soc/esp32/efuse/mod.rs b/esp-hal/src/soc/esp32/efuse/mod.rs index 79773ff0ddd..ff59b537f9e 100644 --- a/esp-hal/src/soc/esp32/efuse/mod.rs +++ b/esp-hal/src/soc/esp32/efuse/mod.rs @@ -24,12 +24,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index b2e34a52ff3..9a7f8449fff 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -536,7 +536,7 @@ macro_rules! rtcio_analog { ( $pin_num:expr, $rtc_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident $(, $rue:literal)? ) => { - impl $crate::gpio::RtcPin for GpioPin<$pin_num> { + impl $crate::gpio::RtcPin for $crate::gpio::GpioPin<$pin_num> { fn rtc_number(&self) -> u8 { $rtc_pin } @@ -565,7 +565,7 @@ macro_rules! rtcio_analog { $( // FIXME: replace with $(ignore($rue)) once stable rtcio_analog!(@ignore $rue); - impl $crate::gpio::RtcPinWithResistors for GpioPin<$pin_num> { + impl $crate::gpio::RtcPinWithResistors for $crate::gpio::GpioPin<$pin_num> { fn rtcio_pullup(&mut self, enable: bool) { paste::paste! { unsafe { $crate::peripherals::RTC_IO::steal() } @@ -582,7 +582,7 @@ macro_rules! rtcio_analog { } )? - impl $crate::gpio::AnalogPin for GpioPin<$pin_num> { + impl $crate::gpio::AnalogPin for $crate::gpio::GpioPin<$pin_num> { /// Configures the pin for analog mode. fn set_analog(&self, _: $crate::private::Internal) { use $crate::gpio::RtcPin; @@ -629,7 +629,7 @@ macro_rules! rtcio_analog { rtcio_analog!($pin_num, $rtc_pin, $pin_reg, $prefix, $hold $(, $rue )?); )+ - pub(crate) fn errata36(mut pin: AnyPin, pull_up: bool, pull_down: bool) { + pub(crate) fn errata36(mut pin: $crate::gpio::AnyPin, pull_up: bool, pull_down: bool) { use $crate::gpio::{Pin, RtcPinWithResistors}; let has_pullups = match pin.number() { @@ -744,45 +744,6 @@ macro_rules! touch { }; } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo, Touch] (5 => EMAC_TX_CLK) (1 => CLK_OUT1)) - (1, [Input, Output] (5 => EMAC_RXD2) (0 => U0TXD 1 => CLK_OUT3)) - (2, [Input, Output, Analog, RtcIo, Touch] (1 => HSPIWP 3 => HS2_DATA0 4 => SD_DATA0) (3 => HS2_DATA0 4 => SD_DATA0)) - (3, [Input, Output] (0 => U0RXD) (1 => CLK_OUT2)) - (4, [Input, Output, Analog, RtcIo, Touch] (1 => HSPIHD 3 => HS2_DATA1 4 => SD_DATA1 5 => EMAC_TX_ER) (3 => HS2_DATA1 4 => SD_DATA1)) - (5, [Input, Output] (1 => VSPICS0 3 => HS1_DATA6 5 => EMAC_RX_CLK) (3 => HS1_DATA6)) - (6, [Input, Output] (4 => U1CTS) (0 => SD_CLK 1 => SPICLK 3 => HS1_CLK)) - (7, [Input, Output] (0 => SD_DATA0 1 => SPIQ 3 => HS1_DATA0) (0 => SD_DATA0 1 => SPIQ 3 => HS1_DATA0 4 => U2RTS)) - (8, [Input, Output] (0 => SD_DATA1 1 => SPID 3 => HS1_DATA1 4 => U2CTS) (0 => SD_DATA1 1 => SPID 3 => HS1_DATA1)) - (9, [Input, Output] (0 => SD_DATA2 1 => SPIHD 3 => HS1_DATA2 4 => U1RXD) (0 => SD_DATA2 1 => SPIHD 3 => HS1_DATA2)) - (10, [Input, Output] ( 0 => SD_DATA3 1 => SPIWP 3 => HS1_DATA3) (0 => SD_DATA3 1 => SPIWP 3 => HS1_DATA3 4 => U1TXD)) - (11, [Input, Output] ( 1 => SPICS0) (0 => SD_CMD 1 => SPICS0 3 => HS1_CMD 4 => U1RTS)) - (12, [Input, Output, Analog, RtcIo, Touch] (0 => MTDI 1 => HSPIQ 3 => HS2_DATA2 4 => SD_DATA2) (1 => HSPIQ 3 => HS2_DATA2 4 => SD_DATA2 5 => EMAC_TXD3)) - (13, [Input, Output, Analog, RtcIo, Touch] (0 => MTCK 1 => HSPID 3 => HS2_DATA3 4 => SD_DATA3) (1 => HSPID 3 => HS2_DATA3 4 => SD_DATA3 5 => EMAC_RX_ER)) - (14, [Input, Output, Analog, RtcIo, Touch] (0 => MTMS 1 => HSPICLK) (1 => HSPICLK 3 => HS2_CLK 4 => SD_CLK 5 => EMAC_TXD2)) - (15, [Input, Output, Analog, RtcIo, Touch] (1 => HSPICS0 5 => EMAC_RXD3) (0 => MTDO 1 => HSPICS0 3 => HS2_CMD 4 => SD_CMD)) - (16, [Input, Output] (3 => HS1_DATA4 4 => U2RXD) (3 => HS1_DATA4 5 => EMAC_CLK_OUT)) - (17, [Input, Output] (3 => HS1_DATA5) (3 => HS1_DATA5 4 => U2TXD 5 => EMAC_CLK_180)) - (18, [Input, Output] (1 => VSPICLK 3 => HS1_DATA7) (1 => VSPICLK 3 => HS1_DATA7)) - (19, [Input, Output] (1 => VSPIQ 3 => U0CTS) (1 => VSPIQ 5 => EMAC_TXD0)) - (20, [Input, Output]) - (21, [Input, Output] (1 => VSPIHD) (1 => VSPIHD 5 => EMAC_TX_EN)) - (22, [Input, Output] (1 => VSPIWP) (1 => VSPIWP 3 => U0RTS 5 => EMAC_TXD1)) - (23, [Input, Output] (1 => VSPID) (1 => VSPID 3 => HS1_STROBE)) - (24, [Input, Output]) - (25, [Input, Output, Analog, RtcIo] (5 => EMAC_RXD0) ()) - (26, [Input, Output, Analog, RtcIo] (5 => EMAC_RXD1) ()) - (27, [Input, Output, Analog, RtcIo, Touch] (5 => EMAC_RX_DV) ()) - (32, [Input, Output, Analog, RtcIo, Touch]) - (33, [Input, Output, Analog, RtcIo, Touch]) - (34, [Input, Analog, RtcIoInput]) - (35, [Input, Analog, RtcIoInput]) - (36, [Input, Analog, RtcIoInput]) - (37, [Input, Analog, RtcIoInput]) - (38, [Input, Analog, RtcIoInput]) - (39, [Input, Analog, RtcIoInput]) -} - rtcio_analog! { (36, 0, sensor_pads(), sense1_, sense1_hold_force ) (37, 1, sensor_pads(), sense2_, sense2_hold_force ) diff --git a/esp-hal/src/soc/esp32/peripherals.rs b/esp-hal/src/soc/esp32/peripherals.rs index ab9b31ce6d1..2bfa72fc05e 100644 --- a/esp-hal/src/soc/esp32/peripherals.rs +++ b/esp-hal/src/soc/esp32/peripherals.rs @@ -20,58 +20,97 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - ADC2 <= virtual, - AES <= AES, - APB_CTRL <= APB_CTRL, - BB <= BB, - BT <= virtual, - CPU_CTRL <= virtual, - DAC1 <= virtual, - DAC2 <= virtual, - DMA <= virtual, - EFUSE <= EFUSE, - FLASH_ENCRYPTION <= FLASH_ENCRYPTION, - FRC_TIMER <= FRC_TIMER, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HINF <= HINF, - I2C0 <= I2C0, - I2C1 <= I2C1, - I2S0 <= I2S0 (I2S0), - I2S1 <= I2S1 (I2S1), - IO_MUX <= IO_MUX, - LEDC <= LEDC, - MCPWM0 <= MCPWM0, - MCPWM1 <= MCPWM1, - NRX <= NRX, - PCNT <= PCNT, - PSRAM <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - LPWR <= RTC_CNTL, - RADIO_CLK <= virtual, - RTC_IO <= RTC_IO, - RTC_I2C <= RTC_I2C, - SDHOST <= SDHOST, - SHA <= SHA, - SLC <= SLC, - SLCHOST <= SLCHOST, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2_DMA, SPI2), - SPI3 <= SPI3 (SPI3_DMA, SPI3), - SYSTEM <= DPORT, - SW_INTERRUPT <= virtual, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TOUCH <= virtual, - TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UART2 <= UART2, - UHCI0 <= UHCI0, - UHCI1 <= UHCI1, - WIFI <= virtual, + peripherals: [ + ADC1 <= virtual, + ADC2 <= virtual, + AES <= AES, + APB_CTRL <= APB_CTRL, + BB <= BB, + BT <= virtual, + CPU_CTRL <= virtual, + DAC1 <= virtual, + DAC2 <= virtual, + DMA <= virtual, + EFUSE <= EFUSE, + FLASH_ENCRYPTION <= FLASH_ENCRYPTION, + FRC_TIMER <= FRC_TIMER, + GPIO_SD <= GPIO_SD, + HINF <= HINF, + I2C0 <= I2C0, + I2C1 <= I2C1, + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), + IO_MUX <= IO_MUX, + LEDC <= LEDC, + MCPWM0 <= MCPWM0, + MCPWM1 <= MCPWM1, + NRX <= NRX, + PCNT <= PCNT, + PSRAM <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + LPWR <= RTC_CNTL, + RADIO_CLK <= virtual, + RTC_IO <= RTC_IO, + RTC_I2C <= RTC_I2C, + SDHOST <= SDHOST, + SHA <= SHA, + SLC <= SLC, + SLCHOST <= SLCHOST, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), + SYSTEM <= DPORT, + SW_INTERRUPT <= virtual, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TOUCH <= virtual, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, + UHCI0 <= UHCI0, + UHCI1 <= UHCI1, + WIFI <= virtual, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo, Touch] (5 => EMAC_TX_CLK) (1 => CLK_OUT1)) + (1, [Input, Output] (5 => EMAC_RXD2) (0 => U0TXD 1 => CLK_OUT3)) + (2, [Input, Output, Analog, RtcIo, Touch] (1 => HSPIWP 3 => HS2_DATA0 4 => SD_DATA0) (3 => HS2_DATA0 4 => SD_DATA0)) + (3, [Input, Output] (0 => U0RXD) (1 => CLK_OUT2)) + (4, [Input, Output, Analog, RtcIo, Touch] (1 => HSPIHD 3 => HS2_DATA1 4 => SD_DATA1 5 => EMAC_TX_ER) (3 => HS2_DATA1 4 => SD_DATA1)) + (5, [Input, Output] (1 => VSPICS0 3 => HS1_DATA6 5 => EMAC_RX_CLK) (3 => HS1_DATA6)) + (6, [Input, Output] (4 => U1CTS) (0 => SD_CLK 1 => SPICLK 3 => HS1_CLK)) + (7, [Input, Output] (0 => SD_DATA0 1 => SPIQ 3 => HS1_DATA0) (0 => SD_DATA0 1 => SPIQ 3 => HS1_DATA0 4 => U2RTS)) + (8, [Input, Output] (0 => SD_DATA1 1 => SPID 3 => HS1_DATA1 4 => U2CTS) (0 => SD_DATA1 1 => SPID 3 => HS1_DATA1)) + (9, [Input, Output] (0 => SD_DATA2 1 => SPIHD 3 => HS1_DATA2 4 => U1RXD) (0 => SD_DATA2 1 => SPIHD 3 => HS1_DATA2)) + (10, [Input, Output] ( 0 => SD_DATA3 1 => SPIWP 3 => HS1_DATA3) (0 => SD_DATA3 1 => SPIWP 3 => HS1_DATA3 4 => U1TXD)) + (11, [Input, Output] ( 1 => SPICS0) (0 => SD_CMD 1 => SPICS0 3 => HS1_CMD 4 => U1RTS)) + (12, [Input, Output, Analog, RtcIo, Touch] (0 => MTDI 1 => HSPIQ 3 => HS2_DATA2 4 => SD_DATA2) (1 => HSPIQ 3 => HS2_DATA2 4 => SD_DATA2 5 => EMAC_TXD3)) + (13, [Input, Output, Analog, RtcIo, Touch] (0 => MTCK 1 => HSPID 3 => HS2_DATA3 4 => SD_DATA3) (1 => HSPID 3 => HS2_DATA3 4 => SD_DATA3 5 => EMAC_RX_ER)) + (14, [Input, Output, Analog, RtcIo, Touch] (0 => MTMS 1 => HSPICLK) (1 => HSPICLK 3 => HS2_CLK 4 => SD_CLK 5 => EMAC_TXD2)) + (15, [Input, Output, Analog, RtcIo, Touch] (1 => HSPICS0 5 => EMAC_RXD3) (0 => MTDO 1 => HSPICS0 3 => HS2_CMD 4 => SD_CMD)) + (16, [Input, Output] (3 => HS1_DATA4 4 => U2RXD) (3 => HS1_DATA4 5 => EMAC_CLK_OUT)) + (17, [Input, Output] (3 => HS1_DATA5) (3 => HS1_DATA5 4 => U2TXD 5 => EMAC_CLK_180)) + (18, [Input, Output] (1 => VSPICLK 3 => HS1_DATA7) (1 => VSPICLK 3 => HS1_DATA7)) + (19, [Input, Output] (1 => VSPIQ 3 => U0CTS) (1 => VSPIQ 5 => EMAC_TXD0)) + (20, [Input, Output]) + (21, [Input, Output] (1 => VSPIHD) (1 => VSPIHD 5 => EMAC_TX_EN)) + (22, [Input, Output] (1 => VSPIWP) (1 => VSPIWP 3 => U0RTS 5 => EMAC_TXD1)) + (23, [Input, Output] (1 => VSPID) (1 => VSPID 3 => HS1_STROBE)) + (24, [Input, Output]) + (25, [Input, Output, Analog, RtcIo] (5 => EMAC_RXD0) ()) + (26, [Input, Output, Analog, RtcIo] (5 => EMAC_RXD1) ()) + (27, [Input, Output, Analog, RtcIo, Touch] (5 => EMAC_RX_DV) ()) + (32, [Input, Output, Analog, RtcIo, Touch]) + (33, [Input, Output, Analog, RtcIo, Touch]) + (34, [Input, Analog, RtcIoInput]) + (35, [Input, Analog, RtcIoInput]) + (36, [Input, Analog, RtcIoInput]) + (37, [Input, Analog, RtcIoInput]) + (38, [Input, Analog, RtcIoInput]) + (39, [Input, Analog, RtcIoInput]) + ] } diff --git a/esp-hal/src/soc/esp32c2/efuse/mod.rs b/esp-hal/src/soc/esp32c2/efuse/mod.rs index 3aeb5fc0a94..bfd724fd459 100644 --- a/esp-hal/src/soc/esp32c2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c2/efuse/mod.rs @@ -21,12 +21,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32c2/gpio.rs b/esp-hal/src/soc/esp32c2/gpio.rs index 5304cc66c1b..f7080686beb 100644 --- a/esp-hal/src/soc/esp32c2/gpio.rs +++ b/esp-hal/src/soc/esp32c2/gpio.rs @@ -215,23 +215,6 @@ where } } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo]) - (1, [Input, Output, Analog, RtcIo]) - (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) - (3, [Input, Output, Analog, RtcIo]) - (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (2 => FSPIHD)) - (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (2 => FSPIWP)) - (6, [Input, Output] (2 => FSPICLK) (2 => FSPICLK_MUX)) - (7, [Input, Output] (2 => FSPID) (2 => FSPID)) - (8, [Input, Output]) - (9, [Input, Output]) - (10, [Input, Output] (2 => FSPICS0) (2 => FSPICS0)) - (18, [Input, Output]) - (19, [Input, Output]) - (20, [Input, Output] (0 => U0RXD) ()) -} - rtc_pins! { 0 1 diff --git a/esp-hal/src/soc/esp32c2/peripherals.rs b/esp-hal/src/soc/esp32c2/peripherals.rs index 3cd86959d96..6748f4e6ce5 100644 --- a/esp-hal/src/soc/esp32c2/peripherals.rs +++ b/esp-hal/src/soc/esp32c2/peripherals.rs @@ -20,40 +20,57 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - APB_CTRL <= APB_CTRL, - ASSIST_DEBUG <= ASSIST_DEBUG, - BT <= virtual, - DMA <= DMA (DMA_CH0), - ECC <= ECC, - EFUSE <= EFUSE, - EXTMEM <= EXTMEM, - GPIO <= GPIO (GPIO,GPIO_NMI), - I2C0 <= I2C0, - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, - LEDC <= LEDC, - LPWR <= RTC_CNTL, - RADIO_CLK <= virtual, - RNG <= RNG, - SENSITIVE <= SENSITIVE, - SHA <= SHA, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SYSTEM <= SYSTEM, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TIMG0 <= TIMG0, - UART0 <= UART0, - UART1 <= UART1, - WIFI <= virtual, - XTS_AES <= XTS_AES, - MEM2MEM1 <= virtual, - MEM2MEM2 <= virtual, - MEM2MEM3 <= virtual, - MEM2MEM4 <= virtual, - MEM2MEM5 <= virtual, - MEM2MEM6 <= virtual, - MEM2MEM8 <= virtual, + peripherals: [ + ADC1 <= virtual, + APB_CTRL <= APB_CTRL, + ASSIST_DEBUG <= ASSIST_DEBUG, + BT <= virtual, + DMA <= DMA (DMA_CH0), + ECC <= ECC, + EFUSE <= EFUSE, + EXTMEM <= EXTMEM, + I2C0 <= I2C0, + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + IO_MUX <= IO_MUX, + LEDC <= LEDC, + LPWR <= RTC_CNTL, + RADIO_CLK <= virtual, + RNG <= RNG, + SENSITIVE <= SENSITIVE, + SHA <= SHA, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2), + SYSTEM <= SYSTEM, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TIMG0 <= TIMG0, + UART0 <= UART0, + UART1 <= UART1, + WIFI <= virtual, + XTS_AES <= XTS_AES, + MEM2MEM1 <= virtual, + MEM2MEM2 <= virtual, + MEM2MEM3 <= virtual, + MEM2MEM4 <= virtual, + MEM2MEM5 <= virtual, + MEM2MEM6 <= virtual, + MEM2MEM8 <= virtual, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo]) + (1, [Input, Output, Analog, RtcIo]) + (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) + (3, [Input, Output, Analog, RtcIo]) + (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (2 => FSPIHD)) + (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (2 => FSPIWP)) + (6, [Input, Output] (2 => FSPICLK) (2 => FSPICLK_MUX)) + (7, [Input, Output] (2 => FSPID) (2 => FSPID)) + (8, [Input, Output]) + (9, [Input, Output]) + (10, [Input, Output] (2 => FSPICS0) (2 => FSPICS0)) + (18, [Input, Output]) + (19, [Input, Output]) + (20, [Input, Output] (0 => U0RXD) ()) + ] } diff --git a/esp-hal/src/soc/esp32c3/efuse/mod.rs b/esp-hal/src/soc/esp32c3/efuse/mod.rs index f1f3b0e2fb5..c7fae51caab 100644 --- a/esp-hal/src/soc/esp32c3/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c3/efuse/mod.rs @@ -22,12 +22,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32c3/gpio.rs b/esp-hal/src/soc/esp32c3/gpio.rs index 80af84bb36f..f6a4fd76fcb 100644 --- a/esp-hal/src/soc/esp32c3/gpio.rs +++ b/esp-hal/src/soc/esp32c3/gpio.rs @@ -243,31 +243,6 @@ where } } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo]) - (1, [Input, Output, Analog, RtcIo]) - (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) - (3, [Input, Output, Analog, RtcIo]) - (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (0 => USB_JTAG_TMS 2 => FSPIHD)) - (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (0 => USB_JTAG_TDI 2 => FSPIWP)) - (6, [Input, Output] (2 => FSPICLK) (0 => USB_JTAG_TCK 2 => FSPICLK_MUX)) - (7, [Input, Output] (2 => FSPID) (0 => USB_JTAG_TDO 2 => FSPID)) - (8, [Input, Output]) - (9, [Input, Output]) - (10, [Input, Output] (2 => FSPICS0) (2 => FSPICS0)) - (11, [Input, Output]) - (12, [Input, Output] (0 => SPIHD) (0 => SPIHD)) - (13, [Input, Output] (0 => SPIWP) (0 => SPIWP)) - (14, [Input, Output] () (0 => SPICS0)) - (15, [Input, Output] () (0 => SPICLK_MUX)) - (16, [Input, Output] (0 => SPID) (0 => SPID)) - (17, [Input, Output] (0 => SPIQ) (0 => SPIQ)) - (18, [Input, Output]) - (19, [Input, Output]) - (20, [Input, Output] (0 => U0RXD) ()) - (21, [Input, Output] () (0 => U0TXD)) -} - // RTC pins 0 through 5 (inclusive) support GPIO wakeup rtc_pins! { 0 diff --git a/esp-hal/src/soc/esp32c3/peripherals.rs b/esp-hal/src/soc/esp32c3/peripherals.rs index dd5308df0c2..f4a52d4fc08 100644 --- a/esp-hal/src/soc/esp32c3/peripherals.rs +++ b/esp-hal/src/soc/esp32c3/peripherals.rs @@ -20,45 +20,70 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - ADC2 <= virtual, - AES <= AES, - APB_CTRL <= APB_CTRL, - ASSIST_DEBUG <= ASSIST_DEBUG, - BT <= virtual, - DMA <= DMA (DMA_CH0,DMA_CH1,DMA_CH2), - DS <= DS, - EFUSE <= EFUSE, - EXTMEM <= EXTMEM, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HMAC <= HMAC, - I2C0 <= I2C0, - I2S0 <= I2S0 (I2S0), - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, - LEDC <= LEDC, - LPWR <= RTC_CNTL, - RADIO_CLK <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - SENSITIVE <= SENSITIVE, - SHA <= SHA, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SYSTEM <= SYSTEM, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UHCI0 <= UHCI0, - UHCI1 <= UHCI1, - USB_DEVICE <= USB_DEVICE, - WIFI <= virtual, - XTS_AES <= XTS_AES, + peripherals: [ + ADC1 <= virtual, + ADC2 <= virtual, + AES <= AES, + APB_CTRL <= APB_CTRL, + ASSIST_DEBUG <= ASSIST_DEBUG, + BT <= virtual, + DMA <= DMA (DMA_CH0,DMA_CH1,DMA_CH2), + DS <= DS, + EFUSE <= EFUSE, + EXTMEM <= EXTMEM, + GPIO_SD <= GPIO_SD, + HMAC <= HMAC, + I2C0 <= I2C0, + I2S0 <= I2S0 (I2S0), + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + IO_MUX <= IO_MUX, + LEDC <= LEDC, + LPWR <= RTC_CNTL, + RADIO_CLK <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + SENSITIVE <= SENSITIVE, + SHA <= SHA, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2), + SYSTEM <= SYSTEM, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UHCI0 <= UHCI0, + UHCI1 <= UHCI1, + USB_DEVICE <= USB_DEVICE, + WIFI <= virtual, + XTS_AES <= XTS_AES, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo]) + (1, [Input, Output, Analog, RtcIo]) + (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) + (3, [Input, Output, Analog, RtcIo]) + (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (0 => USB_JTAG_TMS 2 => FSPIHD)) + (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (0 => USB_JTAG_TDI 2 => FSPIWP)) + (6, [Input, Output] (2 => FSPICLK) (0 => USB_JTAG_TCK 2 => FSPICLK_MUX)) + (7, [Input, Output] (2 => FSPID) (0 => USB_JTAG_TDO 2 => FSPID)) + (8, [Input, Output]) + (9, [Input, Output]) + (10, [Input, Output] (2 => FSPICS0) (2 => FSPICS0)) + (11, [Input, Output]) + (12, [Input, Output] (0 => SPIHD) (0 => SPIHD)) + (13, [Input, Output] (0 => SPIWP) (0 => SPIWP)) + (14, [Input, Output] () (0 => SPICS0)) + (15, [Input, Output] () (0 => SPICLK_MUX)) + (16, [Input, Output] (0 => SPID) (0 => SPID)) + (17, [Input, Output] (0 => SPIQ) (0 => SPIQ)) + (18, [Input, Output]) + (19, [Input, Output]) + (20, [Input, Output] (0 => U0RXD) ()) + (21, [Input, Output] () (0 => U0TXD)) + ] } diff --git a/esp-hal/src/soc/esp32c6/efuse/mod.rs b/esp-hal/src/soc/esp32c6/efuse/mod.rs index 0caa975a253..9e2906e2af7 100644 --- a/esp-hal/src/soc/esp32c6/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c6/efuse/mod.rs @@ -22,12 +22,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32c6/gpio.rs b/esp-hal/src/soc/esp32c6/gpio.rs index 32c73525600..b7d84a403aa 100644 --- a/esp-hal/src/soc/esp32c6/gpio.rs +++ b/esp-hal/src/soc/esp32c6/gpio.rs @@ -287,40 +287,6 @@ pub enum OutputSignal { GPIO = 128, } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo]) - (1, [Input, Output, Analog, RtcIo]) - (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) - (3, [Input, Output, Analog, RtcIo]) - (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (0 => USB_JTAG_TMS 2 => FSPIHD)) - (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (0 => USB_JTAG_TDI 2 => FSPIWP)) - (6, [Input, Output, Analog, RtcIo] (2 => FSPICLK) (0 => USB_JTAG_TCK 2 => FSPICLK_MUX)) - (7, [Input, Output, Analog, RtcIo] (2 => FSPID) (0 => USB_JTAG_TDO 2 => FSPID)) - (8, [Input, Output]) - (9, [Input, Output]) - (10, [Input, Output]) - (11, [Input, Output]) - (12, [Input, Output]) - (13, [Input, Output]) - (14, [Input, Output]) - (15, [Input, Output]) - (16, [Input, Output] (0 => U0RXD) (2 => FSPICS0)) - (17, [Input, Output] () (0 => U0TXD 2 => FSPICS1)) - (18, [Input, Output] () (2 => FSPICS2)) // 0 => SDIO_CMD but there are no signals since it's a fixed pin - (19, [Input, Output] () (2 => FSPICS3)) // 0 => SDIO_CLK but there are no signals since it's a fixed pin - (20, [Input, Output] () (2 => FSPICS4)) // 0 => SDIO_DATA0 but there are no signals since it's a fixed pin - (21, [Input, Output] () (2 => FSPICS5)) // 0 => SDIO_DATA1 but there are no signals since it's a fixed pin - (22, [Input, Output] () ()) // 0 => SDIO_DATA2 but there are no signals since it's a fixed pin - (23, [Input, Output] () ()) // 0 => SDIO_DATA3 but there are no signals since it's a fixed pin - (24, [Input, Output] () (0 => SPICS0)) - (25, [Input, Output] (0 => SPIQ) (0 => SPIQ)) - (26, [Input, Output] (0 => SPIWP) (0 => SPIWP)) - (27, [Input, Output]) - (28, [Input, Output] (0 => SPIHD) (0 => SPIHD)) - (29, [Input, Output] () (0 => SPICLK_MUX)) - (30, [Input, Output] (0 => SPID) (0 => SPID)) -} - crate::lp_gpio! { 0 1 diff --git a/esp-hal/src/soc/esp32c6/peripherals.rs b/esp-hal/src/soc/esp32c6/peripherals.rs index ef74459ed22..b521161faf9 100644 --- a/esp-hal/src/soc/esp32c6/peripherals.rs +++ b/esp-hal/src/soc/esp32c6/peripherals.rs @@ -20,81 +20,115 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - AES <= AES, - ASSIST_DEBUG <= ASSIST_DEBUG, - ATOMIC <= ATOMIC, - BT <= virtual, - DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), - DS <= DS, - ECC <= ECC, - EFUSE <= EFUSE, - EXTMEM <= EXTMEM, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HINF <= HINF, - HMAC <= HMAC, - HP_APM <= HP_APM, - HP_SYS <= HP_SYS, - I2C0 <= I2C0, - I2S0 <= I2S0 (I2S0), - IEEE802154 <= IEEE802154, - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - INTPRI <= INTPRI, - IO_MUX <= IO_MUX, - LEDC <= LEDC, - LPWR <= LP_CLKRST, - LP_CORE <= virtual, - LP_PERI <= LP_PERI, - LP_ANA <= LP_ANA, - LP_AON <= LP_AON, - LP_APM <= LP_APM, - LP_APM0 <= LP_APM0, - LP_I2C0 <= LP_I2C0, - LP_I2C_ANA_MST <= LP_I2C_ANA_MST, - LP_IO <= LP_IO, - LP_TEE <= LP_TEE, - LP_TIMER <= LP_TIMER, - LP_UART <= LP_UART, - LP_WDT <= LP_WDT, - MCPWM0 <= MCPWM0, - MEM_MONITOR <= MEM_MONITOR, - OTP_DEBUG <= OTP_DEBUG, - PARL_IO <= PARL_IO (PARL_IO), - PAU <= PAU, - PCNT <= PCNT, - PMU <= PMU, - RADIO_CLK <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - SHA <= SHA, - SLCHOST <= SLCHOST, - SOC_ETM <= SOC_ETM, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SYSTEM <= PCR, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TEE <= TEE, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TRACE0 <= TRACE, - TWAI0 <= TWAI0, - TWAI1 <= TWAI1, - UART0 <= UART0, - UART1 <= UART1, - UHCI0 <= UHCI0, - USB_DEVICE <= USB_DEVICE, - WIFI <= virtual, - MEM2MEM1 <= virtual, - MEM2MEM4 <= virtual, - MEM2MEM5 <= virtual, - MEM2MEM10 <= virtual, - MEM2MEM11 <= virtual, - MEM2MEM12 <= virtual, - MEM2MEM13 <= virtual, - MEM2MEM14 <= virtual, - MEM2MEM15 <= virtual, + peripherals: [ + ADC1 <= virtual, + AES <= AES, + ASSIST_DEBUG <= ASSIST_DEBUG, + ATOMIC <= ATOMIC, + BT <= virtual, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), + DS <= DS, + ECC <= ECC, + EFUSE <= EFUSE, + EXTMEM <= EXTMEM, + GPIO_SD <= GPIO_SD, + HINF <= HINF, + HMAC <= HMAC, + HP_APM <= HP_APM, + HP_SYS <= HP_SYS, + I2C0 <= I2C0, + I2S0 <= I2S0 (I2S0), + IEEE802154 <= IEEE802154, + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + INTPRI <= INTPRI, + IO_MUX <= IO_MUX, + LEDC <= LEDC, + LPWR <= LP_CLKRST, + LP_CORE <= virtual, + LP_PERI <= LP_PERI, + LP_ANA <= LP_ANA, + LP_AON <= LP_AON, + LP_APM <= LP_APM, + LP_APM0 <= LP_APM0, + LP_I2C0 <= LP_I2C0, + LP_I2C_ANA_MST <= LP_I2C_ANA_MST, + LP_IO <= LP_IO, + LP_TEE <= LP_TEE, + LP_TIMER <= LP_TIMER, + LP_UART <= LP_UART, + LP_WDT <= LP_WDT, + MCPWM0 <= MCPWM0, + MEM_MONITOR <= MEM_MONITOR, + OTP_DEBUG <= OTP_DEBUG, + PARL_IO <= PARL_IO (PARL_IO), + PAU <= PAU, + PCNT <= PCNT, + PMU <= PMU, + RADIO_CLK <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + SHA <= SHA, + SLCHOST <= SLCHOST, + SOC_ETM <= SOC_ETM, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2), + SYSTEM <= PCR, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TEE <= TEE, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TRACE0 <= TRACE, + TWAI0 <= TWAI0, + TWAI1 <= TWAI1, + UART0 <= UART0, + UART1 <= UART1, + UHCI0 <= UHCI0, + USB_DEVICE <= USB_DEVICE, + WIFI <= virtual, + MEM2MEM1 <= virtual, + MEM2MEM4 <= virtual, + MEM2MEM5 <= virtual, + MEM2MEM10 <= virtual, + MEM2MEM11 <= virtual, + MEM2MEM12 <= virtual, + MEM2MEM13 <= virtual, + MEM2MEM14 <= virtual, + MEM2MEM15 <= virtual, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo]) + (1, [Input, Output, Analog, RtcIo]) + (2, [Input, Output, Analog, RtcIo] (2 => FSPIQ) (2 => FSPIQ)) + (3, [Input, Output, Analog, RtcIo]) + (4, [Input, Output, Analog, RtcIo] (2 => FSPIHD) (0 => USB_JTAG_TMS 2 => FSPIHD)) + (5, [Input, Output, Analog, RtcIo] (2 => FSPIWP) (0 => USB_JTAG_TDI 2 => FSPIWP)) + (6, [Input, Output, Analog, RtcIo] (2 => FSPICLK) (0 => USB_JTAG_TCK 2 => FSPICLK_MUX)) + (7, [Input, Output, Analog, RtcIo] (2 => FSPID) (0 => USB_JTAG_TDO 2 => FSPID)) + (8, [Input, Output]) + (9, [Input, Output]) + (10, [Input, Output]) + (11, [Input, Output]) + (12, [Input, Output]) + (13, [Input, Output]) + (14, [Input, Output]) + (15, [Input, Output]) + (16, [Input, Output] (0 => U0RXD) (2 => FSPICS0)) + (17, [Input, Output] () (0 => U0TXD 2 => FSPICS1)) + (18, [Input, Output] () (2 => FSPICS2)) // 0 => SDIO_CMD but there are no signals since it's a fixed pin + (19, [Input, Output] () (2 => FSPICS3)) // 0 => SDIO_CLK but there are no signals since it's a fixed pin + (20, [Input, Output] () (2 => FSPICS4)) // 0 => SDIO_DATA0 but there are no signals since it's a fixed pin + (21, [Input, Output] () (2 => FSPICS5)) // 0 => SDIO_DATA1 but there are no signals since it's a fixed pin + (22, [Input, Output] () ()) // 0 => SDIO_DATA2 but there are no signals since it's a fixed pin + (23, [Input, Output] () ()) // 0 => SDIO_DATA3 but there are no signals since it's a fixed pin + (24, [Input, Output] () (0 => SPICS0)) + (25, [Input, Output] (0 => SPIQ) (0 => SPIQ)) + (26, [Input, Output] (0 => SPIWP) (0 => SPIWP)) + (27, [Input, Output]) + (28, [Input, Output] (0 => SPIHD) (0 => SPIHD)) + (29, [Input, Output] () (0 => SPICLK_MUX)) + (30, [Input, Output] (0 => SPID) (0 => SPID)) + ] } diff --git a/esp-hal/src/soc/esp32h2/efuse/mod.rs b/esp-hal/src/soc/esp32h2/efuse/mod.rs index 73bdcd57b31..eaf75d21d5c 100644 --- a/esp-hal/src/soc/esp32h2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32h2/efuse/mod.rs @@ -22,12 +22,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32h2/gpio.rs b/esp-hal/src/soc/esp32h2/gpio.rs index fba6b839dd2..ffff2e84797 100644 --- a/esp-hal/src/soc/esp32h2/gpio.rs +++ b/esp-hal/src/soc/esp32h2/gpio.rs @@ -36,10 +36,7 @@ //! registers for both the `PRO CPU` and `APP CPU`. The implementation uses the //! `gpio` peripheral to access the appropriate registers. -use crate::{ - gpio::{AlternateFunction, GpioPin}, - peripherals::GPIO, -}; +use crate::{gpio::AlternateFunction, peripherals::GPIO}; // https://github.com/espressif/esp-idf/blob/df9310a/components/soc/esp32h2/gpio_periph.c#L42 /// The total number of GPIO pins available. @@ -252,37 +249,6 @@ pub enum OutputSignal { GPIO = 128, } -crate::gpio! { - (0, [Input, Output, Analog] (2 => FSPIQ) (2 => FSPIQ)) - (1, [Input, Output, Analog] (2 => FSPICS0) (2 => FSPICS0)) - (2, [Input, Output, Analog] (2 => FSPIWP) (2 => FSPIWP)) - (3, [Input, Output, Analog] (2 => FSPIHD) (2 => FSPIHD)) - (4, [Input, Output, Analog] (2 => FSPICLK) (2 => FSPICLK_MUX)) - (5, [Input, Output, Analog] (2 => FSPID) (2 => FSPID)) - (6, [Input, Output]) - (7, [Input, Output]) - (8, [Input, Output]) - (9, [Input, Output]) - (10, [Input, Output]) - (11, [Input, Output]) - (12, [Input, Output]) - (13, [Input, Output]) - (14, [Input, Output]) - (15, [Input, Output] () (0 => SPICS0)) - (16, [Input, Output] (0 => SPIQ) (0 => SPIQ)) - (17, [Input, Output] (0 => SPIWP) (0 => SPIWP)) - (18, [Input, Output] (0 => SPIHD) (0 => SPIHD)) - (19, [Input, Output] () (0 => SPICLK)) - (20, [Input, Output] (0 => SPID) (0 => SPID)) - (21, [Input, Output]) - (22, [Input, Output]) - (23, [Input, Output] () (2 => FSPICS1)) - (24, [Input, Output] () (2 => FSPICS2)) - (25, [Input, Output] () (2 => FSPICS3)) - (26, [Input, Output] () (2 => FSPICS4)) - (27, [Input, Output] () (2 => FSPICS5)) -} - #[derive(Clone, Copy)] pub(crate) enum InterruptStatusRegisterAccess { Bank0, diff --git a/esp-hal/src/soc/esp32h2/peripherals.rs b/esp-hal/src/soc/esp32h2/peripherals.rs index 7fbda39c981..9f2c0cdb7df 100644 --- a/esp-hal/src/soc/esp32h2/peripherals.rs +++ b/esp-hal/src/soc/esp32h2/peripherals.rs @@ -20,71 +20,102 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - AES <= AES, - ASSIST_DEBUG <= ASSIST_DEBUG, - BT <= virtual, - DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), - DS <= DS, - ECC <= ECC, - EFUSE <= EFUSE, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HMAC <= HMAC, - HP_APM <= HP_APM, - HP_SYS <= HP_SYS, - I2C0 <= I2C0, - I2C1 <= I2C1, - I2S0 <= I2S0 (I2S0), - IEEE802154 <= IEEE802154, - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - INTPRI <= INTPRI, - IO_MUX <= IO_MUX, - LEDC <= LEDC, - LPWR <= LP_CLKRST, - LP_ANA <= LP_ANA, - LP_AON <= LP_AON, - LP_APM <= LP_APM, - LP_PERI <= LP_PERI, - LP_TIMER <= LP_TIMER, - LP_WDT <= LP_WDT, - MCPWM0 <= MCPWM0, - MEM_MONITOR <= MEM_MONITOR, - MODEM_LPCON <= MODEM_LPCON, - MODEM_SYSCON <= MODEM_SYSCON, - OTP_DEBUG <= OTP_DEBUG, - PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX), - PAU <= PAU, - PCNT <= PCNT, - PMU <= PMU, - RADIO_CLK <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - SHA <= SHA, - SOC_ETM <= SOC_ETM, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SYSTEM <= PCR, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TEE <= TEE, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TRACE0 <= TRACE, - TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UHCI0 <= UHCI0, - USB_DEVICE <= USB_DEVICE, - MEM2MEM1 <= virtual, - MEM2MEM4 <= virtual, - MEM2MEM5 <= virtual, - MEM2MEM10 <= virtual, - MEM2MEM11 <= virtual, - MEM2MEM12 <= virtual, - MEM2MEM13 <= virtual, - MEM2MEM14 <= virtual, - MEM2MEM15 <= virtual, + peripherals: [ + ADC1 <= virtual, + AES <= AES, + ASSIST_DEBUG <= ASSIST_DEBUG, + BT <= virtual, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2), + DS <= DS, + ECC <= ECC, + EFUSE <= EFUSE, + GPIO_SD <= GPIO_SD, + HMAC <= HMAC, + HP_APM <= HP_APM, + HP_SYS <= HP_SYS, + I2C0 <= I2C0, + I2C1 <= I2C1, + I2S0 <= I2S0 (I2S0), + IEEE802154 <= IEEE802154, + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + INTPRI <= INTPRI, + IO_MUX <= IO_MUX, + LEDC <= LEDC, + LPWR <= LP_CLKRST, + LP_ANA <= LP_ANA, + LP_AON <= LP_AON, + LP_APM <= LP_APM, + LP_PERI <= LP_PERI, + LP_TIMER <= LP_TIMER, + LP_WDT <= LP_WDT, + MCPWM0 <= MCPWM0, + MEM_MONITOR <= MEM_MONITOR, + MODEM_LPCON <= MODEM_LPCON, + MODEM_SYSCON <= MODEM_SYSCON, + OTP_DEBUG <= OTP_DEBUG, + PARL_IO <= PARL_IO (PARL_IO_TX, PARL_IO_RX), + PAU <= PAU, + PCNT <= PCNT, + PMU <= PMU, + RADIO_CLK <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + SHA <= SHA, + SOC_ETM <= SOC_ETM, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2), + SYSTEM <= PCR, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TEE <= TEE, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TRACE0 <= TRACE, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UHCI0 <= UHCI0, + USB_DEVICE <= USB_DEVICE, + MEM2MEM1 <= virtual, + MEM2MEM4 <= virtual, + MEM2MEM5 <= virtual, + MEM2MEM10 <= virtual, + MEM2MEM11 <= virtual, + MEM2MEM12 <= virtual, + MEM2MEM13 <= virtual, + MEM2MEM14 <= virtual, + MEM2MEM15 <= virtual, + ], + pins: [ + (0, [Input, Output, Analog] (2 => FSPIQ) (2 => FSPIQ)) + (1, [Input, Output, Analog] (2 => FSPICS0) (2 => FSPICS0)) + (2, [Input, Output, Analog] (2 => FSPIWP) (2 => FSPIWP)) + (3, [Input, Output, Analog] (2 => FSPIHD) (2 => FSPIHD)) + (4, [Input, Output, Analog] (2 => FSPICLK) (2 => FSPICLK_MUX)) + (5, [Input, Output, Analog] (2 => FSPID) (2 => FSPID)) + (6, [Input, Output]) + (7, [Input, Output]) + (8, [Input, Output]) + (9, [Input, Output]) + (10, [Input, Output]) + (11, [Input, Output]) + (12, [Input, Output]) + (13, [Input, Output]) + (14, [Input, Output]) + (15, [Input, Output] () (0 => SPICS0)) + (16, [Input, Output] (0 => SPIQ) (0 => SPIQ)) + (17, [Input, Output] (0 => SPIWP) (0 => SPIWP)) + (18, [Input, Output] (0 => SPIHD) (0 => SPIHD)) + (19, [Input, Output] () (0 => SPICLK)) + (20, [Input, Output] (0 => SPID) (0 => SPID)) + (21, [Input, Output]) + (22, [Input, Output]) + (23, [Input, Output] () (2 => FSPICS1)) + (24, [Input, Output] () (2 => FSPICS2)) + (25, [Input, Output] () (2 => FSPICS3)) + (26, [Input, Output] () (2 => FSPICS4)) + (27, [Input, Output] () (2 => FSPICS5)) + ] } diff --git a/esp-hal/src/soc/esp32s2/efuse/mod.rs b/esp-hal/src/soc/esp32s2/efuse/mod.rs index 6dd75ceca7c..99e168dbdea 100644 --- a/esp-hal/src/soc/esp32s2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32s2/efuse/mod.rs @@ -24,12 +24,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32s2/gpio.rs b/esp-hal/src/soc/esp32s2/gpio.rs index faa6b8bcd6d..58355676851 100644 --- a/esp-hal/src/soc/esp32s2/gpio.rs +++ b/esp-hal/src/soc/esp32s2/gpio.rs @@ -415,53 +415,6 @@ macro_rules! rtcio_analog { }; } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo]) - (1, [Input, Output, Analog, RtcIo]) - (2, [Input, Output, Analog, RtcIo]) - (3, [Input, Output, Analog, RtcIo]) - (4, [Input, Output, Analog, RtcIo]) - (5, [Input, Output, Analog, RtcIo]) - (6, [Input, Output, Analog, RtcIo]) - (7, [Input, Output, Analog, RtcIo]) - (8, [Input, Output, Analog, RtcIo]) - (9, [Input, Output, Analog, RtcIo]) - (10, [Input, Output, Analog, RtcIo]) - (11, [Input, Output, Analog, RtcIo]) - (12, [Input, Output, Analog, RtcIo]) - (13, [Input, Output, Analog, RtcIo]) - (14, [Input, Output, Analog, RtcIo]) - (15, [Input, Output, Analog, RtcIo]) - (16, [Input, Output, Analog, RtcIo]) - (17, [Input, Output, Analog, RtcIo]) - (18, [Input, Output, Analog, RtcIo]) - (19, [Input, Output, Analog, RtcIo]) - (20, [Input, Output, Analog, RtcIo]) - (21, [Input, Output, Analog, RtcIo]) - - (26, [Input, Output]) - (27, [Input, Output]) - (28, [Input, Output]) - (29, [Input, Output]) - (30, [Input, Output]) - (31, [Input, Output]) - (32, [Input, Output]) - (33, [Input, Output]) - (34, [Input, Output]) - (35, [Input, Output]) - (36, [Input, Output]) - (37, [Input, Output]) - (38, [Input, Output]) - (39, [Input, Output]) - (40, [Input, Output]) - (41, [Input, Output]) - (42, [Input, Output]) - (43, [Input, Output]) - (44, [Input, Output]) - (45, [Input, Output]) - (46, [Input, Output]) -} - rtcio_analog! { ( 0, touch_pad(0), "", touch_pad0_hold ) ( 1, touch_pad(1), "", touch_pad1_hold ) diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs index c96d1c7b171..81f67a9e5f0 100644 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ b/esp-hal/src/soc/esp32s2/peripherals.rs @@ -20,53 +20,100 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - ADC2 <= virtual, - AES <= AES, - DAC1 <= virtual, - DAC2 <= virtual, - DMA <= virtual, - DEDICATED_GPIO <= DEDICATED_GPIO, - DS <= DS, - EFUSE <= EFUSE, - EXTMEM <= EXTMEM, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HMAC <= HMAC, - I2C0 <= I2C0, - I2C1 <= I2C1, - I2S0 <= I2S0 (I2S0), - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - IO_MUX <= IO_MUX, - LEDC <= LEDC, - LPWR <= RTC_CNTL, - PCNT <= PCNT, - PMS <= PMS, - PSRAM <= virtual, - RADIO_CLK <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - RTC_IO <= RTC_IO, - RTC_I2C <= RTC_I2C, - SHA <= SHA, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2_DMA, SPI2), - SPI3 <= SPI3 (SPI3_DMA, SPI3), - SYSCON <= SYSCON, - SYSTEM <= SYSTEM, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UHCI0 <= UHCI0, - ULP_RISCV_CORE <= virtual, - USB0 <= USB0, - USB_WRAP <= USB_WRAP, - WIFI <= virtual, - XTS_AES <= XTS_AES, + peripherals: [ + ADC1 <= virtual, + ADC2 <= virtual, + AES <= AES, + DAC1 <= virtual, + DAC2 <= virtual, + DMA <= virtual, + DEDICATED_GPIO <= DEDICATED_GPIO, + DS <= DS, + EFUSE <= EFUSE, + EXTMEM <= EXTMEM, + GPIO_SD <= GPIO_SD, + HMAC <= HMAC, + I2C0 <= I2C0, + I2C1 <= I2C1, + I2S0 <= I2S0 (I2S0), + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + IO_MUX <= IO_MUX, + LEDC <= LEDC, + LPWR <= RTC_CNTL, + PCNT <= PCNT, + PMS <= PMS, + PSRAM <= virtual, + RADIO_CLK <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + RTC_IO <= RTC_IO, + RTC_I2C <= RTC_I2C, + SHA <= SHA, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2_DMA, SPI2), + SPI3 <= SPI3 (SPI3_DMA, SPI3), + SYSCON <= SYSCON, + SYSTEM <= SYSTEM, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UHCI0 <= UHCI0, + ULP_RISCV_CORE <= virtual, + USB0 <= USB0, + USB_WRAP <= USB_WRAP, + WIFI <= virtual, + XTS_AES <= XTS_AES, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo]) + (1, [Input, Output, Analog, RtcIo]) + (2, [Input, Output, Analog, RtcIo]) + (3, [Input, Output, Analog, RtcIo]) + (4, [Input, Output, Analog, RtcIo]) + (5, [Input, Output, Analog, RtcIo]) + (6, [Input, Output, Analog, RtcIo]) + (7, [Input, Output, Analog, RtcIo]) + (8, [Input, Output, Analog, RtcIo]) + (9, [Input, Output, Analog, RtcIo]) + (10, [Input, Output, Analog, RtcIo]) + (11, [Input, Output, Analog, RtcIo]) + (12, [Input, Output, Analog, RtcIo]) + (13, [Input, Output, Analog, RtcIo]) + (14, [Input, Output, Analog, RtcIo]) + (15, [Input, Output, Analog, RtcIo]) + (16, [Input, Output, Analog, RtcIo]) + (17, [Input, Output, Analog, RtcIo]) + (18, [Input, Output, Analog, RtcIo]) + (19, [Input, Output, Analog, RtcIo]) + (20, [Input, Output, Analog, RtcIo]) + (21, [Input, Output, Analog, RtcIo]) + + (26, [Input, Output]) + (27, [Input, Output]) + (28, [Input, Output]) + (29, [Input, Output]) + (30, [Input, Output]) + (31, [Input, Output]) + (32, [Input, Output]) + (33, [Input, Output]) + (34, [Input, Output]) + (35, [Input, Output]) + (36, [Input, Output]) + (37, [Input, Output]) + (38, [Input, Output]) + (39, [Input, Output]) + (40, [Input, Output]) + (41, [Input, Output]) + (42, [Input, Output]) + (43, [Input, Output]) + (44, [Input, Output]) + (45, [Input, Output]) + (46, [Input, Output]) + ] } diff --git a/esp-hal/src/soc/esp32s3/efuse/mod.rs b/esp-hal/src/soc/esp32s3/efuse/mod.rs index d4303daf85c..2d2257fe43d 100644 --- a/esp-hal/src/soc/esp32s3/efuse/mod.rs +++ b/esp-hal/src/soc/esp32s3/efuse/mod.rs @@ -22,12 +22,10 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::efuse::Efuse; -//! # use esp_hal::gpio::Io; //! # use esp_hal::uart::Uart; //! # use core::writeln; //! # use core::fmt::Write; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! # let mut serial_tx = Uart::new(peripherals.UART0, io.pins.gpio4, io.pins.gpio5).unwrap(); +//! # let mut serial_tx = Uart::new(peripherals.UART0, peripherals.GPIO4, peripherals.GPIO5).unwrap(); //! let mac_address = Efuse::read_base_mac_address(); //! writeln!( //! serial_tx, diff --git a/esp-hal/src/soc/esp32s3/gpio.rs b/esp-hal/src/soc/esp32s3/gpio.rs index 2822ec1cfa0..8c71a0ad109 100644 --- a/esp-hal/src/soc/esp32s3/gpio.rs +++ b/esp-hal/src/soc/esp32s3/gpio.rs @@ -447,54 +447,6 @@ macro_rules! rtcio_analog { }; } -crate::gpio! { - (0, [Input, Output, Analog, RtcIo]) - (1, [Input, Output, Analog, RtcIo]) - (2, [Input, Output, Analog, RtcIo]) - (3, [Input, Output, Analog, RtcIo]) - (4, [Input, Output, Analog, RtcIo]) - (5, [Input, Output, Analog, RtcIo]) - (6, [Input, Output, Analog, RtcIo]) - (7, [Input, Output, Analog, RtcIo]) - (8, [Input, Output, Analog, RtcIo] () (3 => SUBSPICS1)) - (9, [Input, Output, Analog, RtcIo] (3 => SUBSPIHD 4 => FSPIHD) (3 => SUBSPIHD 4 => FSPIHD)) - (10, [Input, Output, Analog, RtcIo] (2 => FSPIIO4 4 => FSPICS0) (2 => FSPIIO4 3 => SUBSPICS0 4 => FSPICS0)) - (11, [Input, Output, Analog, RtcIo] (2 => FSPIIO5 3 => SUBSPID 4 => FSPID) (2 => FSPIIO5 3 => SUBSPID 4 => FSPID)) - (12, [Input, Output, Analog, RtcIo] (2 => FSPIIO6 4 => FSPICLK) (2 => FSPIIO6 3=> SUBSPICLK 4 => FSPICLK)) - (13, [Input, Output, Analog, RtcIo] (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ) (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ)) - (14, [Input, Output, Analog, RtcIo] (3 => SUBSPIWP 4 => FSPIWP) (2 => FSPIDQS 3 => SUBSPIWP 4 => FSPIWP)) - (15, [Input, Output, Analog, RtcIo] () (2 => U0RTS)) - (16, [Input, Output, Analog, RtcIo] (2 => U0CTS) ()) - (17, [Input, Output, Analog, RtcIo] () (2 => U1TXD)) - (18, [Input, Output, Analog, RtcIo] (2 => U1RXD) ()) - (19, [Input, Output, Analog, RtcIo] () (2 => U1RTS)) - (20, [Input, Output, Analog, RtcIo] (2 => U1CTS) ()) - (21, [Input, Output, Analog, RtcIo]) - (26, [Input, Output]) - (27, [Input, Output]) - (28, [Input, Output]) - (29, [Input, Output]) - (30, [Input, Output]) - (31, [Input, Output]) - (32, [Input, Output]) - (33, [Input, Output] (2 => FSPIHD 3 => SUBSPIHD) (2 => FSPIHD 3 => SUBSPIHD)) - (34, [Input, Output] (2 => FSPICS0) (2 => FSPICS0 3 => SUBSPICS0)) - (35, [Input, Output] (2 => FSPID 3 => SUBSPID) (2 => FSPID 3 => SUBSPID)) - (36, [Input, Output] (2 => FSPICLK) (2 => FSPICLK 3 => SUBSPICLK)) - (37, [Input, Output] (2 => FSPIQ 3 => SUBSPIQ 4 => SPIDQS) (2 => FSPIQ 3=> SUBSPIQ 4 => SPIDQS)) - (38, [Input, Output] (2 => FSPIWP 3 => SUBSPIWP) (3 => FSPIWP 3 => SUBSPIWP)) - (39, [Input, Output] () (4 => SUBSPICS1)) - (40, [Input, Output]) - (41, [Input, Output]) - (42, [Input, Output]) - (43, [Input, Output]) - (44, [Input, Output]) - (45, [Input, Output]) - (46, [Input, Output]) - (47, [Input, Output]) - (48, [Input, Output]) -} - rtcio_analog! { ( 0, touch_pad(0), "", touch_pad0_hold ) ( 1, touch_pad(1), "", touch_pad1_hold ) diff --git a/esp-hal/src/soc/esp32s3/peripherals.rs b/esp-hal/src/soc/esp32s3/peripherals.rs index 9e0592abf52..c6ab886c9bf 100644 --- a/esp-hal/src/soc/esp32s3/peripherals.rs +++ b/esp-hal/src/soc/esp32s3/peripherals.rs @@ -20,63 +20,111 @@ pub(crate) use self::peripherals::*; // peripheral (no `PSRAM`, `RADIO`, etc. peripheral in the PACs), so we're // creating "virtual peripherals" for them. crate::peripherals! { - ADC1 <= virtual, - ADC2 <= virtual, - AES <= AES, - APB_CTRL <= APB_CTRL, - ASSIST_DEBUG <= ASSIST_DEBUG, - BT <= virtual, - CPU_CTRL <= virtual, - DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_IN_CH3,DMA_IN_CH4,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2,DMA_OUT_CH3,DMA_OUT_CH4), - DS <= DS, - EFUSE <= EFUSE, - EXTMEM <= EXTMEM, - GPIO <= GPIO (GPIO,GPIO_NMI), - GPIO_SD <= GPIO_SD, - HMAC <= HMAC, - I2C0 <= I2C0, - I2C1 <= I2C1, - I2S0 <= I2S0 (I2S0), - I2S1 <= I2S1 (I2S1), - INTERRUPT_CORE0 <= INTERRUPT_CORE0, - INTERRUPT_CORE1 <= INTERRUPT_CORE1, - IO_MUX <= IO_MUX, - LCD_CAM <= LCD_CAM, - LEDC <= LEDC, - LPWR <= RTC_CNTL, - PCNT <= PCNT, - PERI_BACKUP <= PERI_BACKUP, - PSRAM <= virtual, - MCPWM0 <= MCPWM0, - MCPWM1 <= MCPWM1, - RADIO_CLK <= virtual, - RMT <= RMT, - RNG <= RNG, - RSA <= RSA, - RTC_I2C <= RTC_I2C, - RTC_IO <= RTC_IO, - SENSITIVE <= SENSITIVE, - SHA <= SHA, - SPI0 <= SPI0, - SPI1 <= SPI1, - SPI2 <= SPI2 (SPI2), - SPI3 <= SPI3 (SPI3), - SYSTEM <= SYSTEM, - SYSTIMER <= SYSTIMER, - SW_INTERRUPT <= virtual, - TIMG0 <= TIMG0, - TIMG1 <= TIMG1, - TWAI0 <= TWAI0, - UART0 <= UART0, - UART1 <= UART1, - UART2 <= UART2, - UHCI0 <= UHCI0, - UHCI1 <= UHCI1, - ULP_RISCV_CORE <= virtual, - USB0 <= USB0, - USB_DEVICE <= USB_DEVICE, - USB_WRAP <= USB_WRAP, - WCL <= WCL, - WIFI <= virtual, - XTS_AES <= XTS_AES, + peripherals: [ + ADC1 <= virtual, + ADC2 <= virtual, + AES <= AES, + APB_CTRL <= APB_CTRL, + ASSIST_DEBUG <= ASSIST_DEBUG, + BT <= virtual, + CPU_CTRL <= virtual, + DMA <= DMA (DMA_IN_CH0,DMA_IN_CH1,DMA_IN_CH2,DMA_IN_CH3,DMA_IN_CH4,DMA_OUT_CH0,DMA_OUT_CH1,DMA_OUT_CH2,DMA_OUT_CH3,DMA_OUT_CH4), + DS <= DS, + EFUSE <= EFUSE, + EXTMEM <= EXTMEM, + GPIO_SD <= GPIO_SD, + HMAC <= HMAC, + I2C0 <= I2C0, + I2C1 <= I2C1, + I2S0 <= I2S0 (I2S0), + I2S1 <= I2S1 (I2S1), + INTERRUPT_CORE0 <= INTERRUPT_CORE0, + INTERRUPT_CORE1 <= INTERRUPT_CORE1, + IO_MUX <= IO_MUX, + LCD_CAM <= LCD_CAM, + LEDC <= LEDC, + LPWR <= RTC_CNTL, + PCNT <= PCNT, + PERI_BACKUP <= PERI_BACKUP, + PSRAM <= virtual, + MCPWM0 <= MCPWM0, + MCPWM1 <= MCPWM1, + RADIO_CLK <= virtual, + RMT <= RMT, + RNG <= RNG, + RSA <= RSA, + RTC_I2C <= RTC_I2C, + RTC_IO <= RTC_IO, + SENSITIVE <= SENSITIVE, + SHA <= SHA, + SPI0 <= SPI0, + SPI1 <= SPI1, + SPI2 <= SPI2 (SPI2), + SPI3 <= SPI3 (SPI3), + SYSTEM <= SYSTEM, + SYSTIMER <= SYSTIMER, + SW_INTERRUPT <= virtual, + TIMG0 <= TIMG0, + TIMG1 <= TIMG1, + TWAI0 <= TWAI0, + UART0 <= UART0, + UART1 <= UART1, + UART2 <= UART2, + UHCI0 <= UHCI0, + UHCI1 <= UHCI1, + ULP_RISCV_CORE <= virtual, + USB0 <= USB0, + USB_DEVICE <= USB_DEVICE, + USB_WRAP <= USB_WRAP, + WCL <= WCL, + WIFI <= virtual, + XTS_AES <= XTS_AES, + ], + pins: [ + (0, [Input, Output, Analog, RtcIo]) + (1, [Input, Output, Analog, RtcIo]) + (2, [Input, Output, Analog, RtcIo]) + (3, [Input, Output, Analog, RtcIo]) + (4, [Input, Output, Analog, RtcIo]) + (5, [Input, Output, Analog, RtcIo]) + (6, [Input, Output, Analog, RtcIo]) + (7, [Input, Output, Analog, RtcIo]) + (8, [Input, Output, Analog, RtcIo] () (3 => SUBSPICS1)) + (9, [Input, Output, Analog, RtcIo] (3 => SUBSPIHD 4 => FSPIHD) (3 => SUBSPIHD 4 => FSPIHD)) + (10, [Input, Output, Analog, RtcIo] (2 => FSPIIO4 4 => FSPICS0) (2 => FSPIIO4 3 => SUBSPICS0 4 => FSPICS0)) + (11, [Input, Output, Analog, RtcIo] (2 => FSPIIO5 3 => SUBSPID 4 => FSPID) (2 => FSPIIO5 3 => SUBSPID 4 => FSPID)) + (12, [Input, Output, Analog, RtcIo] (2 => FSPIIO6 4 => FSPICLK) (2 => FSPIIO6 3=> SUBSPICLK 4 => FSPICLK)) + (13, [Input, Output, Analog, RtcIo] (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ) (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ)) + (14, [Input, Output, Analog, RtcIo] (3 => SUBSPIWP 4 => FSPIWP) (2 => FSPIDQS 3 => SUBSPIWP 4 => FSPIWP)) + (15, [Input, Output, Analog, RtcIo] () (2 => U0RTS)) + (16, [Input, Output, Analog, RtcIo] (2 => U0CTS) ()) + (17, [Input, Output, Analog, RtcIo] () (2 => U1TXD)) + (18, [Input, Output, Analog, RtcIo] (2 => U1RXD) ()) + (19, [Input, Output, Analog, RtcIo] () (2 => U1RTS)) + (20, [Input, Output, Analog, RtcIo] (2 => U1CTS) ()) + (21, [Input, Output, Analog, RtcIo]) + (26, [Input, Output]) + (27, [Input, Output]) + (28, [Input, Output]) + (29, [Input, Output]) + (30, [Input, Output]) + (31, [Input, Output]) + (32, [Input, Output]) + (33, [Input, Output] (2 => FSPIHD 3 => SUBSPIHD) (2 => FSPIHD 3 => SUBSPIHD)) + (34, [Input, Output] (2 => FSPICS0) (2 => FSPICS0 3 => SUBSPICS0)) + (35, [Input, Output] (2 => FSPID 3 => SUBSPID) (2 => FSPID 3 => SUBSPID)) + (36, [Input, Output] (2 => FSPICLK) (2 => FSPICLK 3 => SUBSPICLK)) + (37, [Input, Output] (2 => FSPIQ 3 => SUBSPIQ 4 => SPIDQS) (2 => FSPIQ 3=> SUBSPIQ 4 => SPIDQS)) + (38, [Input, Output] (2 => FSPIWP 3 => SUBSPIWP) (3 => FSPIWP 3 => SUBSPIWP)) + (39, [Input, Output] () (4 => SUBSPICS1)) + (40, [Input, Output]) + (41, [Input, Output]) + (42, [Input, Output]) + (43, [Input, Output]) + (44, [Input, Output]) + (45, [Input, Output]) + (46, [Input, Output]) + (47, [Input, Output]) + (48, [Input, Output]) + ] } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 1609c7c2909..1430a5269c3 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -40,12 +40,10 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::spi::SpiMode; //! # use esp_hal::spi::master::{Config, Spi}; -//! # use esp_hal::gpio::Io; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let sclk = io.pins.gpio0; -//! let miso = io.pins.gpio2; -//! let mosi = io.pins.gpio1; -//! let cs = io.pins.gpio5; +//! let sclk = peripherals.GPIO0; +//! let miso = peripherals.GPIO2; +//! let mosi = peripherals.GPIO1; +//! let cs = peripherals.GPIO5; //! //! let mut spi = Spi::new_with_config( //! peripherals.SPI2, diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 86a80ffdca4..0ffd707d1eb 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -20,15 +20,13 @@ //! # use esp_hal::spi::SpiMode; //! # use esp_hal::spi::slave::Spi; //! # use esp_hal::dma::Dma; -//! # use esp_hal::gpio::Io; //! let dma = Dma::new(peripherals.DMA); #![cfg_attr(pdma, doc = "let dma_channel = dma.spi2channel;")] #![cfg_attr(gdma, doc = "let dma_channel = dma.channel0;")] -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let sclk = io.pins.gpio0; -//! let miso = io.pins.gpio1; -//! let mosi = io.pins.gpio2; -//! let cs = io.pins.gpio3; +//! let sclk = peripherals.GPIO0; +//! let miso = peripherals.GPIO1; +//! let mosi = peripherals.GPIO2; +//! let cs = peripherals.GPIO3; //! //! let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = //! dma_buffers!(32000); diff --git a/esp-hal/src/touch.rs b/esp-hal/src/touch.rs index be397dc10ba..66e8dc1c742 100644 --- a/esp-hal/src/touch.rs +++ b/esp-hal/src/touch.rs @@ -10,9 +10,7 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::touch::{Touch, TouchPad}; -//! # use esp_hal::gpio::Io; -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); -//! let touch_pin0 = io.pins.gpio2; +//! let touch_pin0 = peripherals.GPIO2; //! let touch = Touch::continuous_mode(peripherals.TOUCH, None); //! let mut touchpad = TouchPad::new(touch_pin0, &touch); //! // ... give the peripheral some time for the measurement diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index a89d5cfda3d..cfbb1f7ead0 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -32,14 +32,12 @@ //! # use esp_hal::twai::TwaiConfiguration; //! # use esp_hal::twai::BaudRate; //! # use esp_hal::twai::TwaiMode; -//! # use esp_hal::gpio::Io; //! # use embedded_can::Frame; //! # use nb::block; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! // Use GPIO pins 2 and 3 to connect to the respective pins on the TWAI //! // transceiver. -//! let can_rx_pin = io.pins.gpio3; -//! let can_tx_pin = io.pins.gpio2; +//! let can_rx_pin = peripherals.GPIO3; +//! let can_tx_pin = peripherals.GPIO2; //! //! // The speed of the TWAI bus. //! const TWAI_BAUDRATE: twai::BaudRate = BaudRate::B1000K; @@ -86,14 +84,12 @@ //! # use esp_hal::twai::EspTwaiFrame; //! # use esp_hal::twai::StandardId; //! # use esp_hal::twai::TwaiMode; -//! # use esp_hal::gpio::Io; //! # use embedded_can::Frame; //! # use nb::block; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! // Use GPIO pins 2 and 3 to connect to the respective pins on the TWAI //! // transceiver. -//! let can_rx_pin = io.pins.gpio3; -//! let can_tx_pin = io.pins.gpio2; +//! let can_rx_pin = peripherals.GPIO3; +//! let can_tx_pin = peripherals.GPIO2; //! //! // The speed of the TWAI bus. //! const TWAI_BAUDRATE: twai::BaudRate = BaudRate::B1000K; diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index ef1ccb9e3b0..b67f6b97427 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -23,14 +23,11 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::Uart; -//! use esp_hal::gpio::Io; -//! -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! let mut uart1 = Uart::new( //! peripherals.UART1, -//! io.pins.gpio1, -//! io.pins.gpio2, +//! peripherals.GPIO1, +//! peripherals.GPIO2, //! ).unwrap(); //! # } //! ``` @@ -56,13 +53,11 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{Config, Uart}; -//! # use esp_hal::gpio::Io; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( //! # peripherals.UART1, //! # Config::default(), -//! # io.pins.gpio1, -//! # io.pins.gpio2, +//! # peripherals.GPIO1, +//! # peripherals.GPIO2, //! # ).unwrap(); //! // Write bytes out over the UART: //! uart1.write_bytes(b"Hello, world!").expect("write error!"); @@ -73,13 +68,11 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{Config, Uart}; -//! # use esp_hal::gpio::Io; -//! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( //! # peripherals.UART1, //! # Config::default(), -//! # io.pins.gpio1, -//! # io.pins.gpio2, +//! # peripherals.GPIO1, +//! # peripherals.GPIO2, //! # ).unwrap(); //! // The UART can be split into separate Transmit and Receive components: //! let (mut rx, mut tx) = uart1.split(); @@ -94,12 +87,9 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::Uart; -//! use esp_hal::gpio::Io; -//! -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! -//! let (rx, _) = io.pins.gpio2.split(); -//! let (_, tx) = io.pins.gpio1.split(); +//! let (rx, _) = peripherals.GPIO2.split(); +//! let (_, tx) = peripherals.GPIO1.split(); //! let mut uart1 = Uart::new( //! peripherals.UART1, //! rx.inverted(), @@ -112,12 +102,9 @@ //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{UartTx, UartRx}; -//! use esp_hal::gpio::Io; -//! -//! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! -//! let tx = UartTx::new(peripherals.UART0, io.pins.gpio1).unwrap(); -//! let rx = UartRx::new(peripherals.UART1, io.pins.gpio2).unwrap(); +//! let tx = UartTx::new(peripherals.UART0, peripherals.GPIO1).unwrap(); +//! let rx = UartRx::new(peripherals.UART1, peripherals.GPIO2).unwrap(); //! # } //! ``` //! diff --git a/examples/src/bin/adc.rs b/examples/src/bin/adc.rs index 08fe4b3786a..e4c8eb2b423 100644 --- a/examples/src/bin/adc.rs +++ b/examples/src/bin/adc.rs @@ -20,7 +20,6 @@ use esp_backtrace as _; use esp_hal::{ analog::adc::{Adc, AdcConfig, Attenuation}, delay::Delay, - gpio::Io, prelude::*, }; use esp_println::println; @@ -29,14 +28,13 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let analog_pin = io.pins.gpio32; + let analog_pin = peripherals.GPIO32; } else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] { - let analog_pin = io.pins.gpio3; + let analog_pin = peripherals.GPIO3; } else { - let analog_pin = io.pins.gpio2; + let analog_pin = peripherals.GPIO2; } } diff --git a/examples/src/bin/adc_cal.rs b/examples/src/bin/adc_cal.rs index a025a6ba52f..e7d6ceb859d 100644 --- a/examples/src/bin/adc_cal.rs +++ b/examples/src/bin/adc_cal.rs @@ -16,7 +16,6 @@ use esp_backtrace as _; use esp_hal::{ analog::adc::{Adc, AdcConfig, Attenuation}, delay::Delay, - gpio::Io, prelude::*, }; use esp_println::println; @@ -25,12 +24,11 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { if #[cfg(feature = "esp32s3")] { - let analog_pin = io.pins.gpio3; + let analog_pin = peripherals.GPIO3; } else { - let analog_pin = io.pins.gpio2; + let analog_pin = peripherals.GPIO2; } } diff --git a/examples/src/bin/advanced_serial.rs b/examples/src/bin/advanced_serial.rs index b0c4e8d90b3..6012abc4abc 100644 --- a/examples/src/bin/advanced_serial.rs +++ b/examples/src/bin/advanced_serial.rs @@ -13,7 +13,7 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{delay::Delay, gpio::Io, prelude::*, uart::Uart}; +use esp_hal::{delay::Delay, prelude::*, uart::Uart}; use esp_println::println; use nb::block; @@ -21,9 +21,7 @@ use nb::block; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let mut serial1 = Uart::new(peripherals.UART1, io.pins.gpio4, io.pins.gpio5).unwrap(); + let mut serial1 = Uart::new(peripherals.UART1, peripherals.GPIO4, peripherals.GPIO5).unwrap(); let delay = Delay::new(); diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs index f863b8b19b8..f804dda603f 100644 --- a/examples/src/bin/blinky.rs +++ b/examples/src/bin/blinky.rs @@ -11,7 +11,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::{Io, Level, Output}, + gpio::{Level, Output}, prelude::*, }; @@ -20,8 +20,8 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); // Set GPIO0 as an output, and set its state high initially. - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut led = Output::new(io.pins.gpio0, Level::High); + + let mut led = Output::new(peripherals.GPIO0, Level::High); let delay = Delay::new(); diff --git a/examples/src/bin/blinky_erased_pins.rs b/examples/src/bin/blinky_erased_pins.rs index 48d9309f088..140e728e1aa 100644 --- a/examples/src/bin/blinky_erased_pins.rs +++ b/examples/src/bin/blinky_erased_pins.rs @@ -14,7 +14,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::{Input, Io, Level, Output, Pin, Pull}, + gpio::{Input, Level, Output, Pin, Pull}, prelude::*, }; @@ -22,18 +22,16 @@ use esp_hal::{ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Set LED GPIOs as an output: - let led1 = Output::new(io.pins.gpio2.degrade(), Level::Low); - let led2 = Output::new(io.pins.gpio4.degrade(), Level::Low); - let led3 = Output::new(io.pins.gpio5.degrade(), Level::Low); + let led1 = Output::new(peripherals.GPIO2.degrade(), Level::Low); + let led2 = Output::new(peripherals.GPIO4.degrade(), Level::Low); + let led3 = Output::new(peripherals.GPIO5.degrade(), Level::Low); // Use boot button as an input: #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] - let button = io.pins.gpio0.degrade(); + let button = peripherals.GPIO0.degrade(); #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] - let button = io.pins.gpio9.degrade(); + let button = peripherals.GPIO9.degrade(); let button = Input::new(button, Pull::Up); diff --git a/examples/src/bin/dac.rs b/examples/src/bin/dac.rs index d83740d97da..4bd42b29860 100644 --- a/examples/src/bin/dac.rs +++ b/examples/src/bin/dac.rs @@ -19,21 +19,19 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{analog::dac::Dac, delay::Delay, gpio::Io, prelude::*}; +use esp_hal::{analog::dac::Dac, delay::Delay, prelude::*}; #[entry] fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let dac1_pin = io.pins.gpio25; - let dac2_pin = io.pins.gpio26; + let dac1_pin = peripherals.GPIO25; + let dac2_pin = peripherals.GPIO26; } else if #[cfg(feature = "esp32s2")] { - let dac1_pin = io.pins.gpio17; - let dac2_pin = io.pins.gpio18; + let dac1_pin = peripherals.GPIO17; + let dac2_pin = peripherals.GPIO18; } } diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index 64c046695a7..2b7f467ee53 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -20,7 +20,6 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, i2c::master::{Config, I2c}, prelude::*, timer::timg::TimerGroup, @@ -34,15 +33,13 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let i2c0 = I2c::new(peripherals.I2C0, { let mut config = Config::default(); config.frequency = 400.kHz(); config }) - .with_sda(io.pins.gpio4) - .with_scl(io.pins.gpio5) + .with_sda(peripherals.GPIO4) + .with_scl(peripherals.GPIO5) .into_async(); let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap(); diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 204f9e61f38..1f7ff1525af 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -21,7 +21,6 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, i2c::master::{Config, I2c}, prelude::*, timer::timg::TimerGroup, @@ -34,15 +33,13 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut i2c = I2c::new(peripherals.I2C0, { let mut config = Config::default(); config.frequency = 400.kHz(); config }) - .with_sda(io.pins.gpio4) - .with_scl(io.pins.gpio5) + .with_sda(peripherals.GPIO4) + .with_scl(peripherals.GPIO5) .into_async(); loop { diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs index 322b5e4a95b..927b95ded17 100644 --- a/examples/src/bin/embassy_i2s_parallel.rs +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -20,7 +20,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority, DmaTxBuf}, dma_buffers, - gpio::Io, i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, timer::timg::TimerGroup, @@ -35,7 +34,6 @@ async fn main(_spawner: Spawner) { info!("Starting!"); let peripherals = esp_hal::init(esp_hal::Config::default()); let dma = Dma::new(peripherals.DMA); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let timg0 = TimerGroup::new(peripherals.TIMG0); @@ -44,17 +42,17 @@ async fn main(_spawner: Spawner) { let dma_channel = dma.i2s1channel; let i2s = peripherals.I2S1; - let clock = io.pins.gpio25; + let clock = peripherals.GPIO25; let pins = TxEightBits::new( - io.pins.gpio16, - io.pins.gpio4, - io.pins.gpio17, - io.pins.gpio18, - io.pins.gpio5, - io.pins.gpio19, - io.pins.gpio12, - io.pins.gpio14, + peripherals.GPIO16, + peripherals.GPIO4, + peripherals.GPIO17, + peripherals.GPIO18, + peripherals.GPIO5, + peripherals.GPIO19, + peripherals.GPIO12, + peripherals.GPIO14, ); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index 196793e9c23..612ee4ad9f5 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -22,7 +22,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, i2s::master::{DataFormat, I2s, Standard}, prelude::*, timer::timg::TimerGroup, @@ -37,8 +36,6 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); #[cfg(any(feature = "esp32", feature = "esp32s2"))] let dma_channel = dma.i2s0channel; @@ -59,13 +56,13 @@ async fn main(_spawner: Spawner) { .into_async(); #[cfg(not(feature = "esp32"))] - let i2s = i2s.with_mclk(io.pins.gpio0); + let i2s = i2s.with_mclk(peripherals.GPIO0); let i2s_rx = i2s .i2s_rx - .with_bclk(io.pins.gpio2) - .with_ws(io.pins.gpio4) - .with_din(io.pins.gpio5) + .with_bclk(peripherals.GPIO2) + .with_ws(peripherals.GPIO4) + .with_din(peripherals.GPIO5) .build(); let buffer = rx_buffer; diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index dd48f782738..fd06eff7a00 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -36,7 +36,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, i2s::master::{DataFormat, I2s, Standard}, prelude::*, timer::timg::TimerGroup, @@ -59,8 +58,6 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); #[cfg(any(feature = "esp32", feature = "esp32s2"))] let dma_channel = dma.i2s0channel; @@ -82,9 +79,9 @@ async fn main(_spawner: Spawner) { let i2s_tx = i2s .i2s_tx - .with_bclk(io.pins.gpio2) - .with_ws(io.pins.gpio4) - .with_dout(io.pins.gpio5) + .with_bclk(peripherals.GPIO2) + .with_ws(peripherals.GPIO4) + .with_dout(peripherals.GPIO5) .build(); let data = diff --git a/examples/src/bin/embassy_multicore.rs b/examples/src/bin/embassy_multicore.rs index 741b196bb2c..6def339d64d 100644 --- a/examples/src/bin/embassy_multicore.rs +++ b/examples/src/bin/embassy_multicore.rs @@ -21,7 +21,7 @@ use esp_backtrace as _; use esp_hal::{ cpu_control::{CpuControl, Stack}, get_core, - gpio::{Io, Level, Output}, + gpio::{Level, Output}, timer::{timg::TimerGroup, AnyTimer}, }; use esp_hal_embassy::Executor; @@ -53,8 +53,6 @@ async fn control_led( async fn main(_spawner: Spawner) { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let timg0 = TimerGroup::new(peripherals.TIMG0); let timer0: AnyTimer = timg0.timer0.into(); let timer1: AnyTimer = timg0.timer1.into(); @@ -65,7 +63,7 @@ async fn main(_spawner: Spawner) { static LED_CTRL: StaticCell> = StaticCell::new(); let led_ctrl_signal = &*LED_CTRL.init(Signal::new()); - let led = Output::new(io.pins.gpio0, Level::Low); + let led = Output::new(peripherals.GPIO0, Level::Low); let _guard = cpu_control .start_app_core(unsafe { &mut *addr_of_mut!(APP_CORE_STACK) }, move || { diff --git a/examples/src/bin/embassy_multicore_interrupt.rs b/examples/src/bin/embassy_multicore_interrupt.rs index 1b427ebe7b5..7a1de606c95 100644 --- a/examples/src/bin/embassy_multicore_interrupt.rs +++ b/examples/src/bin/embassy_multicore_interrupt.rs @@ -20,7 +20,7 @@ use esp_backtrace as _; use esp_hal::{ cpu_control::{CpuControl, Stack}, get_core, - gpio::{Io, Level, Output}, + gpio::{Level, Output}, interrupt::{software::SoftwareInterruptControl, Priority}, prelude::*, timer::{timg::TimerGroup, AnyTimer}, @@ -75,8 +75,6 @@ fn main() -> ! { let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let timg0 = TimerGroup::new(peripherals.TIMG0); let timer0: AnyTimer = timg0.timer0.into(); let timer1: AnyTimer = timg0.timer1.into(); @@ -87,7 +85,7 @@ fn main() -> ! { static LED_CTRL: StaticCell> = StaticCell::new(); let led_ctrl_signal = &*LED_CTRL.init(Signal::new()); - let led = Output::new(io.pins.gpio0, Level::Low); + let led = Output::new(peripherals.GPIO0, Level::Low); static EXECUTOR_CORE_1: StaticCell> = StaticCell::new(); let executor_core1 = InterruptExecutor::new(sw_ints.software_interrupt1); diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 95e28f696ee..9b589992dc0 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -16,7 +16,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, parl_io::{no_clk_pin, BitPackOrder, ParlIoRxOnly, RxFourBits}, prelude::*, timer::systimer::{SystemTimer, Target}, @@ -31,14 +30,17 @@ async fn main(_spawner: Spawner) { let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); esp_hal_embassy::init(systimer.alarm0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0); let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; - let mut rx_pins = RxFourBits::new(io.pins.gpio1, io.pins.gpio2, io.pins.gpio3, io.pins.gpio4); + let mut rx_pins = RxFourBits::new( + peripherals.GPIO1, + peripherals.GPIO2, + peripherals.GPIO3, + peripherals.GPIO4, + ); let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index e177ad506d9..44302552bde 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -20,7 +20,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, parl_io::{ BitPackOrder, ClkOutPin, @@ -42,16 +41,19 @@ async fn main(_spawner: Spawner) { let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); esp_hal_embassy::init(systimer.alarm0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000); let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; - let tx_pins = TxFourBits::new(io.pins.gpio1, io.pins.gpio2, io.pins.gpio3, io.pins.gpio4); + let tx_pins = TxFourBits::new( + peripherals.GPIO1, + peripherals.GPIO2, + peripherals.GPIO3, + peripherals.GPIO4, + ); - let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, io.pins.gpio5); + let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5); let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, @@ -63,7 +65,7 @@ async fn main(_spawner: Spawner) { ) .unwrap(); - let mut clock_pin = ClkOutPin::new(io.pins.gpio8); + let mut clock_pin = ClkOutPin::new(peripherals.GPIO8); let mut parl_io_tx = parl_io .tx diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 4ebfd23c56e..08c5f8bc28d 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -13,7 +13,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::{Io, Level, Output}, + gpio::{Level, Output}, prelude::*, rmt::{PulseCode, Rmt, RxChannelAsync, RxChannelConfig, RxChannelCreatorAsync}, timer::timg::TimerGroup, @@ -44,8 +44,6 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { let freq = 32.MHz(); @@ -63,16 +61,16 @@ async fn main(spawner: Spawner) { cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2"))] { - let mut channel = rmt.channel0.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel0.configure(peripherals.GPIO4, rx_config).unwrap(); } else if #[cfg(feature = "esp32s3")] { - let mut channel = rmt.channel7.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel7.configure(peripherals.GPIO4, rx_config).unwrap(); } else { - let mut channel = rmt.channel2.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel2.configure(peripherals.GPIO4, rx_config).unwrap(); } } spawner - .spawn(signal_task(Output::new(io.pins.gpio5, Level::Low))) + .spawn(signal_task(Output::new(peripherals.GPIO5, Level::Low))) .unwrap(); let mut data = [PulseCode { diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 79413f3c8b6..5943c453700 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -15,7 +15,6 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, prelude::*, rmt::{PulseCode, Rmt, TxChannelAsync, TxChannelConfig, TxChannelCreatorAsync}, timer::timg::TimerGroup, @@ -30,8 +29,6 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { let freq = 32.MHz(); @@ -45,7 +42,7 @@ async fn main(_spawner: Spawner) { let mut channel = rmt .channel0 .configure( - io.pins.gpio4, + peripherals.GPIO4, TxChannelConfig { clk_divider: 255, ..TxChannelConfig::default() diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index 40d25ef0cfd..643bac9285c 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -13,7 +13,6 @@ use embassy_executor::Spawner; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, signal::Signal}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, timer::timg::TimerGroup, uart::{AtCmdConfig, Config, Uart, UartRx, UartTx}, Async, @@ -71,22 +70,20 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Default pins for Uart/Serial communication cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let (tx_pin, rx_pin) = (io.pins.gpio1, io.pins.gpio3); + let (tx_pin, rx_pin) = (peripherals.GPIO1, peripherals.GPIO3); } else if #[cfg(feature = "esp32c2")] { - let (tx_pin, rx_pin) = (io.pins.gpio20, io.pins.gpio19); + let (tx_pin, rx_pin) = (peripherals.GPIO20, peripherals.GPIO19); } else if #[cfg(feature = "esp32c3")] { - let (tx_pin, rx_pin) = (io.pins.gpio21, io.pins.gpio20); + let (tx_pin, rx_pin) = (peripherals.GPIO21, peripherals.GPIO20); } else if #[cfg(feature = "esp32c6")] { - let (tx_pin, rx_pin) = (io.pins.gpio16, io.pins.gpio17); + let (tx_pin, rx_pin) = (peripherals.GPIO16, peripherals.GPIO17); } else if #[cfg(feature = "esp32h2")] { - let (tx_pin, rx_pin) = (io.pins.gpio24, io.pins.gpio23); + let (tx_pin, rx_pin) = (peripherals.GPIO24, peripherals.GPIO23); } else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] { - let (tx_pin, rx_pin) = (io.pins.gpio43, io.pins.gpio44); + let (tx_pin, rx_pin) = (peripherals.GPIO43, peripherals.GPIO44); } } diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 702b30046de..82a7813f884 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -24,7 +24,6 @@ use esp_backtrace as _; use esp_hal::{ dma::*, dma_buffers, - gpio::Io, prelude::*, spi::{ master::{Config, Spi}, @@ -41,11 +40,10 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let miso = io.pins.gpio2; - let mosi = io.pins.gpio4; - let cs = io.pins.gpio5; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO2; + let mosi = peripherals.GPIO4; + let cs = peripherals.GPIO5; let dma = Dma::new(peripherals.DMA); diff --git a/examples/src/bin/embassy_touch.rs b/examples/src/bin/embassy_touch.rs index 808caf2a869..2849d178343 100644 --- a/examples/src/bin/embassy_touch.rs +++ b/examples/src/bin/embassy_touch.rs @@ -17,7 +17,6 @@ use embassy_futures::select::{select, Either}; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, rtc_cntl::Rtc, timer::timg::TimerGroup, touch::{Touch, TouchConfig, TouchPad}, @@ -32,11 +31,10 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let mut rtc = Rtc::new(peripherals.LPWR); - let touch_pin0 = io.pins.gpio2; - let touch_pin1 = io.pins.gpio4; + let touch_pin0 = peripherals.GPIO2; + let touch_pin1 = peripherals.GPIO4; let touch_cfg = Some(TouchConfig { measurement_duration: Some(0x2000), diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 36b94aa42b4..d788c75301f 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -35,7 +35,6 @@ use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel}; use embedded_can::{Frame, Id}; use esp_backtrace as _; use esp_hal::{ - gpio::Io, timer::timg::TimerGroup, twai::{self, EspTwaiFrame, StandardId, TwaiMode, TwaiRx, TwaiTx}, }; @@ -92,13 +91,11 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Without an external transceiver, we only need a single line between the two MCUs. - let (rx_pin, tx_pin) = io.pins.gpio2.split(); + let (rx_pin, tx_pin) = peripherals.GPIO2.split(); // Use these if you want to use an external transceiver: - // let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; + // let tx_pin = peripherals.GPIO2; + // let rx_pin = peripherals.GPIO0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/examples/src/bin/embassy_usb_serial.rs b/examples/src/bin/embassy_usb_serial.rs index e2054358dd3..207ae1132a1 100644 --- a/examples/src/bin/embassy_usb_serial.rs +++ b/examples/src/bin/embassy_usb_serial.rs @@ -21,7 +21,6 @@ use embassy_usb::{ }; use esp_backtrace as _; use esp_hal::{ - gpio::Io, otg_fs::{ asynch::{Config, Driver}, Usb, @@ -37,9 +36,7 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let usb = Usb::new(peripherals.USB0, io.pins.gpio20, io.pins.gpio19); + let usb = Usb::new(peripherals.USB0, peripherals.GPIO20, peripherals.GPIO19); // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 1024]; diff --git a/examples/src/bin/embassy_wait.rs b/examples/src/bin/embassy_wait.rs index 9f80b2dbc9d..b78a85ff3c4 100644 --- a/examples/src/bin/embassy_wait.rs +++ b/examples/src/bin/embassy_wait.rs @@ -12,7 +12,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, timer::timg::TimerGroup, }; @@ -24,13 +24,11 @@ async fn main(_spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] { - let mut input = Input::new(io.pins.gpio0, Pull::Down); + let mut input = Input::new(peripherals.GPIO0, Pull::Down); } else { - let mut input = Input::new(io.pins.gpio9, Pull::Down); + let mut input = Input::new(peripherals.GPIO9, Pull::Down); } } diff --git a/examples/src/bin/etm_blinky_systimer.rs b/examples/src/bin/etm_blinky_systimer.rs index 65b141bfb51..1cdb361e2ef 100644 --- a/examples/src/bin/etm_blinky_systimer.rs +++ b/examples/src/bin/etm_blinky_systimer.rs @@ -13,7 +13,6 @@ use esp_hal::{ etm::Etm, gpio::{ etm::{Channels, OutputConfig}, - Io, Level, Pull, }, @@ -31,8 +30,7 @@ fn main() -> ! { let mut alarm0 = syst_alarms.alarm0; alarm0.set_period(1u32.secs()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut led = io.pins.gpio1; + let mut led = peripherals.GPIO1; // setup ETM let gpio_ext = Channels::new(peripherals.GPIO_SD); diff --git a/examples/src/bin/etm_gpio.rs b/examples/src/bin/etm_gpio.rs index 83cf726c4ab..d28b1bc3683 100644 --- a/examples/src/bin/etm_gpio.rs +++ b/examples/src/bin/etm_gpio.rs @@ -13,7 +13,6 @@ use esp_hal::{ etm::Etm, gpio::{ etm::{Channels, InputConfig, OutputConfig}, - Io, Level, Output, Pull, @@ -25,10 +24,8 @@ use esp_hal::{ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let mut led = Output::new(io.pins.gpio1, Level::Low); - let button = io.pins.gpio9; + let mut led = Output::new(peripherals.GPIO1, Level::Low); + let button = peripherals.GPIO9; led.set_high(); diff --git a/examples/src/bin/gpio_interrupt.rs b/examples/src/bin/gpio_interrupt.rs index 07e77725e12..befe9d6dc84 100644 --- a/examples/src/bin/gpio_interrupt.rs +++ b/examples/src/bin/gpio_interrupt.rs @@ -30,15 +30,15 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); // Set GPIO2 as an output, and set its state high initially. - let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let mut io = Io::new(peripherals.IO_MUX); io.set_interrupt_handler(handler); - let mut led = Output::new(io.pins.gpio2, Level::Low); + let mut led = Output::new(peripherals.GPIO2, Level::Low); cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] { - let button = io.pins.gpio0; + let button = peripherals.GPIO0; } else { - let button = io.pins.gpio9; + let button = peripherals.GPIO9; } } diff --git a/examples/src/bin/hello_world.rs b/examples/src/bin/hello_world.rs index b4e280c1f0a..a90ebb234c2 100644 --- a/examples/src/bin/hello_world.rs +++ b/examples/src/bin/hello_world.rs @@ -15,7 +15,7 @@ use core::fmt::Write; use esp_backtrace as _; -use esp_hal::{delay::Delay, gpio::Io, prelude::*, uart::Uart}; +use esp_hal::{delay::Delay, prelude::*, uart::Uart}; #[entry] fn main() -> ! { @@ -23,22 +23,20 @@ fn main() -> ! { let delay = Delay::new(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Default pins for Uart/Serial communication cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio1, io.pins.gpio3); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO1, peripherals.GPIO3); } else if #[cfg(feature = "esp32c2")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio20, io.pins.gpio19); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO20, peripherals.GPIO19); } else if #[cfg(feature = "esp32c3")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio21, io.pins.gpio20); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO21, peripherals.GPIO20); } else if #[cfg(feature = "esp32c6")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio16, io.pins.gpio17); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO16, peripherals.GPIO17); } else if #[cfg(feature = "esp32h2")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio24, io.pins.gpio23); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO24, peripherals.GPIO23); } else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio43, io.pins.gpio44); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO43, peripherals.GPIO44); } } diff --git a/examples/src/bin/i2c_bmp180_calibration_data.rs b/examples/src/bin/i2c_bmp180_calibration_data.rs index 7d75aa73adc..2d765fc31c2 100644 --- a/examples/src/bin/i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/i2c_bmp180_calibration_data.rs @@ -13,7 +13,6 @@ use esp_backtrace as _; use esp_hal::{ - gpio::Io, i2c::master::{Config, I2c}, prelude::*, }; @@ -23,13 +22,11 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Create a new peripheral object with the described wiring and standard // I2C clock speed: let mut i2c = I2c::new(peripherals.I2C0, Config::default()) - .with_sda(io.pins.gpio4) - .with_scl(io.pins.gpio5); + .with_sda(peripherals.GPIO4) + .with_scl(peripherals.GPIO5); loop { let mut data = [0u8; 22]; diff --git a/examples/src/bin/i2c_display.rs b/examples/src/bin/i2c_display.rs index cf17fa0a02e..c950def05fb 100644 --- a/examples/src/bin/i2c_display.rs +++ b/examples/src/bin/i2c_display.rs @@ -24,7 +24,6 @@ use embedded_graphics::{ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, i2c::master::{Config, I2c}, prelude::*, }; @@ -35,13 +34,12 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); let delay = Delay::new(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); // Create a new peripheral object with the described wiring // and standard I2C clock speed let i2c = I2c::new(peripherals.I2C0, Config::default()) - .with_sda(io.pins.gpio4) - .with_scl(io.pins.gpio5); + .with_sda(peripherals.GPIO4) + .with_scl(peripherals.GPIO5); // Initialize display let interface = I2CDisplayInterface::new(i2c); diff --git a/examples/src/bin/i2s_parallel.rs b/examples/src/bin/i2s_parallel.rs index 4effbf654f0..5f1bd400a3f 100644 --- a/examples/src/bin/i2s_parallel.rs +++ b/examples/src/bin/i2s_parallel.rs @@ -18,7 +18,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority, DmaTxBuf}, dma_buffers, - gpio::Io, i2s::parallel::{I2sParallel, TxEightBits}, prelude::*, }; @@ -32,23 +31,22 @@ fn main() -> ! { info!("Starting!"); let peripherals = esp_hal::init(esp_hal::Config::default()); let dma = Dma::new(peripherals.DMA); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let delay = Delay::new(); let dma_channel = dma.i2s1channel; let i2s = peripherals.I2S1; - let clock = io.pins.gpio25; + let clock = peripherals.GPIO25; let pins = TxEightBits::new( - io.pins.gpio16, - io.pins.gpio4, - io.pins.gpio17, - io.pins.gpio18, - io.pins.gpio5, - io.pins.gpio19, - io.pins.gpio12, - io.pins.gpio14, + peripherals.GPIO16, + peripherals.GPIO4, + peripherals.GPIO17, + peripherals.GPIO18, + peripherals.GPIO5, + peripherals.GPIO19, + peripherals.GPIO12, + peripherals.GPIO14, ); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); diff --git a/examples/src/bin/i2s_read.rs b/examples/src/bin/i2s_read.rs index 4e2278ff632..6697053cedb 100644 --- a/examples/src/bin/i2s_read.rs +++ b/examples/src/bin/i2s_read.rs @@ -20,7 +20,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, i2s::master::{DataFormat, I2s, Standard}, prelude::*, }; @@ -30,8 +29,6 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); #[cfg(any(feature = "esp32", feature = "esp32s2"))] let dma_channel = dma.i2s0channel; @@ -55,13 +52,13 @@ fn main() -> ! { ); #[cfg(not(feature = "esp32"))] - let i2s = i2s.with_mclk(io.pins.gpio0); + let i2s = i2s.with_mclk(peripherals.GPIO0); let mut i2s_rx = i2s .i2s_rx - .with_bclk(io.pins.gpio2) - .with_ws(io.pins.gpio4) - .with_din(io.pins.gpio5) + .with_bclk(peripherals.GPIO2) + .with_ws(peripherals.GPIO4) + .with_din(peripherals.GPIO5) .build(); let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer).unwrap(); diff --git a/examples/src/bin/i2s_sound.rs b/examples/src/bin/i2s_sound.rs index 8058ef82361..de24c709b18 100644 --- a/examples/src/bin/i2s_sound.rs +++ b/examples/src/bin/i2s_sound.rs @@ -34,7 +34,6 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, i2s::master::{DataFormat, I2s, Standard}, prelude::*, }; @@ -51,8 +50,6 @@ const SINE: [i16; 64] = [ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); #[cfg(any(feature = "esp32", feature = "esp32s2"))] let dma_channel = dma.i2s0channel; @@ -73,9 +70,9 @@ fn main() -> ! { let mut i2s_tx = i2s .i2s_tx - .with_bclk(io.pins.gpio2) - .with_ws(io.pins.gpio4) - .with_dout(io.pins.gpio5) + .with_bclk(peripherals.GPIO2) + .with_ws(peripherals.GPIO4) + .with_dout(peripherals.GPIO5) .build(); let data = diff --git a/examples/src/bin/ieee802154_sniffer.rs b/examples/src/bin/ieee802154_sniffer.rs index f8789241c4a..55b8d29afbe 100644 --- a/examples/src/bin/ieee802154_sniffer.rs +++ b/examples/src/bin/ieee802154_sniffer.rs @@ -8,7 +8,7 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{gpio::Io, prelude::*, reset::software_reset, uart::Uart}; +use esp_hal::{prelude::*, reset::software_reset, uart::Uart}; use esp_ieee802154::{Config, Ieee802154}; use esp_println::println; @@ -16,14 +16,12 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Default pins for Uart/Serial communication cfg_if::cfg_if! { if #[cfg(feature = "esp32c6")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio16, io.pins.gpio17); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO16, peripherals.GPIO17); } else if #[cfg(feature = "esp32h2")] { - let (mut tx_pin, mut rx_pin) = (io.pins.gpio24, io.pins.gpio23); + let (mut tx_pin, mut rx_pin) = (peripherals.GPIO24, peripherals.GPIO23); } } diff --git a/examples/src/bin/lcd_cam_ov2640.rs b/examples/src/bin/lcd_cam_ov2640.rs index 6b9198f97bf..4a419a5d3f2 100644 --- a/examples/src/bin/lcd_cam_ov2640.rs +++ b/examples/src/bin/lcd_cam_ov2640.rs @@ -28,7 +28,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_rx_stream_buffer, - gpio::Io, i2c::{ self, master::{Config, I2c}, @@ -46,8 +45,6 @@ use esp_println::{print, println}; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); let channel = dma.channel0; @@ -55,21 +52,21 @@ fn main() -> ! { let channel = channel.configure(false, DmaPriority::Priority0); - let cam_siod = io.pins.gpio4; - let cam_sioc = io.pins.gpio5; - let cam_xclk = io.pins.gpio15; - let cam_vsync = io.pins.gpio6; - let cam_href = io.pins.gpio7; - let cam_pclk = io.pins.gpio13; + let cam_siod = peripherals.GPIO4; + let cam_sioc = peripherals.GPIO5; + let cam_xclk = peripherals.GPIO15; + let cam_vsync = peripherals.GPIO6; + let cam_href = peripherals.GPIO7; + let cam_pclk = peripherals.GPIO13; let cam_data_pins = RxEightBits::new( - io.pins.gpio11, - io.pins.gpio9, - io.pins.gpio8, - io.pins.gpio10, - io.pins.gpio12, - io.pins.gpio18, - io.pins.gpio17, - io.pins.gpio16, + peripherals.GPIO11, + peripherals.GPIO9, + peripherals.GPIO8, + peripherals.GPIO10, + peripherals.GPIO12, + peripherals.GPIO18, + peripherals.GPIO17, + peripherals.GPIO16, ); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); diff --git a/examples/src/bin/lcd_i8080.rs b/examples/src/bin/lcd_i8080.rs index 2937f427cae..749c5a546ee 100644 --- a/examples/src/bin/lcd_i8080.rs +++ b/examples/src/bin/lcd_i8080.rs @@ -27,7 +27,7 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority, DmaTxBuf}, dma_tx_buffer, - gpio::{Input, Io, Level, Output, Pull}, + gpio::{Input, Level, Output, Pull}, lcd_cam::{ lcd::i8080::{Config, TxEightBits, I8080}, LcdCam, @@ -41,13 +41,11 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let lcd_backlight = io.pins.gpio45; - let lcd_reset = io.pins.gpio4; - let lcd_rs = io.pins.gpio0; // Command/Data selection - let lcd_wr = io.pins.gpio47; // Write clock - let lcd_te = io.pins.gpio48; // Frame sync + let lcd_backlight = peripherals.GPIO45; + let lcd_reset = peripherals.GPIO4; + let lcd_rs = peripherals.GPIO0; // Command/Data selection + let lcd_wr = peripherals.GPIO47; // Write clock + let lcd_te = peripherals.GPIO48; // Frame sync let dma = Dma::new(peripherals.DMA); let channel = dma.channel0; @@ -63,14 +61,14 @@ fn main() -> ! { let tear_effect = Input::new(lcd_te, Pull::None); let tx_pins = TxEightBits::new( - io.pins.gpio9, - io.pins.gpio46, - io.pins.gpio3, - io.pins.gpio8, - io.pins.gpio18, - io.pins.gpio17, - io.pins.gpio16, - io.pins.gpio15, + peripherals.GPIO9, + peripherals.GPIO46, + peripherals.GPIO3, + peripherals.GPIO8, + peripherals.GPIO18, + peripherals.GPIO17, + peripherals.GPIO16, + peripherals.GPIO15, ); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); diff --git a/examples/src/bin/ledc.rs b/examples/src/bin/ledc.rs index a9e8225a290..ce7b3bdd78a 100644 --- a/examples/src/bin/ledc.rs +++ b/examples/src/bin/ledc.rs @@ -11,7 +11,6 @@ use esp_backtrace as _; use esp_hal::{ - gpio::Io, ledc::{ channel::{self, ChannelIFace}, timer::{self, TimerIFace}, @@ -26,8 +25,7 @@ use esp_hal::{ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let led = io.pins.gpio0; + let led = peripherals.GPIO0; let mut ledc = Ledc::new(peripherals.LEDC); diff --git a/examples/src/bin/lp_core_basic.rs b/examples/src/bin/lp_core_basic.rs index d0f38c45e14..b26acf09107 100644 --- a/examples/src/bin/lp_core_basic.rs +++ b/examples/src/bin/lp_core_basic.rs @@ -15,7 +15,7 @@ use esp_backtrace as _; use esp_hal::{ - gpio::{lp_io::LowPowerOutput, Io}, + gpio::lp_io::LowPowerOutput, lp_core::{LpCore, LpCoreWakeupSource}, prelude::*, }; @@ -26,8 +26,8 @@ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); // configure GPIO 1 as LP output pin - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let lp_pin = LowPowerOutput::new(io.pins.gpio1); + + let lp_pin = LowPowerOutput::new(peripherals.GPIO1); let mut lp_core = LpCore::new(peripherals.LP_CORE); lp_core.stop(); diff --git a/examples/src/bin/lp_core_i2c.rs b/examples/src/bin/lp_core_i2c.rs index 55aa731c1bd..c3bbe3c6bcc 100644 --- a/examples/src/bin/lp_core_i2c.rs +++ b/examples/src/bin/lp_core_i2c.rs @@ -16,7 +16,7 @@ use esp_backtrace as _; use esp_hal::{ - gpio::{lp_io::LowPowerOutputOpenDrain, Io}, + gpio::lp_io::LowPowerOutputOpenDrain, i2c::lp_i2c::LpI2c, lp_core::{LpCore, LpCoreWakeupSource}, prelude::*, @@ -27,10 +27,8 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let lp_sda = LowPowerOutputOpenDrain::new(io.pins.gpio6); - let lp_scl = LowPowerOutputOpenDrain::new(io.pins.gpio7); + let lp_sda = LowPowerOutputOpenDrain::new(peripherals.GPIO6); + let lp_scl = LowPowerOutputOpenDrain::new(peripherals.GPIO7); let lp_i2c = LpI2c::new(peripherals.LP_I2C0, lp_sda, lp_scl, 100.kHz()); diff --git a/examples/src/bin/lp_core_uart.rs b/examples/src/bin/lp_core_uart.rs index 9ecb0de7507..15c3d98da71 100644 --- a/examples/src/bin/lp_core_uart.rs +++ b/examples/src/bin/lp_core_uart.rs @@ -16,10 +16,7 @@ use esp_backtrace as _; use esp_hal::{ - gpio::{ - lp_io::{LowPowerInput, LowPowerOutput}, - Io, - }, + gpio::lp_io::{LowPowerInput, LowPowerOutput}, lp_core::{LpCore, LpCoreWakeupSource}, prelude::*, uart::{lp_uart::LpUart, Config, Uart}, @@ -30,21 +27,19 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Set up (HP) UART1: let mut uart1 = Uart::new_with_config( peripherals.UART1, Config::default(), - io.pins.gpio6, - io.pins.gpio7, + peripherals.GPIO6, + peripherals.GPIO7, ) .unwrap(); // Set up (LP) UART: - let lp_tx = LowPowerOutput::new(io.pins.gpio5); - let lp_rx = LowPowerInput::new(io.pins.gpio4); + let lp_tx = LowPowerOutput::new(peripherals.GPIO5); + let lp_rx = LowPowerInput::new(peripherals.GPIO4); let lp_uart = LpUart::new(peripherals.LP_UART, lp_tx, lp_rx); let mut lp_core = LpCore::new(peripherals.LP_CORE); diff --git a/examples/src/bin/mcpwm.rs b/examples/src/bin/mcpwm.rs index 17e08e8c801..8e3281159e9 100644 --- a/examples/src/bin/mcpwm.rs +++ b/examples/src/bin/mcpwm.rs @@ -11,7 +11,6 @@ use esp_backtrace as _; use esp_hal::{ - gpio::Io, mcpwm::{operator::PwmPinConfig, timer::PwmWorkingMode, McPwm, PeripheralClockConfig}, prelude::*, }; @@ -20,8 +19,7 @@ use esp_hal::{ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let pin = io.pins.gpio0; + let pin = peripherals.GPIO0; // initialize peripheral cfg_if::cfg_if! { diff --git a/examples/src/bin/parl_io_rx.rs b/examples/src/bin/parl_io_rx.rs index 8f66c376ea4..6f5d1c2f353 100644 --- a/examples/src/bin/parl_io_rx.rs +++ b/examples/src/bin/parl_io_rx.rs @@ -14,7 +14,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, parl_io::{no_clk_pin, BitPackOrder, ParlIoRxOnly, RxFourBits}, prelude::*, }; @@ -24,14 +23,17 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0); let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; - let mut rx_pins = RxFourBits::new(io.pins.gpio1, io.pins.gpio2, io.pins.gpio3, io.pins.gpio4); + let mut rx_pins = RxFourBits::new( + peripherals.GPIO1, + peripherals.GPIO2, + peripherals.GPIO3, + peripherals.GPIO4, + ); let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, diff --git a/examples/src/bin/parl_io_tx.rs b/examples/src/bin/parl_io_tx.rs index 0df17ad398e..fc790349e78 100644 --- a/examples/src/bin/parl_io_tx.rs +++ b/examples/src/bin/parl_io_tx.rs @@ -18,7 +18,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_buffers, - gpio::Io, parl_io::{ BitPackOrder, ClkOutPin, @@ -35,16 +34,19 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000); let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; - let tx_pins = TxFourBits::new(io.pins.gpio1, io.pins.gpio2, io.pins.gpio3, io.pins.gpio4); + let tx_pins = TxFourBits::new( + peripherals.GPIO1, + peripherals.GPIO2, + peripherals.GPIO3, + peripherals.GPIO4, + ); - let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, io.pins.gpio5); + let mut pin_conf = TxPinConfigWithValidPin::new(tx_pins, peripherals.GPIO5); let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, @@ -54,7 +56,7 @@ fn main() -> ! { ) .unwrap(); - let mut clock_pin = ClkOutPin::new(io.pins.gpio6); + let mut clock_pin = ClkOutPin::new(peripherals.GPIO6); let mut parl_io_tx = parl_io .tx diff --git a/examples/src/bin/pcnt_encoder.rs b/examples/src/bin/pcnt_encoder.rs index bf1b1394144..29a9a1a6b20 100644 --- a/examples/src/bin/pcnt_encoder.rs +++ b/examples/src/bin/pcnt_encoder.rs @@ -20,7 +20,7 @@ use core::{cell::RefCell, cmp::min, sync::atomic::Ordering}; use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, interrupt::Priority, pcnt::{channel, unit, Pcnt}, prelude::*, @@ -35,8 +35,6 @@ static VALUE: AtomicI32 = AtomicI32::new(0); fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Set up a pulse counter: println!("setup pulse counter unit 0"); let mut pcnt = Pcnt::new(peripherals.PCNT); @@ -50,8 +48,8 @@ fn main() -> ! { println!("setup channel 0"); let ch0 = &u0.channel0; - let pin_a = Input::new(io.pins.gpio4, Pull::Up); - let pin_b = Input::new(io.pins.gpio5, Pull::Up); + let pin_a = Input::new(peripherals.GPIO4, Pull::Up); + let pin_b = Input::new(peripherals.GPIO5, Pull::Up); let (input_a, _) = pin_a.split(); let (input_b, _) = pin_b.split(); diff --git a/examples/src/bin/qspi_flash.rs b/examples/src/bin/qspi_flash.rs index cd901df7c31..a7e9df83b54 100644 --- a/examples/src/bin/qspi_flash.rs +++ b/examples/src/bin/qspi_flash.rs @@ -32,7 +32,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::Io, prelude::*, spi::{ master::{Address, Command, Config, Spi}, @@ -46,22 +45,21 @@ use esp_println::{print, println}; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let sclk = io.pins.gpio0; - let miso = io.pins.gpio2; - let mosi = io.pins.gpio4; - let sio2 = io.pins.gpio5; - let sio3 = io.pins.gpio13; - let cs = io.pins.gpio14; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO2; + let mosi = peripherals.GPIO4; + let sio2 = peripherals.GPIO5; + let sio3 = peripherals.GPIO13; + let cs = peripherals.GPIO14; } else { - let sclk = io.pins.gpio0; - let miso = io.pins.gpio1; - let mosi = io.pins.gpio2; - let sio2 = io.pins.gpio3; - let sio3 = io.pins.gpio4; - let cs = io.pins.gpio5; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO1; + let mosi = peripherals.GPIO2; + let sio2 = peripherals.GPIO3; + let sio3 = peripherals.GPIO4; + let cs = peripherals.GPIO5; } } diff --git a/examples/src/bin/rmt_rx.rs b/examples/src/bin/rmt_rx.rs index 948b6c8c6ef..c9dc626b1b4 100644 --- a/examples/src/bin/rmt_rx.rs +++ b/examples/src/bin/rmt_rx.rs @@ -14,7 +14,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::{Io, Level, Output}, + gpio::{Level, Output}, prelude::*, rmt::{PulseCode, Rmt, RxChannel, RxChannelConfig, RxChannelCreator}, }; @@ -26,8 +26,7 @@ const WIDTH: usize = 80; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut out = Output::new(io.pins.gpio5, Level::Low); + let mut out = Output::new(peripherals.GPIO5, Level::Low); cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { @@ -47,11 +46,11 @@ fn main() -> ! { cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2"))] { - let mut channel = rmt.channel0.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel0.configure(peripherals.GPIO4, rx_config).unwrap(); } else if #[cfg(feature = "esp32s3")] { - let mut channel = rmt.channel7.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel7.configure(peripherals.GPIO4, rx_config).unwrap(); } else { - let mut channel = rmt.channel2.configure(io.pins.gpio4, rx_config).unwrap(); + let mut channel = rmt.channel2.configure(peripherals.GPIO4, rx_config).unwrap(); } } diff --git a/examples/src/bin/rmt_tx.rs b/examples/src/bin/rmt_tx.rs index 6d16c26298f..d87e8d87a85 100644 --- a/examples/src/bin/rmt_tx.rs +++ b/examples/src/bin/rmt_tx.rs @@ -13,7 +13,6 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, prelude::*, rmt::{PulseCode, Rmt, TxChannel, TxChannelConfig, TxChannelCreator}, }; @@ -22,8 +21,6 @@ use esp_hal::{ fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { let freq = 32.MHz(); @@ -39,7 +36,10 @@ fn main() -> ! { ..TxChannelConfig::default() }; - let mut channel = rmt.channel0.configure(io.pins.gpio4, tx_config).unwrap(); + let mut channel = rmt + .channel0 + .configure(peripherals.GPIO4, tx_config) + .unwrap(); let delay = Delay::new(); diff --git a/examples/src/bin/serial_interrupts.rs b/examples/src/bin/serial_interrupts.rs index daabb9ff27f..725f5814d24 100644 --- a/examples/src/bin/serial_interrupts.rs +++ b/examples/src/bin/serial_interrupts.rs @@ -13,7 +13,6 @@ use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, prelude::*, uart::{AtCmdConfig, Config, Uart, UartInterrupt}, Blocking, @@ -27,22 +26,20 @@ fn main() -> ! { let delay = Delay::new(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Default pins for Uart/Serial communication cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let (tx_pin, rx_pin) = (io.pins.gpio1, io.pins.gpio3); + let (tx_pin, rx_pin) = (peripherals.GPIO1, peripherals.GPIO3); } else if #[cfg(feature = "esp32c2")] { - let (tx_pin, rx_pin) = (io.pins.gpio20, io.pins.gpio19); + let (tx_pin, rx_pin) = (peripherals.GPIO20, peripherals.GPIO19); } else if #[cfg(feature = "esp32c3")] { - let (tx_pin, rx_pin) = (io.pins.gpio21, io.pins.gpio20); + let (tx_pin, rx_pin) = (peripherals.GPIO21, peripherals.GPIO20); } else if #[cfg(feature = "esp32c6")] { - let (tx_pin, rx_pin) = (io.pins.gpio16, io.pins.gpio17); + let (tx_pin, rx_pin) = (peripherals.GPIO16, peripherals.GPIO17); } else if #[cfg(feature = "esp32h2")] { - let (tx_pin, rx_pin) = (io.pins.gpio24, io.pins.gpio23); + let (tx_pin, rx_pin) = (peripherals.GPIO24, peripherals.GPIO23); } else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] { - let (tx_pin, rx_pin) = (io.pins.gpio43, io.pins.gpio44); + let (tx_pin, rx_pin) = (peripherals.GPIO43, peripherals.GPIO44); } } let config = Config::default().rx_fifo_full_threshold(30); diff --git a/examples/src/bin/sleep_timer_ext0.rs b/examples/src/bin/sleep_timer_ext0.rs index 8803d2b4955..f026bbc68b1 100644 --- a/examples/src/bin/sleep_timer_ext0.rs +++ b/examples/src/bin/sleep_timer_ext0.rs @@ -14,7 +14,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, entry, - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, rtc_cntl::{ get_reset_reason, get_wakeup_cause, @@ -32,8 +32,7 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let ext0_pin = Input::new(io.pins.gpio4, Pull::None); + let ext0_pin = Input::new(peripherals.GPIO4, Pull::None); println!("up and runnning!"); let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); diff --git a/examples/src/bin/sleep_timer_ext1.rs b/examples/src/bin/sleep_timer_ext1.rs index 83a046c6e3b..783a4a26af7 100644 --- a/examples/src/bin/sleep_timer_ext1.rs +++ b/examples/src/bin/sleep_timer_ext1.rs @@ -14,7 +14,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, entry, - gpio::{Input, Io, Pull, RtcPin}, + gpio::{Input, Pull, RtcPin}, peripheral::Peripheral, rtc_cntl::{ get_reset_reason, @@ -33,9 +33,8 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let pin_0 = Input::new(io.pins.gpio4, Pull::None); - let mut pin_2 = io.pins.gpio2; + let pin_0 = Input::new(peripherals.GPIO4, Pull::None); + let mut pin_2 = peripherals.GPIO2; println!("up and runnning!"); let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); diff --git a/examples/src/bin/sleep_timer_lpio.rs b/examples/src/bin/sleep_timer_lpio.rs index 73e6a8f7a75..8ae16d28eb4 100644 --- a/examples/src/bin/sleep_timer_lpio.rs +++ b/examples/src/bin/sleep_timer_lpio.rs @@ -15,7 +15,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, entry, - gpio::{Input, Io, Pull, RtcPinWithResistors}, + gpio::{Input, Pull, RtcPinWithResistors}, peripheral::Peripheral, rtc_cntl::{ get_reset_reason, @@ -34,9 +34,8 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let pin2 = Input::new(io.pins.gpio2, Pull::None); - let mut pin3 = io.pins.gpio3; + let pin2 = Input::new(peripherals.GPIO2, Pull::None); + let mut pin3 = peripherals.GPIO3; println!("up and runnning!"); let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); diff --git a/examples/src/bin/sleep_timer_rtcio.rs b/examples/src/bin/sleep_timer_rtcio.rs index d857d4a06f8..a04c7892ecb 100644 --- a/examples/src/bin/sleep_timer_rtcio.rs +++ b/examples/src/bin/sleep_timer_rtcio.rs @@ -19,7 +19,7 @@ use esp_hal::{ delay::Delay, entry, gpio, - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, peripheral::Peripheral, rtc_cntl::{ get_reset_reason, @@ -36,7 +36,6 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let mut rtc = Rtc::new(peripherals.LPWR); println!("up and runnning!"); @@ -50,16 +49,16 @@ fn main() -> ! { cfg_if::cfg_if! { if #[cfg(any(feature = "esp32c3", feature = "esp32c2"))] { - let pin2 = Input::new(io.pins.gpio2, Pull::None); - let mut pin3 = io.pins.gpio3; + let pin2 = Input::new(peripherals.GPIO2, Pull::None); + let mut pin3 = peripherals.GPIO3; let wakeup_pins: &mut [(&mut dyn gpio::RtcPinWithResistors, WakeupLevel)] = &mut [ (&mut *pin2.into_ref(), WakeupLevel::Low), (&mut pin3, WakeupLevel::High), ]; } else if #[cfg(feature = "esp32s3")] { - let pin17 = Input::new(io.pins.gpio17, Pull::None); - let mut pin18 = io.pins.gpio18; + let pin17 = Input::new(peripherals.GPIO17, Pull::None); + let mut pin18 = peripherals.GPIO18; let wakeup_pins: &mut [(&mut dyn gpio::RtcPin, WakeupLevel)] = &mut [ (&mut *pin17.into_ref(), WakeupLevel::Low), diff --git a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs index 28266b67e93..6ea46778f86 100644 --- a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs +++ b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs @@ -30,7 +30,6 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, prelude::*, spi::{ master::{Address, Command, Config, Spi}, @@ -44,22 +43,21 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { - let sclk = io.pins.gpio0; - let miso = io.pins.gpio2; - let mosi = io.pins.gpio4; - let sio2 = io.pins.gpio5; - let sio3 = io.pins.gpio13; - let cs = io.pins.gpio14; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO2; + let mosi = peripherals.GPIO4; + let sio2 = peripherals.GPIO5; + let sio3 = peripherals.GPIO13; + let cs = peripherals.GPIO14; } else { - let sclk = io.pins.gpio0; - let miso = io.pins.gpio1; - let mosi = io.pins.gpio2; - let sio2 = io.pins.gpio3; - let sio3 = io.pins.gpio4; - let cs = io.pins.gpio5; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO1; + let mosi = peripherals.GPIO2; + let sio2 = peripherals.GPIO3; + let sio3 = peripherals.GPIO4; + let cs = peripherals.GPIO5; } } diff --git a/examples/src/bin/spi_loopback.rs b/examples/src/bin/spi_loopback.rs index 38e9d6f1ed6..22e92a29ca5 100644 --- a/examples/src/bin/spi_loopback.rs +++ b/examples/src/bin/spi_loopback.rs @@ -18,7 +18,6 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, peripheral::Peripheral, prelude::*, spi::{ @@ -32,10 +31,9 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let miso_mosi = io.pins.gpio2; - let cs = io.pins.gpio5; + let sclk = peripherals.GPIO0; + let miso_mosi = peripherals.GPIO2; + let cs = peripherals.GPIO5; let miso = unsafe { miso_mosi.clone_unchecked() }; diff --git a/examples/src/bin/spi_loopback_dma.rs b/examples/src/bin/spi_loopback_dma.rs index e9bc827ff7a..639ac030927 100644 --- a/examples/src/bin/spi_loopback_dma.rs +++ b/examples/src/bin/spi_loopback_dma.rs @@ -23,7 +23,6 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::Io, prelude::*, spi::{ master::{Config, Spi}, @@ -36,11 +35,10 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let miso = io.pins.gpio2; - let mosi = io.pins.gpio4; - let cs = io.pins.gpio5; + let sclk = peripherals.GPIO0; + let miso = peripherals.GPIO2; + let mosi = peripherals.GPIO4; + let cs = peripherals.GPIO5; let dma = Dma::new(peripherals.DMA); diff --git a/examples/src/bin/spi_loopback_dma_psram.rs b/examples/src/bin/spi_loopback_dma_psram.rs index 0ee76893cd8..0a8fe54445b 100644 --- a/examples/src/bin/spi_loopback_dma_psram.rs +++ b/examples/src/bin/spi_loopback_dma_psram.rs @@ -26,7 +26,6 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, dma::{Dma, DmaBufBlkSize, DmaPriority, DmaRxBuf, DmaTxBuf}, - gpio::Io, peripheral::Peripheral, prelude::*, spi::{ @@ -63,11 +62,10 @@ fn main() -> ! { esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram); let delay = Delay::new(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio42; - let mosi = io.pins.gpio48; + let sclk = peripherals.GPIO42; + let mosi = peripherals.GPIO48; let miso = unsafe { mosi.clone_unchecked() }; - let cs = io.pins.gpio38; + let cs = peripherals.GPIO38; let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; diff --git a/examples/src/bin/spi_slave_dma.rs b/examples/src/bin/spi_slave_dma.rs index 44b2d4871fd..142816166f9 100644 --- a/examples/src/bin/spi_slave_dma.rs +++ b/examples/src/bin/spi_slave_dma.rs @@ -34,7 +34,7 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_buffers, - gpio::{Input, Io, Level, Output, Pull}, + gpio::{Input, Level, Output, Pull}, prelude::*, spi::{slave::Spi, SpiMode}, }; @@ -44,17 +44,15 @@ use esp_println::println; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let mut master_sclk = Output::new(peripherals.GPIO4, Level::Low); + let master_miso = Input::new(peripherals.GPIO5, Pull::None); + let mut master_mosi = Output::new(peripherals.GPIO8, Level::Low); + let mut master_cs = Output::new(peripherals.GPIO9, Level::High); - let mut master_sclk = Output::new(io.pins.gpio4, Level::Low); - let master_miso = Input::new(io.pins.gpio5, Pull::None); - let mut master_mosi = Output::new(io.pins.gpio8, Level::Low); - let mut master_cs = Output::new(io.pins.gpio9, Level::High); - - let slave_sclk = io.pins.gpio0; - let slave_miso = io.pins.gpio1; - let slave_mosi = io.pins.gpio2; - let slave_cs = io.pins.gpio3; + let slave_sclk = peripherals.GPIO0; + let slave_miso = peripherals.GPIO1; + let slave_mosi = peripherals.GPIO2; + let slave_cs = peripherals.GPIO3; let dma = Dma::new(peripherals.DMA); cfg_if::cfg_if! { diff --git a/examples/src/bin/touch.rs b/examples/src/bin/touch.rs index 22a324c28e7..a36207a8a75 100644 --- a/examples/src/bin/touch.rs +++ b/examples/src/bin/touch.rs @@ -17,7 +17,7 @@ use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::{GpioPin, Io}, + gpio::GpioPin, macros::ram, prelude::*, rtc_cntl::Rtc, @@ -49,13 +49,11 @@ fn main() -> ! { esp_println::logger::init_logger_from_env(); let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let mut rtc = Rtc::new(peripherals.LPWR); rtc.set_interrupt_handler(interrupt_handler); - let touch_pin0 = io.pins.gpio2; - let touch_pin1 = io.pins.gpio4; + let touch_pin0 = peripherals.GPIO2; + let touch_pin1 = peripherals.GPIO4; let touch_cfg = Some(TouchConfig { measurement_duration: Some(0x2000), diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index fa0bcf9ee8e..b59a39cda55 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -29,7 +29,6 @@ const IS_FIRST_SENDER: bool = true; use esp_backtrace as _; use esp_hal::{ delay::Delay, - gpio::Io, prelude::*, twai::{self, filter::SingleStandardFilter, EspTwaiFrame, StandardId, TwaiMode}, }; @@ -40,13 +39,11 @@ use nb::block; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - // Without an external transceiver, we only need a single line between the two MCUs. - let (rx_pin, tx_pin) = io.pins.gpio2.split(); + let (rx_pin, tx_pin) = peripherals.GPIO2.split(); // Use these if you want to use an external transceiver: - // let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; + // let tx_pin = peripherals.GPIO2; + // let rx_pin = peripherals.GPIO0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/examples/src/bin/ulp_riscv_core_basic.rs b/examples/src/bin/ulp_riscv_core_basic.rs index d89eda74521..6d062b7f3c1 100644 --- a/examples/src/bin/ulp_riscv_core_basic.rs +++ b/examples/src/bin/ulp_riscv_core_basic.rs @@ -12,19 +12,14 @@ #![no_main] use esp_backtrace as _; -use esp_hal::{ - gpio::{rtc_io::*, Io}, - prelude::*, - ulp_core, -}; +use esp_hal::{gpio::rtc_io::*, prelude::*, ulp_core}; use esp_println::{print, println}; #[entry] fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let pin = LowPowerOutput::new(io.pins.gpio1); + let pin = LowPowerOutput::new(peripherals.GPIO1); let mut ulp_core = ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE); diff --git a/examples/src/bin/usb_serial.rs b/examples/src/bin/usb_serial.rs index aee87614333..1bb93ae1a56 100644 --- a/examples/src/bin/usb_serial.rs +++ b/examples/src/bin/usb_serial.rs @@ -15,7 +15,6 @@ use core::ptr::addr_of_mut; use esp_backtrace as _; use esp_hal::{ - gpio::Io, otg_fs::{Usb, UsbBus}, prelude::*, }; @@ -28,9 +27,7 @@ static mut EP_MEMORY: [u32; 1024] = [0; 1024]; fn main() -> ! { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let usb = Usb::new(peripherals.USB0, io.pins.gpio20, io.pins.gpio19); + let usb = Usb::new(peripherals.USB0, peripherals.GPIO20, peripherals.GPIO19); let usb_bus = UsbBus::new(usb, unsafe { &mut *addr_of_mut!(EP_MEMORY) }); let mut serial = SerialPort::new(&usb_bus); diff --git a/examples/src/bin/wifi_ble.rs b/examples/src/bin/wifi_ble.rs index 26ac4f4becf..84e383e0787 100644 --- a/examples/src/bin/wifi_ble.rs +++ b/examples/src/bin/wifi_ble.rs @@ -25,7 +25,7 @@ use bleps::{ use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, prelude::*, rng::Rng, time, @@ -54,13 +54,11 @@ fn main() -> ! { ) .unwrap(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] { - let button = Input::new(io.pins.gpio0, Pull::Down); + let button = Input::new(peripherals.GPIO0, Pull::Down); } else { - let button = Input::new(io.pins.gpio9, Pull::Down); + let button = Input::new(peripherals.GPIO9, Pull::Down); } } diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index 5ba16b69863..22ad06076d4 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -28,7 +28,7 @@ use embassy_executor::Spawner; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ - gpio::{Input, Io, Pull}, + gpio::{Input, Pull}, prelude::*, rng::Rng, time, @@ -70,12 +70,11 @@ async fn main(_spawner: Spawner) -> ! { .unwrap() ); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); cfg_if::cfg_if! { if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] { - let button = Input::new(io.pins.gpio0, Pull::Down); + let button = Input::new(peripherals.GPIO0, Pull::Down); } else { - let button = Input::new(io.pins.gpio9, Pull::Down); + let button = Input::new(peripherals.GPIO9, Pull::Down); } } diff --git a/hil-test/src/lib.rs b/hil-test/src/lib.rs index 8dbf121735e..660e8697cbe 100644 --- a/hil-test/src/lib.rs +++ b/hil-test/src/lib.rs @@ -27,21 +27,21 @@ use esp_backtrace as _; #[macro_export] macro_rules! i2c_pins { - ($io:expr) => {{ + ($peripherals:expr) => {{ // Order: (SDA, SCL) cfg_if::cfg_if! { if #[cfg(any(esp32s2, esp32s3))] { - ($io.pins.gpio2, $io.pins.gpio3) + ($peripherals.GPIO2, $peripherals.GPIO3) } else if #[cfg(esp32)] { - ($io.pins.gpio32, $io.pins.gpio33) + ($peripherals.GPIO32, $peripherals.GPIO33) } else if #[cfg(esp32c6)] { - ($io.pins.gpio6, $io.pins.gpio7) + ($peripherals.GPIO6, $peripherals.GPIO7) } else if #[cfg(esp32h2)] { - ($io.pins.gpio12, $io.pins.gpio22) + ($peripherals.GPIO12, $peripherals.GPIO22) } else if #[cfg(esp32c2)] { - ($io.pins.gpio18, $io.pins.gpio9) + ($peripherals.GPIO18, $peripherals.GPIO9) } else { - ($io.pins.gpio4, $io.pins.gpio5) + ($peripherals.GPIO4, $peripherals.GPIO5) } } }}; @@ -49,14 +49,14 @@ macro_rules! i2c_pins { #[macro_export] macro_rules! common_test_pins { - ($io:expr) => {{ + ($peripherals:expr) => {{ cfg_if::cfg_if! { if #[cfg(any(esp32s2, esp32s3))] { - ($io.pins.gpio9, $io.pins.gpio10) + ($peripherals.GPIO9, $peripherals.GPIO10) } else if #[cfg(esp32)] { - ($io.pins.gpio26, $io.pins.gpio27) + ($peripherals.GPIO26, $peripherals.GPIO27) } else { - ($io.pins.gpio2, $io.pins.gpio3) + ($peripherals.GPIO2, $peripherals.GPIO3) } } }}; @@ -66,18 +66,18 @@ macro_rules! common_test_pins { // beware: it has a pullup. #[macro_export] macro_rules! unconnected_pin { - ($io:expr) => {{ + ($peripherals:expr) => {{ cfg_if::cfg_if! { if #[cfg(any(esp32, esp32s2, esp32s3))] { - $io.pins.gpio0 + $peripherals.GPIO0 } else if #[cfg(esp32c6)] { - $io.pins.gpio9 + $peripherals.GPIO9 } else if #[cfg(esp32h2)] { - $io.pins.gpio9 + $peripherals.GPIO9 } else if #[cfg(esp32c2)] { - $io.pins.gpio8 + $peripherals.GPIO8 } else { - $io.pins.gpio9 + $peripherals.GPIO9 } } }}; diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index d5394ff9ba5..082fd2dceca 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -11,7 +11,6 @@ use embassy_time::{Duration, Instant, Ticker}; use esp_hal::{ dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::Io, interrupt::{software::SoftwareInterruptControl, Priority}, peripheral::Peripheral, prelude::*, @@ -118,8 +117,7 @@ mod test { let dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (_, mosi) = hil_test::common_test_pins!(io); + let (_, mosi) = hil_test::common_test_pins!(peripherals); let mut spi = Spi::new_with_config( peripherals.SPI2, diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs index eaed133de9e..0d197b2d17d 100644 --- a/hil-test/tests/gpio.rs +++ b/hil-test/tests/gpio.rs @@ -51,12 +51,12 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let mut io = Io::new(peripherals.IO_MUX); io.set_interrupt_handler(interrupt_handler); let delay = Delay::new(); - let (gpio1, gpio2) = hil_test::common_test_pins!(io); + let (gpio1, gpio2) = hil_test::common_test_pins!(peripherals); let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); @@ -387,8 +387,8 @@ mod tests { #[cfg(esp32)] #[test] fn can_configure_rtcio_pins_as_input() { - let pins = unsafe { esp_hal::gpio::Pins::steal() }; + let pin = unsafe { esp_hal::gpio::GpioPin::<37>::steal() }; - _ = Input::new(pins.gpio37, Pull::Down); + _ = Input::new(pin, Pull::Down); } } diff --git a/hil-test/tests/gpio_custom_handler.rs b/hil-test/tests/gpio_custom_handler.rs index 334c9f53101..67f2d529870 100644 --- a/hil-test/tests/gpio_custom_handler.rs +++ b/hil-test/tests/gpio_custom_handler.rs @@ -66,9 +66,7 @@ mod tests { async fn default_handler_does_not_run_because_gpio_is_defined() { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (gpio1, gpio2) = hil_test::common_test_pins!(io); + let (gpio1, gpio2) = hil_test::common_test_pins!(peripherals); let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); @@ -83,10 +81,10 @@ mod tests { async fn default_handler_runs_because_handler_is_set() { let peripherals = esp_hal::init(esp_hal::Config::default()); - let mut io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let mut io = Io::new(peripherals.IO_MUX); io.set_interrupt_handler(interrupt_handler); - let (gpio1, gpio2) = hil_test::common_test_pins!(io); + let (gpio1, gpio2) = hil_test::common_test_pins!(peripherals); let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); diff --git a/hil-test/tests/i2c.rs b/hil-test/tests/i2c.rs index 09718abf151..9ea9f267c6b 100644 --- a/hil-test/tests/i2c.rs +++ b/hil-test/tests/i2c.rs @@ -6,7 +6,6 @@ #![no_main] use esp_hal::{ - gpio::Io, i2c::master::{Config, I2c, Operation}, Async, Blocking, @@ -33,9 +32,8 @@ mod tests { #[init] fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (sda, scl) = hil_test::i2c_pins!(io); + let (sda, scl) = hil_test::i2c_pins!(peripherals); // Create a new peripheral object with the described wiring and standard // I2C clock speed: diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index 7610e7791ff..5fd85ca9e5f 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -14,7 +14,7 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_buffers, - gpio::{Io, NoPin}, + gpio::{AnyPin, NoPin, Pin}, i2s::master::{DataFormat, I2s, I2sTx, Standard}, peripherals::I2S0, prelude::*, @@ -103,7 +103,7 @@ mod tests { use super::*; struct Context { - io: Io, + dout: AnyPin, dma_channel: DmaChannel0Creator, i2s: I2S0, } @@ -112,8 +112,6 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let dma = Dma::new(peripherals.DMA); cfg_if::cfg_if! { @@ -124,8 +122,10 @@ mod tests { } } + let (_, dout) = hil_test::common_test_pins!(peripherals); + Context { - io, + dout: dout.degrade(), dma_channel, i2s: peripherals.I2S0, } @@ -149,9 +149,7 @@ mod tests { ) .into_async(); - let (_, dout) = hil_test::common_test_pins!(ctx.io); - - let (din, dout) = dout.split(); + let (din, dout) = ctx.dout.split(); let i2s_tx = i2s .i2s_tx @@ -203,9 +201,7 @@ mod tests { tx_descriptors, ); - let (_, dout) = hil_test::common_test_pins!(ctx.io); - - let (din, dout) = dout.split(); + let (din, dout) = ctx.dout.split(); let mut i2s_tx = i2s .i2s_tx @@ -314,13 +310,11 @@ mod tests { tx_descriptors, ); - let (_, dout) = hil_test::common_test_pins!(ctx.io); - let mut i2s_tx = i2s .i2s_tx .with_bclk(NoPin) .with_ws(NoPin) - .with_dout(dout) + .with_dout(ctx.dout) .build(); let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap(); @@ -346,15 +340,11 @@ mod tests { tx_descriptors, ); - let (_, dout) = hil_test::common_test_pins!(ctx.io); - - let (din, dout) = dout.split(); - let mut i2s_rx = i2s .i2s_rx .with_bclk(NoPin) .with_ws(NoPin) - .with_din(din) + .with_din(ctx.dout) // not a typo .build(); let mut buffer = [0u8; 1024]; diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 1d4555bfa52..33a76d04c36 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -8,7 +8,7 @@ use esp_hal::{ dma::{Dma, DmaPriority, DmaTxBuf}, dma_buffers, - gpio::{Io, NoPin}, + gpio::{GpioPin, NoPin}, lcd_cam::{ lcd::i8080::{Command, Config, TxEightBits, TxSixteenBits, I8080}, BitOrder, @@ -25,10 +25,19 @@ use hil_test as _; const DATA_SIZE: usize = 1024 * 10; +#[allow(non_snake_case)] +struct Pins { + pub GPIO8: GpioPin<8>, + pub GPIO11: GpioPin<11>, + pub GPIO12: GpioPin<12>, + pub GPIO16: GpioPin<16>, + pub GPIO17: GpioPin<17>, +} + struct Context<'d> { lcd_cam: LcdCam<'d, Blocking>, pcnt: Pcnt<'d>, - io: Io, + pins: Pins, dma: Dma<'d>, dma_buf: DmaTxBuf, } @@ -44,7 +53,7 @@ mod tests { let dma = Dma::new(peripherals.DMA); let lcd_cam = LcdCam::new(peripherals.LCD_CAM); let pcnt = Pcnt::new(peripherals.PCNT); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE); let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); @@ -52,7 +61,13 @@ mod tests { lcd_cam, dma, pcnt, - io, + pins: Pins { + GPIO8: peripherals.GPIO8, + GPIO11: peripherals.GPIO11, + GPIO12: peripherals.GPIO12, + GPIO16: peripherals.GPIO16, + GPIO17: peripherals.GPIO17, + }, dma_buf, } } @@ -102,11 +117,11 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); - let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); - let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); - let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); - let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); + let (unit_ctrl, cs_signal) = ctx.pins.GPIO8.split(); + let (unit0_input, unit0_signal) = ctx.pins.GPIO11.split(); + let (unit1_input, unit1_signal) = ctx.pins.GPIO12.split(); + let (unit2_input, unit2_signal) = ctx.pins.GPIO16.split(); + let (unit3_input, unit3_signal) = ctx.pins.GPIO17.split(); let pcnt = ctx.pcnt; @@ -213,11 +228,11 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); - let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); - let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); - let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); - let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); + let (unit_ctrl, cs_signal) = ctx.pins.GPIO8.split(); + let (unit0_input, unit0_signal) = ctx.pins.GPIO11.split(); + let (unit1_input, unit1_signal) = ctx.pins.GPIO12.split(); + let (unit2_input, unit2_signal) = ctx.pins.GPIO16.split(); + let (unit3_input, unit3_signal) = ctx.pins.GPIO17.split(); let pcnt = ctx.pcnt; diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index f2b2cceb559..8924c11ada8 100644 --- a/hil-test/tests/parl_io_tx.rs +++ b/hil-test/tests/parl_io_tx.rs @@ -10,7 +10,6 @@ use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, gpio::{ interconnect::{InputSignal, OutputSignal}, - Io, NoPin, }, parl_io::{ @@ -52,9 +51,8 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (clock, _) = hil_test::common_test_pins!(io); - let valid = hil_test::unconnected_pin!(io); + let (clock, _) = hil_test::common_test_pins!(peripherals); + let valid = hil_test::unconnected_pin!(peripherals); let (clock_loopback, clock) = clock.split(); let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index 2c4522f02cf..a38719ec7e6 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -12,7 +12,6 @@ use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, gpio::{ interconnect::{InputSignal, OutputSignal}, - Io, NoPin, }, parl_io::{ @@ -54,9 +53,8 @@ mod tests { async fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (clock, _) = hil_test::common_test_pins!(io); - let valid = hil_test::unconnected_pin!(io); + let (clock, _) = hil_test::common_test_pins!(peripherals); + let valid = hil_test::unconnected_pin!(peripherals); let (clock_loopback, clock) = clock.split(); let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); diff --git a/hil-test/tests/pcnt.rs b/hil-test/tests/pcnt.rs index d1857be61a8..7c18e62b1b9 100644 --- a/hil-test/tests/pcnt.rs +++ b/hil-test/tests/pcnt.rs @@ -7,7 +7,7 @@ use esp_hal::{ delay::Delay, - gpio::{AnyPin, Input, Io, Level, Output, Pin, Pull}, + gpio::{AnyPin, Input, Level, Output, Pin, Pull}, pcnt::{channel::EdgeMode, Pcnt}, }; use hil_test as _; @@ -28,9 +28,7 @@ mod tests { fn init() -> Context<'static> { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (din, dout) = hil_test::common_test_pins!(io); + let (din, dout) = hil_test::common_test_pins!(peripherals); let din = din.degrade(); let dout = dout.degrade(); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 8b61a26dd57..0123e32d01a 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -10,7 +10,7 @@ use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt}; use esp_hal::{ dma::{Channel, Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::{AnyPin, Input, Io, Level, Output, Pull}, + gpio::{AnyPin, Input, Level, Output, Pull}, prelude::*, spi::{ master::{Address, Command, Config, Spi, SpiDma}, @@ -184,10 +184,8 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (mut pin, mut pin_mirror) = hil_test::common_test_pins!(io); - let mut unconnected_pin = hil_test::unconnected_pin!(io); + let (mut pin, mut pin_mirror) = hil_test::common_test_pins!(peripherals); + let mut unconnected_pin = hil_test::unconnected_pin!(peripherals); // Make sure pins have no pullups let _ = Input::new(&mut pin, Pull::Down); diff --git a/hil-test/tests/rmt.rs b/hil-test/tests/rmt.rs index 5ad82d4af71..c7c9db6d28e 100644 --- a/hil-test/tests/rmt.rs +++ b/hil-test/tests/rmt.rs @@ -6,7 +6,6 @@ #![no_main] use esp_hal::{ - gpio::Io, prelude::*, rmt::{PulseCode, Rmt, RxChannel, RxChannelConfig, TxChannel, TxChannelConfig}, }; @@ -25,8 +24,6 @@ mod tests { fn rmt_loopback() { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { let freq = 32.MHz(); @@ -37,7 +34,7 @@ mod tests { let rmt = Rmt::new(peripherals.RMT, freq).unwrap(); - let (rx, tx) = hil_test::common_test_pins!(io); + let (rx, tx) = hil_test::common_test_pins!(peripherals); let tx_config = TxChannelConfig { clk_divider: 255, diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 2b445303124..3e7a42b398c 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -14,7 +14,7 @@ use embedded_hal_async::spi::SpiBus as SpiBusAsync; use esp_hal::{ dma::{Dma, DmaDescriptor, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::{Io, Level, NoPin}, + gpio::{Level, NoPin}, peripheral::Peripheral, prelude::*, spi::master::{Config, Spi}, @@ -58,9 +58,8 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let (_, mosi) = hil_test::common_test_pins!(io); + let sclk = peripherals.GPIO0; + let (_, mosi) = hil_test::common_test_pins!(peripherals); let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/spi_half_duplex_read.rs b/hil-test/tests/spi_half_duplex_read.rs index dc83a638ce0..212e764424a 100644 --- a/hil-test/tests/spi_half_duplex_read.rs +++ b/hil-test/tests/spi_half_duplex_read.rs @@ -8,7 +8,7 @@ use esp_hal::{ dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::{Io, Level, Output}, + gpio::{Level, Output}, prelude::*, spi::{ master::{Address, Command, Config, Spi, SpiDma}, @@ -33,9 +33,8 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let (miso, miso_mirror) = hil_test::common_test_pins!(io); + let sclk = peripherals.GPIO0; + let (miso, miso_mirror) = hil_test::common_test_pins!(peripherals); let miso_mirror = Output::new(miso_mirror, Level::High); diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index 88a51641e41..985ede3e5f6 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -8,7 +8,7 @@ use esp_hal::{ dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::{interconnect::InputSignal, Io}, + gpio::interconnect::InputSignal, pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ @@ -35,9 +35,8 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let (mosi, _) = hil_test::common_test_pins!(io); + let sclk = peripherals.GPIO0; + let (mosi, _) = hil_test::common_test_pins!(peripherals); let pcnt = Pcnt::new(peripherals.PCNT); let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index aaf9fb7b979..950cf2f0ea6 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -10,7 +10,7 @@ use esp_hal::{ dma::{Dma, DmaBufBlkSize, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, dma_descriptors_chunk_size, - gpio::{interconnect::InputSignal, Io}, + gpio::interconnect::InputSignal, pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ @@ -53,9 +53,8 @@ mod tests { let peripherals = esp_hal::init(esp_hal::Config::default()); esp_alloc::psram_allocator!(peripherals.PSRAM, esp_hal::psram); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let sclk = io.pins.gpio0; - let (mosi, _) = hil_test::common_test_pins!(io); + let sclk = peripherals.GPIO0; + let (mosi, _) = hil_test::common_test_pins!(peripherals); let pcnt = Pcnt::new(peripherals.PCNT); let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 72cd12de3d6..6045f1d4d12 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -11,7 +11,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::{Input, Io, Level, Output, Pull}, + gpio::{Input, Level, Output, Pull}, peripheral::Peripheral, spi::{slave::Spi, SpiMode}, Blocking, @@ -103,11 +103,9 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (mosi_pin, miso_pin) = hil_test::i2c_pins!(io); - let (sclk_pin, _) = hil_test::common_test_pins!(io); - let cs_pin = hil_test::unconnected_pin!(io); + let (mosi_pin, miso_pin) = hil_test::i2c_pins!(peripherals); + let (sclk_pin, _) = hil_test::common_test_pins!(peripherals); + let cs_pin = hil_test::unconnected_pin!(peripherals); let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/twai.rs b/hil-test/tests/twai.rs index a1be5524ef9..14a871d7b36 100644 --- a/hil-test/tests/twai.rs +++ b/hil-test/tests/twai.rs @@ -7,7 +7,6 @@ use embedded_hal_02::can::Frame; use esp_hal::{ - gpio::Io, prelude::*, twai::{self, filter::SingleStandardFilter, EspTwaiFrame, StandardId, TwaiMode}, Blocking, @@ -28,9 +27,7 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (loopback_pin, _) = hil_test::common_test_pins!(io); + let (loopback_pin, _) = hil_test::common_test_pins!(peripherals); let (rx, tx) = loopback_pin.split(); diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index 00e8be5f739..d9cddaa4180 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -7,7 +7,6 @@ use embedded_hal_02::serial::{Read, Write}; use esp_hal::{ - gpio::Io, prelude::*, uart::{self, ClockSource, Uart}, Blocking, @@ -28,9 +27,7 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (_, pin) = hil_test::common_test_pins!(io); + let (_, pin) = hil_test::common_test_pins!(peripherals); let (rx, tx) = pin.split(); diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs index 5adcd854ac8..7a36307c80d 100644 --- a/hil-test/tests/uart_async.rs +++ b/hil-test/tests/uart_async.rs @@ -6,7 +6,7 @@ #![no_std] #![no_main] -use esp_hal::{gpio::Io, uart::Uart, Async}; +use esp_hal::{uart::Uart, Async}; use hil_test as _; struct Context { @@ -22,9 +22,7 @@ mod tests { async fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (rx, tx) = hil_test::common_test_pins!(io); + let (rx, tx) = hil_test::common_test_pins!(peripherals); let uart = Uart::new(peripherals.UART0, rx, tx).unwrap().into_async(); diff --git a/hil-test/tests/uart_regression.rs b/hil-test/tests/uart_regression.rs index 1892ddaeadf..f2118afaa26 100644 --- a/hil-test/tests/uart_regression.rs +++ b/hil-test/tests/uart_regression.rs @@ -9,7 +9,6 @@ #[embedded_test::tests] mod tests { use esp_hal::{ - gpio::Io, prelude::*, uart::{UartRx, UartTx}, }; @@ -21,9 +20,7 @@ mod tests { fn test_that_creating_tx_does_not_cause_a_pulse() { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (rx, mut tx) = hil_test::common_test_pins!(io); + let (rx, mut tx) = hil_test::common_test_pins!(peripherals); let mut rx = UartRx::new(peripherals.UART1, rx).unwrap(); diff --git a/hil-test/tests/uart_tx_rx.rs b/hil-test/tests/uart_tx_rx.rs index 7e99e5e9f70..8274a9043db 100644 --- a/hil-test/tests/uart_tx_rx.rs +++ b/hil-test/tests/uart_tx_rx.rs @@ -6,7 +6,6 @@ #![no_main] use esp_hal::{ - gpio::Io, prelude::*, uart::{UartRx, UartTx}, Blocking, @@ -28,9 +27,7 @@ mod tests { fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (rx, tx) = hil_test::common_test_pins!(io); + let (rx, tx) = hil_test::common_test_pins!(peripherals); let tx = UartTx::new(peripherals.UART0, tx).unwrap(); let rx = UartRx::new(peripherals.UART1, rx).unwrap(); diff --git a/hil-test/tests/uart_tx_rx_async.rs b/hil-test/tests/uart_tx_rx_async.rs index 4122d0963e9..4f02cf63bda 100644 --- a/hil-test/tests/uart_tx_rx_async.rs +++ b/hil-test/tests/uart_tx_rx_async.rs @@ -7,7 +7,6 @@ #![no_main] use esp_hal::{ - gpio::Io, uart::{UartRx, UartTx}, Async, }; @@ -27,9 +26,7 @@ mod tests { async fn init() -> Context { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - - let (rx, tx) = hil_test::common_test_pins!(io); + let (rx, tx) = hil_test::common_test_pins!(peripherals); let tx = UartTx::new(peripherals.UART0, tx).unwrap().into_async(); let rx = UartRx::new(peripherals.UART1, rx).unwrap().into_async(); From 6cb5d9643f3dc0ea61d7260ee8890a12975cdd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 11:49:30 +0100 Subject: [PATCH 55/67] Deduplicate impl, chunk data in ehal transaction Operations (#2481) --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/i2c/master/mod.rs | 602 ++++++++++++++++------------------ 2 files changed, 276 insertions(+), 327 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b056d84a6de..18a821fb17e 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -107,6 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Restored blocking `embedded_hal` compatibility for async I2C driver (#2343) +- I2c::transaction is now able to transmit data of arbitrary length (#2481) ## [0.21.0] diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index 681eeab1f5c..b336ea1b3af 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -336,6 +336,7 @@ where operations: &mut [embedded_hal::i2c::Operation<'_>], ) -> Result<(), Self::Error> { self.transaction_impl(address, operations.iter_mut().map(Operation::from)) + .inspect_err(|_| self.internal_recover()) } } @@ -370,7 +371,6 @@ where address: u8, operations: impl Iterator>, ) -> Result<(), Error> { - let driver = self.driver(); let mut last_op: Option = None; // filter out 0 length read operations let mut op_iter = operations @@ -380,40 +380,30 @@ where while let Some(op) = op_iter.next() { let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one - driver - .write_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Write)), - next_op.is_none(), - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; + self.driver().write_blocking( + address, + buffer, + !matches!(last_op, Some(OpKind::Write)), + next_op.is_none(), + )?; } Operation::Read(buffer) => { // execute a read operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one // - will_continue is true if there is another read operation next - driver - .read_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Read)), - next_op.is_none(), - matches!(next_op, Some(OpKind::Read)), - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; + self.driver().read_blocking( + address, + buffer, + !matches!(last_op, Some(OpKind::Read)), + next_op.is_none(), + matches!(next_op, Some(OpKind::Read)), + )?; } } @@ -505,53 +495,18 @@ where } } - /// Reads enough bytes from slave with `address` to fill `buffer` - pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - let driver = self.driver(); - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - driver - .read_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - idx < chunk_count - 1, - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; - } - - Ok(()) - } - /// Writes bytes to slave with address `address` pub fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - let driver = self.driver(); - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - driver - .write_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; - } + self.driver() + .write_blocking(address, buffer, true, true) + .inspect_err(|_| self.internal_recover()) + } - Ok(()) + /// Reads enough bytes from slave with `address` to fill `buffer` + pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + self.driver() + .read_blocking(address, buffer, true, true, false) + .inspect_err(|_| self.internal_recover()) } /// Writes bytes to slave with address `address` and then reads enough bytes @@ -562,44 +517,13 @@ where write_buffer: &[u8], read_buffer: &mut [u8], ) -> Result<(), Error> { - let driver = self.driver(); - let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); - let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); - - for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - self.driver() - .write_operation( - address, - chunk, - idx == 0, - idx == write_count - 1 && read_count == 0, - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; - } - - for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); + self.driver() + .write_blocking(address, write_buffer, true, read_buffer.is_empty()) + .inspect_err(|_| self.internal_recover())?; - self.driver() - .read_operation( - address, - chunk, - idx == 0, - idx == read_count - 1, - idx < read_count - 1, - cmd_iterator, - ) - .inspect_err(|_| self.internal_recover())?; - } + self.driver() + .read_blocking(address, read_buffer, true, true, false) + .inspect_err(|_| self.internal_recover())?; Ok(()) } @@ -628,6 +552,7 @@ where operations: impl IntoIterator>, ) -> Result<(), Error> { self.transaction_impl(address, operations.into_iter().map(Operation::from)) + .inspect_err(|_| self.internal_recover()) } } @@ -773,163 +698,20 @@ where } } - #[cfg(any(esp32, esp32s2))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() > 32 { - panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); - } - - self.driver().wait_for_completion(false).await?; - - for byte in buffer.iter_mut() { - *byte = read_fifo(self.driver().register_block()); - } - - Ok(()) - } - - #[cfg(not(any(esp32, esp32s2)))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - self.driver().read_all_from_fifo(buffer) - } - - /// Executes an async I2C write operation. - /// - `addr` is the address of the slave device. - /// - `bytes` is the data two be sent. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `cmd_iterator` is an iterator over the command registers. - async fn write_operation<'a, I>( - &self, - address: u8, - bytes: &[u8], - start: bool, - stop: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length writes without start or end as that would be an - // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 - if bytes.is_empty() && !start && !stop { - return Ok(()); - } - - // Reset FIFO and command list - self.driver().reset_fifo(); - self.driver().reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.driver() - .setup_write(address, bytes, start, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - let index = self.driver().fill_tx_fifo(bytes); - self.driver().start_transmission(); - - // Fill the FIFO with the remaining bytes: - self.driver().write_remaining_tx_fifo(index, bytes).await?; - self.driver().wait_for_completion(!stop).await?; - Ok(()) - } - - /// Executes an async I2C read operation. - /// - `addr` is the address of the slave device. - /// - `buffer` is the buffer to store the read data. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `will_continue` indicates whether there is another read operation - /// following this one and we should not nack the last byte. - /// - `cmd_iterator` is an iterator over the command registers. - async fn read_operation<'a, I>( - &self, - address: u8, - buffer: &mut [u8], - start: bool, - stop: bool, - will_continue: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length reads as that would be an invalid operation - // read lengths in the TRM (at least for ESP32-S3) are 1-255 - if buffer.is_empty() { - return Ok(()); - } - - // Reset FIFO and command list - self.driver().reset_fifo(); - self.driver().reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.driver() - .setup_read(address, buffer, start, will_continue, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - self.driver().start_transmission(); - self.read_all_from_fifo(buffer).await?; - self.driver().wait_for_completion(!stop).await?; - Ok(()) - } - /// Writes bytes to slave with address `address` pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - let driver = self.driver(); - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) + self.driver() + .write(address, buffer, true, true) + .await + .inspect_err(|_| self.internal_recover()) } /// Reads enough bytes from slave with `address` to fill `buffer` pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - let driver = self.driver(); - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - self.read_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - idx < chunk_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) + self.driver() + .read(address, buffer, true, true, false) + .await + .inspect_err(|_| self.internal_recover()) } /// Writes bytes to slave with address `address` and then reads enough @@ -940,41 +722,15 @@ where write_buffer: &[u8], read_buffer: &mut [u8], ) -> Result<(), Error> { - let driver = self.driver(); - let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); - let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == write_count - 1 && read_count == 0, - cmd_iterator, - ) - .await?; - } - - for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); + self.driver() + .write(address, write_buffer, true, read_buffer.is_empty()) + .await + .inspect_err(|_| self.internal_recover())?; - self.read_operation( - address, - chunk, - idx == 0, - idx == read_count - 1, - idx < read_count - 1, - cmd_iterator, - ) - .await?; - } + self.driver() + .read(address, read_buffer, true, true, false) + .await + .inspect_err(|_| self.internal_recover())?; Ok(()) } @@ -1005,6 +761,7 @@ where ) -> Result<(), Error> { self.transaction_impl_async(address, operations.into_iter().map(Operation::from)) .await + .inspect_err(|_| self.internal_recover()) } async fn transaction_impl_async<'a>( @@ -1012,7 +769,6 @@ where address: u8, operations: impl Iterator>, ) -> Result<(), Error> { - let driver = self.driver(); let mut last_op: Option = None; // filter out 0 length read operations let mut op_iter = operations @@ -1022,38 +778,34 @@ where while let Some(op) = op_iter.next() { let next_op = op_iter.peek().map(|v| v.kind()); let kind = op.kind(); - // Clear all I2C interrupts - driver.clear_all_interrupts(); - - let cmd_iterator = &mut driver.register_block().comd_iter(); match op { Operation::Write(buffer) => { // execute a write operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one - self.write_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Write)), - next_op.is_none(), - cmd_iterator, - ) - .await?; + self.driver() + .write( + address, + buffer, + !matches!(last_op, Some(OpKind::Write)), + next_op.is_none(), + ) + .await?; } Operation::Read(buffer) => { // execute a read operation: // - issue START/RSTART if op is different from previous // - issue STOP if op is the last one // - will_continue is true if there is another read operation next - self.read_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Read)), - next_op.is_none(), - matches!(next_op, Some(OpKind::Read)), - cmd_iterator, - ) - .await?; + self.driver() + .read( + address, + buffer, + !matches!(last_op, Some(OpKind::Read)), + next_op.is_none(), + matches!(next_op, Some(OpKind::Read)), + ) + .await?; } } @@ -1075,6 +827,7 @@ where ) -> Result<(), Self::Error> { self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) .await + .inspect_err(|_| self.internal_recover()) } } @@ -1528,6 +1281,26 @@ impl Driver<'_> { ); } + #[cfg(any(esp32, esp32s2))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + if buffer.len() > 32 { + panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); + } + + self.wait_for_completion(false).await?; + + for byte in buffer.iter_mut() { + *byte = read_fifo(self.register_block()); + } + + Ok(()) + } + + #[cfg(not(any(esp32, esp32s2)))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + self.read_all_from_fifo_blocking(buffer) + } + /// Configures the I2C peripheral for a write operation. /// - `addr` is the address of the slave device. /// - `bytes` is the data two be sent. @@ -1656,7 +1429,7 @@ impl Driver<'_> { #[cfg(not(any(esp32, esp32s2)))] /// Reads all bytes from the RX FIFO. - fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + fn read_all_from_fifo_blocking(&self, buffer: &mut [u8]) -> Result<(), Error> { // Read bytes from FIFO // FIXME: Handle case where less data has been provided by the slave than // requested? Or is this prevented from a protocol perspective? @@ -1678,7 +1451,7 @@ impl Driver<'_> { #[cfg(any(esp32, esp32s2))] /// Reads all bytes from the RX FIFO. - fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + fn read_all_from_fifo_blocking(&self, buffer: &mut [u8]) -> Result<(), Error> { // on ESP32/ESP32-S2 we currently don't support I2C transactions larger than the // FIFO apparently it would be possible by using non-fifo mode // see https://github.com/espressif/arduino-esp32/blob/7e9afe8c5ed7b5bf29624a5cd6e07d431c027b97/cores/esp32/esp32-hal-i2c.c#L615 @@ -2090,17 +1863,15 @@ impl Driver<'_> { /// - `stop` indicates whether the operation should end with a STOP /// condition. /// - `cmd_iterator` is an iterator over the command registers. - fn write_operation<'a, I>( + fn write_operation_blocking( &self, address: u8, bytes: &[u8], start: bool, stop: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { + ) -> Result<(), Error> { + self.clear_all_interrupts(); + // Short circuit for zero length writes without start or end as that would be an // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 if bytes.is_empty() && !start && !stop { @@ -2111,6 +1882,8 @@ impl Driver<'_> { self.reset_fifo(); self.reset_command_list(); + let cmd_iterator = &mut self.register_block().comd_iter(); + if start { add_cmd(cmd_iterator, Command::Start)?; } @@ -2138,18 +1911,16 @@ impl Driver<'_> { /// - `will_continue` indicates whether there is another read operation /// following this one and we should not nack the last byte. /// - `cmd_iterator` is an iterator over the command registers. - fn read_operation<'a, I>( + fn read_operation_blocking( &self, address: u8, buffer: &mut [u8], start: bool, stop: bool, will_continue: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { + ) -> Result<(), Error> { + self.clear_all_interrupts(); + // Short circuit for zero length reads as that would be an invalid operation // read lengths in the TRM (at least for ESP32-S3) are 1-255 if buffer.is_empty() { @@ -2160,6 +1931,8 @@ impl Driver<'_> { self.reset_fifo(); self.reset_command_list(); + let cmd_iterator = &mut self.register_block().comd_iter(); + if start { add_cmd(cmd_iterator, Command::Start)?; } @@ -2171,10 +1944,185 @@ impl Driver<'_> { if stop { Command::Stop } else { Command::End }, )?; self.start_transmission(); - self.read_all_from_fifo(buffer)?; + self.read_all_from_fifo_blocking(buffer)?; self.wait_for_completion_blocking(!stop)?; Ok(()) } + + /// Executes an async I2C write operation. + /// - `addr` is the address of the slave device. + /// - `bytes` is the data two be sent. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `cmd_iterator` is an iterator over the command registers. + async fn write_operation( + &self, + address: u8, + bytes: &[u8], + start: bool, + stop: bool, + ) -> Result<(), Error> { + self.clear_all_interrupts(); + + // Short circuit for zero length writes without start or end as that would be an + // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 + if bytes.is_empty() && !start && !stop { + return Ok(()); + } + + // Reset FIFO and command list + self.reset_fifo(); + self.reset_command_list(); + + let cmd_iterator = &mut self.register_block().comd_iter(); + if start { + add_cmd(cmd_iterator, Command::Start)?; + } + self.setup_write(address, bytes, start, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + let index = self.fill_tx_fifo(bytes); + self.start_transmission(); + + // Fill the FIFO with the remaining bytes: + self.write_remaining_tx_fifo(index, bytes).await?; + self.wait_for_completion(!stop).await?; + Ok(()) + } + + /// Executes an async I2C read operation. + /// - `addr` is the address of the slave device. + /// - `buffer` is the buffer to store the read data. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `will_continue` indicates whether there is another read operation + /// following this one and we should not nack the last byte. + /// - `cmd_iterator` is an iterator over the command registers. + async fn read_operation( + &self, + address: u8, + buffer: &mut [u8], + start: bool, + stop: bool, + will_continue: bool, + ) -> Result<(), Error> { + self.clear_all_interrupts(); + + // Short circuit for zero length reads as that would be an invalid operation + // read lengths in the TRM (at least for ESP32-S3) are 1-255 + if buffer.is_empty() { + return Ok(()); + } + + // Reset FIFO and command list + self.reset_fifo(); + self.reset_command_list(); + let cmd_iterator = &mut self.register_block().comd_iter(); + if start { + add_cmd(cmd_iterator, Command::Start)?; + } + self.setup_read(address, buffer, start, will_continue, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + self.start_transmission(); + self.read_all_from_fifo(buffer).await?; + self.wait_for_completion(!stop).await?; + Ok(()) + } + + fn read_blocking( + &self, + address: u8, + buffer: &mut [u8], + start: bool, + stop: bool, + will_continue: bool, + ) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + self.read_operation_blocking( + address, + chunk, + start && idx == 0, + stop && idx == chunk_count - 1, + will_continue || idx < chunk_count - 1, + )?; + } + + Ok(()) + } + + fn write_blocking( + &self, + address: u8, + buffer: &[u8], + start: bool, + stop: bool, + ) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + self.write_operation_blocking( + address, + chunk, + start && idx == 0, + stop && idx == chunk_count - 1, + )?; + } + + Ok(()) + } + + async fn read( + &self, + address: u8, + buffer: &mut [u8], + start: bool, + stop: bool, + will_continue: bool, + ) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + self.read_operation( + address, + chunk, + start && idx == 0, + stop && idx == chunk_count - 1, + will_continue || idx < chunk_count - 1, + ) + .await?; + } + + Ok(()) + } + + async fn write( + &self, + address: u8, + buffer: &[u8], + start: bool, + stop: bool, + ) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + self.write_operation( + address, + chunk, + start && idx == 0, + stop && idx == chunk_count - 1, + ) + .await?; + } + + Ok(()) + } } impl PartialEq for Info { From 5d120f7a7088ae7a86dc4dca73f06cd909d851ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Tue, 12 Nov 2024 12:43:01 +0100 Subject: [PATCH 56/67] Remove the integrated blocking networking stack (#2488) * Add simple example using `smoltcp-nal` * Remove the blocking networking stack * Renaming * Fix CI * CHANGELOG.md * Fixes after re-base * Update esp-wifi/MIGRATING-0.10.md Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> * Improve diff in migration guide --------- Co-authored-by: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> --- esp-wifi/CHANGELOG.md | 1 + esp-wifi/Cargo.toml | 28 +- esp-wifi/MIGRATING-0.10.md | 34 + esp-wifi/src/lib.rs | 11 - esp-wifi/src/wifi/mod.rs | 276 ----- esp-wifi/src/wifi/utils.rs | 68 +- esp-wifi/src/wifi_interface.rs | 995 ------------------ examples/Cargo.toml | 3 + examples/src/bin/wifi_80211_tx.rs | 2 +- examples/src/bin/wifi_access_point.rs | 45 +- .../src/bin/wifi_access_point_with_sta.rs | 66 +- examples/src/bin/wifi_bench.rs | 53 +- examples/src/bin/wifi_coex.rs | 42 +- examples/src/bin/wifi_csi.rs | 41 +- examples/src/bin/wifi_dhcp.rs | 41 +- examples/src/bin/wifi_dhcp_smoltcp_nal.rs | 224 ++++ examples/src/bin/wifi_embassy_access_point.rs | 2 +- .../bin/wifi_embassy_access_point_with_sta.rs | 2 +- examples/src/bin/wifi_embassy_bench.rs | 2 +- examples/src/bin/wifi_embassy_dhcp.rs | 2 +- examples/src/bin/wifi_embassy_esp_now.rs | 2 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 2 +- examples/src/bin/wifi_esp_now.rs | 2 +- examples/src/bin/wifi_sniffer.rs | 2 +- examples/src/bin/wifi_static_ip.rs | 41 +- xtask/src/lib.rs | 5 +- xtask/src/main.rs | 2 +- 27 files changed, 472 insertions(+), 1522 deletions(-) delete mode 100644 esp-wifi/src/wifi_interface.rs create mode 100644 examples/src/bin/wifi_dhcp_smoltcp_nal.rs diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 96050adf2da..1280fa9c3d9 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Features `phy-enable-usb` & `dump-packets` have been turned into configuration options `phy_enable_usb` & `dump_packets` (#2446) - Features `ps-min-modem` & `ps-max-modem` have been removed in favour of a runtime config (#2446) +- The blocking networking stack is removed (#2488) ## 0.10.1 - 2024-10-10 diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 65d1beb2443..2199f704bec 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -108,7 +108,7 @@ coex = [] sys-logs = ["esp-wifi-sys/sys-logs"] ## Enable support for `defmt` -defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt", "bt-hci?/defmt", "esp-wifi-sys/defmt"] +defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt", "bt-hci?/defmt", "esp-wifi-sys/defmt", "heapless/defmt-03"] ## Enable support for the `log` crate log = ["dep:log", "esp-hal/log", "esp-wifi-sys/log"] @@ -131,32 +131,6 @@ smoltcp = ["dep:smoltcp"] ## Provide utilities for smoltcp initialization. Adds smoltcp dependency utils = ["smoltcp"] -## IPv6 support. Includes utils feature -ipv6 = ["wifi", "utils", "smoltcp?/proto-ipv6"] - -## IPv4 support. Includes utils feature -ipv4 = ["wifi", "utils", "smoltcp?/proto-ipv4"] - -## TCP socket support. Includes ipv4 feature -tcp = ["ipv4", "smoltcp?/socket-tcp"] - -## UDP socket support. Includes ipv4 feature -udp = ["ipv4", "smoltcp?/socket-udp"] - -## ICMP socket support. Includes ipv4 feature -icmp = ["ipv4", "smoltcp?/socket-icmp"] - -## IGMP (multicast) support. Includes ipv4 featu -igmp = ["ipv4", "smoltcp?/proto-igmp"] - -## DNS support. Includes udp feature -dns = ["udp", "smoltcp?/proto-dns", "smoltcp?/socket-dns"] - -## DHCPv4 support, both creating sockets and autoconfiguring network settings. Includes utils feature -dhcpv4 = ["wifi", "utils", "smoltcp?/proto-dhcpv4", "smoltcp?/socket-dhcpv4"] - -## Convenience to enable "ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4" -wifi-default = ["ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4"] # Implement serde Serialize / Deserialize serde = ["dep:serde", "enumset?/serde", "heapless/serde"] diff --git a/esp-wifi/MIGRATING-0.10.md b/esp-wifi/MIGRATING-0.10.md index d2763ba21fb..68f894d13f8 100644 --- a/esp-wifi/MIGRATING-0.10.md +++ b/esp-wifi/MIGRATING-0.10.md @@ -42,3 +42,37 @@ The cost of this is that we need to rename the various `async` methods on `WifiC - controller.start().await.unwrap(); + controller.start_async().await.unwrap(); ``` + +## The blocking networking stack was removed + +The blocking networking stack is not included anymore. You can use e.g. `smoltcp-nal` or even use `smoltcp` directly. + +For an easy migration path there is https://github.com/bjoernQ/blocking-network-stack.git which is basically the previously included networking stack as it's +own crate. + +The `create_network_interface` function doesn't take `&mut SocketSet[..]` anymore. + +```diff ++use blocking_network_stack::Stack; +use esp_wifi::{ +- wifi_interface::WifiStack, +}; + ++ let mut rng = Rng::new(peripherals.RNG); +- let init = init(timg0.timer0, rng, peripherals.RADIO_CLK).unwrap(); ++ let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); + + let mut wifi = peripherals.WIFI; + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); ++ let (iface, device, mut controller) = ++ create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); ++ +- let (iface, device, mut controller, sockets) = +- create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); ++ let socket_set = SocketSet::new(&mut socket_set_entries[..]); + let now = || time::now().duration_since_epoch().to_millis(); +- let wifi_stack = WifiStack::new(iface, device, sockets, now); ++ let wifi_stack = Stack::new(iface, device, socket_set, now, rng.random()); +``` + +The related features are removed from `esp-wifi`: wifi-default, ipv6, ipv4, tcp, udp, icmp, igmp, dns, dhcpv4 diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 2d5849da440..d370bdd707f 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -136,17 +136,6 @@ pub mod tasks; pub(crate) mod memory_fence; -#[cfg(all(feature = "wifi", any(feature = "tcp", feature = "udp")))] -pub mod wifi_interface; - -// [esp_hal::time::now()] as a smoltcp [`Instant]` -#[cfg(feature = "smoltcp")] -fn timestamp() -> smoltcp::time::Instant { - smoltcp::time::Instant::from_micros( - esp_hal::time::now().duration_since_epoch().to_micros() as i64 - ) -} - // this is just to verify that we use the correct defaults in `build.rs` #[allow(clippy::assertions_on_constants)] // TODO: try assert_eq once it's usable in const context const _: () = { diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index e5b4f494268..b2e2abafc6b 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -829,282 +829,6 @@ impl Configuration { } } -/// IPv4 network configurations. -pub mod ipv4 { - pub use core::net::Ipv4Addr; - use core::{fmt::Display, str::FromStr}; - - #[cfg(feature = "serde")] - use serde::{Deserialize, Serialize}; - - /// Represents a subnet mask. - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct Mask(pub u8); - - impl FromStr for Mask { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - s.parse::() - .map_err(|_| "Invalid subnet mask") - .map_or_else(Err, |mask| { - if (1..=32).contains(&mask) { - Ok(Mask(mask)) - } else { - Err("Mask should be a number between 1 and 32") - } - }) - } - } - - impl Display for Mask { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0) - } - } - - impl TryFrom for Mask { - type Error = (); - - fn try_from(ip: Ipv4Addr) -> Result { - let octets = ip.octets(); - let addr: u32 = ((octets[0] as u32 & 0xff) << 24) - | ((octets[1] as u32 & 0xff) << 16) - | ((octets[2] as u32 & 0xff) << 8) - | (octets[3] as u32 & 0xff); - - if addr.leading_ones() + addr.trailing_zeros() == 32 { - Ok(Mask(addr.leading_ones() as u8)) - } else { - Err(()) - } - } - } - - impl From for Ipv4Addr { - fn from(mask: Mask) -> Self { - let addr: u32 = ((1 << (32 - mask.0)) - 1) ^ 0xffffffffu32; - - let (a, b, c, d) = ( - ((addr >> 24) & 0xff) as u8, - ((addr >> 16) & 0xff) as u8, - ((addr >> 8) & 0xff) as u8, - (addr & 0xff) as u8, - ); - - Ipv4Addr::new(a, b, c, d) - } - } - - /// Represents a subnet consisting of a gateway and a mask. - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct Subnet { - /// The gateway IP address of the subnet. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub gateway: Ipv4Addr, - /// The subnet mask associated with the subnet. - pub mask: Mask, - } - - impl Display for Subnet { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}/{}", self.gateway, self.mask) - } - } - - impl FromStr for Subnet { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - let mut split = s.split('/'); - if let Some(gateway_str) = split.next() { - if let Some(mask_str) = split.next() { - if split.next().is_none() { - if let Ok(gateway) = gateway_str.parse::() { - return mask_str.parse::().map(|mask| Self { gateway, mask }); - } else { - return Err("Invalid IP address format, expected XXX.XXX.XXX.XXX"); - } - } - } - } - - Err("Expected /") - } - } - - /// Settings for a client in an IPv4 network. - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct ClientSettings { - /// The client's IPv4 address. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub ip: Ipv4Addr, - - /// The subnet associated with the client's IP address. - pub subnet: Subnet, - - /// The primary DNS server for name resolution. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub dns: Option, - - /// The secondary DNS server for name resolution. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub secondary_dns: Option, - } - - impl Default for ClientSettings { - fn default() -> ClientSettings { - ClientSettings { - ip: Ipv4Addr::new(192, 168, 71, 200), - subnet: Subnet { - gateway: Ipv4Addr::new(192, 168, 71, 1), - mask: Mask(24), - }, - dns: Some(Ipv4Addr::new(8, 8, 8, 8)), - secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)), - } - } - } - - /// Settings for the DHCP client. - /// - /// This struct contains the configuration for a DHCP client, including a - /// hostname that can be sent during DHCP negotiations. - #[derive(Default, Clone, Debug, PartialEq, Eq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct DHCPClientSettings { - pub hostname: Option>, - } - - /// Configuration for the client in an IPv4 network. - /// - /// This enum defines how the client's IP settings are obtained: either - /// through DHCP, or as a fixed (static) configuration. - #[derive(Clone, Debug, PartialEq, Eq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub enum ClientConfiguration { - /// Use DHCP to obtain network settings. - DHCP(DHCPClientSettings), - - /// Use a fixed configuration for network settings. - Fixed(ClientSettings), - } - - impl ClientConfiguration { - /// Returns a reference to the fixed settings if the client is using a - /// static configuration, `None` otherwise. - pub fn as_fixed_settings_ref(&self) -> Option<&ClientSettings> { - match self { - Self::Fixed(client_settings) => Some(client_settings), - _ => None, - } - } - - /// Returns a mutable reference to the fixed settings, creating a - /// default fixed configuration if necessary. - pub fn as_fixed_settings_mut(&mut self) -> &mut ClientSettings { - match self { - Self::Fixed(client_settings) => client_settings, - _ => { - *self = ClientConfiguration::Fixed(Default::default()); - self.as_fixed_settings_mut() - } - } - } - } - - impl Default for ClientConfiguration { - fn default() -> ClientConfiguration { - ClientConfiguration::DHCP(Default::default()) - } - } - - /// Router configuration in an IPv4 network. - #[derive(Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct RouterConfiguration { - /// The subnet the router is responsible for. - pub subnet: Subnet, - - /// Indicates whether DHCP is enabled on the router. - pub dhcp_enabled: bool, - - /// The primary DNS server for the router. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub dns: Option, - - /// The secondary DNS server for the router. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub secondary_dns: Option, - } - - impl Default for RouterConfiguration { - fn default() -> RouterConfiguration { - RouterConfiguration { - subnet: Subnet { - gateway: Ipv4Addr::new(192, 168, 71, 1), - mask: Mask(24), - }, - dhcp_enabled: true, - dns: Some(Ipv4Addr::new(8, 8, 8, 8)), - secondary_dns: Some(Ipv4Addr::new(8, 8, 4, 4)), - } - } - } - - /// Represents the network configuration for a device. - /// - /// Holds either a client configuration (for devices connecting to a - /// network) or a router configuration (for devices providing a network - /// to other clients). - #[derive(Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub enum Configuration { - /// Configuration for a device acting as a client in the network. - Client(ClientConfiguration), - - /// Configuration for a device acting as a router in the network. - Router(RouterConfiguration), - } - - impl Default for Configuration { - fn default() -> Self { - Self::Client(Default::default()) - } - } - - /// Represents IPv4 information for a device. - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - pub struct IpInfo { - /// The IPv4 address of the device. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub ip: Ipv4Addr, - - /// The subnet mask associated with the device's IP address. - pub subnet: Subnet, - - /// The primary DNS server for the device. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub dns: Option, - - /// The secondary DNS server for the device. - #[cfg_attr(feature = "defmt", defmt(Debug2Format))] - pub secondary_dns: Option, - } -} - trait AuthMethodExt { fn to_raw(&self) -> wifi_auth_mode_t; fn from_raw(raw: wifi_auth_mode_t) -> Self; diff --git a/esp-wifi/src/wifi/utils.rs b/esp-wifi/src/wifi/utils.rs index e48f28f8d38..b7d8831bfd7 100644 --- a/esp-wifi/src/wifi/utils.rs +++ b/esp-wifi/src/wifi/utils.rs @@ -1,83 +1,59 @@ //! Convenience utilities for non-async code -#[cfg(feature = "dhcpv4")] -use smoltcp::socket::dhcpv4::Socket as Dhcpv4Socket; use smoltcp::{ - iface::{Config, Interface, SocketSet, SocketStorage}, + iface::{Config, Interface}, wire::{EthernetAddress, HardwareAddress}, }; use super::{WifiApDevice, WifiController, WifiDevice, WifiDeviceMode, WifiError, WifiStaDevice}; -use crate::{timestamp, EspWifiController}; +use crate::EspWifiController; -fn setup_iface<'a, MODE: WifiDeviceMode>( - device: &mut WifiDevice<'_, MODE>, - mode: MODE, - storage: &'a mut [SocketStorage<'a>], -) -> (Interface, SocketSet<'a>) { +// [esp_hal::time::now()] as a smoltcp [`Instant]` +#[cfg(feature = "smoltcp")] +fn timestamp() -> smoltcp::time::Instant { + smoltcp::time::Instant::from_micros( + esp_hal::time::now().duration_since_epoch().to_micros() as i64 + ) +} + +fn setup_iface(device: &mut WifiDevice<'_, MODE>, mode: MODE) -> Interface { let mac = mode.mac_address(); let hw_address = HardwareAddress::Ethernet(EthernetAddress::from_bytes(&mac)); let config = Config::new(hw_address); let iface = Interface::new(config, device, timestamp()); - - #[allow(unused_mut)] - let mut socket_set = SocketSet::new(storage); - - #[cfg(feature = "dhcpv4")] - if mode.mode().is_sta() { - // only add DHCP client in STA mode - let dhcp_socket = Dhcpv4Socket::new(); - socket_set.add(dhcp_socket); - } - - (iface, socket_set) + iface } /// Convenient way to create an `smoltcp` ethernet interface -/// You can use the provided macros to create and pass a suitable backing -/// storage. -pub fn create_network_interface<'a, 'd, MODE: WifiDeviceMode>( +pub fn create_network_interface<'d, MODE: WifiDeviceMode>( inited: &'d EspWifiController<'d>, device: impl crate::hal::peripheral::Peripheral

+ 'd, mode: MODE, - storage: &'a mut [SocketStorage<'a>], -) -> Result< - ( - Interface, - WifiDevice<'d, MODE>, - WifiController<'d>, - SocketSet<'a>, - ), - WifiError, -> { +) -> Result<(Interface, WifiDevice<'d, MODE>, WifiController<'d>), WifiError> { let (mut device, controller) = crate::wifi::new_with_mode(inited, device, mode)?; - let (iface, socket_set) = setup_iface(&mut device, mode, storage); + let iface = setup_iface(&mut device, mode); - Ok((iface, device, controller, socket_set)) + Ok((iface, device, controller)) } -pub struct ApStaInterface<'a, 'd> { +pub struct ApStaInterface<'d> { pub ap_interface: Interface, pub sta_interface: Interface, pub ap_device: WifiDevice<'d, WifiApDevice>, pub sta_device: WifiDevice<'d, WifiStaDevice>, pub controller: WifiController<'d>, - pub ap_socket_set: SocketSet<'a>, - pub sta_socket_set: SocketSet<'a>, } -pub fn create_ap_sta_network_interface<'a, 'd>( +pub fn create_ap_sta_network_interface<'d>( inited: &'d EspWifiController<'d>, device: impl crate::hal::peripheral::Peripheral

+ 'd, - ap_storage: &'a mut [SocketStorage<'a>], - sta_storage: &'a mut [SocketStorage<'a>], -) -> Result, WifiError> { +) -> Result, WifiError> { let (mut ap_device, mut sta_device, controller) = crate::wifi::new_ap_sta(inited, device)?; - let (ap_interface, ap_socket_set) = setup_iface(&mut ap_device, WifiApDevice, ap_storage); - let (sta_interface, sta_socket_set) = setup_iface(&mut sta_device, WifiStaDevice, sta_storage); + let ap_interface = setup_iface(&mut ap_device, WifiApDevice); + let sta_interface = setup_iface(&mut sta_device, WifiStaDevice); Ok(ApStaInterface { ap_interface, @@ -85,7 +61,5 @@ pub fn create_ap_sta_network_interface<'a, 'd>( ap_device, sta_device, controller, - ap_socket_set, - sta_socket_set, }) } diff --git a/esp-wifi/src/wifi_interface.rs b/esp-wifi/src/wifi_interface.rs deleted file mode 100644 index ddc4ed26164..00000000000 --- a/esp-wifi/src/wifi_interface.rs +++ /dev/null @@ -1,995 +0,0 @@ -//! Non-async Networking primitives for TCP/UDP communication. - -use core::{borrow::BorrowMut, cell::RefCell, fmt::Display}; - -#[cfg(feature = "dhcpv4")] -use smoltcp::socket::dhcpv4::Socket as Dhcpv4Socket; -#[cfg(feature = "tcp")] -use smoltcp::socket::tcp::Socket as TcpSocket; -#[cfg(feature = "dns")] -use smoltcp::wire::DnsQueryType; -#[cfg(feature = "udp")] -use smoltcp::wire::IpEndpoint; -use smoltcp::{ - iface::{Interface, SocketHandle, SocketSet}, - time::Instant, - wire::{IpAddress, IpCidr, Ipv4Address}, -}; - -use crate::{ - timestamp, - wifi::{ipv4, WifiDevice, WifiDeviceMode}, -}; - -#[cfg(feature = "tcp")] -const LOCAL_PORT_MIN: u16 = 41000; -#[cfg(feature = "tcp")] -const LOCAL_PORT_MAX: u16 = 65535; - -/// Non-async TCP/IP network stack -/// -/// Mostly a convenience wrapper for `smoltcp` -pub struct WifiStack<'a, MODE: WifiDeviceMode> { - device: RefCell>, - network_interface: RefCell, - sockets: RefCell>, - current_millis_fn: fn() -> u64, - #[cfg(feature = "tcp")] - local_port: RefCell, - pub(crate) network_config: RefCell, - pub(crate) ip_info: RefCell>, - #[cfg(feature = "dhcpv4")] - pub(crate) dhcp_socket_handle: RefCell>, - #[cfg(feature = "dhcpv4")] - pub(crate) old_connected: RefCell, - #[cfg(feature = "dns")] - dns_socket_handle: RefCell>, -} - -impl<'a, MODE: WifiDeviceMode> WifiStack<'a, MODE> { - /// Creates new `WifiStack` instance. - /// - /// Handles optional DHCP/DNS features and sets up the - /// configuration for the network interface. - pub fn new( - network_interface: Interface, - device: WifiDevice<'a, MODE>, - #[allow(unused_mut)] mut sockets: SocketSet<'a>, - current_millis_fn: fn() -> u64, - ) -> WifiStack<'a, MODE> { - #[cfg(feature = "dhcpv4")] - let mut dhcp_socket_handle: Option = None; - #[cfg(feature = "dns")] - let mut dns_socket_handle: Option = None; - - #[cfg(any(feature = "dhcpv4", feature = "dns"))] - for (handle, socket) in sockets.iter_mut() { - match socket { - #[cfg(feature = "dhcpv4")] - smoltcp::socket::Socket::Dhcpv4(_) => dhcp_socket_handle = Some(handle), - #[cfg(feature = "dns")] - smoltcp::socket::Socket::Dns(_) => dns_socket_handle = Some(handle), - _ => {} - } - } - - let this = Self { - device: RefCell::new(device), - network_interface: RefCell::new(network_interface), - network_config: RefCell::new(ipv4::Configuration::Client( - ipv4::ClientConfiguration::DHCP(ipv4::DHCPClientSettings { - // FIXME: smoltcp currently doesn't have a way of giving a hostname through DHCP - hostname: Some(unwrap!("Espressif".try_into().ok())), - }), - )), - ip_info: RefCell::new(None), - #[cfg(feature = "dhcpv4")] - dhcp_socket_handle: RefCell::new(dhcp_socket_handle), - #[cfg(feature = "dhcpv4")] - old_connected: RefCell::new(false), - sockets: RefCell::new(sockets), - current_millis_fn, - #[cfg(feature = "tcp")] - local_port: RefCell::new( - (unsafe { crate::common_adapter::random() } - % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u32) as u16 - + LOCAL_PORT_MIN, - ), - #[cfg(feature = "dns")] - dns_socket_handle: RefCell::new(dns_socket_handle), - }; - - this.reset(); - - this - } - - /// Update the interface configuration - pub fn update_iface_configuration( - &self, - conf: &ipv4::Configuration, - ) -> Result<(), WifiStackError> { - let mac = self.device.borrow().mac_address(); - let hw_address = smoltcp::wire::HardwareAddress::Ethernet( - smoltcp::wire::EthernetAddress::from_bytes(&mac), - ); - self.network_interface - .borrow_mut() - .set_hardware_addr(hw_address); - info!("Set hardware address: {:?}", hw_address); - - self.reset(); // reset IP address - - #[cfg(feature = "dhcpv4")] - { - let mut dhcp_socket_handle_ref = self.dhcp_socket_handle.borrow_mut(); - let mut sockets_ref = self.sockets.borrow_mut(); - - if let Some(dhcp_handle) = *dhcp_socket_handle_ref { - // remove the DHCP client if we use a static IP - if matches!( - conf, - ipv4::Configuration::Client(ipv4::ClientConfiguration::Fixed(_)) - ) { - sockets_ref.remove(dhcp_handle); - *dhcp_socket_handle_ref = None; - } - } - - // re-add the DHCP client if we use DHCP and it has been removed before - if matches!( - conf, - ipv4::Configuration::Client(ipv4::ClientConfiguration::DHCP(_)) - ) && dhcp_socket_handle_ref.is_none() - { - let dhcp_socket = Dhcpv4Socket::new(); - let dhcp_socket_handle = sockets_ref.add(dhcp_socket); - *dhcp_socket_handle_ref = Some(dhcp_socket_handle); - } - - if let Some(dhcp_handle) = *dhcp_socket_handle_ref { - let dhcp_socket = sockets_ref.get_mut::(dhcp_handle); - info!("Reset DHCP client"); - dhcp_socket.reset(); - } - } - - *self.network_config.borrow_mut() = conf.clone(); - Ok(()) - } - - /// Reset the stack - pub fn reset(&self) { - debug!("Reset TCP stack"); - - #[cfg(feature = "dhcpv4")] - { - let dhcp_socket_handle_ref = self.dhcp_socket_handle.borrow_mut(); - if let Some(dhcp_handle) = *dhcp_socket_handle_ref { - self.with_mut(|_, _, sockets| { - let dhcp_socket = sockets.get_mut::(dhcp_handle); - debug!("Reset DHCP client"); - dhcp_socket.reset(); - }); - } - } - - self.with_mut(|interface, _, _| { - interface.routes_mut().remove_default_ipv4_route(); - interface.update_ip_addrs(|addrs| { - addrs.clear(); - }); - - #[cfg(feature = "ipv6")] - { - unwrap!(interface.routes_mut().add_default_ipv6_route( - smoltcp::wire::Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0,) - )); - - let mut mac = [0u8; 6]; - match interface.hardware_addr() { - smoltcp::wire::HardwareAddress::Ethernet(hw_address) => { - mac.copy_from_slice(hw_address.as_bytes()); - } - } - - let a4 = ((mac[0] ^ 2) as u16) << 8 | mac[1] as u16; - let a5 = (mac[2] as u16) << 8 | 0xff; - let a6 = 0xfe << 8 | mac[3] as u16; - let a7 = (mac[4] as u16) << 8 | mac[5] as u16; - - info!( - "IPv6 link-local address fe80::{:x}:{:x}:{:x}:{:x}", - a4, a5, a6, a7 - ); - - interface.update_ip_addrs(|addrs| { - unwrap!(addrs.push(IpCidr::new( - smoltcp::wire::IpAddress::v6(0xfe80, 0, 0, 0, a4, a5, a6, a7), - 64, - ))); - }); - } - }); - } - - /// Retrieve all current IP addresses - pub fn get_ip_addresses(&self, f: impl FnOnce(&[smoltcp::wire::IpCidr])) { - self.with_mut(|interface, _, _| f(interface.ip_addrs())) - } - - /// Convenience function to poll the DHCP socket. - #[cfg(feature = "dhcpv4")] - pub fn poll_dhcp( - &self, - interface: &mut Interface, - sockets: &mut SocketSet<'a>, - ) -> Result<(), WifiStackError> { - let dhcp_socket_handle_ref = self.dhcp_socket_handle.borrow_mut(); - if let Some(dhcp_handle) = *dhcp_socket_handle_ref { - let dhcp_socket = sockets.get_mut::(dhcp_handle); - - let connected = matches!( - crate::wifi::get_sta_state(), - crate::wifi::WifiState::StaConnected - ); - - if connected && !*self.old_connected.borrow() { - dhcp_socket.reset(); - } - - *self.old_connected.borrow_mut() = connected; - - let event = dhcp_socket.poll(); - if let Some(event) = event { - match event { - smoltcp::socket::dhcpv4::Event::Deconfigured => { - *self.ip_info.borrow_mut() = None; - interface.routes_mut().remove_default_ipv4_route(); - } - smoltcp::socket::dhcpv4::Event::Configured(config) => { - let dns = config.dns_servers.first(); - *self.ip_info.borrow_mut() = Some(ipv4::IpInfo { - ip: config.address.address().0.into(), - subnet: ipv4::Subnet { - gateway: unwrap!(config.router).0.into(), - mask: ipv4::Mask(config.address.prefix_len()), - }, - dns: dns.map(|x| x.0.into()), - secondary_dns: config.dns_servers.get(1).map(|x| x.0.into()), - }); - - let address = config.address; - interface.borrow_mut().update_ip_addrs(|addrs| { - unwrap!(addrs.push(smoltcp::wire::IpCidr::Ipv4(address))); - }); - if let Some(route) = config.router { - unwrap!(interface.routes_mut().add_default_ipv4_route(route)); - } - - #[cfg(feature = "dns")] - if let (Some(&dns), Some(dns_handle)) = - (dns, *self.dns_socket_handle.borrow()) - { - sockets - .get_mut::(dns_handle) - .update_servers(&[dns.into()]); - } - } - } - } - } - - Ok(()) - } - - /// Create a new [Socket] - #[cfg(feature = "tcp")] - pub fn get_socket<'s>( - &'s self, - rx_buffer: &'a mut [u8], - tx_buffer: &'a mut [u8], - ) -> Socket<'s, 'a, MODE> - where - 'a: 's, - { - let socket = TcpSocket::new( - smoltcp::socket::tcp::SocketBuffer::new(rx_buffer), - smoltcp::socket::tcp::SocketBuffer::new(tx_buffer), - ); - - let socket_handle = - self.with_mut(|_interface, _device, sockets| sockets.borrow_mut().add(socket)); - - Socket { - socket_handle, - network: self, - } - } - - /// Create a new [UdpSocket] - #[cfg(feature = "udp")] - pub fn get_udp_socket<'s>( - &'s self, - rx_meta: &'a mut [smoltcp::socket::udp::PacketMetadata], - rx_buffer: &'a mut [u8], - tx_meta: &'a mut [smoltcp::socket::udp::PacketMetadata], - tx_buffer: &'a mut [u8], - ) -> UdpSocket<'s, 'a, MODE> - where - 'a: 's, - { - let socket = smoltcp::socket::udp::Socket::new( - smoltcp::socket::udp::PacketBuffer::new(rx_meta, rx_buffer), - smoltcp::socket::udp::PacketBuffer::new(tx_meta, tx_buffer), - ); - - let socket_handle = - self.with_mut(|_interface, _device, sockets| sockets.borrow_mut().add(socket)); - - UdpSocket { - socket_handle, - network: self, - } - } - - /// Check if DNS is configured - #[cfg(feature = "dns")] - pub fn is_dns_configured(&self) -> bool { - self.dns_socket_handle.borrow().is_some() - } - - /// Configure DNS - #[cfg(feature = "dns")] - pub fn configure_dns( - &'a self, - servers: &[IpAddress], - query_storage: &'a mut [Option], - ) { - if let Some(old_handle) = self.dns_socket_handle.take() { - self.with_mut(|_interface, _device, sockets| sockets.remove(old_handle)); - // the returned socket get dropped and frees a slot for the new one - } - - let dns = smoltcp::socket::dns::Socket::new(servers, query_storage); - let handle = self.with_mut(|_interface, _device, sockets| sockets.add(dns)); - self.dns_socket_handle.replace(Some(handle)); - } - - /// Update the DNS servers - #[cfg(feature = "dns")] - pub fn update_dns_servers(&self, servers: &[IpAddress]) { - if let Some(dns_handle) = *self.dns_socket_handle.borrow_mut() { - self.with_mut(|_interface, _device, sockets| { - sockets - .get_mut::(dns_handle) - .update_servers(servers); - }); - } - } - - /// Perform a DNS query - #[cfg(feature = "dns")] - pub fn dns_query( - &self, - name: &str, - query_type: DnsQueryType, - ) -> Result, WifiStackError> - { - use smoltcp::socket::dns; - - match query_type { - // check if name is already an IP - DnsQueryType::A => { - if let Ok(ip) = name.parse::() { - return Ok([ip.into()].into_iter().collect()); - } - } - #[cfg(feature = "ipv6")] - DnsQueryType::Aaaa => { - if let Ok(ip) = name.parse::() { - return Ok([ip.into()].into_iter().collect()); - } - } - _ => {} - } - - let Some(dns_handle) = *self.dns_socket_handle.borrow() else { - return Err(WifiStackError::DnsNotConfigured); - }; - - let query = self.with_mut(|interface, _device, sockets| { - sockets - .get_mut::(dns_handle) - .start_query(interface.context(), name, query_type) - .map_err(WifiStackError::DnsQueryError) - })?; - - loop { - self.work(); - - let result = self.with_mut(|_interface, _device, sockets| { - sockets - .get_mut::(dns_handle) - .get_query_result(query) - }); - - match result { - Ok(addrs) => return Ok(addrs), // query finished - Err(dns::GetQueryResultError::Pending) => {} // query not finished - Err(_) => return Err(WifiStackError::DnsQueryFailed), - } - } - } - - /// Let the stack make progress - /// - /// Make sure to regularly call this function. - pub fn work(&self) { - loop { - let did_work = self.with_mut(|interface, device, sockets| { - let network_config = self.network_config.borrow().clone(); - if let ipv4::Configuration::Client(ipv4::ClientConfiguration::DHCP(_)) = - network_config - { - #[cfg(feature = "dhcpv4")] - self.poll_dhcp(interface, sockets).ok(); - } else if let ipv4::Configuration::Client(ipv4::ClientConfiguration::Fixed( - settings, - )) = network_config - { - let addr = Ipv4Address::from_bytes(&settings.ip.octets()); - if !interface.has_ip_addr(addr) { - let gateway = Ipv4Address::from_bytes(&settings.subnet.gateway.octets()); - interface.routes_mut().add_default_ipv4_route(gateway).ok(); - interface.update_ip_addrs(|addrs| { - unwrap!(addrs.push(IpCidr::new(addr.into(), settings.subnet.mask.0))); - }); - } - } - interface.poll( - Instant::from_millis((self.current_millis_fn)() as i64), - device, - sockets, - ) - }); - - if !did_work { - break; - } - } - } - - #[cfg(feature = "tcp")] - fn next_local_port(&self) -> u16 { - self.local_port.replace_with(|local_port| { - if *local_port == LOCAL_PORT_MAX { - LOCAL_PORT_MIN - } else { - *local_port + 1 - } - }); - *self.local_port.borrow() - } - - #[allow(unused)] - fn with(&self, f: impl FnOnce(&Interface, &WifiDevice, &SocketSet<'a>) -> R) -> R { - f( - &self.network_interface.borrow(), - &self.device.borrow(), - &self.sockets.borrow(), - ) - } - - fn with_mut( - &self, - f: impl FnOnce(&mut Interface, &mut WifiDevice, &mut SocketSet<'a>) -> R, - ) -> R { - f( - &mut self.network_interface.borrow_mut(), - &mut self.device.borrow_mut(), - &mut self.sockets.borrow_mut(), - ) - } -} - -/// Errors returned by functions in this module -#[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum WifiStackError { - /// An unknown error occurred, with the associated error code. - Unknown(i32), - - /// An error occurred during Wi-Fi stack initialization. - InitializationError(crate::InitializationError), - - /// A common Wi-Fi error occured. - DeviceError(crate::wifi::WifiError), - - /// Couldn't get the device's IP. - MissingIp, - - /// DNS is not configured. - #[cfg(feature = "dns")] - DnsNotConfigured, - - /// An error occurred when starting a DNS query. - #[cfg(feature = "dns")] - DnsQueryError(smoltcp::socket::dns::StartQueryError), - - /// Cannot get result from a DNS query. - #[cfg(feature = "dns")] - DnsQueryFailed, -} - -impl Display for WifiStackError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}", self) - } -} - -impl WifiStack<'_, MODE> { - /// Retrieves the current interface configuration. - pub fn get_iface_configuration(&self) -> Result { - Ok(self.network_config.borrow().clone()) - } - - /// Sets a new interface configuration using the provided IPv4 - /// configuration. - pub fn set_iface_configuration( - &mut self, - conf: &ipv4::Configuration, - ) -> Result<(), WifiStackError> { - self.update_iface_configuration(conf) - } - - /// Checks if the interface is up (has IP information). - pub fn is_iface_up(&self) -> bool { - self.ip_info.borrow().is_some() - } - - /// Retrieves the current IP information (IP address, subnet info). - pub fn get_ip_info(&self) -> Result { - self.ip_info.borrow().ok_or(WifiStackError::MissingIp) - } -} - -/// A TCP socket -#[cfg(feature = "tcp")] -pub struct Socket<'s, 'n: 's, MODE: WifiDeviceMode> { - socket_handle: SocketHandle, - network: &'s WifiStack<'n, MODE>, -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> Socket<'s, 'n, MODE> { - /// Connect the socket - pub fn open<'i>(&'i mut self, addr: IpAddress, port: u16) -> Result<(), IoError> - where - 's: 'i, - { - { - let res = self.network.with_mut(|interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - let cx = interface.context(); - let remote_endpoint = (addr, port); - sock.set_ack_delay(Some(smoltcp::time::Duration::from_millis(100))); - sock.connect(cx, remote_endpoint, self.network.next_local_port()) - }); - - res.map_err(IoError::ConnectError)?; - } - - loop { - let can_send = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.can_send() - }); - - if can_send { - break; - } - - self.work(); - } - - Ok(()) - } - - /// Listen on the given port. This blocks until there is a peer connected - pub fn listen<'i>(&'i mut self, port: u16) -> Result<(), IoError> - where - 's: 'i, - { - { - let res = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.listen(port) - }); - - res.map_err(IoError::ListenError)?; - } - - loop { - let can_send = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.can_send() - }); - - if can_send { - break; - } - - self.work(); - } - - Ok(()) - } - - /// Listen on the given port. This doesn't block - pub fn listen_unblocking<'i>(&'i mut self, port: u16) -> Result<(), IoError> - where - 's: 'i, - { - { - let res = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.listen(port) - }); - - res.map_err(IoError::ListenError)?; - } - - self.work(); - Ok(()) - } - - /// Closes the socket - pub fn close(&mut self) { - self.network.with_mut(|_interface, _device, sockets| { - sockets.get_mut::(self.socket_handle).close(); - }); - - self.work(); - } - - /// Disconnect the socket - pub fn disconnect(&mut self) { - self.network.with_mut(|_interface, _device, sockets| { - sockets.get_mut::(self.socket_handle).abort(); - }); - - self.work(); - } - - /// Checks if the socket is currently open - pub fn is_open(&mut self) -> bool { - self.network.with_mut(|_interface, _device, sockets| { - sockets.get_mut::(self.socket_handle).is_open() - }) - } - - /// Checks if the socket is currently connected - pub fn is_connected(&mut self) -> bool { - self.network.with_mut(|_interface, _device, sockets| { - let socket = sockets.get_mut::(self.socket_handle); - - socket.may_recv() && socket.may_send() - }) - } - - /// Delegates to [WifiStack::work] - pub fn work(&mut self) { - self.network.work() - } -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> Drop for Socket<'s, 'n, MODE> { - fn drop(&mut self) { - self.network - .with_mut(|_interface, _device, sockets| sockets.remove(self.socket_handle)); - } -} - -/// IO Errors -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum IoError { - SocketClosed, - #[cfg(feature = "igmp")] - MultiCastError(smoltcp::iface::MulticastError), - #[cfg(feature = "tcp")] - TcpRecvError, - #[cfg(feature = "udp")] - UdpRecvError(smoltcp::socket::udp::RecvError), - #[cfg(feature = "tcp")] - TcpSendError(smoltcp::socket::tcp::SendError), - #[cfg(feature = "udp")] - UdpSendError(smoltcp::socket::udp::SendError), - #[cfg(feature = "tcp")] - ConnectError(smoltcp::socket::tcp::ConnectError), - #[cfg(feature = "udp")] - BindError(smoltcp::socket::udp::BindError), - #[cfg(feature = "tcp")] - ListenError(smoltcp::socket::tcp::ListenError), -} - -impl embedded_io::Error for IoError { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> embedded_io::ErrorType for Socket<'s, 'n, MODE> { - type Error = IoError; -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> embedded_io::Read for Socket<'s, 'n, MODE> { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.network.with_mut(|interface, device, sockets| { - use smoltcp::socket::tcp::RecvError; - - loop { - interface.poll(timestamp(), device, sockets); - let socket = sockets.get_mut::(self.socket_handle); - - match socket.recv_slice(buf) { - Ok(0) => continue, // no data - Ok(n) => return Ok(n), - Err(RecvError::Finished) => return Err(IoError::SocketClosed), // eof - Err(RecvError::InvalidState) => return Err(IoError::TcpRecvError), - } - } - }) - } -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> embedded_io::ReadReady for Socket<'s, 'n, MODE> { - fn read_ready(&mut self) -> Result { - self.network.with_mut(|interface, device, sockets| { - use smoltcp::socket::tcp::RecvError; - - interface.poll(timestamp(), device, sockets); - let socket = sockets.get_mut::(self.socket_handle); - - match socket.peek(1) { - Ok(s) => Ok(!s.is_empty()), - Err(RecvError::Finished) => Err(IoError::SocketClosed), - Err(RecvError::InvalidState) => Err(IoError::TcpRecvError), - } - }) - } -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> embedded_io::Write for Socket<'s, 'n, MODE> { - fn write(&mut self, buf: &[u8]) -> Result { - loop { - let (may_send, is_open, can_send) = - self.network.with_mut(|interface, device, sockets| { - interface.poll( - Instant::from_millis((self.network.current_millis_fn)() as i64), - device, - sockets, - ); - - let socket = sockets.get_mut::(self.socket_handle); - - (socket.may_send(), socket.is_open(), socket.can_send()) - }); - - if may_send { - break; - } - - if !is_open || !can_send { - return Err(IoError::SocketClosed); - } - } - - let mut written = 0; - loop { - self.flush()?; - - self.network.with_mut(|_interface, _device, sockets| { - sockets - .get_mut::(self.socket_handle) - .send_slice(&buf[written..]) - .map(|len| written += len) - .map_err(IoError::TcpSendError) - })?; - - if written >= buf.len() { - break; - } - } - - Ok(written) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - loop { - let res = self.network.with_mut(|interface, device, sockets| { - interface.poll( - Instant::from_millis((self.network.current_millis_fn)() as i64), - device, - sockets, - ) - }); - - if !res { - break; - } - } - - Ok(()) - } -} - -#[cfg(feature = "tcp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> embedded_io::WriteReady for Socket<'s, 'n, MODE> { - fn write_ready(&mut self) -> Result { - let (may_send, is_open, can_send) = self.network.with_mut(|interface, device, sockets| { - interface.poll( - Instant::from_millis((self.network.current_millis_fn)() as i64), - device, - sockets, - ); - - let socket = sockets.get_mut::(self.socket_handle); - - (socket.may_send(), socket.is_open(), socket.can_send()) - }); - - if !is_open || !can_send { - return Err(IoError::SocketClosed); - } - - Ok(may_send) - } -} - -/// A UDP socket -#[cfg(feature = "udp")] -pub struct UdpSocket<'s, 'n: 's, MODE: WifiDeviceMode> { - socket_handle: SocketHandle, - network: &'s WifiStack<'n, MODE>, -} - -#[cfg(feature = "udp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> UdpSocket<'s, 'n, MODE> { - /// Binds the socket to the given port - pub fn bind<'i>(&'i mut self, port: u16) -> Result<(), IoError> - where - 's: 'i, - { - self.work(); - - { - let res = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.bind(port) - }); - - if let Err(err) = res { - return Err(IoError::BindError(err)); - } - } - - loop { - let can_send = self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - sock.can_send() - }); - - if can_send { - break; - } - - self.work(); - } - - Ok(()) - } - - /// Close the socket - pub fn close(&mut self) { - self.network.with_mut(|_interface, _device, sockets| { - sockets - .get_mut::(self.socket_handle) - .close(); - }); - - self.work(); - } - - /// Sends data on the socket to the given address - pub fn send(&mut self, addr: IpAddress, port: u16, data: &[u8]) -> Result<(), IoError> { - loop { - self.work(); - - let (can_send, packet_capacity, payload_capacity) = - self.network.with_mut(|_interface, _device, sockets| { - let sock = sockets.get_mut::(self.socket_handle); - ( - sock.can_send(), - sock.packet_send_capacity(), - sock.payload_send_capacity(), - ) - }); - - if can_send && packet_capacity > 0 && payload_capacity > data.len() { - break; - } - } - - self.network - .with_mut(|_interface, _device, sockets| { - let endpoint = (addr, port); - let endpoint: IpEndpoint = endpoint.into(); - - sockets - .get_mut::(self.socket_handle) - .send_slice(data, endpoint) - }) - .map_err(IoError::UdpSendError)?; - - self.work(); - - Ok(()) - } - - /// Receives a single datagram message on the socket - pub fn receive(&mut self, data: &mut [u8]) -> Result<(usize, IpAddress, u16), IoError> { - self.work(); - - let res = self.network.with_mut(|_interface, _device, sockets| { - sockets - .get_mut::(self.socket_handle) - .recv_slice(data) - }); - - match res { - Ok((len, endpoint)) => { - let addr = endpoint.endpoint.addr; - Ok((len, addr, endpoint.endpoint.port)) - } - Err(e) => Err(IoError::UdpRecvError(e)), - } - } - - /// This function specifies a new multicast group for this socket to join - #[cfg(feature = "igmp")] - pub fn join_multicast_group(&mut self, addr: IpAddress) -> Result { - self.work(); - - let res = self.network.with_mut(|interface, device, _| { - interface.join_multicast_group( - device, - addr, - Instant::from_millis((self.network.current_millis_fn)() as i64), - ) - }); - - self.work(); - - res.map_err(IoError::MultiCastError) - } - - /// Delegates to [WifiStack::work] - pub fn work(&mut self) { - self.network.work() - } -} - -#[cfg(feature = "udp")] -impl<'s, 'n: 's, MODE: WifiDeviceMode> Drop for UdpSocket<'s, 'n, MODE> { - fn drop(&mut self) { - self.network - .with_mut(|_, _, sockets| sockets.borrow_mut().remove(self.socket_handle)); - } -} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index c9af3773735..d8751a2f2aa 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,6 +8,7 @@ publish = false [dependencies] aligned = { version = "0.4.2", optional = true } bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [ "macros", "async"] } +blocking-network-stack = { git = "https://github.com/bjoernQ/blocking-network-stack.git", rev = "1c581661d78e0cf0f17b936297179b993fb149d7" } bt-hci = "0.1.1" cfg-if = "1.0.0" critical-section = "1.1.3" @@ -42,6 +43,8 @@ nb = "1.1.0" portable-atomic = { version = "1.9.0", default-features = false } sha2 = { version = "0.10.8", default-features = false } smoltcp = { version = "0.11.0", default-features = false, features = [ "medium-ethernet", "socket-raw"] } +smoltcp-nal = "0.5.1" +embedded-time = "=0.12.1" ssd1306 = "0.8.4" static_cell = { version = "2.1.0", features = ["nightly"] } trouble-host = { git = "https://github.com/embassy-rs/trouble", package = "trouble-host", rev = "4f1114ce58e96fe54f5ed7e726f66e1ad8d9ce54", features = [ "log", "gatt" ] } diff --git a/examples/src/bin/wifi_80211_tx.rs b/examples/src/bin/wifi_80211_tx.rs index 3b33456fd09..d05782790de 100644 --- a/examples/src/bin/wifi_80211_tx.rs +++ b/examples/src/bin/wifi_80211_tx.rs @@ -3,7 +3,7 @@ //! Periodically transmits a beacon frame. //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index 94c5b182105..8a5c1387bdd 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -8,12 +8,13 @@ //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -32,9 +33,8 @@ use esp_wifi::{ Configuration, WifiApDevice, }, - wifi_interface::WifiStack, }; -use smoltcp::iface::SocketStorage; +use smoltcp::iface::{SocketSet, SocketStorage}; #[entry] fn main() -> ! { @@ -49,19 +49,18 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); + + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; - let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiApDevice, &mut socket_set_entries).unwrap(); + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiApDevice).unwrap(); let now = || time::now().duration_since_epoch().to_millis(); - let mut wifi_stack = WifiStack::new(iface, device, sockets, now); + + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let socket_set = SocketSet::new(&mut socket_set_entries[..]); + let mut stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::AccessPoint(AccessPointConfiguration { ssid: "esp-wifi".try_into().unwrap(), @@ -75,14 +74,16 @@ fn main() -> ! { println!("{:?}", controller.get_capabilities()); - wifi_stack - .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( - esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( - esp_wifi::wifi::ipv4::ClientSettings { - ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - subnet: esp_wifi::wifi::ipv4::Subnet { - gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - mask: esp_wifi::wifi::ipv4::Mask(24), + stack + .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( + blocking_network_stack::ipv4::ClientConfiguration::Fixed( + blocking_network_stack::ipv4::ClientSettings { + ip: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: blocking_network_stack::ipv4::Subnet { + gateway: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip( + "192.168.2.1", + )), + mask: blocking_network_stack::ipv4::Mask(24), }, dns: None, secondary_dns: None, @@ -96,7 +97,7 @@ fn main() -> ! { let mut rx_buffer = [0u8; 1536]; let mut tx_buffer = [0u8; 1536]; - let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); socket.listen(8080).unwrap(); diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index f9c3e0792e5..74ce52e5b0c 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -9,12 +9,13 @@ //! On Android you might need to choose _Keep Accesspoint_ when it tells you the WiFi has no internet connection, Chrome might not want to load the URL - you can use a shell and try `curl` and `ping` //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -33,10 +34,9 @@ use esp_wifi::{ ClientConfiguration, Configuration, }, - wifi_interface::WifiStack, }; use smoltcp::{ - iface::SocketStorage, + iface::{SocketSet, SocketStorage}, wire::{IpAddress, Ipv4Address}, }; @@ -56,17 +56,11 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); - let wifi = peripherals.WIFI; + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); - let mut ap_socket_set_entries: [SocketStorage; 3] = Default::default(); - let mut sta_socket_set_entries: [SocketStorage; 3] = Default::default(); + let wifi = peripherals.WIFI; let ApStaInterface { ap_interface, @@ -74,19 +68,17 @@ fn main() -> ! { ap_device, sta_device, mut controller, - ap_socket_set, - sta_socket_set, - } = create_ap_sta_network_interface( - &init, - wifi, - &mut ap_socket_set_entries, - &mut sta_socket_set_entries, - ) - .unwrap(); + } = create_ap_sta_network_interface(&init, wifi).unwrap(); let now = || time::now().duration_since_epoch().to_millis(); - let mut wifi_ap_stack = WifiStack::new(ap_interface, ap_device, ap_socket_set, now); - let wifi_sta_stack = WifiStack::new(sta_interface, sta_device, sta_socket_set, now); + let mut ap_socket_set_entries: [SocketStorage; 3] = Default::default(); + let ap_socket_set = SocketSet::new(&mut ap_socket_set_entries[..]); + let mut ap_stack = Stack::new(ap_interface, ap_device, ap_socket_set, now, rng.random()); + + let mut sta_socket_set_entries: [SocketStorage; 3] = Default::default(); + let mut sta_socket_set = SocketSet::new(&mut sta_socket_set_entries[..]); + sta_socket_set.add(smoltcp::socket::dhcpv4::Socket::new()); + let sta_stack = Stack::new(sta_interface, sta_device, sta_socket_set, now, rng.random()); let client_config = Configuration::Mixed( ClientConfiguration { @@ -107,14 +99,16 @@ fn main() -> ! { println!("{:?}", controller.get_capabilities()); - wifi_ap_stack - .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( - esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( - esp_wifi::wifi::ipv4::ClientSettings { - ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - subnet: esp_wifi::wifi::ipv4::Subnet { - gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), - mask: esp_wifi::wifi::ipv4::Mask(24), + ap_stack + .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( + blocking_network_stack::ipv4::ClientConfiguration::Fixed( + blocking_network_stack::ipv4::ClientSettings { + ip: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip("192.168.2.1")), + subnet: blocking_network_stack::ipv4::Subnet { + gateway: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip( + "192.168.2.1", + )), + mask: blocking_network_stack::ipv4::Mask(24), }, dns: None, secondary_dns: None, @@ -128,10 +122,10 @@ fn main() -> ! { // wait for STA getting an ip address println!("Wait to get an ip address"); loop { - wifi_sta_stack.work(); + sta_stack.work(); - if wifi_sta_stack.is_iface_up() { - println!("got ip {:?}", wifi_sta_stack.get_ip_info()); + if sta_stack.is_iface_up() { + println!("got ip {:?}", sta_stack.get_ip_info()); break; } } @@ -141,11 +135,11 @@ fn main() -> ! { let mut rx_buffer = [0u8; 1536]; let mut tx_buffer = [0u8; 1536]; - let mut ap_socket = wifi_ap_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut ap_socket = ap_stack.get_socket(&mut rx_buffer, &mut tx_buffer); let mut sta_rx_buffer = [0u8; 1536]; let mut sta_tx_buffer = [0u8; 1536]; - let mut sta_socket = wifi_sta_stack.get_socket(&mut sta_rx_buffer, &mut sta_tx_buffer); + let mut sta_socket = sta_stack.get_socket(&mut sta_rx_buffer, &mut sta_tx_buffer); ap_socket.listen(8080).unwrap(); diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index 511773ee705..1efd7800af1 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -8,12 +8,13 @@ //! Ensure you have set the IP of your local machine in the `HOST_IP` env variable. E.g `HOST_IP="192.168.0.24"` and also set SSID and PASSWORD env variable before running this example. //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -35,11 +36,10 @@ use esp_wifi::{ WifiError, WifiStaDevice, }, - wifi_interface::WifiStack, }; use smoltcp::{ - iface::SocketStorage, - wire::{IpAddress, Ipv4Address}, + iface::{SocketSet, SocketStorage}, + wire::{DhcpOption, IpAddress, Ipv4Address}, }; const SSID: &str = env!("SSID"); @@ -69,19 +69,26 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); + + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); + let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); + // we can set a hostname here (or add other DHCP options) + dhcp_socket.set_outgoing_options(&[DhcpOption { + kind: 12, + data: b"esp-wifi", + }]); + socket_set.add(dhcp_socket); + let now = || time::now().duration_since_epoch().to_millis(); - let wifi_stack = WifiStack::new(iface, device, sockets, now); + let stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), @@ -122,17 +129,17 @@ fn main() -> ! { // wait for getting an ip address println!("Wait to get an ip address"); loop { - wifi_stack.work(); + stack.work(); - if wifi_stack.is_iface_up() { - println!("got ip {:?}", wifi_stack.get_ip_info()); + if stack.is_iface_up() { + println!("got ip {:?}", stack.get_ip_info()); break; } } let mut rx_buffer = [0u8; RX_BUFFER_SIZE]; let mut tx_buffer = [0u8; TX_BUFFER_SIZE]; - let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); let delay = Delay::new(); @@ -149,9 +156,9 @@ fn main() -> ! { } } -fn test_download<'a>( +fn test_download<'a, D: smoltcp::phy::Device>( server_address: Ipv4Address, - socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>, + socket: &mut blocking_network_stack::Socket<'a, 'a, D>, ) { println!("Testing download..."); socket.work(); @@ -183,9 +190,9 @@ fn test_download<'a>( socket.disconnect(); } -fn test_upload<'a>( +fn test_upload<'a, D: smoltcp::phy::Device>( server_address: Ipv4Address, - socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>, + socket: &mut blocking_network_stack::Socket<'a, 'a, D>, ) { println!("Testing upload..."); socket.work(); @@ -217,9 +224,9 @@ fn test_upload<'a>( socket.disconnect(); } -fn test_upload_download<'a>( +fn test_upload_download<'a, D: smoltcp::phy::Device>( server_address: Ipv4Address, - socket: &mut esp_wifi::wifi_interface::Socket<'a, 'a, WifiStaDevice>, + socket: &mut blocking_network_stack::Socket<'a, 'a, D>, ) { println!("Testing upload+download..."); socket.work(); diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index 002ea35e8f3..2c7b936d84e 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -8,7 +8,7 @@ //! Note: On ESP32-C2 and ESP32-C3 you need a wifi-heap size of 70000, on ESP32-C6 you need 80000 and a tx_queue_size of 10 //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/ble esp-wifi/coex +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/ble esp-wifi/coex //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![allow(static_mut_refs)] @@ -26,6 +26,7 @@ use bleps::{ Ble, HciConnector, }; +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -40,11 +41,10 @@ use esp_wifi::{ ble::controller::BleConnector, init, wifi::{utils::create_network_interface, ClientConfiguration, Configuration, WifiStaDevice}, - wifi_interface::WifiStack, }; use smoltcp::{ - iface::SocketStorage, - wire::{IpAddress, Ipv4Address}, + iface::{SocketSet, SocketStorage}, + wire::{DhcpOption, IpAddress, Ipv4Address}, }; const SSID: &str = env!("SSID"); @@ -81,22 +81,28 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); + + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; let bluetooth = peripherals.BT; - let mut socket_set_entries: [SocketStorage; 2] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); + let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); + // we can set a hostname here (or add other DHCP options) + dhcp_socket.set_outgoing_options(&[DhcpOption { + kind: 12, + data: b"esp-wifi", + }]); + socket_set.add(dhcp_socket); let now = || time::now().duration_since_epoch().to_millis(); - let wifi_stack = WifiStack::new(iface, device, sockets, now); + let stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), @@ -128,10 +134,10 @@ fn main() -> ! { // wait for getting an ip address println!("Wait to get an ip address"); loop { - wifi_stack.work(); + stack.work(); - if wifi_stack.is_iface_up() { - println!("got ip {:?}", wifi_stack.get_ip_info()); + if stack.is_iface_up() { + println!("got ip {:?}", stack.get_ip_info()); break; } } @@ -161,7 +167,7 @@ fn main() -> ! { let mut rx_buffer = [0u8; 128]; let mut tx_buffer = [0u8; 128]; - let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); loop { println!("Making HTTP request"); diff --git a/examples/src/bin/wifi_csi.rs b/examples/src/bin/wifi_csi.rs index e330c3d6cf8..eca2d392bfc 100644 --- a/examples/src/bin/wifi_csi.rs +++ b/examples/src/bin/wifi_csi.rs @@ -4,7 +4,7 @@ //! Set SSID and PASSWORD env variable before running this example. //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/log +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/log //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -12,6 +12,7 @@ extern crate alloc; +use blocking_network_stack::Stack; use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ @@ -32,10 +33,11 @@ use esp_wifi::{ WifiError, WifiStaDevice, }, - wifi_interface::WifiStack, - // EspWifiInitFor, }; -use smoltcp::iface::SocketStorage; +use smoltcp::{ + iface::{SocketSet, SocketStorage}, + wire::DhcpOption, +}; const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); @@ -51,20 +53,27 @@ fn main() -> ! { esp_alloc::heap_allocator!(72 * 1024); + let mut rng = Rng::new(peripherals.RNG); + let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); + let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); + // we can set a hostname here (or add other DHCP options) + dhcp_socket.set_outgoing_options(&[DhcpOption { + kind: 12, + data: b"esp-wifi", + }]); + socket_set.add(dhcp_socket); + let now = || time::now().duration_since_epoch().to_millis(); - let wifi_stack = WifiStack::new(iface, device, sockets, now); + let stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), @@ -120,10 +129,10 @@ fn main() -> ! { // wait for getting an ip address println!("Wait to get an ip address"); loop { - wifi_stack.work(); + stack.work(); - if wifi_stack.is_iface_up() { - println!("got ip {:?}", wifi_stack.get_ip_info()); + if stack.is_iface_up() { + println!("got ip {:?}", stack.get_ip_info()); break; } } diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index fd756e4478c..020fe6303e9 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -6,7 +6,7 @@ //! This gets an ip address via DHCP then performs an HTTP get request to some "random" server //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -14,6 +14,7 @@ extern crate alloc; +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -34,11 +35,10 @@ use esp_wifi::{ WifiError, WifiStaDevice, }, - wifi_interface::WifiStack, }; use smoltcp::{ - iface::SocketStorage, - wire::{IpAddress, Ipv4Address}, + iface::{SocketSet, SocketStorage}, + wire::{DhcpOption, IpAddress, Ipv4Address}, }; const SSID: &str = env!("SSID"); @@ -57,19 +57,26 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); + + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let mut socket_set = SocketSet::new(&mut socket_set_entries[..]); + let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); + // we can set a hostname here (or add other DHCP options) + dhcp_socket.set_outgoing_options(&[DhcpOption { + kind: 12, + data: b"esp-wifi", + }]); + socket_set.add(dhcp_socket); + let now = || time::now().duration_since_epoch().to_millis(); - let wifi_stack = WifiStack::new(iface, device, sockets, now); + let stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), @@ -110,10 +117,10 @@ fn main() -> ! { // wait for getting an ip address println!("Wait to get an ip address"); loop { - wifi_stack.work(); + stack.work(); - if wifi_stack.is_iface_up() { - println!("got ip {:?}", wifi_stack.get_ip_info()); + if stack.is_iface_up() { + println!("got ip {:?}", stack.get_ip_info()); break; } } @@ -122,7 +129,7 @@ fn main() -> ! { let mut rx_buffer = [0u8; 1536]; let mut tx_buffer = [0u8; 1536]; - let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); loop { println!("Making HTTP request"); diff --git a/examples/src/bin/wifi_dhcp_smoltcp_nal.rs b/examples/src/bin/wifi_dhcp_smoltcp_nal.rs new file mode 100644 index 00000000000..118f74b9ab1 --- /dev/null +++ b/examples/src/bin/wifi_dhcp_smoltcp_nal.rs @@ -0,0 +1,224 @@ +//! DHCP Example using [smoltcp-nal](https://crates.io/crates/smoltcp-nal) +//! +//! +//! Set SSID and PASSWORD env variable before running this example. +//! +//! This gets an ip address via DHCP then performs an HTTP get request to some "random" server +//! When using USB-SERIAL-JTAG you may have to activate the feature `phy-enable-usb` in the esp-wifi crate. + +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 + +#![no_std] +#![no_main] + +extern crate alloc; + +use esp_alloc as _; +use esp_backtrace as _; +use esp_hal::{ + prelude::*, + rng::Rng, + time::{self, Duration}, + timer::timg::TimerGroup, +}; +use esp_println::{print, println}; +use esp_wifi::{ + init, + wifi::{ + utils::create_network_interface, + AccessPointInfo, + ClientConfiguration, + Configuration, + WifiError, + WifiStaDevice, + }, +}; +use smoltcp::{ + iface::{SocketSet, SocketStorage}, + wire::DhcpOption, +}; +use smoltcp_nal::{ + embedded_nal::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpClientStack}, + NetworkStack, +}; + +const SSID: &str = env!("SSID"); +const PASSWORD: &str = env!("PASSWORD"); + +#[entry] +fn main() -> ! { + esp_println::logger::init_logger_from_env(); + let peripherals = esp_hal::init({ + let mut config = esp_hal::Config::default(); + config.cpu_clock = CpuClock::max(); + config + }); + + esp_alloc::heap_allocator!(72 * 1024); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + + let init = init( + timg0.timer0, + Rng::new(peripherals.RNG), + peripherals.RADIO_CLK, + ) + .unwrap(); + + let mut wifi = peripherals.WIFI; + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let mut sockets = SocketSet::new(&mut socket_set_entries[..]); + + let mut rx_buffer = [0u8; 128]; + let mut tx_buffer = [0u8; 128]; + sockets.add(smoltcp::socket::tcp::Socket::new( + smoltcp::socket::tcp::SocketBuffer::new(&mut rx_buffer[..]), + smoltcp::socket::tcp::SocketBuffer::new(&mut tx_buffer[..]), + )); + let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); + // we can set a hostname here (or add other DHCP options) + dhcp_socket.set_outgoing_options(&[DhcpOption { + kind: 12, + data: b"esp-wifi", + }]); + sockets.add(dhcp_socket); + let mut network_stack = NetworkStack::new(iface, device, sockets, StackClock); + + let client_config = Configuration::Client(ClientConfiguration { + ssid: SSID.try_into().unwrap(), + password: PASSWORD.try_into().unwrap(), + ..Default::default() + }); + let res = controller.set_configuration(&client_config); + println!("wifi_set_configuration returned {:?}", res); + + controller.start().unwrap(); + println!("is wifi started: {:?}", controller.is_started()); + + println!("Start Wifi Scan"); + let res: Result<(heapless::Vec, usize), WifiError> = controller.scan_n(); + if let Ok((res, _count)) = res { + for ap in res { + println!("{:?}", ap); + } + } + + println!("{:?}", controller.get_capabilities()); + println!("wifi_connect {:?}", controller.connect()); + + // wait to get connected + println!("Wait to get connected"); + loop { + match controller.is_connected() { + Ok(true) => break, + Ok(false) => {} + Err(err) => { + println!("{:?}", err); + loop {} + } + } + } + println!("{:?}", controller.is_connected()); + + // wait for getting an ip address + println!("Wait to get an ip address"); + loop { + network_stack.poll().unwrap(); + + if let Some(ip) = network_stack.interface().ipv4_addr() { + if !ip.is_unspecified() { + println!("got ip {:?}", ip); + break; + } + } + } + + println!("Start busy loop on main"); + + let mut socket = network_stack.socket().unwrap(); + + loop { + println!("Making HTTP request"); + while network_stack.poll().unwrap() {} + + with_network_stack(&mut network_stack, |network_stack| { + network_stack.connect( + &mut socket, + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(142, 250, 185, 115), 80)), + ) + }) + .unwrap(); + + println!("connected"); + + with_network_stack(&mut network_stack, |network_stack| { + network_stack.send( + &mut socket, + b"GET / HTTP/1.0\r\nHost: www.mobile-j.de\r\n\r\n", + ) + }) + .unwrap(); + + let deadline = time::now() + Duration::secs(20); + let mut buffer = [0u8; 512]; + while let Ok(len) = with_network_stack(&mut network_stack, |network_stack| { + network_stack.receive(&mut socket, &mut buffer) + }) { + let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..len]) }; + print!("{}", to_print); + + if time::now() > deadline { + println!("Timeout"); + break; + } + + network_stack.poll().unwrap(); + } + println!(); + + network_stack.close_sockets(); + + let deadline = time::now() + Duration::secs(5); + while time::now() < deadline { + network_stack.poll().unwrap(); + } + } +} + +fn with_network_stack<'a, D: smoltcp::phy::Device, C: embedded_time::Clock, R>( + network_stack: &mut smoltcp_nal::NetworkStack<'a, D, C>, + mut f: impl FnMut( + &mut smoltcp_nal::NetworkStack<'a, D, C>, + ) -> smoltcp_nal::embedded_nal::nb::Result, +) -> smoltcp_nal::embedded_nal::nb::Result { + let res = loop { + let res = f(network_stack); + if let nb::Result::Err(nb::Error::WouldBlock) = res { + network_stack.poll().unwrap(); + continue; + } + + break res; + }; + + res +} + +struct StackClock; + +impl embedded_time::Clock for StackClock { + type T = u32; + + const SCALING_FACTOR: embedded_time::rate::Fraction = + embedded_time::rate::Fraction::new(1, 1_000_000); + + fn try_now(&self) -> Result, embedded_time::clock::Error> { + Ok(embedded_time::Instant::new( + esp_hal::time::now().ticks() as u32 + )) + } +} diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index ca86dc2d078..5ade028bb1b 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -9,7 +9,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 6ce2d859052..fe0e2e956e7 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -12,7 +12,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index d33289a4218..9b3ecd8ca4c 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -10,7 +10,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 and ESP32-C2 //! -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 #![allow(static_mut_refs)] diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 67bea7f3ada..5adc1838bc7 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -7,7 +7,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index 3828ec9a9e8..3476734f45c 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 600aca964c9..7b2e6cdf27f 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_esp_now.rs b/examples/src/bin/wifi_esp_now.rs index 0b3a268dba2..974f19987ff 100644 --- a/examples/src/bin/wifi_esp_now.rs +++ b/examples/src/bin/wifi_esp_now.rs @@ -2,7 +2,7 @@ //! //! Broadcasts, receives and sends messages via esp-now -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 69256e326bc..d6c26840c88 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -3,7 +3,7 @@ //! Sniffs for beacon frames. //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index af7f14d2674..1d7958c6c7b 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -7,12 +7,13 @@ //! - responds with some HTML content when connecting to port 8080 //! -//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: esp-wifi esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] +use blocking_network_stack::Stack; use embedded_io::*; use esp_alloc as _; use esp_backtrace as _; @@ -33,9 +34,8 @@ use esp_wifi::{ WifiError, WifiStaDevice, }, - wifi_interface::WifiStack, }; -use smoltcp::iface::SocketStorage; +use smoltcp::iface::{SocketSet, SocketStorage}; const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); @@ -55,20 +55,19 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); - let init = init( - timg0.timer0, - Rng::new(peripherals.RNG), - peripherals.RADIO_CLK, - ) - .unwrap(); + let mut rng = Rng::new(peripherals.RNG); + + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); let mut wifi = peripherals.WIFI; + let (iface, device, mut controller) = + create_network_interface(&init, &mut wifi, WifiStaDevice).unwrap(); + let mut socket_set_entries: [SocketStorage; 3] = Default::default(); - let (iface, device, mut controller, sockets) = - create_network_interface(&init, &mut wifi, WifiStaDevice, &mut socket_set_entries).unwrap(); + let socket_set = SocketSet::new(&mut socket_set_entries[..]); let now = || time::now().duration_since_epoch().to_millis(); - let mut wifi_stack = WifiStack::new(iface, device, sockets, now); + let mut stack = Stack::new(iface, device, socket_set, now, rng.random()); let client_config = Configuration::Client(ClientConfiguration { ssid: SSID.try_into().unwrap(), @@ -108,14 +107,14 @@ fn main() -> ! { println!("Setting static IP {}", STATIC_IP); - wifi_stack - .set_iface_configuration(&esp_wifi::wifi::ipv4::Configuration::Client( - esp_wifi::wifi::ipv4::ClientConfiguration::Fixed( - esp_wifi::wifi::ipv4::ClientSettings { - ip: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), - subnet: esp_wifi::wifi::ipv4::Subnet { - gateway: esp_wifi::wifi::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), - mask: esp_wifi::wifi::ipv4::Mask(24), + stack + .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( + blocking_network_stack::ipv4::ClientConfiguration::Fixed( + blocking_network_stack::ipv4::ClientSettings { + ip: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip(STATIC_IP)), + subnet: blocking_network_stack::ipv4::Subnet { + gateway: blocking_network_stack::ipv4::Ipv4Addr::from(parse_ip(GATEWAY_IP)), + mask: blocking_network_stack::ipv4::Mask(24), }, dns: None, secondary_dns: None, @@ -131,7 +130,7 @@ fn main() -> ! { let mut rx_buffer = [0u8; 1536]; let mut tx_buffer = [0u8; 1536]; - let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); + let mut socket = stack.get_socket(&mut rx_buffer, &mut tx_buffer); socket.listen(8080).unwrap(); diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index c807586a4a9..a7d72b76cfd 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -159,11 +159,11 @@ fn apply_feature_rules(package: &Package, config: &Config) -> Vec { let mut features = vec![]; if config.contains("wifi") { features.push("wifi".to_owned()); - features.push("wifi-default".to_owned()); features.push("esp-now".to_owned()); features.push("sniffer".to_owned()); features.push("utils".to_owned()); - features.push("embassy-net".to_owned()); + features.push("smoltcp/proto-ipv4".to_owned()); + features.push("smoltcp/proto-ipv6".to_owned()); } if config.contains("ble") { features.push("ble".to_owned()); @@ -171,7 +171,6 @@ fn apply_feature_rules(package: &Package, config: &Config) -> Vec { if config.contains("wifi") && config.contains("ble") { features.push("coex".to_owned()); } - features.push("async".to_owned()); features } _ => vec![], diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 9a4488c6dab..a1c1e18e61e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -700,7 +700,7 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> { let mut features = format!("--features={chip},defmt,sys-logs"); if device.contains("wifi") { - features.push_str(",wifi-default,esp-now,sniffer") + features.push_str(",esp-now,sniffer") } if device.contains("bt") { features.push_str(",ble") From 5d9cc1a588be3e90c48d40c32ecd846b1e83ffcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 12 Nov 2024 13:18:16 +0100 Subject: [PATCH 57/67] Add ESP32-S2 alternate functions (#2512) --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/soc/esp32s2/peripherals.rs | 40 +++++++++++++------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 18a821fb17e..1552624a25b 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `slave::Spi::{with_mosi(), with_miso(), with_sclk(), with_cs()}` functions (#2485) - I8080: Added `set_8bits_order()` to set the byte order in 8-bit mode (#2487) - `I2c::{apply_config(), with_sda(), with_scl()}` (#2477) +- ESP32-S2: Added missing GPIO alternate functions (#2512) ### Changed diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs index 81f67a9e5f0..fc0cf5917fd 100644 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ b/esp-hal/src/soc/esp32s2/peripherals.rs @@ -79,19 +79,19 @@ crate::peripherals! { (5, [Input, Output, Analog, RtcIo]) (6, [Input, Output, Analog, RtcIo]) (7, [Input, Output, Analog, RtcIo]) - (8, [Input, Output, Analog, RtcIo]) - (9, [Input, Output, Analog, RtcIo]) - (10, [Input, Output, Analog, RtcIo]) - (11, [Input, Output, Analog, RtcIo]) - (12, [Input, Output, Analog, RtcIo]) - (13, [Input, Output, Analog, RtcIo]) - (14, [Input, Output, Analog, RtcIo]) - (15, [Input, Output, Analog, RtcIo]) - (16, [Input, Output, Analog, RtcIo]) - (17, [Input, Output, Analog, RtcIo]) - (18, [Input, Output, Analog, RtcIo]) - (19, [Input, Output, Analog, RtcIo]) - (20, [Input, Output, Analog, RtcIo]) + (8, [Input, Output, Analog, RtcIo] ( ) ( 3 => SUBSPICS1 )) + (9, [Input, Output, Analog, RtcIo] ( 3 => SUBSPIHD 4 => FSPIHD ) ( 3 => SUBSPIHD 4 => FSPIHD )) + (10, [Input, Output, Analog, RtcIo] (2 => FSPIIO4 4 => FSPICS0) (2 => FSPIIO4 3 => SUBSPICS0 4 => FSPICS0)) + (11, [Input, Output, Analog, RtcIo] (2 => FSPIIO5 3 => SUBSPID 4 => FSPID ) (2 => FSPIIO5 3 => SUBSPID 4 => FSPID )) + (12, [Input, Output, Analog, RtcIo] (2 => FSPIIO6 4 => FSPICLK) (2 => FSPIIO6 3 => SUBSPICLK 4 => FSPICLK)) + (13, [Input, Output, Analog, RtcIo] (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ ) (2 => FSPIIO7 3 => SUBSPIQ 4 => FSPIQ )) + (14, [Input, Output, Analog, RtcIo] ( 3 => SUBSPIWP 4 => FSPIWP ) (2 => FSPIDQS 3 => SUBSPIWP 4 => FSPIWP )) + (15, [Input, Output, Analog, RtcIo] ( ) (2 => U0RTS)) + (16, [Input, Output, Analog, RtcIo] (2 => U0CTS) ( )) + (17, [Input, Output, Analog, RtcIo] ( ) (2 => U1TXD)) + (18, [Input, Output, Analog, RtcIo] (2 => U1RXD) ( )) + (19, [Input, Output, Analog, RtcIo] ( ) (2 => U1RTS)) + (20, [Input, Output, Analog, RtcIo] (2 => U1CTS) ( )) (21, [Input, Output, Analog, RtcIo]) (26, [Input, Output]) @@ -101,13 +101,13 @@ crate::peripherals! { (30, [Input, Output]) (31, [Input, Output]) (32, [Input, Output]) - (33, [Input, Output]) - (34, [Input, Output]) - (35, [Input, Output]) - (36, [Input, Output]) - (37, [Input, Output]) - (38, [Input, Output]) - (39, [Input, Output]) + (33, [Input, Output] (2 => FSPIHD 3 => SUBSPIHD ) (2 => FSPIHD 3 => SUBSPIHD )) + (34, [Input, Output] (2 => FSPICS0 ) (2 => FSPICS0 3 => SUBSPICS0 )) + (35, [Input, Output] (2 => FSPID 3 => SUBSPID ) (2 => FSPID 3 => SUBSPID )) + (36, [Input, Output] (2 => FSPICLK ) (2 => FSPICLK 3 => SUBSPICLK )) + (37, [Input, Output] (2 => FSPIQ 3 => SUBSPIQ 4 => SPIDQS) (2 => FSPIQ 3 => SUBSPIQ 4 => SPIDQS)) + (38, [Input, Output] (2 => FSPIWP 3 => SUBSPIWP ) (2 => FSPIWP 3 => SUBSPIWP )) + (39, [Input, Output] ( ) ( 3 => SUBSPICS1 )) (40, [Input, Output]) (41, [Input, Output]) (42, [Input, Output]) From 0b452f7933eecc102ef6068ad582eeaaeed2153c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 13 Nov 2024 09:11:01 +0100 Subject: [PATCH 58/67] C6/H2 Make higher LEDC frequencies work (#2520) * ESP32-C6/H2: Make higher LEDC frequencies work * FMT * CHANGELOG.md --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/ledc/channel.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 1552624a25b..d11e2fc515d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -72,6 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed some SysTimer race conditions and panics (#2451) - TWAI: accept all messages by default (#2467) - I8080: `set_byte_order()` now works correctly in 16-bit mode (#2487) +- ESP32-C6/ESP32-H2: Make higher LEDC frequencies work (#2520) ### Removed diff --git a/esp-hal/src/ledc/channel.rs b/esp-hal/src/ledc/channel.rs index 67b43e3f289..fb7f6448c08 100644 --- a/esp-hal/src/ledc/channel.rs +++ b/esp-hal/src/ledc/channel.rs @@ -369,6 +369,13 @@ impl Channel<'_, S> { unsafe { w.timer_sel().bits(timer_number) } }); } + + // this is needed to make low duty-resolutions / high frequencies work + #[cfg(any(esp32h2, esp32c6))] + self.ledc + .ch_gamma_wr_addr(self.number as usize) + .write(|w| unsafe { w.bits(0) }); + self.start_duty_without_fading(); } From 456bcfb7c6d8e7799df607313d592bdeac765bcd Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Wed, 13 Nov 2024 08:26:18 +0000 Subject: [PATCH 59/67] Remove redundant Enable trait (#2523) Co-authored-by: Dominic Fischer --- esp-hal/src/timer/timg.rs | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 40be2cd2bf8..d51eec9e25e 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -81,7 +81,7 @@ use crate::{ peripherals::{timg0::RegisterBlock, Interrupt, TIMG0}, private::Sealed, sync::{lock, Lock}, - system::{Peripheral as PeripheralEnable, PeripheralClockControl}, + system::PeripheralClockControl, Async, Blocking, InterruptConfigurable, @@ -152,7 +152,7 @@ impl TimerGroupInstance for TIMG0 { } fn enable_peripheral() { - crate::system::PeripheralClockControl::enable(crate::system::Peripheral::Timg0) + PeripheralClockControl::enable(crate::system::Peripheral::Timg0) } fn reset_peripheral() { @@ -215,11 +215,11 @@ impl TimerGroupInstance for crate::peripherals::TIMG1 { } fn enable_peripheral() { - crate::system::PeripheralClockControl::enable(crate::system::Peripheral::Timg1) + PeripheralClockControl::enable(crate::system::Peripheral::Timg1) } fn reset_peripheral() { - crate::system::PeripheralClockControl::reset(crate::system::Peripheral::Timg1) + PeripheralClockControl::reset(crate::system::Peripheral::Timg1) } fn configure_wdt_src_clk() { @@ -377,7 +377,6 @@ where { /// Construct a new instance of [`Timer`] pub fn new(timg: T, apb_clk_freq: HertzU32) -> Self { - timg.enable_peripheral(); timg.set_counter_active(true); Self { @@ -599,7 +598,7 @@ where } #[doc(hidden)] -pub trait Instance: Sealed + Enable { +pub trait Instance: Sealed { fn register_block(&self) -> &RegisterBlock; fn timer_group(&self) -> u8; @@ -637,11 +636,6 @@ pub trait Instance: Sealed + Enable { fn is_interrupt_set(&self) -> bool; } -#[doc(hidden)] -pub trait Enable: Sealed { - fn enable_peripheral(&self); -} - /// A timer within a Timer Group. pub struct TimerX { phantom: PhantomData, @@ -674,7 +668,6 @@ where impl Instance for TimerX where TG: TimerGroupInstance, - Self: Enable, { fn register_block(&self) -> &RegisterBlock { unsafe { &*TG::register_block() } @@ -815,25 +808,6 @@ pub type Timer0 = TimerX; #[cfg(timg_timer1)] pub type Timer1 = TimerX; -impl Enable for Timer0 -where - TG: TimerGroupInstance, -{ - fn enable_peripheral(&self) { - PeripheralClockControl::enable(PeripheralEnable::Timg0); - } -} - -#[cfg(timg_timer1)] -impl Enable for Timer1 -where - TG: TimerGroupInstance, -{ - fn enable_peripheral(&self) { - PeripheralClockControl::enable(PeripheralEnable::Timg1); - } -} - fn ticks_to_timeout(ticks: u64, clock: F, divider: u32) -> u64 where F: Into, @@ -956,7 +930,7 @@ where /// Construct a new instance of [`Wdt`] pub fn new() -> Self { #[cfg(lp_wdt)] - PeripheralClockControl::enable(PeripheralEnable::Wdt); + PeripheralClockControl::enable(crate::system::Peripheral::Wdt); TG::configure_wdt_src_clk(); From 30276e160927aa6a4a6db551dc0efc3dba5c5958 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Wed, 13 Nov 2024 01:49:41 -0700 Subject: [PATCH 60/67] implement wifi event handling with data (#2453) * implement event handling for apsta{,dis}connect and probe add to wifi_access_point example * hide internal `Option` to simplify api * move handler call logic to event.rs * update_handler_leak * - Add comments - match simpler api from `std::panic::update_hook` - do not assume size_of in prelude - make all events handleable - box static instead of leak * update changelog * elide lifetime on default handler * newtypes for all event types. * add doc to newtypes * fix previous doc example * - `get_handler` -> `handler` - pass critical section to event handlers - comment on perf of Box - don't pass `prev` in `update_handler`, instead call previous handler first unconditionally * pass cs to dispatch_event_handler * don't print "unhandled event" for handled events. --- esp-wifi/CHANGELOG.md | 1 + esp-wifi/src/wifi/event.rs | 348 ++++++++++++++++++++++++++ esp-wifi/src/wifi/mod.rs | 1 + esp-wifi/src/wifi/os_adapter.rs | 9 +- esp-wifi/src/wifi/state.rs | 8 +- examples/src/bin/wifi_access_point.rs | 19 ++ 6 files changed, 382 insertions(+), 4 deletions(-) create mode 100644 esp-wifi/src/wifi/event.rs diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 1280fa9c3d9..6d2275777c3 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `serde` support through the `serde` feature (#2346) - Added `PowerSaveMode` and `set_power_saving` methods on `EspNowManager` & `WifiController` (#2446) - Added CSI support (#2422) +- Enable setting event handlers for wifi events (#2453) ### Changed diff --git a/esp-wifi/src/wifi/event.rs b/esp-wifi/src/wifi/event.rs new file mode 100644 index 00000000000..f0daf78d4fa --- /dev/null +++ b/esp-wifi/src/wifi/event.rs @@ -0,0 +1,348 @@ +use alloc::boxed::Box; +use core::cell::RefCell; + +use critical_section::Mutex; + +use super::WifiEvent; + +pub(crate) mod sealed { + use super::*; + + pub trait Event { + /// Get the static reference to the handler for this event. + fn handler() -> &'static Mutex>>>>; + /// # Safety + /// `ptr` must be a valid for casting to this event's inner event data. + unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self; + } +} +/// The type of handlers of events. +pub type Handler = dyn FnMut(critical_section::CriticalSection<'_>, &T) + Sync + Send; + +fn default_handler() -> Box> { + fn drop_ref(_: critical_section::CriticalSection<'_>, _: &T) {} + // perf: `drop_ref` is a ZST [function item](https://doc.rust-lang.org/reference/types/function-item.html) + // so this doesn't actually allocate. + Box::new(drop_ref) +} + +/// Extension trait for setting handlers for an event. +/// +/// Register a new event handler like: +/// ``` +/// # use esp_wifi::wifi::event::{self, *}; +/// # fn new_handler(_: critical_section::CriticalSection<'_>, _: &ApStaconnected) {} +/// event::ApStaconnected::update_handler(|_cs, event| { +/// new_handler(event); +/// }) +/// ``` +// Implemented like this instead of free functions because the syntax would be +// ``` +// event::update_handler::(...) +// ``` +pub trait EventExt: sealed::Event + Sized + 'static { + /// Get the handler for this event, replacing it with the default handler. + fn take_handler() -> Box> { + critical_section::with(|cs| { + Self::handler() + .borrow_ref_mut(cs) + .take() + .unwrap_or_else(default_handler::) + }) + } + /// Set the handler for this event, returning the old handler. + fn replace_handler< + F: FnMut(critical_section::CriticalSection<'_>, &Self) + Sync + Send + 'static, + >( + f: F, + ) -> Box> { + critical_section::with(|cs| { + Self::handler() + .borrow_ref_mut(cs) + .replace(Box::new(f)) + .unwrap_or_else(default_handler::) + }) + } + /// Atomic combination of [`take_handler`] and [`replace_handler`]. Use this + /// to add a new handler which runs after the previously registered + /// handlers. + fn update_handler< + F: FnMut(critical_section::CriticalSection<'_>, &Self) + Sync + Send + 'static, + >( + mut f: F, + ) { + critical_section::with(move |cs| { + let mut handler: Box> = Self::handler() + .borrow_ref_mut(cs) + .take() + .unwrap_or_else(default_handler::); + Self::handler().borrow_ref_mut(cs).replace(Box::new( + move |cs: critical_section::CriticalSection<'_>, event| { + handler(cs, event); + f(cs, event) + }, + )); + }); + } +} +impl EventExt for T {} + +macro_rules! impl_wifi_event { + // no data + ($newtype:ident) => { + /// See [`WifiEvent`]. + #[derive(Copy, Clone)] + pub struct $newtype; + impl sealed::Event for $newtype { + unsafe fn from_raw_event_data(_: *mut crate::binary::c_types::c_void) -> Self { + Self + } + fn handler() -> &'static Mutex>>>> { + static HANDLE: Mutex>>>> = + Mutex::new(RefCell::new(None)); + &HANDLE + } + } + }; + // data + ($newtype:ident, $data:ident) => { + pub use esp_wifi_sys::include::$data; + /// See [`WifiEvent`]. + #[derive(Copy, Clone)] + pub struct $newtype(pub $data); + impl sealed::Event for $newtype { + unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self { + Self(unsafe { *ptr.cast() }) + } + fn handler() -> &'static Mutex>>>> { + static HANDLE: Mutex>>>> = + Mutex::new(RefCell::new(None)); + &HANDLE + } + } + }; +} + +impl_wifi_event!(WifiReady); +impl_wifi_event!(ScanDone); +impl_wifi_event!(StaStart); +impl_wifi_event!(StaStop); +impl_wifi_event!(StaConnected, wifi_event_sta_connected_t); +impl_wifi_event!(StaDisconnected, wifi_event_sta_disconnected_t); +impl_wifi_event!(StaAuthmodeChange, wifi_event_sta_authmode_change_t); +impl_wifi_event!(StaWpsErSuccess, wifi_event_sta_wps_er_success_t); +impl_wifi_event!(StaWpsErFailed); +impl_wifi_event!(StaWpsErTimeout); +impl_wifi_event!(StaWpsErPin, wifi_event_sta_wps_er_pin_t); +impl_wifi_event!(StaWpsErPbcOverlap); +impl_wifi_event!(ApStart); +impl_wifi_event!(ApStop); +impl_wifi_event!(ApStaconnected, wifi_event_ap_staconnected_t); +impl_wifi_event!(ApStadisconnected, wifi_event_ap_stadisconnected_t); +impl_wifi_event!(ApProbereqrecved, wifi_event_ap_probe_req_rx_t); +impl_wifi_event!(FtmReport, wifi_event_ftm_report_t); +impl_wifi_event!(StaBssRssiLow, wifi_event_bss_rssi_low_t); +impl_wifi_event!(ActionTxStatus, wifi_event_action_tx_status_t); +impl_wifi_event!(RocDone, wifi_event_roc_done_t); +impl_wifi_event!(StaBeaconTimeout); +impl_wifi_event!(ConnectionlessModuleWakeIntervalStart); +impl_wifi_event!(ApWpsRgSuccess, wifi_event_ap_wps_rg_success_t); +impl_wifi_event!(ApWpsRgFailed, wifi_event_ap_wps_rg_fail_reason_t); +impl_wifi_event!(ApWpsRgTimeout); +impl_wifi_event!(ApWpsRgPin, wifi_event_ap_wps_rg_pin_t); +impl_wifi_event!(ApWpsRgPbcOverlap); +impl_wifi_event!(ItwtSetup); +impl_wifi_event!(ItwtTeardown); +impl_wifi_event!(ItwtProbe); +impl_wifi_event!(ItwtSuspend); +impl_wifi_event!(TwtWakeup); +impl_wifi_event!(BtwtSetup); +impl_wifi_event!(BtwtTeardown); +impl_wifi_event!(NanStarted); +impl_wifi_event!(NanStopped); +impl_wifi_event!(NanSvcMatch, wifi_event_nan_svc_match_t); +impl_wifi_event!(NanReplied, wifi_event_nan_replied_t); +impl_wifi_event!(NanReceive, wifi_event_nan_receive_t); +impl_wifi_event!(NdpIndication, wifi_event_ndp_indication_t); +impl_wifi_event!(NdpConfirm, wifi_event_ndp_confirm_t); +impl_wifi_event!(NdpTerminated, wifi_event_ndp_terminated_t); +impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t); +impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t); + +/// Handle the given event using the registered event handlers. +pub fn handle( + cs: critical_section::CriticalSection<'_>, + event_data: &Event, +) -> bool { + if let Some(handler) = &mut *Event::handler().borrow_ref_mut(cs) { + handler(cs, event_data); + true + } else { + false + } +} + +/// Handle an event given the raw pointers. +/// # Safety +/// The pointer should be valid to cast to `Event`'s inner type (if it has one) +pub(crate) unsafe fn handle_raw( + cs: critical_section::CriticalSection<'_>, + event_data: *mut crate::binary::c_types::c_void, + event_data_size: usize, +) -> bool { + debug_assert_eq!( + event_data_size, + core::mem::size_of::(), + "wrong size event data" + ); + handle::(cs, unsafe { &Event::from_raw_event_data(event_data) }) +} + +/// Handle event regardless of its type. +/// # Safety +/// Arguments should be self-consistent. +#[rustfmt::skip] +pub(crate) unsafe fn dispatch_event_handler( + cs: critical_section::CriticalSection<'_>, + event: WifiEvent, + event_data: *mut crate::binary::c_types::c_void, + event_data_size: usize, +) -> bool { + match event { + WifiEvent::WifiReady => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ScanDone => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaStart => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaStop => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaConnected => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaDisconnected => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaAuthmodeChange => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaWpsErSuccess => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaWpsErFailed => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaWpsErTimeout => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaWpsErPin => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaWpsErPbcOverlap => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApStart => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApStop => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApStaconnected => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApStadisconnected => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApProbereqrecved => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::FtmReport => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaBssRssiLow => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ActionTxStatus => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::RocDone => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaBeaconTimeout => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ConnectionlessModuleWakeIntervalStart => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApWpsRgSuccess => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApWpsRgFailed => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApWpsRgTimeout => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApWpsRgPin => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ApWpsRgPbcOverlap => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ItwtSetup => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ItwtTeardown => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ItwtProbe => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::ItwtSuspend => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::TwtWakeup => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::BtwtSetup => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::BtwtTeardown => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NanStarted => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NanStopped => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NanSvcMatch => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NanReplied => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NanReceive => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NdpIndication => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NdpConfirm => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::NdpTerminated => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::HomeChannelChange => { + handle_raw::(cs, event_data, event_data_size) + } + WifiEvent::StaNeighborRep => { + handle_raw::(cs, event_data, event_data_size) + } + } +} diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index b2e2abafc6b..cad2758a276 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -1,5 +1,6 @@ //! WiFi +pub mod event; pub(crate) mod os_adapter; pub(crate) mod state; diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index cd87ab6633d..862ae5cb2be 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -866,9 +866,14 @@ pub unsafe extern "C" fn event_post( let event = unwrap!(WifiEvent::from_i32(event_id)); trace!("EVENT: {:?}", event); - critical_section::with(|cs| WIFI_EVENTS.borrow_ref_mut(cs).insert(event)); - super::state::update_state(event); + let mut handled = false; + critical_section::with(|cs| { + WIFI_EVENTS.borrow_ref_mut(cs).insert(event); + handled = super::event::dispatch_event_handler(cs, event, event_data, event_data_size); + }); + + super::state::update_state(event, handled); event.waker().wake(); diff --git a/esp-wifi/src/wifi/state.rs b/esp-wifi/src/wifi/state.rs index e11f584f576..5072091488b 100644 --- a/esp-wifi/src/wifi/state.rs +++ b/esp-wifi/src/wifi/state.rs @@ -47,7 +47,7 @@ pub fn get_sta_state() -> WifiState { STA_STATE.load(Ordering::Relaxed) } -pub(crate) fn update_state(event: WifiEvent) { +pub(crate) fn update_state(event: WifiEvent, handled: bool) { match event { WifiEvent::StaConnected | WifiEvent::StaDisconnected @@ -58,7 +58,11 @@ pub(crate) fn update_state(event: WifiEvent) { AP_STATE.store(WifiState::from(event), Ordering::Relaxed) } - other => debug!("Unhandled event: {:?}", other), + other => { + if !handled { + debug!("Unhandled event: {:?}", other) + } + } } } diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index 8a5c1387bdd..fcd699cd09b 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -28,6 +28,7 @@ use esp_println::{print, println}; use esp_wifi::{ init, wifi::{ + event::{self, EventExt}, utils::create_network_interface, AccessPointConfiguration, Configuration, @@ -49,6 +50,24 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0); + // Set event handlers for wifi before init to avoid missing any. + let mut connections = 0u32; + _ = event::ApStart::replace_handler(|_, _| esp_println::println!("ap start event")); + event::ApStaconnected::update_handler(move |_, event| { + connections += 1; + esp_println::println!("connected {}, mac: {:?}", connections, event.0.mac); + }); + event::ApStaconnected::update_handler(|_, event| { + esp_println::println!("connected aid: {}", event.0.aid); + }); + event::ApStadisconnected::update_handler(|_, event| { + esp_println::println!( + "disconnected mac: {:?}, reason: {:?}", + event.0.mac, + event.0.reason + ); + }); + let mut rng = Rng::new(peripherals.RNG); let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); From 8cbc249e2ece199c60c762d3c50619ce539dadcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 10:57:30 +0100 Subject: [PATCH 61/67] I2c: attempt empty writes (#2506) * Attempt 0-length writes * Deduplicate * Changelog * Test existing address * Name addresses * Fix formatting --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/i2c/master/mod.rs | 133 ++++++++++++++++++---------------- hil-test/tests/i2c.rs | 25 ++++++- 3 files changed, 94 insertions(+), 65 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d11e2fc515d..f57a9e67bbd 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -199,6 +199,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - TWAI should no longer panic when receiving a non-compliant frame (#2255) - OneShotTimer: fixed `delay_nanos` behaviour (#2256) - Fixed unsoundness around `Efuse` (#2259) +- Empty I2C writes to unknown addresses now correctly fail with `AckCheckFailed`. (#2506) ### Removed diff --git a/esp-hal/src/i2c/master/mod.rs b/esp-hal/src/i2c/master/mod.rs index b336ea1b3af..167a1b855f7 100644 --- a/esp-hal/src/i2c/master/mod.rs +++ b/esp-hal/src/i2c/master/mod.rs @@ -1855,30 +1855,51 @@ impl Driver<'_> { .write(|w| w.rxfifo_full().clear_bit_by_one()); } - /// Executes an I2C write operation. + fn start_write_operation( + &self, + address: u8, + bytes: &[u8], + start: bool, + stop: bool, + ) -> Result { + self.reset_fifo(); + self.reset_command_list(); + let cmd_iterator = &mut self.register_block().comd_iter(); + + if start { + add_cmd(cmd_iterator, Command::Start)?; + } + + self.setup_write(address, bytes, start, cmd_iterator)?; + + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + let index = self.fill_tx_fifo(bytes); + self.start_transmission(); + + Ok(index) + } + + /// Executes an I2C read operation. /// - `addr` is the address of the slave device. - /// - `bytes` is the data two be sent. + /// - `buffer` is the buffer to store the read data. /// - `start` indicates whether the operation should start by a START /// condition and sending the address. /// - `stop` indicates whether the operation should end with a STOP /// condition. + /// - `will_continue` indicates whether there is another read operation + /// following this one and we should not nack the last byte. /// - `cmd_iterator` is an iterator over the command registers. - fn write_operation_blocking( + fn start_read_operation( &self, address: u8, - bytes: &[u8], + buffer: &mut [u8], start: bool, stop: bool, + will_continue: bool, ) -> Result<(), Error> { - self.clear_all_interrupts(); - - // Short circuit for zero length writes without start or end as that would be an - // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 - if bytes.is_empty() && !start && !stop { - return Ok(()); - } - - // Reset FIFO and command list self.reset_fifo(); self.reset_command_list(); @@ -1887,14 +1908,41 @@ impl Driver<'_> { if start { add_cmd(cmd_iterator, Command::Start)?; } - self.setup_write(address, bytes, start, cmd_iterator)?; + + self.setup_read(address, buffer, start, will_continue, cmd_iterator)?; + add_cmd( cmd_iterator, if stop { Command::Stop } else { Command::End }, )?; - let index = self.fill_tx_fifo(bytes); self.start_transmission(); + Ok(()) + } + /// Executes an I2C write operation. + /// - `addr` is the address of the slave device. + /// - `bytes` is the data two be sent. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `cmd_iterator` is an iterator over the command registers. + fn write_operation_blocking( + &self, + address: u8, + bytes: &[u8], + start: bool, + stop: bool, + ) -> Result<(), Error> { + self.clear_all_interrupts(); + + // Short circuit for zero length writes without start or end as that would be an + // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 + if bytes.is_empty() && !start && !stop { + return Ok(()); + } + + let index = self.start_write_operation(address, bytes, start, stop)?; // Fill the FIFO with the remaining bytes: self.write_remaining_tx_fifo_blocking(index, bytes)?; self.wait_for_completion_blocking(!stop)?; @@ -1927,23 +1975,7 @@ impl Driver<'_> { return Ok(()); } - // Reset FIFO and command list - self.reset_fifo(); - self.reset_command_list(); - - let cmd_iterator = &mut self.register_block().comd_iter(); - - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - - self.setup_read(address, buffer, start, will_continue, cmd_iterator)?; - - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - self.start_transmission(); + self.start_read_operation(address, buffer, start, stop, will_continue)?; self.read_all_from_fifo_blocking(buffer)?; self.wait_for_completion_blocking(!stop)?; Ok(()) @@ -1972,22 +2004,7 @@ impl Driver<'_> { return Ok(()); } - // Reset FIFO and command list - self.reset_fifo(); - self.reset_command_list(); - - let cmd_iterator = &mut self.register_block().comd_iter(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.setup_write(address, bytes, start, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - let index = self.fill_tx_fifo(bytes); - self.start_transmission(); - + let index = self.start_write_operation(address, bytes, start, stop)?; // Fill the FIFO with the remaining bytes: self.write_remaining_tx_fifo(index, bytes).await?; self.wait_for_completion(!stop).await?; @@ -2020,19 +2037,7 @@ impl Driver<'_> { return Ok(()); } - // Reset FIFO and command list - self.reset_fifo(); - self.reset_command_list(); - let cmd_iterator = &mut self.register_block().comd_iter(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.setup_read(address, buffer, start, will_continue, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - self.start_transmission(); + self.start_read_operation(address, buffer, start, stop, will_continue)?; self.read_all_from_fifo(buffer).await?; self.wait_for_completion(!stop).await?; Ok(()) @@ -2067,6 +2072,9 @@ impl Driver<'_> { start: bool, stop: bool, ) -> Result<(), Error> { + if buffer.is_empty() { + return self.write_operation_blocking(address, &[], start, stop); + } let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { self.write_operation_blocking( @@ -2110,6 +2118,9 @@ impl Driver<'_> { start: bool, stop: bool, ) -> Result<(), Error> { + if buffer.is_empty() { + return self.write_operation(address, &[], start, stop).await; + } let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { self.write_operation( diff --git a/hil-test/tests/i2c.rs b/hil-test/tests/i2c.rs index 9ea9f267c6b..8f786717c9b 100644 --- a/hil-test/tests/i2c.rs +++ b/hil-test/tests/i2c.rs @@ -6,7 +6,7 @@ #![no_main] use esp_hal::{ - i2c::master::{Config, I2c, Operation}, + i2c::master::{Config, Error, I2c, Operation}, Async, Blocking, }; @@ -24,6 +24,9 @@ fn _async_driver_is_compatible_with_blocking_ehal() { fn _with_ehal(_: impl embedded_hal::i2c::I2c) {} } +const DUT_ADDRESS: u8 = 0x77; +const NON_EXISTENT_ADDRESS: u8 = 0x6b; + #[cfg(test)] #[embedded_test::tests] mod tests { @@ -44,6 +47,16 @@ mod tests { Context { i2c } } + #[test] + #[timeout(3)] + fn empty_write_returns_ack_error_for_unknown_address(mut ctx: Context) { + assert_eq!( + ctx.i2c.write(NON_EXISTENT_ADDRESS, &[]), + Err(Error::AckCheckFailed) + ); + assert_eq!(ctx.i2c.write(DUT_ADDRESS, &[]), Ok(())); + } + #[test] #[timeout(3)] fn test_read_cali(mut ctx: Context) { @@ -51,10 +64,14 @@ mod tests { // have a failing read which might could leave the peripheral in an undesirable // state - ctx.i2c.write_read(0x55, &[0xaa], &mut read_data).ok(); + ctx.i2c + .write_read(NON_EXISTENT_ADDRESS, &[0xaa], &mut read_data) + .ok(); // do the real read which should succeed - ctx.i2c.write_read(0x77, &[0xaa], &mut read_data).ok(); + ctx.i2c + .write_read(DUT_ADDRESS, &[0xaa], &mut read_data) + .ok(); assert_ne!(read_data, [0u8; 22]) } @@ -67,7 +84,7 @@ mod tests { // do the real read which should succeed ctx.i2c .transaction( - 0x77, + DUT_ADDRESS, &mut [Operation::Write(&[0xaa]), Operation::Read(&mut read_data)], ) .ok(); From 7da4444a7e8680bdb12b313bacd325e7243c52e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 13 Nov 2024 12:29:36 +0100 Subject: [PATCH 62/67] Fail RMT one-shot transactions if end-marker is missing (#2463) * Fail RMT one-shot transactions if end-marker is missing * CHANGELOG.md * Add test * Fix * Fix * RMT: use u32, turn PulseCode into a convenience trait * Clippy * Adapt test --- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 28 ++++++ esp-hal/src/rmt.rs | 145 +++++++++++++++-------------- examples/src/bin/embassy_rmt_rx.rs | 27 +++--- examples/src/bin/embassy_rmt_tx.rs | 16 +--- examples/src/bin/rmt_rx.rs | 30 +++--- examples/src/bin/rmt_tx.rs | 19 +--- hil-test/tests/rmt.rs | 66 ++++++++----- 8 files changed, 178 insertions(+), 154 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index f57a9e67bbd..2bba6de8d04 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -62,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `slave::Spi` constructors no longer take pins (#2485) - The `I2c` master driver has been moved from `esp_hal::i2c` to `esp_hal::i2c::master`. (#2476) - `I2c` SCL timeout is now defined in bus clock cycles. (#2477) +- Trying to send a single-shot RMT transmission will result in an error now, `RMT` deals with `u32` now, `PulseCode` is a convenience trait now (#2463) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 9304bddd0b6..ca6dfba8d06 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -368,3 +368,31 @@ If you were using an 16-bit bus, you don't need to change anything, `set_byte_or If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when you switch between devices. Be sure to read the documentation of the new methods. + + +## `rmt::Channel::transmit` now returns `Result`, `PulseCode` is now `u32` + +When trying to send a one-shot transmission will fail if it doesn't end with an end-marker. + +```diff +- let mut data = [PulseCode { +- level1: true, +- length1: 200, +- level2: false, +- length2: 50, +- }; 20]; +- +- data[data.len() - 2] = PulseCode { +- level1: true, +- length1: 3000, +- level2: false, +- length2: 500, +- }; +- data[data.len() - 1] = PulseCode::default(); ++ let mut data = [PulseCode::new(true, 200, false, 50); 20]; ++ data[data.len() - 2] = PulseCode::new(true, 3000, false, 500); ++ data[data.len() - 1] = PulseCode::empty(); + +- let transaction = channel.transmit(&data); ++ let transaction = channel.transmit(&data).unwrap(); +``` diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index ef6f4b1063a..dc2d4e916e3 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -112,61 +112,62 @@ pub enum Error { InvalidArgument, /// An error occurred during transmission TransmissionError, + /// No transmission end marker found + EndMarkerMissing, } -/// Convenience representation of a pulse code entry. -/// -/// Allows for the assignment of two levels and their lengths -#[derive(Clone, Copy, Debug, Default, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PulseCode { +/// Convenience trait to work with pulse codes. +pub trait PulseCode: crate::private::Sealed { + /// Create a new instance + fn new(level1: bool, length1: u16, level2: bool, length2: u16) -> Self; + + /// Create a new empty instance + fn empty() -> Self; + + /// Set all levels and lengths to 0 + fn reset(&mut self); + /// Logical output level in the first pulse code interval - pub level1: bool, + fn level1(&self) -> bool; + /// Length of the first pulse code interval (in clock cycles) - pub length1: u16, + fn length1(&self) -> u16; + /// Logical output level in the second pulse code interval - pub level2: bool, + fn level2(&self) -> bool; + /// Length of the second pulse code interval (in clock cycles) - pub length2: u16, + fn length2(&self) -> u16; } -impl From for PulseCode { - fn from(value: u32) -> Self { - Self { - level1: value & (1 << 15) != 0, - length1: (value & 0b111_1111_1111_1111) as u16, - level2: value & (1 << 31) != 0, - length2: ((value >> 16) & 0b111_1111_1111_1111) as u16, - } +impl PulseCode for u32 { + fn new(level1: bool, length1: u16, level2: bool, length2: u16) -> Self { + (((level1 as u32) << 15) | length1 as u32 & 0b111_1111_1111_1111) + | (((level2 as u32) << 15) | length2 as u32 & 0b111_1111_1111_1111) << 16 } -} -/// Convert a pulse code structure into a u32 value that can be written -/// into the data registers -impl From for u32 { - #[inline(always)] - fn from(p: PulseCode) -> u32 { - // The length1 value resides in bits [14:0] - let mut entry: u32 = p.length1 as u32; - - // If level1 is high, set bit 15, otherwise clear it - if p.level1 { - entry |= 1 << 15; - } else { - entry &= !(1 << 15); - } + fn empty() -> Self { + 0 + } - // If level2 is high, set bit 31, otherwise clear it - if p.level2 { - entry |= 1 << 31; - } else { - entry &= !(1 << 31); - } + fn reset(&mut self) { + *self = 0 + } - // The length2 value resides in bits [30:16] - entry |= (p.length2 as u32) << 16; + fn level1(&self) -> bool { + self & (1 << 15) != 0 + } + + fn length1(&self) -> u16 { + (self & 0b111_1111_1111_1111) as u16 + } + + fn level2(&self) -> bool { + self & (1 << 31) != 0 + } - entry + fn length2(&self) -> u16 { + ((self >> 16) & 0b111_1111_1111_1111) as u16 } } @@ -423,16 +424,16 @@ where } /// An in-progress transaction for a single shot TX transaction. -pub struct SingleShotTxTransaction<'a, C, T: Into + Copy> +pub struct SingleShotTxTransaction<'a, C> where C: TxChannel, { channel: C, index: usize, - data: &'a [T], + data: &'a [u32], } -impl + Copy> SingleShotTxTransaction<'_, C, T> +impl SingleShotTxTransaction<'_, C> where C: TxChannel, { @@ -466,7 +467,7 @@ where .enumerate() { unsafe { - ptr.add(idx).write_volatile((*entry).into()); + ptr.add(idx).write_volatile(*entry); } } @@ -982,26 +983,23 @@ pub trait TxChannel: TxChannelInternal { /// This returns a [`SingleShotTxTransaction`] which can be used to wait for /// the transaction to complete and get back the channel for further /// use. - fn transmit + Copy>(self, data: &[T]) -> SingleShotTxTransaction<'_, Self, T> + fn transmit(self, data: &[u32]) -> Result, Error> where Self: Sized, { - let index = Self::send_raw(data, false, 0); - SingleShotTxTransaction { + let index = Self::send_raw(data, false, 0)?; + Ok(SingleShotTxTransaction { channel: self, index, data, - } + }) } /// Start transmitting the given pulse code continuously. /// This returns a [`ContinuousTxTransaction`] which can be used to stop the /// ongoing transmission and get back the channel for further use. /// The length of sequence cannot exceed the size of the allocated RMT RAM. - fn transmit_continuously + Copy>( - self, - data: &[T], - ) -> Result, Error> + fn transmit_continuously(self, data: &[u32]) -> Result, Error> where Self: Sized, { @@ -1011,10 +1009,10 @@ pub trait TxChannel: TxChannelInternal { /// Like [`Self::transmit_continuously`] but also sets a loop count. /// [`ContinuousTxTransaction`] can be used to check if the loop count is /// reached. - fn transmit_continuously_with_loopcount + Copy>( + fn transmit_continuously_with_loopcount( self, loopcount: u16, - data: &[T], + data: &[u32], ) -> Result, Error> where Self: Sized, @@ -1023,21 +1021,21 @@ pub trait TxChannel: TxChannelInternal { return Err(Error::Overflow); } - let _index = Self::send_raw(data, true, loopcount); + let _index = Self::send_raw(data, true, loopcount)?; Ok(ContinuousTxTransaction { channel: self }) } } /// RX transaction instance -pub struct RxTransaction<'a, C, T: From + Copy> +pub struct RxTransaction<'a, C> where C: RxChannel, { channel: C, - data: &'a mut [T], + data: &'a mut [u32], } -impl + Copy> RxTransaction<'_, C, T> +impl RxTransaction<'_, C> where C: RxChannel, { @@ -1062,7 +1060,7 @@ where as *mut u32; let len = self.data.len(); for (idx, entry) in self.data.iter_mut().take(len).enumerate() { - *entry = unsafe { ptr.add(idx).read_volatile().into() }; + *entry = unsafe { ptr.add(idx).read_volatile() }; } Ok(self.channel) @@ -1075,10 +1073,7 @@ pub trait RxChannel: RxChannelInternal { /// This returns a [RxTransaction] which can be used to wait for receive to /// complete and get back the channel for further use. /// The length of the received data cannot exceed the allocated RMT RAM. - fn receive + Copy>( - self, - data: &mut [T], - ) -> Result, Error> + fn receive(self, data: &mut [u32]) -> Result, Error> where Self: Sized, { @@ -1143,7 +1138,7 @@ pub trait TxChannelAsync: TxChannelInternal { /// Start transmitting the given pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. - async fn transmit<'a, T: Into + Copy>(&mut self, data: &'a [T]) -> Result<(), Error> + async fn transmit<'a>(&mut self, data: &'a [u32]) -> Result<(), Error> where Self: Sized, { @@ -1154,7 +1149,7 @@ pub trait TxChannelAsync: TxChannelInternal { Self::clear_interrupts(); Self::listen_interrupt(Event::End); Self::listen_interrupt(Event::Error); - Self::send_raw(data, false, 0); + Self::send_raw(data, false, 0)?; RmtTxFuture::new(self).await; @@ -1402,9 +1397,17 @@ where fn is_loopcount_interrupt_set() -> bool; - fn send_raw + Copy>(data: &[T], continuous: bool, repeat: u16) -> usize { + fn send_raw(data: &[u32], continuous: bool, repeat: u16) -> Result { Self::clear_interrupts(); + if let Some(last) = data.last() { + if !continuous && last.length2() != 0 && last.length1() != 0 { + return Err(Error::EndMarkerMissing); + } + } else { + return Err(Error::InvalidArgument); + } + let ptr = (constants::RMT_RAM_START + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) as *mut u32; @@ -1414,7 +1417,7 @@ where .enumerate() { unsafe { - ptr.add(idx).write_volatile((*entry).into()); + ptr.add(idx).write_volatile(*entry); } } @@ -1428,9 +1431,9 @@ where Self::update(); if data.len() >= constants::RMT_CHANNEL_RAM_SIZE { - constants::RMT_CHANNEL_RAM_SIZE + Ok(constants::RMT_CHANNEL_RAM_SIZE) } else { - data.len() + Ok(data.len()) } } diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 08c5f8bc28d..81faf25cd11 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -73,46 +73,41 @@ async fn main(spawner: Spawner) { .spawn(signal_task(Output::new(peripherals.GPIO5, Level::Low))) .unwrap(); - let mut data = [PulseCode { - level1: true, - length1: 1, - level2: false, - length2: 1, - }; 48]; + let mut data: [u32; 48] = [PulseCode::empty(); 48]; loop { println!("receive"); channel.receive(&mut data).await.unwrap(); let mut total = 0usize; for entry in &data[..data.len()] { - if entry.length1 == 0 { + if entry.length1() == 0 { break; } - total += entry.length1 as usize; + total += entry.length1() as usize; - if entry.length2 == 0 { + if entry.length2() == 0 { break; } - total += entry.length2 as usize; + total += entry.length2() as usize; } for entry in &data[..data.len()] { - if entry.length1 == 0 { + if entry.length1() == 0 { break; } - let count = WIDTH / (total / entry.length1 as usize); - let c = if entry.level1 { '-' } else { '_' }; + let count = WIDTH / (total / entry.length1() as usize); + let c = if entry.level1() { '-' } else { '_' }; for _ in 0..count + 1 { print!("{}", c); } - if entry.length2 == 0 { + if entry.length2() == 0 { break; } - let count = WIDTH / (total / entry.length2 as usize); - let c = if entry.level2 { '-' } else { '_' }; + let count = WIDTH / (total / entry.length2() as usize); + let c = if entry.level2() { '-' } else { '_' }; for _ in 0..count + 1 { print!("{}", c); } diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 5943c453700..20e14cfa574 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -50,20 +50,10 @@ async fn main(_spawner: Spawner) { ) .unwrap(); - let mut data = [PulseCode { - level1: true, - length1: 200, - level2: false, - length2: 50, - }; 20]; + let mut data = [PulseCode::new(true, 200, false, 50); 20]; - data[data.len() - 2] = PulseCode { - level1: true, - length1: 3000, - level2: false, - length2: 500, - }; - data[data.len() - 1] = PulseCode::default(); + data[data.len() - 2] = PulseCode::new(true, 3000, false, 500); + data[data.len() - 1] = PulseCode::empty(); loop { println!("transmit"); diff --git a/examples/src/bin/rmt_rx.rs b/examples/src/bin/rmt_rx.rs index c9dc626b1b4..39869dd3741 100644 --- a/examples/src/bin/rmt_rx.rs +++ b/examples/src/bin/rmt_rx.rs @@ -56,17 +56,11 @@ fn main() -> ! { let delay = Delay::new(); - let mut data = [PulseCode { - level1: true, - length1: 1, - level2: false, - length2: 1, - }; 48]; + let mut data: [u32; 48] = [PulseCode::empty(); 48]; loop { for x in data.iter_mut() { - x.length1 = 0; - x.length2 = 0; + x.reset() } let transaction = channel.receive(&mut data).unwrap(); @@ -84,34 +78,34 @@ fn main() -> ! { channel = channel_res; let mut total = 0usize; for entry in &data[..data.len()] { - if entry.length1 == 0 { + if entry.length1() == 0 { break; } - total += entry.length1 as usize; + total += entry.length1() as usize; - if entry.length2 == 0 { + if entry.length2() == 0 { break; } - total += entry.length2 as usize; + total += entry.length2() as usize; } for entry in &data[..data.len()] { - if entry.length1 == 0 { + if entry.length1() == 0 { break; } - let count = WIDTH / (total / entry.length1 as usize); - let c = if entry.level1 { '-' } else { '_' }; + let count = WIDTH / (total / entry.length1() as usize); + let c = if entry.level1() { '-' } else { '_' }; for _ in 0..count + 1 { print!("{}", c); } - if entry.length2 == 0 { + if entry.length2() == 0 { break; } - let count = WIDTH / (total / entry.length2 as usize); - let c = if entry.level2 { '-' } else { '_' }; + let count = WIDTH / (total / entry.length2() as usize); + let c = if entry.level2() { '-' } else { '_' }; for _ in 0..count + 1 { print!("{}", c); } diff --git a/examples/src/bin/rmt_tx.rs b/examples/src/bin/rmt_tx.rs index d87e8d87a85..7689ce47c4a 100644 --- a/examples/src/bin/rmt_tx.rs +++ b/examples/src/bin/rmt_tx.rs @@ -43,23 +43,12 @@ fn main() -> ! { let delay = Delay::new(); - let mut data = [PulseCode { - level1: true, - length1: 200, - level2: false, - length2: 50, - }; 20]; - - data[data.len() - 2] = PulseCode { - level1: true, - length1: 3000, - level2: false, - length2: 500, - }; - data[data.len() - 1] = PulseCode::default(); + let mut data = [PulseCode::new(true, 200, false, 50); 20]; + data[data.len() - 2] = PulseCode::new(true, 3000, false, 500); + data[data.len() - 1] = PulseCode::empty(); loop { - let transaction = channel.transmit(&data); + let transaction = channel.transmit(&data).unwrap(); channel = transaction.wait().unwrap(); delay.delay_millis(500); } diff --git a/hil-test/tests/rmt.rs b/hil-test/tests/rmt.rs index c7c9db6d28e..5f014745b0a 100644 --- a/hil-test/tests/rmt.rs +++ b/hil-test/tests/rmt.rs @@ -14,6 +14,8 @@ use hil_test as _; #[cfg(test)] #[embedded_test::tests] mod tests { + use esp_hal::rmt::Error; + use super::*; #[init] @@ -76,30 +78,15 @@ mod tests { } } - let mut tx_data = [PulseCode { - level1: true, - length1: 200, - level2: false, - length2: 50, - }; 20]; - - tx_data[tx_data.len() - 2] = PulseCode { - level1: true, - length1: 3000, - level2: false, - length2: 500, - }; - tx_data[tx_data.len() - 1] = PulseCode::default(); + let mut tx_data = [PulseCode::new(true, 200, false, 50); 20]; + + tx_data[tx_data.len() - 2] = PulseCode::new(true, 3000, false, 500); + tx_data[tx_data.len() - 1] = PulseCode::empty(); - let mut rcv_data = [PulseCode { - level1: false, - length1: 0, - level2: false, - length2: 0, - }; 20]; + let mut rcv_data: [u32; 20] = [PulseCode::empty(); 20]; let rx_transaction = rx_channel.receive(&mut rcv_data).unwrap(); - let tx_transaction = tx_channel.transmit(&tx_data); + let tx_transaction = tx_channel.transmit(&tx_data).unwrap(); rx_transaction.wait().unwrap(); tx_transaction.wait().unwrap(); @@ -108,4 +95,41 @@ mod tests { // they can't be equal assert_eq!(&tx_data[..18], &rcv_data[..18]); } + + #[test] + #[timeout(1)] + fn rmt_single_shot_fails_without_end_marker() { + let peripherals = esp_hal::init(esp_hal::Config::default()); + + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); + + cfg_if::cfg_if! { + if #[cfg(feature = "esp32h2")] { + let freq = 32.MHz(); + } else { + let freq = 80.MHz(); + } + }; + + let rmt = Rmt::new(peripherals.RMT, freq).unwrap(); + + let (_, tx) = hil_test::common_test_pins!(io); + + let tx_config = TxChannelConfig { + clk_divider: 255, + ..TxChannelConfig::default() + }; + + let tx_channel = { + use esp_hal::rmt::TxChannelCreator; + rmt.channel0.configure(tx, tx_config).unwrap() + }; + + let tx_data = [PulseCode::new(true, 200, false, 50); 20]; + + let tx_transaction = tx_channel.transmit(&tx_data); + + assert!(tx_transaction.is_err()); + assert!(matches!(tx_transaction, Err(Error::EndMarkerMissing))); + } } From b538e48ea4268a567bc2cb88fbd77fa546ad5553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 14:52:11 +0100 Subject: [PATCH 63/67] Fix RMT test (#2529) --- hil-test/tests/rmt.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hil-test/tests/rmt.rs b/hil-test/tests/rmt.rs index 5f014745b0a..8d7622f2661 100644 --- a/hil-test/tests/rmt.rs +++ b/hil-test/tests/rmt.rs @@ -101,8 +101,6 @@ mod tests { fn rmt_single_shot_fails_without_end_marker() { let peripherals = esp_hal::init(esp_hal::Config::default()); - let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - cfg_if::cfg_if! { if #[cfg(feature = "esp32h2")] { let freq = 32.MHz(); @@ -113,7 +111,7 @@ mod tests { let rmt = Rmt::new(peripherals.RMT, freq).unwrap(); - let (_, tx) = hil_test::common_test_pins!(io); + let (_, tx) = hil_test::common_test_pins!(peripherals); let tx_config = TxChannelConfig { clk_divider: 255, From 099e0eacdf33d6f504ad609a1de3d6009ac14086 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Wed, 13 Nov 2024 07:06:22 -0800 Subject: [PATCH 64/67] Use newest published PACs (#2530) --- esp-hal/Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 6291fb2fe2f..a92c64af117 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -56,13 +56,13 @@ xtensa-lx = { version = "0.9.0", optional = true } # IMPORTANT: # Each supported device MUST have its PAC included below along with a # corresponding feature. -esp32 = { version = "0.33.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32c2 = { version = "0.22.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32c3 = { version = "0.25.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32c6 = { version = "0.16.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32h2 = { version = "0.12.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32s2 = { version = "0.24.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } -esp32s3 = { version = "0.28.0", git = "https://github.com/esp-rs/esp-pacs.git", rev = "c364721", features = ["critical-section", "rt"], optional = true } +esp32 = { version = "0.34.0", features = ["critical-section", "rt"], optional = true } +esp32c2 = { version = "0.23.0", features = ["critical-section", "rt"], optional = true } +esp32c3 = { version = "0.26.0", features = ["critical-section", "rt"], optional = true } +esp32c6 = { version = "0.17.0", features = ["critical-section", "rt"], optional = true } +esp32h2 = { version = "0.13.0", features = ["critical-section", "rt"], optional = true } +esp32s2 = { version = "0.25.0", features = ["critical-section", "rt"], optional = true } +esp32s3 = { version = "0.29.0", features = ["critical-section", "rt"], optional = true } [target.'cfg(target_arch = "riscv32")'.dependencies] esp-riscv-rt = { version = "0.9.0", path = "../esp-riscv-rt" } From b11fc0fce8998b8b2bc3751e9a968a6132f383a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 13 Nov 2024 16:07:55 +0100 Subject: [PATCH 65/67] Remove NoClkPin (#2531) --- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 16 ++++++++++++++++ esp-hal/src/parl_io.rs | 20 ++++++++------------ examples/src/bin/embassy_parl_io_rx.rs | 11 +++++++++-- examples/src/bin/parl_io_rx.rs | 11 +++++++++-- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 2bba6de8d04..5acacce017a 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -104,6 +104,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `TaskSet`, `TaskClear`, `TaskToggle` types have been replaced with `Task` (#2427) - `{Spi, SpiDma, SpiDmaBus}` configuration methods (#2448) - `Io::new_with_priority` and `Io::new_no_bind_interrupt`. (#2486) +- `parl_io::{no_clk_pin(), NoClkPin}` (#2531) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index ca6dfba8d06..f24b6bef02c 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -396,3 +396,19 @@ When trying to send a one-shot transmission will fail if it doesn't end with an - let transaction = channel.transmit(&data); + let transaction = channel.transmit(&data).unwrap(); ``` + + +## The `parl_io::NoClkPin` and `no_clk_pin()` have been removed + +You can use `gpio::NoPin` instead. + +```diff + use esp_hal:: { +- parl_io::no_clk_pin, ++ gpio::NoPin, + } + +-parl_io.rx.with_config(&mut rx_pins, no_clk_pin(), BitPackOrder::Msb, Some(0xfff)) ++let mut rx_clk_pin = NoPin; ++parl_io.rx.with_config(&mut rx_pins, &mut rx_clk_pin, BitPackOrder::Msb, Some(0xfff)) +``` diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 57b558cc5ff..2d95e1427ec 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -49,7 +49,10 @@ use crate::{ Tx, WriteBuffer, }, - gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput}, + gpio::{ + interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput}, + NoPin, + }, interrupt::InterruptHandler, peripheral::{self, Peripheral}, peripherals::{self, Interrupt, PARL_IO}, @@ -260,24 +263,17 @@ pub enum EofMode { } /// Used to configure no pin as clock output -pub struct NoClkPin; -impl TxClkPin for NoClkPin { +impl TxClkPin for NoPin { fn configure(&mut self) { - // nothing + crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(self); } } -impl RxClkPin for NoClkPin { +impl RxClkPin for NoPin { fn configure(&mut self) { - // nothing + crate::gpio::InputSignal::PARL_RX_CLK.connect_to(self); } } -/// This can be used to pass to the `with_config` functions -pub fn no_clk_pin() -> &'static mut NoClkPin { - static mut NO_CLK: NoClkPin = NoClkPin; - unsafe { &mut *core::ptr::addr_of_mut!(NO_CLK) } -} - /// Wraps a GPIO pin which will be used as the clock output signal pub struct ClkOutPin<'d> { pin: PeripheralRef<'d, OutputConnection>, diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 9b589992dc0..33749c91f36 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -16,7 +16,8 @@ use esp_backtrace as _; use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - parl_io::{no_clk_pin, BitPackOrder, ParlIoRxOnly, RxFourBits}, + gpio::NoPin, + parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits}, prelude::*, timer::systimer::{SystemTimer, Target}, }; @@ -41,6 +42,7 @@ async fn main(_spawner: Spawner) { peripherals.GPIO3, peripherals.GPIO4, ); + let mut rx_clk_pin = NoPin; let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, @@ -54,7 +56,12 @@ async fn main(_spawner: Spawner) { let mut parl_io_rx = parl_io .rx - .with_config(&mut rx_pins, no_clk_pin(), BitPackOrder::Msb, Some(0xfff)) + .with_config( + &mut rx_pins, + &mut rx_clk_pin, + BitPackOrder::Msb, + Some(0xfff), + ) .unwrap(); let buffer = rx_buffer; diff --git a/examples/src/bin/parl_io_rx.rs b/examples/src/bin/parl_io_rx.rs index 6f5d1c2f353..2a0390878ce 100644 --- a/examples/src/bin/parl_io_rx.rs +++ b/examples/src/bin/parl_io_rx.rs @@ -14,7 +14,8 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaPriority}, dma_buffers, - parl_io::{no_clk_pin, BitPackOrder, ParlIoRxOnly, RxFourBits}, + gpio::NoPin, + parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits}, prelude::*, }; use esp_println::println; @@ -34,6 +35,7 @@ fn main() -> ! { peripherals.GPIO3, peripherals.GPIO4, ); + let mut rx_clk_pin = NoPin; let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, @@ -45,7 +47,12 @@ fn main() -> ! { let mut parl_io_rx = parl_io .rx - .with_config(&mut rx_pins, no_clk_pin(), BitPackOrder::Msb, Some(0xfff)) + .with_config( + &mut rx_pins, + &mut rx_clk_pin, + BitPackOrder::Msb, + Some(0xfff), + ) .unwrap(); let mut buffer = rx_buffer; From 92b91257e951a4a7b9c9614aec4708bc82e1bc7f Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Wed, 13 Nov 2024 07:40:26 -0800 Subject: [PATCH 66/67] Remove `get_` prefix from functions (#2528) * Remove `get_` prefixes from functions * Update migration guides for `esp-hal` and `esp-wifi` * Update `CHANGELOG.md` files --- esp-hal-embassy/src/executor/interrupt.rs | 4 +- esp-hal-embassy/src/executor/thread.rs | 8 +- esp-hal-procmacros/src/lp_core.rs | 4 +- esp-hal/CHANGELOG.md | 2 + esp-hal/MIGRATING-0.21.md | 9 +- esp-hal/src/aes/mod.rs | 4 +- esp-hal/src/analog/adc/calibration/basic.rs | 2 +- esp-hal/src/analog/adc/calibration/line.rs | 4 +- esp-hal/src/analog/adc/mod.rs | 6 +- esp-hal/src/analog/adc/riscv.rs | 24 +++--- esp-hal/src/analog/adc/xtensa.rs | 24 +++--- esp-hal/src/assist_debug.rs | 8 +- esp-hal/src/dma/gdma.rs | 4 +- esp-hal/src/dma/mod.rs | 8 +- esp-hal/src/dma/pdma.rs | 8 +- esp-hal/src/gpio/interconnect.rs | 2 +- esp-hal/src/gpio/mod.rs | 70 +++++++-------- esp-hal/src/interrupt/riscv.rs | 40 ++++----- esp-hal/src/interrupt/xtensa.rs | 22 ++--- esp-hal/src/ledc/channel.rs | 12 +-- esp-hal/src/ledc/mod.rs | 8 +- esp-hal/src/ledc/timer.rs | 26 +++--- esp-hal/src/lib.rs | 14 +-- esp-hal/src/mcpwm/operator.rs | 10 +-- esp-hal/src/pcnt/unit.rs | 6 +- esp-hal/src/reset.rs | 8 +- esp-hal/src/rtc_cntl/mod.rs | 40 ++++----- esp-hal/src/rtc_cntl/rtc/esp32c3.rs | 5 +- esp-hal/src/rtc_cntl/rtc/esp32c6.rs | 27 +++--- esp-hal/src/rtc_cntl/rtc/esp32h2.rs | 17 ++-- esp-hal/src/rtc_cntl/rtc/esp32s2.rs | 5 +- esp-hal/src/rtc_cntl/rtc/esp32s3.rs | 5 +- esp-hal/src/rtc_cntl/sleep/esp32.rs | 2 +- esp-hal/src/rtc_cntl/sleep/esp32c2.rs | 2 +- esp-hal/src/rtc_cntl/sleep/esp32c3.rs | 2 +- esp-hal/src/rtc_cntl/sleep/esp32c6.rs | 2 +- esp-hal/src/rtc_cntl/sleep/esp32s3.rs | 2 +- esp-hal/src/soc/esp32/cpu_control.rs | 2 +- esp-hal/src/soc/esp32/efuse/mod.rs | 8 +- esp-hal/src/soc/esp32/gpio.rs | 14 +-- esp-hal/src/soc/esp32/mod.rs | 2 +- esp-hal/src/soc/esp32/psram.rs | 4 +- esp-hal/src/soc/esp32c2/efuse/mod.rs | 20 ++--- esp-hal/src/soc/esp32c2/gpio.rs | 5 +- esp-hal/src/soc/esp32c3/efuse/mod.rs | 20 ++--- esp-hal/src/soc/esp32c3/gpio.rs | 4 +- esp-hal/src/soc/esp32c6/efuse/mod.rs | 20 ++--- esp-hal/src/soc/esp32c6/gpio.rs | 4 +- esp-hal/src/soc/esp32h2/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32h2/gpio.rs | 4 +- esp-hal/src/soc/esp32s2/efuse/mod.rs | 4 +- esp-hal/src/soc/esp32s2/gpio.rs | 4 +- esp-hal/src/soc/esp32s2/mod.rs | 2 +- esp-hal/src/soc/esp32s3/cpu_control.rs | 2 +- esp-hal/src/soc/esp32s3/efuse/mod.rs | 20 ++--- esp-hal/src/soc/esp32s3/gpio.rs | 4 +- esp-hal/src/soc/esp32s3/mod.rs | 2 +- esp-hal/src/soc/esp32s3/psram.rs | 26 +++--- esp-hal/src/soc/mod.rs | 2 +- esp-hal/src/sync.rs | 4 +- esp-hal/src/timer/systimer.rs | 6 +- esp-hal/src/touch.rs | 12 +-- esp-ieee802154/CHANGELOG.md | 2 + esp-ieee802154/src/hal.rs | 8 +- esp-ieee802154/src/lib.rs | 4 +- esp-ieee802154/src/raw.rs | 12 ++- esp-lp-hal/src/uart.rs | 14 +-- esp-wifi/CHANGELOG.md | 1 + esp-wifi/MIGRATING-0.10.md | 8 +- esp-wifi/src/ble/controller/mod.rs | 2 +- .../common_adapter/common_adapter_esp32.rs | 5 +- esp-wifi/src/common_adapter/mod.rs | 2 +- esp-wifi/src/compat/common.rs | 4 +- esp-wifi/src/compat/timer_compat.rs | 2 +- esp-wifi/src/esp_now/mod.rs | 12 +-- esp-wifi/src/tasks.rs | 4 +- esp-wifi/src/timer/mod.rs | 2 +- esp-wifi/src/timer/riscv.rs | 2 +- esp-wifi/src/timer/xtensa.rs | 2 +- esp-wifi/src/wifi/mod.rs | 22 ++--- esp-wifi/src/wifi/os_adapter.rs | 4 +- esp-wifi/src/wifi/state.rs | 14 +-- examples/src/bin/debug_assist.rs | 6 +- examples/src/bin/embassy_multicore.rs | 9 +- .../src/bin/embassy_multicore_interrupt.rs | 9 +- .../src/bin/ieee802154_receive_all_frames.rs | 2 +- examples/src/bin/ieee802154_receive_frame.rs | 2 +- examples/src/bin/ieee802154_sniffer.rs | 2 +- examples/src/bin/ledc.rs | 4 +- examples/src/bin/pcnt_encoder.rs | 2 +- examples/src/bin/read_efuse.rs | 10 +-- examples/src/bin/sleep_timer.rs | 6 +- examples/src/bin/sleep_timer_ext0.rs | 8 +- examples/src/bin/sleep_timer_ext1.rs | 8 +- examples/src/bin/sleep_timer_lpio.rs | 8 +- examples/src/bin/sleep_timer_rtcio.rs | 8 +- examples/src/bin/wifi_access_point.rs | 2 +- .../src/bin/wifi_access_point_with_sta.rs | 2 +- examples/src/bin/wifi_bench.rs | 2 +- examples/src/bin/wifi_coex.rs | 2 +- examples/src/bin/wifi_csi.rs | 2 +- examples/src/bin/wifi_dhcp.rs | 2 +- examples/src/bin/wifi_dhcp_smoltcp_nal.rs | 2 +- examples/src/bin/wifi_embassy_access_point.rs | 4 +- .../bin/wifi_embassy_access_point_with_sta.rs | 4 +- examples/src/bin/wifi_embassy_bench.rs | 4 +- examples/src/bin/wifi_embassy_dhcp.rs | 4 +- examples/src/bin/wifi_embassy_esp_now.rs | 2 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 2 +- examples/src/bin/wifi_esp_now.rs | 2 +- examples/src/bin/wifi_static_ip.rs | 2 +- hil-test/tests/lcd_cam_i8080.rs | 16 ++-- hil-test/tests/parl_io_tx.rs | 8 +- hil-test/tests/parl_io_tx_async.rs | 8 +- hil-test/tests/pcnt.rs | 86 +++++++++---------- hil-test/tests/qspi.rs | 20 ++--- hil-test/tests/spi_full_duplex.rs | 12 +-- hil-test/tests/spi_half_duplex_write.rs | 8 +- hil-test/tests/spi_half_duplex_write_psram.rs | 8 +- hil-test/tests/spi_slave.rs | 2 +- 120 files changed, 526 insertions(+), 535 deletions(-) diff --git a/esp-hal-embassy/src/executor/interrupt.rs b/esp-hal-embassy/src/executor/interrupt.rs index 28ce6ccd574..335d130dcb3 100644 --- a/esp-hal-embassy/src/executor/interrupt.rs +++ b/esp-hal-embassy/src/executor/interrupt.rs @@ -4,7 +4,7 @@ use core::{cell::UnsafeCell, mem::MaybeUninit}; use embassy_executor::{raw, SendSpawner}; use esp_hal::{ - get_core, + core, interrupt::{self, software::SoftwareInterrupt, InterruptHandler}, }; use portable_atomic::{AtomicUsize, Ordering}; @@ -87,7 +87,7 @@ impl InterruptExecutor { .core .compare_exchange( usize::MAX, - get_core() as usize, + core() as usize, Ordering::Acquire, Ordering::Relaxed, ) diff --git a/esp-hal-embassy/src/executor/thread.rs b/esp-hal-embassy/src/executor/thread.rs index b279c6d417b..0aefdfb2c41 100644 --- a/esp-hal-embassy/src/executor/thread.rs +++ b/esp-hal-embassy/src/executor/thread.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use embassy_executor::{raw, Spawner}; -use esp_hal::{get_core, Cpu}; +use esp_hal::{core, Cpu}; #[cfg(multi_core)] use esp_hal::{interrupt::software::SoftwareInterrupt, macros::handler}; #[cfg(low_power_wait)] @@ -35,7 +35,7 @@ pub(crate) fn pend_thread_mode(_core: usize) { // If we are pending a task on the current core, we're done. Otherwise, we // need to make sure the other core wakes up. #[cfg(multi_core)] - if _core != get_core() as usize { + if _core != core() as usize { // We need to clear the interrupt from software. We don't actually // need it to trigger and run the interrupt handler, we just need to // kick waiti to return. @@ -74,7 +74,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa } Self { - inner: raw::Executor::new((THREAD_MODE_CONTEXT + get_core() as usize) as *mut ()), + inner: raw::Executor::new((THREAD_MODE_CONTEXT + core() as usize) as *mut ()), not_send: PhantomData, } } @@ -103,7 +103,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa init(self.inner.spawner()); #[cfg(low_power_wait)] - let cpu = get_core() as usize; + let cpu = core() as usize; loop { unsafe { self.inner.poll() }; diff --git a/esp-hal-procmacros/src/lp_core.rs b/esp-hal-procmacros/src/lp_core.rs index 5fa639d7e92..60a3b351cc1 100644 --- a/esp-hal-procmacros/src/lp_core.rs +++ b/esp-hal-procmacros/src/lp_core.rs @@ -31,7 +31,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { res } - pub(crate) fn get_simplename(t: &Type) -> String { + pub(crate) fn simplename(t: &Type) -> String { match t { Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(), _ => String::new(), @@ -125,7 +125,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { .into(); } FnArg::Typed(t) => { - match get_simplename(&t.ty).as_str() { + match simplename(&t.ty).as_str() { "Output" => { let pin = extract_pin(&t.ty); if used_pins.contains(&pin) { diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 5acacce017a..e113cf3ca11 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - A new config option `PLACE_SWITCH_TABLES_IN_RAM` to improve performance (especially for interrupts) at the cost of slightly more RAM usage (#2331) - A new config option `PLACE_ANON_IN_RAM` to improve performance (especially for interrupts) at the cost of RAM usage (#2331) - Add burst transfer support to DMA buffers (#2336) @@ -63,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `I2c` master driver has been moved from `esp_hal::i2c` to `esp_hal::i2c::master`. (#2476) - `I2c` SCL timeout is now defined in bus clock cycles. (#2477) - Trying to send a single-shot RMT transmission will result in an error now, `RMT` deals with `u32` now, `PulseCode` is a convenience trait now (#2463) +- Removed `get_` prefixes from functions (#2528) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index f24b6bef02c..a97b25b020a 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -223,6 +223,7 @@ You can now use the `UartInterrupt` enum and the corresponding `listen`, `unlist Use `interrupts` in place of `_interrupt_set` and `clear_interrupts` in place of the old `reset_` functions. `UartInterrupt`: + - `AtCmd` - `TxDone` - `RxFifoFull` @@ -359,6 +360,7 @@ refer to the `Config` struct as `uart::Config`. ## I8080 driver split `set_byte_order()` into `set_8bits_order()` and `set_byte_order()`. If you were using an 8-bit bus. + ```diff - i8080.set_byte_order(ByteOrder::default()); + i8080.set_8bits_order(ByteOrder::default()); @@ -369,7 +371,6 @@ If you were using an 16-bit bus, you don't need to change anything, `set_byte_or If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when you switch between devices. Be sure to read the documentation of the new methods. - ## `rmt::Channel::transmit` now returns `Result`, `PulseCode` is now `u32` When trying to send a one-shot transmission will fail if it doesn't end with an end-marker. @@ -412,3 +413,9 @@ You can use `gpio::NoPin` instead. +let mut rx_clk_pin = NoPin; +parl_io.rx.with_config(&mut rx_pins, &mut rx_clk_pin, BitPackOrder::Msb, Some(0xfff)) ``` + +## `get_` prefixes have been removed from functions + +In order to better comply with the Rust API Guidelines [getter names convention], we have removed the `get_` prefixes from all functions which previously had it. Due to the number of changes it's not practical to list all changes here, however if a function previous began with `get_`, you can simply remove this prefix. + +[getter names convention]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index eac8f95066a..e6815b8877b 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -166,7 +166,7 @@ impl<'d> Aes<'d> { self.set_block(block); self.start(); while !(self.is_idle()) {} - self.get_block(block); + self.block(block); } fn set_mode(&mut self, mode: u8) { @@ -181,7 +181,7 @@ impl<'d> Aes<'d> { self.write_block(block); } - fn get_block(&self, block: &mut [u8; 16]) { + fn block(&self, block: &mut [u8; 16]) { self.read_block(block); } diff --git a/esp-hal/src/analog/adc/calibration/basic.rs b/esp-hal/src/analog/adc/calibration/basic.rs index 4943d6648e8..643653d5178 100644 --- a/esp-hal/src/analog/adc/calibration/basic.rs +++ b/esp-hal/src/analog/adc/calibration/basic.rs @@ -36,7 +36,7 @@ where fn new_cal(atten: Attenuation) -> Self { // Try to get init code (Dout0) from efuse // Dout0 means mean raw ADC value when zero voltage applied to input. - let cal_val = ADCI::get_init_code(atten).unwrap_or_else(|| { + let cal_val = ADCI::init_code(atten).unwrap_or_else(|| { // As a fallback try to calibrate via connecting input to ground internally. AdcConfig::::adc_calibrate(atten, AdcCalSource::Gnd) }); diff --git a/esp-hal/src/analog/adc/calibration/line.rs b/esp-hal/src/analog/adc/calibration/line.rs index 64b0105bc6f..ea6bf66f3b1 100644 --- a/esp-hal/src/analog/adc/calibration/line.rs +++ b/esp-hal/src/analog/adc/calibration/line.rs @@ -59,8 +59,8 @@ where // Try get the reference point (Dout, Vin) from efuse // Dout means mean raw ADC value when specified Vin applied to input. - let (code, mv) = ADCI::get_cal_code(atten) - .map(|code| (code, ADCI::get_cal_mv(atten))) + let (code, mv) = ADCI::cal_code(atten) + .map(|code| (code, ADCI::cal_mv(atten))) .unwrap_or_else(|| { // As a fallback try to calibrate using reference voltage source. // This method is not too good because actual reference voltage may varies diff --git a/esp-hal/src/analog/adc/mod.rs b/esp-hal/src/analog/adc/mod.rs index 0f8f76067c5..a0b3193cdcc 100644 --- a/esp-hal/src/analog/adc/mod.rs +++ b/esp-hal/src/analog/adc/mod.rs @@ -235,17 +235,17 @@ trait AdcCalEfuse { /// Get ADC calibration init code /// /// Returns digital value for zero voltage for a given attenuation - fn get_init_code(atten: Attenuation) -> Option; + fn init_code(atten: Attenuation) -> Option; /// Get ADC calibration reference point voltage /// /// Returns reference voltage (millivolts) for a given attenuation - fn get_cal_mv(atten: Attenuation) -> u16; + fn cal_mv(atten: Attenuation) -> u16; /// Get ADC calibration reference point digital value /// /// Returns digital value for reference voltage for a given attenuation - fn get_cal_code(atten: Attenuation) -> Option; + fn cal_code(atten: Attenuation) -> Option; } macro_rules! impl_adc_interface { diff --git a/esp-hal/src/analog/adc/riscv.rs b/esp-hal/src/analog/adc/riscv.rs index 6b54131600a..c9c4bcdd655 100644 --- a/esp-hal/src/analog/adc/riscv.rs +++ b/esp-hal/src/analog/adc/riscv.rs @@ -502,31 +502,31 @@ where #[cfg(any(esp32c2, esp32c3, esp32c6))] impl super::AdcCalEfuse for crate::peripherals::ADC1 { - fn get_init_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_init_code(1, atten) + fn init_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_init_code(1, atten) } - fn get_cal_mv(atten: Attenuation) -> u16 { - Efuse::get_rtc_calib_cal_mv(1, atten) + fn cal_mv(atten: Attenuation) -> u16 { + Efuse::rtc_calib_cal_mv(1, atten) } - fn get_cal_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_cal_code(1, atten) + fn cal_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_cal_code(1, atten) } } #[cfg(esp32c3)] impl super::AdcCalEfuse for crate::peripherals::ADC2 { - fn get_init_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_init_code(2, atten) + fn init_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_init_code(2, atten) } - fn get_cal_mv(atten: Attenuation) -> u16 { - Efuse::get_rtc_calib_cal_mv(2, atten) + fn cal_mv(atten: Attenuation) -> u16 { + Efuse::rtc_calib_cal_mv(2, atten) } - fn get_cal_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_cal_code(2, atten) + fn cal_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_cal_code(2, atten) } } diff --git a/esp-hal/src/analog/adc/xtensa.rs b/esp-hal/src/analog/adc/xtensa.rs index bc9d6ef3202..324c79462db 100644 --- a/esp-hal/src/analog/adc/xtensa.rs +++ b/esp-hal/src/analog/adc/xtensa.rs @@ -562,31 +562,31 @@ where #[cfg(esp32s3)] impl super::AdcCalEfuse for crate::peripherals::ADC1 { - fn get_init_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_init_code(1, atten) + fn init_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_init_code(1, atten) } - fn get_cal_mv(atten: Attenuation) -> u16 { - Efuse::get_rtc_calib_cal_mv(1, atten) + fn cal_mv(atten: Attenuation) -> u16 { + Efuse::rtc_calib_cal_mv(1, atten) } - fn get_cal_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_cal_code(1, atten) + fn cal_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_cal_code(1, atten) } } #[cfg(esp32s3)] impl super::AdcCalEfuse for crate::peripherals::ADC2 { - fn get_init_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_init_code(2, atten) + fn init_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_init_code(2, atten) } - fn get_cal_mv(atten: Attenuation) -> u16 { - Efuse::get_rtc_calib_cal_mv(2, atten) + fn cal_mv(atten: Attenuation) -> u16 { + Efuse::rtc_calib_cal_mv(2, atten) } - fn get_cal_code(atten: Attenuation) -> Option { - Efuse::get_rtc_calib_cal_code(2, atten) + fn cal_code(atten: Attenuation) -> Option { + Efuse::rtc_calib_cal_code(2, atten) } } diff --git a/esp-hal/src/assist_debug.rs b/esp-hal/src/assist_debug.rs index 945d1e87ce6..d99a0334613 100644 --- a/esp-hal/src/assist_debug.rs +++ b/esp-hal/src/assist_debug.rs @@ -136,7 +136,7 @@ impl DebugAssist<'_> { } /// Get SP monitoring PC value on main core. - pub fn get_sp_monitor_pc(&self) -> u32 { + pub fn sp_monitor_pc(&self) -> u32 { self.debug_assist .core_0_sp_pc() .read() @@ -219,7 +219,7 @@ impl<'d> DebugAssist<'d> { } /// Get SP monitoring PC value on secondary core. - pub fn get_core1_sp_monitor_pc(&self) -> u32 { + pub fn core1_sp_monitor_pc(&self) -> u32 { self.debug_assist.core_1_sp_pc.read().core_1_sp_pc().bits() } } @@ -382,7 +382,7 @@ impl DebugAssist<'_> { } /// Get region monitoring PC value on main core. - pub fn get_region_monitor_pc(&self) -> u32 { + pub fn region_monitor_pc(&self) -> u32 { self.debug_assist .core_0_area_pc() .read() @@ -548,7 +548,7 @@ impl<'d> DebugAssist<'d> { } /// Get region monitoring PC value on secondary core. - pub fn get_core1_region_monitor_pc(&self) -> u32 { + pub fn core1_region_monitor_pc(&self) -> u32 { self.debug_assist .core_1_area_pc() .read() diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 8b5c387eadf..8ac8b6b4731 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -522,11 +522,11 @@ macro_rules! impl_channel { } impl DmaChannelExt for [] { - fn get_rx_interrupts() -> impl InterruptAccess { + fn rx_interrupts() -> impl InterruptAccess { ChannelRxImpl(SpecificGdmaChannel::<$num> {}) } - fn get_tx_interrupts() -> impl InterruptAccess { + fn tx_interrupts() -> impl InterruptAccess { ChannelTxImpl(SpecificGdmaChannel::<$num> {}) } } diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index e88776e423b..6deca41d657 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -1581,8 +1581,8 @@ pub trait DmaChannel: crate::private::Sealed + Sized { #[doc(hidden)] pub trait DmaChannelExt: DmaChannel { - fn get_rx_interrupts() -> impl InterruptAccess; - fn get_tx_interrupts() -> impl InterruptAccess; + fn rx_interrupts() -> impl InterruptAccess; + fn tx_interrupts() -> impl InterruptAccess; } #[diagnostic::on_unimplemented( @@ -2885,8 +2885,8 @@ pub(crate) mod asynch { } fn handle_interrupt() { - let rx = CH::get_rx_interrupts(); - let tx = CH::get_tx_interrupts(); + let rx = CH::rx_interrupts(); + let tx = CH::tx_interrupts(); if rx.pending_interrupts().is_disjoint( DmaRxInterrupt::DescriptorError diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 098da68add1..bfbaee48dfc 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -367,10 +367,10 @@ macro_rules! ImplSpiChannel { } impl DmaChannelExt for [] { - fn get_rx_interrupts() -> impl InterruptAccess { + fn rx_interrupts() -> impl InterruptAccess { SpiDmaRxChannelImpl(Self {}) } - fn get_tx_interrupts() -> impl InterruptAccess { + fn tx_interrupts() -> impl InterruptAccess { SpiDmaTxChannelImpl(Self {}) } } @@ -780,10 +780,10 @@ macro_rules! ImplI2sChannel { } impl DmaChannelExt for [] { - fn get_rx_interrupts() -> impl InterruptAccess { + fn rx_interrupts() -> impl InterruptAccess { I2sDmaRxChannelImpl(Self {}) } - fn get_tx_interrupts() -> impl InterruptAccess { + fn tx_interrupts() -> impl InterruptAccess { I2sDmaTxChannelImpl(Self {}) } } diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index e07e8d97ec8..c63c37ecc68 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -268,7 +268,7 @@ impl InputSignal { } /// Returns the current signal level. - pub fn get_level(&self) -> Level { + pub fn level(&self) -> Level { self.is_input_high(private::Internal).into() } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index c15dacbe529..1a329590450 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -343,13 +343,13 @@ pub trait Pin: Sealed { /// Enable/disable sleep-mode #[doc(hidden)] fn sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.slp_sel().bit(on)); + io_mux_reg(self.number()).modify(|_, w| w.slp_sel().bit(on)); } /// Configure the alternate function #[doc(hidden)] fn set_alternate_function(&mut self, alternate: AlternateFunction, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8) }); + io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8) }); } /// Enable or disable the GPIO pin output buffer. @@ -362,7 +362,7 @@ pub trait Pin: Sealed { /// Enable input for the pin #[doc(hidden)] fn enable_input(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.fun_ie().bit(on)); + io_mux_reg(self.number()).modify(|_, w| w.fun_ie().bit(on)); } #[doc(hidden)] @@ -382,7 +382,7 @@ pub trait Pin: Sealed { #[cfg(esp32)] crate::soc::gpio::errata36(self.degrade_pin(private::Internal), pull_up, pull_down); - get_io_mux_reg(self.number()).modify(|_, w| { + io_mux_reg(self.number()).modify(|_, w| { w.fun_wpd().bit(pull_down); w.fun_wpu().bit(pull_up) }); @@ -399,7 +399,7 @@ pub trait InputPin: Pin + Into + 'static { #[cfg(usb_device)] disable_usb_pads(self.number()); - get_io_mux_reg(self.number()).modify(|_, w| unsafe { + io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(GPIO_FUNCTION as u8); w.fun_ie().set_bit(); w.slp_sel().clear_bit() @@ -437,7 +437,7 @@ pub trait OutputPin: Pin + Into + 'static { #[cfg(any(esp32c3, esp32s3))] disable_usb_pads(self.number()); - get_io_mux_reg(self.number()).modify(|_, w| unsafe { + io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8); if let Some(input_enable) = input_enable { w.fun_ie().bit(input_enable); @@ -469,7 +469,7 @@ pub trait OutputPin: Pin + Into + 'static { /// Configure the [DriveStrength] of the pin #[doc(hidden)] fn set_drive_strength(&mut self, strength: DriveStrength, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) }); + io_mux_reg(self.number()).modify(|_, w| unsafe { w.fun_drv().bits(strength as u8) }); } /// Enable/disable open-drain mode @@ -483,13 +483,13 @@ pub trait OutputPin: Pin + Into + 'static { /// Configure internal pull-up resistor in sleep mode #[doc(hidden)] fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_wpu().bit(on)); + io_mux_reg(self.number()).modify(|_, w| w.mcu_wpu().bit(on)); } /// Configure internal pull-down resistor in sleep mode #[doc(hidden)] fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_wpd().bit(on)); + io_mux_reg(self.number()).modify(|_, w| w.mcu_wpd().bit(on)); } /// Is the output set to high @@ -514,11 +514,11 @@ pub trait TouchPin: Pin { /// Reads the pin's touch measurement register #[doc(hidden)] - fn get_touch_measurement(&self, _: private::Internal) -> u16; + fn touch_measurement(&self, _: private::Internal) -> u16; /// Maps the pin nr to the touch pad nr #[doc(hidden)] - fn get_touch_nr(&self, _: private::Internal) -> u8; + fn touch_nr(&self, _: private::Internal) -> u8; /// Set a pins touch threshold for interrupts. #[doc(hidden)] @@ -929,7 +929,7 @@ macro_rules! io_type { fn set_analog(&self, _: $crate::private::Internal) { use $crate::peripherals::GPIO; - $crate::gpio::get_io_mux_reg($gpionum).modify(|_, w| unsafe { + $crate::gpio::io_mux_reg($gpionum).modify(|_, w| unsafe { w.mcu_sel().bits(1); w.fun_ie().clear_bit(); w.fun_wpu().clear_bit(); @@ -1195,19 +1195,19 @@ where /// Is the output pin set as high? #[inline] pub fn is_set_high(&self) -> bool { - self.get_output_level() == Level::High + self.output_level() == Level::High } /// Is the output pin set as low? #[inline] pub fn is_set_low(&self) -> bool { - self.get_output_level() == Level::Low + self.output_level() == Level::Low } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { - self.pin.get_output_level() + pub fn output_level(&self) -> Level { + self.pin.output_level() } /// Toggle pin output @@ -1273,19 +1273,19 @@ where /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { - self.get_level() == Level::High + self.level() == Level::High } /// Get whether the pin input level is low. #[inline] pub fn is_low(&self) -> bool { - self.get_level() == Level::Low + self.level() == Level::Low } /// Get the current pin input level. #[inline] - pub fn get_level(&self) -> Level { - self.pin.get_level() + pub fn level(&self) -> Level { + self.pin.level() } /// Listen for interrupts @@ -1417,19 +1417,19 @@ where /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { - self.get_level() == Level::High + self.level() == Level::High } /// Get whether the pin input level is low. #[inline] pub fn is_low(&self) -> bool { - self.get_level() == Level::Low + self.level() == Level::Low } /// Get the current pin input level. #[inline] - pub fn get_level(&self) -> Level { - self.pin.get_level() + pub fn level(&self) -> Level { + self.pin.level() } /// Listen for interrupts @@ -1465,19 +1465,19 @@ where /// Is the output pin set as high? #[inline] pub fn is_set_high(&self) -> bool { - self.get_output_level() == Level::High + self.output_level() == Level::High } /// Is the output pin set as low? #[inline] pub fn is_set_low(&self) -> bool { - self.get_output_level() == Level::Low + self.output_level() == Level::Low } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { - self.pin.get_output_level() + pub fn output_level(&self) -> Level { + self.pin.output_level() } /// Toggle pin output @@ -1552,18 +1552,18 @@ where /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { - self.get_level() == Level::High + self.level() == Level::High } /// Get whether the pin input level is low. #[inline] pub fn is_low(&self) -> bool { - self.get_level() == Level::Low + self.level() == Level::Low } /// Get the current pin input level. #[inline] - pub fn get_level(&self) -> Level { + pub fn level(&self) -> Level { self.pin.is_input_high(private::Internal).into() } @@ -1659,25 +1659,25 @@ where /// Is the output pin set as high? #[inline] pub fn is_set_high(&self) -> bool { - self.get_output_level() == Level::High + self.output_level() == Level::High } /// Is the output pin set as low? #[inline] pub fn is_set_low(&self) -> bool { - self.get_output_level() == Level::Low + self.output_level() == Level::Low } /// What level output is set to #[inline] - pub fn get_output_level(&self) -> Level { + pub fn output_level(&self) -> Level { self.pin.is_set_high(private::Internal).into() } /// Toggle pin output #[inline] pub fn toggle(&mut self) { - let level = !self.get_output_level(); + let level = !self.output_level(); self.set_level(level); } diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index de55b303e8f..a1ea6d78bcc 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -239,8 +239,8 @@ pub fn enable_direct( return Err(Error::InvalidInterruptPriority); } unsafe { - map(crate::get_core(), interrupt, cpu_interrupt); - set_priority(crate::get_core(), cpu_interrupt, level); + map(crate::core(), interrupt, cpu_interrupt); + set_priority(crate::core(), cpu_interrupt, level); enable_cpu_interrupt(cpu_interrupt); } Ok(()) @@ -262,7 +262,7 @@ pub fn disable(_core: Cpu, interrupt: Interrupt) { /// Get status of peripheral interrupts #[inline] -pub fn get_status(_core: Cpu) -> InterruptStatus { +pub fn status(_core: Cpu) -> InterruptStatus { #[cfg(large_intr_status)] unsafe { InterruptStatus::from( @@ -341,7 +341,7 @@ pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { /// Get cpu interrupt assigned to peripheral interrupt #[inline] -unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option { +unsafe fn assigned_cpu_interrupt(interrupt: Interrupt) -> Option { let interrupt_number = interrupt as isize; let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; @@ -356,7 +356,7 @@ unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option Option { - unsafe { get_assigned_cpu_interrupt(interrupt) } + unsafe { assigned_cpu_interrupt(interrupt) } } mod vectored { @@ -369,12 +369,12 @@ mod vectored { pub(crate) unsafe fn init_vectoring() { for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() { set_kind( - crate::get_core(), + crate::core(), core::mem::transmute::(*num as u32), InterruptKind::Level, ); set_priority( - crate::get_core(), + crate::core(), core::mem::transmute::(*num as u32), core::mem::transmute::((prio as u8) + 1), ); @@ -385,7 +385,7 @@ mod vectored { /// Get the interrupts configured for the core at the given priority /// matching the given status #[inline] - fn get_configured_interrupts( + fn configured_interrupts( core: Cpu, status: InterruptStatus, priority: Priority, @@ -396,11 +396,11 @@ mod vectored { for interrupt_nr in status.iterator() { // safety: cast is safe because of repr(u16) if let Some(cpu_interrupt) = - get_assigned_cpu_interrupt(core::mem::transmute::( + assigned_cpu_interrupt(core::mem::transmute::( interrupt_nr as u16, )) { - if get_priority_by_core(core, cpu_interrupt) == priority { + if priority_by_core(core, cpu_interrupt) == priority { res.set(interrupt_nr as u16); } } @@ -421,7 +421,7 @@ mod vectored { let cpu_interrupt = core::mem::transmute::( PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32, ); - map(crate::get_core(), interrupt, cpu_interrupt); + map(crate::core(), interrupt, cpu_interrupt); enable_cpu_interrupt(cpu_interrupt); } Ok(()) @@ -453,15 +453,15 @@ mod vectored { #[no_mangle] #[ram] unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { - let core = crate::get_core(); - let status = get_status(core); + let core = crate::core(); + let status = status(core); // this has no effect on level interrupts, but the interrupt may be an edge one // so we clear it anyway clear(core, cpu_intr); let prio: Priority = unsafe { core::mem::transmute(INTERRUPT_TO_PRIORITY[cpu_intr as usize - 1] as u8) }; - let configured_interrupts = get_configured_interrupts(core, status, prio); + let configured_interrupts = configured_interrupts(core, status, prio); for interrupt_nr in configured_interrupts.iterator() { // Don't use `Interrupt::try_from`. It's slower and placed in flash @@ -639,13 +639,13 @@ mod classic { /// Get interrupt priority #[inline] - pub(super) fn get_priority_by_core(_core: Cpu, cpu_interrupt: CpuInterrupt) -> Priority { - unsafe { get_priority(cpu_interrupt) } + pub(super) fn priority_by_core(_core: Cpu, cpu_interrupt: CpuInterrupt) -> Priority { + unsafe { priority(cpu_interrupt) } } /// Get interrupt priority - called by assembly code #[inline] - pub(super) unsafe extern "C" fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { + pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { let intr = &*crate::peripherals::INTERRUPT_CORE0::PTR; core::mem::transmute::( intr.cpu_int_pri(cpu_interrupt as usize).read().map().bits(), @@ -771,16 +771,16 @@ mod plic { /// Get interrupt priority #[inline] - pub(super) unsafe extern "C" fn get_priority_by_core( + pub(super) unsafe extern "C" fn priority_by_core( _core: Cpu, cpu_interrupt: CpuInterrupt, ) -> Priority { - unsafe { get_priority(cpu_interrupt) } + unsafe { priority(cpu_interrupt) } } /// Get interrupt priority - called by assembly code #[inline] - pub(super) unsafe extern "C" fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { + pub(super) unsafe extern "C" fn priority(cpu_interrupt: CpuInterrupt) -> Priority { let plic = &*crate::peripherals::PLIC_MX::PTR; let prio = plic .mxint_pri(cpu_interrupt as usize) diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index c83d1e75011..a6d0c03e60e 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -156,7 +156,7 @@ pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Resul return Err(Error::CpuInterruptReserved); } unsafe { - map(crate::get_core(), interrupt, cpu_interrupt); + map(crate::core(), interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, @@ -230,7 +230,7 @@ pub fn clear(_core: Cpu, which: CpuInterrupt) { /// Get status of peripheral interrupts #[cfg(large_intr_status)] -pub fn get_status(core: Cpu) -> InterruptStatus { +pub fn status(core: Cpu) -> InterruptStatus { unsafe { match core { Cpu::ProCpu => InterruptStatus::from( @@ -268,7 +268,7 @@ pub fn get_status(core: Cpu) -> InterruptStatus { /// Get status of peripheral interrupts #[cfg(very_large_intr_status)] -pub fn get_status(core: Cpu) -> InterruptStatus { +pub fn status(core: Cpu) -> InterruptStatus { unsafe { match core { Cpu::ProCpu => InterruptStatus::from( @@ -338,7 +338,7 @@ mod vectored { use procmacros::ram; use super::*; - use crate::get_core; + use crate::core; /// Interrupt priority levels. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -414,11 +414,7 @@ mod vectored { /// Get the interrupts configured for the core #[inline(always)] - fn get_configured_interrupts( - core: Cpu, - status: InterruptStatus, - level: u32, - ) -> InterruptStatus { + fn configured_interrupts(core: Cpu, status: InterruptStatus, level: u32) -> InterruptStatus { unsafe { let intr_map_base = match core { Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map().as_ptr(), @@ -451,7 +447,7 @@ mod vectored { interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; unsafe { - map(get_core(), interrupt, cpu_interrupt); + map(core(), interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, @@ -545,7 +541,7 @@ mod vectored { #[no_mangle] #[ram] unsafe fn handle_interrupts(level: u32, save_frame: &mut Context) { - let core = crate::get_core(); + let core = crate::core(); let cpu_interrupt_mask = interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize]; @@ -583,10 +579,10 @@ mod vectored { } else { // Finally, check level-triggered peripheral sources. // These interrupts are cleared by the peripheral. - get_status(core) + status(core) }; - let configured_interrupts = get_configured_interrupts(core, status, level); + let configured_interrupts = configured_interrupts(core, status, level); for interrupt_nr in configured_interrupts.iterator() { // Don't use `Interrupt::try_from`. It's slower and placed in flash let interrupt: Interrupt = unsafe { core::mem::transmute(interrupt_nr as u16) }; diff --git a/esp-hal/src/ledc/channel.rs b/esp-hal/src/ledc/channel.rs index fb7f6448c08..73267fc9a5b 100644 --- a/esp-hal/src/ledc/channel.rs +++ b/esp-hal/src/ledc/channel.rs @@ -189,7 +189,7 @@ where fn set_duty(&self, duty_pct: u8) -> Result<(), Error> { let duty_exp; if let Some(timer) = self.timer { - if let Some(timer_duty) = timer.get_duty() { + if let Some(timer_duty) = timer.duty() { duty_exp = timer_duty as u32; } else { return Err(Error::Timer); @@ -238,10 +238,10 @@ where return Err(Error::Fade(FadeError::EndDuty)); } if let Some(timer) = self.timer { - if let Some(timer_duty) = timer.get_duty() { - if timer.get_frequency() > 0 { + if let Some(timer_duty) = timer.duty() { + if timer.frequency() > 0 { duty_exp = timer_duty as u32; - frequency = timer.get_frequency(); + frequency = timer.frequency(); } else { return Err(Error::Timer); } @@ -323,7 +323,7 @@ mod ehal1 { fn max_duty_cycle(&self) -> u16 { let duty_exp; - if let Some(timer_duty) = self.timer.and_then(|timer| timer.get_duty()) { + if let Some(timer_duty) = self.timer.and_then(|timer| timer.duty()) { duty_exp = timer_duty as u32; } else { return 0; @@ -571,7 +571,7 @@ where .set_to_open_drain_output(crate::private::Internal), }; - let timer_number = timer.get_number() as u8; + let timer_number = timer.number() as u8; self.set_channel(timer_number); self.update_channel(); diff --git a/esp-hal/src/ledc/mod.rs b/esp-hal/src/ledc/mod.rs index 54797a42880..98b95ff72cd 100644 --- a/esp-hal/src/ledc/mod.rs +++ b/esp-hal/src/ledc/mod.rs @@ -34,7 +34,7 @@ //! let mut ledc = Ledc::new(peripherals.LEDC); //! ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); //! -//! let mut lstimer0 = ledc.get_timer::(timer::Number::Timer0); +//! let mut lstimer0 = ledc.timer::(timer::Number::Timer0); //! lstimer0 //! .configure(timer::config::Config { //! duty: timer::config::Duty::Duty5Bit, @@ -43,7 +43,7 @@ //! }) //! .unwrap(); //! -//! let mut channel0 = ledc.get_channel(channel::Number::Channel0, led); +//! let mut channel0 = ledc.channel(channel::Number::Channel0, led); //! channel0 //! .configure(channel::config::Config { //! timer: &lstimer0, @@ -158,12 +158,12 @@ impl<'d> Ledc<'d> { } /// Return a new timer - pub fn get_timer(&self, number: timer::Number) -> Timer<'d, S> { + pub fn timer(&self, number: timer::Number) -> Timer<'d, S> { Timer::new(self.ledc, number) } /// Return a new channel - pub fn get_channel( + pub fn channel( &self, number: channel::Number, output_pin: impl Peripheral

+ 'd, diff --git a/esp-hal/src/ledc/timer.rs b/esp-hal/src/ledc/timer.rs index 051520c6e10..30bf8082652 100644 --- a/esp-hal/src/ledc/timer.rs +++ b/esp-hal/src/ledc/timer.rs @@ -187,7 +187,7 @@ impl TimerSpeed for HighSpeed { /// Interface for Timers pub trait TimerIFace { /// Return the frequency of the timer - fn get_freq(&self) -> Option; + fn freq(&self) -> Option; /// Configure the timer fn configure(&mut self, config: config::Config) -> Result<(), Error>; @@ -196,19 +196,19 @@ pub trait TimerIFace { fn is_configured(&self) -> bool; /// Return the duty resolution of the timer - fn get_duty(&self) -> Option; + fn duty(&self) -> Option; /// Return the timer number - fn get_number(&self) -> Number; + fn number(&self) -> Number; /// Return the timer frequency, or 0 if not configured - fn get_frequency(&self) -> u32; + fn frequency(&self) -> u32; } /// Interface for HW configuration of timer pub trait TimerHW { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option; + fn freq_hw(&self) -> Option; /// Configure the HW for the timer fn configure_hw(&self, divisor: u32); @@ -233,8 +233,8 @@ where Timer<'a, S>: TimerHW, { /// Return the frequency of the timer - fn get_freq(&self) -> Option { - self.get_freq_hw() + fn freq(&self) -> Option { + self.freq_hw() } /// Configure the timer @@ -243,7 +243,7 @@ where self.clock_source = Some(config.clock_source); // TODO: we should return some error here if `unwrap()` fails - let src_freq: u32 = self.get_freq().unwrap().to_Hz(); + let src_freq: u32 = self.freq().unwrap().to_Hz(); let precision = 1 << config.duty as u32; let frequency: u32 = config.frequency.raw(); self.frequency = frequency; @@ -275,17 +275,17 @@ where } /// Return the duty resolution of the timer - fn get_duty(&self) -> Option { + fn duty(&self) -> Option { self.duty } /// Return the timer number - fn get_number(&self) -> Number { + fn number(&self) -> Number { self.number } /// Return the timer frequency - fn get_frequency(&self) -> u32 { + fn frequency(&self) -> u32 { self.frequency } } @@ -308,7 +308,7 @@ impl<'a, S: TimerSpeed> Timer<'a, S> { /// Timer HW implementation for LowSpeed timers impl TimerHW for Timer<'_, LowSpeed> { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option { + fn freq_hw(&self) -> Option { self.clock_source.map(|source| match source { LSClockSource::APBClk => { let clocks = Clocks::get(); @@ -371,7 +371,7 @@ impl TimerHW for Timer<'_, LowSpeed> { /// Timer HW implementation for HighSpeed timers impl<'a> TimerHW for Timer<'a, HighSpeed> { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option { + fn freq_hw(&self) -> Option { self.clock_source.map(|source| match source { HSClockSource::APBClk => { let clocks = Clocks::get(); diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index 21e2c6cd0cc..dbad5471c00 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -369,7 +369,7 @@ impl Cpu { /// Returns the core the application is currently executing on #[inline(always)] pub fn current() -> Self { - get_core() + core() } /// Returns an iterator over the "other" cores. @@ -377,7 +377,7 @@ impl Cpu { pub fn other() -> impl Iterator { cfg_if::cfg_if! { if #[cfg(multi_core)] { - match get_core() { + match core() { Cpu::ProCpu => [Cpu::AppCpu].into_iter(), Cpu::AppCpu => [Cpu::ProCpu].into_iter(), } @@ -390,12 +390,12 @@ impl Cpu { /// Which core the application is currently executing on #[inline(always)] -pub fn get_core() -> Cpu { +pub fn core() -> Cpu { // This works for both RISCV and Xtensa because both - // get_raw_core functions return zero, _or_ something + // raw_core functions return zero, _or_ something // greater than zero; 1 in the case of RISCV and 0x2000 // in the case of Xtensa. - match get_raw_core() { + match raw_core() { 0 => Cpu::ProCpu, #[cfg(all(multi_core, riscv))] 1 => Cpu::AppCpu, @@ -410,7 +410,7 @@ pub fn get_core() -> Cpu { /// Safety: This method should never return UNUSED_THREAD_ID_VALUE #[cfg(riscv)] #[inline(always)] -fn get_raw_core() -> usize { +fn raw_core() -> usize { #[cfg(multi_core)] { riscv::register::mhartid::read() @@ -429,7 +429,7 @@ fn get_raw_core() -> usize { /// Safety: This method should never return UNUSED_THREAD_ID_VALUE #[cfg(xtensa)] #[inline(always)] -fn get_raw_core() -> usize { +fn raw_core() -> usize { (xtensa_lx::get_processor_id() & 0x2000) as usize } diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index 5edbb02ccb4..8c99ee03ecd 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -363,7 +363,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, /// Get the old timestamp. /// The value of the timestamp will take effect according to the set /// [`PwmUpdateMethod`]. - pub fn get_timestamp(&self) -> u16 { + pub fn timestamp(&self) -> u16 { // SAFETY: // We only read to our GENx_TSTMP_x register let ch = unsafe { Self::ch() }; @@ -384,7 +384,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, } /// Get the period of the timer. - pub fn get_period(&self) -> u16 { + pub fn period(&self) -> u16 { // SAFETY: // We only grant access to our CFG0 register with the lifetime of &mut self let block = unsafe { &*PWM::block() }; @@ -430,12 +430,12 @@ impl embedded_hal_02::PwmPin /// Get the duty of the pin fn get_duty(&self) -> Self::Duty { - self.get_timestamp() + self.timestamp() } /// Get the max duty of the pin fn get_max_duty(&self) -> Self::Duty { - self.get_period() + self.period() } /// Set the duty of the pin @@ -457,7 +457,7 @@ impl embedded_hal::pwm::SetD { /// Get the max duty of the PwmPin fn max_duty_cycle(&self) -> u16 { - self.get_period() + self.period() } /// Set the max duty of the PwmPin diff --git a/esp-hal/src/pcnt/unit.rs b/esp-hal/src/pcnt/unit.rs index cdcaae7830e..fb1a0cf4914 100644 --- a/esp-hal/src/pcnt/unit.rs +++ b/esp-hal/src/pcnt/unit.rs @@ -243,7 +243,7 @@ impl Unit<'_, NUM> { } /// Get the latest events for this unit. - pub fn get_events(&self) -> Events { + pub fn events(&self) -> Events { let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() }; let status = pcnt.u_status(NUM).read(); @@ -257,7 +257,7 @@ impl Unit<'_, NUM> { } /// Get the mode of the last zero crossing - pub fn get_zero_mode(&self) -> ZeroMode { + pub fn zero_mode(&self) -> ZeroMode { let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() }; pcnt.u_status(NUM).read().zero_mode().bits().into() } @@ -296,7 +296,7 @@ impl Unit<'_, NUM> { } /// Get the current counter value. - pub fn get_value(&self) -> i16 { + pub fn value(&self) -> i16 { self.counter.get() } } diff --git a/esp-hal/src/reset.rs b/esp-hal/src/reset.rs index 5b3486769d6..d4e85d10245 100644 --- a/esp-hal/src/reset.rs +++ b/esp-hal/src/reset.rs @@ -102,11 +102,11 @@ pub fn software_reset_cpu() { /// Retrieves the reason for the last reset as a SocResetReason enum value. /// Returns `None` if the reset reason cannot be determined. -pub fn get_reset_reason() -> Option { - crate::rtc_cntl::get_reset_reason(crate::get_core()) +pub fn reset_reason() -> Option { + crate::rtc_cntl::reset_reason(crate::core()) } /// Retrieves the cause of the last wakeup event as a SleepSource enum value. -pub fn get_wakeup_cause() -> SleepSource { - crate::rtc_cntl::get_wakeup_cause() +pub fn wakeup_cause() -> SleepSource { + crate::rtc_cntl::wakeup_cause() } diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 71797a64a26..772790fd343 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -283,7 +283,7 @@ impl<'d> Rtc<'d> { pub fn time_since_boot(&self) -> MicrosDurationU64 { MicrosDurationU64::micros( self.time_since_boot_raw() * 1_000_000 - / RtcClock::get_slow_freq().frequency().to_Hz() as u64, + / RtcClock::slow_freq().frequency().to_Hz() as u64, ) } @@ -516,7 +516,7 @@ impl RtcClock { /// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the /// bootloader, as passed to rtc_clk_init function. #[cfg(not(any(esp32c6, esp32h2)))] - pub fn get_xtal_freq() -> XtalClock { + pub fn xtal_freq() -> XtalClock { match Self::read_xtal_freq_mhz() { None | Some(40) => XtalClock::RtcXtalFreq40M, #[cfg(any(esp32c3, esp32s3))] @@ -529,7 +529,7 @@ impl RtcClock { /// Get the RTC_SLOW_CLK source. #[cfg(not(any(esp32c6, esp32h2)))] - pub fn get_slow_freq() -> RtcSlowClock { + pub fn slow_freq() -> RtcSlowClock { let rtc_cntl = unsafe { &*LPWR::PTR }; let slow_freq = rtc_cntl.clk_conf().read().ana_clk_rtc_sel().bits(); match slow_freq { @@ -590,7 +590,7 @@ impl RtcClock { // The following code emulates ESP32 behavior for the other chips: #[cfg(not(esp32))] let cal_clk = match cal_clk { - RtcCalSel::RtcCalRtcMux => match RtcClock::get_slow_freq() { + RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, RtcSlowClock::RtcSlowClock8mD256 => RtcCalSel::RtcCal8mD256, _ => cal_clk, @@ -725,7 +725,7 @@ impl RtcClock { /// Measure ratio between XTAL frequency and RTC slow clock frequency. #[cfg(not(any(esp32c6, esp32h2)))] - fn get_calibration_ratio(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { + fn calibration_ratio(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64; let ratio = (xtal_cycles << RtcClock::CAL_FRACT) / slowclk_cycles as u64; @@ -741,7 +741,7 @@ impl RtcClock { /// issue, or lack of 32 XTAL on board). #[cfg(not(any(esp32c6, esp32h2)))] fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { - let xtal_freq = RtcClock::get_xtal_freq(); + let xtal_freq = RtcClock::xtal_freq(); let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64; let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64; let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider; @@ -753,7 +753,7 @@ impl RtcClock { #[cfg(not(any(esp32c6, esp32h2)))] fn cycles_to_1ms() -> u16 { let period_13q19 = RtcClock::calibrate( - match RtcClock::get_slow_freq() { + match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClockRtc => RtcCalSel::RtcCalRtcMux, RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, #[cfg(not(any(esp32c6, esp32h2)))] @@ -782,7 +782,7 @@ impl RtcClock { RtcClock::enable_8m(true, true); } - let ratio = RtcClock::get_calibration_ratio(RtcCalSel::RtcCal8mD256, XTAL_FREQ_EST_CYCLES); + let ratio = RtcClock::calibration_ratio(RtcCalSel::RtcCal8mD256, XTAL_FREQ_EST_CYCLES); let freq_mhz = ((ratio as u64 * RtcFastClock::RtcFastClock8m.hz() as u64 / 1_000_000u64 / 256u64) >> RtcClock::CAL_FRACT) as u32; @@ -989,19 +989,19 @@ impl Rwdt { match stage { RwdtStage::Stage0 => rtc_cntl.config1().modify(|_, w| { w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage1 => rtc_cntl.config2().modify(|_, w| { w.wdt_stg1_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage2 => rtc_cntl.config3().modify(|_, w| { w.wdt_stg2_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage3 => rtc_cntl.config4().modify(|_, w| { w.wdt_stg3_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), }; @@ -1009,19 +1009,19 @@ impl Rwdt { match stage { RwdtStage::Stage0 => rtc_cntl.wdtconfig1().modify(|_, w| { w.wdt_stg0_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage1 => rtc_cntl.wdtconfig2().modify(|_, w| { w.wdt_stg1_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage2 => rtc_cntl.wdtconfig3().modify(|_, w| { w.wdt_stg2_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), RwdtStage::Stage3 => rtc_cntl.wdtconfig4().modify(|_, w| { w.wdt_stg3_hold() - .bits(timeout_raw >> (1 + Efuse::get_rwdt_multiplier())) + .bits(timeout_raw >> (1 + Efuse::rwdt_multiplier())) }), }; } @@ -1139,15 +1139,15 @@ impl embedded_hal_02::watchdog::WatchdogDisable for Swd { } /// Return reset reason. -pub fn get_reset_reason(cpu: Cpu) -> Option { +pub fn reset_reason(cpu: Cpu) -> Option { let reason = crate::rom::rtc_get_reset_reason(cpu as u32); SocResetReason::from_repr(reason as usize) } /// Return wakeup reason. -pub fn get_wakeup_cause() -> SleepSource { - if get_reset_reason(Cpu::ProCpu) != Some(SocResetReason::CoreDeepSleep) { +pub fn wakeup_cause() -> SleepSource { + if reset_reason(Cpu::ProCpu) != Some(SocResetReason::CoreDeepSleep) { return SleepSource::Undefined; } @@ -1221,6 +1221,6 @@ pub fn get_wakeup_cause() -> SleepSource { // so that either ieee or esp-wifi gets it for free without duplicating in both #[no_mangle] extern "C" fn rtc_clk_xtal_freq_get() -> i32 { - let xtal = RtcClock::get_xtal_freq(); + let xtal = RtcClock::xtal_freq(); xtal.mhz() as i32 } diff --git a/esp-hal/src/rtc_cntl/rtc/esp32c3.rs b/esp-hal/src/rtc_cntl/rtc/esp32c3.rs index 57719925832..fce8684fbb8 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32c3.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32c3.rs @@ -86,10 +86,7 @@ pub(crate) fn init() { } pub(crate) fn configure_clock() { - assert!(matches!( - RtcClock::get_xtal_freq(), - XtalClock::RtcXtalFreq40M - )); + assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq40M)); unsafe { // from esp_clk_init: diff --git a/esp-hal/src/rtc_cntl/rtc/esp32c6.rs b/esp-hal/src/rtc_cntl/rtc/esp32c6.rs index ff7efe0ed22..66d72abf62c 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32c6.rs @@ -1200,10 +1200,7 @@ pub(crate) fn init() { } pub(crate) fn configure_clock() { - assert!(matches!( - RtcClock::get_xtal_freq(), - XtalClock::RtcXtalFreq40M - )); + assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq40M)); RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast); @@ -1423,22 +1420,22 @@ pub(crate) enum RtcCaliClkSel { /// RTC Watchdog Timer driver impl RtcClock { // rtc_clk_xtal_freq_get - pub(crate) fn get_xtal_freq_mhz() -> u32 { + pub(crate) fn xtal_freq_mhz() -> u32 { Self::read_xtal_freq_mhz().unwrap_or(40) } /// Get main XTAL frequency /// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the /// bootloader, as passed to rtc_clk_init function. - pub fn get_xtal_freq() -> XtalClock { - match Self::get_xtal_freq_mhz() { + pub fn xtal_freq() -> XtalClock { + match Self::xtal_freq_mhz() { 40 => XtalClock::RtcXtalFreq40M, other => XtalClock::RtcXtalFreqOther(other), } } /// Get the RTC_SLOW_CLK source - pub fn get_slow_freq() -> RtcSlowClock { + pub fn slow_freq() -> RtcSlowClock { let lp_clrst = unsafe { lp_clkrst() }; let slow_freq = lp_clrst.lp_clk_conf().read().slow_clk_sel().bits(); @@ -1492,7 +1489,7 @@ impl RtcClock { if cal_clk == RtcCalSel::RtcCalRtcMux { cal_clk = match cal_clk { - RtcCalSel::RtcCalRtcMux => match RtcClock::get_slow_freq() { + RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc, _ => cal_clk, @@ -1506,7 +1503,7 @@ impl RtcClock { let pcr = unsafe { pcr() }; let pmu = unsafe { pmu() }; - let clk_src = RtcClock::get_slow_freq(); + let clk_src = RtcClock::slow_freq(); if cal_clk == RtcCalSel::RtcCalRtcMux { cal_clk = match clk_src { @@ -1756,7 +1753,7 @@ impl RtcClock { /// not started up (due to incorrect loading capacitance, board design /// issue, or lack of 32 XTAL on board). fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { - let xtal_freq = RtcClock::get_xtal_freq(); + let xtal_freq = RtcClock::xtal_freq(); let mut slowclk_cycles = slowclk_cycles; @@ -1777,7 +1774,7 @@ impl RtcClock { /// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond. pub(crate) fn cycles_to_1ms() -> u16 { let period_13q19 = RtcClock::calibrate( - match RtcClock::get_slow_freq() { + match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux, RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc, @@ -1821,7 +1818,7 @@ impl RtcClock { pub(crate) fn rtc_clk_cpu_freq_set_xtal() { // rtc_clk_cpu_set_to_default_config - let freq = RtcClock::get_xtal_freq_mhz(); + let freq = RtcClock::xtal_freq_mhz(); esp32c6_rtc_update_to_xtal_raw(freq, 1); @@ -1889,7 +1886,7 @@ impl SavedClockConfig { match source { CpuClockSource::Xtal => { div = esp32c6_cpu_get_ls_divider(); - source_freq_mhz = RtcClock::get_xtal_freq_mhz(); + source_freq_mhz = RtcClock::xtal_freq_mhz(); } CpuClockSource::Pll => { div = esp32c6_cpu_get_hs_divider(); @@ -1923,7 +1920,7 @@ impl SavedClockConfig { if old_source != CpuClockSource::Pll { rtc_clk_bbpll_enable(); esp32c6_rtc_bbpll_configure_raw( - RtcClock::get_xtal_freq_mhz(), + RtcClock::xtal_freq_mhz(), self.source_freq_mhz, ); } diff --git a/esp-hal/src/rtc_cntl/rtc/esp32h2.rs b/esp-hal/src/rtc_cntl/rtc/esp32h2.rs index 5419df84ebe..5fd0a72ec12 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32h2.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32h2.rs @@ -120,10 +120,7 @@ pub(crate) fn init() { } pub(crate) fn configure_clock() { - assert!(matches!( - RtcClock::get_xtal_freq(), - XtalClock::RtcXtalFreq32M - )); + assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq32M)); RtcClock::set_fast_freq(RtcFastClock::RtcFastClockRcFast); @@ -270,7 +267,7 @@ impl RtcClock { /// Get main XTAL frequency. /// This is the value stored in RTC register RTC_XTAL_FREQ_REG by the /// bootloader, as passed to rtc_clk_init function. - pub fn get_xtal_freq() -> XtalClock { + pub fn xtal_freq() -> XtalClock { match Self::read_xtal_freq_mhz() { None | Some(32) => XtalClock::RtcXtalFreq32M, Some(other) => XtalClock::RtcXtalFreqOther(other), @@ -309,7 +306,7 @@ impl RtcClock { } /// Get the RTC_SLOW_CLK source - pub fn get_slow_freq() -> RtcSlowClock { + pub fn slow_freq() -> RtcSlowClock { let lp_clrst = unsafe { &*LPWR::ptr() }; let slow_freq = lp_clrst.lp_clk_conf().read().slow_clk_sel().bits(); @@ -323,7 +320,7 @@ impl RtcClock { } fn calibrate(cal_clk: RtcCalSel, slowclk_cycles: u32) -> u32 { - let xtal_freq = RtcClock::get_xtal_freq(); + let xtal_freq = RtcClock::xtal_freq(); let xtal_cycles = RtcClock::calibrate_internal(cal_clk, slowclk_cycles) as u64; let divider = xtal_freq.mhz() as u64 * slowclk_cycles as u64; let period_64 = ((xtal_cycles << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider; @@ -341,7 +338,7 @@ impl RtcClock { if cal_clk == RtcCalSel::RtcCalRtcMux { cal_clk = match cal_clk { - RtcCalSel::RtcCalRtcMux => match RtcClock::get_slow_freq() { + RtcCalSel::RtcCalRtcMux => match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc, _ => cal_clk, @@ -355,7 +352,7 @@ impl RtcClock { let pcr = unsafe { &*PCR::ptr() }; let pmu = unsafe { &*PMU::ptr() }; - let clk_src = RtcClock::get_slow_freq(); + let clk_src = RtcClock::slow_freq(); if cal_clk == RtcCalSel::RtcCalRtcMux { cal_clk = match clk_src { @@ -587,7 +584,7 @@ impl RtcClock { pub(crate) fn cycles_to_1ms() -> u16 { let period_13q19 = RtcClock::calibrate( - match RtcClock::get_slow_freq() { + match RtcClock::slow_freq() { RtcSlowClock::RtcSlowClockRcSlow => RtcCalSel::RtcCalRtcMux, RtcSlowClock::RtcSlowClock32kXtal => RtcCalSel::RtcCal32kXtal, RtcSlowClock::RtcSlowClock32kRc => RtcCalSel::RtcCal32kRc, diff --git a/esp-hal/src/rtc_cntl/rtc/esp32s2.rs b/esp-hal/src/rtc_cntl/rtc/esp32s2.rs index 51250e35e05..cf679877770 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32s2.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32s2.rs @@ -9,10 +9,7 @@ use crate::{ pub(crate) fn init() {} pub(crate) fn configure_clock() { - assert!(matches!( - RtcClock::get_xtal_freq(), - XtalClock::RtcXtalFreq40M - )); + assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq40M)); RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m); diff --git a/esp-hal/src/rtc_cntl/rtc/esp32s3.rs b/esp-hal/src/rtc_cntl/rtc/esp32s3.rs index 35c12f8bde3..37a682d7a34 100644 --- a/esp-hal/src/rtc_cntl/rtc/esp32s3.rs +++ b/esp-hal/src/rtc_cntl/rtc/esp32s3.rs @@ -9,10 +9,7 @@ use crate::{ pub(crate) fn init() {} pub(crate) fn configure_clock() { - assert!(matches!( - RtcClock::get_xtal_freq(), - XtalClock::RtcXtalFreq40M - )); + assert!(matches!(RtcClock::xtal_freq(), XtalClock::RtcXtalFreq40M)); RtcClock::set_fast_freq(RtcFastClock::RtcFastClock8m); diff --git a/esp-hal/src/rtc_cntl/sleep/esp32.rs b/esp-hal/src/rtc_cntl/sleep/esp32.rs index f8c3446939c..c43cf8ad19f 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32.rs @@ -76,7 +76,7 @@ impl WakeSource for TimerWakeupSource { ) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32::RTC_CNTL::ptr() }; - let clock_freq = RtcClock::get_slow_freq(); + let clock_freq = RtcClock::slow_freq(); // TODO: maybe add sleep time adjustlemnt like idf // TODO: maybe add check to prevent overflow? let clock_hz = clock_freq.frequency().to_Hz() as u64; diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c2.rs b/esp-hal/src/rtc_cntl/sleep/esp32c2.rs index ef690a704c3..9609ea5141f 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c2.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c2.rs @@ -130,7 +130,7 @@ impl WakeSource for TimerWakeupSource { ) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32c2::RTC_CNTL::ptr() }; - let clock_freq = RtcClock::get_slow_freq(); + let clock_freq = RtcClock::slow_freq(); // TODO: maybe add sleep time adjustlemnt like idf // TODO: maybe add check to prevent overflow? let clock_hz = clock_freq.frequency().to_Hz() as u64; diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c3.rs b/esp-hal/src/rtc_cntl/sleep/esp32c3.rs index cd01c636164..48a23fcec69 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c3.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c3.rs @@ -130,7 +130,7 @@ impl WakeSource for TimerWakeupSource { ) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32c3::RTC_CNTL::ptr() }; - let clock_freq = RtcClock::get_slow_freq(); + let clock_freq = RtcClock::slow_freq(); // TODO: maybe add sleep time adjustlemnt like idf // TODO: maybe add check to prevent overflow? let clock_hz = clock_freq.frequency().to_Hz() as u64; diff --git a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs index 4692513c992..e874617b7a8 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32c6.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32c6.rs @@ -38,7 +38,7 @@ impl WakeSource for TimerWakeupSource { triggers.set_timer(true); let lp_timer = unsafe { &*esp32c6::LP_TIMER::ptr() }; - let clock_freq = RtcClock::get_slow_freq(); + let clock_freq = RtcClock::slow_freq(); // TODO: maybe add sleep time adjustment like idf // TODO: maybe add check to prevent overflow? let clock_hz = clock_freq.frequency().to_Hz() as u64; diff --git a/esp-hal/src/rtc_cntl/sleep/esp32s3.rs b/esp-hal/src/rtc_cntl/sleep/esp32s3.rs index e4ebfeb05e8..3fbb349a264 100644 --- a/esp-hal/src/rtc_cntl/sleep/esp32s3.rs +++ b/esp-hal/src/rtc_cntl/sleep/esp32s3.rs @@ -116,7 +116,7 @@ impl WakeSource for TimerWakeupSource { ) { triggers.set_timer(true); let rtc_cntl = unsafe { &*esp32s3::RTC_CNTL::ptr() }; - let clock_freq = RtcClock::get_slow_freq(); + let clock_freq = RtcClock::slow_freq(); // TODO: maybe add sleep time adjustlemnt like idf // TODO: maybe add check to prevent overflow? let clock_hz = clock_freq.frequency().to_Hz() as u64; diff --git a/esp-hal/src/soc/esp32/cpu_control.rs b/esp-hal/src/soc/esp32/cpu_control.rs index b7d5cc0503b..14ac9cb7cf2 100644 --- a/esp-hal/src/soc/esp32/cpu_control.rs +++ b/esp-hal/src/soc/esp32/cpu_control.rs @@ -328,7 +328,7 @@ impl<'d> CpuControl<'d> { let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::>()) }; entry(); loop { - unsafe { internal_park_core(crate::get_core()) }; + unsafe { internal_park_core(crate::core()) }; } } None => panic!("No start function set"), diff --git a/esp-hal/src/soc/esp32/efuse/mod.rs b/esp-hal/src/soc/esp32/efuse/mod.rs index ff59b537f9e..9b7467240bc 100644 --- a/esp-hal/src/soc/esp32/efuse/mod.rs +++ b/esp-hal/src/soc/esp32/efuse/mod.rs @@ -82,7 +82,7 @@ impl Efuse { /// While ESP32 chips usually come with two mostly equivalent CPUs (protocol /// CPU and application CPU), the application CPU is unavailable on /// some. - pub fn get_core_count() -> u32 { + pub fn core_count() -> u32 { if Self::read_bit(DISABLE_APP_CPU) { 1 } else { @@ -94,7 +94,7 @@ impl Efuse { /// /// Note that the actual clock may be lower, depending on the current power /// configuration of the chip, clock source, and other settings. - pub fn get_max_cpu_frequency() -> HertzU32 { + pub fn max_cpu_frequency() -> HertzU32 { let has_rating = Self::read_bit(CHIP_CPU_FREQ_RATED); let has_low_rating = Self::read_bit(CHIP_CPU_FREQ_LOW); @@ -111,7 +111,7 @@ impl Efuse { } /// Returns the CHIP_VER_PKG eFuse value. - pub fn get_chip_type() -> ChipType { + pub fn chip_type() -> ChipType { let chip_ver = Self::read_field_le::(CHIP_PACKAGE) | Self::read_field_le::(CHIP_PACKAGE_4BIT) << 4; @@ -127,7 +127,7 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(FLASH_CRYPT_CNT).count_ones() % 2) != 0 } } diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index 9a7f8449fff..b25bc0a85ac 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0:`: +//! - `io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0:`: //! * This function returns a reference to the GPIO register associated //! with the given GPIO number. It uses unsafe code and transmutation to //! access the GPIO registers based on the provided GPIO number. @@ -63,7 +63,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x30; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function2; -pub(crate) fn get_io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { +pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { unsafe { let iomux = &*IO_MUX::PTR; @@ -110,7 +110,7 @@ pub(crate) fn get_io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { } pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { - match crate::get_core() { + match crate::core() { Cpu::AppCpu => int_enable as u8 | ((nmi_enable as u8) << 1), // this should be bits 3 & 4 respectively, according to the TRM, but it doesn't seem to // work. This does though. @@ -719,7 +719,7 @@ macro_rules! touch { } } - fn get_touch_measurement(&self, _: $crate::private::Internal) -> u16 { + fn touch_measurement(&self, _: $crate::private::Internal) -> u16 { paste::paste! { unsafe { $crate::peripherals::SENS::steal() } . $touch_out_reg ().read() @@ -727,7 +727,7 @@ macro_rules! touch { } } - fn get_touch_nr(&self, _: $crate::private::Internal) -> u8 { + fn touch_nr(&self, _: $crate::private::Internal) -> u8 { $touch_num } @@ -789,11 +789,11 @@ pub(crate) enum InterruptStatusRegisterAccess { impl InterruptStatusRegisterAccess { pub(crate) fn interrupt_status_read(self) -> u32 { match self { - Self::Bank0 => match crate::get_core() { + Self::Bank0 => match crate::core() { crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int().read().bits(), crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int().read().bits(), }, - Self::Bank1 => match crate::get_core() { + Self::Bank1 => match crate::core() { crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int1().read().bits(), }, diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 513675bc8ab..aeeffa81ee8 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -93,7 +93,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { addr_of_mut!(_rtc_slow_bss_end), ); if matches!( - crate::reset::get_reset_reason(), + crate::reset::reset_reason(), None | Some(SocResetReason::ChipPowerOn) ) { xtensa_lx_rt::zero_bss( diff --git a/esp-hal/src/soc/esp32/psram.rs b/esp-hal/src/soc/esp32/psram.rs index 3e46c79f91a..7843d1cc171 100644 --- a/esp-hal/src/soc/esp32/psram.rs +++ b/esp-hal/src/soc/esp32/psram.rs @@ -304,7 +304,7 @@ pub(crate) mod utils { #[ram] pub(crate) fn psram_init(config: &PsramConfig) { - let chip = crate::efuse::Efuse::get_chip_type(); + let chip = crate::efuse::Efuse::chip_type(); let mode = config.cache_speed; let mut psram_io = PsramIo::default(); @@ -1061,7 +1061,7 @@ pub(crate) mod utils { fn configure_gpio(gpio: u8, field: Field, bits: u8) { unsafe { - let ptr = crate::gpio::get_io_mux_reg(gpio); + let ptr = crate::gpio::io_mux_reg(gpio); ptr.modify(|_, w| apply_to_field!(w, field, bits)); } } diff --git a/esp-hal/src/soc/esp32c2/efuse/mod.rs b/esp-hal/src/soc/esp32c2/efuse/mod.rs index bfd724fd459..124d3bb29d5 100644 --- a/esp-hal/src/soc/esp32c2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c2/efuse/mod.rs @@ -54,19 +54,19 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } /// Get efuse block version /// /// see - pub fn get_block_version() -> (u8, u8) { + pub fn block_version() -> (u8, u8) { // see // ( @@ -78,8 +78,8 @@ impl Efuse { /// Get version of RTC calibration block /// /// see - pub fn get_rtc_calib_version() -> u8 { - let (major, _minor) = Self::get_block_version(); + pub fn rtc_calib_version() -> u8 { + let (major, _minor) = Self::block_version(); if major == 0 { 1 } else { @@ -90,8 +90,8 @@ impl Efuse { /// Get ADC initial code for specified attenuation from efuse /// /// see - pub fn get_rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; @@ -119,7 +119,7 @@ impl Efuse { /// Get ADC reference point voltage for specified attenuation in millivolts /// /// see - pub fn get_rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { + pub fn rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { match atten { Attenuation::Attenuation0dB => 400, Attenuation::Attenuation11dB => 1370, @@ -129,8 +129,8 @@ impl Efuse { /// Get ADC reference point digital code for specified attenuation /// /// see - pub fn get_rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; diff --git a/esp-hal/src/soc/esp32c2/gpio.rs b/esp-hal/src/soc/esp32c2/gpio.rs index f7080686beb..4416b324c4a 100644 --- a/esp-hal/src/soc/esp32c2/gpio.rs +++ b/esp-hal/src/soc/esp32c2/gpio.rs @@ -8,8 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static -//! crate::peripherals::io_mux::GPIO`: +//! - `io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO`: //! * Returns the IO_MUX register for the specified GPIO pin number. //! - `gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8`: //! * This function enables or disables GPIO interrupts and Non-Maskable @@ -55,7 +54,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x1f; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { unsafe { (*crate::peripherals::IO_MUX::PTR).gpio(gpio_num as usize) } } diff --git a/esp-hal/src/soc/esp32c3/efuse/mod.rs b/esp-hal/src/soc/esp32c3/efuse/mod.rs index c7fae51caab..d7f62114e9b 100644 --- a/esp-hal/src/soc/esp32c3/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c3/efuse/mod.rs @@ -55,19 +55,19 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } /// Get efuse block version /// /// see - pub fn get_block_version() -> (u8, u8) { + pub fn block_version() -> (u8, u8) { // see // // @@ -80,8 +80,8 @@ impl Efuse { /// Get version of RTC calibration block /// /// see - pub fn get_rtc_calib_version() -> u8 { - let (major, _minor) = Self::get_block_version(); + pub fn rtc_calib_version() -> u8 { + let (major, _minor) = Self::block_version(); if major == 1 { 1 } else { @@ -92,8 +92,8 @@ impl Efuse { /// Get ADC initial code for specified attenuation from efuse /// /// see - pub fn get_rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; @@ -113,7 +113,7 @@ impl Efuse { /// Get ADC reference point voltage for specified attenuation in millivolts /// /// see - pub fn get_rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { + pub fn rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { match atten { Attenuation::Attenuation0dB => 400, Attenuation::Attenuation2p5dB => 550, @@ -125,8 +125,8 @@ impl Efuse { /// Get ADC reference point digital code for specified attenuation /// /// see - pub fn get_rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; diff --git a/esp-hal/src/soc/esp32c3/gpio.rs b/esp-hal/src/soc/esp32c3/gpio.rs index f6a4fd76fcb..11b99a08534 100644 --- a/esp-hal/src/soc/esp32c3/gpio.rs +++ b/esp-hal/src/soc/esp32c3/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static +//! - `io_mux_reg(gpio_num: u8) -> &'static //! crate::peripherals::io_mux::GPIO0:`: //! * Returns the IO_MUX register for the specified GPIO pin number. //! - `gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8`: @@ -56,7 +56,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x1f; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { unsafe { (*crate::peripherals::IO_MUX::PTR).gpio(gpio_num as usize) } } diff --git a/esp-hal/src/soc/esp32c6/efuse/mod.rs b/esp-hal/src/soc/esp32c6/efuse/mod.rs index 9e2906e2af7..0ec84d7c0e4 100644 --- a/esp-hal/src/soc/esp32c6/efuse/mod.rs +++ b/esp-hal/src/soc/esp32c6/efuse/mod.rs @@ -55,19 +55,19 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } /// Get efuse block version /// /// see - pub fn get_block_version() -> (u8, u8) { + pub fn block_version() -> (u8, u8) { // see // ( @@ -79,8 +79,8 @@ impl Efuse { /// Get version of RTC calibration block /// /// see - pub fn get_rtc_calib_version() -> u8 { - let (_major, minor) = Self::get_block_version(); + pub fn rtc_calib_version() -> u8 { + let (_major, minor) = Self::block_version(); if minor >= 1 { 1 } else { @@ -91,8 +91,8 @@ impl Efuse { /// Get ADC initial code for specified attenuation from efuse /// /// see - pub fn get_rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_init_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; @@ -112,7 +112,7 @@ impl Efuse { /// Get ADC reference point voltage for specified attenuation in millivolts /// /// see - pub fn get_rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { + pub fn rtc_calib_cal_mv(_unit: u8, atten: Attenuation) -> u16 { match atten { Attenuation::Attenuation0dB => 400, Attenuation::Attenuation2p5dB => 550, @@ -124,8 +124,8 @@ impl Efuse { /// Get ADC reference point digital code for specified attenuation /// /// see - pub fn get_rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_cal_code(_unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; diff --git a/esp-hal/src/soc/esp32c6/gpio.rs b/esp-hal/src/soc/esp32c6/gpio.rs index b7d84a403aa..1ae8f62b86d 100644 --- a/esp-hal/src/soc/esp32c6/gpio.rs +++ b/esp-hal/src/soc/esp32c6/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static +//! - `io_mux_reg(gpio_num: u8) -> &'static //! crate::peripherals::io_mux::GPIO0:`: //! * Returns the IO_MUX register for the specified GPIO pin number. //! - `gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8`: @@ -56,7 +56,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x3c; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { unsafe { (*crate::peripherals::IO_MUX::PTR).gpio(gpio_num as usize) } } diff --git a/esp-hal/src/soc/esp32h2/efuse/mod.rs b/esp-hal/src/soc/esp32h2/efuse/mod.rs index eaf75d21d5c..d0ec6794f33 100644 --- a/esp-hal/src/soc/esp32h2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32h2/efuse/mod.rs @@ -55,12 +55,12 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } } diff --git a/esp-hal/src/soc/esp32h2/gpio.rs b/esp-hal/src/soc/esp32h2/gpio.rs index ffff2e84797..e1931c1371a 100644 --- a/esp-hal/src/soc/esp32h2/gpio.rs +++ b/esp-hal/src/soc/esp32h2/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static +//! - `io_mux_reg(gpio_num: u8) -> &'static //! crate::peripherals::io_mux::GPIO0:`: //! * Returns the IO_MUX register for the specified GPIO pin number. //! - `gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8`: @@ -54,7 +54,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x3c; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { unsafe { (*crate::peripherals::IO_MUX::PTR).gpio(gpio_num as usize) } } diff --git a/esp-hal/src/soc/esp32s2/efuse/mod.rs b/esp-hal/src/soc/esp32s2/efuse/mod.rs index 99e168dbdea..1f675505f1e 100644 --- a/esp-hal/src/soc/esp32s2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32s2/efuse/mod.rs @@ -57,12 +57,12 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } } diff --git a/esp-hal/src/soc/esp32s2/gpio.rs b/esp-hal/src/soc/esp32s2/gpio.rs index 58355676851..52c3deee7e9 100644 --- a/esp-hal/src/soc/esp32s2/gpio.rs +++ b/esp-hal/src/soc/esp32s2/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0:`: +//! - `io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0:`: //! * This function returns a reference to the GPIO register associated //! with the given GPIO number. It uses unsafe code and transmutation to //! access the GPIO registers based on the provided GPIO number. @@ -69,7 +69,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x3c; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { unsafe { let iomux = &*IO_MUX::PTR; diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index ca2dd1dfa38..ed39d35546f 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -98,7 +98,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { addr_of_mut!(_rtc_slow_bss_end), ); if matches!( - crate::reset::get_reset_reason(), + crate::reset::reset_reason(), None | Some(SocResetReason::ChipPowerOn) ) { xtensa_lx_rt::zero_bss( diff --git a/esp-hal/src/soc/esp32s3/cpu_control.rs b/esp-hal/src/soc/esp32s3/cpu_control.rs index cc9fe6f415a..65e3f16ab25 100644 --- a/esp-hal/src/soc/esp32s3/cpu_control.rs +++ b/esp-hal/src/soc/esp32s3/cpu_control.rs @@ -264,7 +264,7 @@ impl<'d> CpuControl<'d> { let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::>()) }; entry(); loop { - unsafe { internal_park_core(crate::get_core()) }; + unsafe { internal_park_core(crate::core()) }; } } None => panic!("No start function set"), diff --git a/esp-hal/src/soc/esp32s3/efuse/mod.rs b/esp-hal/src/soc/esp32s3/efuse/mod.rs index 2d2257fe43d..2762aae95c2 100644 --- a/esp-hal/src/soc/esp32s3/efuse/mod.rs +++ b/esp-hal/src/soc/esp32s3/efuse/mod.rs @@ -55,19 +55,19 @@ impl Efuse { } /// Get status of SPI boot encryption. - pub fn get_flash_encryption() -> bool { + pub fn flash_encryption() -> bool { (Self::read_field_le::(SPI_BOOT_CRYPT_CNT).count_ones() % 2) != 0 } /// Get the multiplier for the timeout value of the RWDT STAGE 0 register. - pub fn get_rwdt_multiplier() -> u8 { + pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } /// Get efuse block version /// /// see - pub fn get_block_version() -> (u8, u8) { + pub fn block_version() -> (u8, u8) { // see // ( @@ -79,8 +79,8 @@ impl Efuse { /// Get version of RTC calibration block /// /// see - pub fn get_rtc_calib_version() -> u8 { - let (major, _minor) = Self::get_block_version(); + pub fn rtc_calib_version() -> u8 { + let (major, _minor) = Self::block_version(); if major == 1 { 1 @@ -92,8 +92,8 @@ impl Efuse { /// Get ADC initial code for specified attenuation from efuse /// /// see - pub fn get_rtc_calib_init_code(unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_init_code(unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; @@ -143,15 +143,15 @@ impl Efuse { /// Get ADC reference point voltage for specified attenuation in millivolts /// /// see - pub fn get_rtc_calib_cal_mv(_unit: u8, _atten: Attenuation) -> u16 { + pub fn rtc_calib_cal_mv(_unit: u8, _atten: Attenuation) -> u16 { 850 } /// Get ADC reference point digital code for specified attenuation /// /// see - pub fn get_rtc_calib_cal_code(unit: u8, atten: Attenuation) -> Option { - let version = Self::get_rtc_calib_version(); + pub fn rtc_calib_cal_code(unit: u8, atten: Attenuation) -> Option { + let version = Self::rtc_calib_version(); if version != 1 { return None; diff --git a/esp-hal/src/soc/esp32s3/gpio.rs b/esp-hal/src/soc/esp32s3/gpio.rs index 8c71a0ad109..f202b064875 100644 --- a/esp-hal/src/soc/esp32s3/gpio.rs +++ b/esp-hal/src/soc/esp32s3/gpio.rs @@ -8,7 +8,7 @@ //! //! Let's get through the functionality and configurations provided by this GPIO //! module: -//! - `get_io_mux_reg(gpio_num: u8) -> &'static +//! - `io_mux_reg(gpio_num: u8) -> &'static //! crate::peripherals::io_mux::GPIO0:`: //! * Returns the IO_MUX register for the specified GPIO pin number. //! - `gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8`: @@ -56,7 +56,7 @@ pub(crate) const ZERO_INPUT: u8 = 0x3c; pub(crate) const GPIO_FUNCTION: AlternateFunction = AlternateFunction::Function1; -pub(crate) const fn get_io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { +pub(crate) const fn io_mux_reg(gpio_num: u8) -> &'static crate::peripherals::io_mux::GPIO { unsafe { (*crate::peripherals::IO_MUX::PTR).gpio(gpio_num as usize) } } diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 0d1dbde1b85..f0b5171c4f0 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -137,7 +137,7 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { addr_of_mut!(_rtc_slow_bss_end), ); if matches!( - crate::reset::get_reset_reason(), + crate::reset::reset_reason(), None | Some(SocResetReason::ChipPowerOn) ) { xtensa_lx_rt::zero_bss( diff --git a/esp-hal/src/soc/esp32s3/psram.rs b/esp-hal/src/soc/esp32s3/psram.rs index 1083b5ac896..2a6d00a4812 100644 --- a/esp-hal/src/soc/esp32s3/psram.rs +++ b/esp-hal/src/soc/esp32s3/psram.rs @@ -379,9 +379,9 @@ pub(crate) mod utils { /// or `calculate_best_flash_tuning_config` #[ram] fn mspi_timing_enter_high_speed_mode(control_spi1: bool, config: &PsramConfig) { - let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock(config); - let flash_div: u32 = get_flash_clock_divider(config); - let psram_div: u32 = get_psram_clock_divider(config); + let core_clock: SpiTimingConfigCoreClock = mspi_core_clock(config); + let flash_div: u32 = flash_clock_divider(config); + let psram_div: u32 = psram_clock_divider(config); info!( "PSRAM core_clock {:?}, flash_div = {}, psram_div = {}", @@ -466,17 +466,17 @@ pub(crate) mod utils { } #[ram] - fn get_mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock { + fn mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock { config.core_clock } #[ram] - fn get_flash_clock_divider(config: &PsramConfig) -> u32 { + fn flash_clock_divider(config: &PsramConfig) -> u32 { config.core_clock as u32 / config.flash_frequency as u32 } #[ram] - fn get_psram_clock_divider(config: &PsramConfig) -> u32 { + fn psram_clock_divider(config: &PsramConfig) -> u32 { config.core_clock as u32 / config.ram_frequency as u32 } @@ -1058,7 +1058,7 @@ pub(crate) mod utils { init_psram_mode_reg(1, &mode_reg); // Print PSRAM info - get_psram_mode_reg(1, &mut mode_reg); + psram_mode_reg(1, &mut mode_reg); print_psram_info(&mode_reg); @@ -1238,11 +1238,11 @@ pub(crate) mod utils { // This function should always be called after `spi_timing_flash_tuning` or // `calculate_best_flash_tuning_config` fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool, config: &PsramConfig) { - // spi_timing_config_core_clock_t core_clock = get_mspi_core_clock(); + // spi_timing_config_core_clock_t core_clock = mspi_core_clock(); let core_clock = SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m; - let flash_div: u32 = get_flash_clock_divider(config); - let psram_div: u32 = get_psram_clock_divider(config); + let flash_div: u32 = flash_clock_divider(config); + let psram_div: u32 = psram_clock_divider(config); // Set SPI01 core clock spi0_timing_config_set_core_clock(core_clock); // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here. @@ -1306,7 +1306,7 @@ pub(crate) mod utils { } } - fn get_psram_mode_reg(spi_num: u32, out_reg: &mut OpiPsramModeReg) { + fn psram_mode_reg(spi_num: u32, out_reg: &mut OpiPsramModeReg) { let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE; let cmd_len: u32 = 16; let addr_bit_len: u32 = 32; @@ -1601,12 +1601,12 @@ pub(crate) mod utils { } #[ram] - fn get_flash_clock_divider(config: &PsramConfig) -> u32 { + fn flash_clock_divider(config: &PsramConfig) -> u32 { config.core_clock as u32 / config.flash_frequency as u32 } #[ram] - fn get_psram_clock_divider(config: &PsramConfig) -> u32 { + fn psram_clock_divider(config: &PsramConfig) -> u32 { config.core_clock as u32 / config.ram_frequency as u32 } } diff --git a/esp-hal/src/soc/mod.rs b/esp-hal/src/soc/mod.rs index 67f068643cb..600b6629bdb 100644 --- a/esp-hal/src/soc/mod.rs +++ b/esp-hal/src/soc/mod.rs @@ -87,7 +87,7 @@ impl self::efuse::Efuse { /// /// By default this reads the base mac address from eFuse, but it can be /// overridden by `set_mac_address`. - pub fn get_mac_address() -> [u8; 6] { + pub fn mac_address() -> [u8; 6] { if MAC_OVERRIDE_STATE.load(Ordering::Relaxed) == 2 { unsafe { MAC_OVERRIDE } } else { diff --git a/esp-hal/src/sync.rs b/esp-hal/src/sync.rs index 6d9ccfaab32..111bd6f8edd 100644 --- a/esp-hal/src/sync.rs +++ b/esp-hal/src/sync.rs @@ -56,13 +56,13 @@ mod single_core { mod multicore { use portable_atomic::{AtomicUsize, Ordering}; - // Safety: Ensure that when adding new chips `get_raw_core` doesn't return this + // Safety: Ensure that when adding new chips `raw_core` doesn't return this // value. // FIXME: ensure in HIL tests this is the case! const UNUSED_THREAD_ID_VALUE: usize = 0x100; pub fn thread_id() -> usize { - crate::get_raw_core() + crate::raw_core() } pub(super) struct AtomicLock { diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index d2bac3ddf19..d640502041e 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -454,7 +454,7 @@ pub trait Comparator { /// Get the current mode of the comparator, which is either target or /// periodic. - fn get_mode(&self) -> ComparatorMode { + fn mode(&self) -> ComparatorMode { let tconf = unsafe { let systimer = &*SYSTIMER::ptr(); systimer.target_conf(self.channel() as usize) @@ -497,7 +497,7 @@ pub trait Comparator { } /// Get the actual target value of the comparator. - fn get_actual_target(&self) -> u64 { + fn actual_target(&self) -> u64 { let target = unsafe { let systimer = &*SYSTIMER::ptr(); systimer.trgt(self.channel() as usize) @@ -871,7 +871,7 @@ where } fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> { - let mode = self.comparator.get_mode(); + let mode = self.comparator.mode(); let us = value.ticks(); let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000); diff --git a/esp-hal/src/touch.rs b/esp-hal/src/touch.rs index 66e8dc1c742..fdf05bd532d 100644 --- a/esp-hal/src/touch.rs +++ b/esp-hal/src/touch.rs @@ -394,7 +394,7 @@ impl TouchPad .touch_meas_done() .bit_is_set() { - Some(self.pin.get_touch_measurement(Internal)) + Some(self.pin.touch_measurement(Internal)) } else { None } @@ -420,7 +420,7 @@ impl TouchPad { .touch_meas_done() .bit_is_clear() {} - self.pin.get_touch_measurement(Internal) + self.pin.touch_measurement(Internal) } /// Enables the touch_pad interrupt. @@ -439,7 +439,7 @@ impl TouchPad { /// ## Example pub fn enable_interrupt(&mut self, threshold: u16) { self.pin.set_threshold(threshold, Internal); - internal_enable_interrupt(self.pin.get_touch_nr(Internal)) + internal_enable_interrupt(self.pin.touch_nr(Internal)) } /// Disables the touch pad's interrupt. @@ -447,7 +447,7 @@ impl TouchPad { /// If no other touch pad interrupts are active, the touch interrupt is /// disabled completely. pub fn disable_interrupt(&mut self) { - internal_disable_interrupt(self.pin.get_touch_nr(Internal)) + internal_disable_interrupt(self.pin.touch_nr(Internal)) } /// Clears a pending touch interrupt. @@ -464,7 +464,7 @@ impl TouchPad { /// Checks if the pad is touched, based on the configured threshold value. pub fn is_interrupt_set(&mut self) -> bool { - internal_is_interrupt_set(self.pin.get_touch_nr(Internal)) + internal_is_interrupt_set(self.pin.touch_nr(Internal)) } } @@ -587,7 +587,7 @@ mod asynch { /// Wait for the pad to be touched. pub async fn wait_for_touch(&mut self, threshold: u16) { self.pin.set_threshold(threshold, Internal); - let touch_nr = self.pin.get_touch_nr(Internal); + let touch_nr = self.pin.touch_nr(Internal); internal_enable_interrupt(touch_nr); TouchFuture::new(touch_nr).await; } diff --git a/esp-ieee802154/CHANGELOG.md b/esp-ieee802154/CHANGELOG.md index c1b96f7a120..b44d9109499 100644 --- a/esp-ieee802154/CHANGELOG.md +++ b/esp-ieee802154/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Removed `get_` prefixes from functions (#2528) + ### Fixed ### Removed diff --git a/esp-ieee802154/src/hal.rs b/esp-ieee802154/src/hal.rs index dd116715977..e3387ced8ca 100644 --- a/esp-ieee802154/src/hal.rs +++ b/esp-ieee802154/src/hal.rs @@ -255,7 +255,7 @@ pub(crate) fn set_freq(freq: u8) { } #[inline(always)] -pub(crate) fn get_freq() -> u8 { +pub(crate) fn freq() -> u8 { unsafe { &*IEEE802154::PTR }.channel().read().hop().bits() } @@ -344,7 +344,7 @@ pub(crate) fn set_tx_auto_ack(enable: bool) { } #[inline(always)] -pub(crate) fn get_tx_auto_ack() -> bool { +pub(crate) fn tx_auto_ack() -> bool { unsafe { &*IEEE802154::PTR } .ctrl_cfg() .read() @@ -367,7 +367,7 @@ pub(crate) fn set_tx_enhance_ack(enable: bool) { } #[inline(always)] -pub(crate) fn get_tx_enhance_ack() -> bool { +pub(crate) fn tx_enhance_ack() -> bool { unsafe { &*IEEE802154::PTR } .ctrl_cfg() .read() @@ -397,7 +397,7 @@ pub(crate) fn set_pending_mode(enable: bool) { } #[inline(always)] -pub(crate) fn get_events() -> u16 { +pub(crate) fn events() -> u16 { unsafe { &*IEEE802154::PTR }.event_status().read().bits() as u16 } diff --git a/esp-ieee802154/src/lib.rs b/esp-ieee802154/src/lib.rs index 4d0d43f9f6c..15d8bf3ad33 100644 --- a/esp-ieee802154/src/lib.rs +++ b/esp-ieee802154/src/lib.rs @@ -160,12 +160,12 @@ impl<'a> Ieee802154<'a> { } /// Return the raw data of a received frame - pub fn get_raw_received(&mut self) -> Option { + pub fn raw_received(&mut self) -> Option { ieee802154_poll() } /// Get a received frame, if available - pub fn get_received(&mut self) -> Option> { + pub fn received(&mut self) -> Option> { if let Some(raw) = ieee802154_poll() { let maybe_decoded = if raw.data[0] as usize > raw.data.len() { // try to decode up to data.len() diff --git a/esp-ieee802154/src/raw.rs b/esp-ieee802154/src/raw.rs index 73fb9b7175e..53f104743c2 100644 --- a/esp-ieee802154/src/raw.rs +++ b/esp-ieee802154/src/raw.rs @@ -252,7 +252,7 @@ fn enable_rx() { } fn stop_current_operation() { - let events = get_events(); + let events = events(); set_cmd(Command::Stop); clear_events(events); } @@ -359,7 +359,7 @@ fn next_operation() { fn ZB_MAC() { trace!("ZB_MAC interrupt"); - let events = get_events(); + let events = events(); clear_events(events); trace!("events = {:032b}", events); @@ -390,7 +390,7 @@ fn ZB_MAC() { if !queue.is_full() { let item = RawReceived { data: RX_BUFFER, - channel: freq_to_channel(get_freq()), + channel: freq_to_channel(freq()), }; queue.enqueue(item).ok(); } else { @@ -440,11 +440,9 @@ fn freq_to_channel(freq: u8) -> u8 { } fn will_auto_send_ack(frame: &[u8]) -> bool { - frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && get_tx_auto_ack() + frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && tx_auto_ack() } fn should_send_enhanced_ack(frame: &[u8]) -> bool { - frame_is_ack_required(frame) - && frame_get_version(frame) <= FRAME_VERSION_2 - && get_tx_enhance_ack() + frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_2 && tx_enhance_ack() } diff --git a/esp-lp-hal/src/uart.rs b/esp-lp-hal/src/uart.rs index 8ffd2ba0f06..dc8664267fb 100644 --- a/esp-lp-hal/src/uart.rs +++ b/esp-lp-hal/src/uart.rs @@ -170,7 +170,7 @@ pub struct LpUart { impl LpUart { /// Read a single byte from the UART in a non-blocking manner. pub fn read_byte(&mut self) -> nb::Result { - if self.get_rx_fifo_count() > 0 { + if self.rx_fifo_count() > 0 { let byte = self.uart.fifo().read().rxfifo_rd_byte().bits(); Ok(byte) } else { @@ -180,7 +180,7 @@ impl LpUart { /// Write a single byte to the UART in a non-blocking manner. pub fn write_byte(&mut self, byte: u8) -> nb::Result<(), Error> { - if self.get_tx_fifo_count() < UART_FIFO_SIZE { + if self.tx_fifo_count() < UART_FIFO_SIZE { self.uart .fifo() .write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) }); @@ -210,11 +210,11 @@ impl LpUart { } } - fn get_rx_fifo_count(&mut self) -> u16 { + fn rx_fifo_count(&mut self) -> u16 { self.uart.status().read().rxfifo_cnt().bits().into() } - fn get_tx_fifo_count(&mut self) -> u16 { + fn tx_fifo_count(&mut self) -> u16 { self.uart.status().read().txfifo_cnt().bits().into() } @@ -288,12 +288,12 @@ impl embedded_io::Read for LpUart { return Ok(0); } - while self.get_rx_fifo_count() == 0 { + while self.rx_fifo_count() == 0 { // Block until we have received at least one byte } let mut count = 0; - while self.get_rx_fifo_count() > 0 && count < buf.len() { + while self.rx_fifo_count() > 0 && count < buf.len() { buf[count] = self.uart.fifo().read().rxfifo_rd_byte().bits(); count += 1; } @@ -305,7 +305,7 @@ impl embedded_io::Read for LpUart { #[cfg(feature = "embedded-io")] impl embedded_io::ReadReady for LpUart { fn read_ready(&mut self) -> Result { - Ok(self.get_rx_fifo_count() > 0) + Ok(self.rx_fifo_count() > 0) } } diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 6d2275777c3..fec981690a2 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - esp-now: Data is now private in `ReceivedData` - use `data()`(#2396) - Changed the async APIs to have a `_async` postfix to avoid name collisions (#2446) - `phy_enable_usb` is enabled by default (#2446) +- Removed `get_` prefixes from functions (#2528) ### Fixed diff --git a/esp-wifi/MIGRATING-0.10.md b/esp-wifi/MIGRATING-0.10.md index 68f894d13f8..190311d46a9 100644 --- a/esp-wifi/MIGRATING-0.10.md +++ b/esp-wifi/MIGRATING-0.10.md @@ -61,7 +61,7 @@ use esp_wifi::{ + let mut rng = Rng::new(peripherals.RNG); - let init = init(timg0.timer0, rng, peripherals.RADIO_CLK).unwrap(); + let init = init(timg0.timer0, rng.clone(), peripherals.RADIO_CLK).unwrap(); - + let mut wifi = peripherals.WIFI; let mut socket_set_entries: [SocketStorage; 3] = Default::default(); + let (iface, device, mut controller) = @@ -76,3 +76,9 @@ use esp_wifi::{ ``` The related features are removed from `esp-wifi`: wifi-default, ipv6, ipv4, tcp, udp, icmp, igmp, dns, dhcpv4 + +## `get_` prefixes have been removed from functions + +In order to better comply with the Rust API Guidelines [getter names convention], we have removed the `get_` prefixes from all functions which previously had it. Due to the number of changes it's not practical to list all changes here, however if a function previous began with `get_`, you can simply remove this prefix. + +[getter names convention]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter diff --git a/esp-wifi/src/ble/controller/mod.rs b/esp-wifi/src/ble/controller/mod.rs index 7667a187982..41a6ae188cb 100644 --- a/esp-wifi/src/ble/controller/mod.rs +++ b/esp-wifi/src/ble/controller/mod.rs @@ -29,7 +29,7 @@ impl<'d> BleConnector<'d> { } } - pub fn get_next(&mut self, buf: &mut [u8]) -> Result { + pub fn next(&mut self, buf: &mut [u8]) -> Result { Ok(read_next(buf)) } } diff --git a/esp-wifi/src/common_adapter/common_adapter_esp32.rs b/esp-wifi/src/common_adapter/common_adapter_esp32.rs index 268311fe81c..82e215fbe9b 100644 --- a/esp-wifi/src/common_adapter/common_adapter_esp32.rs +++ b/esp-wifi/src/common_adapter/common_adapter_esp32.rs @@ -209,8 +209,9 @@ unsafe extern "C" fn phy_exit_critical(level: u32) { #[ram] #[no_mangle] unsafe extern "C" fn rtc_get_xtal() -> u32 { - use crate::hal::clock::Clock; - let xtal = crate::hal::rtc_cntl::RtcClock::get_xtal_freq(); + use esp_hal::clock::Clock; + + let xtal = crate::hal::rtc_cntl::RtcClock::xtal_freq(); xtal.mhz() } diff --git a/esp-wifi/src/common_adapter/mod.rs b/esp-wifi/src/common_adapter/mod.rs index e41dc17ec9f..67bf299889e 100644 --- a/esp-wifi/src/common_adapter/mod.rs +++ b/esp-wifi/src/common_adapter/mod.rs @@ -137,7 +137,7 @@ pub unsafe extern "C" fn random() -> crate::binary::c_types::c_ulong { pub unsafe extern "C" fn read_mac(mac: *mut u8, type_: u32) -> crate::binary::c_types::c_int { trace!("read_mac {:?} {}", mac, type_); - let base_mac = crate::hal::efuse::Efuse::get_mac_address(); + let base_mac = crate::hal::efuse::Efuse::mac_address(); for (i, &byte) in base_mac.iter().enumerate() { mac.add(i).write_volatile(byte); diff --git a/esp-wifi/src/compat/common.rs b/esp-wifi/src/compat/common.rs index 946650f75c2..784c0366ceb 100644 --- a/esp-wifi/src/compat/common.rs +++ b/esp-wifi/src/compat/common.rs @@ -207,7 +207,7 @@ pub(crate) fn sem_take(semphr: *mut c_void, tick: u32) -> i32 { let forever = tick == OSI_FUNCS_TIME_BLOCKING; let timeout = tick as u64; - let start = crate::timer::get_systimer_count(); + let start = crate::timer::systimer_count(); let sem = semphr as *mut u32; @@ -377,7 +377,7 @@ pub(crate) fn receive_queued( let forever = block_time_tick == OSI_FUNCS_TIME_BLOCKING; let timeout = block_time_tick as u64; - let start = crate::timer::get_systimer_count(); + let start = crate::timer::systimer_count(); loop { if unsafe { (*queue).try_dequeue(item) } { diff --git a/esp-wifi/src/compat/timer_compat.rs b/esp-wifi/src/compat/timer_compat.rs index c7f67ea4778..62204f12bea 100644 --- a/esp-wifi/src/compat/timer_compat.rs +++ b/esp-wifi/src/compat/timer_compat.rs @@ -145,7 +145,7 @@ pub(crate) fn compat_timer_arm(ets_timer: *mut ets_timer, tmout: u32, repeat: bo } pub(crate) fn compat_timer_arm_us(ets_timer: *mut ets_timer, us: u32, repeat: bool) { - let systick = crate::timer::get_systimer_count(); + let systick = crate::timer::systimer_count(); let ticks = crate::timer::micros_to_ticks(us as u64); trace!( diff --git a/esp-wifi/src/esp_now/mod.rs b/esp-wifi/src/esp_now/mod.rs index d4f26fdb6fe..4ee12c909e1 100644 --- a/esp-wifi/src/esp_now/mod.rs +++ b/esp-wifi/src/esp_now/mod.rs @@ -352,7 +352,7 @@ impl EspNowManager<'_> { } /// Get the version of ESP-NOW. - pub fn get_version(&self) -> Result { + pub fn version(&self) -> Result { let mut version = 0u32; check_error!({ esp_now_get_version(&mut version as *mut u32) })?; Ok(version) @@ -404,7 +404,7 @@ impl EspNowManager<'_> { } /// Get peer by MAC address. - pub fn get_peer(&self, peer_address: &[u8; 6]) -> Result { + pub fn peer(&self, peer_address: &[u8; 6]) -> Result { let mut raw_peer = esp_now_peer_info_t { peer_addr: [0u8; 6], lmk: [0u8; 16], @@ -744,8 +744,8 @@ impl<'d> EspNow<'d> { } /// Get the version of ESP-NOW. - pub fn get_version(&self) -> Result { - self.manager.get_version() + pub fn version(&self) -> Result { + self.manager.version() } /// Add a peer to the list of known peers. @@ -764,8 +764,8 @@ impl<'d> EspNow<'d> { } /// Get peer by MAC address. - pub fn get_peer(&self, peer_address: &[u8; 6]) -> Result { - self.manager.get_peer(peer_address) + pub fn peer(&self, peer_address: &[u8; 6]) -> Result { + self.manager.peer(peer_address) } /// Fetch a peer from peer list. diff --git a/esp-wifi/src/tasks.rs b/esp-wifi/src/tasks.rs index 21df825955d..7dae1e046b6 100644 --- a/esp-wifi/src/tasks.rs +++ b/esp-wifi/src/tasks.rs @@ -1,7 +1,7 @@ use crate::{ compat::timer_compat::TIMERS, preempt::arch_specific::task_create, - timer::{get_systimer_count, yield_task}, + timer::{systimer_count, yield_task}, }; /// Initializes the `main` and `timer` tasks for the Wi-Fi driver. @@ -17,7 +17,7 @@ pub(crate) fn init_tasks() { /// events. pub(crate) extern "C" fn timer_task(_param: *mut esp_wifi_sys::c_types::c_void) { loop { - let current_timestamp = get_systimer_count(); + let current_timestamp = systimer_count(); let to_run = critical_section::with(|cs| unsafe { let mut timers = TIMERS.borrow_ref_mut(cs); let to_run = timers.find_next_due(current_timestamp); diff --git a/esp-wifi/src/timer/mod.rs b/esp-wifi/src/timer/mod.rs index d806fd9111a..0cd4d541ef2 100644 --- a/esp-wifi/src/timer/mod.rs +++ b/esp-wifi/src/timer/mod.rs @@ -62,6 +62,6 @@ pub(crate) fn ticks_to_millis(ticks: u64) -> u64 { /// Do not call this in a critical section! pub(crate) fn elapsed_time_since(start: u64) -> u64 { - let now = get_systimer_count(); + let now = systimer_count(); time_diff(start, now) } diff --git a/esp-wifi/src/timer/riscv.rs b/esp-wifi/src/timer/riscv.rs index 8cb7c919144..b0a4bb2635f 100644 --- a/esp-wifi/src/timer/riscv.rs +++ b/esp-wifi/src/timer/riscv.rs @@ -95,7 +95,7 @@ pub(crate) fn yield_task() { /// Current systimer count value /// A tick is 1 / 1_000_000 seconds -pub(crate) fn get_systimer_count() -> u64 { +pub(crate) fn systimer_count() -> u64 { esp_hal::time::now().ticks() } diff --git a/esp-wifi/src/timer/xtensa.rs b/esp-wifi/src/timer/xtensa.rs index dedb61b4a42..3cff547ac06 100644 --- a/esp-wifi/src/timer/xtensa.rs +++ b/esp-wifi/src/timer/xtensa.rs @@ -17,7 +17,7 @@ pub const TICKS_PER_SECOND: u64 = 1_000_000; /// This function must not be called in a critical section. Doing so may return /// an incorrect value. -pub(crate) fn get_systimer_count() -> u64 { +pub(crate) fn systimer_count() -> u64 { esp_hal::time::now().ticks() } diff --git a/esp-wifi/src/wifi/mod.rs b/esp-wifi/src/wifi/mod.rs index cad2758a276..7bb5ce6ce06 100644 --- a/esp-wifi/src/wifi/mod.rs +++ b/esp-wifi/src/wifi/mod.rs @@ -1465,14 +1465,14 @@ static mut G_CONFIG: wifi_init_config_t = wifi_init_config_t { }; /// Get the STA MAC address -pub fn get_sta_mac(mac: &mut [u8; 6]) { +pub fn sta_mac(mac: &mut [u8; 6]) { unsafe { read_mac(mac as *mut u8, 0); } } /// Get the AP MAC address -pub fn get_ap_mac(mac: &mut [u8; 6]) { +pub fn ap_mac(mac: &mut [u8; 6]) { unsafe { read_mac(mac as *mut u8, 1); } @@ -1984,7 +1984,7 @@ mod sealed { } fn link_state(self) -> embassy_net_driver::LinkState { - if matches!(get_sta_state(), WifiState::StaConnected) { + if matches!(sta_state(), WifiState::StaConnected) { embassy_net_driver::LinkState::Up } else { embassy_net_driver::LinkState::Down @@ -2020,7 +2020,7 @@ mod sealed { } fn link_state(self) -> embassy_net_driver::LinkState { - if matches!(get_ap_state(), WifiState::ApStarted) { + if matches!(ap_state(), WifiState::ApStarted) { embassy_net_driver::LinkState::Up } else { embassy_net_driver::LinkState::Down @@ -2052,7 +2052,7 @@ impl WifiDeviceMode for WifiStaDevice { fn mac_address(self) -> [u8; 6] { let mut mac = [0; 6]; - get_sta_mac(&mut mac); + sta_mac(&mut mac); mac } } @@ -2069,7 +2069,7 @@ impl WifiDeviceMode for WifiApDevice { fn mac_address(self) -> [u8; 6] { let mut mac = [0; 6]; - get_ap_mac(&mut mac); + ap_mac(&mut mac); mac } } @@ -2986,7 +2986,7 @@ fn apply_sta_eap_config(config: &EapClientConfiguration) -> Result<(), WifiError impl WifiController<'_> { /// Get the supported capabilities of the controller. - pub fn get_capabilities(&self) -> Result, WifiError> { + pub fn capabilities(&self) -> Result, WifiError> { let caps = match self.config { Configuration::None => unreachable!(), Configuration::Client(_) => enumset::enum_set! { Capability::Client }, @@ -3001,7 +3001,7 @@ impl WifiController<'_> { } /// Get the currently used configuration. - pub fn get_configuration(&self) -> Result { + pub fn configuration(&self) -> Result { Ok(self.config.clone()) } @@ -3071,12 +3071,12 @@ impl WifiController<'_> { /// WiFi has started successfully. pub fn is_started(&self) -> Result { if matches!( - crate::wifi::get_sta_state(), + crate::wifi::sta_state(), WifiState::StaStarted | WifiState::StaConnected | WifiState::StaDisconnected ) { return Ok(true); } - if matches!(crate::wifi::get_ap_state(), WifiState::ApStarted) { + if matches!(crate::wifi::ap_state(), WifiState::ApStarted) { return Ok(true); } Ok(false) @@ -3087,7 +3087,7 @@ impl WifiController<'_> { /// This function should be called after the `connect` method to verify if /// the connection was successful. pub fn is_connected(&self) -> Result { - match crate::wifi::get_sta_state() { + match crate::wifi::sta_state() { crate::wifi::WifiState::StaConnected => Ok(true), crate::wifi::WifiState::StaDisconnected => Err(WifiError::Disconnected), // FIXME: Should any other enum value trigger an error instead of returning false? diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index 862ae5cb2be..1fe92992fda 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -734,7 +734,7 @@ pub unsafe extern "C" fn task_delete(task_handle: *mut crate::binary::c_types::c /// ************************************************************************* pub unsafe extern "C" fn task_delay(tick: u32) { trace!("task_delay tick {}", tick); - let start_time = crate::timer::get_systimer_count(); + let start_time = crate::timer::systimer_count(); while crate::timer::elapsed_time_since(start_time) < tick as u64 { yield_task(); } @@ -1126,7 +1126,7 @@ pub unsafe extern "C" fn wifi_rtc_disable_iso() { #[no_mangle] pub unsafe extern "C" fn esp_timer_get_time() -> i64 { trace!("esp_timer_get_time"); - crate::timer::ticks_to_micros(crate::timer::get_systimer_count()) as i64 + crate::timer::ticks_to_micros(crate::timer::systimer_count()) as i64 } /// ************************************************************************** diff --git a/esp-wifi/src/wifi/state.rs b/esp-wifi/src/wifi/state.rs index 5072091488b..5180bbf18be 100644 --- a/esp-wifi/src/wifi/state.rs +++ b/esp-wifi/src/wifi/state.rs @@ -38,12 +38,12 @@ pub(crate) static STA_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::I pub(crate) static AP_STATE: AtomicWifiState = AtomicWifiState::new(WifiState::Invalid); /// Get the current state of the AP -pub fn get_ap_state() -> WifiState { +pub fn ap_state() -> WifiState { AP_STATE.load(Ordering::Relaxed) } /// Get the current state of the STA -pub fn get_sta_state() -> WifiState { +pub fn sta_state() -> WifiState { STA_STATE.load(Ordering::Relaxed) } @@ -76,13 +76,13 @@ pub(crate) fn reset_sta_state() { /// Returns the current state of the WiFi stack. /// -/// This does not support AP-STA mode. Use one of `get_sta_state` or -/// `get_ap_state` instead. -pub fn get_wifi_state() -> WifiState { +/// This does not support AP-STA mode. Use one of `sta_state` or +/// `ap_state` instead. +pub fn wifi_state() -> WifiState { use super::WifiMode; match WifiMode::current() { - Ok(WifiMode::Sta) => get_sta_state(), - Ok(WifiMode::Ap) => get_ap_state(), + Ok(WifiMode::Sta) => sta_state(), + Ok(WifiMode::Ap) => ap_state(), _ => WifiState::Invalid, } } diff --git a/examples/src/bin/debug_assist.rs b/examples/src/bin/debug_assist.rs index 639037f5cfe..1fa35ae63c7 100644 --- a/examples/src/bin/debug_assist.rs +++ b/examples/src/bin/debug_assist.rs @@ -87,7 +87,7 @@ fn interrupt_handler() { if da.is_sp_monitor_interrupt_set() { println!("SP MONITOR TRIGGERED"); da.clear_sp_monitor_interrupt(); - let pc = da.get_sp_monitor_pc(); + let pc = da.sp_monitor_pc(); println!("PC = 0x{:x}", pc); } @@ -95,7 +95,7 @@ fn interrupt_handler() { if da.is_region0_monitor_interrupt_set() { println!("REGION0 MONITOR TRIGGERED"); da.clear_region0_monitor_interrupt(); - let pc = da.get_region_monitor_pc(); + let pc = da.region_monitor_pc(); println!("PC = 0x{:x}", pc); } @@ -103,7 +103,7 @@ fn interrupt_handler() { if da.is_region1_monitor_interrupt_set() { println!("REGION1 MONITOR TRIGGERED"); da.clear_region1_monitor_interrupt(); - let pc = da.get_region_monitor_pc(); + let pc = da.region_monitor_pc(); println!("PC = 0x{:x}", pc); } diff --git a/examples/src/bin/embassy_multicore.rs b/examples/src/bin/embassy_multicore.rs index 6def339d64d..f3ed022ad7d 100644 --- a/examples/src/bin/embassy_multicore.rs +++ b/examples/src/bin/embassy_multicore.rs @@ -19,8 +19,8 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal} use embassy_time::{Duration, Ticker}; use esp_backtrace as _; use esp_hal::{ + core, cpu_control::{CpuControl, Stack}, - get_core, gpio::{Level, Output}, timer::{timg::TimerGroup, AnyTimer}, }; @@ -37,7 +37,7 @@ async fn control_led( mut led: Output<'static>, control: &'static Signal, ) { - println!("Starting control_led() on core {}", get_core() as usize); + println!("Starting control_led() on core {}", core() as usize); loop { if control.wait().await { esp_println::println!("LED on"); @@ -76,10 +76,7 @@ async fn main(_spawner: Spawner) { .unwrap(); // Sends periodic messages to control_led, enabling or disabling it. - println!( - "Starting enable_disable_led() on core {}", - get_core() as usize - ); + println!("Starting enable_disable_led() on core {}", core() as usize); let mut ticker = Ticker::every(Duration::from_secs(1)); loop { esp_println::println!("Sending LED on"); diff --git a/examples/src/bin/embassy_multicore_interrupt.rs b/examples/src/bin/embassy_multicore_interrupt.rs index 7a1de606c95..5d1e53082a2 100644 --- a/examples/src/bin/embassy_multicore_interrupt.rs +++ b/examples/src/bin/embassy_multicore_interrupt.rs @@ -18,8 +18,8 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal} use embassy_time::{Duration, Ticker}; use esp_backtrace as _; use esp_hal::{ + core, cpu_control::{CpuControl, Stack}, - get_core, gpio::{Level, Output}, interrupt::{software::SoftwareInterruptControl, Priority}, prelude::*, @@ -38,7 +38,7 @@ async fn control_led( mut led: Output<'static>, control: &'static Signal, ) { - println!("Starting control_led() on core {}", get_core() as usize); + println!("Starting control_led() on core {}", core() as usize); loop { if control.wait().await { esp_println::println!("LED on"); @@ -53,10 +53,7 @@ async fn control_led( /// Sends periodic messages to control_led, enabling or disabling it. #[embassy_executor::task] async fn enable_disable_led(control: &'static Signal) { - println!( - "Starting enable_disable_led() on core {}", - get_core() as usize - ); + println!("Starting enable_disable_led() on core {}", core() as usize); let mut ticker = Ticker::every(Duration::from_secs(1)); loop { esp_println::println!("Sending LED on"); diff --git a/examples/src/bin/ieee802154_receive_all_frames.rs b/examples/src/bin/ieee802154_receive_all_frames.rs index f92ff43b2f0..a4ea1a5b017 100644 --- a/examples/src/bin/ieee802154_receive_all_frames.rs +++ b/examples/src/bin/ieee802154_receive_all_frames.rs @@ -26,7 +26,7 @@ fn main() -> ! { ieee802154.start_receive(); loop { - if let Some(frame) = ieee802154.get_received() { + if let Some(frame) = ieee802154.received() { println!("Received {:?}\n", &frame); } } diff --git a/examples/src/bin/ieee802154_receive_frame.rs b/examples/src/bin/ieee802154_receive_frame.rs index e1ee7e164df..ca47f53c35b 100644 --- a/examples/src/bin/ieee802154_receive_frame.rs +++ b/examples/src/bin/ieee802154_receive_frame.rs @@ -28,7 +28,7 @@ fn main() -> ! { ieee802154.start_receive(); loop { - if let Some(frame) = ieee802154.get_received() { + if let Some(frame) = ieee802154.received() { println!("Received {:?}\n", &frame); } } diff --git a/examples/src/bin/ieee802154_sniffer.rs b/examples/src/bin/ieee802154_sniffer.rs index 55b8d29afbe..e8ac85cffdc 100644 --- a/examples/src/bin/ieee802154_sniffer.rs +++ b/examples/src/bin/ieee802154_sniffer.rs @@ -62,7 +62,7 @@ fn main() -> ! { ieee802154.start_receive(); loop { - if let Some(frame) = ieee802154.get_raw_received() { + if let Some(frame) = ieee802154.raw_received() { println!("@RAW {:02x?}", &frame.data); } diff --git a/examples/src/bin/ledc.rs b/examples/src/bin/ledc.rs index ce7b3bdd78a..c2358b3b5ad 100644 --- a/examples/src/bin/ledc.rs +++ b/examples/src/bin/ledc.rs @@ -31,7 +31,7 @@ fn main() -> ! { ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); - let mut lstimer0 = ledc.get_timer::(timer::Number::Timer0); + let mut lstimer0 = ledc.timer::(timer::Number::Timer0); lstimer0 .configure(timer::config::Config { @@ -41,7 +41,7 @@ fn main() -> ! { }) .unwrap(); - let mut channel0 = ledc.get_channel(channel::Number::Channel0, led); + let mut channel0 = ledc.channel(channel::Number::Channel0, led); channel0 .configure(channel::config::Config { timer: &lstimer0, diff --git a/examples/src/bin/pcnt_encoder.rs b/examples/src/bin/pcnt_encoder.rs index 29a9a1a6b20..35b716df94c 100644 --- a/examples/src/bin/pcnt_encoder.rs +++ b/examples/src/bin/pcnt_encoder.rs @@ -91,7 +91,7 @@ fn interrupt_handler() { let mut u0 = UNIT0.borrow_ref_mut(cs); let u0 = u0.as_mut().unwrap(); if u0.interrupt_is_set() { - let events = u0.get_events(); + let events = u0.events(); if events.high_limit { VALUE.fetch_add(100, Ordering::SeqCst); } else if events.low_limit { diff --git a/examples/src/bin/read_efuse.rs b/examples/src/bin/read_efuse.rs index b3d7163ec6f..d1f2024d146 100644 --- a/examples/src/bin/read_efuse.rs +++ b/examples/src/bin/read_efuse.rs @@ -14,15 +14,15 @@ use esp_println::println; #[entry] fn main() -> ! { - println!("MAC address {:02x?}", Efuse::get_mac_address()); - println!("Flash Encryption {:?}", Efuse::get_flash_encryption()); + println!("MAC address {:02x?}", Efuse::mac_address()); + println!("Flash Encryption {:?}", Efuse::flash_encryption()); #[cfg(feature = "esp32")] { - println!("Core Count {}", Efuse::get_core_count()); + println!("Core Count {}", Efuse::core_count()); println!("Bluetooth enabled {}", Efuse::is_bluetooth_enabled()); - println!("Chip type {:?}", Efuse::get_chip_type()); - println!("Max CPU clock {:?}", Efuse::get_max_cpu_frequency()); + println!("Chip type {:?}", Efuse::chip_type()); + println!("Max CPU clock {:?}", Efuse::max_cpu_frequency()); } loop {} diff --git a/examples/src/bin/sleep_timer.rs b/examples/src/bin/sleep_timer.rs index b742c9c5c84..18eccba9eac 100644 --- a/examples/src/bin/sleep_timer.rs +++ b/examples/src/bin/sleep_timer.rs @@ -11,7 +11,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, entry, - rtc_cntl::{get_reset_reason, get_wakeup_cause, sleep::TimerWakeupSource, Rtc, SocResetReason}, + rtc_cntl::{reset_reason, sleep::TimerWakeupSource, wakeup_cause, Rtc, SocResetReason}, Cpu, }; use esp_println::println; @@ -24,9 +24,9 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); println!("up and runnning!"); - let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + let reason = reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); println!("reset reason: {:?}", reason); - let wake_reason = get_wakeup_cause(); + let wake_reason = wakeup_cause(); println!("wake reason: {:?}", wake_reason); let timer = TimerWakeupSource::new(Duration::from_secs(5)); diff --git a/examples/src/bin/sleep_timer_ext0.rs b/examples/src/bin/sleep_timer_ext0.rs index f026bbc68b1..a76973af8bf 100644 --- a/examples/src/bin/sleep_timer_ext0.rs +++ b/examples/src/bin/sleep_timer_ext0.rs @@ -16,9 +16,9 @@ use esp_hal::{ entry, gpio::{Input, Pull}, rtc_cntl::{ - get_reset_reason, - get_wakeup_cause, + reset_reason, sleep::{Ext0WakeupSource, TimerWakeupSource, WakeupLevel}, + wakeup_cause, Rtc, SocResetReason, }, @@ -35,9 +35,9 @@ fn main() -> ! { let ext0_pin = Input::new(peripherals.GPIO4, Pull::None); println!("up and runnning!"); - let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + let reason = reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); println!("reset reason: {:?}", reason); - let wake_reason = get_wakeup_cause(); + let wake_reason = wakeup_cause(); println!("wake reason: {:?}", wake_reason); let delay = Delay::new(); diff --git a/examples/src/bin/sleep_timer_ext1.rs b/examples/src/bin/sleep_timer_ext1.rs index 783a4a26af7..300759c5c5b 100644 --- a/examples/src/bin/sleep_timer_ext1.rs +++ b/examples/src/bin/sleep_timer_ext1.rs @@ -17,9 +17,9 @@ use esp_hal::{ gpio::{Input, Pull, RtcPin}, peripheral::Peripheral, rtc_cntl::{ - get_reset_reason, - get_wakeup_cause, + reset_reason, sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, + wakeup_cause, Rtc, SocResetReason, }, @@ -37,9 +37,9 @@ fn main() -> ! { let mut pin_2 = peripherals.GPIO2; println!("up and runnning!"); - let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + let reason = reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); println!("reset reason: {:?}", reason); - let wake_reason = get_wakeup_cause(); + let wake_reason = wakeup_cause(); println!("wake reason: {:?}", wake_reason); let delay = Delay::new(); diff --git a/examples/src/bin/sleep_timer_lpio.rs b/examples/src/bin/sleep_timer_lpio.rs index 8ae16d28eb4..6b432bd940e 100644 --- a/examples/src/bin/sleep_timer_lpio.rs +++ b/examples/src/bin/sleep_timer_lpio.rs @@ -18,9 +18,9 @@ use esp_hal::{ gpio::{Input, Pull, RtcPinWithResistors}, peripheral::Peripheral, rtc_cntl::{ - get_reset_reason, - get_wakeup_cause, + reset_reason, sleep::{Ext1WakeupSource, TimerWakeupSource, WakeupLevel}, + wakeup_cause, Rtc, SocResetReason, }, @@ -38,9 +38,9 @@ fn main() -> ! { let mut pin3 = peripherals.GPIO3; println!("up and runnning!"); - let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + let reason = reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); println!("reset reason: {:?}", reason); - let wake_reason = get_wakeup_cause(); + let wake_reason = wakeup_cause(); println!("wake reason: {:?}", wake_reason); let delay = Delay::new(); diff --git a/examples/src/bin/sleep_timer_rtcio.rs b/examples/src/bin/sleep_timer_rtcio.rs index a04c7892ecb..f2af3eb9a3b 100644 --- a/examples/src/bin/sleep_timer_rtcio.rs +++ b/examples/src/bin/sleep_timer_rtcio.rs @@ -22,9 +22,9 @@ use esp_hal::{ gpio::{Input, Pull}, peripheral::Peripheral, rtc_cntl::{ - get_reset_reason, - get_wakeup_cause, + reset_reason, sleep::{RtcioWakeupSource, TimerWakeupSource, WakeupLevel}, + wakeup_cause, Rtc, SocResetReason, }, @@ -39,9 +39,9 @@ fn main() -> ! { let mut rtc = Rtc::new(peripherals.LPWR); println!("up and runnning!"); - let reason = get_reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); + let reason = reset_reason(Cpu::ProCpu).unwrap_or(SocResetReason::ChipPowerOn); println!("reset reason: {:?}", reason); - let wake_reason = get_wakeup_cause(); + let wake_reason = wakeup_cause(); println!("wake reason: {:?}", wake_reason); let delay = Delay::new(); diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index fcd699cd09b..249c3b32332 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -91,7 +91,7 @@ fn main() -> ! { controller.start().unwrap(); println!("is wifi started: {:?}", controller.is_started()); - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); stack .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index 74ce52e5b0c..4321ca14259 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -97,7 +97,7 @@ fn main() -> ! { controller.start().unwrap(); println!("is wifi started: {:?}", controller.is_started()); - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); ap_stack .set_iface_configuration(&blocking_network_stack::ipv4::Configuration::Client( diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index 1efd7800af1..e561c0f2de6 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -109,7 +109,7 @@ fn main() -> ! { } } - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index 2c7b936d84e..c6926b3bc09 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -114,7 +114,7 @@ fn main() -> ! { controller.start().unwrap(); println!("is wifi started: {:?}", controller.is_started()); - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/examples/src/bin/wifi_csi.rs b/examples/src/bin/wifi_csi.rs index eca2d392bfc..fd06cfe4987 100644 --- a/examples/src/bin/wifi_csi.rs +++ b/examples/src/bin/wifi_csi.rs @@ -109,7 +109,7 @@ fn main() -> ! { } } - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index 020fe6303e9..81b9541575f 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -97,7 +97,7 @@ fn main() -> ! { } } - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/examples/src/bin/wifi_dhcp_smoltcp_nal.rs b/examples/src/bin/wifi_dhcp_smoltcp_nal.rs index 118f74b9ab1..a4ad4ca6da7 100644 --- a/examples/src/bin/wifi_dhcp_smoltcp_nal.rs +++ b/examples/src/bin/wifi_dhcp_smoltcp_nal.rs @@ -107,7 +107,7 @@ fn main() -> ! { } } - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index 5ade028bb1b..6296dbc598b 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -203,9 +203,9 @@ async fn main(spawner: Spawner) -> ! { #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { println!("start connection task"); - println!("Device capabilities: {:?}", controller.get_capabilities()); + println!("Device capabilities: {:?}", controller.capabilities()); loop { - match esp_wifi::wifi::get_wifi_state() { + match esp_wifi::wifi::wifi_state() { WifiState::ApStarted => { // wait until we're no longer connected controller.wait_for_event(WifiEvent::ApStop).await; diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index fe0e2e956e7..15eea34e088 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -312,14 +312,14 @@ async fn main(spawner: Spawner) -> ! { #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { println!("start connection task"); - println!("Device capabilities: {:?}", controller.get_capabilities()); + println!("Device capabilities: {:?}", controller.capabilities()); println!("Starting wifi"); controller.start_async().await.unwrap(); println!("Wifi started!"); loop { - match esp_wifi::wifi::get_ap_state() { + match esp_wifi::wifi::ap_state() { WifiState::ApStarted => { println!("About to connect..."); diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 9b3ecd8ca4c..cb3b843654d 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -175,9 +175,9 @@ async fn main(spawner: Spawner) -> ! { #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { println!("start connection task"); - println!("Device capabilities: {:?}", controller.get_capabilities()); + println!("Device capabilities: {:?}", controller.capabilities()); loop { - match esp_wifi::wifi::get_wifi_state() { + match esp_wifi::wifi::wifi_state() { WifiState::StaConnected => { // wait until we're no longer connected controller.wait_for_event(WifiEvent::StaDisconnected).await; diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 5adc1838bc7..2f896c422cd 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -167,9 +167,9 @@ async fn main(spawner: Spawner) -> ! { #[embassy_executor::task] async fn connection(mut controller: WifiController<'static>) { println!("start connection task"); - println!("Device capabilities: {:?}", controller.get_capabilities()); + println!("Device capabilities: {:?}", controller.capabilities()); loop { - match esp_wifi::wifi::get_wifi_state() { + match esp_wifi::wifi::wifi_state() { WifiState::StaConnected => { // wait until we're no longer connected controller.wait_for_event(WifiEvent::StaDisconnected).await; diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index 3476734f45c..a99b3c74a02 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -58,7 +58,7 @@ async fn main(_spawner: Spawner) -> ! { let wifi = peripherals.WIFI; let mut esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); - println!("esp-now version {}", esp_now.get_version().unwrap()); + println!("esp-now version {}", esp_now.version().unwrap()); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 7b2e6cdf27f..f75d5d65ea5 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -58,7 +58,7 @@ async fn main(spawner: Spawner) -> ! { let wifi = peripherals.WIFI; let esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); - println!("esp-now version {}", esp_now.get_version().unwrap()); + println!("esp-now version {}", esp_now.version().unwrap()); cfg_if::cfg_if! { if #[cfg(feature = "esp32")] { diff --git a/examples/src/bin/wifi_esp_now.rs b/examples/src/bin/wifi_esp_now.rs index 974f19987ff..dc32a787900 100644 --- a/examples/src/bin/wifi_esp_now.rs +++ b/examples/src/bin/wifi_esp_now.rs @@ -45,7 +45,7 @@ fn main() -> ! { let wifi = peripherals.WIFI; let mut esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); - println!("esp-now version {}", esp_now.get_version().unwrap()); + println!("esp-now version {}", esp_now.version().unwrap()); let mut next_send_time = time::now() + Duration::secs(5); loop { diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index 1d7958c6c7b..8344a610305 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -88,7 +88,7 @@ fn main() -> ! { } } - println!("{:?}", controller.get_capabilities()); + println!("{:?}", controller.capabilities()); println!("wifi_connect {:?}", controller.connect()); // wait to get connected diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 33a76d04c36..987a0ad543a 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -212,10 +212,10 @@ mod tests { xfer.wait().0.unwrap(); let actual = [ - pcnt.unit0.get_value(), - pcnt.unit1.get_value(), - pcnt.unit2.get_value(), - pcnt.unit3.get_value(), + pcnt.unit0.value(), + pcnt.unit1.value(), + pcnt.unit2.value(), + pcnt.unit3.value(), ]; let expected = [5, 3, 2, 1]; @@ -339,10 +339,10 @@ mod tests { xfer.wait().0.unwrap(); let actual = [ - pcnt.unit0.get_value(), - pcnt.unit1.get_value(), - pcnt.unit2.get_value(), - pcnt.unit3.get_value(), + pcnt.unit0.value(), + pcnt.unit1.value(), + pcnt.unit2.value(), + pcnt.unit3.value(), ]; let expected = [5, 3, 2, 1]; diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index 8924c11ada8..a43659bdc8c 100644 --- a/hil-test/tests/parl_io_tx.rs +++ b/hil-test/tests/parl_io_tx.rs @@ -122,8 +122,8 @@ mod tests { clock_unit.clear(); let xfer = pio.write_dma(&tx_buffer).unwrap(); xfer.wait().unwrap(); - info!("clock count: {}", clock_unit.get_value()); - assert_eq!(clock_unit.get_value(), BUFFER_SIZE as _); + info!("clock count: {}", clock_unit.value()); + assert_eq!(clock_unit.value(), BUFFER_SIZE as _); } } @@ -189,8 +189,8 @@ mod tests { clock_unit.clear(); let xfer = pio.write_dma(&tx_buffer).unwrap(); xfer.wait().unwrap(); - info!("clock count: {}", clock_unit.get_value()); - assert_eq!(clock_unit.get_value(), BUFFER_SIZE as _); + info!("clock count: {}", clock_unit.value()); + assert_eq!(clock_unit.value(), BUFFER_SIZE as _); } } } diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index a38719ec7e6..240a805c0e6 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -125,8 +125,8 @@ mod tests { for _ in 0..100 { clock_unit.clear(); pio.write_dma_async(&tx_buffer).await.unwrap(); - info!("clock count: {}", clock_unit.get_value()); - assert_eq!(clock_unit.get_value(), BUFFER_SIZE as _); + info!("clock count: {}", clock_unit.value()); + assert_eq!(clock_unit.value(), BUFFER_SIZE as _); } } @@ -193,8 +193,8 @@ mod tests { for _ in 0..100 { clock_unit.clear(); pio.write_dma_async(&tx_buffer).await.unwrap(); - info!("clock count: {}", clock_unit.get_value()); - assert_eq!(clock_unit.get_value(), BUFFER_SIZE as _); + info!("clock count: {}", clock_unit.value()); + assert_eq!(clock_unit.value(), BUFFER_SIZE as _); } } } diff --git a/hil-test/tests/pcnt.rs b/hil-test/tests/pcnt.rs index 7c18e62b1b9..482e7e256a3 100644 --- a/hil-test/tests/pcnt.rs +++ b/hil-test/tests/pcnt.rs @@ -55,27 +55,27 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); output.set_low(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); output.set_low(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); } #[test] @@ -92,27 +92,27 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); output.set_low(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); output.set_low(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); } #[test] @@ -131,29 +131,29 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(0, unit.get_value()); - assert!(unit.get_events().high_limit); + assert_eq!(0, unit.value()); + assert!(unit.events().high_limit); assert!(unit.interrupt_is_set()); output.set_low(); @@ -161,16 +161,16 @@ mod tests { output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); // high limit event remains after next increment. - assert!(unit.get_events().high_limit); + assert!(unit.events().high_limit); unit.reset_interrupt(); assert!(!unit.interrupt_is_set()); // high limit event remains after interrupt is cleared. - assert!(unit.get_events().high_limit); + assert!(unit.events().high_limit); } #[test] @@ -192,27 +192,27 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(1, unit.get_value()); + assert_eq!(1, unit.value()); assert!(!unit.interrupt_is_set()); - assert!(!unit.get_events().threshold0); - assert!(!unit.get_events().threshold1); + assert!(!unit.events().threshold0); + assert!(!unit.events().threshold1); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(2, unit.get_value()); + assert_eq!(2, unit.value()); assert!(unit.interrupt_is_set()); - assert!(unit.get_events().threshold0); - assert!(!unit.get_events().threshold1); + assert!(unit.events().threshold0); + assert!(!unit.events().threshold1); unit.reset_interrupt(); @@ -221,22 +221,22 @@ mod tests { output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(3, unit.get_value()); + assert_eq!(3, unit.value()); assert!(!unit.interrupt_is_set()); // threshold event remains after next increment and after interrupt is cleared. - assert!(unit.get_events().threshold0); - assert!(!unit.get_events().threshold1); + assert!(unit.events().threshold0); + assert!(!unit.events().threshold1); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(4, unit.get_value()); + assert_eq!(4, unit.value()); assert!(unit.interrupt_is_set()); // threshold event cleared after new event occurs. - assert!(!unit.get_events().threshold0); - assert!(unit.get_events().threshold1); + assert!(!unit.events().threshold0); + assert!(unit.events().threshold1); } #[test] @@ -257,29 +257,29 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(-1, unit.get_value()); + assert_eq!(-1, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(-2, unit.get_value()); + assert_eq!(-2, unit.value()); output.set_low(); ctx.delay.delay_micros(1); output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(0, unit.get_value()); - assert!(unit.get_events().low_limit); + assert_eq!(0, unit.value()); + assert!(unit.events().low_limit); assert!(unit.interrupt_is_set()); output.set_low(); @@ -287,16 +287,16 @@ mod tests { output.set_high(); ctx.delay.delay_micros(1); - assert_eq!(-1, unit.get_value()); + assert_eq!(-1, unit.value()); // low limit event remains after next increment. - assert!(unit.get_events().low_limit); + assert!(unit.events().low_limit); unit.reset_interrupt(); assert!(!unit.interrupt_is_set()); // low limit event remains after interrupt is cleared. - assert!(unit.get_events().low_limit); + assert!(unit.events().low_limit); } #[test] @@ -313,10 +313,10 @@ mod tests { unit.resume(); - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); for i in (0..=i16::MAX).chain(i16::MIN..0) { - assert_eq!(i, unit.get_value()); + assert_eq!(i, unit.value()); output.set_low(); ctx.delay.delay_micros(1); @@ -324,14 +324,14 @@ mod tests { ctx.delay.delay_micros(1); } - assert_eq!(0, unit.get_value()); + assert_eq!(0, unit.value()); // Channel 1 should now decrement. unit.channel1 .set_input_mode(EdgeMode::Decrement, EdgeMode::Hold); for i in (0..=i16::MAX).chain(i16::MIN..=0).rev() { - assert_eq!(i, unit.get_value()); + assert_eq!(i, unit.value()); output.set_low(); ctx.delay.delay_micros(1); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 0123e32d01a..c2f69b9ebdf 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -143,15 +143,15 @@ fn execute_write( unit0.clear(); unit1.clear(); (spi, dma_tx_buf) = transfer_write(spi, dma_tx_buf, write, command_data_mode); - assert_eq!(unit0.get_value() + unit1.get_value(), 8); + assert_eq!(unit0.value() + unit1.value(), 8); if data_on_multiple_pins { if command_data_mode == SpiDataMode::Single { - assert_eq!(unit0.get_value(), 1); - assert_eq!(unit1.get_value(), 7); + assert_eq!(unit0.value(), 1); + assert_eq!(unit1.value(), 7); } else { - assert_eq!(unit0.get_value(), 0); - assert_eq!(unit1.get_value(), 8); + assert_eq!(unit0.value(), 0); + assert_eq!(unit1.value(), 8); } } @@ -161,15 +161,15 @@ fn execute_write( unit0.clear(); unit1.clear(); (spi, dma_tx_buf) = transfer_write(spi, dma_tx_buf, write, command_data_mode); - assert_eq!(unit0.get_value() + unit1.get_value(), 4); + assert_eq!(unit0.value() + unit1.value(), 4); if data_on_multiple_pins { if command_data_mode == SpiDataMode::Single { - assert_eq!(unit0.get_value(), 1); - assert_eq!(unit1.get_value(), 3); + assert_eq!(unit0.value(), 1); + assert_eq!(unit1.value(), 3); } else { - assert_eq!(unit0.get_value(), 0); - assert_eq!(unit1.get_value(), 4); + assert_eq!(unit0.value(), 0); + assert_eq!(unit1.value(), 4); } } } diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 3e7a42b398c..1b893dcb132 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -143,7 +143,7 @@ mod tests { // Flush because we're not reading, so the write may happen in the background ctx.spi.flush().expect("Flush failed"); - assert_eq!(unit.get_value(), 9); + assert_eq!(unit.value(), 9); } #[test] @@ -162,7 +162,7 @@ mod tests { // Flush because we're not reading, so the write may happen in the background ctx.spi.flush().expect("Flush failed"); - assert_eq!(unit.get_value(), 9); + assert_eq!(unit.value(), 9); } #[test] @@ -223,7 +223,7 @@ mod tests { let transfer = spi.write(dma_tx_buf).map_err(|e| e.0).unwrap(); (spi, dma_tx_buf) = transfer.wait(); - assert_eq!(unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (i * 3 * DMA_BUFFER_SIZE) as _); } } @@ -259,7 +259,7 @@ mod tests { .map_err(|e| e.0) .unwrap(); (spi, (dma_rx_buf, dma_tx_buf)) = transfer.wait(); - assert_eq!(unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (i * 3 * DMA_BUFFER_SIZE) as _); } } @@ -418,7 +418,7 @@ mod tests { assert_eq!(receive, [0, 0, 0, 0, 0]); SpiBusAsync::write(&mut spi, &transmit).await.unwrap(); - assert_eq!(ctx.pcnt_unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _); + assert_eq!(ctx.pcnt_unit.value(), (i * 3 * DMA_BUFFER_SIZE) as _); } } @@ -454,7 +454,7 @@ mod tests { SpiBusAsync::transfer(&mut spi, &mut receive, &transmit) .await .unwrap(); - assert_eq!(ctx.pcnt_unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _); + assert_eq!(ctx.pcnt_unit.value(), (i * 3 * DMA_BUFFER_SIZE) as _); } } diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index 985ede3e5f6..1db9ad2cb13 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -100,7 +100,7 @@ mod tests { .unwrap(); (spi, dma_tx_buf) = transfer.wait(); - assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _); let transfer = spi .half_duplex_write( @@ -114,7 +114,7 @@ mod tests { .unwrap(); transfer.wait(); - assert_eq!(unit.get_value(), (6 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _); } #[test] @@ -144,7 +144,7 @@ mod tests { ) .unwrap(); - assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _); spi.half_duplex_write( SpiDataMode::Single, @@ -155,6 +155,6 @@ mod tests { ) .unwrap(); - assert_eq!(unit.get_value(), (6 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _); } } diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index 950cf2f0ea6..91f29804adb 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -115,7 +115,7 @@ mod tests { .unwrap(); (spi, dma_tx_buf) = transfer.wait(); - assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _); let transfer = spi .half_duplex_write( @@ -129,7 +129,7 @@ mod tests { .unwrap(); transfer.wait(); - assert_eq!(unit.get_value(), (6 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _); } #[test] @@ -165,7 +165,7 @@ mod tests { ) .unwrap(); - assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (3 * DMA_BUFFER_SIZE) as _); spi.half_duplex_write( SpiDataMode::Single, @@ -176,6 +176,6 @@ mod tests { ) .unwrap(); - assert_eq!(unit.get_value(), (6 * DMA_BUFFER_SIZE) as _); + assert_eq!(unit.value(), (6 * DMA_BUFFER_SIZE) as _); } } diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 6045f1d4d12..0ccda85e86f 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -69,7 +69,7 @@ impl BitbangSpi { self.mosi.set_level(Level::from(bit)); self.sclk.set_level(Level::High); - let miso = self.miso.get_level().into(); + let miso = self.miso.level().into(); self.sclk.set_level(Level::Low); miso From c19c7fcf01bac8eb82be38a8ddaf603f191a61a5 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Wed, 13 Nov 2024 08:13:47 -0800 Subject: [PATCH 67/67] Remove `get_core()` in favour of `Cpu::current()` (#2533) * Remove `esp_hal::core()` in favour of `Cpu::current()` * Update migration guide * Update `CHANGELOG.md` --- esp-hal-embassy/src/executor/interrupt.rs | 4 +-- esp-hal-embassy/src/executor/thread.rs | 8 ++--- esp-hal/CHANGELOG.md | 1 + esp-hal/MIGRATING-0.21.md | 7 ++++ esp-hal/src/interrupt/riscv.rs | 12 +++---- esp-hal/src/interrupt/xtensa.rs | 7 ++-- esp-hal/src/lib.rs | 32 ++++++++----------- esp-hal/src/reset.rs | 2 +- esp-hal/src/soc/esp32/cpu_control.rs | 2 +- esp-hal/src/soc/esp32/gpio.rs | 14 ++++---- esp-hal/src/soc/esp32s3/cpu_control.rs | 2 +- examples/src/bin/embassy_multicore.rs | 9 ++++-- .../src/bin/embassy_multicore_interrupt.rs | 9 ++++-- 13 files changed, 58 insertions(+), 51 deletions(-) diff --git a/esp-hal-embassy/src/executor/interrupt.rs b/esp-hal-embassy/src/executor/interrupt.rs index 335d130dcb3..7f3599127c2 100644 --- a/esp-hal-embassy/src/executor/interrupt.rs +++ b/esp-hal-embassy/src/executor/interrupt.rs @@ -4,8 +4,8 @@ use core::{cell::UnsafeCell, mem::MaybeUninit}; use embassy_executor::{raw, SendSpawner}; use esp_hal::{ - core, interrupt::{self, software::SoftwareInterrupt, InterruptHandler}, + Cpu, }; use portable_atomic::{AtomicUsize, Ordering}; @@ -87,7 +87,7 @@ impl InterruptExecutor { .core .compare_exchange( usize::MAX, - core() as usize, + Cpu::current() as usize, Ordering::Acquire, Ordering::Relaxed, ) diff --git a/esp-hal-embassy/src/executor/thread.rs b/esp-hal-embassy/src/executor/thread.rs index 0aefdfb2c41..3539a36d204 100644 --- a/esp-hal-embassy/src/executor/thread.rs +++ b/esp-hal-embassy/src/executor/thread.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use embassy_executor::{raw, Spawner}; -use esp_hal::{core, Cpu}; +use esp_hal::Cpu; #[cfg(multi_core)] use esp_hal::{interrupt::software::SoftwareInterrupt, macros::handler}; #[cfg(low_power_wait)] @@ -35,7 +35,7 @@ pub(crate) fn pend_thread_mode(_core: usize) { // If we are pending a task on the current core, we're done. Otherwise, we // need to make sure the other core wakes up. #[cfg(multi_core)] - if _core != core() as usize { + if _core != Cpu::current() as usize { // We need to clear the interrupt from software. We don't actually // need it to trigger and run the interrupt handler, we just need to // kick waiti to return. @@ -74,7 +74,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa } Self { - inner: raw::Executor::new((THREAD_MODE_CONTEXT + core() as usize) as *mut ()), + inner: raw::Executor::new((THREAD_MODE_CONTEXT + Cpu::current() as usize) as *mut ()), not_send: PhantomData, } } @@ -103,7 +103,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa init(self.inner.spawner()); #[cfg(low_power_wait)] - let cpu = core() as usize; + let cpu = Cpu::current() as usize; loop { unsafe { self.inner.poll() }; diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index e113cf3ca11..90ea7f5edb3 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -107,6 +107,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `{Spi, SpiDma, SpiDmaBus}` configuration methods (#2448) - `Io::new_with_priority` and `Io::new_no_bind_interrupt`. (#2486) - `parl_io::{no_clk_pin(), NoClkPin}` (#2531) +- Removed `get_core` function in favour of `Cpu::current` (#2533) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index a97b25b020a..6211533dba6 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -419,3 +419,10 @@ You can use `gpio::NoPin` instead. In order to better comply with the Rust API Guidelines [getter names convention], we have removed the `get_` prefixes from all functions which previously had it. Due to the number of changes it's not practical to list all changes here, however if a function previous began with `get_`, you can simply remove this prefix. [getter names convention]: https://rust-lang.github.io/api-guidelines/naming.html#c-getter + +## The `get_core()` function has been removed in favour of `Cpu::current()` + +```diff +- let core = esp_hal::get_core(); ++ let core = esp_hal::Cpu::current(); +``` diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index a1ea6d78bcc..8516dca4c4f 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -239,8 +239,8 @@ pub fn enable_direct( return Err(Error::InvalidInterruptPriority); } unsafe { - map(crate::core(), interrupt, cpu_interrupt); - set_priority(crate::core(), cpu_interrupt, level); + map(Cpu::current(), interrupt, cpu_interrupt); + set_priority(Cpu::current(), cpu_interrupt, level); enable_cpu_interrupt(cpu_interrupt); } Ok(()) @@ -369,12 +369,12 @@ mod vectored { pub(crate) unsafe fn init_vectoring() { for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() { set_kind( - crate::core(), + Cpu::current(), core::mem::transmute::(*num as u32), InterruptKind::Level, ); set_priority( - crate::core(), + Cpu::current(), core::mem::transmute::(*num as u32), core::mem::transmute::((prio as u8) + 1), ); @@ -421,7 +421,7 @@ mod vectored { let cpu_interrupt = core::mem::transmute::( PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32, ); - map(crate::core(), interrupt, cpu_interrupt); + map(Cpu::current(), interrupt, cpu_interrupt); enable_cpu_interrupt(cpu_interrupt); } Ok(()) @@ -453,7 +453,7 @@ mod vectored { #[no_mangle] #[ram] unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { - let core = crate::core(); + let core = Cpu::current(); let status = status(core); // this has no effect on level interrupts, but the interrupt may be an edge one diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index a6d0c03e60e..f0aaa54e6f6 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -156,7 +156,7 @@ pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Resul return Err(Error::CpuInterruptReserved); } unsafe { - map(crate::core(), interrupt, cpu_interrupt); + map(Cpu::current(), interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, @@ -338,7 +338,6 @@ mod vectored { use procmacros::ram; use super::*; - use crate::core; /// Interrupt priority levels. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -447,7 +446,7 @@ mod vectored { interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; unsafe { - map(core(), interrupt, cpu_interrupt); + map(Cpu::current(), interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, @@ -541,7 +540,7 @@ mod vectored { #[no_mangle] #[ram] unsafe fn handle_interrupts(level: u32, save_frame: &mut Context) { - let core = crate::core(); + let core = Cpu::current(); let cpu_interrupt_mask = interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize]; diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index dbad5471c00..2214852fe4b 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -369,7 +369,18 @@ impl Cpu { /// Returns the core the application is currently executing on #[inline(always)] pub fn current() -> Self { - core() + // This works for both RISCV and Xtensa because both + // get_raw_core functions return zero, _or_ something + // greater than zero; 1 in the case of RISCV and 0x2000 + // in the case of Xtensa. + match raw_core() { + 0 => Cpu::ProCpu, + #[cfg(all(multi_core, riscv))] + 1 => Cpu::AppCpu, + #[cfg(all(multi_core, xtensa))] + 0x2000 => Cpu::AppCpu, + _ => unreachable!(), + } } /// Returns an iterator over the "other" cores. @@ -377,7 +388,7 @@ impl Cpu { pub fn other() -> impl Iterator { cfg_if::cfg_if! { if #[cfg(multi_core)] { - match core() { + match Self::current() { Cpu::ProCpu => [Cpu::AppCpu].into_iter(), Cpu::AppCpu => [Cpu::ProCpu].into_iter(), } @@ -388,23 +399,6 @@ impl Cpu { } } -/// Which core the application is currently executing on -#[inline(always)] -pub fn core() -> Cpu { - // This works for both RISCV and Xtensa because both - // raw_core functions return zero, _or_ something - // greater than zero; 1 in the case of RISCV and 0x2000 - // in the case of Xtensa. - match raw_core() { - 0 => Cpu::ProCpu, - #[cfg(all(multi_core, riscv))] - 1 => Cpu::AppCpu, - #[cfg(all(multi_core, xtensa))] - 0x2000 => Cpu::AppCpu, - _ => unreachable!(), - } -} - /// Returns the raw value of the mhartid register. /// /// Safety: This method should never return UNUSED_THREAD_ID_VALUE diff --git a/esp-hal/src/reset.rs b/esp-hal/src/reset.rs index d4e85d10245..eeed2b09296 100644 --- a/esp-hal/src/reset.rs +++ b/esp-hal/src/reset.rs @@ -103,7 +103,7 @@ pub fn software_reset_cpu() { /// Retrieves the reason for the last reset as a SocResetReason enum value. /// Returns `None` if the reset reason cannot be determined. pub fn reset_reason() -> Option { - crate::rtc_cntl::reset_reason(crate::core()) + crate::rtc_cntl::reset_reason(crate::Cpu::current()) } /// Retrieves the cause of the last wakeup event as a SleepSource enum value. diff --git a/esp-hal/src/soc/esp32/cpu_control.rs b/esp-hal/src/soc/esp32/cpu_control.rs index 14ac9cb7cf2..d0a0a143202 100644 --- a/esp-hal/src/soc/esp32/cpu_control.rs +++ b/esp-hal/src/soc/esp32/cpu_control.rs @@ -328,7 +328,7 @@ impl<'d> CpuControl<'d> { let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::>()) }; entry(); loop { - unsafe { internal_park_core(crate::core()) }; + unsafe { internal_park_core(Cpu::current()) }; } } None => panic!("No start function set"), diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index b25bc0a85ac..21e85a6f423 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -110,7 +110,7 @@ pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static io_mux::GPIO0 { } pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { - match crate::core() { + match Cpu::current() { Cpu::AppCpu => int_enable as u8 | ((nmi_enable as u8) << 1), // this should be bits 3 & 4 respectively, according to the TRM, but it doesn't seem to // work. This does though. @@ -789,13 +789,13 @@ pub(crate) enum InterruptStatusRegisterAccess { impl InterruptStatusRegisterAccess { pub(crate) fn interrupt_status_read(self) -> u32 { match self { - Self::Bank0 => match crate::core() { - crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int().read().bits(), - crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int().read().bits(), + Self::Bank0 => match Cpu::current() { + Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int().read().bits(), + Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int().read().bits(), }, - Self::Bank1 => match crate::core() { - crate::Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), - crate::Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int1().read().bits(), + Self::Bank1 => match Cpu::current() { + Cpu::ProCpu => unsafe { GPIO::steal() }.pcpu_int1().read().bits(), + Cpu::AppCpu => unsafe { GPIO::steal() }.acpu_int1().read().bits(), }, } } diff --git a/esp-hal/src/soc/esp32s3/cpu_control.rs b/esp-hal/src/soc/esp32s3/cpu_control.rs index 65e3f16ab25..9e086bed5e2 100644 --- a/esp-hal/src/soc/esp32s3/cpu_control.rs +++ b/esp-hal/src/soc/esp32s3/cpu_control.rs @@ -264,7 +264,7 @@ impl<'d> CpuControl<'d> { let entry = unsafe { ManuallyDrop::take(&mut *entry.cast::>()) }; entry(); loop { - unsafe { internal_park_core(crate::core()) }; + unsafe { internal_park_core(Cpu::current()) }; } } None => panic!("No start function set"), diff --git a/examples/src/bin/embassy_multicore.rs b/examples/src/bin/embassy_multicore.rs index f3ed022ad7d..5c5c1f645aa 100644 --- a/examples/src/bin/embassy_multicore.rs +++ b/examples/src/bin/embassy_multicore.rs @@ -19,10 +19,10 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal} use embassy_time::{Duration, Ticker}; use esp_backtrace as _; use esp_hal::{ - core, cpu_control::{CpuControl, Stack}, gpio::{Level, Output}, timer::{timg::TimerGroup, AnyTimer}, + Cpu, }; use esp_hal_embassy::Executor; use esp_println::println; @@ -37,7 +37,7 @@ async fn control_led( mut led: Output<'static>, control: &'static Signal, ) { - println!("Starting control_led() on core {}", core() as usize); + println!("Starting control_led() on core {}", Cpu::current() as usize); loop { if control.wait().await { esp_println::println!("LED on"); @@ -76,7 +76,10 @@ async fn main(_spawner: Spawner) { .unwrap(); // Sends periodic messages to control_led, enabling or disabling it. - println!("Starting enable_disable_led() on core {}", core() as usize); + println!( + "Starting enable_disable_led() on core {}", + Cpu::current() as usize + ); let mut ticker = Ticker::every(Duration::from_secs(1)); loop { esp_println::println!("Sending LED on"); diff --git a/examples/src/bin/embassy_multicore_interrupt.rs b/examples/src/bin/embassy_multicore_interrupt.rs index 5d1e53082a2..6056c541edb 100644 --- a/examples/src/bin/embassy_multicore_interrupt.rs +++ b/examples/src/bin/embassy_multicore_interrupt.rs @@ -18,12 +18,12 @@ use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal} use embassy_time::{Duration, Ticker}; use esp_backtrace as _; use esp_hal::{ - core, cpu_control::{CpuControl, Stack}, gpio::{Level, Output}, interrupt::{software::SoftwareInterruptControl, Priority}, prelude::*, timer::{timg::TimerGroup, AnyTimer}, + Cpu, }; use esp_hal_embassy::InterruptExecutor; use esp_println::println; @@ -38,7 +38,7 @@ async fn control_led( mut led: Output<'static>, control: &'static Signal, ) { - println!("Starting control_led() on core {}", core() as usize); + println!("Starting control_led() on core {}", Cpu::current() as usize); loop { if control.wait().await { esp_println::println!("LED on"); @@ -53,7 +53,10 @@ async fn control_led( /// Sends periodic messages to control_led, enabling or disabling it. #[embassy_executor::task] async fn enable_disable_led(control: &'static Signal) { - println!("Starting enable_disable_led() on core {}", core() as usize); + println!( + "Starting enable_disable_led() on core {}", + Cpu::current() as usize + ); let mut ticker = Ticker::every(Duration::from_secs(1)); loop { esp_println::println!("Sending LED on");