diff --git a/CHANGELOG.md b/CHANGELOG.md index fa16b18..cbfd4b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - Added peripheral drivers: Timer(counter) +- Added examples: Watchdog +- Added docs: Watchdog ## [0.2.0] diff --git a/rp2040-hal/examples/watchdog.rs b/rp2040-hal/examples/watchdog.rs new file mode 100644 index 0000000..f230f8b --- /dev/null +++ b/rp2040-hal/examples/watchdog.rs @@ -0,0 +1,82 @@ +//! How to use the watchdog peripheral to reset the system in case something takes too long +#![no_std] +#![no_main] + +use cortex_m::prelude::{_embedded_hal_watchdog_Watchdog, _embedded_hal_watchdog_WatchdogEnable}; +use cortex_m_rt::entry; +use embedded_hal::digital::v2::OutputPin; +use embedded_time::duration::units::*; +use embedded_time::fixed_point::FixedPoint; +use hal::clocks::{init_clocks_and_plls, Clock}; +use hal::gpio::Pins; +use hal::pac; +use hal::sio::Sio; +use hal::watchdog::Watchdog; +use panic_halt as _; +use rp2040_hal as hal; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +// External high-speed crystal on the pico board is 12Mhz +// Adjust for your board if this isn't the same +const EXTERNAL_XTAL_FREQ_HZ: u32 = 12_000_000; + +#[entry] +fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + let cp = pac::CorePeripherals::take().unwrap(); + let mut watchdog = Watchdog::new(pac.WATCHDOG); + let sio = Sio::new(pac.SIO); + + let clocks = init_clocks_and_plls( + EXTERNAL_XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let pins = Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + // We need to accurately delay to give feedback that the watchdog is working correctly + let mut delay = cortex_m::delay::Delay::new(cp.SYST, clocks.system_clock.freq().integer()); + + // Configure an LED so we can show the current state of the watchdog + let mut led_pin = pins.gpio25.into_push_pull_output(); + + // Set the LED high for 2 seconds so we know when we're about to start the watchdog + led_pin.set_high().unwrap(); + delay.delay_ms(2000); + + // Set to watchdog to reset if it's not reloaded within 1.05 seconds, and start it + watchdog.start(1_050_000.microseconds()); + + // Blink once a second for 5 seconds, refreshing the watchdog timer once a second to avoid a reset + for _ in 1..=5 { + led_pin.set_low().unwrap(); + delay.delay_ms(500); + led_pin.set_high().unwrap(); + delay.delay_ms(500); + watchdog.feed(); + } + + // Blink 10 times per second, not feeding the watchdog. + // The processor should reset in 1.05 seconds, or 5 blinks time + loop { + led_pin.set_low().unwrap(); + delay.delay_ms(100); + led_pin.set_high().unwrap(); + delay.delay_ms(100); + } +} diff --git a/rp2040-hal/src/watchdog.rs b/rp2040-hal/src/watchdog.rs index aff5f5d..8b300a5 100644 --- a/rp2040-hal/src/watchdog.rs +++ b/rp2040-hal/src/watchdog.rs @@ -1,5 +1,39 @@ //! Watchdog -// See [Chapter 4 Section 7](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details +//! +//! 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 + use crate::pac::WATCHDOG; use embedded_hal::watchdog; use embedded_time::{duration, fixed_point::FixedPoint};