Merge pull request #4119 from 0e4ef622/nrf53-wdt

nrf53: add WDT support
This commit is contained in:
Dario Nieuwenhuis 2025-04-21 19:08:02 +02:00 committed by GitHub
commit fb5ce05b26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 102 additions and 40 deletions

1
ci.sh
View File

@ -188,6 +188,7 @@ cargo batch \
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf5340-app-s \
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
--- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \

View File

@ -8,7 +8,6 @@ pub use embassy_boot::{
FirmwareUpdater, FirmwareUpdaterConfig, FirmwareUpdater, FirmwareUpdaterConfig,
}; };
use embassy_nrf::nvmc::PAGE_SIZE; use embassy_nrf::nvmc::PAGE_SIZE;
use embassy_nrf::peripherals::WDT;
use embassy_nrf::{wdt, Peri}; use embassy_nrf::{wdt, Peri};
use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
@ -113,7 +112,7 @@ pub struct WatchdogFlash<FLASH> {
impl<FLASH> WatchdogFlash<FLASH> { impl<FLASH> WatchdogFlash<FLASH> {
/// Start a new watchdog with a given flash and WDT peripheral and a timeout /// Start a new watchdog with a given flash and WDT peripheral and a timeout
pub fn start(flash: FLASH, wdt: Peri<'static, WDT>, config: wdt::Config) -> Self { pub fn start(flash: FLASH, wdt: Peri<'static, impl wdt::Instance>, config: wdt::Config) -> Self {
let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) {
Ok(x) => x, Ok(x) => x,
Err(_) => { Err(_) => {

View File

@ -109,7 +109,7 @@ nrf9161-ns = ["nrf9120-ns"]
# Features starting with `_` are for internal use only. They're not intended # Features starting with `_` are for internal use only. They're not intended
# to be enabled by other crates, and are not covered by semver guarantees. # to be enabled by other crates, and are not covered by semver guarantees.
_nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] _nrf5340-app = ["_nrf5340", "_multi_wdt", "nrf-pac/nrf5340-app"]
_nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"]
_nrf5340 = ["_gpio-p1", "_dppi"] _nrf5340 = ["_gpio-p1", "_dppi"]
_nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"]
@ -136,6 +136,9 @@ _gpio-p2 = []
# Errata workarounds # Errata workarounds
_nrf52832_anomaly_109 = [] _nrf52832_anomaly_109 = []
# watchdog timer
_multi_wdt = []
[dependencies] [dependencies]
embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true }
embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }

View File

@ -145,6 +145,8 @@ impl_pin!(P0_31, 0, 31);
impl_radio!(RADIO, RADIO, RADIO); impl_radio!(RADIO, RADIO, RADIO);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -221,6 +221,8 @@ impl_radio!(RADIO, RADIO, RADIO);
impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU0, EGU0, EGU0_SWI0);
impl_egu!(EGU1, EGU1, EGU1_SWI1); impl_egu!(EGU1, EGU1, EGU1_SWI1);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -247,6 +247,8 @@ impl_radio!(RADIO, RADIO, RADIO);
impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU0, EGU0, EGU0_SWI0);
impl_egu!(EGU1, EGU1, EGU1_SWI1); impl_egu!(EGU1, EGU1, EGU1_SWI1);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -249,6 +249,8 @@ impl_radio!(RADIO, RADIO, RADIO);
impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU0, EGU0, EGU0_SWI0);
impl_egu!(EGU1, EGU1, EGU1_SWI1); impl_egu!(EGU1, EGU1, EGU1_SWI1);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -244,6 +244,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3);
impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU4, EGU4, EGU4_SWI4);
impl_egu!(EGU5, EGU5, EGU5_SWI5); impl_egu!(EGU5, EGU5, EGU5_SWI5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -287,6 +287,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3);
impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU4, EGU4, EGU4_SWI4);
impl_egu!(EGU5, EGU5, EGU5_SWI5); impl_egu!(EGU5, EGU5, EGU5_SWI5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -329,6 +329,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3);
impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU4, EGU4, EGU4_SWI4);
impl_egu!(EGU5, EGU5, EGU5_SWI5); impl_egu!(EGU5, EGU5, EGU5_SWI5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -334,6 +334,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3);
impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU4, EGU4, EGU4_SWI4);
impl_egu!(EGU5, EGU5, EGU5_SWI5); impl_egu!(EGU5, EGU5, EGU5_SWI5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -171,7 +171,8 @@ embassy_hal_internal::peripherals! {
RTC1, RTC1,
// WDT // WDT
WDT, WDT0,
WDT1,
// NVMC // NVMC
NVMC, NVMC,
@ -473,6 +474,9 @@ impl_egu!(EGU3, EGU3, EGU3);
impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU4, EGU4, EGU4);
impl_egu!(EGU5, EGU5, EGU5); impl_egu!(EGU5, EGU5, EGU5);
impl_wdt!(WDT0, WDT0, WDT0, 0);
impl_wdt!(WDT1, WDT1, WDT1, 1);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
FPU, FPU,
CACHE, CACHE,

View File

@ -299,6 +299,8 @@ impl_radio!(RADIO, RADIO, RADIO);
impl_egu!(EGU0, EGU0, EGU0); impl_egu!(EGU0, EGU0, EGU0);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
CLOCK_POWER, CLOCK_POWER,
RADIO, RADIO,

View File

@ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3);
impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU4, EGU4, EGU4);
impl_egu!(EGU5, EGU5, EGU5); impl_egu!(EGU5, EGU5, EGU5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
SPU, SPU,
CLOCK_POWER, CLOCK_POWER,

View File

@ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3);
impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU4, EGU4, EGU4);
impl_egu!(EGU5, EGU5, EGU5); impl_egu!(EGU5, EGU5, EGU5);
impl_wdt!(WDT, WDT, WDT, 0);
embassy_hal_internal::interrupt_mod!( embassy_hal_internal::interrupt_mod!(
SPU, SPU,
CLOCK_POWER, CLOCK_POWER,

View File

@ -169,7 +169,6 @@ pub mod uarte;
))] ))]
pub mod usb; pub mod usb;
#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf54l"))] // TODO
#[cfg(not(feature = "_nrf5340"))]
pub mod wdt; pub mod wdt;
// This mod MUST go last, so that it sees all the `impl_foo!` macros // This mod MUST go last, so that it sees all the `impl_foo!` macros

