1139: Wdt config changes r=lulf a=huntc

Per commits:

* By passing WDT config around we can control it more easily and promote sharing it between files.

* The memory layout of the s140 crept into a number of memory files, which can cause confusion (well, it did for me!).

* Obtaining the current WDT config is useful so that we do not have to duplicate configurations around the place. A constructor method has been introduced that attempts to return the current running WDT config from the WDT peripheral. The bootloader example has also been updated to show how the watchdog can be obtained and used.

Co-authored-by: huntc <huntchr@gmail.com>
This commit is contained in:
bors[bot] 2023-01-04 07:44:23 +00:00 committed by GitHub
commit bf4c0de16a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 59 additions and 10 deletions

View File

@ -149,11 +149,7 @@ pub struct WatchdogFlash<'d> {
impl<'d> WatchdogFlash<'d> { impl<'d> WatchdogFlash<'d> {
/// Start a new watchdog with a given flash and WDT peripheral and a timeout /// 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 { pub fn start(flash: Nvmc<'d>, wdt: WDT, config: wdt::Config) -> 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;
let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) {
Ok(x) => x, Ok(x) => x,
Err(_) => { Err(_) => {

View File

@ -23,6 +23,30 @@ pub struct Config {
pub run_during_debug_halt: bool, 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<Self> {
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 { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {

View File

@ -32,3 +32,7 @@ cargo objcopy --release --bin b -- -O binary b.bin
``` ```
cargo flash --release --bin a --chip nRF52840_xxAA 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.

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
} }
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); __bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
FLASH : ORIGIN = 0x00007000, LENGTH = 64K FLASH : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
} }
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); __bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -8,6 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
use embassy_nrf::nvmc::Nvmc; use embassy_nrf::nvmc::Nvmc;
use embassy_nrf::wdt::{self, Watchdog};
use panic_reset as _; use panic_reset as _;
static APP_B: &[u8] = include_bytes!("../../b.bin"); 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 led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
//let mut button = Input::new(p.P1_02, Pull::Up); //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 nvmc = Nvmc::new(p.NVMC);
let mut nvmc = BlockingAsync::new(nvmc); let mut nvmc = BlockingAsync::new(nvmc);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
} }
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); __bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -5,7 +5,7 @@ MEMORY
BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
DFU : ORIGIN = 0x00017000, LENGTH = 68K DFU : ORIGIN = 0x00017000, LENGTH = 68K
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
} }
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); __bootloader_state_start = ORIGIN(BOOTLOADER_STATE);

View File

@ -6,6 +6,7 @@ use cortex_m_rt::{entry, exception};
use defmt_rtt as _; use defmt_rtt as _;
use embassy_boot_nrf::*; use embassy_boot_nrf::*;
use embassy_nrf::nvmc::Nvmc; use embassy_nrf::nvmc::Nvmc;
use embassy_nrf::wdt;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -20,8 +21,14 @@ fn main() -> ! {
*/ */
let mut bl = BootLoader::default(); 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( 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) } unsafe { bl.load(start) }
} }