From e30d6d3f22437e3d5427bb5cf9ae8d76376e1751 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 30 Sep 2024 11:21:21 +0200 Subject: [PATCH] delay works --- bootloader/README.md | 4 +++- bootloader/src/main.rs | 33 ++++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/bootloader/README.md b/bootloader/README.md index 9d8f64f..dd89c67 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -22,7 +22,9 @@ The bootloader uses the following memory map: ## Additional Information This bootloader was specifically written for the REB1 board, so it assumes a M95M01 ST EEPROM -is used to load the application code. +is used to load the application code. The bootloader will also delay for a configurable amount +of time before booting. This allows to catch the RTT printout, but should probably be disabled +for production firmware. This bootloader does not provide tools to flash the NVM memory by itself. Instead, you can use the [flashloader](https://egit.irs.uni-stuttgart.de/rust/va108xx-rs/src/branch/main/flashloader) diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs index e68a938..2ac00f7 100644 --- a/bootloader/src/main.rs +++ b/bootloader/src/main.rs @@ -4,18 +4,21 @@ use bootloader::NvmInterface; use cortex_m_rt::entry; use crc::{Crc, CRC_16_IBM_3740}; +use embedded_hal::delay::DelayNs; #[cfg(not(feature = "rtt-panic"))] use panic_halt as _; #[cfg(feature = "rtt-panic")] use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; -use va108xx_hal::{pac, time::Hertz}; +use va108xx_hal::{pac, time::Hertz, timer::CountdownTimer}; use vorago_reb1::m95m01::M95M01; // Useful for debugging and see what the bootloader is doing. Enabled currently, because // the binary stays small enough. const RTT_PRINTOUT: bool = true; const DEBUG_PRINTOUTS: bool = true; +// Small delay, allows RTT printout to catch up. +const BOOT_DELAY_MS: u32 = 2000; // Dangerous option! An image with this option set to true will flash itself from RAM directly // into the NVM. This can be used as a recovery option from a direct RAM flash to fix the NVM @@ -99,6 +102,7 @@ fn main() -> ! { } let mut dp = pac::Peripherals::take().unwrap(); let cp = cortex_m::Peripherals::take().unwrap(); + let mut timer = CountdownTimer::new(&mut dp.sysconfig, CLOCK_FREQ, dp.tim0); let mut nvm = M95M01::new(&mut dp.sysconfig, CLOCK_FREQ, dp.spic); @@ -148,23 +152,28 @@ fn main() -> ! { let mut nvm = NvmWrapper(nvm); // Check bootloader's CRC (and write it if blank) - check_own_crc(&dp.sysconfig, &cp, &mut nvm); + check_own_crc(&dp.sysconfig, &cp, &mut nvm, &mut timer); if check_app_crc(AppSel::A) { - boot_app(&dp.sysconfig, &cp, AppSel::A) + boot_app(&dp.sysconfig, &cp, AppSel::A, &mut timer) } else if check_app_crc(AppSel::B) { - boot_app(&dp.sysconfig, &cp, AppSel::B) + boot_app(&dp.sysconfig, &cp, AppSel::B, &mut timer) } else { if DEBUG_PRINTOUTS && RTT_PRINTOUT { rprintln!("both images corrupt! booting image A"); } // TODO: Shift a CCSDS packet out to inform host/OBC about image corruption. // Both images seem to be corrupt. Boot default image A. - boot_app(&dp.sysconfig, &cp, AppSel::A) + boot_app(&dp.sysconfig, &cp, AppSel::A, &mut timer) } } -fn check_own_crc(sysconfig: &pac::Sysconfig, cp: &cortex_m::Peripherals, nvm: &mut NvmWrapper) { +fn check_own_crc( + sysconfig: &pac::Sysconfig, + cp: &cortex_m::Peripherals, + nvm: &mut NvmWrapper, + timer: &mut CountdownTimer, +) { let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u16).read_unaligned().to_be() }; // I'd prefer to use [core::slice::from_raw_parts], but that is problematic // because the address of the bootloader is 0x0, so the NULL check fails and the functions @@ -200,7 +209,7 @@ fn check_own_crc(sysconfig: &pac::Sysconfig, cp: &cortex_m::Peripherals, nvm: &m ); } // TODO: Shift out minimal CCSDS frame to notify about bootloader corruption. - boot_app(sysconfig, cp, AppSel::A); + boot_app(sysconfig, cp, AppSel::A, timer); } } @@ -249,10 +258,17 @@ fn check_app_given_addr(crc_addr: u32, start_addr: u32, image_size_addr: u32) -> // The boot works by copying the interrupt vector table (IVT) of the respective app to the // base address in code RAM (0x0) and then performing a soft reset. -fn boot_app(syscfg: &pac::Sysconfig, cp: &cortex_m::Peripherals, app_sel: AppSel) -> ! { +fn boot_app( + syscfg: &pac::Sysconfig, + cp: &cortex_m::Peripherals, + app_sel: AppSel, + timer: &mut CountdownTimer, +) -> ! { if DEBUG_PRINTOUTS && RTT_PRINTOUT { rprintln!("booting app {:?}", app_sel); } + timer.delay_ms(BOOT_DELAY_MS); + // Clear all interrupts set. unsafe { cp.NVIC.icer[0].write(0xFFFFFFFF); @@ -302,7 +318,6 @@ fn soft_reset(cp: &cortex_m::Peripherals) -> ! { } // Ensure completion of memory access. cortex_m::asm::dsb(); - rprintln!("soft reset done"); // Loop until the reset occurs. loop {