diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs index 205bbd6df..f40ae62d6 100644 --- a/embassy-boot/nrf/src/lib.rs +++ b/embassy-boot/nrf/src/lib.rs @@ -149,11 +149,7 @@ pub struct WatchdogFlash<'d> { impl<'d> WatchdogFlash<'d> { /// Start a new watchdog with a given flash and WDT peripheral and a timeout - pub fn start(flash: Nvmc<'d>, wdt: WDT, timeout: u32) -> Self { - let mut config = wdt::Config::default(); - config.timeout_ticks = 32768 * timeout; // timeout seconds - config.run_during_sleep = true; - config.run_during_debug_halt = false; + pub fn start(flash: Nvmc<'d>, wdt: WDT, config: wdt::Config) -> Self { let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { Ok(x) => x, Err(_) => { diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index 8760aa301..330ca98bf 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -23,6 +23,30 @@ pub struct Config { pub run_during_debug_halt: bool, } +impl Config { + /// Create a config structure from the current configuration of the WDT + /// peripheral. + pub fn try_new(_wdt: &peripherals::WDT) -> Option { + let r = unsafe { &*WDT::ptr() }; + + #[cfg(not(feature = "_nrf9160"))] + let runstatus = r.runstatus.read().runstatus().bit(); + #[cfg(feature = "_nrf9160")] + let runstatus = r.runstatus.read().runstatuswdt().bit(); + + if runstatus { + let config = r.config.read(); + Some(Self { + timeout_ticks: r.crv.read().bits(), + run_during_sleep: config.sleep().bit(), + run_during_debug_halt: config.halt().bit(), + }) + } else { + None + } + } +} + impl Default for Config { fn default() -> Self { Self { diff --git a/examples/boot/application/nrf/README.md b/examples/boot/application/nrf/README.md index 703377a20..a6719b505 100644 --- a/examples/boot/application/nrf/README.md +++ b/examples/boot/application/nrf/README.md @@ -32,3 +32,7 @@ cargo objcopy --release --bin b -- -O binary b.bin ``` cargo flash --release --bin a --chip nRF52840_xxAA ``` + +You should then see a solid LED. Pressing button 1 will cause the DFU to be loaded by the bootloader. Upon +successfully loading, you'll see the LED flash. After 5 seconds, because there is no petting of the watchdog, +you'll see the LED go solid again. This indicates that the bootloader has reverted the update. \ No newline at end of file diff --git a/examples/boot/application/nrf/memory-bl.x b/examples/boot/application/nrf/memory-bl.x index 8a32b905f..257d65644 100644 --- a/examples/boot/application/nrf/memory-bl.x +++ b/examples/boot/application/nrf/memory-bl.x @@ -5,7 +5,7 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K DFU : ORIGIN = 0x00017000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE); diff --git a/examples/boot/application/nrf/memory.x b/examples/boot/application/nrf/memory.x index 3a54ca460..c6926e422 100644 --- a/examples/boot/application/nrf/memory.x +++ b/examples/boot/application/nrf/memory.x @@ -5,7 +5,7 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K FLASH : ORIGIN = 0x00007000, LENGTH = 64K DFU : ORIGIN = 0x00017000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE); diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 7a404a914..83191f388 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -8,6 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::nvmc::Nvmc; +use embassy_nrf::wdt::{self, Watchdog}; use panic_reset as _; static APP_B: &[u8] = include_bytes!("../../b.bin"); @@ -20,6 +21,23 @@ async fn main(_spawner: Spawner) { //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); //let mut button = Input::new(p.P1_02, Pull::Up); + // The following code block illustrates how to obtain a watchdog that is configured + // as per the existing watchdog. Ordinarily, we'd use the handle returned to "pet" the + // watchdog periodically. If we don't, and we're not going to for this example, then + // the watchdog will cause the device to reset as per its configured timeout in the bootloader. + // This helps is avoid a situation where new firmware might be bad and block our executor. + // If firmware is bad in this way then the bootloader will revert to any previous version. + let wdt_config = wdt::Config::try_new(&p.WDT).unwrap(); + let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT, wdt_config) { + Ok(x) => x, + Err(_) => { + // Watchdog already active with the wrong number of handles, waiting for it to timeout... + loop { + cortex_m::asm::wfe(); + } + } + }; + let nvmc = Nvmc::new(p.NVMC); let mut nvmc = BlockingAsync::new(nvmc); diff --git a/examples/boot/bootloader/nrf/memory-bm.x b/examples/boot/bootloader/nrf/memory-bm.x index 8a32b905f..257d65644 100644 --- a/examples/boot/bootloader/nrf/memory-bm.x +++ b/examples/boot/bootloader/nrf/memory-bm.x @@ -5,7 +5,7 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K DFU : ORIGIN = 0x00017000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE); diff --git a/examples/boot/bootloader/nrf/memory.x b/examples/boot/bootloader/nrf/memory.x index 8a32b905f..257d65644 100644 --- a/examples/boot/bootloader/nrf/memory.x +++ b/examples/boot/bootloader/nrf/memory.x @@ -5,7 +5,7 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K DFU : ORIGIN = 0x00017000, LENGTH = 68K - RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE); diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 8266206b3..aca3b857a 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -6,6 +6,7 @@ use cortex_m_rt::{entry, exception}; use defmt_rtt as _; use embassy_boot_nrf::*; use embassy_nrf::nvmc::Nvmc; +use embassy_nrf::wdt; #[entry] fn main() -> ! { @@ -20,8 +21,14 @@ fn main() -> ! { */ let mut bl = BootLoader::default(); + + let mut wdt_config = wdt::Config::default(); + wdt_config.timeout_ticks = 32768 * 5; // timeout seconds + wdt_config.run_during_sleep = true; + wdt_config.run_during_debug_halt = false; + let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new( - WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, 5), + WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config), ))); unsafe { bl.load(start) } }