aboutsummaryrefslogtreecommitdiff
path: root/rtic-monotonics
diff options
context:
space:
mode:
Diffstat (limited to 'rtic-monotonics')
-rw-r--r--rtic-monotonics/Cargo.toml9
-rw-r--r--rtic-monotonics/src/esp32c6.rs187
-rw-r--r--rtic-monotonics/src/lib.rs3
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;