aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-11-26 14:35:18 +0100
committerUlf Lilleengen <[email protected]>2025-11-26 14:35:18 +0100
commit660fc4f7602c0be689e2c6cb4b20e55a26127636 (patch)
tree71a135d191e7a06076c8c9abaf914832f5bc39fc /embassy-nrf
parent9fa4f7309895bab81eb0e398d8f457ee528aad69 (diff)
feat: support nrf54 GRTC as time-driver
* Refactor GRTC peripheral splitting it into multiple channels * Reserve channel 1 for time-driver if enabled * Implement time-driver using GRTC (RTC peripheral is now removed). * Add timer example to nrf54l15
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/Cargo.toml18
-rw-r--r--embassy-nrf/src/chips/nrf54l15_app.rs28
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/time_driver.rs157
4 files changed, 147 insertions, 57 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 08f4b280b..0a71094eb 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -23,8 +23,8 @@ build = [
23 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-s", "time", "time-driver-rtc1"]}, 23 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-s", "time", "time-driver-rtc1"]},
24 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-ns", "time", "time-driver-rtc1"]}, 24 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-app-ns", "time", "time-driver-rtc1"]},
25 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-net", "time", "time-driver-rtc1"]}, 25 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf5340-net", "time", "time-driver-rtc1"]},
26 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-s", "time", "time-driver-rtc1"]}, 26 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-s", "time", "time-driver-grtc"]},
27 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-ns", "time", "time-driver-rtc1"]}, 27 {target = "thumbv8m.main-none-eabihf", features = ["gpiote", "nrf54l15-app-ns", "time", "time-driver-grtc"]},
28 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]}, 28 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time"]},
29 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]}, 29 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time-driver-rtc1"]},
30 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]}, 30 {target = "thumbv7em-none-eabi", features = ["gpiote", "nrf52840", "time", "time-driver-rtc1"]},
@@ -80,9 +80,10 @@ unstable-pac = []
80gpiote = [] 80gpiote = []
81 81
82## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz 82## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz
83## 83time-driver-rtc1 = ["_time-driver", "embassy-time-driver?/tick-hz-32_768"]
84## Note: For nRF54L, it's actually RTC30 84
85time-driver-rtc1 = ["_time-driver"] 85## Use GRTC (CC n=1, GRTC_1 irq) as the time driver for `embassy-time`, with a tick rate of 1 MHz
86time-driver-grtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"]
86 87
87## Enable embassy-net 802.15.4 driver 88## Enable embassy-net 802.15.4 driver
88net-driver = ["_net-driver"] 89net-driver = ["_net-driver"]
@@ -152,7 +153,7 @@ _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"]
152_nrf5340 = ["_gpio-p1", "_dppi"] 153_nrf5340 = ["_gpio-p1", "_dppi"]
153_nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] 154_nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"]
154_nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] 155_nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"]
155_nrf54l = ["_dppi"] 156_nrf54l = ["_dppi", "_grtc"]
156 157
157_nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"] 158_nrf9160 = ["nrf-pac/nrf9160", "_dppi", "_spi-v1"]
158_nrf9120 = ["nrf-pac/nrf9120", "_dppi", "_spi-v1"] 159_nrf9120 = ["nrf-pac/nrf9120", "_dppi", "_spi-v1"]
@@ -160,7 +161,7 @@ _nrf52 = ["_ppi"]
160_nrf51 = ["_ppi", "_spi-v1"] 161_nrf51 = ["_ppi", "_spi-v1"]
161_nrf91 = [] 162_nrf91 = []
162 163
163_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] 164_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
164 165
165_net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"] 166_net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"]
166 167
@@ -173,6 +174,7 @@ _dppi = []
173_gpio-p1 = [] 174_gpio-p1 = []
174_gpio-p2 = [] 175_gpio-p2 = []
175_spi-v1 = [] 176_spi-v1 = []
177_grtc = []
176 178
177# Errata workarounds 179# Errata workarounds
178_nrf52832_anomaly_109 = [] 180_nrf52832_anomaly_109 = []
@@ -200,7 +202,7 @@ embedded-io-async = { version = "0.6.1" }
200rand-core-06 = { package = "rand_core", version = "0.6" } 202rand-core-06 = { package = "rand_core", version = "0.6" }
201rand-core-09 = { package = "rand_core", version = "0.9" } 203rand-core-09 = { package = "rand_core", version = "0.9" }
202 204
203nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } 205nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "0068816c482932e3c59964817610ef41e79a6843" }
204 206
205defmt = { version = "1.0.1", optional = true } 207defmt = { version = "1.0.1", optional = true }
206bitflags = "2.4.2" 208bitflags = "2.4.2"
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs
index 8846717db..b6c9fd110 100644
--- a/embassy-nrf/src/chips/nrf54l15_app.rs
+++ b/embassy-nrf/src/chips/nrf54l15_app.rs
@@ -26,7 +26,6 @@ pub mod pac {
26 PPIB10_NS as PPIB10, 26 PPIB10_NS as PPIB10,
27 PPIB11_NS as PPIB11, 27 PPIB11_NS as PPIB11,
28 TIMER10_NS as TIMER10, 28 TIMER10_NS as TIMER10,
29 RTC10_NS as RTC10,
30 EGU10_NS as EGU10, 29 EGU10_NS as EGU10,
31 RADIO_NS as RADIO, 30 RADIO_NS as RADIO,
32 DPPIC20_NS as DPPIC20, 31 DPPIC20_NS as DPPIC20,
@@ -76,7 +75,6 @@ pub mod pac {
76 TWIM30_NS as TWIM30, 75 TWIM30_NS as TWIM30,
77 TWIS30_NS as TWIS30, 76 TWIS30_NS as TWIS30,
78 UARTE30_NS as UARTE30, 77 UARTE30_NS as UARTE30,
79 RTC30_NS as RTC30,
80 COMP_NS as COMP, 78 COMP_NS as COMP,
81 LPCOMP_NS as LPCOMP, 79 LPCOMP_NS as LPCOMP,
82 WDT31_NS as WDT31, 80 WDT31_NS as WDT31,
@@ -127,7 +125,6 @@ pub mod pac {
127 PPIB10_S as PPIB10, 125 PPIB10_S as PPIB10,
128 PPIB11_S as PPIB11, 126 PPIB11_S as PPIB11,
129 TIMER10_S as TIMER10, 127 TIMER10_S as TIMER10,
130 RTC10_S as RTC10,
131 EGU10_S as EGU10, 128 EGU10_S as EGU10,
132 RADIO_S as RADIO, 129 RADIO_S as RADIO,
133 SPU20_S as SPU20, 130 SPU20_S as SPU20,
@@ -180,7 +177,6 @@ pub mod pac {
180 TWIM30_S as TWIM30, 177 TWIM30_S as TWIM30,
181 TWIS30_S as TWIS30, 178 TWIS30_S as TWIS30,
182 UARTE30_S as UARTE30, 179 UARTE30_S as UARTE30,
183 RTC30_S as RTC30,
184 COMP_S as COMP, 180 COMP_S as COMP,
185 LPCOMP_S as LPCOMP, 181 LPCOMP_S as LPCOMP,
186 WDT30_S as WDT30, 182 WDT30_S as WDT30,
@@ -417,11 +413,19 @@ embassy_hal_internal::peripherals! {
417 P2_10, 413 P2_10,
418 414
419 // GRTC 415 // GRTC
420 GRTC, 416 GRTC_CH0,
421 417 #[cfg(not(feature = "time-driver-grtc"))]
422 // RTC 418 GRTC_CH1,
423 RTC10, 419 GRTC_CH2,
424 RTC30, 420 GRTC_CH3,
421 GRTC_CH4,
422 GRTC_CH5,
423 GRTC_CH6,
424 GRTC_CH7,
425 GRTC_CH8,
426 GRTC_CH9,
427 GRTC_CH10,
428 GRTC_CH11,
425 429
426 // PWM 430 // PWM
427 PWM20, 431 PWM20,
@@ -548,9 +552,6 @@ cfg_if::cfg_if! {
548 } 552 }
549} 553}
550 554
551impl_rtc!(RTC10, RTC10, RTC10);
552impl_rtc!(RTC30, RTC30, RTC30);
553
554#[cfg(feature = "_ns")] 555#[cfg(feature = "_ns")]
555impl_wdt!(WDT, WDT31, WDT31, 0); 556impl_wdt!(WDT, WDT31, WDT31, 0);
556#[cfg(feature = "_s")] 557#[cfg(feature = "_s")]
@@ -703,7 +704,6 @@ embassy_hal_internal::interrupt_mod!(
703 TIMER00, 704 TIMER00,
704 SPU10, 705 SPU10,
705 TIMER10, 706 TIMER10,
706 RTC10,
707 EGU10, 707 EGU10,
708 RADIO_0, 708 RADIO_0,
709 RADIO_1, 709 RADIO_1,
@@ -737,11 +737,9 @@ embassy_hal_internal::interrupt_mod!(
737 GRTC_3, 737 GRTC_3,
738 SPU30, 738 SPU30,
739 SERIAL30, 739 SERIAL30,
740 RTC30,
741 COMP_LPCOMP, 740 COMP_LPCOMP,
742 WDT30, 741 WDT30,
743 WDT31, 742 WDT31,
744 GPIOTE30_0, 743 GPIOTE30_0,
745 GPIOTE30_1, 744 GPIOTE30_1,
746 CLOCK_POWER,
747); 745);
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 28d2119ae..e8762b00d 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -153,6 +153,7 @@ pub mod reset;
153#[cfg(not(feature = "_nrf54l"))] 153#[cfg(not(feature = "_nrf54l"))]
154#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] 154#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
155pub mod rng; 155pub mod rng;
156#[cfg(not(feature = "_nrf54l"))]
156pub mod rtc; 157pub mod rtc;
157#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] 158#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
158pub mod saadc; 159pub mod saadc;
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index b723e2334..de1974fb7 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -1,4 +1,5 @@
1use core::cell::{Cell, RefCell}; 1use core::cell::{Cell, RefCell};
2#[cfg(not(feature = "_grtc"))]
2use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; 3use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
3 4
4use critical_section::CriticalSection; 5use critical_section::CriticalSection;
@@ -8,21 +9,27 @@ use embassy_time_driver::Driver;
8use embassy_time_queue_utils::Queue; 9use embassy_time_queue_utils::Queue;
9 10
10use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
12#[cfg(feature = "_grtc")]
13use crate::pac::grtc::vals::Busy;
11use crate::{interrupt, pac}; 14use crate::{interrupt, pac};
12 15
13#[cfg(feature = "_nrf54l")] 16#[cfg(feature = "_grtc")]
14fn rtc() -> pac::rtc::Rtc { 17fn rtc() -> pac::grtc::Grtc {
15 pac::RTC30 18 pac::GRTC
16} 19}
17#[cfg(not(feature = "_nrf54l"))] 20
21#[cfg(not(feature = "_grtc"))]
18fn rtc() -> pac::rtc::Rtc { 22fn rtc() -> pac::rtc::Rtc {
19 pac::RTC1 23 pac::RTC1
20} 24}
21 25
22/// Calculate the timestamp from the period count and the tick count. 26/// Calculate the timestamp from the period count and the tick count.
23/// 27///
24/// The RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes. This is 28/// For nRF54 devices and newer, the GRTC counter is 52 bits, so the time driver uses the
25/// too short. We must make it "never" overflow. 29/// syscounter and ignores the periods handling, since it overflows every 142 years.
30///
31/// For most other devices, the RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes.
32/// This is too short. We must make it "never" overflow.
26/// 33///
27/// The obvious way would be to count overflow periods. Every time the counter overflows, 34/// The obvious way would be to count overflow periods. Every time the counter overflows,
28/// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic 35/// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic
@@ -64,14 +71,39 @@ fn rtc() -> pac::rtc::Rtc {
64/// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865 71/// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865
65/// years. For comparison, flash memory like the one containing your firmware is usually rated to retain 72/// years. For comparison, flash memory like the one containing your firmware is usually rated to retain
66/// data for only 10-20 years. 34865 years is long enough! 73/// data for only 10-20 years. 34865 years is long enough!
74#[cfg(not(feature = "_grtc"))]
67fn calc_now(period: u32, counter: u32) -> u64 { 75fn calc_now(period: u32, counter: u32) -> u64 {
68 ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64) 76 ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64)
69} 77}
70 78
79#[cfg(feature = "_grtc")]
80fn syscounter() -> u64 {
81 let r = rtc();
82 r.syscounter(0).active().write(|w| w.set_active(true));
83 loop {
84 let countl: u32 = r.syscounter(0).syscounterl().read();
85 let counth = r.syscounter(0).syscounterh().read();
86
87 if counth.busy() == Busy::READY && !counth.overflow() {
88 let counth: u32 = counth.value();
89 let count = countl as u64 | ((counth as u64) << 32);
90 r.syscounter(0).active().write(|w| w.set_active(false));
91 return count;
92 }
93 // If overflow or not ready, loop will re-read both registers
94 }
95}
96
97#[cfg(not(feature = "_grtc"))]
71fn compare_n(n: usize) -> u32 { 98fn compare_n(n: usize) -> u32 {
72 1 << (n + 16) 99 1 << (n + 16)
73} 100}
74 101
102#[cfg(feature = "_grtc")]
103fn compare_n(n: usize) -> u32 {
104 1 << n // GRTC uses bits 0-11 for COMPARE[0-11]
105}
106
75#[cfg(test)] 107#[cfg(test)]
76mod test { 108mod test {
77 use super::*; 109 use super::*;
@@ -108,6 +140,7 @@ impl AlarmState {
108 140
109struct RtcDriver { 141struct RtcDriver {
110 /// Number of 2^23 periods elapsed since boot. 142 /// Number of 2^23 periods elapsed since boot.
143 #[cfg(not(feature = "_grtc"))]
111 period: AtomicU32, 144 period: AtomicU32,
112 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 145 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
113 alarms: Mutex<AlarmState>, 146 alarms: Mutex<AlarmState>,
@@ -115,6 +148,7 @@ struct RtcDriver {
115} 148}
116 149
117embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 150embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
151 #[cfg(not(feature = "_grtc"))]
118 period: AtomicU32::new(0), 152 period: AtomicU32::new(0),
119 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 153 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
120 queue: Mutex::new(RefCell::new(Queue::new())), 154 queue: Mutex::new(RefCell::new(Queue::new())),
@@ -123,25 +157,48 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
123impl RtcDriver { 157impl RtcDriver {
124 fn init(&'static self, irq_prio: crate::interrupt::Priority) { 158 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
125 let r = rtc(); 159 let r = rtc();
126 r.cc(3).write(|w| w.set_compare(0x800000)); 160 // Chips without GRTC needs to deal with overflow
161 #[cfg(not(feature = "_grtc"))]
162 {
163 r.cc(3).write(|w| w.set_compare(0x800000));
127 164
128 r.intenset().write(|w| { 165 r.intenset().write(|w| {
129 w.set_ovrflw(true); 166 w.set_ovrflw(true);
130 w.set_compare(3, true); 167 w.set_compare(3, true);
131 }); 168 });
169 }
132 170
171 #[cfg(feature = "_grtc")]
172 {
173 r.mode().write(|w| {
174 w.set_syscounteren(true);
175 });
176 }
133 r.tasks_clear().write_value(1); 177 r.tasks_clear().write_value(1);
134 r.tasks_start().write_value(1); 178 r.tasks_start().write_value(1);
135 179
136 // Wait for clear 180 // Wait for clear
181 #[cfg(not(feature = "_grtc"))]
137 while r.counter().read().0 != 0 {} 182 while r.counter().read().0 != 0 {}
138 183
139 #[cfg(feature = "_nrf54l")] 184 #[cfg(feature = "_grtc")]
185 {
186 // According to datasheet, we need to wait for STATUS.LFTIMER.READY
187 // before the timer is actually started
188 loop {
189 if r.status().lftimer().read().ready() {
190 break;
191 }
192 }
193 // Keep SYSCOUNTER[0] always active so we can read it anytime without BUSY waits
194 }
195
196 #[cfg(feature = "_grtc")]
140 { 197 {
141 interrupt::RTC30.set_priority(irq_prio); 198 interrupt::GRTC_1.set_priority(irq_prio);
142 unsafe { interrupt::RTC30.enable() }; 199 unsafe { interrupt::GRTC_1.enable() };
143 } 200 }
144 #[cfg(not(feature = "_nrf54l"))] 201 #[cfg(not(feature = "_grtc"))]
145 { 202 {
146 interrupt::RTC1.set_priority(irq_prio); 203 interrupt::RTC1.set_priority(irq_prio);
147 unsafe { interrupt::RTC1.enable() }; 204 unsafe { interrupt::RTC1.enable() };
@@ -150,11 +207,14 @@ impl RtcDriver {
150 207
151 fn on_interrupt(&self) { 208 fn on_interrupt(&self) {
152 let r = rtc(); 209 let r = rtc();
210
211 #[cfg(not(feature = "_grtc"))]
153 if r.events_ovrflw().read() == 1 { 212 if r.events_ovrflw().read() == 1 {
154 r.events_ovrflw().write_value(0); 213 r.events_ovrflw().write_value(0);
155 self.next_period(); 214 self.next_period();
156 } 215 }
157 216
217 #[cfg(not(feature = "_grtc"))]
158 if r.events_compare(3).read() == 1 { 218 if r.events_compare(3).read() == 1 {
159 r.events_compare(3).write_value(0); 219 r.events_compare(3).write_value(0);
160 self.next_period(); 220 self.next_period();
@@ -169,6 +229,7 @@ impl RtcDriver {
169 } 229 }
170 } 230 }
171 231
232 #[cfg(not(feature = "_grtc"))]
172 fn next_period(&self) { 233 fn next_period(&self) {
173 critical_section::with(|cs| { 234 critical_section::with(|cs| {
174 let r = rtc(); 235 let r = rtc();
@@ -190,7 +251,10 @@ impl RtcDriver {
190 fn trigger_alarm(&self, cs: CriticalSection) { 251 fn trigger_alarm(&self, cs: CriticalSection) {
191 let n = 0; 252 let n = 0;
192 let r = rtc(); 253 let r = rtc();
254 #[cfg(not(feature = "_grtc"))]
193 r.intenclr().write(|w| w.0 = compare_n(n)); 255 r.intenclr().write(|w| w.0 = compare_n(n));
256 #[cfg(feature = "_grtc")]
257 r.intenclr(1).write(|w| w.0 = compare_n(n));
194 258
195 let alarm = &self.alarms.borrow(cs); 259 let alarm = &self.alarms.borrow(cs);
196 alarm.timestamp.set(u64::MAX); 260 alarm.timestamp.set(u64::MAX);
@@ -214,7 +278,10 @@ impl RtcDriver {
214 if timestamp <= t { 278 if timestamp <= t {
215 // If alarm timestamp has passed the alarm will not fire. 279 // If alarm timestamp has passed the alarm will not fire.
216 // Disarm the alarm and return `false` to indicate that. 280 // Disarm the alarm and return `false` to indicate that.
281 #[cfg(not(feature = "_grtc"))]
217 r.intenclr().write(|w| w.0 = compare_n(n)); 282 r.intenclr().write(|w| w.0 = compare_n(n));
283 #[cfg(feature = "_grtc")]
284 r.intenclr(1).write(|w| w.0 = compare_n(n));
218 285
219 alarm.timestamp.set(u64::MAX); 286 alarm.timestamp.set(u64::MAX);
220 287
@@ -226,7 +293,7 @@ impl RtcDriver {
226 // Write the CC value regardless of whether we're going to enable it now or not. 293 // Write the CC value regardless of whether we're going to enable it now or not.
227 // This way, when we enable it later, the right value is already set. 294 // This way, when we enable it later, the right value is already set.
228 295
229 // nrf52 docs say: 296 // nrf52 docs say :
230 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. 297 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
231 // To workaround this, we never write a timestamp smaller than N+3. 298 // To workaround this, we never write a timestamp smaller than N+3.
232 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. 299 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
@@ -238,22 +305,39 @@ impl RtcDriver {
238 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed 305 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
239 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, 306 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
240 // and we don't do that here. 307 // and we don't do that here.
241 let safe_timestamp = timestamp.max(t + 3); 308 #[cfg(not(feature = "_grtc"))]
242 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); 309 {
243 310 let safe_timestamp = timestamp.max(t + 3);
244 let diff = timestamp - t; 311 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
245 if diff < 0xc00000 { 312 let diff = timestamp - t;
246 r.intenset().write(|w| w.0 = compare_n(n)); 313 if diff < 0xc00000 {
247 314 r.intenset().write(|w| w.0 = compare_n(n));
248 // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, 315
249 // we need to retry setting the alarm. 316 // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise,
250 if self.now() + 2 <= timestamp { 317 // we need to retry setting the alarm.
318 if self.now() + 2 <= timestamp {
319 return true;
320 }
321 } else {
322 // If it's too far in the future, don't setup the compare channel yet.
323 // It will be setup later by `next_period`.
324 r.intenclr().write(|w| w.0 = compare_n(n));
251 return true; 325 return true;
252 } 326 }
253 } else { 327 }
254 // If it's too far in the future, don't setup the compare channel yet. 328
255 // It will be setup later by `next_period`. 329 // The nRF54 datasheet states that 'The EVENTS_COMPARE[n] event is generated immediately if the
256 r.intenclr().write(|w| w.0 = compare_n(n)); 330 // configured compare value at CC[n] is less than the current SYSCOUNTER value.'. This means we
331 // can write the expected timestamp and be sure the alarm is triggered.
332 #[cfg(feature = "_grtc")]
333 {
334 let ccl = timestamp as u32;
335 let cch = (timestamp >> 32) as u32 & 0xFFFFF; // 20 bits for CCH
336
337 r.cc(n).ccl().write_value(ccl);
338 r.cc(n).cch().write(|w| w.set_cch(cch));
339 r.intenset(1).write(|w| w.0 = compare_n(n));
340
257 return true; 341 return true;
258 } 342 }
259 } 343 }
@@ -261,6 +345,7 @@ impl RtcDriver {
261} 345}
262 346
263impl Driver for RtcDriver { 347impl Driver for RtcDriver {
348 #[cfg(not(feature = "_grtc"))]
264 fn now(&self) -> u64 { 349 fn now(&self) -> u64 {
265 // `period` MUST be read before `counter`, see comment at the top for details. 350 // `period` MUST be read before `counter`, see comment at the top for details.
266 let period = self.period.load(Ordering::Relaxed); 351 let period = self.period.load(Ordering::Relaxed);
@@ -269,10 +354,14 @@ impl Driver for RtcDriver {
269 calc_now(period, counter) 354 calc_now(period, counter)
270 } 355 }
271 356
357 #[cfg(feature = "_grtc")]
358 fn now(&self) -> u64 {
359 syscounter()
360 }
361
272 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { 362 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
273 critical_section::with(|cs| { 363 critical_section::with(|cs| {
274 let mut queue = self.queue.borrow(cs).borrow_mut(); 364 let mut queue = self.queue.borrow(cs).borrow_mut();
275
276 if queue.schedule_wake(at, waker) { 365 if queue.schedule_wake(at, waker) {
277 let mut next = queue.next_expiration(self.now()); 366 let mut next = queue.next_expiration(self.now());
278 while !self.set_alarm(cs, next) { 367 while !self.set_alarm(cs, next) {
@@ -283,14 +372,14 @@ impl Driver for RtcDriver {
283 } 372 }
284} 373}
285 374
286#[cfg(feature = "_nrf54l")] 375#[cfg(feature = "_grtc")]
287#[cfg(feature = "rt")] 376#[cfg(feature = "rt")]
288#[interrupt] 377#[interrupt]
289fn RTC30() { 378fn GRTC_1() {
290 DRIVER.on_interrupt() 379 DRIVER.on_interrupt()
291} 380}
292 381
293#[cfg(not(feature = "_nrf54l"))] 382#[cfg(not(feature = "_grtc"))]
294#[cfg(feature = "rt")] 383#[cfg(feature = "rt")]
295#[interrupt] 384#[interrupt]
296fn RTC1() { 385fn RTC1() {