2021-01-26 07:42:43 +11:00
|
|
|
//! Watchdog
|
2021-08-21 21:05:55 +10:00
|
|
|
//!
|
|
|
|
//! 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.
|
|
|
|
//!
|
|
|
|
//! See [Chapter 4 Section 7](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) of the datasheet for more details
|
|
|
|
//!
|
|
|
|
//! ## Usage
|
|
|
|
//! ```no_run
|
|
|
|
//! use cortex_m::prelude::{_embedded_hal_watchdog_Watchdog, _embedded_hal_watchdog_WatchdogEnable};
|
|
|
|
//! use embedded_time::duration::units::*;
|
|
|
|
//! use rp2040_hal::{clocks::init_clocks_and_plls, pac, watchdog::Watchdog};
|
|
|
|
//! let mut pac = pac::Peripherals::take().unwrap();
|
|
|
|
//! let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
|
|
|
//! let _clocks = init_clocks_and_plls(
|
|
|
|
//! 12_000_000,
|
|
|
|
//! pac.XOSC,
|
|
|
|
//! pac.CLOCKS,
|
|
|
|
//! pac.PLL_SYS,
|
|
|
|
//! pac.PLL_USB,
|
|
|
|
//! &mut pac.RESETS,
|
|
|
|
//! &mut watchdog,
|
|
|
|
//! ).ok().unwrap();
|
|
|
|
//! // Set to watchdog to reset if it's not reloaded within 1.05 seconds, and start it
|
|
|
|
//! watchdog.start(1_050_000.microseconds());
|
|
|
|
//! // Feed the watchdog once per cycle to avoid reset
|
|
|
|
//! for _ in 1..=10000 {
|
|
|
|
//! cortex_m::asm::delay(100_000);
|
|
|
|
//! watchdog.feed();
|
|
|
|
//! }
|
|
|
|
//! // Stop feeding, now we'll reset
|
|
|
|
//! loop {}
|
|
|
|
//! ```
|
|
|
|
//! See [examples/watchdog.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples/watchdog.rs) for a more complete example
|
|
|
|
|
2021-05-16 03:32:14 +10:00
|
|
|
use crate::pac::WATCHDOG;
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
use eh1_0_alpha::watchdog::blocking as eh1;
|
2021-05-18 05:06:12 +10:00
|
|
|
use embedded_hal::watchdog;
|
|
|
|
use embedded_time::{duration, fixed_point::FixedPoint};
|
2021-05-16 03:32:14 +10:00
|
|
|
|
2021-05-18 09:58:12 +10:00
|
|
|
/// Watchdog peripheral
|
2021-05-16 03:32:14 +10:00
|
|
|
pub struct Watchdog {
|
|
|
|
watchdog: WATCHDOG,
|
|
|
|
delay_ms: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Watchdog {
|
2021-05-18 09:58:12 +10:00
|
|
|
/// Create a new [`Watchdog`]
|
2021-05-16 03:32:14 +10:00
|
|
|
pub fn new(watchdog: WATCHDOG) -> Self {
|
|
|
|
Self {
|
|
|
|
watchdog,
|
|
|
|
delay_ms: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 09:58:12 +10:00
|
|
|
/// Starts tick generation on clk_tick which is driven from clk_ref.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
2021-05-17 07:41:38 +10:00
|
|
|
///
|
2021-05-18 09:58:12 +10:00
|
|
|
/// * `cycles` - Total number of tick cycles before the next tick is generated.
|
2021-05-16 03:32:14 +10:00
|
|
|
pub fn enable_tick_generation(&mut self, cycles: u8) {
|
|
|
|
const WATCHDOG_TICK_ENABLE_BITS: u32 = 0x200;
|
|
|
|
|
|
|
|
self.watchdog
|
|
|
|
.tick
|
2021-05-17 08:17:36 +10:00
|
|
|
.write(|w| unsafe { w.bits(WATCHDOG_TICK_ENABLE_BITS | cycles as u32) })
|
|
|
|
}
|
|
|
|
|
2021-05-18 09:58:12 +10:00
|
|
|
/// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
|
|
|
|
/// or when JTAG is accessing bus fabric
|
|
|
|
///
|
|
|
|
/// # Arguments
|
2021-05-17 08:17:36 +10:00
|
|
|
///
|
2021-05-18 09:58:12 +10:00
|
|
|
/// * `pause` - If true, watchdog timer will be paused
|
2021-05-17 08:17:36 +10:00
|
|
|
pub fn pause_on_debug(&mut self, pause: bool) {
|
2021-05-18 05:06:12 +10:00
|
|
|
self.watchdog.ctrl.write(|w| {
|
|
|
|
w.pause_dbg0()
|
|
|
|
.bit(pause)
|
|
|
|
.pause_dbg1()
|
|
|
|
.bit(pause)
|
|
|
|
.pause_jtag()
|
|
|
|
.bit(pause)
|
|
|
|
})
|
2021-05-16 03:32:14 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn load_counter(&self, counter: u32) {
|
2021-05-18 05:06:12 +10:00
|
|
|
self.watchdog.load.write(|w| unsafe { w.bits(counter) });
|
2021-05-16 03:32:14 +10:00
|
|
|
}
|
|
|
|
|
2021-05-17 08:17:36 +10:00
|
|
|
fn enable(&self, bit: bool) {
|
2021-05-18 05:06:12 +10:00
|
|
|
self.watchdog.ctrl.write(|w| w.enable().bit(bit))
|
2021-05-16 03:32:14 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl watchdog::Watchdog for Watchdog {
|
|
|
|
fn feed(&mut self) {
|
|
|
|
self.load_counter(self.delay_ms)
|
|
|
|
}
|
|
|
|
}
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1::Watchdog for Watchdog {
|
|
|
|
type Error = core::convert::Infallible;
|
|
|
|
|
|
|
|
fn feed(&mut self) -> Result<(), Self::Error> {
|
|
|
|
self.load_counter(self.delay_ms);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2021-05-16 03:32:14 +10:00
|
|
|
|
|
|
|
impl watchdog::WatchdogEnable for Watchdog {
|
|
|
|
type Time = duration::Microseconds;
|
|
|
|
|
|
|
|
fn start<T: Into<Self::Time>>(&mut self, period: T) {
|
2021-05-18 09:58:12 +10:00
|
|
|
const MAX_PERIOD: u32 = 0xFFFFFF;
|
2021-05-18 05:06:12 +10:00
|
|
|
|
|
|
|
// Due to a logic error, the watchdog decrements by 2 and
|
|
|
|
// the load value must be compensated; see RP2040-E1
|
|
|
|
self.delay_ms = period.into().integer() * 2;
|
|
|
|
|
|
|
|
if self.delay_ms > MAX_PERIOD {
|
|
|
|
panic!("Period cannot exceed maximum load value of {}", MAX_PERIOD);
|
|
|
|
}
|
2021-05-16 03:32:14 +10:00
|
|
|
|
2021-05-17 08:17:36 +10:00
|
|
|
self.enable(false);
|
2021-05-17 07:41:38 +10:00
|
|
|
self.load_counter(self.delay_ms);
|
2021-05-17 08:17:36 +10:00
|
|
|
self.enable(true);
|
2021-05-16 03:32:14 +10:00
|
|
|
}
|
|
|
|
}
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1::Enable for Watchdog {
|
|
|
|
type Error = core::convert::Infallible;
|
|
|
|
type Target = Self;
|
|
|
|
type Time = duration::Microseconds;
|
|
|
|
|
|
|
|
fn start<T: Into<Self::Time>>(mut self, period: T) -> Result<Self::Target, Self::Error> {
|
|
|
|
const MAX_PERIOD: u32 = 0xFFFFFF;
|
|
|
|
|
|
|
|
// Due to a logic error, the watchdog decrements by 2 and
|
|
|
|
// the load value must be compensated; see RP2040-E1
|
|
|
|
self.delay_ms = period.into().integer() * 2;
|
|
|
|
|
|
|
|
if self.delay_ms > MAX_PERIOD {
|
|
|
|
panic!("Period cannot exceed maximum load value of {}", MAX_PERIOD);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.enable(false);
|
|
|
|
self.load_counter(self.delay_ms);
|
|
|
|
self.enable(true);
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
}
|
2021-05-16 03:32:14 +10:00
|
|
|
|
|
|
|
impl watchdog::WatchdogDisable for Watchdog {
|
|
|
|
fn disable(&mut self) {
|
2021-05-17 08:17:36 +10:00
|
|
|
self.enable(false)
|
2021-05-16 03:32:14 +10:00
|
|
|
}
|
|
|
|
}
|
2021-10-02 15:36:40 +10:00
|
|
|
#[cfg(feature = "eh1_0_alpha")]
|
|
|
|
impl eh1::Disable for Watchdog {
|
|
|
|
type Error = core::convert::Infallible;
|
|
|
|
type Target = Self;
|
|
|
|
fn disable(self) -> Result<Self::Target, Self::Error> {
|
|
|
|
self.enable(false);
|
|
|
|
Ok(self)
|
|
|
|
}
|
|
|
|
}
|