diff options
| -rw-r--r-- | embassy-nrf/src/chips/nrf52805.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52810.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52811.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52820.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52832.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52833.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52840.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/wdt.rs | 153 | ||||
| -rw-r--r-- | examples/nrf/src/bin/wdt.rs | 46 |
10 files changed, 221 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 2034c67e0..c3fcdf21e 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -8,6 +8,9 @@ embassy_hal_common::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // WDT | ||
| 12 | WDT, | ||
| 13 | |||
| 11 | // RNG | 14 | // RNG |
| 12 | RNG, | 15 | RNG, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 27e1f3d20..997f130f9 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -8,6 +8,9 @@ embassy_hal_common::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // WDT | ||
| 12 | WDT, | ||
| 13 | |||
| 11 | // RNG | 14 | // RNG |
| 12 | RNG, | 15 | RNG, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 0d0c5ac75..7e53f734b 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -8,6 +8,9 @@ embassy_hal_common::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // WDT | ||
| 12 | WDT, | ||
| 13 | |||
| 11 | // RNG | 14 | // RNG |
| 12 | RNG, | 15 | RNG, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 9b5bdef16..a0315c406 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -8,6 +8,9 @@ embassy_hal_common::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // WDT | ||
| 12 | WDT, | ||
| 13 | |||
| 11 | // RNG | 14 | // RNG |
| 12 | RNG, | 15 | RNG, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index e79dba524..6e506d3fc 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -9,6 +9,9 @@ embassy_hal_common::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // WDT | ||
| 13 | WDT, | ||
| 14 | |||
| 12 | // RNG | 15 | // RNG |
| 13 | RNG, | 16 | RNG, |
| 14 | 17 | ||
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 7c62a7fdc..037efacbb 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -9,6 +9,9 @@ embassy_hal_common::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // WDT | ||
| 13 | WDT, | ||
| 14 | |||
| 12 | // RNG | 15 | // RNG |
| 13 | RNG, | 16 | RNG, |
| 14 | 17 | ||
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 00f6d49dd..6523858d8 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -9,6 +9,9 @@ embassy_hal_common::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // WDT | ||
| 13 | WDT, | ||
| 14 | |||
| 12 | // RNG | 15 | // RNG |
| 13 | RNG, | 16 | RNG, |
| 14 | 17 | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 4cce8028a..e846746b8 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -40,6 +40,7 @@ pub mod spim; | |||
| 40 | pub mod timer; | 40 | pub mod timer; |
| 41 | pub mod twim; | 41 | pub mod twim; |
| 42 | pub mod uarte; | 42 | pub mod uarte; |
| 43 | pub mod wdt; | ||
| 43 | 44 | ||
| 44 | // This mod MUST go last, so that it sees all the `impl_foo!` macros | 45 | // This mod MUST go last, so that it sees all the `impl_foo!` macros |
| 45 | #[cfg(feature = "nrf52805")] | 46 | #[cfg(feature = "nrf52805")] |
diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs new file mode 100644 index 000000000..0c6f2b3fb --- /dev/null +++ b/embassy-nrf/src/wdt.rs | |||
| @@ -0,0 +1,153 @@ | |||
| 1 | //! HAL interface to the WDT peripheral. | ||
| 2 | //! | ||
| 3 | //! This HAL implements a basic watchdog timer with 1..=8 handles. | ||
| 4 | //! Once the watchdog has been started, it cannot be stopped. | ||
| 5 | |||
| 6 | use crate::pac::WDT; | ||
| 7 | use crate::peripherals; | ||
| 8 | |||
| 9 | const MIN_TICKS: u32 = 15; | ||
| 10 | |||
| 11 | #[non_exhaustive] | ||
| 12 | pub struct Config { | ||
| 13 | /// Number of 32768 Hz ticks in each watchdog period. | ||
| 14 | /// | ||
| 15 | /// Note: there is a minimum of 15 ticks (458 microseconds). If a lower | ||
| 16 | /// number is provided, 15 ticks will be used as the configured value. | ||
| 17 | pub timeout_ticks: u32, | ||
| 18 | |||
| 19 | /// Should the watchdog continue to count during sleep modes? | ||
| 20 | pub run_during_sleep: bool, | ||
| 21 | |||
| 22 | /// Should the watchdog continue to count when the CPU is halted for debug? | ||
| 23 | pub run_during_debug_halt: bool, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Default for Config { | ||
| 27 | fn default() -> Self { | ||
| 28 | Self { | ||
| 29 | timeout_ticks: 32768, // 1 second | ||
| 30 | run_during_debug_halt: true, | ||
| 31 | run_during_sleep: true, | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | /// An interface to the Watchdog. | ||
| 37 | pub struct Watchdog { | ||
| 38 | _private: (), | ||
| 39 | } | ||
| 40 | |||
| 41 | impl Watchdog { | ||
| 42 | /// Try to create a new watchdog instance from the peripheral. | ||
| 43 | /// | ||
| 44 | /// This function will return an error if the watchdog is already active | ||
| 45 | /// with a `config` different to the requested one, or a different number of | ||
| 46 | /// enabled handles. | ||
| 47 | /// | ||
| 48 | /// `N` must be between 1 and 8, inclusive. | ||
| 49 | #[inline] | ||
| 50 | pub fn try_new<const N: usize>( | ||
| 51 | wdt: peripherals::WDT, | ||
| 52 | config: Config, | ||
| 53 | ) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> { | ||
| 54 | assert!(N >= 1 && N <= 8); | ||
| 55 | |||
| 56 | let r = unsafe { &*WDT::ptr() }; | ||
| 57 | |||
| 58 | let crv = config.timeout_ticks.max(MIN_TICKS); | ||
| 59 | let rren = (1u32 << N) - 1; | ||
| 60 | |||
| 61 | if r.runstatus.read().runstatus().bit() { | ||
| 62 | let curr_config = r.config.read(); | ||
| 63 | if curr_config.halt().bit() != config.run_during_debug_halt | ||
| 64 | || curr_config.sleep().bit() != config.run_during_sleep | ||
| 65 | || r.crv.read().bits() != crv | ||
| 66 | || r.rren.read().bits() != rren | ||
| 67 | { | ||
| 68 | return Err(wdt); | ||
| 69 | } | ||
| 70 | } else { | ||
| 71 | r.config.write(|w| { | ||
| 72 | w.sleep().bit(config.run_during_sleep); | ||
| 73 | w.halt().bit(config.run_during_debug_halt); | ||
| 74 | w | ||
| 75 | }); | ||
| 76 | r.intenset.write(|w| w.timeout().set_bit()); | ||
| 77 | |||
| 78 | r.crv.write(|w| unsafe { w.bits(crv) }); | ||
| 79 | r.rren.write(|w| unsafe { w.bits(rren) }); | ||
| 80 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 81 | } | ||
| 82 | |||
| 83 | let this = Self { _private: () }; | ||
| 84 | |||
| 85 | const DUMMY_HANDLE: WatchdogHandle = WatchdogHandle { index: 0 }; | ||
| 86 | let mut handles = [DUMMY_HANDLE; N]; | ||
| 87 | for i in 0..N { | ||
| 88 | handles[i] = WatchdogHandle { index: i as u8 }; | ||
| 89 | handles[i].pet(); | ||
| 90 | } | ||
| 91 | |||
| 92 | Ok((this, handles)) | ||
| 93 | } | ||
| 94 | |||
| 95 | /// Enable the watchdog interrupt. | ||
| 96 | /// | ||
| 97 | /// NOTE: Although the interrupt will occur, there is no way to prevent | ||
| 98 | /// the reset from occurring. From the time the event was fired, the | ||
| 99 | /// system will reset two LFCLK ticks later (61 microseconds) if the | ||
| 100 | /// interrupt has been enabled. | ||
| 101 | #[inline(always)] | ||
| 102 | pub fn enable_interrupt(&mut self) { | ||
| 103 | let r = unsafe { &*WDT::ptr() }; | ||
| 104 | r.intenset.write(|w| w.timeout().set_bit()); | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Disable the watchdog interrupt. | ||
| 108 | /// | ||
| 109 | /// NOTE: This has no effect on the reset caused by the Watchdog. | ||
| 110 | #[inline(always)] | ||
| 111 | pub fn disable_interrupt(&mut self) { | ||
| 112 | let r = unsafe { &*WDT::ptr() }; | ||
| 113 | r.intenclr.write(|w| w.timeout().set_bit()); | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Is the watchdog still awaiting pets from any handle? | ||
| 117 | /// | ||
| 118 | /// This reports whether sufficient pets have been received from all | ||
| 119 | /// handles to prevent a reset this time period. | ||
| 120 | #[inline(always)] | ||
| 121 | pub fn awaiting_pets(&self) -> bool { | ||
| 122 | let r = unsafe { &*WDT::ptr() }; | ||
| 123 | let enabled = r.rren.read().bits(); | ||
| 124 | let status = r.reqstatus.read().bits(); | ||
| 125 | (status & enabled) == 0 | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | pub struct WatchdogHandle { | ||
| 130 | index: u8, | ||
| 131 | } | ||
| 132 | |||
| 133 | impl WatchdogHandle { | ||
| 134 | /// Pet the watchdog. | ||
| 135 | /// | ||
| 136 | /// This function pets the given watchdog handle. | ||
| 137 | /// | ||
| 138 | /// NOTE: All active handles must be pet within the time interval to | ||
| 139 | /// prevent a reset from occurring. | ||
| 140 | #[inline] | ||
| 141 | pub fn pet(&mut self) { | ||
| 142 | let r = unsafe { &*WDT::ptr() }; | ||
| 143 | r.rr[self.index as usize].write(|w| w.rr().reload()); | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Has this handle been pet within the current window? | ||
| 147 | pub fn is_pet(&self) -> bool { | ||
| 148 | let r = unsafe { &*WDT::ptr() }; | ||
| 149 | let rd = r.reqstatus.read().bits(); | ||
| 150 | let idx = self.index as usize; | ||
| 151 | ((rd >> idx) & 0x1) == 0 | ||
| 152 | } | ||
| 153 | } | ||
diff --git a/examples/nrf/src/bin/wdt.rs b/examples/nrf/src/bin/wdt.rs new file mode 100644 index 000000000..53df7b0b7 --- /dev/null +++ b/examples/nrf/src/bin/wdt.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | #![allow(incomplete_features)] | ||
| 5 | |||
| 6 | #[path = "../example_common.rs"] | ||
| 7 | mod example_common; | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy::executor::Spawner; | ||
| 11 | use embassy_nrf::gpio::{Input, Pull}; | ||
| 12 | use embassy_nrf::gpiote::PortInput; | ||
| 13 | use embassy_nrf::wdt::{Config, Watchdog}; | ||
| 14 | use embassy_nrf::Peripherals; | ||
| 15 | use embassy_traits::gpio::{WaitForHigh, WaitForLow}; | ||
| 16 | |||
| 17 | #[embassy::main] | ||
| 18 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let mut config = Config::default(); | ||
| 22 | config.timeout_ticks = 32768 * 3; // 3 seconds | ||
| 23 | |||
| 24 | // This is needed for `probe-run` to be able to catch the panic message | ||
| 25 | // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. | ||
| 26 | config.run_during_debug_halt = false; | ||
| 27 | |||
| 28 | let (_wdt, [mut handle]) = match Watchdog::try_new::<1>(p.WDT, config) { | ||
| 29 | Ok(x) => x, | ||
| 30 | Err(_) => { | ||
| 31 | info!("Watchdog already active with wrong config, waiting for it to timeout..."); | ||
| 32 | loop {} | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | let mut button = PortInput::new(Input::new(p.P0_11, Pull::Up)); | ||
| 37 | |||
| 38 | info!("Watchdog started, press button 1 to pet it or I'll reset in 3 seconds!"); | ||
| 39 | |||
| 40 | loop { | ||
| 41 | button.wait_for_high().await; | ||
| 42 | button.wait_for_low().await; | ||
| 43 | info!("Button pressed, petting watchdog!"); | ||
| 44 | handle.pet(); | ||
| 45 | } | ||
| 46 | } | ||