View File

@ -3,11 +3,15 @@
//! This HAL implements a basic watchdog timer with 1..=8 handles. //! This HAL implements a basic watchdog timer with 1..=8 handles.
//! Once the watchdog has been started, it cannot be stopped. //! Once the watchdog has been started, it cannot be stopped.
use core::marker::PhantomData; #![macro_use]
use core::hint::unreachable_unchecked;
use embassy_hal_internal::PeripheralType;
use crate::pac::wdt::vals; use crate::pac::wdt::vals;
pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig};
use crate::{peripherals, Peri}; use crate::{interrupt, pac, peripherals, Peri};
const MIN_TICKS: u32 = 15; const MIN_TICKS: u32 = 15;
@ -30,12 +34,12 @@ pub struct Config {
impl Config { impl Config {
/// Create a config structure from the current configuration of the WDT /// Create a config structure from the current configuration of the WDT
/// peripheral. /// peripheral.
pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> { pub fn try_new<T: Instance>(_wdt: &Peri<'_, T>) -> Option<Self> {
let r = crate::pac::WDT; let r = T::REGS;
#[cfg(not(feature = "_nrf91"))] #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
let runstatus = r.runstatus().read().runstatus(); let runstatus = r.runstatus().read().runstatus();
#[cfg(feature = "_nrf91")] #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
let runstatus = r.runstatus().read().runstatuswdt(); let runstatus = r.runstatus().read().runstatuswdt();
if runstatus { if runstatus {
@ -62,11 +66,11 @@ impl Default for Config {
} }
/// Watchdog driver. /// Watchdog driver.
pub struct Watchdog { pub struct Watchdog<T: Instance> {
_wdt: Peri<'static, peripherals::WDT>, _wdt: Peri<'static, T>,
} }
impl Watchdog { impl<T: Instance> Watchdog<T> {
/// Try to create a new watchdog driver. /// Try to create a new watchdog driver.
/// ///
/// This function will return an error if the watchdog is already active /// This function will return an error if the watchdog is already active
@ -76,19 +80,19 @@ impl Watchdog {
/// `N` must be between 1 and 8, inclusive. /// `N` must be between 1 and 8, inclusive.
#[inline] #[inline]
pub fn try_new<const N: usize>( pub fn try_new<const N: usize>(
wdt: Peri<'static, peripherals::WDT>, wdt: Peri<'static, T>,
config: Config, config: Config,
) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, peripherals::WDT>> { ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> {
assert!(N >= 1 && N <= 8); assert!(N >= 1 && N <= 8);
let r = crate::pac::WDT; let r = T::REGS;
let crv = config.timeout_ticks.max(MIN_TICKS); let crv = config.timeout_ticks.max(MIN_TICKS);
let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1); let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1);
#[cfg(not(feature = "_nrf91"))] #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
let runstatus = r.runstatus().read().runstatus(); let runstatus = r.runstatus().read().runstatus();
#[cfg(feature = "_nrf91")] #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
let runstatus = r.runstatus().read().runstatuswdt(); let runstatus = r.runstatus().read().runstatuswdt();
if runstatus { if runstatus {
@ -114,17 +118,9 @@ impl Watchdog {
let this = Self { _wdt: wdt }; let this = Self { _wdt: wdt };
let mut handles = [const { let mut handles = [const { WatchdogHandle { index: 0 } }; N];
WatchdogHandle {
_wdt: PhantomData,
index: 0,
}
}; N];
for i in 0..N { for i in 0..N {
handles[i] = WatchdogHandle { handles[i] = unsafe { WatchdogHandle::steal::<T>(i as u8) };
_wdt: PhantomData,
index: i as u8,
};
handles[i].pet(); handles[i].pet();
} }
@ -139,7 +135,7 @@ impl Watchdog {
/// interrupt has been enabled. /// interrupt has been enabled.
#[inline(always)] #[inline(always)]
pub fn enable_interrupt(&mut self) { pub fn enable_interrupt(&mut self) {
crate::pac::WDT.intenset().write(|w| w.set_timeout(true)); T::REGS.intenset().write(|w| w.set_timeout(true));
} }
/// Disable the watchdog interrupt. /// Disable the watchdog interrupt.
@ -147,7 +143,7 @@ impl Watchdog {
/// NOTE: This has no effect on the reset caused by the Watchdog. /// NOTE: This has no effect on the reset caused by the Watchdog.
#[inline(always)] #[inline(always)]
pub fn disable_interrupt(&mut self) { pub fn disable_interrupt(&mut self) {
crate::pac::WDT.intenclr().write(|w| w.set_timeout(true)); T::REGS.intenclr().write(|w| w.set_timeout(true));
} }
/// Is the watchdog still awaiting pets from any handle? /// Is the watchdog still awaiting pets from any handle?
@ -156,7 +152,7 @@ impl Watchdog {
/// handles to prevent a reset this time period. /// handles to prevent a reset this time period.
#[inline(always)] #[inline(always)]
pub fn awaiting_pets(&self) -> bool { pub fn awaiting_pets(&self) -> bool {
let r = crate::pac::WDT; let r = T::REGS;
let enabled = r.rren().read().0; let enabled = r.rren().read().0;
let status = r.reqstatus().read().0; let status = r.reqstatus().read().0;
(status & enabled) == 0 (status & enabled) == 0
@ -165,11 +161,26 @@ impl Watchdog {
/// Watchdog handle. /// Watchdog handle.
pub struct WatchdogHandle { pub struct WatchdogHandle {
_wdt: PhantomData<Peri<'static, peripherals::WDT>>,
index: u8, index: u8,
} }
impl WatchdogHandle { impl WatchdogHandle {
fn regs(&self) -> pac::wdt::Wdt {
match self.index / 8 {
#[cfg(not(feature = "_multi_wdt"))]
peripherals::WDT::INDEX => peripherals::WDT::REGS,
#[cfg(feature = "_multi_wdt")]
peripherals::WDT0::INDEX => peripherals::WDT0::REGS,
#[cfg(feature = "_multi_wdt")]
peripherals::WDT1::INDEX => peripherals::WDT1::REGS,
_ => unsafe { unreachable_unchecked() },
}
}
fn rr_index(&self) -> usize {
usize::from(self.index % 8)
}
/// Pet the watchdog. /// Pet the watchdog.
/// ///
/// This function pets the given watchdog handle. /// This function pets the given watchdog handle.
@ -178,14 +189,14 @@ impl WatchdogHandle {
/// prevent a reset from occurring. /// prevent a reset from occurring.
#[inline] #[inline]
pub fn pet(&mut self) { pub fn pet(&mut self) {
let r = crate::pac::WDT; let r = self.regs();
r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD)); r.rr(self.rr_index()).write(|w| w.set_rr(vals::Rr::RELOAD));
} }
/// Has this handle been pet within the current window? /// Has this handle been pet within the current window?
pub fn is_pet(&self) -> bool { pub fn is_pet(&self) -> bool {
let r = crate::pac::WDT; let r = self.regs();
!r.reqstatus().read().rr(self.index as usize) !r.reqstatus().read().rr(self.rr_index())
} }
/// Steal a watchdog handle by index. /// Steal a watchdog handle by index.
@ -193,10 +204,33 @@ impl WatchdogHandle {
/// # Safety /// # Safety
/// Watchdog must be initialized and `index` must be between `0` and `N-1` /// Watchdog must be initialized and `index` must be between `0` and `N-1`
/// where `N` is the handle count when initializing. /// where `N` is the handle count when initializing.
pub unsafe fn steal(index: u8) -> Self { pub unsafe fn steal<T: Instance>(index: u8) -> Self {
Self { Self {
_wdt: PhantomData, index: T::INDEX * 8 + index,
index,
} }
} }
} }
pub(crate) trait SealedInstance {
const REGS: pac::wdt::Wdt;
const INDEX: u8;
}
/// WDT instance.
#[allow(private_bounds)]
pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
/// Interrupt for this peripheral.
type Interrupt: interrupt::typelevel::Interrupt;
}
macro_rules! impl_wdt {
($type:ident, $pac_type:ident, $irq:ident, $index:literal) => {
impl crate::wdt::SealedInstance for peripherals::$type {
const REGS: pac::wdt::Wdt = pac::$pac_type;
const INDEX: u8 = $index;
}
impl crate::wdt::Instance for peripherals::$type {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}