Move timer instance config into driver metadata (#3626)

* Remove timg_timer1 symbol

* Ensure instances exist

* Rename timers to timergroup

* Remove unnecessary cfg
This commit is contained in:
Dániel Buga 2025-06-12 16:49:04 +02:00 committed by GitHub
parent 1b5a85e7d6
commit 793b01beaa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 145 additions and 71 deletions

View File

@ -168,7 +168,7 @@ fn main() -> Result<(), Box<dyn Error>> {
for (key, value) in &cfg { for (key, value) in &cfg {
if let Value::Bool(true) = value { if let Value::Bool(true) = value {
config_symbols.push(key); config_symbols.push(key.to_string());
} }
} }
@ -230,7 +230,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// Helper Functions // Helper Functions
fn copy_dir_all( fn copy_dir_all(
config_symbols: &[&str], config_symbols: &[String],
cfg: &HashMap<String, Value>, cfg: &HashMap<String, Value>,
src: impl AsRef<Path>, src: impl AsRef<Path>,
dst: impl AsRef<Path>, dst: impl AsRef<Path>,
@ -260,7 +260,7 @@ fn copy_dir_all(
/// A naive pre-processor for linker scripts /// A naive pre-processor for linker scripts
fn preprocess_file( fn preprocess_file(
config: &[&str], config: &[String],
cfg: &HashMap<String, Value>, cfg: &HashMap<String, Value>,
src: impl AsRef<Path>, src: impl AsRef<Path>,
dst: impl AsRef<Path>, dst: impl AsRef<Path>,
@ -279,7 +279,7 @@ fn preprocess_file(
if let Some(condition) = trimmed.strip_prefix("#IF ") { if let Some(condition) = trimmed.strip_prefix("#IF ") {
let should_take = take.iter().all(|v| *v); let should_take = take.iter().all(|v| *v);
let should_take = should_take && config.contains(&condition); let should_take = should_take && config.iter().any(|c| c.as_str() == condition);
take.push(should_take); take.push(should_take);
continue; continue;
} else if trimmed == "#ELSE" { } else if trimmed == "#ELSE" {

View File

@ -58,8 +58,9 @@ pub struct WatchdogConfig {
/// Configures the reset watchdog timer. /// Configures the reset watchdog timer.
rwdt: WatchdogStatus, rwdt: WatchdogStatus,
/// Configures the `timg0` watchdog timer. /// Configures the `timg0` watchdog timer.
#[cfg(timergroup_timg0)]
timg0: WatchdogStatus, timg0: WatchdogStatus,
#[cfg(timg1)] #[cfg(timergroup_timg1)]
/// Configures the `timg1` watchdog timer. /// Configures the `timg1` watchdog timer.
/// ///
/// By default, the bootloader does not enable this watchdog timer. /// By default, the bootloader does not enable this watchdog timer.

View File

@ -308,7 +308,7 @@ unstable_module! {
// Drivers needed for initialization or they are tightly coupled to something else. // Drivers needed for initialization or they are tightly coupled to something else.
#[cfg(any(adc1, adc2, dac))] #[cfg(any(adc1, adc2, dac))]
pub mod analog; pub mod analog;
#[cfg(any(systimer, timg0, timg1))] #[cfg(any(systimer, timergroup))]
pub mod timer; pub mod timer;
#[cfg(any(lp_clkrst, rtc_cntl))] #[cfg(any(lp_clkrst, rtc_cntl))]
pub mod rtc_cntl; pub mod rtc_cntl;
@ -325,7 +325,6 @@ unstable_driver! {
pub mod aes; pub mod aes;
#[cfg(assist_debug)] #[cfg(assist_debug)]
pub mod assist_debug; pub mod assist_debug;
#[cfg(any(xtensa, all(riscv, systimer)))]
pub mod delay; pub mod delay;
#[cfg(ecc)] #[cfg(ecc)]
pub mod ecc; pub mod ecc;
@ -634,6 +633,7 @@ pub fn init(config: Config) -> Peripherals {
} }
} }
#[cfg(timergroup_timg0)]
match config.watchdog.timg0() { match config.watchdog.timg0() {
WatchdogStatus::Enabled(duration) => { WatchdogStatus::Enabled(duration) => {
let mut timg0_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new(); let mut timg0_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new();
@ -645,7 +645,7 @@ pub fn init(config: Config) -> Peripherals {
} }
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
match config.watchdog.timg1() { match config.watchdog.timg1() {
WatchdogStatus::Enabled(duration) => { WatchdogStatus::Enabled(duration) => {
let mut timg1_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new(); let mut timg1_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new();
@ -664,9 +664,10 @@ pub fn init(config: Config) -> Peripherals {
rtc.rwdt.disable(); rtc.rwdt.disable();
#[cfg(timergroup_timg0)]
crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable(); crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable();
#[cfg(timg1)] #[cfg(timergroup_timg1)]
crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable(); crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable();
} }
} }

View File

@ -129,6 +129,7 @@ impl Peripheral {
Peripheral::UsbDevice, Peripheral::UsbDevice,
#[cfg(systimer)] #[cfg(systimer)]
Peripheral::Systimer, Peripheral::Systimer,
#[cfg(timg0)]
Peripheral::Timg0, Peripheral::Timg0,
#[cfg(esp32c6)] // used by some wifi calibration steps. #[cfg(esp32c6)] // used by some wifi calibration steps.
// TODO: We should probably automatically enable this when needed. // TODO: We should probably automatically enable this when needed.

View File

@ -60,7 +60,7 @@ use crate::{
#[cfg(systimer)] #[cfg(systimer)]
pub mod systimer; pub mod systimer;
#[cfg(any(timg0, timg1))] #[cfg(timergroup)]
pub mod timg; pub mod timg;
/// Timer errors. /// Timer errors.
@ -416,6 +416,7 @@ where
crate::any_peripheral! { crate::any_peripheral! {
/// Any Timer peripheral. /// Any Timer peripheral.
pub peripheral AnyTimer<'d> { pub peripheral AnyTimer<'d> {
#[cfg(timergroup)]
TimgTimer(timg::Timer<'d>), TimgTimer(timg::Timer<'d>),
#[cfg(systimer)] #[cfg(systimer)]
SystimerAlarm(systimer::Alarm<'d>), SystimerAlarm(systimer::Alarm<'d>),

View File

@ -69,7 +69,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use super::Error; use super::Error;
#[cfg(timg1)] #[cfg(timergroup_timg1)]
use crate::peripherals::TIMG1; use crate::peripherals::TIMG1;
#[cfg(any(esp32c6, esp32h2))] #[cfg(any(esp32c6, esp32h2))]
use crate::soc::constants::TIMG_DEFAULT_CLK_SRC; use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
@ -84,21 +84,21 @@ use crate::{
time::{Duration, Instant, Rate}, time::{Duration, Instant, Rate},
}; };
const NUM_TIMG: usize = 1 + cfg!(timg1) as usize; const NUM_TIMG: usize = 1 + cfg!(timergroup_timg1) as usize;
cfg_if::cfg_if! { cfg_if::cfg_if! {
// We need no locks when a TIMG has a single timer, and we don't need locks for ESP32 // We need no locks when a TIMG has a single timer, and we don't need locks for ESP32
// and S2 where the effective interrupt enable register (config) is not shared between // and S2 where the effective interrupt enable register (config) is not shared between
// the timers. // the timers.
if #[cfg(all(timg_timer1, not(any(esp32, esp32s2))))] { if #[cfg(all(timergroup_timg_has_timer1, not(any(esp32, esp32s2))))] {
use crate::sync::{lock, RawMutex}; use crate::sync::{lock, RawMutex};
static INT_ENA_LOCK: [RawMutex; NUM_TIMG] = [const { RawMutex::new() }; NUM_TIMG]; static INT_ENA_LOCK: [RawMutex; NUM_TIMG] = [const { RawMutex::new() }; NUM_TIMG];
} }
} }
/// A timer group consisting of /// A timer group consisting of
#[cfg_attr(not(timg_timer1), doc = "a general purpose timer")] #[cfg_attr(not(timergroup_timg_has_timer1), doc = "a general purpose timer")]
#[cfg_attr(timg_timer1, doc = "2 timers")] #[cfg_attr(timergroup_timg_has_timer1, doc = "2 timers")]
/// and a watchdog timer. /// and a watchdog timer.
pub struct TimerGroup<'d, T> pub struct TimerGroup<'d, T>
where where
@ -108,7 +108,7 @@ where
/// Timer 0 /// Timer 0
pub timer0: Timer<'d>, pub timer0: Timer<'d>,
/// Timer 1 /// Timer 1
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
pub timer1: Timer<'d>, pub timer1: Timer<'d>,
/// Watchdog timer /// Watchdog timer
pub wdt: Wdt<T>, pub wdt: Wdt<T>,
@ -125,6 +125,7 @@ pub trait TimerGroupInstance {
fn wdt_interrupt() -> Interrupt; fn wdt_interrupt() -> Interrupt;
} }
#[cfg(timergroup_timg0)]
impl TimerGroupInstance for TIMG0<'_> { impl TimerGroupInstance for TIMG0<'_> {
fn id() -> u8 { fn id() -> u8 {
0 0
@ -186,7 +187,7 @@ impl TimerGroupInstance for TIMG0<'_> {
} }
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
impl TimerGroupInstance for crate::peripherals::TIMG1<'_> { impl TimerGroupInstance for crate::peripherals::TIMG1<'_> {
fn id() -> u8 { fn id() -> u8 {
1 1
@ -262,7 +263,7 @@ where
register_block: T::register_block(), register_block: T::register_block(),
_lifetime: PhantomData, _lifetime: PhantomData,
}, },
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
timer1: Timer { timer1: Timer {
timer: 1, timer: 1,
tg: T::id(), tg: T::id(),
@ -325,11 +326,11 @@ impl super::Timer for Timer<'_> {
fn async_interrupt_handler(&self) -> InterruptHandler { fn async_interrupt_handler(&self) -> InterruptHandler {
match (self.timer_group(), self.timer_number()) { match (self.timer_group(), self.timer_number()) {
(0, 0) => asynch::timg0_timer0_handler, (0, 0) => asynch::timg0_timer0_handler,
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
(0, 1) => asynch::timg0_timer1_handler, (0, 1) => asynch::timg0_timer1_handler,
#[cfg(timg1)] #[cfg(timergroup_timg1)]
(1, 0) => asynch::timg1_timer0_handler, (1, 0) => asynch::timg1_timer0_handler,
#[cfg(all(timg_timer1, timg1))] #[cfg(all(timergroup_timg_has_timer1, timergroup_timg1))]
(1, 1) => asynch::timg1_timer1_handler, (1, 1) => asynch::timg1_timer1_handler,
_ => unreachable!(), _ => unreachable!(),
} }
@ -338,11 +339,11 @@ impl super::Timer for Timer<'_> {
fn peripheral_interrupt(&self) -> Interrupt { fn peripheral_interrupt(&self) -> Interrupt {
match (self.timer_group(), self.timer_number()) { match (self.timer_group(), self.timer_number()) {
(0, 0) => Interrupt::TG0_T0_LEVEL, (0, 0) => Interrupt::TG0_T0_LEVEL,
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
(0, 1) => Interrupt::TG0_T1_LEVEL, (0, 1) => Interrupt::TG0_T1_LEVEL,
#[cfg(timg1)] #[cfg(timergroup_timg1)]
(1, 0) => Interrupt::TG1_T0_LEVEL, (1, 0) => Interrupt::TG1_T0_LEVEL,
#[cfg(all(timg_timer1, timg1))] #[cfg(all(timergroup_timg_has_timer1, timergroup_timg1))]
(1, 1) => Interrupt::TG1_T1_LEVEL, (1, 1) => Interrupt::TG1_T1_LEVEL,
_ => unreachable!(), _ => unreachable!(),
} }
@ -398,11 +399,11 @@ impl Timer<'_> {
pub(crate) fn set_interrupt_handler(&self, handler: InterruptHandler) { pub(crate) fn set_interrupt_handler(&self, handler: InterruptHandler) {
let interrupt = match (self.timer_group(), self.timer_number()) { let interrupt = match (self.timer_group(), self.timer_number()) {
(0, 0) => Interrupt::TG0_T0_LEVEL, (0, 0) => Interrupt::TG0_T0_LEVEL,
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
(0, 1) => Interrupt::TG0_T1_LEVEL, (0, 1) => Interrupt::TG0_T1_LEVEL,
#[cfg(timg1)] #[cfg(timergroup_timg1)]
(1, 0) => Interrupt::TG1_T0_LEVEL, (1, 0) => Interrupt::TG1_T0_LEVEL,
#[cfg(all(timg_timer1, timg1))] #[cfg(all(timergroup_timg_has_timer1, timergroup_timg1))]
(1, 1) => Interrupt::TG1_T1_LEVEL, (1, 1) => Interrupt::TG1_T1_LEVEL,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -560,7 +561,7 @@ impl Timer<'_> {
.t(self.timer as usize) .t(self.timer as usize)
.config() .config()
.modify(|_, w| w.level_int_en().bit(state)); .modify(|_, w| w.level_int_en().bit(state));
} else if #[cfg(timg_timer1)] { } else if #[cfg(timergroup_timg_has_timer1)] {
lock(&INT_ENA_LOCK[self.timer_group() as usize], || { lock(&INT_ENA_LOCK[self.timer_group() as usize], || {
self.register_block() self.register_block()
.int_ena() .int_ena()
@ -828,7 +829,7 @@ mod asynch {
use crate::asynch::AtomicWaker; use crate::asynch::AtomicWaker;
const NUM_WAKERS: usize = { const NUM_WAKERS: usize = {
let timer_per_group = 1 + cfg!(timg_timer1) as usize; let timer_per_group = 1 + cfg!(timergroup_timg_has_timer1) as usize;
NUM_TIMG * timer_per_group NUM_TIMG * timer_per_group
}; };
@ -859,7 +860,7 @@ mod asynch {
}); });
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
#[handler] #[handler]
pub(crate) fn timg1_timer0_handler() { pub(crate) fn timg1_timer0_handler() {
handle_irq(Timer { handle_irq(Timer {
@ -870,7 +871,7 @@ mod asynch {
}); });
} }
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
#[handler] #[handler]
pub(crate) fn timg0_timer1_handler() { pub(crate) fn timg0_timer1_handler() {
handle_irq(Timer { handle_irq(Timer {
@ -881,7 +882,7 @@ mod asynch {
}); });
} }
#[cfg(all(timg1, timg_timer1))] #[cfg(all(timergroup_timg1, timergroup_timg_has_timer1))]
#[handler] #[handler]
pub(crate) fn timg1_timer1_handler() { pub(crate) fn timg1_timer1_handler() {
handle_irq(Timer { handle_irq(Timer {

View File

@ -67,7 +67,6 @@ symbols = [
"pdma", "pdma",
"phy", "phy",
"psram", "psram",
"timg_timer1",
"touch", "touch",
"large_intr_status", "large_intr_status",
"gpio_bank_1", "gpio_bank_1",
@ -108,6 +107,10 @@ channel_ram_size = 64
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
timg_has_timer1 = true
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -146,7 +149,7 @@ status = "not_supported"
[device.psram] [device.psram]
[device.temp_sensor] [device.temp_sensor]
[device.sleep] [device.sleep]
[device.timers]
[device.ulp_fsm] [device.ulp_fsm]
## Radio ## Radio

View File

@ -80,6 +80,9 @@ bus_timeout_is_exponential = true
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
instances = [{ name = "timg0" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -103,7 +106,6 @@ status = "supported"
[device.io_mux] [device.io_mux]
[device.temp_sensor] [device.temp_sensor]
[device.sleep] [device.sleep]
[device.timers]
[device.systimer] [device.systimer]
## Radio ## Radio

View File

@ -100,6 +100,9 @@ channel_ram_size = 48
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -129,7 +132,6 @@ status = "not_supported"
[device.interrupts] [device.interrupts]
[device.io_mux] [device.io_mux]
[device.temp_sensor] [device.temp_sensor]
[device.timers]
[device.sleep] [device.sleep]
[device.systimer] [device.systimer]

View File

@ -131,6 +131,9 @@ channel_ram_size = 48
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -172,7 +175,6 @@ has_wifi6 = true
[device.sleep] [device.sleep]
[device.temp_sensor] [device.temp_sensor]
[device.systimer] [device.systimer]
[device.timers]
[device.ulp_riscv] [device.ulp_riscv]
## Radio ## Radio

View File

@ -113,6 +113,9 @@ channel_ram_size = 48
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -149,7 +152,6 @@ status = "not_supported"
[device.sleep] [device.sleep]
[device.systimer] [device.systimer]
[device.temp_sensor] [device.temp_sensor]
[device.timers]
## Radio ## Radio
[device.bt] [device.bt]

View File

@ -65,7 +65,6 @@ symbols = [
"psram", "psram",
"psram_dma", "psram_dma",
"ulp_riscv_core", "ulp_riscv_core",
"timg_timer1",
"large_intr_status", "large_intr_status",
"gpio_bank_1", "gpio_bank_1",
"spi_octal", "spi_octal",
@ -107,6 +106,10 @@ channel_ram_size = 64
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
timg_has_timer1 = true
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -148,7 +151,6 @@ status = "not_supported"
[device.psram] [device.psram]
[device.sleep] [device.sleep]
[device.systimer] [device.systimer]
[device.timers]
[device.temp_sensor] [device.temp_sensor]
[device.ulp_fsm] [device.ulp_fsm]
[device.ulp_riscv] [device.ulp_riscv]

View File

@ -79,7 +79,6 @@ symbols = [
"psram_dma", "psram_dma",
"octal_psram", "octal_psram",
"ulp_riscv_core", "ulp_riscv_core",
"timg_timer1",
"very_large_intr_status", "very_large_intr_status",
"gpio_bank_1", "gpio_bank_1",
"spi_octal", "spi_octal",
@ -127,6 +126,10 @@ channel_ram_size = 48
[device.spi_master] [device.spi_master]
status = "supported" status = "supported"
[device.timergroup]
timg_has_timer1 = true
instances = [{ name = "timg0" }, { name = "timg1" }]
[device.uart] [device.uart]
status = "supported" status = "supported"
@ -168,7 +171,6 @@ status = "not_supported"
[device.sleep] [device.sleep]
[device.systimer] [device.systimer]
[device.temp_sensor] [device.temp_sensor]
[device.timers]
[device.ulp_fsm] [device.ulp_fsm]
[device.ulp_riscv] [device.ulp_riscv]

View File

@ -1,7 +1,7 @@
use core::str::FromStr; use core::str::FromStr;
use std::{fmt::Write, sync::OnceLock}; use std::{fmt::Write, sync::OnceLock};
use anyhow::{Result, bail}; use anyhow::{Result, bail, ensure};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -257,6 +257,20 @@ impl SupportStatus {
} }
} }
/// An empty configuration, used when a driver just wants to declare that
/// it supports a peripheral, but does not have any configuration options.
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
struct EmptyInstanceConfig {}
/// A peripheral instance for which a driver is implemented.
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
struct PeriInstance<I> {
/// The name of the instance
name: String,
#[serde(flatten)]
instance_config: I,
}
struct SupportItem { struct SupportItem {
name: &'static str, name: &'static str,
config_group: &'static str, config_group: &'static str,
@ -276,9 +290,10 @@ macro_rules! driver_configs {
struct $struct { struct $struct {
#[serde(default)] #[serde(default)]
status: SupportStatus, status: SupportStatus,
// If empty, the driver supports a single instance only. /// The list of peripherals for which this driver is implemented.
/// If empty, the driver supports a single instance only.
#[serde(default)] #[serde(default)]
instances: Vec<String>, instances: Vec<PeriInstance<EmptyInstanceConfig>>,
$( $(
$(#[$meta])? $(#[$meta])?
$config: $ty, $config: $ty,
@ -362,6 +377,14 @@ macro_rules! driver_configs {
} )))* } )))*
} }
fn driver_instances(&self) -> impl Iterator<Item = String> {
// Chain all driver instances from each driver.
std::iter::empty()
$(.chain(self.$driver.iter().flat_map(|d| {
d.instances.iter().map(|i| format!("{}.{}", stringify!($driver), i.name.as_str()))
})))*
}
/// Returns an iterator over all properties of all peripherals. /// Returns an iterator over all properties of all peripherals.
fn properties(&self) -> impl Iterator<Item = (&str, Value)> { fn properties(&self) -> impl Iterator<Item = (&str, Value)> {
// Chain all properties from each driver. // Chain all properties from each driver.
@ -617,10 +640,13 @@ driver_configs![
properties: {} properties: {}
}, },
TimersProperties { TimersProperties {
driver: timers, driver: timergroup,
name: "Timers", name: "Timers",
peripherals: &["timg0", "timg1"], peripherals: &[],
properties: {} properties: {
#[serde(default)]
timg_has_timer1: bool,
}
}, },
TouchProperties { TouchProperties {
driver: touch, driver: touch,
@ -702,7 +728,7 @@ pub struct Config {
impl Config { impl Config {
/// The configuration for the specified chip. /// The configuration for the specified chip.
pub fn for_chip(chip: &Chip) -> &Self { pub fn for_chip(chip: &Chip) -> &Self {
match chip { let config = match chip {
Chip::Esp32 => include_toml!(Config, "../devices/esp32.toml"), Chip::Esp32 => include_toml!(Config, "../devices/esp32.toml"),
Chip::Esp32c2 => include_toml!(Config, "../devices/esp32c2.toml"), Chip::Esp32c2 => include_toml!(Config, "../devices/esp32c2.toml"),
Chip::Esp32c3 => include_toml!(Config, "../devices/esp32c3.toml"), Chip::Esp32c3 => include_toml!(Config, "../devices/esp32c3.toml"),
@ -710,7 +736,11 @@ impl Config {
Chip::Esp32h2 => include_toml!(Config, "../devices/esp32h2.toml"), Chip::Esp32h2 => include_toml!(Config, "../devices/esp32h2.toml"),
Chip::Esp32s2 => include_toml!(Config, "../devices/esp32s2.toml"), Chip::Esp32s2 => include_toml!(Config, "../devices/esp32s2.toml"),
Chip::Esp32s3 => include_toml!(Config, "../devices/esp32s3.toml"), Chip::Esp32s3 => include_toml!(Config, "../devices/esp32s3.toml"),
} };
config.validate().expect("Invalid device configuration");
config
} }
/// Create an empty configuration /// Create an empty configuration
@ -729,6 +759,19 @@ impl Config {
} }
} }
fn validate(&self) -> Result<()> {
for instance in self.device.peri_config.driver_instances() {
let (driver, peri) = instance.split_once('.').unwrap();
ensure!(
self.device.peripherals.iter().any(|p| p == peri),
"Driver {driver} marks an implementation for '{peri}' but this peripheral is not defined for '{}'",
self.device.name
);
}
Ok(())
}
/// The name of the device. /// The name of the device.
pub fn name(&self) -> String { pub fn name(&self) -> String {
self.device.name.clone() self.device.name.clone()
@ -767,25 +810,31 @@ impl Config {
} }
/// All configuration values for the device. /// All configuration values for the device.
pub fn all(&self) -> impl Iterator<Item = &str> + '_ { pub fn all(&self) -> impl Iterator<Item = String> + '_ {
[ [
self.device.name.as_str(), self.device.name.clone(),
self.device.arch.as_ref(), self.device.arch.to_string(),
match self.cores() { match self.cores() {
Cores::Single => "single_core", Cores::Single => String::from("single_core"),
Cores::Multi => "multi_core", Cores::Multi => String::from("multi_core"),
}, },
] ]
.into_iter() .into_iter()
.chain(self.device.peripherals.iter().map(|s| s.as_str())) .chain(self.device.peripherals.iter().cloned())
.chain(self.device.symbols.iter().map(|s| s.as_str())) .chain(self.device.symbols.iter().cloned())
.chain(self.device.peri_config.driver_names()) .chain(
self.device
.peri_config
.driver_names()
.map(|name| name.to_string()),
)
.chain(self.device.peri_config.driver_instances())
.chain( .chain(
self.device self.device
.peri_config .peri_config
.properties() .properties()
.filter_map(|(name, value)| match value { .filter_map(|(name, value)| match value {
Value::Boolean(true) => Some(name), Value::Boolean(true) => Some(name.to_string()),
_ => None, _ => None,
}), }),
) )

View File

@ -137,14 +137,14 @@ pub use executor::Executor;
macro_rules! init_embassy { macro_rules! init_embassy {
($peripherals:expr, 2) => {{ ($peripherals:expr, 2) => {{
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(timg_timer1)] { if #[cfg(timergroup_timg_has_timer1)] {
use esp_hal::timer::timg::TimerGroup; use esp_hal::timer::timg::TimerGroup;
let timg0 = TimerGroup::new($peripherals.TIMG0); let timg0 = TimerGroup::new($peripherals.TIMG0);
esp_hal_embassy::init([ esp_hal_embassy::init([
timg0.timer0, timg0.timer0,
timg0.timer1, timg0.timer1,
]); ]);
} else if #[cfg(timg1)] { } else if #[cfg(timergroup_timg1)] {
use esp_hal::timer::timg::TimerGroup; use esp_hal::timer::timg::TimerGroup;
let timg0 = TimerGroup::new($peripherals.TIMG0); let timg0 = TimerGroup::new($peripherals.TIMG0);
let timg1 = TimerGroup::new($peripherals.TIMG1); let timg1 = TimerGroup::new($peripherals.TIMG1);

View File

@ -94,22 +94,23 @@ mod tests {
test_async_delay_ns(OneShotTimer::new(alarms.alarm0).into_async(), 10_000).await; test_async_delay_ns(OneShotTimer::new(alarms.alarm0).into_async(), 10_000).await;
} }
#[cfg(timergroup_timg0)]
#[test] #[test]
async fn test_timg0_async_delay_ns(ctx: Context) { async fn test_timg0_async_delay_ns(ctx: Context) {
let timg0 = TimerGroup::new(ctx.peripherals.TIMG0); let timg0 = TimerGroup::new(ctx.peripherals.TIMG0);
test_async_delay_ns(OneShotTimer::new(timg0.timer0).into_async(), 10_000).await; test_async_delay_ns(OneShotTimer::new(timg0.timer0).into_async(), 10_000).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_ns(OneShotTimer::new(timg0.timer1).into_async(), 10_000).await; test_async_delay_ns(OneShotTimer::new(timg0.timer1).into_async(), 10_000).await;
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
#[test] #[test]
async fn test_timg1_async_delay_ns(ctx: Context) { async fn test_timg1_async_delay_ns(ctx: Context) {
let timg1 = TimerGroup::new(ctx.peripherals.TIMG1); let timg1 = TimerGroup::new(ctx.peripherals.TIMG1);
test_async_delay_ns(OneShotTimer::new(timg1.timer0).into_async(), 10_000).await; test_async_delay_ns(OneShotTimer::new(timg1.timer0).into_async(), 10_000).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_ns(OneShotTimer::new(timg1.timer1).into_async(), 10_000).await; test_async_delay_ns(OneShotTimer::new(timg1.timer1).into_async(), 10_000).await;
} }
@ -121,22 +122,23 @@ mod tests {
test_async_delay_us(OneShotTimer::new(alarms.alarm0).into_async(), 10).await; test_async_delay_us(OneShotTimer::new(alarms.alarm0).into_async(), 10).await;
} }
#[cfg(timergroup_timg0)]
#[test] #[test]
async fn test_timg0_async_delay_us(ctx: Context) { async fn test_timg0_async_delay_us(ctx: Context) {
let timg0 = TimerGroup::new(ctx.peripherals.TIMG0); let timg0 = TimerGroup::new(ctx.peripherals.TIMG0);
test_async_delay_us(OneShotTimer::new(timg0.timer0).into_async(), 10).await; test_async_delay_us(OneShotTimer::new(timg0.timer0).into_async(), 10).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_us(OneShotTimer::new(timg0.timer1).into_async(), 10).await; test_async_delay_us(OneShotTimer::new(timg0.timer1).into_async(), 10).await;
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
#[test] #[test]
async fn test_timg1_async_delay_us(ctx: Context) { async fn test_timg1_async_delay_us(ctx: Context) {
let timg1 = TimerGroup::new(ctx.peripherals.TIMG1); let timg1 = TimerGroup::new(ctx.peripherals.TIMG1);
test_async_delay_us(OneShotTimer::new(timg1.timer0).into_async(), 10).await; test_async_delay_us(OneShotTimer::new(timg1.timer0).into_async(), 10).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_us(OneShotTimer::new(timg1.timer1).into_async(), 10).await; test_async_delay_us(OneShotTimer::new(timg1.timer1).into_async(), 10).await;
} }
@ -148,22 +150,23 @@ mod tests {
test_async_delay_ms(OneShotTimer::new(alarms.alarm0).into_async(), 1).await; test_async_delay_ms(OneShotTimer::new(alarms.alarm0).into_async(), 1).await;
} }
#[cfg(timergroup_timg0)]
#[test] #[test]
async fn test_timg0_async_delay_ms(ctx: Context) { async fn test_timg0_async_delay_ms(ctx: Context) {
let timg0 = TimerGroup::new(ctx.peripherals.TIMG0); let timg0 = TimerGroup::new(ctx.peripherals.TIMG0);
test_async_delay_ms(OneShotTimer::new(timg0.timer0).into_async(), 1).await; test_async_delay_ms(OneShotTimer::new(timg0.timer0).into_async(), 1).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_ms(OneShotTimer::new(timg0.timer1).into_async(), 1).await; test_async_delay_ms(OneShotTimer::new(timg0.timer1).into_async(), 1).await;
} }
#[cfg(timg1)] #[cfg(timergroup_timg1)]
#[test] #[test]
async fn test_timg1_async_delay_ms(ctx: Context) { async fn test_timg1_async_delay_ms(ctx: Context) {
let timg1 = TimerGroup::new(ctx.peripherals.TIMG1); let timg1 = TimerGroup::new(ctx.peripherals.TIMG1);
test_async_delay_ms(OneShotTimer::new(timg1.timer0).into_async(), 1).await; test_async_delay_ms(OneShotTimer::new(timg1.timer0).into_async(), 1).await;
#[cfg(timg_timer1)] #[cfg(timergroup_timg_has_timer1)]
test_async_delay_ms(OneShotTimer::new(timg1.timer1).into_async(), 1).await; test_async_delay_ms(OneShotTimer::new(timg1.timer1).into_async(), 1).await;
} }
} }

View File

@ -25,6 +25,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
#[cfg(timergroup_timg0)]
fn test_feeding_timg0_wdt() { fn test_feeding_timg0_wdt() {
let peripherals = esp_hal::init( let peripherals = esp_hal::init(
Config::default().with_watchdog( Config::default().with_watchdog(
@ -44,7 +45,7 @@ mod tests {
} }
#[test] #[test]
#[cfg(timg1)] #[cfg(timergroup_timg1)]
fn test_feeding_timg1_wdt() { fn test_feeding_timg1_wdt() {
let peripherals = esp_hal::init( let peripherals = esp_hal::init(
Config::default().with_watchdog( Config::default().with_watchdog(
@ -64,6 +65,7 @@ mod tests {
} }
#[test] #[test]
#[cfg(timergroup_timg0)]
fn test_feeding_timg0_wdt_max_clock() { fn test_feeding_timg0_wdt_max_clock() {
let peripherals = esp_hal::init( let peripherals = esp_hal::init(
Config::default() Config::default()