diff options
Diffstat (limited to 'rtic-monotonics')
| -rw-r--r-- | rtic-monotonics/Cargo.toml | 9 | ||||
| -rw-r--r-- | rtic-monotonics/src/esp32c6.rs | 187 | ||||
| -rw-r--r-- | rtic-monotonics/src/lib.rs | 3 |
3 files changed, 195 insertions, 4 deletions
diff --git a/rtic-monotonics/Cargo.toml b/rtic-monotonics/Cargo.toml index 89f57bb..366cd83 100644 --- a/rtic-monotonics/Cargo.toml +++ b/rtic-monotonics/Cargo.toml @@ -32,6 +32,7 @@ features = [ "stm32_tim5", "stm32_tim15", "esp32c3-systimer", + "esp32c6-systimer", ] rustdoc-flags = ["--cfg", "docsrs"] @@ -66,10 +67,9 @@ stm32-metapac = { version = "15.0.0", optional = true } # i.MX RT imxrt-ral = { version = "0.5.3", optional = true } - esp32c3 = {version = "0.28.0", optional = true } -riscv = {version = "0.12.1", optional = true } - +esp32c6 = {version = "0.18.0", optional = true } +riscv = {version = "0.13.0", optional = true } [build-dependencies] proc-macro2 = { version = "1.0.36", optional = true } @@ -110,8 +110,9 @@ imxrt = ["dep:cortex-m", "dep:imxrt-ral"] imxrt_gpt1 = ["imxrt"] imxrt_gpt2 = ["imxrt"] -# ESP32-C3 Timer +# ESP32 Timers esp32c3-systimer = ["dep:esp32c3", "dep:riscv"] +esp32c6-systimer = ["dep:esp32c6", "dep:riscv"] # STM32 timers # Use as `features = ["stm32g081kb", "stm32_tim15"]` diff --git a/rtic-monotonics/src/esp32c6.rs b/rtic-monotonics/src/esp32c6.rs new file mode 100644 index 0000000..60a8175 --- /dev/null +++ b/rtic-monotonics/src/esp32c6.rs @@ -0,0 +1,187 @@ +//! [`Monotonic`](rtic_time::Monotonic) implementation for ESP32-C6's SYSTIMER. +//! +//! Always runs at a fixed rate of 16 MHz. +//! +//! # Example +//! +//! ``` +//! use rtic_monotonics::esp32c6::prelude::*; +//! +//! esp32c6_systimer_monotonic!(Mono); +//! +//! fn init() { +//! # // This is normally provided by the selected PAC +//! # let timer = unsafe { esp32c6::Peripherals::steal() }.SYSTIMER; +//! # +//! // Start the monotonic +//! Mono::start(timer); +//! } +//! +//! async fn usage() { +//! loop { +//! // Use the monotonic +//! let timestamp = Mono::now(); +//! Mono::delay(100.millis()).await; +//! } +//! } +//! ``` + +/// Common definitions and traits for using the ESP32-C6 timer monotonic +pub mod prelude { + pub use crate::esp32c6_systimer_monotonic; + + pub use crate::Monotonic; + + pub use fugit::{self, ExtU64, ExtU64Ceil}; +} +use crate::TimerQueueBackend; +use esp32c6::{INTERRUPT_CORE0, INTPRI, SYSTIMER}; +use rtic_time::timer_queue::TimerQueue; + +/// Timer implementing [`TimerQueueBackend`]. +pub struct TimerBackend; + +impl TimerBackend { + /// Starts the monotonic timer. + /// + /// **Do not use this function directly.** + /// + /// Use the prelude macros instead. + pub fn _start(timer: SYSTIMER) { + let interrupt_number = 57 as isize; + let cpu_interrupt_number = 31 as isize; + + unsafe { + (INTERRUPT_CORE0::ptr() as *mut u32) + .offset(interrupt_number as isize) + .write_volatile(cpu_interrupt_number as u32); + + // Set the interrupt's priority: + (*INTPRI::ptr()) + .cpu_int_pri(cpu_interrupt_number as usize) + .write(|w| w.bits(15 as u32)); + + // Finally, enable the CPU interrupt: + (*INTPRI::ptr()) + .cpu_int_enable() + .modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits())); + } + + timer.conf().write(|w| w.timer_unit0_work_en().set_bit()); + timer + .conf() + .write(|w| w.timer_unit1_core0_stall_en().clear_bit()); + + TIMER_QUEUE.initialize(Self {}) + } +} + +static TIMER_QUEUE: TimerQueue<TimerBackend> = TimerQueue::new(); +use esp32c6; +impl TimerQueueBackend for TimerBackend { + type Ticks = u64; + fn now() -> Self::Ticks { + let peripherals = unsafe { esp32c6::Peripherals::steal() }; + peripherals + .SYSTIMER + .unit0_op() + .write(|w| w.update().set_bit()); + // this must be polled until value is valid + while peripherals.SYSTIMER.unit0_op().read().value_valid() == false {} + let instant: u64 = (peripherals.SYSTIMER.unit_value(0).lo().read().bits() as u64) + | ((peripherals.SYSTIMER.unit_value(0).hi().read().bits() as u64) << 32); + instant + } + + fn set_compare(instant: Self::Ticks) { + let systimer = unsafe { esp32c6::Peripherals::steal() }.SYSTIMER; + systimer + .target0_conf() + .write(|w| w.timer_unit_sel().set_bit()); + systimer + .target0_conf() + .write(|w| w.period_mode().clear_bit()); + systimer + .trgt(0) + .lo() + .write(|w| unsafe { w.bits((instant & 0xFFFFFFFF).try_into().unwrap()) }); + systimer + .trgt(0) + .hi() + .write(|w| unsafe { w.bits((instant >> 32).try_into().unwrap()) }); + systimer.comp0_load().write(|w| w.load().set_bit()); //sync period to comp register + systimer.conf().write(|w| w.target0_work_en().set_bit()); + systimer.int_ena().write(|w| w.target0().set_bit()); + } + + fn clear_compare_flag() { + unsafe { esp32c6::Peripherals::steal() } + .SYSTIMER + .int_clr() + .write(|w| w.target0().bit(true)); + } + + fn pend_interrupt() { + extern "C" { + fn interrupt31(); + } + //run the timer interrupt handler in a critical section to emulate a max priority + //interrupt. + //since there is no hardware support for pending a timer interrupt. + riscv::interrupt::disable(); + unsafe { interrupt31() }; + unsafe { riscv::interrupt::enable() }; + } + + fn timer_queue() -> &'static TimerQueue<Self> { + &TIMER_QUEUE + } +} + +/// Create an ESP32-C6 SysTimer based monotonic and register the necessary interrupt for it. +/// +/// See [`crate::esp32c6`] for more details. +/// +/// # Arguments +/// +/// * `name` - The name that the monotonic type will have. +#[macro_export] +macro_rules! esp32c6_systimer_monotonic { + ($name:ident) => { + /// A `Monotonic` based on the ESP32-C6 SysTimer peripheral. + pub struct $name; + + impl $name { + /// Starts the `Monotonic`. + /// + /// This method must be called only once. + pub fn start(timer: esp32c6::SYSTIMER) { + #[export_name = "interrupt31"] + #[allow(non_snake_case)] + unsafe extern "C" fn Systimer() { + use $crate::TimerQueueBackend; + $crate::esp32c6::TimerBackend::timer_queue().on_monotonic_interrupt(); + } + + $crate::esp32c6::TimerBackend::_start(timer); + } + } + + impl $crate::TimerQueueBasedMonotonic for $name { + type Backend = $crate::esp32c6::TimerBackend; + type Instant = $crate::fugit::Instant< + <Self::Backend as $crate::TimerQueueBackend>::Ticks, + 1, + 16_000_000, + >; + type Duration = $crate::fugit::Duration< + <Self::Backend as $crate::TimerQueueBackend>::Ticks, + 1, + 16_000_000, + >; + } + + $crate::rtic_time::impl_embedded_hal_delay_fugit!($name); + $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name); + }; +} diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 38f3b53..a02ddb5 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -54,6 +54,9 @@ pub use rtic_time::{ #[cfg(feature = "esp32c3-systimer")] pub mod esp32c3; +#[cfg(feature = "esp32c6-systimer")] +pub mod esp32c6; + #[cfg(feature = "cortex-m-systick")] pub mod systick; |
