1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
//! Watchdog
//!
//! The watchdog is a countdown timer that can restart parts of the chip if it reaches zero. This can be used to restart the
//! processor if software gets stuck in an infinite loop. The programmer must periodically write a value to the watchdog to
//! stop it from reaching zero.
//!
//! Credit: based on `rp-hal` implementation (also licensed Apache+MIT)
use core::marker::PhantomData;
use embassy_time::Duration;
use crate::pac;
use crate::peripherals::WATCHDOG;
/// Watchdog peripheral
pub struct Watchdog {
phantom: PhantomData<WATCHDOG>,
load_value: u32, // decremented by 2 per tick (µs)
}
impl Watchdog {
/// Create a new `Watchdog`
pub fn new(_watchdog: WATCHDOG) -> Self {
Self {
phantom: PhantomData,
load_value: 0,
}
}
/// Start tick generation on clk_tick which is driven from clk_ref.
///
/// # Arguments
///
/// * `cycles` - Total number of tick cycles before the next tick is generated.
/// It is expected to be the frequency in MHz of clk_ref.
pub fn enable_tick_generation(&mut self, cycles: u8) {
let watchdog = pac::WATCHDOG;
watchdog.tick().write(|w| {
w.set_enable(true);
w.set_cycles(cycles.into())
});
}
/// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
/// or when JTAG is accessing bus fabric
pub fn pause_on_debug(&mut self, pause: bool) {
let watchdog = pac::WATCHDOG;
watchdog.ctrl().write(|w| {
w.set_pause_dbg0(pause);
w.set_pause_dbg1(pause);
w.set_pause_jtag(pause);
})
}
fn load_counter(&self, counter: u32) {
let watchdog = pac::WATCHDOG;
watchdog.load().write_value(pac::watchdog::regs::Load(counter));
}
fn enable(&self, bit: bool) {
let watchdog = pac::WATCHDOG;
watchdog.ctrl().write(|w| w.set_enable(bit))
}
// Configure which hardware will be reset by the watchdog
// (everything except ROSC, XOSC)
fn configure_wdog_reset_triggers(&self) {
let psm = pac::PSM;
psm.wdsel().write_value(pac::psm::regs::Wdsel(
0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
));
}
/// Feed the watchdog timer
pub fn feed(&mut self) {
self.load_counter(self.load_value)
}
/// Start the watchdog timer
pub fn start(&mut self, period: Duration) {
const MAX_PERIOD: u32 = 0xFFFFFF;
let delay_us = period.as_micros();
if delay_us > (MAX_PERIOD / 2) as u64 {
panic!("Period cannot exceed {} microseconds", MAX_PERIOD / 2);
}
let delay_us = delay_us as u32;
// Due to a logic error, the watchdog decrements by 2 and
// the load value must be compensated; see RP2040-E1
self.load_value = delay_us * 2;
self.enable(false);
self.configure_wdog_reset_triggers();
self.load_counter(self.load_value);
self.enable(true);
}
/// Trigger a system reset
pub fn trigger_reset(&mut self) {
self.configure_wdog_reset_triggers();
self.pause_on_debug(false);
self.enable(true);
let watchdog = pac::WATCHDOG;
watchdog.ctrl().write(|w| {
w.set_trigger(true);
})
}
/// Store data in scratch register
pub fn set_scratch(&mut self, index: usize, value: u32) {
let watchdog = pac::WATCHDOG;
match index {
0 => watchdog.scratch0().write(|w| *w = value),
1 => watchdog.scratch1().write(|w| *w = value),
2 => watchdog.scratch2().write(|w| *w = value),
3 => watchdog.scratch3().write(|w| *w = value),
4 => watchdog.scratch4().write(|w| *w = value),
5 => watchdog.scratch5().write(|w| *w = value),
6 => watchdog.scratch6().write(|w| *w = value),
7 => watchdog.scratch7().write(|w| *w = value),
_ => panic!("Invalid watchdog scratch index"),
}
}
/// Read data from scratch register
pub fn get_scratch(&mut self, index: usize) -> u32 {
let watchdog = pac::WATCHDOG;
match index {
0 => watchdog.scratch0().read(),
1 => watchdog.scratch1().read(),
2 => watchdog.scratch2().read(),
3 => watchdog.scratch3().read(),
4 => watchdog.scratch4().read(),
5 => watchdog.scratch5().read(),
6 => watchdog.scratch6().read(),
7 => watchdog.scratch7().read(),
_ => panic!("Invalid watchdog scratch index"),
}
}
}
|