mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
Merge pull request #4686 from robamu/add-nrf-rtc-driver
add basic RTC driver for nRF
This commit is contained in:
commit
a25c5c4b2a
@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- changed: nrf54l: Disable glitch detection and enable DC/DC in init.
|
||||
- changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4
|
||||
- changed: add persist() method for gpio and ppi
|
||||
- added: basic RTC driver
|
||||
- changed: add persist() method for gpio, gpiote, timer and ppi
|
||||
- changed: impl Drop for Timer
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub const FLASH_SIZE: usize = 128 * 1024;
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -110,6 +111,10 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B';
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature="time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -156,6 +157,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
@ -234,12 +239,12 @@ embassy_hal_internal::interrupt_mod!(
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
RTC0,
|
||||
TEMP,
|
||||
RNG,
|
||||
ECB,
|
||||
AAR_CCM,
|
||||
WDT,
|
||||
RTC0,
|
||||
RTC1,
|
||||
QDEC,
|
||||
EGU0_SWI0,
|
||||
|
@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'E';
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature="time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -166,6 +167,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B';
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature="time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -168,6 +169,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
|
||||
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature="time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -164,6 +165,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
@ -16,6 +16,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'G';
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature="time-driver-rtc1"))]
|
||||
RTC1,
|
||||
RTC2,
|
||||
|
||||
@ -182,6 +183,11 @@ impl_twim!(TWISPI1, TWIM1, TWISPI1);
|
||||
impl_twis!(TWISPI0, TWIS0, TWISPI0);
|
||||
impl_twis!(TWISPI1, TWIS1, TWISPI1);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
impl_rtc!(RTC2, RTC2, RTC2);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
|
@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
|
||||
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
RTC2,
|
||||
|
||||
@ -223,6 +224,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
||||
impl_timer!(TIMER4, TIMER4, TIMER4, extended);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
impl_rtc!(RTC2, RTC2, RTC2);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
|
||||
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
RTC2,
|
||||
|
||||
@ -220,6 +221,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
||||
impl_timer!(TIMER4, TIMER4, TIMER4, extended);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
impl_rtc!(RTC2, RTC2, RTC2);
|
||||
|
||||
impl_qspi!(QSPI, QSPI, QSPI);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
@ -168,6 +168,7 @@ embassy_hal_internal::peripherals! {
|
||||
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -369,6 +370,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_qspi!(QSPI, QSPI, QSPI);
|
||||
|
||||
impl_pdm!(PDM0, PDM0, PDM0);
|
||||
|
@ -59,6 +59,7 @@ pub const FLASH_SIZE: usize = 256 * 1024;
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -218,6 +219,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
|
@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024;
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -276,6 +277,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024;
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
@ -276,6 +277,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rtc!(RTC0, RTC0, RTC0);
|
||||
#[cfg(not(feature = "time-driver-rtc1"))]
|
||||
impl_rtc!(RTC1, RTC1, RTC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -155,6 +155,8 @@ pub mod reset;
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
pub mod rtc;
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
#[cfg(not(feature = "_nrf54l"))] // TODO
|
||||
|
265
embassy-nrf/src/rtc.rs
Normal file
265
embassy-nrf/src/rtc.rs
Normal file
@ -0,0 +1,265 @@
|
||||
//! Low-level RTC driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use embassy_hal_internal::{Peri, PeripheralType};
|
||||
|
||||
use crate::chip::interrupt::typelevel::Interrupt as _;
|
||||
use crate::pac;
|
||||
|
||||
/// Prescaler has an invalid value which exceeds 12 bits.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct PrescalerOutOfRangeError(u32);
|
||||
|
||||
/// Compare value has an invalid value which exceeds 24 bits.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct CompareOutOfRangeError(u32);
|
||||
|
||||
/// Interrupts/Events that can be generated by the RTCn peripheral.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Interrupt {
|
||||
/// Tick interrupt.
|
||||
Tick,
|
||||
/// Overflow interrupt.
|
||||
Overflow,
|
||||
/// Compare 0 interrupt.
|
||||
Compare0,
|
||||
/// Compare 1 interrupt.
|
||||
Compare1,
|
||||
/// Compare 2 interrupt.
|
||||
Compare2,
|
||||
/// Compare 3 interrupt. Only implemented for RTC1 and RTC2.
|
||||
Compare3,
|
||||
}
|
||||
|
||||
/// Compare registers available on the RTCn.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum CompareChannel {
|
||||
/// Channel 0
|
||||
_0,
|
||||
/// Channel 1
|
||||
_1,
|
||||
/// Channel 2
|
||||
_2,
|
||||
/// Channel 3. Only implemented for RTC1 and RTC2.
|
||||
_3,
|
||||
}
|
||||
|
||||
pub(crate) trait SealedInstance {
|
||||
fn regs() -> pac::rtc::Rtc;
|
||||
}
|
||||
|
||||
/// Basic RTC instance.
|
||||
#[allow(private_bounds)]
|
||||
pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
|
||||
/// Unsafely create a peripheral instance.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Potentially allows to create multiple instances of the driver for the same peripheral
|
||||
/// which can lead to undefined behavior.
|
||||
unsafe fn steal() -> Peri<'static, Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_rtc {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::rtc::SealedInstance for peripherals::$type {
|
||||
#[inline]
|
||||
fn regs() -> pac::rtc::Rtc {
|
||||
unsafe { pac::rtc::Rtc::from_ptr(pac::$pac_type.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::rtc::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||
|
||||
unsafe fn steal() -> embassy_hal_internal::Peri<'static, Self> {
|
||||
unsafe { peripherals::$type::steal() }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// nRF RTC driver.
|
||||
pub struct Rtc<'d, T: Instance>(Peri<'d, T>);
|
||||
|
||||
impl<'d, T: Instance> Rtc<'d, T> {
|
||||
/// Create a new `Rtc` driver.
|
||||
///
|
||||
/// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 )
|
||||
pub fn new(rtc: Peri<'d, T>, prescaler: u32) -> Result<Self, PrescalerOutOfRangeError> {
|
||||
if prescaler >= (1 << 12) {
|
||||
return Err(PrescalerOutOfRangeError(prescaler));
|
||||
}
|
||||
|
||||
T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16));
|
||||
Ok(Self(rtc))
|
||||
}
|
||||
|
||||
/// Create a new `Rtc` driver, configuring it to run at the given frequency.
|
||||
pub fn new_for_freq(rtc: Peri<'d, T>, freq_hz: u32) -> Result<Self, PrescalerOutOfRangeError> {
|
||||
let prescaler = (32_768 / freq_hz).saturating_sub(1);
|
||||
Self::new(rtc, prescaler)
|
||||
}
|
||||
|
||||
/// Steal the RTC peripheral, without checking if it's already taken.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Potentially allows to create multiple instances of the driver for the same peripheral
|
||||
/// which can lead to undefined behavior.
|
||||
pub unsafe fn steal() -> Self {
|
||||
Self(unsafe { T::steal() })
|
||||
}
|
||||
|
||||
/// Direct access to the RTC registers.
|
||||
#[cfg(feature = "unstable-pac")]
|
||||
#[inline]
|
||||
pub fn regs(&mut self) -> pac::rtc::Rtc {
|
||||
T::regs()
|
||||
}
|
||||
|
||||
/// Enable the RTC.
|
||||
#[inline]
|
||||
pub fn enable(&mut self) {
|
||||
T::regs().tasks_start().write_value(1);
|
||||
}
|
||||
|
||||
/// Disable the RTC.
|
||||
#[inline]
|
||||
pub fn disable(&mut self) {
|
||||
T::regs().tasks_stop().write_value(1);
|
||||
}
|
||||
|
||||
/// Enables interrupts for the given [Interrupt] source.
|
||||
///
|
||||
/// Optionally also enables the interrupt in the NVIC.
|
||||
pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) {
|
||||
let regs = T::regs();
|
||||
match int {
|
||||
Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)),
|
||||
Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)),
|
||||
Interrupt::Compare0 => regs.intenset().write(|w| w.set_compare(0, true)),
|
||||
Interrupt::Compare1 => regs.intenset().write(|w| w.set_compare(1, true)),
|
||||
Interrupt::Compare2 => regs.intenset().write(|w| w.set_compare(2, true)),
|
||||
Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)),
|
||||
}
|
||||
if enable_in_nvic {
|
||||
unsafe { T::Interrupt::enable() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Disables interrupts for the given [Interrupt] source.
|
||||
///
|
||||
/// Optionally also disables the interrupt in the NVIC.
|
||||
pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) {
|
||||
let regs = T::regs();
|
||||
match int {
|
||||
Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)),
|
||||
Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)),
|
||||
Interrupt::Compare0 => regs.intenclr().write(|w| w.set_compare(0, true)),
|
||||
Interrupt::Compare1 => regs.intenclr().write(|w| w.set_compare(1, true)),
|
||||
Interrupt::Compare2 => regs.intenclr().write(|w| w.set_compare(2, true)),
|
||||
Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)),
|
||||
}
|
||||
if disable_in_nvic {
|
||||
T::Interrupt::disable();
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable the generation of a hardware event from a given stimulus.
|
||||
pub fn enable_event(&mut self, evt: Interrupt) {
|
||||
let regs = T::regs();
|
||||
match evt {
|
||||
Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)),
|
||||
Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)),
|
||||
Interrupt::Compare0 => regs.evtenset().write(|w| w.set_compare(0, true)),
|
||||
Interrupt::Compare1 => regs.evtenset().write(|w| w.set_compare(1, true)),
|
||||
Interrupt::Compare2 => regs.evtenset().write(|w| w.set_compare(2, true)),
|
||||
Interrupt::Compare3 => regs.evtenset().write(|w| w.set_compare(3, true)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Disable the generation of a hardware event from a given stimulus.
|
||||
pub fn disable_event(&mut self, evt: Interrupt) {
|
||||
let regs = T::regs();
|
||||
match evt {
|
||||
Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)),
|
||||
Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)),
|
||||
Interrupt::Compare0 => regs.evtenclr().write(|w| w.set_compare(0, true)),
|
||||
Interrupt::Compare1 => regs.evtenclr().write(|w| w.set_compare(1, true)),
|
||||
Interrupt::Compare2 => regs.evtenclr().write(|w| w.set_compare(2, true)),
|
||||
Interrupt::Compare3 => regs.evtenclr().write(|w| w.set_compare(3, true)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the given event.
|
||||
pub fn reset_event(&mut self, evt: Interrupt) {
|
||||
let regs = T::regs();
|
||||
match evt {
|
||||
Interrupt::Tick => regs.events_tick().write_value(0),
|
||||
Interrupt::Overflow => regs.events_ovrflw().write_value(0),
|
||||
Interrupt::Compare0 => regs.events_compare(0).write_value(0),
|
||||
Interrupt::Compare1 => regs.events_compare(1).write_value(0),
|
||||
Interrupt::Compare2 => regs.events_compare(2).write_value(0),
|
||||
Interrupt::Compare3 => regs.events_compare(3).write_value(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given event has been triggered.
|
||||
pub fn is_event_triggered(&self, evt: Interrupt) -> bool {
|
||||
let regs = T::regs();
|
||||
let val = match evt {
|
||||
Interrupt::Tick => regs.events_tick().read(),
|
||||
Interrupt::Overflow => regs.events_ovrflw().read(),
|
||||
Interrupt::Compare0 => regs.events_compare(0).read(),
|
||||
Interrupt::Compare1 => regs.events_compare(1).read(),
|
||||
Interrupt::Compare2 => regs.events_compare(2).read(),
|
||||
Interrupt::Compare3 => regs.events_compare(3).read(),
|
||||
};
|
||||
val == 1
|
||||
}
|
||||
|
||||
/// Set the compare value of a given register. The compare registers have a width
|
||||
/// of 24 bits.
|
||||
pub fn set_compare(&mut self, reg: CompareChannel, val: u32) -> Result<(), CompareOutOfRangeError> {
|
||||
if val >= (1 << 24) {
|
||||
return Err(CompareOutOfRangeError(val));
|
||||
}
|
||||
|
||||
let reg = match reg {
|
||||
CompareChannel::_0 => 0,
|
||||
CompareChannel::_1 => 1,
|
||||
CompareChannel::_2 => 2,
|
||||
CompareChannel::_3 => 3,
|
||||
};
|
||||
|
||||
T::regs().cc(reg).write(|w| w.set_compare(val));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clear the Real Time Counter.
|
||||
#[inline]
|
||||
pub fn clear(&self) {
|
||||
T::regs().tasks_clear().write_value(1);
|
||||
}
|
||||
|
||||
/// Obtain the current value of the Real Time Counter, 24 bits of range.
|
||||
#[inline]
|
||||
pub fn read(&self) -> u32 {
|
||||
T::regs().counter().read().counter()
|
||||
}
|
||||
|
||||
/// Relase the RTC, returning the underlying peripheral instance.
|
||||
#[inline]
|
||||
pub fn release(self) -> Peri<'d, T> {
|
||||
self.0
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ embedded-hal-async = { version = "1.0" }
|
||||
embedded-hal-bus = { version = "0.1", features = ["async"] }
|
||||
num-integer = { version = "0.1.45", default-features = false }
|
||||
microfft = "0.5.0"
|
||||
portable-atomic = "1"
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
||||
|
57
examples/nrf52840/src/bin/rtc.rs
Normal file
57
examples/nrf52840/src/bin/rtc.rs
Normal file
@ -0,0 +1,57 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::rtc::Rtc;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use portable_atomic::AtomicU64;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
// 64 bit counter which will never overflow.
|
||||
static TICK_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static, embassy_nrf::peripherals::RTC0>>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
defmt::println!("nRF52840 RTC example");
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut led = Output::new(p.P0_13, Level::High, OutputDrive::Standard);
|
||||
// Counter resolution is 125 ms.
|
||||
let mut rtc = Rtc::new(p.RTC0, (1 << 12) - 1).unwrap();
|
||||
rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true);
|
||||
rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick);
|
||||
rtc.enable();
|
||||
RTC.lock(|r| {
|
||||
let mut rtc_borrow = r.borrow_mut();
|
||||
*rtc_borrow = Some(rtc);
|
||||
});
|
||||
|
||||
let mut last_counter_val = 0;
|
||||
loop {
|
||||
let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed);
|
||||
if current != last_counter_val {
|
||||
led.toggle();
|
||||
last_counter_val = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn RTC0() {
|
||||
// For 64-bit, we do not need to worry about overflowing, at least not for realistic program
|
||||
// lifetimes.
|
||||
TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
|
||||
RTC.lock(|r| {
|
||||
let mut rtc_borrow = r.borrow_mut();
|
||||
rtc_borrow
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.reset_event(embassy_nrf::rtc::Interrupt::Tick);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user