From f2aef2022cbfec237d20a41b4071bca5c642955e Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Wed, 31 May 2023 11:42:21 +0200 Subject: [PATCH 1/5] H2: Use PLL_48M_CLK in Timg driver and add imer_interrupt example --- esp-hal-common/src/timer.rs | 18 ++++ esp32h2-hal/examples/timer_interrupt.rs | 110 ++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 esp32h2-hal/examples/timer_interrupt.rs diff --git a/esp-hal-common/src/timer.rs b/esp-hal-common/src/timer.rs index 9af8edb1d4a..1ae6cc67317 100644 --- a/esp-hal-common/src/timer.rs +++ b/esp-hal-common/src/timer.rs @@ -72,6 +72,11 @@ where ) -> Self { crate::into_ref!(timer_group); + use esp_println::println; + + println!("123"); + + #[cfg(not(esp32h2))] let timer0 = Timer::new( Timer0 { phantom: PhantomData::default(), @@ -80,6 +85,16 @@ where peripheral_clock_control, ); + // ESP32-H2 is using PLL_48M_CLK source instead of APB_CLK + #[cfg(esp32h2)] + let timer0 = Timer::new( + Timer0 { + phantom: PhantomData::default(), + }, + clocks.pll_48m_clock, + peripheral_clock_control, + ); + #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] let timer1 = Timer::new( Timer1 { @@ -120,6 +135,9 @@ where ) -> Self { // TODO: this currently assumes APB_CLK is being used, as we don't yet have a // way to select the XTAL_CLK. + use esp_println::println; + + println!("LOLP {}", apb_clk_freq.to_Hz()); timg.enable_peripheral(peripheral_clock_control); Self { timg, apb_clk_freq } } diff --git a/esp32h2-hal/examples/timer_interrupt.rs b/esp32h2-hal/examples/timer_interrupt.rs new file mode 100644 index 00000000000..aa2c061202e --- /dev/null +++ b/esp32h2-hal/examples/timer_interrupt.rs @@ -0,0 +1,110 @@ +//! This shows how to use the TIMG peripheral interrupts. +//! There is TIMG0 and TIMG1 each of them containing a general purpose timer and +//! a watchdog timer. + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32h2_hal::{ + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals, TIMG0, TIMG1}, + prelude::*, + riscv, + timer::{Timer, Timer0, TimerGroup}, + Rtc, +}; +use esp_backtrace as _; + +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER1: Mutex>>>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT, + // and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut timer0 = timer_group0.timer0; + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut timer1 = timer_group1.timer0; + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + interrupt::enable( + peripherals::Interrupt::TG0_T0_LEVEL, + interrupt::Priority::Priority2, + ) + .unwrap(); + + timer0.start(500u64.millis()); + + timer0.listen(); + + interrupt::enable( + peripherals::Interrupt::TG1_T0_LEVEL, + interrupt::Priority::Priority2, + ) + .unwrap(); + + timer1.start(1u64.secs()); + timer1.listen(); + + critical_section::with(|cs| { + TIMER0.borrow_ref_mut(cs).replace(timer0); + TIMER1.borrow_ref_mut(cs).replace(timer1); + }); + + unsafe { + riscv::interrupt::enable(); + } + + loop {} +} + +#[interrupt] +fn TG0_T0_LEVEL() { + critical_section::with(|cs| { + esp_println::println!("Interrupt 1"); + + let mut timer0 = TIMER0.borrow_ref_mut(cs); + let timer0 = timer0.as_mut().unwrap(); + + timer0.clear_interrupt(); + timer0.start(1000u64.millis()); + }); +} + +#[interrupt] +fn TG1_T0_LEVEL() { + critical_section::with(|cs| { + esp_println::println!("Interrupt 11"); + + let mut timer1 = TIMER1.borrow_ref_mut(cs); + let timer1 = timer1.as_mut().unwrap(); + + timer1.clear_interrupt(); + timer1.start(1u64.secs()); + }); +} From 7e7e8080a5b4e88e71425711faa9b19d3948d587 Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Mon, 5 Jun 2023 11:33:35 +0200 Subject: [PATCH 2/5] Clean timer driver, add helper configure_src_clk and configure_wdt_src_clk methods --- esp-hal-common/src/soc/esp32c6/mod.rs | 4 +++ esp-hal-common/src/soc/esp32h2/mod.rs | 4 +++ esp-hal-common/src/system.rs | 23 +++------------ esp-hal-common/src/timer.rs | 42 +++++++++++++++++++++++---- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/esp-hal-common/src/soc/esp32c6/mod.rs b/esp-hal-common/src/soc/esp32c6/mod.rs index 310b8d7141c..b94159f5c74 100644 --- a/esp-hal-common/src/soc/esp32c6/mod.rs +++ b/esp-hal-common/src/soc/esp32c6/mod.rs @@ -6,3 +6,7 @@ pub mod radio_clocks; pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; } + +pub(crate) mod constants { + pub const TIMG_DEFAULT_CLK_SRC: u8 = 1; +} diff --git a/esp-hal-common/src/soc/esp32h2/mod.rs b/esp-hal-common/src/soc/esp32h2/mod.rs index 310b8d7141c..4cfdb3d97d9 100644 --- a/esp-hal-common/src/soc/esp32h2/mod.rs +++ b/esp-hal-common/src/soc/esp32h2/mod.rs @@ -6,3 +6,7 @@ pub mod radio_clocks; pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; } + +pub(crate) mod constants { + pub const TIMG_DEFAULT_CLK_SRC: u8 = 2; +} diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index 62f7b164597..a929e37f4ee 100755 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -455,37 +455,22 @@ impl PeripheralClockControl { Peripheral::Timg0 => { system .timergroup0_timer_clk_conf - .write(|w| w.tg0_timer_clk_en().set_bit()); - let bits = if cfg!(esp32c6) { 1 } else { 2 }; - system - .timergroup0_timer_clk_conf - .write(|w| unsafe { w.tg0_timer_clk_sel().bits(bits) }); + .modify(|_, w| w.tg0_timer_clk_en().set_bit()); } #[cfg(timg1)] Peripheral::Timg1 => { system .timergroup1_timer_clk_conf - .write(|w| w.tg1_timer_clk_en().set_bit()); - let bits = if cfg!(esp32c6) { 1 } else { 2 }; - system - .timergroup1_timer_clk_conf - .write(|w| unsafe { w.tg1_timer_clk_sel().bits(bits) }); + .modify(|_, w| w.tg1_timer_clk_en().set_bit()); } #[cfg(lp_wdt)] Peripheral::Wdt => { system .timergroup0_wdt_clk_conf - .write(|w| w.tg0_wdt_clk_en().set_bit()); - system - .timergroup0_wdt_clk_conf - .write(|w| unsafe { w.tg0_wdt_clk_sel().bits(1) }); - - system - .timergroup1_timer_clk_conf - .write(|w| w.tg1_timer_clk_en().set_bit()); + .modify(|_, w| w.tg0_wdt_clk_en().set_bit()); system .timergroup1_timer_clk_conf - .write(|w| unsafe { w.tg1_timer_clk_sel().bits(1) }); + .modify(|_, w| w.tg1_timer_clk_en().set_bit()); } #[cfg(sha)] Peripheral::Sha => { diff --git a/esp-hal-common/src/timer.rs b/esp-hal-common/src/timer.rs index 1ae6cc67317..a59f34f0fdb 100644 --- a/esp-hal-common/src/timer.rs +++ b/esp-hal-common/src/timer.rs @@ -12,6 +12,9 @@ use embedded_hal::{ use fugit::{HertzU32, MicrosDurationU64}; use void::Void; +#[cfg(any(esp32c6, esp32h2))] +use crate::soc::constants::TIMG_DEFAULT_CLK_SRC; + #[cfg(timg1)] use crate::peripherals::TIMG1; use crate::{ @@ -44,6 +47,10 @@ where pub trait TimerGroupInstance { fn register_block() -> *const RegisterBlock; + #[cfg(any(esp32c6, esp32h2))] + fn configure_src_clk(); + #[cfg(any(esp32c6, esp32h2))] + fn configure_wdt_src_clk(); } impl TimerGroupInstance for TIMG0 { @@ -51,6 +58,19 @@ impl TimerGroupInstance for TIMG0 { fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG0::PTR } + #[inline(always)] + #[cfg(any(esp32c6, esp32h2))] + fn configure_src_clk() { + unsafe { &*crate::peripherals::PCR::PTR} + .timergroup0_timer_clk_conf + .modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + } + #[inline(always)] + #[cfg(any(esp32c6, esp32h2))] + fn configure_wdt_src_clk() { + unsafe { &*crate::peripherals::PCR::PTR}.timergroup0_wdt_clk_conf + .modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) }); + } } #[cfg(timg1)] @@ -59,6 +79,19 @@ impl TimerGroupInstance for TIMG1 { fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG1::PTR } + #[inline(always)] + #[cfg(any(esp32c6, esp32h2))] + fn configure_src_clk() { + unsafe { &*crate::peripherals::PCR::PTR} + .timergroup1_timer_clk_conf + .modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + } + #[inline(always)] + #[cfg(any(esp32c6, esp32h2))] + fn configure_wdt_src_clk() { + unsafe { &*crate::peripherals::PCR::PTR}.timergroup1_wdt_clk_conf + .modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(1) }); + } } impl<'d, T> TimerGroup<'d, T> @@ -72,9 +105,8 @@ where ) -> Self { crate::into_ref!(timer_group); - use esp_println::println; - - println!("123"); + #[cfg(any(esp32c6, esp32h2))] + T::configure_src_clk(); #[cfg(not(esp32h2))] let timer0 = Timer::new( @@ -135,9 +167,7 @@ where ) -> Self { // TODO: this currently assumes APB_CLK is being used, as we don't yet have a // way to select the XTAL_CLK. - use esp_println::println; - println!("LOLP {}", apb_clk_freq.to_Hz()); timg.enable_peripheral(peripheral_clock_control); Self { timg, apb_clk_freq } } @@ -615,6 +645,8 @@ where pub fn new(_peripheral_clock_control: &mut PeripheralClockControl) -> Self { #[cfg(lp_wdt)] _peripheral_clock_control.enable(crate::system::Peripheral::Wdt); + #[cfg(any(esp32c6, esp32h2))] + TG::configure_wdt_src_clk(); Self { phantom: PhantomData::default(), } From 70da89767746f35ab4f4ad5e0a7392746843a616 Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Mon, 5 Jun 2023 11:34:04 +0200 Subject: [PATCH 3/5] H2: Add imer_interrupt example --- esp32h2-hal/examples/timer_interrupt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp32h2-hal/examples/timer_interrupt.rs b/esp32h2-hal/examples/timer_interrupt.rs index aa2c061202e..0a2d4da7a35 100644 --- a/esp32h2-hal/examples/timer_interrupt.rs +++ b/esp32h2-hal/examples/timer_interrupt.rs @@ -92,7 +92,7 @@ fn TG0_T0_LEVEL() { let timer0 = timer0.as_mut().unwrap(); timer0.clear_interrupt(); - timer0.start(1000u64.millis()); + timer0.start(500u64.millis()); }); } From dd3c91e8c2a401d5de9353ccfb3b40035c65530c Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Mon, 5 Jun 2023 15:46:31 +0200 Subject: [PATCH 4/5] add helper methods for selecting default clk src --- CHANGELOG.md | 1 + esp-hal-common/src/timer.rs | 95 ++++++++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97342b40583..341e1b977e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `embassy_serial` and `embassy_wait` examples for ESP32-H2 (#569) - Fix Async GPIO not disabling interupts on chips with multiple banks (#572) - Add unified field-based efuse access +- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#575) ### Changed diff --git a/esp-hal-common/src/timer.rs b/esp-hal-common/src/timer.rs index a59f34f0fdb..dab28155459 100644 --- a/esp-hal-common/src/timer.rs +++ b/esp-hal-common/src/timer.rs @@ -12,11 +12,10 @@ use embedded_hal::{ use fugit::{HertzU32, MicrosDurationU64}; use void::Void; -#[cfg(any(esp32c6, esp32h2))] -use crate::soc::constants::TIMG_DEFAULT_CLK_SRC; - #[cfg(timg1)] use crate::peripherals::TIMG1; +#[cfg(any(esp32c6, esp32h2))] +use crate::soc::constants::TIMG_DEFAULT_CLK_SRC; use crate::{ clock::Clocks, peripheral::{Peripheral, PeripheralRef}, @@ -47,9 +46,7 @@ where pub trait TimerGroupInstance { fn register_block() -> *const RegisterBlock; - #[cfg(any(esp32c6, esp32h2))] fn configure_src_clk(); - #[cfg(any(esp32c6, esp32h2))] fn configure_wdt_src_clk(); } @@ -61,15 +58,44 @@ impl TimerGroupInstance for TIMG0 { #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn configure_src_clk() { - unsafe { &*crate::peripherals::PCR::PTR} - .timergroup0_timer_clk_conf - .modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + unsafe { &*crate::peripherals::PCR::PTR } + .timergroup0_timer_clk_conf + .modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + } + #[inline(always)] + #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))] + fn configure_src_clk() { + unsafe { + (*Self::register_block()) + .t0config + .modify(|_, w| w.use_xtal().clear_bit()) + }; + } + #[inline(always)] + #[cfg(esp32)] + fn configure_src_clk() { + // ESP32 has only APB clock source, do nothing + } + #[inline(always)] + #[cfg(any(esp32c2, esp32c3))] + fn configure_wdt_src_clk() { + unsafe { + (*Self::register_block()) + .wdtconfig0 + .modify(|_, w| w.wdt_use_xtal().clear_bit()) + }; } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn configure_wdt_src_clk() { - unsafe { &*crate::peripherals::PCR::PTR}.timergroup0_wdt_clk_conf - .modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) }); + unsafe { &*crate::peripherals::PCR::PTR } + .timergroup0_wdt_clk_conf + .modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) }); + } + #[inline(always)] + #[cfg(any(esp32, esp32s2, esp32s3))] + fn configure_wdt_src_clk() { + // ESP32, ESP32-S2, and ESP32-S3 use only ABP, do nothing } } @@ -82,15 +108,37 @@ impl TimerGroupInstance for TIMG1 { #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn configure_src_clk() { - unsafe { &*crate::peripherals::PCR::PTR} - .timergroup1_timer_clk_conf - .modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + unsafe { &*crate::peripherals::PCR::PTR } + .timergroup1_timer_clk_conf + .modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) }); + } + #[inline(always)] + #[cfg(any(esp32s2, esp32s3))] + fn configure_src_clk() { + unsafe { + (*Self::register_block()) + .t1config + .modify(|_, w| w.use_xtal().clear_bit()) + }; + } + #[inline(always)] + #[cfg(any(esp32, esp32c2, esp32c3))] + fn configure_src_clk() { + // ESP32 has only APB clock source, do nothing + // ESP32-C2 and ESP32-C3 don't have t1config only t0config, do nothing } #[inline(always)] #[cfg(any(esp32c6, esp32h2))] fn configure_wdt_src_clk() { - unsafe { &*crate::peripherals::PCR::PTR}.timergroup1_wdt_clk_conf - .modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(1) }); + unsafe { &*crate::peripherals::PCR::PTR } + .timergroup1_wdt_clk_conf + .modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(1) }); + } + #[inline(always)] + #[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))] + fn configure_wdt_src_clk() { + // ESP32-C2 and ESP32-C3 don't have t1config only t0config, do nothing + // ESP32, ESP32-S2, and ESP32-S3 use only ABP, do nothing } } @@ -105,24 +153,16 @@ where ) -> Self { crate::into_ref!(timer_group); - #[cfg(any(esp32c6, esp32h2))] T::configure_src_clk(); - #[cfg(not(esp32h2))] - let timer0 = Timer::new( - Timer0 { - phantom: PhantomData::default(), - }, - clocks.apb_clock, - peripheral_clock_control, - ); - // ESP32-H2 is using PLL_48M_CLK source instead of APB_CLK - #[cfg(esp32h2)] let timer0 = Timer::new( Timer0 { phantom: PhantomData::default(), }, + #[cfg(not(esp32h2))] + clocks.apb_clock, + #[cfg(esp32h2)] clocks.pll_48m_clock, peripheral_clock_control, ); @@ -241,6 +281,7 @@ impl Timer0 where TG: TimerGroupInstance, { + #[cfg(feature = "embassy-time-timg0")] pub(crate) unsafe fn steal() -> Self { Self { phantom: PhantomData, @@ -401,6 +442,7 @@ impl Timer1 where TG: TimerGroupInstance, { + #[cfg(feature = "embassy-time-timg1")] pub(crate) unsafe fn steal() -> Self { Self { phantom: PhantomData, @@ -645,7 +687,6 @@ where pub fn new(_peripheral_clock_control: &mut PeripheralClockControl) -> Self { #[cfg(lp_wdt)] _peripheral_clock_control.enable(crate::system::Peripheral::Wdt); - #[cfg(any(esp32c6, esp32h2))] TG::configure_wdt_src_clk(); Self { phantom: PhantomData::default(), From 83e880d82ce24b550a07729d31dffc33a9fa06d5 Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Tue, 6 Jun 2023 13:58:16 +0200 Subject: [PATCH 5/5] Change PR number in the Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 341e1b977e2..a06e88be42f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `embassy_serial` and `embassy_wait` examples for ESP32-H2 (#569) - Fix Async GPIO not disabling interupts on chips with multiple banks (#572) - Add unified field-based efuse access -- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#575) +- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#576) ### Changed