nrf: add WDT driver
This commit is contained in:
		@@ -8,6 +8,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC0,
 | 
					    RTC0,
 | 
				
			||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC0,
 | 
					    RTC0,
 | 
				
			||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC0,
 | 
					    RTC0,
 | 
				
			||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC0,
 | 
					    RTC0,
 | 
				
			||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
    RTC2,
 | 
					    RTC2,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
    RTC2,
 | 
					    RTC2,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ embassy_hal_common::peripherals! {
 | 
				
			|||||||
    RTC1,
 | 
					    RTC1,
 | 
				
			||||||
    RTC2,
 | 
					    RTC2,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // WDT
 | 
				
			||||||
 | 
					    WDT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // RNG
 | 
					    // RNG
 | 
				
			||||||
    RNG,
 | 
					    RNG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@ pub mod spim;
 | 
				
			|||||||
pub mod timer;
 | 
					pub mod timer;
 | 
				
			||||||
pub mod twim;
 | 
					pub mod twim;
 | 
				
			||||||
pub mod uarte;
 | 
					pub mod uarte;
 | 
				
			||||||
 | 
					pub mod wdt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
 | 
					// This mod MUST go last, so that it sees all the `impl_foo!` macros
 | 
				
			||||||
#[cfg(feature = "nrf52805")]
 | 
					#[cfg(feature = "nrf52805")]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										153
									
								
								embassy-nrf/src/wdt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								embassy-nrf/src/wdt.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					//! HAL interface to the WDT peripheral.
 | 
				
			||||||
 | 
					//!
 | 
				
			||||||
 | 
					//! This HAL implements a basic watchdog timer with 1..=8 handles.
 | 
				
			||||||
 | 
					//! Once the watchdog has been started, it cannot be stopped.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::pac::WDT;
 | 
				
			||||||
 | 
					use crate::peripherals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MIN_TICKS: u32 = 15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[non_exhaustive]
 | 
				
			||||||
 | 
					pub struct Config {
 | 
				
			||||||
 | 
					    /// Number of 32768 Hz ticks in each watchdog period.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Note: there is a minimum of 15 ticks (458 microseconds). If a lower
 | 
				
			||||||
 | 
					    /// number is provided, 15 ticks will be used as the configured value.
 | 
				
			||||||
 | 
					    pub timeout_ticks: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Should the watchdog continue to count during sleep modes?
 | 
				
			||||||
 | 
					    pub run_during_sleep: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Should the watchdog continue to count when the CPU is halted for debug?
 | 
				
			||||||
 | 
					    pub run_during_debug_halt: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for Config {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            timeout_ticks: 32768, // 1 second
 | 
				
			||||||
 | 
					            run_during_debug_halt: true,
 | 
				
			||||||
 | 
					            run_during_sleep: true,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// An interface to the Watchdog.
 | 
				
			||||||
 | 
					pub struct Watchdog {
 | 
				
			||||||
 | 
					    _private: (),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Watchdog {
 | 
				
			||||||
 | 
					    /// Try to create a new watchdog instance from the peripheral.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This function will return an error if the watchdog is already active
 | 
				
			||||||
 | 
					    /// with a `config` different to the requested one, or a different number of
 | 
				
			||||||
 | 
					    /// enabled handles.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// `N` must be between 1 and 8, inclusive.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub fn try_new<const N: usize>(
 | 
				
			||||||
 | 
					        wdt: peripherals::WDT,
 | 
				
			||||||
 | 
					        config: Config,
 | 
				
			||||||
 | 
					    ) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> {
 | 
				
			||||||
 | 
					        assert!(N >= 1 && N <= 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let crv = config.timeout_ticks.max(MIN_TICKS);
 | 
				
			||||||
 | 
					        let rren = (1u32 << N) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if r.runstatus.read().runstatus().bit() {
 | 
				
			||||||
 | 
					            let curr_config = r.config.read();
 | 
				
			||||||
 | 
					            if curr_config.halt().bit() != config.run_during_debug_halt
 | 
				
			||||||
 | 
					                || curr_config.sleep().bit() != config.run_during_sleep
 | 
				
			||||||
 | 
					                || r.crv.read().bits() != crv
 | 
				
			||||||
 | 
					                || r.rren.read().bits() != rren
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return Err(wdt);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            r.config.write(|w| {
 | 
				
			||||||
 | 
					                w.sleep().bit(config.run_during_sleep);
 | 
				
			||||||
 | 
					                w.halt().bit(config.run_during_debug_halt);
 | 
				
			||||||
 | 
					                w
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            r.intenset.write(|w| w.timeout().set_bit());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            r.crv.write(|w| unsafe { w.bits(crv) });
 | 
				
			||||||
 | 
					            r.rren.write(|w| unsafe { w.bits(rren) });
 | 
				
			||||||
 | 
					            r.tasks_start.write(|w| unsafe { w.bits(1) });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let this = Self { _private: () };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const DUMMY_HANDLE: WatchdogHandle = WatchdogHandle { index: 0 };
 | 
				
			||||||
 | 
					        let mut handles = [DUMMY_HANDLE; N];
 | 
				
			||||||
 | 
					        for i in 0..N {
 | 
				
			||||||
 | 
					            handles[i] = WatchdogHandle { index: i as u8 };
 | 
				
			||||||
 | 
					            handles[i].pet();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok((this, handles))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Enable the watchdog interrupt.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// NOTE: Although the interrupt will occur, there is no way to prevent
 | 
				
			||||||
 | 
					    /// the reset from occurring. From the time the event was fired, the
 | 
				
			||||||
 | 
					    /// system will reset two LFCLK ticks later (61 microseconds) if the
 | 
				
			||||||
 | 
					    /// interrupt has been enabled.
 | 
				
			||||||
 | 
					    #[inline(always)]
 | 
				
			||||||
 | 
					    pub fn enable_interrupt(&mut self) {
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					        r.intenset.write(|w| w.timeout().set_bit());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Disable the watchdog interrupt.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// NOTE: This has no effect on the reset caused by the Watchdog.
 | 
				
			||||||
 | 
					    #[inline(always)]
 | 
				
			||||||
 | 
					    pub fn disable_interrupt(&mut self) {
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					        r.intenclr.write(|w| w.timeout().set_bit());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Is the watchdog still awaiting pets from any handle?
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This reports whether sufficient pets have been received from all
 | 
				
			||||||
 | 
					    /// handles to prevent a reset this time period.
 | 
				
			||||||
 | 
					    #[inline(always)]
 | 
				
			||||||
 | 
					    pub fn awaiting_pets(&self) -> bool {
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					        let enabled = r.rren.read().bits();
 | 
				
			||||||
 | 
					        let status = r.reqstatus.read().bits();
 | 
				
			||||||
 | 
					        (status & enabled) == 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct WatchdogHandle {
 | 
				
			||||||
 | 
					    index: u8,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl WatchdogHandle {
 | 
				
			||||||
 | 
					    /// Pet the watchdog.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// This function pets the given watchdog handle.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// NOTE: All active handles must be pet within the time interval to
 | 
				
			||||||
 | 
					    /// prevent a reset from occurring.
 | 
				
			||||||
 | 
					    #[inline]
 | 
				
			||||||
 | 
					    pub fn pet(&mut self) {
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					        r.rr[self.index as usize].write(|w| w.rr().reload());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Has this handle been pet within the current window?
 | 
				
			||||||
 | 
					    pub fn is_pet(&self) -> bool {
 | 
				
			||||||
 | 
					        let r = unsafe { &*WDT::ptr() };
 | 
				
			||||||
 | 
					        let rd = r.reqstatus.read().bits();
 | 
				
			||||||
 | 
					        let idx = self.index as usize;
 | 
				
			||||||
 | 
					        ((rd >> idx) & 0x1) == 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								examples/nrf/src/bin/wdt.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								examples/nrf/src/bin/wdt.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					#![no_main]
 | 
				
			||||||
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					#![allow(incomplete_features)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[path = "../example_common.rs"]
 | 
				
			||||||
 | 
					mod example_common;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::*;
 | 
				
			||||||
 | 
					use embassy::executor::Spawner;
 | 
				
			||||||
 | 
					use embassy_nrf::gpio::{Input, Pull};
 | 
				
			||||||
 | 
					use embassy_nrf::gpiote::PortInput;
 | 
				
			||||||
 | 
					use embassy_nrf::wdt::{Config, Watchdog};
 | 
				
			||||||
 | 
					use embassy_nrf::Peripherals;
 | 
				
			||||||
 | 
					use embassy_traits::gpio::{WaitForHigh, WaitForLow};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[embassy::main]
 | 
				
			||||||
 | 
					async fn main(_spawner: Spawner, p: Peripherals) {
 | 
				
			||||||
 | 
					    info!("Hello World!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut config = Config::default();
 | 
				
			||||||
 | 
					    config.timeout_ticks = 32768 * 3; // 3 seconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This is needed for `probe-run` to be able to catch the panic message
 | 
				
			||||||
 | 
					    // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
 | 
				
			||||||
 | 
					    config.run_during_debug_halt = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let (_wdt, [mut handle]) = match Watchdog::try_new::<1>(p.WDT, config) {
 | 
				
			||||||
 | 
					        Ok(x) => x,
 | 
				
			||||||
 | 
					        Err(_) => {
 | 
				
			||||||
 | 
					            info!("Watchdog already active with wrong config, waiting for it to timeout...");
 | 
				
			||||||
 | 
					            loop {}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut button = PortInput::new(Input::new(p.P0_11, Pull::Up));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    info!("Watchdog started, press button 1 to pet it or I'll reset in 3 seconds!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    loop {
 | 
				
			||||||
 | 
					        button.wait_for_high().await;
 | 
				
			||||||
 | 
					        button.wait_for_low().await;
 | 
				
			||||||
 | 
					        info!("Button pressed, petting watchdog!");
 | 
				
			||||||
 | 
					        handle.pet();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user