diff options
| -rw-r--r-- | embassy-nrf/src/rtc.rs | 67 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/rtc.rs | 3 |
2 files changed, 39 insertions, 31 deletions
diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index 1a90d1e24..652de511b 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs | |||
| @@ -2,10 +2,13 @@ | |||
| 2 | 2 | ||
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | use core::marker::PhantomData; | ||
| 6 | |||
| 7 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 5 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 6 | 9 | ||
| 7 | use crate::chip::interrupt::typelevel::Interrupt as _; | 10 | use crate::interrupt::typelevel::Interrupt as _; |
| 8 | use crate::pac; | 11 | use crate::{interrupt, pac}; |
| 9 | 12 | ||
| 10 | /// Prescaler has an invalid value which exceeds 12 bits. | 13 | /// Prescaler has an invalid value which exceeds 12 bits. |
| 11 | #[derive(Debug, PartialEq, Eq)] | 14 | #[derive(Debug, PartialEq, Eq)] |
| @@ -88,23 +91,31 @@ macro_rules! impl_rtc { | |||
| 88 | } | 91 | } |
| 89 | 92 | ||
| 90 | /// nRF RTC driver. | 93 | /// nRF RTC driver. |
| 91 | pub struct Rtc<'d, T: Instance>(Peri<'d, T>); | 94 | pub struct Rtc<'d> { |
| 95 | r: pac::rtc::Rtc, | ||
| 96 | irq: interrupt::Interrupt, | ||
| 97 | _phantom: PhantomData<&'d ()>, | ||
| 98 | } | ||
| 92 | 99 | ||
| 93 | impl<'d, T: Instance> Rtc<'d, T> { | 100 | impl<'d> Rtc<'d> { |
| 94 | /// Create a new `Rtc` driver. | 101 | /// Create a new `Rtc` driver. |
| 95 | /// | 102 | /// |
| 96 | /// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 ) | 103 | /// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 ) |
| 97 | pub fn new(rtc: Peri<'d, T>, prescaler: u32) -> Result<Self, PrescalerOutOfRangeError> { | 104 | pub fn new<T: Instance>(_rtc: Peri<'d, T>, prescaler: u32) -> Result<Self, PrescalerOutOfRangeError> { |
| 98 | if prescaler >= (1 << 12) { | 105 | if prescaler >= (1 << 12) { |
| 99 | return Err(PrescalerOutOfRangeError(prescaler)); | 106 | return Err(PrescalerOutOfRangeError(prescaler)); |
| 100 | } | 107 | } |
| 101 | 108 | ||
| 102 | T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16)); | 109 | T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16)); |
| 103 | Ok(Self(rtc)) | 110 | Ok(Self { |
| 111 | r: T::regs(), | ||
| 112 | irq: T::Interrupt::IRQ, | ||
| 113 | _phantom: PhantomData, | ||
| 114 | }) | ||
| 104 | } | 115 | } |
| 105 | 116 | ||
| 106 | /// Create a new `Rtc` driver, configuring it to run at the given frequency. | 117 | /// Create a new `Rtc` driver, configuring it to run at the given frequency. |
| 107 | pub fn new_for_freq(rtc: Peri<'d, T>, freq_hz: u32) -> Result<Self, PrescalerOutOfRangeError> { | 118 | pub fn new_for_freq<T: Instance>(rtc: Peri<'d, T>, freq_hz: u32) -> Result<Self, PrescalerOutOfRangeError> { |
| 108 | let prescaler = (32_768 / freq_hz).saturating_sub(1); | 119 | let prescaler = (32_768 / freq_hz).saturating_sub(1); |
| 109 | Self::new(rtc, prescaler) | 120 | Self::new(rtc, prescaler) |
| 110 | } | 121 | } |
| @@ -115,34 +126,38 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 115 | /// | 126 | /// |
| 116 | /// Potentially allows to create multiple instances of the driver for the same peripheral | 127 | /// Potentially allows to create multiple instances of the driver for the same peripheral |
| 117 | /// which can lead to undefined behavior. | 128 | /// which can lead to undefined behavior. |
| 118 | pub unsafe fn steal() -> Self { | 129 | pub unsafe fn steal<T: Instance>() -> Self { |
| 119 | Self(unsafe { T::steal() }) | 130 | Self { |
| 131 | r: T::regs(), | ||
| 132 | irq: T::Interrupt::IRQ, | ||
| 133 | _phantom: PhantomData, | ||
| 134 | } | ||
| 120 | } | 135 | } |
| 121 | 136 | ||
| 122 | /// Direct access to the RTC registers. | 137 | /// Direct access to the RTC registers. |
| 123 | #[cfg(feature = "unstable-pac")] | 138 | #[cfg(feature = "unstable-pac")] |
| 124 | #[inline] | 139 | #[inline] |
| 125 | pub fn regs(&mut self) -> pac::rtc::Rtc { | 140 | pub fn regs(&mut self) -> pac::rtc::Rtc { |
| 126 | T::regs() | 141 | self.r |
| 127 | } | 142 | } |
| 128 | 143 | ||
| 129 | /// Enable the RTC. | 144 | /// Enable the RTC. |
| 130 | #[inline] | 145 | #[inline] |
| 131 | pub fn enable(&mut self) { | 146 | pub fn enable(&mut self) { |
| 132 | T::regs().tasks_start().write_value(1); | 147 | self.r.tasks_start().write_value(1); |
| 133 | } | 148 | } |
| 134 | 149 | ||
| 135 | /// Disable the RTC. | 150 | /// Disable the RTC. |
| 136 | #[inline] | 151 | #[inline] |
| 137 | pub fn disable(&mut self) { | 152 | pub fn disable(&mut self) { |
| 138 | T::regs().tasks_stop().write_value(1); | 153 | self.r.tasks_stop().write_value(1); |
| 139 | } | 154 | } |
| 140 | 155 | ||
| 141 | /// Enables interrupts for the given [Interrupt] source. | 156 | /// Enables interrupts for the given [Interrupt] source. |
| 142 | /// | 157 | /// |
| 143 | /// Optionally also enables the interrupt in the NVIC. | 158 | /// Optionally also enables the interrupt in the NVIC. |
| 144 | pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) { | 159 | pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) { |
| 145 | let regs = T::regs(); | 160 | let regs = self.r; |
| 146 | match int { | 161 | match int { |
| 147 | Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)), | 162 | Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)), |
| 148 | Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)), | 163 | Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)), |
| @@ -152,7 +167,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 152 | Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)), | 167 | Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)), |
| 153 | } | 168 | } |
| 154 | if enable_in_nvic { | 169 | if enable_in_nvic { |
| 155 | unsafe { T::Interrupt::enable() }; | 170 | unsafe { self.irq.enable() }; |
| 156 | } | 171 | } |
| 157 | } | 172 | } |
| 158 | 173 | ||
| @@ -160,7 +175,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 160 | /// | 175 | /// |
| 161 | /// Optionally also disables the interrupt in the NVIC. | 176 | /// Optionally also disables the interrupt in the NVIC. |
| 162 | pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) { | 177 | pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) { |
| 163 | let regs = T::regs(); | 178 | let regs = self.r; |
| 164 | match int { | 179 | match int { |
| 165 | Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)), | 180 | Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)), |
| 166 | Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)), | 181 | Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)), |
| @@ -170,13 +185,13 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 170 | Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)), | 185 | Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)), |
| 171 | } | 186 | } |
| 172 | if disable_in_nvic { | 187 | if disable_in_nvic { |
| 173 | T::Interrupt::disable(); | 188 | self.irq.disable(); |
| 174 | } | 189 | } |
| 175 | } | 190 | } |
| 176 | 191 | ||
| 177 | /// Enable the generation of a hardware event from a given stimulus. | 192 | /// Enable the generation of a hardware event from a given stimulus. |
| 178 | pub fn enable_event(&mut self, evt: Interrupt) { | 193 | pub fn enable_event(&mut self, evt: Interrupt) { |
| 179 | let regs = T::regs(); | 194 | let regs = self.r; |
| 180 | match evt { | 195 | match evt { |
| 181 | Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)), | 196 | Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)), |
| 182 | Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)), | 197 | Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)), |
| @@ -189,7 +204,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 189 | 204 | ||
| 190 | /// Disable the generation of a hardware event from a given stimulus. | 205 | /// Disable the generation of a hardware event from a given stimulus. |
| 191 | pub fn disable_event(&mut self, evt: Interrupt) { | 206 | pub fn disable_event(&mut self, evt: Interrupt) { |
| 192 | let regs = T::regs(); | 207 | let regs = self.r; |
| 193 | match evt { | 208 | match evt { |
| 194 | Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)), | 209 | Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)), |
| 195 | Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)), | 210 | Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)), |
| @@ -202,7 +217,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 202 | 217 | ||
| 203 | /// Resets the given event. | 218 | /// Resets the given event. |
| 204 | pub fn reset_event(&mut self, evt: Interrupt) { | 219 | pub fn reset_event(&mut self, evt: Interrupt) { |
| 205 | let regs = T::regs(); | 220 | let regs = self.r; |
| 206 | match evt { | 221 | match evt { |
| 207 | Interrupt::Tick => regs.events_tick().write_value(0), | 222 | Interrupt::Tick => regs.events_tick().write_value(0), |
| 208 | Interrupt::Overflow => regs.events_ovrflw().write_value(0), | 223 | Interrupt::Overflow => regs.events_ovrflw().write_value(0), |
| @@ -215,7 +230,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 215 | 230 | ||
| 216 | /// Checks if the given event has been triggered. | 231 | /// Checks if the given event has been triggered. |
| 217 | pub fn is_event_triggered(&self, evt: Interrupt) -> bool { | 232 | pub fn is_event_triggered(&self, evt: Interrupt) -> bool { |
| 218 | let regs = T::regs(); | 233 | let regs = self.r; |
| 219 | let val = match evt { | 234 | let val = match evt { |
| 220 | Interrupt::Tick => regs.events_tick().read(), | 235 | Interrupt::Tick => regs.events_tick().read(), |
| 221 | Interrupt::Overflow => regs.events_ovrflw().read(), | 236 | Interrupt::Overflow => regs.events_ovrflw().read(), |
| @@ -241,25 +256,19 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 241 | CompareChannel::_3 => 3, | 256 | CompareChannel::_3 => 3, |
| 242 | }; | 257 | }; |
| 243 | 258 | ||
| 244 | T::regs().cc(reg).write(|w| w.set_compare(val)); | 259 | self.r.cc(reg).write(|w| w.set_compare(val)); |
| 245 | Ok(()) | 260 | Ok(()) |
| 246 | } | 261 | } |
| 247 | 262 | ||
| 248 | /// Clear the Real Time Counter. | 263 | /// Clear the Real Time Counter. |
| 249 | #[inline] | 264 | #[inline] |
| 250 | pub fn clear(&self) { | 265 | pub fn clear(&self) { |
| 251 | T::regs().tasks_clear().write_value(1); | 266 | self.r.tasks_clear().write_value(1); |
| 252 | } | 267 | } |
| 253 | 268 | ||
| 254 | /// Obtain the current value of the Real Time Counter, 24 bits of range. | 269 | /// Obtain the current value of the Real Time Counter, 24 bits of range. |
| 255 | #[inline] | 270 | #[inline] |
| 256 | pub fn read(&self) -> u32 { | 271 | pub fn read(&self) -> u32 { |
| 257 | T::regs().counter().read().counter() | 272 | self.r.counter().read().counter() |
| 258 | } | ||
| 259 | |||
| 260 | /// Relase the RTC, returning the underlying peripheral instance. | ||
| 261 | #[inline] | ||
| 262 | pub fn release(self) -> Peri<'d, T> { | ||
| 263 | self.0 | ||
| 264 | } | 273 | } |
| 265 | } | 274 | } |
diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs index a3df7da14..9d475df7f 100644 --- a/examples/nrf52840/src/bin/rtc.rs +++ b/examples/nrf52840/src/bin/rtc.rs | |||
| @@ -14,8 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 14 | 14 | ||
| 15 | // 64 bit counter which will never overflow. | 15 | // 64 bit counter which will never overflow. |
| 16 | static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); | 16 | static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); |
| 17 | static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static, embassy_nrf::peripherals::RTC0>>>> = | 17 | static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static>>>> = Mutex::new(RefCell::new(None)); |
| 18 | Mutex::new(RefCell::new(None)); | ||
| 19 | 18 | ||
| 20 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 20 | async fn main(_spawner: Spawner) { |
