blob: 924df2c2c4fc1adb48e89a87b8af5eb256aac24e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
//! [`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);
};
}
|