From 86e006b601af15b6fceebd8605c0d935ec34f53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 4 Jul 2025 14:15:12 +0200 Subject: [PATCH] Rework how peripheral singletons are generated (#3747) * Handle GPIOs as stable peripherals * Define interrupts in create_peripheral * Remove the rest of paste from the peripherals macro * Move create_peripheral calls out of peripherals! * Merge macros * Merge peripherals files * Delete the peripheral module * Replace the peripherals macro with for_each generated code * Do not generate code directly in GPIO metadata --- esp-hal-embassy/src/executor/thread.rs | 1 + esp-hal/src/lib.rs | 5 +- esp-hal/src/peripheral.rs | 237 ------------------------ esp-hal/src/peripherals.rs | 242 +++++++++++++++++++++++++ esp-hal/src/soc/esp32/mod.rs | 3 +- esp-hal/src/soc/esp32/peripherals.rs | 17 -- esp-hal/src/soc/esp32c2/mod.rs | 3 +- esp-hal/src/soc/esp32c2/peripherals.rs | 17 -- esp-hal/src/soc/esp32c3/mod.rs | 3 +- esp-hal/src/soc/esp32c3/peripherals.rs | 17 -- esp-hal/src/soc/esp32c6/mod.rs | 3 +- esp-hal/src/soc/esp32c6/peripherals.rs | 17 -- esp-hal/src/soc/esp32h2/mod.rs | 3 +- esp-hal/src/soc/esp32h2/peripherals.rs | 17 -- esp-hal/src/soc/esp32s2/mod.rs | 3 +- esp-hal/src/soc/esp32s2/peripherals.rs | 17 -- esp-hal/src/soc/esp32s3/mod.rs | 3 +- esp-hal/src/soc/esp32s3/peripherals.rs | 17 -- esp-metadata/src/cfg/gpio.rs | 35 ++-- esp-metadata/src/lib.rs | 67 ++++--- 20 files changed, 322 insertions(+), 405 deletions(-) delete mode 100644 esp-hal/src/peripheral.rs create mode 100644 esp-hal/src/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32c2/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32c3/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32c6/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32h2/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32s2/peripherals.rs delete mode 100644 esp-hal/src/soc/esp32s3/peripherals.rs diff --git a/esp-hal-embassy/src/executor/thread.rs b/esp-hal-embassy/src/executor/thread.rs index 06e856898..f715b6c01 100644 --- a/esp-hal-embassy/src/executor/thread.rs +++ b/esp-hal-embassy/src/executor/thread.rs @@ -104,6 +104,7 @@ This will use software-interrupt 3 which isn't available for anything else to wa /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + #[cfg_attr(not(low_power_wait), expect(dead_code, reason = "cpu index is unused"))] struct NoHooks(usize); impl Callbacks for NoHooks { diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index f007ac441..c74aa86c2 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -205,6 +205,7 @@ metadata!("build_info", CHIP_NAME, chip!()); #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] #[cfg_attr(not(feature = "unstable"), doc(hidden))] pub use esp_riscv_rt::{self, riscv}; +pub(crate) use peripherals::pac; #[cfg(xtensa)] #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] #[cfg_attr(not(feature = "unstable"), doc(hidden))] @@ -218,8 +219,6 @@ pub use self::soc::efuse; #[instability::unstable] #[cfg_attr(not(feature = "unstable"), allow(unused))] pub use self::soc::lp_core; -pub use self::soc::peripherals; -pub(crate) use self::soc::peripherals::pac; #[instability::unstable] #[cfg(feature = "psram")] pub use self::soc::psram; @@ -234,6 +233,7 @@ pub mod clock; pub mod gpio; #[cfg(any(soc_has_i2c0, soc_has_i2c1))] pub mod i2c; +pub mod peripherals; #[cfg(all(feature = "unstable", any(soc_has_hmac, soc_has_sha)))] mod reg_access; #[cfg(any(soc_has_spi0, soc_has_spi1, soc_has_spi2, soc_has_spi3))] @@ -244,7 +244,6 @@ pub mod time; pub mod uart; mod macros; -mod peripheral; pub use procmacros::blocking_main as main; #[cfg(any(lp_core, ulp_riscv_core))] diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs deleted file mode 100644 index d05304325..000000000 --- a/esp-hal/src/peripheral.rs +++ /dev/null @@ -1,237 +0,0 @@ -//! # Exclusive peripheral access - -/// Creates a new `Peripherals` struct and its associated methods. -/// -/// The macro has a few fields doing different things, in the form of -/// `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 PAC. This may be `virtual` -/// if the peripheral is not present in the PAC. -/// - The fourth field is an optional list of interrupts that can be bound to the peripheral. -#[doc(hidden)] -#[macro_export] -macro_rules! peripherals { - ( - peripherals: [ - $( - $name:ident <= $from_pac:tt ($($interrupt_name:ident => $interrupt:ident),*), - )* - ], - unstable_peripherals: [ - $( - $unstable_name:ident <= $unstable_from_pac:tt ($($unstable_interrupt_name:ident => $unstable_interrupt:ident),*), - )* - ], - pins: [ - $( $gpio:ident, )* - ] - ) => { - macro_rules! generate_interrupt_fns { - ($fn_name:ident, $int_name:ident) => { - paste::paste!{ - /// Binds an interrupt handler to the corresponding interrupt for this peripheral. - #[instability::unstable] - pub fn [](&self, handler: unsafe extern "C" fn() -> ()) { - unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$int_name, handler); } - } - - /// Disables the interrupt handler - #[instability::unstable] - pub fn [](&self) { - for core in $crate::system::Cpu::other() { - $crate::interrupt::disable(core, $crate::peripherals::Interrupt::$int_name); - } - } - - /// Enables the interrupt handler on the given core - #[instability::unstable] - pub fn [](&self, priority: $crate::interrupt::Priority) { - unwrap!($crate::interrupt::enable($crate::peripherals::Interrupt::$int_name, priority)); - } - } - }; - } - - $( - $crate::create_peripheral!($name <= $from_pac); - )* - $( - $crate::create_peripheral!(#[instability::unstable] $unstable_name <= $unstable_from_pac); - )* - $( - $crate::create_peripheral!($gpio <= virtual); - )* - - /// 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: $name<'static>, - )* - $( - #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")] - #[doc = "**This API is marked as unstable** and is only available when the `unstable` - crate feature is enabled. This comes with no stability guarantees, and could be changed - or removed at any time."] - #[cfg(feature = "unstable")] - #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] - pub $unstable_name: $unstable_name<'static>, - - #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")] - #[doc = "**This API is marked as unstable** and is only available when the `unstable` - crate feature is enabled. This comes with no stability guarantees, and could be changed - or removed at any time."] - #[cfg(not(feature = "unstable"))] - #[allow(unused)] - pub(crate) $unstable_name: $unstable_name<'static>, - )* - - $( - #[doc = stringify!($gpio)] - pub $gpio: $gpio<'static>, - )* - } - - impl Peripherals { - /// Returns all the peripherals *once* - #[inline] - pub(crate) fn take() -> Self { - #[unsafe(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 { - unsafe { - Self { - $( - $name: $name::steal(), - )* - $( - $unstable_name: $unstable_name::steal(), - )* - - $( - $gpio: $gpio::steal(), - )* - } - } - } - } - - $( - impl $name<'_> { - $( - generate_interrupt_fns!($interrupt_name, $interrupt); - )* - } - )* - - $( - impl $unstable_name<'_> { - $( - generate_interrupt_fns!($unstable_interrupt_name, $unstable_interrupt); - )* - } - )* - }; -} - -#[doc(hidden)] -#[macro_export] -/// Macro to create a peripheral structure. -macro_rules! create_peripheral { - ($(#[$attr:meta])? $name:ident <= virtual) => { - $(#[$attr])? - #[derive(Debug)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - #[non_exhaustive] - #[allow(non_camel_case_types, clippy::upper_case_acronyms)] - #[doc = concat!(stringify!($name), " peripheral singleton")] - pub struct $name<'a> { - _marker: core::marker::PhantomData<&'a mut ()>, - } - - impl $name<'_> { - /// 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 { - _marker: core::marker::PhantomData, - } - } - - /// Unsafely clone this peripheral reference. - /// - /// # Safety - /// - /// You must ensure that you're only using one instance of this type at a time. - #[inline] - #[allow(dead_code)] - pub unsafe fn clone_unchecked(&self) -> Self { - unsafe { Self::steal() } - } - - /// Creates a new peripheral reference with a shorter lifetime. - /// - /// Use this method if you would like to keep working with the peripheral after - /// you dropped the driver that consumes this. - #[inline] - #[allow(dead_code)] - pub fn reborrow(&mut self) -> $name<'_> { - unsafe { self.clone_unchecked() } - } - } - - impl $crate::private::Sealed for $name<'_> {} - }; - - ($(#[$attr:meta])? $name:ident <= $base:ident) => { - $crate::create_peripheral!($(#[$attr])? $name <= virtual); - - impl $name<'_> { - #[doc = r"Pointer to the register block"] - #[instability::unstable] - pub const PTR: *const ::Target = pac::$base::PTR; - - #[doc = r"Return the pointer to the register block"] - #[inline(always)] - #[instability::unstable] - pub const fn ptr() -> *const ::Target { - pac::$base::PTR - } - - #[doc = r"Return a reference to the register block"] - #[inline(always)] - #[instability::unstable] - pub const fn regs<'a>() -> &'a ::Target { - unsafe { &*Self::PTR } - } - - #[doc = r"Return a reference to the register block"] - #[inline(always)] - #[instability::unstable] - pub fn register_block(&self) -> &::Target { - unsafe { &*Self::PTR } - } - } - }; -} diff --git a/esp-hal/src/peripherals.rs b/esp-hal/src/peripherals.rs new file mode 100644 index 000000000..b83459474 --- /dev/null +++ b/esp-hal/src/peripherals.rs @@ -0,0 +1,242 @@ +//! # Peripheral Instances +//! +//! This module creates singleton instances for each of the various peripherals, +//! and re-exports them to allow users to access and use them in their +//! applications. +//! +//! Should be noted that that the module also re-exports the [Interrupt] enum +//! from the PAC, allowing users to handle interrupts associated with these +//! peripherals. + +// We need to export this for users to use +#[doc(hidden)] +pub use pac::Interrupt; + +pub(crate) use crate::soc::pac; + +/// Macro to create a peripheral structure. +macro_rules! create_peripheral { + ($(#[$attr:meta])? $name:ident <= virtual ($($interrupt:ident: { $bind:ident, $enable:ident, $disable:ident }),*)) => { + $(#[$attr])? + #[derive(Debug)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[non_exhaustive] + #[allow(non_camel_case_types, clippy::upper_case_acronyms)] + #[doc = concat!(stringify!($name), " peripheral singleton")] + pub struct $name<'a> { + _marker: core::marker::PhantomData<&'a mut ()>, + } + + impl $name<'_> { + /// 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 { + _marker: core::marker::PhantomData, + } + } + + /// Unsafely clone this peripheral reference. + /// + /// # Safety + /// + /// You must ensure that you're only using one instance of this type at a time. + #[inline] + #[allow(dead_code)] + pub unsafe fn clone_unchecked(&self) -> Self { + unsafe { Self::steal() } + } + + /// Creates a new peripheral reference with a shorter lifetime. + /// + /// Use this method if you would like to keep working with the peripheral after + /// you dropped the driver that consumes this. + #[inline] + #[allow(dead_code)] + pub fn reborrow(&mut self) -> $name<'_> { + unsafe { self.clone_unchecked() } + } + + $( + /// Binds an interrupt handler to the corresponding interrupt for this peripheral. + #[instability::unstable] + pub fn $bind(&self, handler: unsafe extern "C" fn() -> ()) { + unsafe { $crate::interrupt::bind_interrupt($crate::peripherals::Interrupt::$interrupt, handler); } + } + + /// Disables the interrupt handler + #[instability::unstable] + pub fn $disable(&self) { + for core in $crate::system::Cpu::other() { + $crate::interrupt::disable(core, $crate::peripherals::Interrupt::$interrupt); + } + } + + /// Enables the interrupt handler on the given core + #[instability::unstable] + pub fn $enable(&self, priority: $crate::interrupt::Priority) { + unwrap!($crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, priority)); + } + )* + } + + impl $crate::private::Sealed for $name<'_> {} + }; + + ($(#[$attr:meta])? $name:ident <= $base:ident $interrupts:tt) => { + create_peripheral!($(#[$attr])? $name <= virtual $interrupts); + + impl $name<'_> { + #[doc = r"Pointer to the register block"] + #[instability::unstable] + pub const PTR: *const ::Target = pac::$base::PTR; + + #[doc = r"Return the pointer to the register block"] + #[inline(always)] + #[instability::unstable] + pub const fn ptr() -> *const ::Target { + pac::$base::PTR + } + + #[doc = r"Return a reference to the register block"] + #[inline(always)] + #[instability::unstable] + pub const fn regs<'a>() -> &'a ::Target { + unsafe { &*Self::PTR } + } + + #[doc = r"Return a reference to the register block"] + #[inline(always)] + #[instability::unstable] + pub fn register_block(&self) -> &::Target { + unsafe { &*Self::PTR } + } + } + }; +} + +include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); +include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); + +for_each_gpio! { + ($n:literal, $pin_peri:ident $af_ins:tt $af_outs:tt ($($attr:ident)*)) => { + $( + crate::io_type!($attr, $pin_peri); + )* + }; + + (all $( ($n:literal, $pin_peri:ident $af_ins:tt $af_outs:tt $attrs:tt) ),*) => { + crate::gpio! { + $( ($n, $pin_peri $af_ins $af_outs) )* + } + }; +} + +define_io_mux_reg!(); + +for_each_peripheral! { + // Define stable peripheral singletons + ($name:ident <= $from_pac:tt $interrupts:tt) => { + create_peripheral!($name <= $from_pac $interrupts); + }; + + // Define unstable peripheral singletons + ($name:ident <= $from_pac:tt $interrupts:tt (unstable)) => { + create_peripheral!(#[instability::unstable] $name <= $from_pac $interrupts); + }; + + // Define the Peripherals struct + (all $( ($name:ident <= $from_pac:tt $interrupts:tt $(($unstable:ident))?) ),*) => { + // We need a way to ignore the "unstable" marker, but macros can't generate attributes or struct fields. + // The solution is printing an empty doc comment. + macro_rules! ignore { ($any:tt) => {""} } + + /// The `Peripherals` struct provides access to all of the hardware peripherals on the chip. + #[allow(non_snake_case)] + pub struct Peripherals { + $( + // This is a bit hairy, but non-macro attributes are not allowed on struct fields. We work + // around this by excluding code with the `$()?` optional macro syntax and an "unstable" marker + // in the source data. The marker itself is passed through the `ignore` macro so that it doesn't + // appear in the generated code. + // + // The code can end up looking two ways: + // + // - Without `unstable` we just generate the field: + // ``` + // #[attributes] + // pub PERI: PERI<'static>, + // ``` + // + // - With `unstable` we're basically emulating what `instability::unstable` would do: + // ``` + // #[attributes] + // #[cfg(feature = "unstable")] + // pub PERI: PERI<'static>, + // + // #[attributes] + // #[cfg(not(feature = "unstable"))] + // pub(crate) PERI: PERI<'static>, + // ``` + #[doc = concat!("The ", stringify!($name), " peripheral.")] + $( + #[doc = "**This API is marked as unstable** and is only available when the `unstable` + crate feature is enabled. This comes with no stability guarantees, and could be changed + or removed at any time."] + #[doc = ignore!($unstable)] + #[cfg(feature = "unstable")] + #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] + )? + pub $name: $name<'static>, + + $( + #[doc = concat!("The ", stringify!($unstable_name), " peripheral.")] + #[doc = "**This API is marked as unstable** and is only available when the `unstable` + crate feature is enabled. This comes with no stability guarantees, and could be changed + or removed at any time."] + #[doc = ignore!($unstable)] + #[cfg(not(feature = "unstable"))] + #[allow(unused)] + pub(crate) $name: $name<'static>, + )? + )* + } + + impl Peripherals { + /// Returns all the peripherals *once* + #[inline] + pub(crate) fn take() -> Self { + #[unsafe(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 { + unsafe { + Self { + $( + $name: $name::steal(), + )* + } + } + } + } + }; +} diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 6f7e5642b..e843cb3bd 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -13,9 +13,10 @@ crate::unstable_module! { } pub mod cpu_control; pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32 as pac; + #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) mod constants { use crate::time::Rate; diff --git a/esp-hal/src/soc/esp32/peripherals.rs b/esp-hal/src/soc/esp32/peripherals.rs deleted file mode 100644 index 908357ec0..000000000 --- a/esp-hal/src/soc/esp32/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32c2/mod.rs b/esp-hal/src/soc/esp32c2/mod.rs index 1bb805cae..9414c913b 100644 --- a/esp-hal/src/soc/esp32c2/mod.rs +++ b/esp-hal/src/soc/esp32c2/mod.rs @@ -10,9 +10,10 @@ crate::unstable_module! { pub mod trng; } pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32c2 as pac; + #[allow(unused)] pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x600c2000; diff --git a/esp-hal/src/soc/esp32c2/peripherals.rs b/esp-hal/src/soc/esp32c2/peripherals.rs deleted file mode 100644 index bea889679..000000000 --- a/esp-hal/src/soc/esp32c2/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32c2 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32c3/mod.rs b/esp-hal/src/soc/esp32c3/mod.rs index ca9895f1a..f963c5b2e 100644 --- a/esp-hal/src/soc/esp32c3/mod.rs +++ b/esp-hal/src/soc/esp32c3/mod.rs @@ -14,9 +14,10 @@ crate::unstable_module! { pub mod trng; } pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32c3 as pac; + #[allow(unused)] pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x600c2000; diff --git a/esp-hal/src/soc/esp32c3/peripherals.rs b/esp-hal/src/soc/esp32c3/peripherals.rs deleted file mode 100644 index 3153bfd1f..000000000 --- a/esp-hal/src/soc/esp32c3/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32c3 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32c6/mod.rs b/esp-hal/src/soc/esp32c6/mod.rs index 1a0c5ad7d..bc25dbc36 100644 --- a/esp-hal/src/soc/esp32c6/mod.rs +++ b/esp-hal/src/soc/esp32c6/mod.rs @@ -16,9 +16,10 @@ crate::unstable_module! { pub mod trng; } pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32c6 as pac; + #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; diff --git a/esp-hal/src/soc/esp32c6/peripherals.rs b/esp-hal/src/soc/esp32c6/peripherals.rs deleted file mode 100644 index 642445e3c..000000000 --- a/esp-hal/src/soc/esp32c6/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32c6 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32h2/mod.rs b/esp-hal/src/soc/esp32h2/mod.rs index ca10252dc..b88f68639 100644 --- a/esp-hal/src/soc/esp32h2/mod.rs +++ b/esp-hal/src/soc/esp32h2/mod.rs @@ -15,9 +15,10 @@ crate::unstable_module! { pub mod trng; } pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32h2 as pac; + #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; diff --git a/esp-hal/src/soc/esp32h2/peripherals.rs b/esp-hal/src/soc/esp32h2/peripherals.rs deleted file mode 100644 index f0cc08386..000000000 --- a/esp-hal/src/soc/esp32h2/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32h2 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index d5ea24078..f052b7e3a 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -17,9 +17,10 @@ crate::unstable_module! { pub mod ulp_core; } pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub(crate) use esp32s2 as pac; + #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) mod constants { use crate::time::Rate; diff --git a/esp-hal/src/soc/esp32s2/peripherals.rs b/esp-hal/src/soc/esp32s2/peripherals.rs deleted file mode 100644 index e2d46083d..000000000 --- a/esp-hal/src/soc/esp32s2/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32s2 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 1d85c1202..92027583b 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -18,9 +18,10 @@ crate::unstable_module! { } pub mod cpu_control; pub mod gpio; -pub mod peripherals; pub(crate) mod regi2c; +pub use esp32s3 as pac; + #[cfg_attr(not(feature = "unstable"), allow(unused))] pub(crate) mod constants { use crate::time::Rate; diff --git a/esp-hal/src/soc/esp32s3/peripherals.rs b/esp-hal/src/soc/esp32s3/peripherals.rs deleted file mode 100644 index 2b703eda2..000000000 --- a/esp-hal/src/soc/esp32s3/peripherals.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! # Peripheral Instances -//! -//! This module creates singleton instances for each of the various peripherals, -//! and re-exports them to allow users to access and use them in their -//! applications. -//! -//! Should be noted that that the module also re-exports the [Interrupt] enum -//! from the PAC, allowing users to handle interrupts associated with these -//! peripherals. - -pub(crate) use esp32s3 as pac; -// We need to export this for users to use -#[doc(hidden)] -pub use pac::Interrupt; - -include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs")); -include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs")); diff --git a/esp-metadata/src/cfg/gpio.rs b/esp-metadata/src/cfg/gpio.rs index c60599404..fb1656af0 100644 --- a/esp-metadata/src/cfg/gpio.rs +++ b/esp-metadata/src/cfg/gpio.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use proc_macro2::TokenStream; use quote::format_ident; -use crate::number; +use crate::{generate_for_each_macro, number}; /// Additional properties (besides those defined in cfg.rs) for [device.gpio]. /// These don't get turned into symbols, but are used to generate code. @@ -244,13 +244,6 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream { } }; - let mut io_type_macro_calls = vec![]; - for (pin, attrs) in pin_peris.iter().zip(pin_attrs.iter()) { - io_type_macro_calls.push(quote::quote! { - #( crate::io_type!(#attrs, #pin); )* - }) - } - // Generates a macro that can select between a `then` and an `else` branch based // on whether a pin implement a certain attribute. // @@ -314,17 +307,31 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream { } }; - quote::quote! { - crate::gpio! { - #( (#pin_numbers, #pin_peris #pin_afs) )* - } + let mut branches = vec![]; + for (((n, p), af), attrs) in pin_numbers + .iter() + .zip(pin_peris.iter()) + .zip(pin_afs.iter()) + .zip(pin_attrs.iter()) + { + branches.push(quote::quote! { + #n, #p #af (#(#attrs)*) + }) + } - #( #io_type_macro_calls )* + let for_each = generate_for_each_macro("gpio", &branches); + + quote::quote! { + #for_each #if_pin_is_type #impl_for_pin_type - #io_mux_accessor + macro_rules! define_io_mux_reg { + () => { + #io_mux_accessor + }; + } } } diff --git a/esp-metadata/src/lib.rs b/esp-metadata/src/lib.rs index 459fa61db..04659074e 100644 --- a/esp-metadata/src/lib.rs +++ b/esp-metadata/src/lib.rs @@ -515,6 +515,7 @@ impl Config { fn generate_peripherals_macro(&self) -> TokenStream { let mut stable = vec![]; let mut unstable = vec![]; + let mut all_peripherals = vec![]; let mut stable_peris = vec![]; @@ -530,15 +531,16 @@ impl Config { } } - let gpios = if let Some(gpio) = self.device.peri_config.gpio.as_ref() { - gpio.pins_and_signals - .pins - .iter() - .map(|pin| format_ident!("GPIO{}", pin.pin)) - .collect::>() - } else { - vec![] - }; + if let Some(gpio) = self.device.peri_config.gpio.as_ref() { + for pin in gpio.pins_and_signals.pins.iter() { + let pin = format_ident!("GPIO{}", pin.pin); + let tokens = quote::quote! { + #pin <= virtual () + }; + all_peripherals.push(quote::quote! { #tokens }); + stable.push(tokens); + } + } for peri in self.device.peripherals.iter() { let hal = format_ident!("{}", peri.name); @@ -551,9 +553,11 @@ impl Config { let mut interrupts = peri.interrupts.iter().collect::>(); interrupts.sort_by_key(|(k, _)| k.as_str()); let interrupts = interrupts.iter().map(|(k, v)| { - let k = format_ident!("{k}"); - let v = format_ident!("{v}"); - quote::quote! { #k => #v } + let pac_interrupt_name = format_ident!("{v}"); + let bind = format_ident!("bind_{k}_interrupt"); + let enable = format_ident!("enable_{k}_interrupt"); + let disable = format_ident!("disable_{k}_interrupt"); + quote::quote! { #pac_interrupt_name: { #bind, #enable, #disable } } }); let tokens = quote::quote! { #hal <= #pac ( #(#interrupts),* ) @@ -562,23 +566,15 @@ impl Config { .iter() .any(|p| peri.name.eq_ignore_ascii_case(p)) { + all_peripherals.push(quote::quote! { #tokens }); stable.push(tokens); } else { + all_peripherals.push(quote::quote! { #tokens (unstable) }); unstable.push(tokens); } } - quote::quote! { - crate::peripherals! { - peripherals: [ - #(#stable,)* - ], - unstable_peripherals: [ - #(#unstable,)* - ], - pins: [#(#gpios,)*] - } - } + generate_for_each_macro("peripheral", &all_peripherals) } } @@ -590,13 +586,34 @@ fn generate_for_each_macro(name: &str, branches: &[TokenStream]) -> TokenStream // macro that substitutes the properties into the template provided by the call in esp-hal. macro_rules! #macro_name { ( - $pattern:tt => $code:tt; + $($pattern:tt => $code:tt;)* ) => { macro_rules! _for_each_inner { - ($pattern) => $code; + $(($pattern) => $code;)* + ($other:tt) => {} } + // Generate single macro calls with each branch + // Usage: + // ``` + // for_each_x! { + // ( $pattern ) => { + // $code + // } + // } + // ``` #(_for_each_inner!(( #branches ));)* + + // Generate a single macro call with all branches. + // Usage: + // ``` + // for_each_x! { + // (all $( ($pattern) ),*) => { + // $( $code )* + // } + // } + // ``` + _for_each_inner!((all #((#branches)),*)); }; }