Document esp-metadata-generated (#3787)

* Try to make it more obvious how to update e-m-g

* Document top level, ensure build-script docs are present

* Document Chip, hide Config
This commit is contained in:
Dániel Buga 2025-07-11 14:48:25 +02:00 committed by GitHub
parent 9e20bc3807
commit df7ba7d427
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1384 additions and 427 deletions

View File

@ -4,7 +4,7 @@ version = "0.0.1"
edition = "2024"
rust-version = "1.86.0"
description = "Generated metadata for Espressif devices"
documentation = "https://docs.espressif.com/projects/rust/esp-metadata/latest/"
documentation = "https://docs.espressif.com/projects/rust/esp-metadata-generated/latest/"
repository = "https://github.com/esp-rs/esp-hal"
license = "MIT OR Apache-2.0"
@ -15,10 +15,11 @@ esp-metadata = { version = "0.7.0", path = "../esp-metadata" } # TODO: remove
[features]
build-script = []
esp32 = []
esp32c2 = []
esp32c3 = []
esp32c6 = []
esp32h2 = []
esp32s2 = []
esp32s3 = []
_device-selected = []
esp32 = ["_device-selected"]
esp32c2 = ["_device-selected"]
esp32c3 = ["_device-selected"]
esp32c6 = ["_device-selected"]
esp32h2 = ["_device-selected"]
esp32s2 = ["_device-selected"]
esp32s3 = ["_device-selected"]

View File

@ -8,9 +8,11 @@
The generated output of `esp-metadata`, intended for use in [build scripts] and HAL crates alike.
The contents of this crate have been generated by running `cargo xtask update-metadata`. Do not edit by hand.
[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
## [Documentation](https://docs.espressif.com/projects/rust/esp-metadata/latest/)
## [Documentation](https://docs.espressif.com/projects/rust/esp-metadata-generated/latest/)
## Minimum Supported Rust Version (MSRV)

View File

@ -1,4 +1,12 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
#[cfg(docsrs)]
macro_rules! println {
($($any:tt)*) => {};
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(docsrs, doc(cfg(feature = "build-script")))]
pub enum Chip {
Esp32,
Esp32c2,
@ -24,7 +32,10 @@ impl core::str::FromStr for Chip {
}
}
impl Chip {
pub fn from_cargo_feature() -> Result<Self, Box<dyn std::error::Error>> {
/// Tries to extract the active chip from the active cargo features.
///
/// Exactly one device feature must be enabled for this function to succeed.
pub fn from_cargo_feature() -> Result<Self, &'static str> {
let all_chips = [
("CARGO_FEATURE_ESP32", Self::Esp32),
("CARGO_FEATURE_ESP32C2", Self::Esp32c2),
@ -39,8 +50,7 @@ impl Chip {
if std::env::var(env).is_ok() {
if chip.is_some() {
return Err(
"Expected exactly one of the following features to be enabled: esp32, esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3"
.into(),
"Expected exactly one of the following features to be enabled: esp32, esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3",
);
}
chip = Some(c);
@ -48,20 +58,26 @@ impl Chip {
}
match chip {
Some(chip) => Ok(chip),
None => {
Err(
"Expected exactly one of the following features to be enabled: esp32, esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3"
.into(),
)
}
None => Err(
"Expected exactly one of the following features to be enabled: esp32, esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3",
),
}
}
/// Returns whether the current chip uses the Tensilica Xtensa ISA.
pub fn is_xtensa(self) -> bool {
self.config().architecture == "xtensa"
}
/// The target triple of the current chip.
pub fn target(self) -> &'static str {
self.config().target
}
/// The simple name of the current chip.
///
/// ## Example
///
/// ```rust
/// assert_eq!(Chip::Esp32s3.name(), "esp32s3");
/// ```
pub fn name(self) -> &'static str {
match self {
Self::Esp32 => "esp32",
@ -73,15 +89,39 @@ impl Chip {
Self::Esp32s3 => "esp32s3",
}
}
/// Returns whether the chip configuration contains the given symbol.
///
/// This function is a short-hand for `self.all_symbols().contains(&symbol)`.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::Esp32s3.contains("soc_has_pcnt"));
/// ```
pub fn contains(self, symbol: &str) -> bool {
self.config().contains(symbol)
self.all_symbols().contains(&symbol)
}
/// Calling this function will define all cfg symbols for the firmware crate to use.
pub fn define_cfgs(self) {
self.config().define_cfgs()
}
/// Returns all symbols as a big slice.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::Esp32s3.all_symbols().contains("soc_has_pcnt"));
/// ```
pub fn all_symbols(&self) -> &'static [&'static str] {
self.config().symbols
}
/// Returns an iterator over all chips.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::iter().any(|c| c == Chip::Esp32));
/// ```
pub fn iter() -> impl Iterator<Item = Chip> {
[
Self::Esp32,
@ -94,7 +134,7 @@ impl Chip {
]
.into_iter()
}
pub fn config(self) -> Config {
fn config(self) -> Config {
match self {
Self::Esp32 => Config {
architecture: "xtensa",
@ -2105,16 +2145,13 @@ impl Chip {
}
}
}
pub struct Config {
struct Config {
architecture: &'static str,
target: &'static str,
symbols: &'static [&'static str],
cfgs: &'static [&'static str],
}
impl Config {
fn contains(&self, symbol: &str) -> bool {
self.symbols.contains(&symbol)
}
fn define_cfgs(&self) {
println!("cargo:rustc-check-cfg=cfg(not_really_docsrs)");
println!("cargo:rustc-check-cfg=cfg(esp32)");

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32"
@ -157,12 +162,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1073405952..1073741824
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -172,7 +195,24 @@ macro_rules! for_each_i2c_master {
I2CEXT1_SCL, I2CEXT1_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -183,7 +223,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS), (UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -195,7 +257,24 @@ macro_rules! for_each_spi_master {
true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -206,6 +285,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -327,56 +407,32 @@ macro_rules! for_each_peripheral {
virtual() (unstable)), (TOUCH <= virtual() (unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -467,7 +523,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -476,8 +532,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -549,7 +618,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -559,8 +628,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -612,6 +694,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -912,6 +995,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -1027,6 +1111,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -1436,6 +1521,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO0 {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32c2"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32c2"
@ -145,12 +150,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1070202880..1070465024
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -158,7 +181,24 @@ macro_rules! for_each_i2c_master {
_for_each_inner!((all(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -168,7 +208,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -178,7 +240,24 @@ macro_rules! for_each_spi_master {
FSPICS4, FSPICS5] [FSPID, FSPIQ, FSPIWP, FSPIHD], true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -187,6 +266,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -264,56 +344,32 @@ macro_rules! for_each_peripheral {
(unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -354,7 +410,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -363,8 +419,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -384,7 +453,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -394,8 +463,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -415,6 +497,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -607,6 +690,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -680,6 +764,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -797,6 +882,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32c3"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32c3"
@ -157,12 +162,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1070071808..1070465024
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -170,7 +193,24 @@ macro_rules! for_each_i2c_master {
_for_each_inner!((all(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -180,7 +220,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -190,7 +252,24 @@ macro_rules! for_each_spi_master {
FSPICS4, FSPICS5] [FSPID, FSPIQ, FSPIWP, FSPIHD], true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -199,6 +278,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -289,56 +369,32 @@ macro_rules! for_each_peripheral {
(unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -380,7 +436,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -389,8 +445,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -413,7 +482,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -423,8 +492,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -444,6 +526,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -645,6 +728,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -721,6 +805,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -864,6 +949,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32c6"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32c6"
@ -157,12 +162,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1082130432..1082654720
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -170,7 +193,24 @@ macro_rules! for_each_i2c_master {
_for_each_inner!((all(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -180,7 +220,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -190,7 +252,24 @@ macro_rules! for_each_spi_master {
FSPICS4, FSPICS5] [FSPID, FSPIQ, FSPIWP, FSPIHD], true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -199,6 +278,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -344,56 +424,32 @@ macro_rules! for_each_peripheral {
(unstable)), (MEM2MEM15 <= virtual() (unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -452,7 +508,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -461,8 +517,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -489,7 +558,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -499,8 +568,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -531,6 +613,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -813,6 +896,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -916,6 +1000,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -1156,6 +1241,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32h2"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32h2"
@ -154,12 +159,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1082130432..1082458112
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -169,7 +192,24 @@ macro_rules! for_each_i2c_master {
I2CEXT1_SCL, I2CEXT1_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -179,7 +219,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -189,7 +251,24 @@ macro_rules! for_each_spi_master {
FSPICS4, FSPICS5] [FSPID, FSPIQ, FSPIWP, FSPIHD], true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -198,6 +277,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -325,56 +405,32 @@ macro_rules! for_each_peripheral {
virtual() (unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -414,7 +470,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -423,8 +479,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -450,7 +519,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -460,8 +529,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -469,6 +551,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -661,6 +744,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -734,6 +818,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -927,6 +1012,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32s2"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32s2"
@ -157,12 +162,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1073414144..1073741824
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -172,7 +195,24 @@ macro_rules! for_each_i2c_master {
I2CEXT1_SCL, I2CEXT1_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -182,7 +222,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -195,7 +257,24 @@ macro_rules! for_each_spi_master {
SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -206,6 +285,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -327,56 +407,32 @@ macro_rules! for_each_peripheral {
virtual() (unstable)), (ULP_RISCV_CORE <= virtual() (unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -462,7 +518,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -471,8 +527,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -554,7 +623,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -564,8 +633,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -621,6 +703,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -1011,6 +1094,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -1150,6 +1234,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -1367,6 +1452,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,6 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
/// The name of the chip as `&str`
///
/// # Example
@ -8,6 +11,7 @@
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => {
"esp32s3"
@ -15,6 +19,7 @@ macro_rules! chip {
}
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => {
"esp32s3"
@ -157,12 +162,30 @@ macro_rules! property {
}
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
("DRAM") => {
1070104576..1070596096
};
}
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_i2c_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -172,7 +195,24 @@ macro_rules! for_each_i2c_master {
I2CEXT1_SCL, I2CEXT1_SDA)));
};
}
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_uart {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -183,7 +223,29 @@ macro_rules! for_each_uart {
U1RXD, U1TXD, U1CTS, U1RTS), (UART2, Uart2, U2RXD, U2TXD, U2CTS, U2RTS)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),*
/// $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ,
/// FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_master {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -197,7 +259,24 @@ macro_rules! for_each_spi_master {
true)));
};
}
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_spi_slave {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -208,6 +287,7 @@ macro_rules! for_each_spi_slave {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_peripheral {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -345,56 +425,32 @@ macro_rules! for_each_peripheral {
virtual() (unstable))));
};
}
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident =>
/// $digital_input_signal:ident)*) ($($digital_output_function:ident =>
/// $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for
/// function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used
/// to, for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_gpio {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -486,7 +542,7 @@ macro_rules! for_each_gpio {
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -495,8 +551,21 @@ macro_rules! for_each_gpio {
/// where you need the number(s) of a signal, or the general group to which the signal belongs.
/// For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_analog_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -575,7 +644,7 @@ macro_rules! for_each_analog_function {
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
@ -585,8 +654,21 @@ macro_rules! for_each_analog_function {
/// For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1,
/// SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this
/// is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! for_each_lp_function {
($($pattern:tt => $code:tt;)*) => {
macro_rules! _for_each_inner { $(($pattern) => $code;)* ($other : tt) => {} }
@ -653,6 +735,7 @@ macro_rules! for_each_lp_function {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
(GPIO0, Input, $then_tt:tt else $else_tt:tt) => {
$then_tt
@ -1061,6 +1144,7 @@ macro_rules! if_pin_is_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -1206,6 +1290,7 @@ macro_rules! impl_for_pin_type {
};
}
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -1582,6 +1667,7 @@ macro_rules! define_io_mux_signals {
}
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
pub(crate) fn io_mux_reg(gpio_num: u8) -> &'static crate::pac::io_mux::GPIO {

View File

@ -1,3 +1,100 @@
// Do NOT edit this file directly. Make your changes to esp-metadata,
// then run `cargo xtask update-metadata`.
//! # (Generated) metadata for Espressif MCUs.
//!
//! This crate provides properties that are specific to various Espressif microcontrollers,
//! and provides macros to work with peripherals, pins, and various other parts of the chips.
//!
//! This crate can be used both in firmware, as well as in build scripts, but the usage is
//! different.
//!
//! ## Usage in build scripts
//!
//! To use the `Chip` enum, add the crate to your `Cargo.toml` build
//! dependencies, with the `build-script` feature:
//!
//! ```toml
//! [build-dependencies]
//! esp-metadata-generated = { version = "...", features = ["build-script"] }
//! ```
//!
//! ## Usage in firmware
//!
//! To use the various macros, add the crate to your `Cargo.toml` dependencies.
//! A device-specific feature needs to be enabled in order to use the crate, usually
//! picked by the user:
//!
//! ```toml
//! [dependencies]
//! esp-metadata-generated = { version = "..." }
//! # ...
//!
//! [features]
//! esp32 = ["esp-metadata-generated/esp32"]
//! esp32c2 = ["esp-metadata-generated/esp32c2"]
//! # ...
//! ```
//!
//! ## `for_each` macros
//!
//! The basic syntax of this macro looks like a macro definition with two distinct syntax options:
//!
//! ```rust, no_run
//! for_each_peripherals! {
//! // Individual matcher, invoked separately for each peripheral instance
//! ( <individual match syntax> ) => { /* some code */ };
//!
//! // Repeated matcher, invoked once with all peripheral instances
//! ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
//! }
//! ```
//!
//! You can specify any number of matchers in the same invocation.
//!
//! ### Using the individual matcher
//!
//! In this use case, each item's data is individually passed through the macro. This can be used to
//! generate code for each item separately, allowing specializing the implementation where needed.
//!
//! ```rust,no_run
//! for_each_gpio! {
//! // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
//! ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
//!
//! // You can create matchers with data filled in. This example will specifically match GPIO2
//! ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
//! }
//! ```
//!
//! Different macros can have multiple different syntax options for their individual matchers,
//! usually to provide more detailed information, while preserving simpler syntax for more basic use
//! cases. Consult each macro's documentation for available options.
//!
//! ### Repeated matcher
//!
//! With this option, all data is passed through the macro all at once. This form can be used to,
//! for example, generate struct fields. If the macro has multiple individual matcher options,
//! the repeated matcher will contain each item's data multiple times, once for each available
//! syntax option. Currently, using the repeated matcher is not recommended for these macros.
//!
//! > This issue will be likely resolved by naming the different syntax options, and providing
//! > different match arms for each in place of `all`.
//!
//! ```rust,no_run
//! // Example usage to create a struct containing all GPIOs:
//! for_each_gpio! {
//! (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
//! struct Gpios {
//! $(
//! #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
//! pub $gpio: Gpio<$n>,
//! )*
//! }
//! };
//! }
//! ```
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(feature = "build-script"), no_std)]
#[cfg(all(not(feature = "build-script"), feature = "esp32"))]
include!("_generated_esp32.rs");
@ -13,5 +110,5 @@ include!("_generated_esp32h2.rs");
include!("_generated_esp32s2.rs");
#[cfg(all(not(feature = "build-script"), feature = "esp32s3"))]
include!("_generated_esp32s3.rs");
#[cfg(feature = "build-script")]
#[cfg(any(feature = "build-script", docsrs))]
include!("_build_script_utils.rs");

View File

@ -8,6 +8,8 @@
Metadata for Espressif devices, intended for use in [build scripts].
Firmware crates are meant to depend on `esp-metadata-generated`, not on this crate directly. To update `esp-metadata-generated`, make your changes in `esp-metadata`, then run `cargo xtask update-metadata`.
[build scripts]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
## [Documentation](https://docs.espressif.com/projects/rust/esp-metadata/latest/)

View File

@ -425,6 +425,7 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream {
quote! {
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! if_pin_is_type {
#(#branches)*
}
@ -453,6 +454,7 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream {
quote! {
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
#[expect(clippy::crate_in_macro_def)]
macro_rules! impl_for_pin_type {
($any_pin:ident, $inner_ident:ident, $on_type:tt, $code:tt else $otherwise:tt) => {
@ -487,87 +489,81 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream {
let output_signals = render_signals("OutputSignal", &gpio.pins_and_signals.output_signals);
quote! {
/// This macro can be used to generate code for each GPIOn instance.
/// This macro can be used to generate code for each `GPIOn` instance.
///
/// The basic syntax of this macro looks like a macro definition with two distinct syntax options:
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// ```rust, no_run
/// for_each_gpio! {
/// // Individual matcher, invoked separately for each GPIO
/// ( <match arm> ) => { /* some code */ };
/// This macro has one option for its "Individual matcher" case:
///
/// // Repeated matcher, invoked once with all GPIOs
/// ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
/// }
/// ```
/// Syntax: `($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*))`
///
/// You can specify any number of matchers.
/// Macro fragments:
///
/// ## Using the individual matcher
/// - `$n`: the number of the GPIO. For `GPIO0`, `$n` is 0.
/// - `$gpio`: the name of the GPIO.
/// - `$digital_input_function`: the number of the digital function, as an identifier (i.e. for function 0 this is `_0`).
/// - `$digital_input_function`: the name of the digital function, as an identifier.
/// - `$digital_output_function`: the number of the digital function, as an identifier (i.e. for function 0 this is `_0`).
/// - `$digital_output_function`: the name of the digital function, as an identifier.
/// - `$pin_attribute`: `Input` and/or `Output`, marks the possible directions of the GPIO.
///
/// In this use case, each GPIO's data is individually passed through the macro. This can be used to
/// generate code for each GPIO separately, allowing specializing the implementation where needed.
///
/// ```rust,no_run
/// for_each_gpio! {
/// // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
/// ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
///
/// // You can create matchers with data filled in. This example will specifically match GPIO2
/// ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
/// }
/// ```
///
/// ## Repeated matcher
///
/// With this option, all GPIO data is passed through the macro all at once. This form can be used to,
/// for example, generate struct fields.
///
/// ```rust,no_run
/// // Example usage to create a struct containing all GPIOs:
/// for_each_gpio! {
/// (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
/// struct Gpios {
/// $(
/// #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
/// pub $gpio: Gpio<$n>,
/// )*
/// }
/// };
/// }
/// ```
/// Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
#for_each_gpio
/// This macro can be used to generate code for each analog function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
/// - `($signal:ident, $gpio:ident)` - simple case where you only need identifiers
/// - `(($signal:ident, $group:ident $(, $number:literal)+), $gpio:ident)` - expanded signal case, where you need the number(s) of a signal, or the general group to which the signal belongs. For example, in case of `ADC2_CH3` the expanded form looks like `(ADC2_CH3, ADCn_CHm, 2, 3)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(ADC2_CH5, GPIO12)`
/// - `((ADC2_CH5, ADCn_CHm, 2, 5), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#for_each_analog
/// This macro can be used to generate code for each LP/RTC function of each GPIO.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [for_each_gpio].
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has two options for its "Individual matcher" case:
///
/// - `($signal:ident, $gpio:ident)` - simple case where you only need identifiers
/// - `(($signal:ident, $group:ident $(, $number:literal)+), $gpio:ident)` - expanded signal case, where you need the number(s) of a signal, or the general group to which the signal belongs. For example, in case of `SAR_I2C_SCL_1` the expanded form looks like `(SAR_I2C_SCL_1, SAR_I2C_SCL_n, 1)`.
///
/// The expanded signal are only available when the signal has at least one numbered component.
/// Macro fragments:
///
/// - `$signal`: the name of the signal.
/// - `$group`: the name of the signal, with numbers replaced by placeholders. For `ADC2_CH3` this is `ADCn_CHm`.
/// - `$number`: the numbers extracted from `$signal`.
/// - `$gpio`: the name of the GPIO.
///
/// Example data:
/// - `(RTC_GPIO15, GPIO12)`
/// - `((RTC_GPIO15, RTC_GPIOn, 15), GPIO12)`
///
/// The expanded syntax is only available when the signal has at least one numbered component.
#for_each_lp
#if_pin_is_type
#impl_for_pin_type
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_signals {
() => {
#input_signals
@ -577,6 +573,7 @@ pub(crate) fn generate_gpios(gpio: &super::GpioProperties) -> TokenStream {
#[macro_export]
#[expect(clippy::crate_in_macro_def)]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! define_io_mux_reg {
() => {
#io_mux_accessor

View File

@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::{format_ident, quote};
use crate::{cfg::I2cMasterProperties, generate_for_each_macro};
@ -34,11 +34,31 @@ pub(crate) fn generate_i2c_master_peripherals(i2c: &I2cMasterProperties) -> Toke
// The order and meaning of these tokens must match their use in the
// `for_each_i2c_master!` call.
quote::quote! {
quote! {
#instance, #sys, #scl, #sda
}
})
.collect::<Vec<_>>();
generate_for_each_macro("i2c_master", &i2c_master_instance_cfgs)
let for_each = generate_for_each_macro("i2c_master", &i2c_master_instance_cfgs);
quote! {
/// This macro can be used to generate code for each peripheral instance of the I2C master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $scl:ident, $sda:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$scl`, `$sda`: peripheral signal names.
///
/// Example data: `(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA)`
#for_each
}
}

View File

@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::{format_ident, quote};
use crate::{cfg::SpiMasterProperties, generate_for_each_macro};
@ -32,18 +32,40 @@ pub(crate) fn generate_spi_master_peripherals(spi_slave: &SpiMasterProperties) -
let sio = instance_config.sio.iter().map(|cs| format_ident!("{cs}"));
let is_qspi = if instance_config.sio.len() > 2 {
quote::quote! { , true }
quote! { , true }
} else {
quote::quote! {}
quote! {}
};
// The order and meaning of these tokens must match their use in the
// `for_each_i2c_master!` call.
quote::quote! {
quote! {
#instance, #sys, #sclk [#(#cs),*] [#(#sio),*] #is_qspi
}
})
.collect::<Vec<_>>();
generate_for_each_macro("spi_master", &instance_cfgs)
let for_each = generate_for_each_macro("spi_master", &instance_cfgs);
quote! {
/// This macro can be used to generate code for each peripheral instance of the SPI master driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, [$($cs:ident),*] [$($sio:ident),* $($is_qspi:iteral)?])`
///
/// Macro fragments:
///
/// - `$instance`: the name of the SPI instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$cs`, `$sio`: chip select and SIO signal names.
/// - `$is_qspi`: a `true` literal present if the SPI instance supports QSPI.
///
/// Example data:
/// - `(SPI2, Spi2, FSPICLK [FSPICS0, FSPICS1, FSPICS2, FSPICS3, FSPICS4, FSPICS5] [FSPID, FSPIQ, FSPIWP, FSPIHD, FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7], true)`
/// - `(SPI3, Spi3, SPI3_CLK [SPI3_CS0, SPI3_CS1, SPI3_CS2] [SPI3_D, SPI3_Q])`
#for_each
}
}

View File

@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::{format_ident, quote};
use crate::{cfg::SpiSlaveProperties, generate_for_each_macro};
@ -35,11 +35,30 @@ pub(crate) fn generate_spi_slave_peripherals(spi_slave: &SpiSlaveProperties) ->
// The order and meaning of these tokens must match their use in the
// `for_each_i2c_master!` call.
quote::quote! {
quote! {
#instance, #sys, #sclk, #mosi, #miso, #cs
}
})
.collect::<Vec<_>>();
generate_for_each_macro("spi_slave", &instance_cfgs)
let for_each = generate_for_each_macro("spi_slave", &instance_cfgs);
quote! {
/// This macro can be used to generate code for each peripheral instance of the SPI slave driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the I2C instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$mosi`, `$miso`, `$cs`: signal names.
///
/// Example data: `(SPI2, Spi2, FSPICLK, FSPID, FSPIQ, FSPICS0)`
#for_each
}
}

View File

@ -1,5 +1,5 @@
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::{format_ident, quote};
use crate::{cfg::UartProperties, generate_for_each_macro};
@ -42,11 +42,30 @@ pub(crate) fn generate_uart_peripherals(uart: &UartProperties) -> TokenStream {
// The order and meaning of these tokens must match their use in the
// `for_each_uart!` call.
quote::quote! {
quote! {
#instance, #sys, #rx, #tx, #cts, #rts
}
})
.collect::<Vec<_>>();
generate_for_each_macro("uart", &uart_instance_cfgs)
let for_each = generate_for_each_macro("uart", &uart_instance_cfgs);
quote! {
/// This macro can be used to generate code for each peripheral instance of the UART driver.
///
/// For an explanation on the general syntax, as well as usage of individual/repeated
/// matchers, refer to [the crate-level documentation][crate#for_each-macros].
///
/// This macro has one option for its "Individual matcher" case:
///
/// Syntax: `($instance:ident, $sys:ident, $rx:ident, $tx:ident, $cts:ident, $rts:ident)`
///
/// Macro fragments:
///
/// - `$instance`: the name of the UART instance
/// - `$sys`: the name of the instance as it is in the `esp_hal::system::Peripheral` enum.
/// - `$rx`, `$tx`, `$cts`, `$rts`: signal names.
///
/// Example data: `(UART0, Uart0, U0RXD, U0TXD, U0CTS, U0RTS)`
#for_each
}
}

View File

@ -444,6 +444,7 @@ impl Config {
#[doc = concat!("assert_eq!(chip_name, ", chip!(), ")")]
/// ```
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! chip {
() => { #chip_name };
}
@ -476,6 +477,7 @@ impl Config {
tokens.extend(quote! {
/// The properties of this chip and its drivers.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! property {
("chip") => { #chip_name };
("arch") => { #arch };
@ -501,6 +503,7 @@ impl Config {
tokens.extend(quote! {
/// Macro to get the address range of the given memory region.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! memory_range {
#(#region_branches)*
}
@ -636,6 +639,7 @@ fn generate_for_each_macro(name: &str, branches: &[TokenStream]) -> TokenStream
// Instance trait for available peripherals. It works by defining, then calling an inner
// macro that substitutes the properties into the template provided by the call in esp-hal.
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "_device-selected")))]
macro_rules! #macro_name {
(
$($pattern:tt => $code:tt;)*
@ -707,7 +711,14 @@ pub fn generate_build_script_utils() -> TokenStream {
);
quote! {
// make it possible to build documentation without `std`.
#[cfg(docsrs)]
macro_rules! println {
($($any:tt)*) => {};
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(docsrs, doc(cfg(feature = "build-script")))]
pub enum Chip {
#(#chip),*
}
@ -724,7 +735,10 @@ pub fn generate_build_script_utils() -> TokenStream {
}
impl Chip {
pub fn from_cargo_feature() -> Result<Self, Box<dyn std::error::Error>> {
/// Tries to extract the active chip from the active cargo features.
///
/// Exactly one device feature must be enabled for this function to succeed.
pub fn from_cargo_feature() -> Result<Self, &'static str> {
let all_chips = [
#(( #feature_env, Self::#chip )),*
];
@ -733,7 +747,7 @@ pub fn generate_build_script_utils() -> TokenStream {
for (env, c) in all_chips {
if std::env::var(env).is_ok() {
if chip.is_some() {
return Err(#bail_message.into());
return Err(#bail_message);
}
chip = Some(c);
}
@ -741,50 +755,83 @@ pub fn generate_build_script_utils() -> TokenStream {
match chip {
Some(chip) => Ok(chip),
None => Err(#bail_message.into())
None => Err(#bail_message)
}
}
/// Returns whether the current chip uses the Tensilica Xtensa ISA.
pub fn is_xtensa(self) -> bool {
self.config().architecture == "xtensa"
}
/// The target triple of the current chip.
pub fn target(self) -> &'static str {
self.config().target
}
/// The simple name of the current chip.
///
/// ## Example
///
/// ```rust
/// assert_eq!(Chip::Esp32s3.name(), "esp32s3");
/// ```
pub fn name(self) -> &'static str {
match self {
#( Self::#chip => #name ),*
}
}
/// Returns whether the chip configuration contains the given symbol.
///
/// This function is a short-hand for `self.all_symbols().contains(&symbol)`.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::Esp32s3.contains("soc_has_pcnt"));
/// ```
pub fn contains(self, symbol: &str) -> bool {
self.config().contains(symbol)
self.all_symbols().contains(&symbol)
}
/// Calling this function will define all cfg symbols for the firmware crate to use.
pub fn define_cfgs(self) {
self.config().define_cfgs()
}
/// Returns all symbols as a big slice.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::Esp32s3.all_symbols().contains("soc_has_pcnt"));
/// ```
pub fn all_symbols(&self) -> &'static [&'static str] {
self.config().symbols
}
/// Returns an iterator over all chips.
///
/// ## Example
///
/// ```rust
/// assert!(Chip::iter().any(|c| c == Chip::Esp32));
/// ```
pub fn iter() -> impl Iterator<Item = Chip> {
[
#( Self::#chip ),*
].into_iter()
}
pub fn config(self) -> Config {
fn config(self) -> Config {
match self {
#(Self::#chip => #config),*
}
}
}
pub struct Config {
struct Config {
architecture: &'static str,
target: &'static str,
symbols: &'static [&'static str],
@ -792,10 +839,6 @@ pub fn generate_build_script_utils() -> TokenStream {
}
impl Config {
fn contains(&self, symbol: &str) -> bool {
self.symbols.contains(&symbol)
}
fn define_cfgs(&self) {
#(println!(#check_cfgs);)*
@ -818,11 +861,104 @@ pub fn generate_lib_rs() -> TokenStream {
});
quote! {
//! # (Generated) metadata for Espressif MCUs.
//!
//! This crate provides properties that are specific to various Espressif microcontrollers,
//! and provides macros to work with peripherals, pins, and various other parts of the chips.
//!
//! This crate can be used both in firmware, as well as in build scripts, but the usage is different.
//!
//! ## Usage in build scripts
//!
//! To use the `Chip` enum, add the crate to your `Cargo.toml` build
//! dependencies, with the `build-script` feature:
//!
//! ```toml
//! [build-dependencies]
//! esp-metadata-generated = { version = "...", features = ["build-script"] }
//! ```
//!
//! ## Usage in firmware
//!
//! To use the various macros, add the crate to your `Cargo.toml` dependencies.
//! A device-specific feature needs to be enabled in order to use the crate, usually
//! picked by the user:
//!
//! ```toml
//! [dependencies]
//! esp-metadata-generated = { version = "..." }
//! # ...
//!
//! [features]
//! esp32 = ["esp-metadata-generated/esp32"]
//! esp32c2 = ["esp-metadata-generated/esp32c2"]
//! # ...
//! ```
//!
//! ## `for_each` macros
//!
//! The basic syntax of this macro looks like a macro definition with two distinct syntax options:
//!
//! ```rust, no_run
//! for_each_peripherals! {
//! // Individual matcher, invoked separately for each peripheral instance
//! ( <individual match syntax> ) => { /* some code */ };
//!
//! // Repeated matcher, invoked once with all peripheral instances
//! ( all $( (<individual match syntax>) ),* ) => { /* some code */ };
//! }
//! ```
//!
//! You can specify any number of matchers in the same invocation.
//!
//! ### Using the individual matcher
//!
//! In this use case, each item's data is individually passed through the macro. This can be used to
//! generate code for each item separately, allowing specializing the implementation where needed.
//!
//! ```rust,no_run
//! for_each_gpio! {
//! // Example data: `(0, GPIO0 (_5 => EMAC_TX_CLK) (_1 => CLK_OUT1 _5 => EMAC_TX_CLK) (Input Output))`
//! ($n:literal, $gpio:ident ($($digital_input_function:ident => $digital_input_signal:ident)*) ($($digital_output_function:ident => $digital_output_signal:ident)*) ($($pin_attribute:ident)*)) => { /* some code */ };
//!
//! // You can create matchers with data filled in. This example will specifically match GPIO2
//! ($n:literal, GPIO2 $input_af:tt $output_af:tt $attributes:tt) => { /* Additional case only for GPIO2 */ };
//! }
//! ```
//!
//! Different macros can have multiple different syntax options for their individual matchers, usually
//! to provide more detailed information, while preserving simpler syntax for more basic use cases.
//! Consult each macro's documentation for available options.
//!
//! ### Repeated matcher
//!
//! With this option, all data is passed through the macro all at once. This form can be used to,
//! for example, generate struct fields. If the macro has multiple individual matcher options,
//! the repeated matcher will contain each item's data multiple times, once for each available
//! syntax option. Currently, using the repeated matcher is not recommended for these macros.
//!
//! > This issue will be likely resolved by naming the different syntax options, and providing
//! > different match arms for each in place of `all`.
//!
//! ```rust,no_run
//! // Example usage to create a struct containing all GPIOs:
//! for_each_gpio! {
//! (all $( ($n:literal, $gpio:ident $_af_ins:tt $_af_outs:tt $_attrs:tt) ),*) => {
//! struct Gpios {
//! $(
//! #[doc = concat!(" The ", stringify!($n), "th GPIO pin")]
//! pub $gpio: Gpio<$n>,
//! )*
//! }
//! };
//! }
//! ```
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(not(feature = "build-script"), no_std)]
#(#chips)*
#[cfg(feature = "build-script")]
#[cfg(any(feature = "build-script", docsrs))]
include!( "_build_script_utils.rs");
}
}

View File

@ -564,7 +564,10 @@ fn save(out_path: &Path, tokens: TokenStream) -> Result<()> {
let source = tokens.to_string();
let syntax_tree = syn::parse_file(&source)?;
let source = prettyplease::unparse(&syntax_tree);
let mut source = String::from(
"// Do NOT edit this file directly. Make your changes to esp-metadata,\n// then run `cargo xtask update-metadata`.\n\n",
);
source.push_str(&prettyplease::unparse(&syntax_tree));
std::fs::write(out_path, source)?;