Merge pull request #4119 from 0e4ef622/nrf53-wdt
nrf53: add WDT support
This commit is contained in:
		
						commit
						fb5ce05b26
					
				
							
								
								
									
										1
									
								
								ci.sh
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								ci.sh
									
									
									
									
									
								
							| @ -188,6 +188,7 @@ cargo batch \ | ||||
|     --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ | ||||
|     --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ | ||||
|     --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ | ||||
|     --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf5340-app-s \ | ||||
|     --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ | ||||
|     --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ | ||||
|     --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \ | ||||
|  | ||||
| @ -8,7 +8,6 @@ pub use embassy_boot::{ | ||||
|     FirmwareUpdater, FirmwareUpdaterConfig, | ||||
| }; | ||||
| use embassy_nrf::nvmc::PAGE_SIZE; | ||||
| use embassy_nrf::peripherals::WDT; | ||||
| use embassy_nrf::{wdt, Peri}; | ||||
| use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; | ||||
| 
 | ||||
| @ -113,7 +112,7 @@ pub struct WatchdogFlash<FLASH> { | ||||
| 
 | ||||
| impl<FLASH> WatchdogFlash<FLASH> { | ||||
|     /// Start a new watchdog with a given flash and WDT peripheral and a timeout
 | ||||
|     pub fn start(flash: FLASH, wdt: Peri<'static, WDT>, config: wdt::Config) -> Self { | ||||
|     pub fn start(flash: FLASH, wdt: Peri<'static, impl wdt::Instance>, config: wdt::Config) -> Self { | ||||
|         let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { | ||||
|             Ok(x) => x, | ||||
|             Err(_) => { | ||||
|  | ||||
| @ -109,7 +109,7 @@ nrf9161-ns = ["nrf9120-ns"] | ||||
| # Features starting with `_` are for internal use only. They're not intended | ||||
| # to be enabled by other crates, and are not covered by semver guarantees. | ||||
| 
 | ||||
| _nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] | ||||
| _nrf5340-app = ["_nrf5340", "_multi_wdt", "nrf-pac/nrf5340-app"] | ||||
| _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] | ||||
| _nrf5340 = ["_gpio-p1", "_dppi"] | ||||
| _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] | ||||
| @ -136,6 +136,9 @@ _gpio-p2 = [] | ||||
| # Errata workarounds | ||||
| _nrf52832_anomaly_109 = [] | ||||
| 
 | ||||
| # watchdog timer | ||||
| _multi_wdt = [] | ||||
| 
 | ||||
| [dependencies] | ||||
| embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } | ||||
| embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } | ||||
|  | ||||
| @ -145,6 +145,8 @@ impl_pin!(P0_31, 0, 31); | ||||
| 
 | ||||
| impl_radio!(RADIO, RADIO, RADIO); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -221,6 +221,8 @@ impl_radio!(RADIO, RADIO, RADIO); | ||||
| impl_egu!(EGU0, EGU0, EGU0_SWI0); | ||||
| impl_egu!(EGU1, EGU1, EGU1_SWI1); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -247,6 +247,8 @@ impl_radio!(RADIO, RADIO, RADIO); | ||||
| impl_egu!(EGU0, EGU0, EGU0_SWI0); | ||||
| impl_egu!(EGU1, EGU1, EGU1_SWI1); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -249,6 +249,8 @@ impl_radio!(RADIO, RADIO, RADIO); | ||||
| impl_egu!(EGU0, EGU0, EGU0_SWI0); | ||||
| impl_egu!(EGU1, EGU1, EGU1_SWI1); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -244,6 +244,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); | ||||
| impl_egu!(EGU4, EGU4, EGU4_SWI4); | ||||
| impl_egu!(EGU5, EGU5, EGU5_SWI5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -287,6 +287,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); | ||||
| impl_egu!(EGU4, EGU4, EGU4_SWI4); | ||||
| impl_egu!(EGU5, EGU5, EGU5_SWI5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -329,6 +329,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); | ||||
| impl_egu!(EGU4, EGU4, EGU4_SWI4); | ||||
| impl_egu!(EGU5, EGU5, EGU5_SWI5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -334,6 +334,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); | ||||
| impl_egu!(EGU4, EGU4, EGU4_SWI4); | ||||
| impl_egu!(EGU5, EGU5, EGU5_SWI5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -171,7 +171,8 @@ embassy_hal_internal::peripherals! { | ||||
|     RTC1, | ||||
| 
 | ||||
|     // WDT
 | ||||
|     WDT, | ||||
|     WDT0, | ||||
|     WDT1, | ||||
| 
 | ||||
|     // NVMC
 | ||||
|     NVMC, | ||||
| @ -473,6 +474,9 @@ impl_egu!(EGU3, EGU3, EGU3); | ||||
| impl_egu!(EGU4, EGU4, EGU4); | ||||
| impl_egu!(EGU5, EGU5, EGU5); | ||||
| 
 | ||||
| impl_wdt!(WDT0, WDT0, WDT0, 0); | ||||
| impl_wdt!(WDT1, WDT1, WDT1, 1); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     FPU, | ||||
|     CACHE, | ||||
|  | ||||
| @ -299,6 +299,8 @@ impl_radio!(RADIO, RADIO, RADIO); | ||||
| 
 | ||||
| impl_egu!(EGU0, EGU0, EGU0); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     CLOCK_POWER, | ||||
|     RADIO, | ||||
|  | ||||
| @ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3); | ||||
| impl_egu!(EGU4, EGU4, EGU4); | ||||
| impl_egu!(EGU5, EGU5, EGU5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     SPU, | ||||
|     CLOCK_POWER, | ||||
|  | ||||
| @ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3); | ||||
| impl_egu!(EGU4, EGU4, EGU4); | ||||
| impl_egu!(EGU5, EGU5, EGU5); | ||||
| 
 | ||||
| impl_wdt!(WDT, WDT, WDT, 0); | ||||
| 
 | ||||
| embassy_hal_internal::interrupt_mod!( | ||||
|     SPU, | ||||
|     CLOCK_POWER, | ||||
|  | ||||
| @ -169,7 +169,6 @@ pub mod uarte; | ||||
| ))] | ||||
| pub mod usb; | ||||
| #[cfg(not(feature = "_nrf54l"))] // TODO
 | ||||
