1#![macro_use]
7
8use core::hint::unreachable_unchecked;
9
10use embassy_hal_internal::PeripheralType;
11
12use crate::pac::wdt::vals;
13pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig};
14use crate::{interrupt, pac, peripherals, Peri};
15
16const MIN_TICKS: u32 = 15;
17
18#[non_exhaustive]
20pub struct Config {
21 pub timeout_ticks: u32,
26
27 pub action_during_sleep: SleepConfig,
29
30 pub action_during_debug_halt: HaltConfig,
32}
33
34impl Config {
35 pub fn try_new<T: Instance>(_wdt: &Peri<'_, T>) -> Option<Self> {
38 let r = T::REGS;
39
40 #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340", feature = "_nrf54l")))]
41 let runstatus = r.runstatus().read().runstatus();
42 #[cfg(any(feature = "_nrf91", feature = "_nrf5340", feature = "_nrf54l"))]
43 let runstatus = r.runstatus().read().runstatuswdt();
44
45 if runstatus {
46 let config = r.config().read();
47 Some(Self {
48 timeout_ticks: r.crv().read(),
49 action_during_sleep: config.sleep(),
50 action_during_debug_halt: config.halt(),
51 })
52 } else {
53 None
54 }
55 }
56}
57
58impl Default for Config {
59 fn default() -> Self {
60 Self {
61 timeout_ticks: 32768, action_during_debug_halt: HaltConfig::RUN,
63 action_during_sleep: SleepConfig::RUN,
64 }
65 }
66}
67
68pub struct Watchdog {
70 r: pac::wdt::Wdt,
71}
72
73impl Watchdog {
74 #[inline]
82 pub fn try_new<T: Instance, const N: usize>(
83 wdt: Peri<'static, T>,
84 config: Config,
85 ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> {
86 assert!(N >= 1 && N <= 8);
87
88 let r = T::REGS;
89
90 let crv = config.timeout_ticks.max(MIN_TICKS);
91 let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1);
92
93 #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340", feature = "_nrf54l")))]
94 let runstatus = r.runstatus().read().runstatus();
95 #[cfg(any(feature = "_nrf91", feature = "_nrf5340", feature = "_nrf54l"))]
96 let runstatus = r.runstatus().read().runstatuswdt();
97
98 if runstatus {
99 let curr_config = r.config().read();
100 if curr_config.halt() != config.action_during_debug_halt
101 || curr_config.sleep() != config.action_during_sleep
102 || r.crv().read() != crv
103 || r.rren().read() != rren
104 {
105 return Err(wdt);
106 }
107 } else {
108 r.config().write(|w| {
109 w.set_sleep(config.action_during_sleep);
110 w.set_halt(config.action_during_debug_halt);
111 });
112 r.intenset().write(|w| w.set_timeout(true));
113
114 r.crv().write_value(crv);
115 r.rren().write_value(rren);
116 r.tasks_start().write_value(1);
117 }
118
119 let this = Self { r: T::REGS };
120
121 let mut handles = [const { WatchdogHandle { index: 0 } }; N];
122 for i in 0..N {
123 handles[i] = unsafe { WatchdogHandle::steal::<T>(i as u8) };
124 handles[i].pet();
125 }
126
127 Ok((this, handles))
128 }
129
130 #[inline(always)]
137 pub fn enable_interrupt(&mut self) {
138 self.r.intenset().write(|w| w.set_timeout(true));
139 }
140
141 #[inline(always)]
145 pub fn disable_interrupt(&mut self) {
146 self.r.intenclr().write(|w| w.set_timeout(true));
147 }
148
149 #[inline(always)]
154 pub fn awaiting_pets(&self) -> bool {
155 let enabled = self.r.rren().read().0;
156 let status = self.r.reqstatus().read().0;
157 (status & enabled) == 0
158 }
159}
160
161pub struct WatchdogHandle {
163 index: u8,
164}
165
166impl WatchdogHandle {
167 fn regs(&self) -> pac::wdt::Wdt {
168 match self.index / 8 {
169 #[cfg(not(feature = "_multi_wdt"))]
170 peripherals::WDT::INDEX => peripherals::WDT::REGS,
171 #[cfg(feature = "_multi_wdt")]
172 peripherals::WDT0::INDEX => peripherals::WDT0::REGS,
173 #[cfg(feature = "_multi_wdt")]
174 peripherals::WDT1::INDEX => peripherals::WDT1::REGS,
175 _ => unsafe { unreachable_unchecked() },
176 }
177 }
178
179 fn rr_index(&self) -> usize {
180 usize::from(self.index % 8)
181 }
182
183 #[inline]
190 pub fn pet(&mut self) {
191 let r = self.regs();
192 r.rr(self.rr_index()).write(|w| w.set_rr(vals::Rr::RELOAD));
193 }
194
195 pub fn is_pet(&self) -> bool {
197 let r = self.regs();
198 !r.reqstatus().read().rr(self.rr_index())
199 }
200
201 pub unsafe fn steal<T: Instance>(index: u8) -> Self {
207 Self {
208 index: T::INDEX * 8 + index,
209 }
210 }
211}
212
213pub(crate) trait SealedInstance {
214 const REGS: pac::wdt::Wdt;
215 const INDEX: u8;
216}
217
218#[allow(private_bounds)]
220pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
221 type Interrupt: interrupt::typelevel::Interrupt;
223}
224
225macro_rules! impl_wdt {
226 ($type:ident, $pac_type:ident, $irq:ident, $index:literal) => {
227 impl crate::wdt::SealedInstance for peripherals::$type {
228 const REGS: pac::wdt::Wdt = pac::$pac_type;
229 const INDEX: u8 = $index;
230 }
231 impl crate::wdt::Instance for peripherals::$type {
232 type Interrupt = crate::interrupt::typelevel::$irq;
233 }
234 };
235}