mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-16 21:05:35 +01:00
Port ESP32-C3 changes to ESP32-C6 branch
This commit is contained in:
parent
0efb77300e
commit
ef09e4b65f
13 changed files with 916 additions and 454 deletions
|
|
@ -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"]`
|
||||
|
|
|
|||
187
rtic-monotonics/src/esp32c6.rs
Normal file
187
rtic-monotonics/src/esp32c6.rs
Normal file
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue