mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
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
This commit is contained in:
parent
68b992f6d6
commit
86e006b601
@ -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 {
|
||||
|
@ -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))]
|
||||
|
@ -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 [<bind_ $fn_name _interrupt >](&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 [<disable_ $fn_name _interrupt >](&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 [<enable_ $fn_name _interrupt >](&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 <pac::$base as core::ops::Deref>::Target = pac::$base::PTR;
|
||||
|
||||
#[doc = r"Return the pointer to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub const fn ptr() -> *const <pac::$base as core::ops::Deref>::Target {
|
||||
pac::$base::PTR
|
||||
}
|
||||
|
||||
#[doc = r"Return a reference to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub const fn regs<'a>() -> &'a <pac::$base as core::ops::Deref>::Target {
|
||||
unsafe { &*Self::PTR }
|
||||
}
|
||||
|
||||
#[doc = r"Return a reference to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub fn register_block(&self) -> &<pac::$base as core::ops::Deref>::Target {
|
||||
unsafe { &*Self::PTR }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
242
esp-hal/src/peripherals.rs
Normal file
242
esp-hal/src/peripherals.rs
Normal file
@ -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 <pac::$base as core::ops::Deref>::Target = pac::$base::PTR;
|
||||
|
||||
#[doc = r"Return the pointer to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub const fn ptr() -> *const <pac::$base as core::ops::Deref>::Target {
|
||||
pac::$base::PTR
|
||||
}
|
||||
|
||||
#[doc = r"Return a reference to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub const fn regs<'a>() -> &'a <pac::$base as core::ops::Deref>::Target {
|
||||
unsafe { &*Self::PTR }
|
||||
}
|
||||
|
||||
#[doc = r"Return a reference to the register block"]
|
||||
#[inline(always)]
|
||||
#[instability::unstable]
|
||||
pub fn register_block(&self) -> &<pac::$base as core::ops::Deref>::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(),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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;
|
||||
|
@ -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"));
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::<Vec<_>>()
|
||||
} 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::<Vec<_>>();
|
||||
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)),*));
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user