Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 (#576)

### Changed

Expand Down
4 changes: 4 additions & 0 deletions esp-hal-common/src/soc/esp32c6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions esp-hal-common/src/soc/esp32h2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
23 changes: 4 additions & 19 deletions esp-hal-common/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
91 changes: 91 additions & 0 deletions esp-hal-common/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use void::Void;

#[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},
Expand Down Expand Up @@ -44,13 +46,57 @@ where

pub trait TimerGroupInstance {
fn register_block() -> *const RegisterBlock;
fn configure_src_clk();
fn configure_wdt_src_clk();
}

impl TimerGroupInstance for TIMG0 {
#[inline(always)]
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(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) });
}
#[inline(always)]
#[cfg(any(esp32, esp32s2, esp32s3))]
fn configure_wdt_src_clk() {
// ESP32, ESP32-S2, and ESP32-S3 use only ABP, do nothing
}
}

#[cfg(timg1)]
Expand All @@ -59,6 +105,41 @@ 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(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) });
}
#[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
}
}

impl<'d, T> TimerGroup<'d, T>
Expand All @@ -72,11 +153,17 @@ where
) -> Self {
crate::into_ref!(timer_group);

T::configure_src_clk();

// ESP32-H2 is using PLL_48M_CLK source instead of APB_CLK
let timer0 = Timer::new(
Timer0 {
phantom: PhantomData::default(),
},
#[cfg(not(esp32h2))]
clocks.apb_clock,
#[cfg(esp32h2)]
clocks.pll_48m_clock,
peripheral_clock_control,
);

Expand Down Expand Up @@ -120,6 +207,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.

timg.enable_peripheral(peripheral_clock_control);
Self { timg, apb_clk_freq }
}
Expand Down Expand Up @@ -193,6 +281,7 @@ impl<TG> Timer0<TG>
where
TG: TimerGroupInstance,
{
#[cfg(feature = "embassy-time-timg0")]
pub(crate) unsafe fn steal() -> Self {
Self {
phantom: PhantomData,
Expand Down Expand Up @@ -353,6 +442,7 @@ impl<TG> Timer1<TG>
where
TG: TimerGroupInstance,
{
#[cfg(feature = "embassy-time-timg1")]
pub(crate) unsafe fn steal() -> Self {
Self {
phantom: PhantomData,
Expand Down Expand Up @@ -597,6 +687,7 @@ where
pub fn new(_peripheral_clock_control: &mut PeripheralClockControl) -> Self {
#[cfg(lp_wdt)]
_peripheral_clock_control.enable(crate::system::Peripheral::Wdt);
TG::configure_wdt_src_clk();
Self {
phantom: PhantomData::default(),
}
Expand Down
110 changes: 110 additions & 0 deletions esp32h2-hal/examples/timer_interrupt.rs
Original file line number Diff line number Diff line change
@@ -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<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None));
static TIMER1: Mutex<RefCell<Option<Timer<Timer0<TIMG1>>>>> = 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(500u64.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());
});
}