Skip to content

Commit 963915c

Browse files
Merge pull request #175 from nrf-rs/wdt
Watchdog
2 parents 4692919 + 887cd4e commit 963915c

File tree

6 files changed

+740
-0
lines changed

6 files changed

+740
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ members = [
1212
"examples/ccm-demo",
1313
"examples/ppi-demo",
1414
"examples/gpiote-demo",
15+
"examples/wdt-demo",
1516
]
1617

1718
[profile.dev]

examples/wdt-demo/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "wdt-demo"
3+
version = "0.1.0"
4+
authors = ["James Munns <[email protected]>"]
5+
edition = "2018"
6+
publish = false
7+
8+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9+
10+
[dependencies]
11+
cortex-m = "0.6.2"
12+
cortex-m-rtic = "0.5.3"
13+
rtt-target = {version = "0.2.0", features = ["cortex-m"] }
14+
nrf52840-hal = { version = "0.11", features = ["rt"], path = "../../nrf52840-hal" }
15+
16+
[dependencies.embedded-hal]
17+
version = "0.2.3"
18+
features = ["unproven"]

examples/wdt-demo/Embed.toml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[default.probe]
2+
# The index of the probe in the connected probe list.
3+
# probe_index = 0
4+
# The protocol to be used for communicating with the target.
5+
protocol = "Swd"
6+
# The speed in kHz of the data link to the target.
7+
# speed = 1337
8+
9+
[default.flashing]
10+
# Whether or not the target should be flashed.
11+
enabled = true
12+
# Whether or not the target should be halted after flashing.
13+
halt_afterwards = false
14+
# Whether or not bytes erased but not rewritten with data from the ELF
15+
# should be restored with their contents before erasing.
16+
restore_unwritten_bytes = false
17+
# The path where an SVG of the assembled flash layout should be written to.
18+
# flash_layout_output_path = "out.svg"
19+
20+
[default.general]
21+
# The chip name of the chip to be debugged.
22+
chip = "nRF52840"
23+
# A list of chip descriptions to be loaded during runtime.
24+
chip_descriptions = []
25+
# The default log level to be used.
26+
log_level = "Warn"
27+
28+
[default.rtt]
29+
# Whether or not an RTTUI should be opened after flashing.
30+
# This is exclusive and cannot be used with GDB at the moment.
31+
enabled = true
32+
# A list of channel associations to be displayed. If left empty, all channels are displayed.
33+
channels = [
34+
# { up = 0, down = 0, name = "name" }
35+
]
36+
# The duration in ms for which the logger should retry to attach to RTT.
37+
timeout = 3000
38+
# Whether timestamps in the RTTUI are enabled
39+
show_timestamps = true
40+
41+
[default.gdb]
42+
# Whether or not a GDB server should be opened after flashing.
43+
# This is exclusive and cannot be used with RTT at the moment.
44+
enabled = false
45+
# The connection string in host:port format wher the GDB server will open a socket.
46+
# gdb_connection_string

