aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs3
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs3
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/wdt.rs153
-rw-r--r--examples/nrf/src/bin/wdt.rs46
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;
40pub mod timer; 40pub mod timer;
41pub mod twim; 41pub mod twim;
42pub mod uarte; 42pub mod uarte;
43pub 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
6use crate::pac::WDT;
7use crate::peripherals;
8
9const MIN_TICKS: u32 = 15;
10
11#[non_exhaustive]
12pub 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
26impl 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.
37pub struct Watchdog {
38 _private: (),
39}
40
41impl 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
129pub struct WatchdogHandle {
130 index: u8,
131}
132
133impl 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"]
7mod example_common;
8
9use defmt::*;
10use embassy::executor::Spawner;
11use embassy_nrf::gpio::{Input, Pull};
12use embassy_nrf::gpiote::PortInput;
13use embassy_nrf::wdt::{Config, Watchdog};
14use embassy_nrf::Peripherals;
15use embassy_traits::gpio::{WaitForHigh, WaitForLow};
16
17#[embassy::main]
18async 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}