This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/vendor/embassy-nrf/src/wdt.rs
T
swaitsandClaude Opus 4.6 3102fc747a feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:54 -06:00

193 lines
5.8 KiB
Rust

//! Watchdog Timer (WDT) driver.
//!
//! This HAL implements a basic watchdog timer with 1..=8 handles.
//! Once the watchdog has been started, it cannot be stopped.
use crate::pac::WDT;
use crate::peripherals;
const MIN_TICKS: u32 = 15;
/// WDT configuration.
#[non_exhaustive]
pub struct Config {
/// Number of 32768 Hz ticks in each watchdog period.
///
/// Note: there is a minimum of 15 ticks (458 microseconds). If a lower
/// number is provided, 15 ticks will be used as the configured value.
pub timeout_ticks: u32,
/// Should the watchdog continue to count during sleep modes?
pub run_during_sleep: bool,
/// Should the watchdog continue to count when the CPU is halted for debug?
pub run_during_debug_halt: bool,
}
impl Config {
/// Create a config structure from the current configuration of the WDT
/// peripheral.
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
let r = unsafe { &*WDT::ptr() };
#[cfg(not(feature = "_nrf91"))]
let runstatus = r.runstatus.read().runstatus().bit();
#[cfg(feature = "_nrf91")]
let runstatus = r.runstatus.read().runstatuswdt().bit();
if runstatus {
let config = r.config.read();
Some(Self {
timeout_ticks: r.crv.read().bits(),
run_during_sleep: config.sleep().bit(),
run_during_debug_halt: config.halt().bit(),
})
} else {
None
}
}
}
impl Default for Config {
fn default() -> Self {
Self {
timeout_ticks: 32768, // 1 second
run_during_debug_halt: true,
run_during_sleep: true,
}
}
}
/// Watchdog driver.
pub struct Watchdog {
_private: (),
}
impl Watchdog {
/// Try to create a new watchdog driver.
///
/// This function will return an error if the watchdog is already active
/// with a `config` different to the requested one, or a different number of
/// enabled handles.
///
/// `N` must be between 1 and 8, inclusive.
#[inline]
pub fn try_new<const N: usize>(
wdt: peripherals::WDT,
config: Config,
) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> {
assert!(N >= 1 && N <= 8);
let r = unsafe { &*WDT::ptr() };
let crv = config.timeout_ticks.max(MIN_TICKS);
let rren = (1u32 << N) - 1;
#[cfg(not(feature = "_nrf91"))]
let runstatus = r.runstatus.read().runstatus().bit();
#[cfg(feature = "_nrf91")]
let runstatus = r.runstatus.read().runstatuswdt().bit();
if runstatus {
let curr_config = r.config.read();
if curr_config.halt().bit() != config.run_during_debug_halt
|| curr_config.sleep().bit() != config.run_during_sleep
|| r.crv.read().bits() != crv
|| r.rren.read().bits() != rren
{
return Err(wdt);
}
} else {
r.config.write(|w| {
w.sleep().bit(config.run_during_sleep);
w.halt().bit(config.run_during_debug_halt);
w
});
r.intenset.write(|w| w.timeout().set_bit());
r.crv.write(|w| unsafe { w.bits(crv) });
r.rren.write(|w| unsafe { w.bits(rren) });
r.tasks_start.write(|w| unsafe { w.bits(1) });
}
let this = Self { _private: () };
const DUMMY_HANDLE: WatchdogHandle = WatchdogHandle { index: 0 };
let mut handles = [DUMMY_HANDLE; N];
for i in 0..N {
handles[i] = WatchdogHandle { index: i as u8 };
handles[i].pet();
}
Ok((this, handles))
}
/// Enable the watchdog interrupt.
///
/// NOTE: Although the interrupt will occur, there is no way to prevent
/// the reset from occurring. From the time the event was fired, the
/// system will reset two LFCLK ticks later (61 microseconds) if the
/// interrupt has been enabled.
#[inline(always)]
pub fn enable_interrupt(&mut self) {
let r = unsafe { &*WDT::ptr() };
r.intenset.write(|w| w.timeout().set_bit());
}
/// Disable the watchdog interrupt.
///
/// NOTE: This has no effect on the reset caused by the Watchdog.
#[inline(always)]
pub fn disable_interrupt(&mut self) {
let r = unsafe { &*WDT::ptr() };
r.intenclr.write(|w| w.timeout().set_bit());
}
/// Is the watchdog still awaiting pets from any handle?
///
/// This reports whether sufficient pets have been received from all
/// handles to prevent a reset this time period.
#[inline(always)]
pub fn awaiting_pets(&self) -> bool {
let r = unsafe { &*WDT::ptr() };
let enabled = r.rren.read().bits();
let status = r.reqstatus.read().bits();
(status & enabled) == 0
}
}
/// Watchdog handle.
pub struct WatchdogHandle {
index: u8,
}
impl WatchdogHandle {
/// Pet the watchdog.
///
/// This function pets the given watchdog handle.
///
/// NOTE: All active handles must be pet within the time interval to
/// prevent a reset from occurring.
#[inline]
pub fn pet(&mut self) {
let r = unsafe { &*WDT::ptr() };
r.rr[self.index as usize].write(|w| w.rr().reload());
}
/// Has this handle been pet within the current window?
pub fn is_pet(&self) -> bool {
let r = unsafe { &*WDT::ptr() };
let rd = r.reqstatus.read().bits();
let idx = self.index as usize;
((rd >> idx) & 0x1) == 0
}
/// Steal a watchdog handle by index.
///
/// Safety: watchdog must be initialized, index must be between 0 and N-1 where
/// N is the handle count when initializing.
pub unsafe fn steal(index: u8) -> Self {
Self { index }
}
}