1use core::marker::PhantomData;
6
7use cortex_m::asm;
8use embassy_hal_internal::{Peri, PeripheralType, interrupt::InterruptExt as _};
9
10use crate::{
11 event_link::{IcuInterrupt as _, InterruptEvent},
12 interrupt,
13 interrupt::typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
14 pac::{
15 self,
16 dbg::vals::DbgstopIwdt,
17 osm::vals::{IwdtCks, IwdtTops, StartMode},
18 },
19 peripherals,
20 watchdog::Action,
21};
22
23pub struct IwdtInterruptHandler<I: Instance> {
25 _phantom: PhantomData<I>,
26}
27
28pub struct Watchdog<'d, I: Instance> {
30 phantom: PhantomData<&'d I>,
31}
32
33#[allow(private_bounds)]
35pub trait Instance: SealedInstance + PeripheralType {}
36
37pub(crate) trait SealedInstance {
38 fn regs() -> pac::iwdt::Iwdt;
39}
40
41impl<'d, I: Instance> Watchdog<'d, I> {
42 pub fn new(peri: Peri<'d, I>, action: Action) -> Self {
47 let _ = peri;
48
49 let osm = pac::OSM;
50 let ofs0 = osm.ofs0().read();
51
52 if ofs0.iwdtstrt() != StartMode::AutoStart {
53 warn!("IWDT: Not enabled");
54 } else if ofs0.iwdtstpctl() {
55 warn!("IWDT: Suspended in sleep mode, may not behave as expected with e.g. Embassy")
56 }
57
58 match action {
59 Action::Interrupt => {
60 debug!("IWDT: Enabling NMI");
61
62 cfg_select! {
63 not(ra8m1) => {
64 let icu = pac::ICU;
65
66 icu.nmicr().write(|r| r.set_nflten(false));
67 icu.nmicr().write(|r| r.set_nmimd(true));
68 icu.nmiclr().write(|r| r.set_nmiclr(true));
69 },
70 ra8m1 => {
71 let icu = pac::ICU;
72 let icu_common = pac::ICU_COMMON;
73
74 icu_common.nmicr().write(|r| r.set_nflten(false));
75 icu_common.nmicr().write(|r| r.set_nmimd(true));
76 icu.nmiclr().write(|r| r.set_nmiclr(true));
77 },
78 }
79
80 icu.nmier().write(|r| r.set_iwdten(true));
81 }
82 Action::Reset => {}
83 Action::Handler => {}
84 }
85
86 let dbg = pac::DBG;
89 dbg.dbgstopcr()
90 .write(|r| r.set_dbgstop_iwdt(DbgstopIwdt::Enable));
91
92 {
93 let osm = pac::OSM;
94 let ofs0 = osm.ofs0().read();
95 let divider: u16 = match ofs0.iwdtcks() {
96 IwdtCks::_1 => 1,
97 IwdtCks::_16 => 16,
98 IwdtCks::_32 => 32,
99 IwdtCks::_64 => 64,
100 IwdtCks::_128 => 128,
101 IwdtCks::_256 => 256,
102 _ => unreachable!(),
103 };
104 let period: u16 = match ofs0.iwdttops() {
105 IwdtTops::_128 => 128,
106 IwdtTops::_512 => 512,
107 IwdtTops::_1024 => 1024,
108 IwdtTops::_2048 => 2048,
109 };
110
111 let timeout = f32::from(period) / (15_000.0 / f32::from(divider));
112 debug!("IWDT: timeout: {} sec", timeout);
113 }
114
115 Self {
116 phantom: PhantomData,
117 }
118 }
119
120 #[inline]
122 pub fn new_handler<IwdtInt: InterruptType>(
123 peri: Peri<'d, I>,
124 irq: impl interrupt::typelevel::Binding<IwdtInt, IwdtInterruptHandler<I>>,
125 ) -> Self {
126 let _ = peri;
127 let _ = irq;
128
129 unsafe {
131 IwdtInt::IRQ.enable();
132 IwdtInt::IRQ.icu_enable(InterruptEvent::IwdtUnderflow);
133 }
134
135 Self::new(peri, Action::Handler)
136 }
137
138 pub fn refresh(&mut self) {
140 let iwdt = I::regs();
141
142 asm::dsb();
143 iwdt.iwdtrr().write_value(0x00);
144 asm::dsb();
145 iwdt.iwdtrr().write_value(0xFF);
146 }
147
148 #[inline(always)]
150 pub fn value(&self) -> u16 {
151 let iwdt = I::regs();
152
153 iwdt.iwdtsr().read().cntval()
154 }
155}
156
157impl Instance for peripherals::IWDT {}
158
159impl SealedInstance for peripherals::IWDT {
160 #[inline(always)]
161 fn regs() -> pac::iwdt::Iwdt {
162 pac::IWDT
163 }
164}
165
166impl<I: Instance, IwdtInt: InterruptType> InterruptHandler<IwdtInt> for IwdtInterruptHandler<I> {
167 unsafe fn on_interrupt() {
168 IwdtInt::IRQ.icu_unpend();
169
170 panic!("Independent watchdog underflow");
171 }
172}