| #[cfg(not(feature = "_nrf5340"))] | ||||
| pub mod wdt; | ||||
| 
 | ||||
| // This mod MUST go last, so that it sees all the `impl_foo!` macros
 | ||||
|  | ||||
| @ -3,11 +3,15 @@ | ||||
| //! This HAL implements a basic watchdog timer with 1..=8 handles.
 | ||||
| //! Once the watchdog has been started, it cannot be stopped.
 | ||||
| 
 | ||||
| use core::marker::PhantomData; | ||||
| #![macro_use] | ||||
| 
 | ||||
| use core::hint::unreachable_unchecked; | ||||
| 
 | ||||
| use embassy_hal_internal::PeripheralType; | ||||
| 
 | ||||
| use crate::pac::wdt::vals; | ||||
| pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; | ||||
| use crate::{peripherals, Peri}; | ||||
| use crate::{interrupt, pac, peripherals, Peri}; | ||||
| 
 | ||||
| const MIN_TICKS: u32 = 15; | ||||
| 
 | ||||
| @ -30,12 +34,12 @@ pub struct Config { | ||||
| impl Config { | ||||
|     /// Create a config structure from the current configuration of the WDT
 | ||||
|     /// peripheral.
 | ||||
|     pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> { | ||||
|         let r = crate::pac::WDT; | ||||
|     pub fn try_new<T: Instance>(_wdt: &Peri<'_, T>) -> Option<Self> { | ||||
|         let r = T::REGS; | ||||
| 
 | ||||
|         #[cfg(not(feature = "_nrf91"))] | ||||
|         #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] | ||||
|         let runstatus = r.runstatus().read().runstatus(); | ||||
|         #[cfg(feature = "_nrf91")] | ||||
|         #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] | ||||
|         let runstatus = r.runstatus().read().runstatuswdt(); | ||||
| 
 | ||||
|         if runstatus { | ||||
| @ -62,11 +66,11 @@ impl Default for Config { | ||||
| } | ||||
| 
 | ||||
| /// Watchdog driver.
 | ||||
| pub struct Watchdog { | ||||
|     _wdt: Peri<'static, peripherals::WDT>, | ||||
| pub struct Watchdog<T: Instance> { | ||||
|     _wdt: Peri<'static, T>, | ||||
| } | ||||
| 
 | ||||
| impl Watchdog { | ||||
| impl<T: Instance> Watchdog<T> { | ||||
|     /// Try to create a new watchdog driver.
 | ||||
|     ///
 | ||||
|     /// This function will return an error if the watchdog is already active
 | ||||
| @ -76,19 +80,19 @@ impl Watchdog { | ||||
|     /// `N` must be between 1 and 8, inclusive.
 | ||||
|     #[inline] | ||||
|     pub fn try_new<const N: usize>( | ||||
|         wdt: Peri<'static, peripherals::WDT>, | ||||
|         wdt: Peri<'static, T>, | ||||
|         config: Config, | ||||
|     ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, peripherals::WDT>> { | ||||
|     ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> { | ||||
|         assert!(N >= 1 && N <= 8); | ||||
| 
 | ||||
|         let r = crate::pac::WDT; | ||||
|         let r = T::REGS; | ||||
| 
 | ||||
|         let crv = config.timeout_ticks.max(MIN_TICKS); | ||||
|         let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1); | ||||
| 
 | ||||
|         #[cfg(not(feature = "_nrf91"))] | ||||
|         #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] | ||||
|         let runstatus = r.runstatus().read().runstatus(); | ||||
|         #[cfg(feature = "_nrf91")] | ||||
|         #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] | ||||
|         let runstatus = r.runstatus().read().runstatuswdt(); | ||||
| 
 | ||||
|         if runstatus { | ||||
| @ -114,17 +118,9 @@ impl Watchdog { | ||||
| 
 | ||||
|         let this = Self { _wdt: wdt }; | ||||
| 
 | ||||
|         let mut handles = [const { | ||||
|             WatchdogHandle { | ||||
|                 _wdt: PhantomData, | ||||
|                 index: 0, | ||||
|             } | ||||
|         }; N]; | ||||
|         let mut handles = [const { WatchdogHandle { index: 0 } }; N]; | ||||
|         for i in 0..N { | ||||
|             handles[i] = WatchdogHandle { | ||||
|                 _wdt: PhantomData, | ||||
|                 index: i as u8, | ||||
|             }; | ||||
|             handles[i] = unsafe { WatchdogHandle::steal::<T>(i as u8) }; | ||||
|             handles[i].pet(); | ||||
|         } | ||||
| 
 | ||||
| @ -139,7 +135,7 @@ impl Watchdog { | ||||
|     /// interrupt has been enabled.
 | ||||
|     #[inline(always)] | ||||
|     pub fn enable_interrupt(&mut self) { | ||||
|         crate::pac::WDT.intenset().write(|w| w.set_timeout(true)); | ||||
|         T::REGS.intenset().write(|w| w.set_timeout(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Disable the watchdog interrupt.
 | ||||
| @ -147,7 +143,7 @@ impl Watchdog { | ||||
|     /// NOTE: This has no effect on the reset caused by the Watchdog.
 | ||||
|     #[inline(always)] | ||||
|     pub fn disable_interrupt(&mut self) { | ||||
|         crate::pac::WDT.intenclr().write(|w| w.set_timeout(true)); | ||||
|         T::REGS.intenclr().write(|w| w.set_timeout(true)); | ||||
|     } | ||||
| 
 | ||||
|     /// Is the watchdog still awaiting pets from any handle?
 | ||||
| @ -156,7 +152,7 @@ impl Watchdog { | ||||
|     /// handles to prevent a reset this time period.
 | ||||
|     #[inline(always)] | ||||
|     pub fn awaiting_pets(&self) -> bool { | ||||
|         let r = crate::pac::WDT; | ||||
|         let r = T::REGS; | ||||
|         let enabled = r.rren().read().0; | ||||
|         let status = r.reqstatus().read().0; | ||||
|         (status & enabled) == 0 | ||||
| @ -165,11 +161,26 @@ impl Watchdog { | ||||
| 
 | ||||
| /// Watchdog handle.
 | ||||
| pub struct WatchdogHandle { | ||||
|     _wdt: PhantomData<Peri<'static, peripherals::WDT>>, | ||||
|     index: u8, | ||||
| } | ||||
| 
 | ||||
| impl WatchdogHandle { | ||||
|     fn regs(&self) -> pac::wdt::Wdt { | ||||
|         match self.index / 8 { | ||||
|             #[cfg(not(feature = "_multi_wdt"))] | ||||
|             peripherals::WDT::INDEX => peripherals::WDT::REGS, | ||||
|             #[cfg(feature = "_multi_wdt")] | ||||
|             peripherals::WDT0::INDEX => peripherals::WDT0::REGS, | ||||
|             #[cfg(feature = "_multi_wdt")] | ||||
|             peripherals::WDT1::INDEX => peripherals::WDT1::REGS, | ||||
|             _ => unsafe { unreachable_unchecked() }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn rr_index(&self) -> usize { | ||||
|         usize::from(self.index % 8) | ||||
|     } | ||||
| 
 | ||||
|     /// Pet the watchdog.
 | ||||
|     ///
 | ||||
|     /// This function pets the given watchdog handle.
 | ||||
| @ -178,14 +189,14 @@ impl WatchdogHandle { | ||||
|     /// prevent a reset from occurring.
 | ||||
|     #[inline] | ||||
|     pub fn pet(&mut self) { | ||||
|         let r = crate::pac::WDT; | ||||
|         r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD)); | ||||
|         let r = self.regs(); | ||||
|         r.rr(self.rr_index()).write(|w| w.set_rr(vals::Rr::RELOAD)); | ||||
|     } | ||||
| 
 | ||||
|     /// Has this handle been pet within the current window?
 | ||||
|     pub fn is_pet(&self) -> bool { | ||||
|         let r = crate::pac::WDT; | ||||
|         !r.reqstatus().read().rr(self.index as usize) | ||||
|         let r = self.regs(); | ||||
|         !r.reqstatus().read().rr(self.rr_index()) | ||||
|     } | ||||
| 
 | ||||
|     /// Steal a watchdog handle by index.
 | ||||
| @ -193,10 +204,33 @@ impl WatchdogHandle { | ||||
|     /// # Safety
 | ||||
|     /// Watchdog must be initialized and `index` must be between `0` and `N-1`
 | ||||
|     /// where `N` is the handle count when initializing.
 | ||||
|     pub unsafe fn steal(index: u8) -> Self { | ||||
|     pub unsafe fn steal<T: Instance>(index: u8) -> Self { | ||||
|         Self { | ||||
|             _wdt: PhantomData, | ||||
|             index, | ||||
|             index: T::INDEX * 8 + index, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub(crate) trait SealedInstance { | ||||
|     const REGS: pac::wdt::Wdt; | ||||
|     const INDEX: u8; | ||||
| } | ||||
| 
 | ||||
| /// WDT instance.
 | ||||
| #[allow(private_bounds)] | ||||
| pub trait Instance: SealedInstance + PeripheralType + 'static + Send { | ||||
|     /// Interrupt for this peripheral.
 | ||||
|     type Interrupt: interrupt::typelevel::Interrupt; | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_wdt { | ||||
|     ($type:ident, $pac_type:ident, $irq:ident, $index:literal) => { | ||||
|         impl crate::wdt::SealedInstance for peripherals::$type { | ||||
|             const REGS: pac::wdt::Wdt = pac::$pac_type; | ||||
|             const INDEX: u8 = $index; | ||||
|         } | ||||
|         impl crate::wdt::Instance for peripherals::$type { | ||||
|             type Interrupt = crate::interrupt::typelevel::$irq; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user