diff options
| author | Ulf Lilleengen <[email protected]> | 2025-11-26 14:35:18 +0100 |
|---|---|---|
| committer | Ulf Lilleengen <[email protected]> | 2025-11-26 14:35:18 +0100 |
| commit | 660fc4f7602c0be689e2c6cb4b20e55a26127636 (patch) | |
| tree | 71a135d191e7a06076c8c9abaf914832f5bc39fc /embassy-nrf | |
| parent | 9fa4f7309895bab81eb0e398d8f457ee528aad69 (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.toml | 18 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf54l15_app.rs | 28 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/time_driver.rs | 157 |
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 = [] | |||
| 80 | gpiote = [] | 80 | gpiote = [] |
| 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 | ## | 83 | time-driver-rtc1 = ["_time-driver", "embassy-time-driver?/tick-hz-32_768"] |
| 84 | ## Note: For nRF54L, it's actually RTC30 | 84 | |
| 85 | time-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 |
| 86 | time-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 |
| 88 | net-driver = ["_net-driver"] | 89 | net-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" } | |||
| 200 | rand-core-06 = { package = "rand_core", version = "0.6" } | 202 | rand-core-06 = { package = "rand_core", version = "0.6" } |
| 201 | rand-core-09 = { package = "rand_core", version = "0.9" } | 203 | rand-core-09 = { package = "rand_core", version = "0.9" } |
| 202 | 204 | ||
| 203 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "58198c23bce72edc10b4e1656d1b54441fc74e7c" } | 205 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "0068816c482932e3c59964817610ef41e79a6843" } |
| 204 | 206 | ||
| 205 | defmt = { version = "1.0.1", optional = true } | 207 | defmt = { version = "1.0.1", optional = true } |
| 206 | bitflags = "2.4.2" | 208 | bitflags = "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 | ||
| 551 | impl_rtc!(RTC10, RTC10, RTC10); | ||
| 552 | impl_rtc!(RTC30, RTC30, RTC30); | ||
| 553 | |||
| 554 | #[cfg(feature = "_ns")] | 555 | #[cfg(feature = "_ns")] |
| 555 | impl_wdt!(WDT, WDT31, WDT31, 0); | 556 | impl_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")))] |
| 155 | pub mod rng; | 155 | pub mod rng; |
| 156 | #[cfg(not(feature = "_nrf54l"))] | ||
| 156 | pub mod rtc; | 157 | pub mod rtc; |
| 157 | #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] | 158 | #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] |
| 158 | pub mod saadc; | 159 | pub 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 @@ | |||
| 1 | use core::cell::{Cell, RefCell}; | 1 | use core::cell::{Cell, RefCell}; |
| 2 | #[cfg(not(feature = "_grtc"))] | ||
| 2 | use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; | 3 | use core::sync::atomic::{AtomicU32, Ordering, compiler_fence}; |
| 3 | 4 | ||
| 4 | use critical_section::CriticalSection; | 5 | use critical_section::CriticalSection; |
| @@ -8,21 +9,27 @@ use embassy_time_driver::Driver; | |||
| 8 | use embassy_time_queue_utils::Queue; | 9 | use embassy_time_queue_utils::Queue; |
| 9 | 10 | ||
| 10 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 12 | #[cfg(feature = "_grtc")] | ||
| 13 | use crate::pac::grtc::vals::Busy; | ||
| 11 | use crate::{interrupt, pac}; | 14 | use crate::{interrupt, pac}; |
| 12 | 15 | ||
| 13 | #[cfg(feature = "_nrf54l")] | 16 | #[cfg(feature = "_grtc")] |
| 14 | fn rtc() -> pac::rtc::Rtc { | 17 | fn rtc() -> pac::grtc::Grtc { |
| 15 | pac::RTC30 | 18 | pac::GRTC |
| 16 | } | 19 | } |
| 17 | #[cfg(not(feature = "_nrf54l"))] | 20 | |
| 21 | #[cfg(not(feature = "_grtc"))] | ||
| 18 | fn rtc() -> pac::rtc::Rtc { | 22 | fn 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"))] | ||
| 67 | fn calc_now(period: u32, counter: u32) -> u64 { | 75 | fn 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")] | ||
| 80 | fn 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"))] | ||
| 71 | fn compare_n(n: usize) -> u32 { | 98 | fn compare_n(n: usize) -> u32 { |
| 72 | 1 << (n + 16) | 99 | 1 << (n + 16) |
| 73 | } | 100 | } |
| 74 | 101 | ||
| 102 | #[cfg(feature = "_grtc")] | ||
| 103 | fn 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)] |
| 76 | mod test { | 108 | mod test { |
| 77 | use super::*; | 109 | use super::*; |
| @@ -108,6 +140,7 @@ impl AlarmState { | |||
| 108 | 140 | ||
| 109 | struct RtcDriver { | 141 | struct 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 | ||
| 117 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 150 | embassy_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 { | |||
| 123 | impl RtcDriver { | 157 | impl 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 | ||
| 263 | impl Driver for RtcDriver { | 347 | impl 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] |
| 289 | fn RTC30() { | 378 | fn 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] |
| 296 | fn RTC1() { | 385 | fn RTC1() { |
