mirror of
https://github.com/rtic-rs/rtic.git
synced 2025-12-17 21:35:20 +01:00
* Update `rtic` package to use latest version of `esp32c3` dependency * Update `rtic-macros` ESP32-C3 bindings to reflect changes in HAL * Update the ESP32-C3 examples to use latest versions of all dependencies * Update changelogs * adjust expected qemu output, add compile-time checks * remove runtime checks, this is checked at compile time * fix expected qemu output * Clean up interrupt enable code a bit * Update `rtic-monotonic` to use the latest PAC for ESP32-C3 * Update `CHANGELOG.md` for `rtic-monotonic` * ci: esp32c3: Format runner.sh * ci: esp32c3: Default to silent boot export DEBUGGING while running to get verbose boot env DEBUGGING=1 cargo xtask ... * ci: esp32c3: Update expected example output --------- Co-authored-by: onsdagens <pawdzi-7@student.ltu.se> Co-authored-by: Henrik Tjäder <henrik@tjaders.com>
186 lines
5.9 KiB
Rust
186 lines
5.9 KiB
Rust
//! [`Monotonic`](rtic_time::Monotonic) implementation for ESP32-C3's SYSTIMER.
|
|
//!
|
|
//! Always runs at a fixed rate of 16 MHz.
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```
|
|
//! use rtic_monotonics::esp32c3::prelude::*;
|
|
//!
|
|
//! esp32c3_systimer_monotonic!(Mono);
|
|
//!
|
|
//! fn init() {
|
|
//! # // This is normally provided by the selected PAC
|
|
//! # let timer = unsafe { esp32c3::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-C3 timer monotonic
|
|
pub mod prelude {
|
|
pub use crate::esp32c3_systimer_monotonic;
|
|
|
|
pub use crate::Monotonic;
|
|
|
|
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
|
}
|
|
use crate::TimerQueueBackend;
|
|
use esp32c3::{INTERRUPT_CORE0, 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) {
|
|
const INTERRUPT_MAP_BASE: u32 = 0x600c2000;
|
|
let interrupt_number = 37 as isize;
|
|
let cpu_interrupt_number = 31 as isize;
|
|
unsafe {
|
|
let intr_map_base = INTERRUPT_MAP_BASE as *mut u32;
|
|
intr_map_base
|
|
.offset(interrupt_number)
|
|
.write_volatile(cpu_interrupt_number as u32);
|
|
//map peripheral interrupt to CPU interrupt
|
|
(*INTERRUPT_CORE0::ptr())
|
|
.cpu_int_enable()
|
|
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits())); //enable the CPU interupt.
|
|
let intr = INTERRUPT_CORE0::ptr();
|
|
let intr_prio_base = (*intr).cpu_int_pri(0).as_ptr();
|
|
|
|
intr_prio_base
|
|
.offset(cpu_interrupt_number)
|
|
.write_volatile(15 as u32);
|
|
}
|
|
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 esp32c3;
|
|
impl TimerQueueBackend for TimerBackend {
|
|
type Ticks = u64;
|
|
fn now() -> Self::Ticks {
|
|
let peripherals = unsafe { esp32c3::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 { esp32c3::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 { esp32c3::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-C3 SysTimer based monotonic and register the necessary interrupt for it.
|
|
///
|
|
/// See [`crate::esp32c3`] for more details.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `name` - The name that the monotonic type will have.
|
|
#[macro_export]
|
|
macro_rules! esp32c3_systimer_monotonic {
|
|
($name:ident) => {
|
|
/// A `Monotonic` based on the ESP32-C3 SysTimer peripheral.
|
|
pub struct $name;
|
|
|
|
impl $name {
|
|
/// Starts the `Monotonic`.
|
|
///
|
|
/// This method must be called only once.
|
|
pub fn start(timer: esp32c3::SYSTIMER) {
|
|
#[export_name = "interrupt31"]
|
|
#[allow(non_snake_case)]
|
|
unsafe extern "C" fn Systimer() {
|
|
use $crate::TimerQueueBackend;
|
|
$crate::esp32c3::TimerBackend::timer_queue().on_monotonic_interrupt();
|
|
}
|
|
|
|
$crate::esp32c3::TimerBackend::_start(timer);
|
|
}
|
|
}
|
|
|
|
impl $crate::TimerQueueBasedMonotonic for $name {
|
|
type Backend = $crate::esp32c3::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);
|
|
};
|
|
}
|