aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-imxrt/Cargo.toml9
-rw-r--r--embassy-imxrt/src/lib.rs4
-rw-r--r--embassy-imxrt/src/time_driver.rs196
-rw-r--r--examples/mimxrt6/Cargo.toml4
4 files changed, 184 insertions, 29 deletions
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index d58de6353..f16002a8d 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -12,7 +12,7 @@ documentation = "https://docs.embassy.dev/embassy-imxrt"
12[package.metadata.embassy_docs] 12[package.metadata.embassy_docs]
13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" 13src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/"
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" 14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/"
15features = ["defmt", "unstable-pac", "time", "time-driver"] 15features = ["defmt", "unstable-pac", "time", "time-driver-os-timer"]
16flavors = [ 16flavors = [
17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } 17 { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" }
18] 18]
@@ -37,9 +37,12 @@ defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxr
37time = ["dep:embassy-time", "embassy-embedded-hal/time"] 37time = ["dep:embassy-time", "embassy-embedded-hal/time"]
38 38
39## Enable custom embassy time-driver implementation, using 32KHz RTC 39## Enable custom embassy time-driver implementation, using 32KHz RTC
40time-driver-rtc = ["_time-driver"] 40time-driver-rtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000"]
41 41
42_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] 42## Enable custom embassy time-driver implementation, using 1MHz OS Timer
43time-driver-os-timer = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"]
44
45_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
43 46
44## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) 47## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable)
45unstable-pac = [] 48unstable-pac = []
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index fdf07b433..ad9f81e88 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -132,12 +132,10 @@ pub fn init(config: config::Config) -> Peripherals {
132 error!("unable to initialize Clocks for reason: {:?}", e); 132 error!("unable to initialize Clocks for reason: {:?}", e);
133 // Panic here? 133 // Panic here?
134 } 134 }
135 gpio::init();
136 } 135 }
137
138 // init RTC time driver
139 #[cfg(feature = "_time-driver")] 136 #[cfg(feature = "_time-driver")]
140 time_driver::init(config.time_interrupt_priority); 137 time_driver::init(config.time_interrupt_priority);
138 gpio::init();
141 139
142 peripherals 140 peripherals
143} 141}
diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs
index 56a8f7397..c68679d3e 100644
--- a/embassy-imxrt/src/time_driver.rs
+++ b/embassy-imxrt/src/time_driver.rs
@@ -1,5 +1,6 @@
1//! RTC Time Driver. 1//! Time Driver.
2use core::cell::{Cell, RefCell}; 2use core::cell::{Cell, RefCell};
3#[cfg(feature = "time-driver-rtc")]
3use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
4 5
5use critical_section::CriticalSection; 6use critical_section::CriticalSection;
@@ -8,9 +9,26 @@ use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::Driver; 9use embassy_time_driver::Driver;
9use embassy_time_queue_utils::Queue; 10use embassy_time_queue_utils::Queue;
10 11
12#[cfg(feature = "time-driver-os-timer")]
13use crate::clocks::enable;
11use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
12use crate::{interrupt, pac}; 15use crate::{interrupt, pac};
13 16
17struct AlarmState {
18 timestamp: Cell<u64>,
19}
20
21unsafe impl Send for AlarmState {}
22
23impl AlarmState {
24 const fn new() -> Self {
25 Self {
26 timestamp: Cell::new(u64::MAX),
27 }
28 }
29}
30
31#[cfg(feature = "time-driver-rtc")]
14fn rtc() -> &'static pac::rtc::RegisterBlock { 32fn rtc() -> &'static pac::rtc::RegisterBlock {
15 unsafe { &*pac::Rtc::ptr() } 33 unsafe { &*pac::Rtc::ptr() }
16} 34}
@@ -25,24 +43,19 @@ fn rtc() -> &'static pac::rtc::RegisterBlock {
25/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, 43/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels,
26/// so using a 32 bit GPREG0-2 as counter, compare, and int_en 44/// so using a 32 bit GPREG0-2 as counter, compare, and int_en
27/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection 45/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection
46#[cfg(feature = "time-driver-rtc")]
28fn calc_now(period: u32, counter: u32) -> u64 { 47fn calc_now(period: u32, counter: u32) -> u64 {
29 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) 48 ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64)
30} 49}
31 50
32struct AlarmState { 51#[cfg(feature = "time-driver-rtc")]
33 timestamp: Cell<u64>, 52embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc {
34} 53 period: AtomicU32::new(0),
35 54 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
36unsafe impl Send for AlarmState {} 55 queue: Mutex::new(RefCell::new(Queue::new())),
37 56});
38impl AlarmState {
39 const fn new() -> Self {
40 Self {
41 timestamp: Cell::new(u64::MAX),
42 }
43 }
44}
45 57
58#[cfg(feature = "time-driver-rtc")]
46struct Rtc { 59struct Rtc {
47 /// Number of 2^31 periods elapsed since boot. 60 /// Number of 2^31 periods elapsed since boot.
48 period: AtomicU32, 61 period: AtomicU32,
@@ -51,12 +64,7 @@ struct Rtc {
51 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 64 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
52} 65}
53 66
54embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { 67#[cfg(feature = "time-driver-rtc")]
55 period: AtomicU32::new(0),
56 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
57 queue: Mutex::new(RefCell::new(Queue::new())),
58});
59
60impl Rtc { 68impl Rtc {
61 /// Access the GPREG0 register to use it as a 31-bit counter. 69 /// Access the GPREG0 register to use it as a 31-bit counter.
62 #[inline] 70 #[inline]
@@ -219,6 +227,7 @@ impl Rtc {
219 } 227 }
220} 228}
221 229
230#[cfg(feature = "time-driver-rtc")]
222impl Driver for Rtc { 231impl Driver for Rtc {
223 fn now(&self) -> u64 { 232 fn now(&self) -> u64 {
224 // `period` MUST be read before `counter`, see comment at the top for details. 233 // `period` MUST be read before `counter`, see comment at the top for details.
@@ -242,13 +251,158 @@ impl Driver for Rtc {
242 } 251 }
243} 252}
244 253
245#[cfg(feature = "rt")] 254#[cfg(all(feature = "rt", feature = "time-driver-rtc"))]
246#[allow(non_snake_case)] 255#[allow(non_snake_case)]
247#[interrupt] 256#[interrupt]
248fn RTC() { 257fn RTC() {
249 DRIVER.on_interrupt() 258 DRIVER.on_interrupt()
250} 259}
251 260
261#[cfg(feature = "time-driver-os-timer")]
262fn os() -> &'static pac::ostimer0::RegisterBlock {
263 unsafe { &*pac::Ostimer0::ptr() }
264}
265
266/// Convert gray to decimal
267///
268/// Os Event provides a 64-bit timestamp gray-encoded. All we have to
269/// do here is read both 32-bit halves of the register and convert
270/// from gray to regular binary.
271#[cfg(feature = "time-driver-os-timer")]
272fn gray_to_dec(gray: u64) -> u64 {
273 let mut dec = gray;
274
275 dec ^= dec >> 1;
276 dec ^= dec >> 2;
277 dec ^= dec >> 4;
278 dec ^= dec >> 8;
279 dec ^= dec >> 16;
280 dec ^= dec >> 32;
281
282 dec
283}
284
285/// Convert decimal to gray
286///
287/// Before writing match value to the target register, we must convert
288/// it back into gray code.
289#[cfg(feature = "time-driver-os-timer")]
290fn dec_to_gray(dec: u64) -> u64 {
291 let gray = dec;
292 gray ^ (gray >> 1)
293}
294
295#[cfg(feature = "time-driver-os-timer")]
296embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer {
297 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
298 queue: Mutex::new(RefCell::new(Queue::new())),
299});
300
301#[cfg(feature = "time-driver-os-timer")]
302struct OsTimer {
303 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
304 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
305 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
306}
307
308#[cfg(feature = "time-driver-os-timer")]
309impl OsTimer {
310 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
311 // init alarms
312 critical_section::with(|cs| {
313 let alarm = DRIVER.alarms.borrow(cs);
314 alarm.timestamp.set(u64::MAX);
315 });
316
317 // Enable clocks. Documentation advises AGAINST resetting this
318 // peripheral.
319 enable::<crate::peripherals::OS_EVENT>();
320
321 interrupt::OS_EVENT.disable();
322
323 // Make sure interrupt is masked
324 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
325
326 // Default to the end of time
327 os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) });
328 os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) });
329
330 interrupt::OS_EVENT.unpend();
331 interrupt::OS_EVENT.set_priority(irq_prio);
332 unsafe { interrupt::OS_EVENT.enable() };
333 }
334
335 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
336 let alarm = self.alarms.borrow(cs);
337 alarm.timestamp.set(timestamp);
338
339 let t = self.now();
340 if timestamp <= t {
341 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
342 alarm.timestamp.set(u64::MAX);
343 return false;
344 }
345
346 let gray_timestamp = dec_to_gray(timestamp);
347
348 os().match_l()
349 .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) });
350 os().match_h()
351 .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) });
352 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit());
353
354 true
355 }
356
357 #[cfg(feature = "rt")]
358 fn trigger_alarm(&self, cs: CriticalSection) {
359 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
360 while !self.set_alarm(cs, next) {
361 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
362 }
363 }
364
365 #[cfg(feature = "rt")]
366 fn on_interrupt(&self) {
367 critical_section::with(|cs| {
368 if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() {
369 os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit());
370 self.trigger_alarm(cs);
371 }
372 });
373 }
374}
375
376#[cfg(feature = "time-driver-os-timer")]
377impl Driver for OsTimer {
378 fn now(&self) -> u64 {
379 let mut t = os().evtimerh().read().bits() as u64;
380 t <<= 32;
381 t |= os().evtimerl().read().bits() as u64;
382 gray_to_dec(t)
383 }
384
385 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
386 critical_section::with(|cs| {
387 let mut queue = self.queue.borrow(cs).borrow_mut();
388
389 if queue.schedule_wake(at, waker) {
390 let mut next = queue.next_expiration(self.now());
391 while !self.set_alarm(cs, next) {
392 next = queue.next_expiration(self.now());
393 }
394 }
395 })
396 }
397}
398
399#[cfg(all(feature = "rt", feature = "time-driver-os-timer"))]
400#[allow(non_snake_case)]
401#[interrupt]
402fn OS_EVENT() {
403 DRIVER.on_interrupt()
404}
405
252pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 406pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
253 DRIVER.init(irq_prio) 407 DRIVER.init(irq_prio)
254} 408}
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
index 8fc510c47..b0c56f003 100644
--- a/examples/mimxrt6/Cargo.toml
+++ b/examples/mimxrt6/Cargo.toml
@@ -12,8 +12,8 @@ defmt-rtt = "1.0"
12 12
13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 13embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.1", path = "../../embassy-futures" }
15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-rtc"] } 15embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] }
16embassy-time = { version = "0.4", path = "../../embassy-time" } 16embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } 17embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
18embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 18embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19embedded-hal-async = "1.0.0" 19embedded-hal-async = "1.0.0"