examples/wdt-demo/src/main.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
//! Watchdog example for nRF52840-DK
2+
//!
3+
//! The watchdog will be configured to time out after five seconds.
4+
//! There will be four handles, one tied to each button. To prevent a
5+
//! reset from occuring, the user must press all four buttons within
6+
//! a five second window. The LEDs represent the "is_pet" state of
7+
//! each watchdog handle.
8+
//!
9+
//! This is basically playing whack-a-mole (pet-a-dog?) with the buttons
10+
//! to prevent the watchdog from restarting the system. If you use the
11+
//! Reset button to reset the device before the watchdog kicks, you'll
12+
//! see the reset reason was not due to the watchdog.
13+
14+
#![no_std]
15+
#![no_main]
16+
17+
use embedded_hal::{
18+
digital::v2::{InputPin, OutputPin},
19+
timer::CountDown,
20+
};
21+
use {
22+
core::{
23+
panic::PanicInfo,
24+
sync::atomic::{compiler_fence, Ordering},
25+
},
26+
hal::pac::TIMER0,
27+
hal::{
28+
gpio::{Input, Level, Output, Pin, PullUp, PushPull},
29+
timer::Timer,
30+
wdt::{count, handles::HdlN, Parts, Watchdog, WatchdogHandle},
31+
},
32+
nrf52840_hal as hal,
33+
rtt_target::{rprintln, rtt_init_print},
34+
};
35+
36+
#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
37+
const APP: () = {
38+
struct Resources {
39+
btn1: Pin<Input<PullUp>>,
40+
btn2: Pin<Input<PullUp>>,
41+
btn3: Pin<Input<PullUp>>,
42+
btn4: Pin<Input<PullUp>>,
43+
led1: Pin<Output<PushPull>>,
44+
led2: Pin<Output<PushPull>>,
45+
led3: Pin<Output<PushPull>>,
46+
led4: Pin<Output<PushPull>>,
47+
hdl0: WatchdogHandle<HdlN>,
48+
hdl1: WatchdogHandle<HdlN>,
49+
hdl2: WatchdogHandle<HdlN>,
50+
hdl3: WatchdogHandle<HdlN>,
51+
timer: Timer<TIMER0>,
52+
}
53+
54+
#[init]
55+
fn init(mut ctx: init::Context) -> init::LateResources {
56+
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
57+
rtt_init_print!();
58+
let p0 = hal::gpio::p0::Parts::new(ctx.device.P0);
59+
60+
let btn1 = p0.p0_11.into_pullup_input().degrade();
61+
let btn2 = p0.p0_12.into_pullup_input().degrade();
62+
let btn3 = p0.p0_24.into_pullup_input().degrade();
63+
let btn4 = p0.p0_25.into_pullup_input().degrade();
64+
65+
let led1 = p0.p0_13.into_push_pull_output(Level::High).degrade();
66+
let led2 = p0.p0_14.into_push_pull_output(Level::High).degrade();
67+
let led3 = p0.p0_15.into_push_pull_output(Level::High).degrade();
68+
let led4 = p0.p0_16.into_push_pull_output(Level::High).degrade();
69+
70+
let timer = Timer::new(ctx.device.TIMER0);
71+
72+
// Create a new watchdog instance
73+
//
74+
// In case the watchdog is already running, just spin and let it expire, since
75+
// we can't configure it anyway. This usually happens when we first program
76+
// the device and the watchdog was previously active
77+
let (hdl0, hdl1, hdl2, hdl3) = match Watchdog::try_new(ctx.device.WDT) {
78+
Ok(mut watchdog) => {
79+
// Set the watchdog to timeout after 5 seconds (in 32.768kHz ticks)
80+
watchdog.set_lfosc_ticks(5 * 32768);
81+
82+
// Activate the watchdog with four handles
83+
let Parts {
84+
watchdog: _watchdog,
85+
handles,
86+
} = watchdog.activate::<count::Four>();
87+
88+
handles
89+
}
90+
Err(wdt) => match Watchdog::try_recover::<count::Four>(wdt) {
91+
Ok(Parts { mut handles, .. }) => {
92+
rprintln!("Oops, watchdog already active, but recovering!");
93+
94+
// Pet all the dogs quickly to reset to default timeout
95+
handles.0.pet();
96+
handles.1.pet();
97+
handles.2.pet();
98+
handles.3.pet();
99+
100+
handles
101+
}
102+
Err(_wdt) => {
103+
rprintln!("Oops, watchdog already active, resetting!");
104+
loop {
105+
continue;
106+
}
107+
}
108+
},
109+
};
110+
111+
// Enable the monotonic timer (CYCCNT)
112+
ctx.core.DCB.enable_trace();
113+
ctx.core.DWT.enable_cycle_counter();
114+
115+
rprintln!("Starting!");
116+
117+
if ctx.device.POWER.resetreas.read().dog().is_detected() {
118+
ctx.device.POWER.resetreas.modify(|_r, w| {
119+
// Clear the watchdog reset reason bit
120+
w.dog().set_bit()
121+
});
122+
rprintln!("Restarted by the dog!");
123+
} else {
124+
rprintln!("Not restarted by the dog!");
125+
}
126+
127+
init::LateResources {
128+
btn1,
129+
btn2,
130+
btn3,
131+
btn4,
132+
led1,
133+
led2,
134+
led3,
135+
led4,
136+
hdl0: hdl0.degrade(),
137+
hdl1: hdl1.degrade(),
138+
hdl2: hdl2.degrade(),
139+
hdl3: hdl3.degrade(),
140+
timer,
141+
}
142+
}
143+
144+
#[idle(resources = [btn1, btn2, btn3, btn4, led1, led2, led3, led4, hdl0, hdl1, hdl2, hdl3, timer])]
145+
fn idle(mut ctx: idle::Context) -> ! {
146+
let buttons = [
147+
&ctx.resources.btn1,
148+
&ctx.resources.btn2,
149+
&ctx.resources.btn3,
150+
&ctx.resources.btn4,
151+
];
152+
153+
let leds = [
154+
&mut ctx.resources.led1,
155+
&mut ctx.resources.led2,
156+
&mut ctx.resources.led3,
157+
&mut ctx.resources.led4,
158+
];
159+
160+
let handles = [
161+
&mut ctx.resources.hdl0,
162+
&mut ctx.resources.hdl1,
163+
&mut ctx.resources.hdl2,
164+
&mut ctx.resources.hdl3,
165+
];
166+
167+
let timer = &mut ctx.resources.timer;
168+
169+
let mut cumulative_ticks = 0;
170+
let mut any_pet = false;
171+
172+
timer.start(1_000_000u32 * 6);
173+
174+
loop {
175+
let mut petted = 0;
176+
177+
// Loop through all handles/leds/buttons
178+
for i in 0..4 {
179+
if !handles[i].is_pet() && buttons[i].is_low().unwrap() {
180+
rprintln!("Petting {}", i);
181+
any_pet = true;
182+
handles[i].pet();
183+
while buttons[i].is_low().unwrap() {}
184+
}
185+
186+
if handles[i].is_pet() {
187+
petted += 1;
188+
leds[i].set_low().ok();
189+
} else {
190+
leds[i].set_high().ok();
191+
}
192+
}
193+
194+
// We must have pet all handles, reset the timer
195+
if any_pet && petted == 0 {
196+
cumulative_ticks = 0;
197+
any_pet = false;
198+
timer.start(1_000_000u32 * 6);
199+
}
200+
201+
// Check whether to update the counter time
202+
let rd = timer.read();
203+
if (cumulative_ticks + 250_000) <= rd {
204+
cumulative_ticks = rd;
205+
rprintln!("Time left: {}ms", (5_000_000 - rd) / 1_000);
206+
}
207+
}
208+
}
209+
};
210+
211+
#[inline(never)]
212+
#[panic_handler]
213+
fn panic(info: &PanicInfo) -> ! {
214+
cortex_m::interrupt::disable();
215+
rprintln!("{}", info);
216+
loop {
217+
compiler_fence(Ordering::SeqCst);
218+
}
219+
}

nrf-hal-common/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub mod uart;
6060
pub mod uarte;
6161
#[cfg(not(feature = "9160"))]
6262
pub mod uicr;
63+
#[cfg(not(feature = "9160"))]
64+
pub mod wdt;
6365

6466
pub mod prelude {
6567
pub use crate::hal::digital::v2::*;

0 commit comments

Comments
 (0)