|
4 | 4 | use bootloader::NvmInterface;
|
5 | 5 | use cortex_m_rt::entry;
|
6 | 6 | use crc::{Crc, CRC_16_IBM_3740};
|
| 7 | +use embedded_hal::delay::DelayNs; |
7 | 8 | #[cfg(not(feature = "rtt-panic"))]
|
8 | 9 | use panic_halt as _;
|
9 | 10 | #[cfg(feature = "rtt-panic")]
|
10 | 11 | use panic_rtt_target as _;
|
11 | 12 | use rtt_target::{rprintln, rtt_init_print};
|
12 |
| -use va108xx_hal::{pac, time::Hertz}; |
| 13 | +use va108xx_hal::{pac, time::Hertz, timer::CountdownTimer}; |
13 | 14 | use vorago_reb1::m95m01::M95M01;
|
14 | 15 |
|
15 | 16 | // Useful for debugging and see what the bootloader is doing. Enabled currently, because
|
16 | 17 | // the binary stays small enough.
|
17 | 18 | const RTT_PRINTOUT: bool = true;
|
18 | 19 | const DEBUG_PRINTOUTS: bool = true;
|
| 20 | +// Small delay, allows RTT printout to catch up. |
| 21 | +const BOOT_DELAY_MS: u32 = 2000; |
19 | 22 |
|
20 | 23 | // Dangerous option! An image with this option set to true will flash itself from RAM directly
|
21 | 24 | // 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() -> ! {
|
99 | 102 | }
|
100 | 103 | let mut dp = pac::Peripherals::take().unwrap();
|
101 | 104 | let cp = cortex_m::Peripherals::take().unwrap();
|
| 105 | + let mut timer = CountdownTimer::new(&mut dp.sysconfig, CLOCK_FREQ, dp.tim0); |
102 | 106 |
|
103 | 107 | let mut nvm = M95M01::new(&mut dp.sysconfig, CLOCK_FREQ, dp.spic);
|
104 | 108 |
|
@@ -148,23 +152,28 @@ fn main() -> ! {
|
148 | 152 | let mut nvm = NvmWrapper(nvm);
|
149 | 153 |
|
150 | 154 | // Check bootloader's CRC (and write it if blank)
|
151 |
| - check_own_crc(&dp.sysconfig, &cp, &mut nvm); |
| 155 | + check_own_crc(&dp.sysconfig, &cp, &mut nvm, &mut timer); |
152 | 156 |
|
153 | 157 | if check_app_crc(AppSel::A) {
|
154 |
| - boot_app(&dp.sysconfig, &cp, AppSel::A) |
| 158 | + boot_app(&dp.sysconfig, &cp, AppSel::A, &mut timer) |
155 | 159 | } else if check_app_crc(AppSel::B) {
|
156 |
| - boot_app(&dp.sysconfig, &cp, AppSel::B) |
| 160 | + boot_app(&dp.sysconfig, &cp, AppSel::B, &mut timer) |
157 | 161 | } else {
|
158 | 162 | if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
159 | 163 | rprintln!("both images corrupt! booting image A");
|
160 | 164 | }
|
161 | 165 | // TODO: Shift a CCSDS packet out to inform host/OBC about image corruption.
|
162 | 166 | // Both images seem to be corrupt. Boot default image A.
|
163 |
| - boot_app(&dp.sysconfig, &cp, AppSel::A) |
| 167 | + boot_app(&dp.sysconfig, &cp, AppSel::A, &mut timer) |
164 | 168 | }
|
165 | 169 | }
|
166 | 170 |
|
167 |
| -fn check_own_crc(sysconfig: &pac::Sysconfig, cp: &cortex_m::Peripherals, nvm: &mut NvmWrapper) { |
| 171 | +fn check_own_crc( |
| 172 | + sysconfig: &pac::Sysconfig, |
| 173 | + cp: &cortex_m::Peripherals, |
| 174 | + nvm: &mut NvmWrapper, |
| 175 | + timer: &mut CountdownTimer<pac::Tim0>, |
| 176 | +) { |
168 | 177 | let crc_exp = unsafe { (BOOTLOADER_CRC_ADDR as *const u16).read_unaligned().to_be() };
|
169 | 178 | // I'd prefer to use [core::slice::from_raw_parts], but that is problematic
|
170 | 179 | // 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
|
200 | 209 | );
|
201 | 210 | }
|
202 | 211 | // TODO: Shift out minimal CCSDS frame to notify about bootloader corruption.
|
203 |
| - boot_app(sysconfig, cp, AppSel::A); |
| 212 | + boot_app(sysconfig, cp, AppSel::A, timer); |
204 | 213 | }
|
205 | 214 | }
|
206 | 215 |
|
@@ -249,10 +258,17 @@ fn check_app_given_addr(crc_addr: u32, start_addr: u32, image_size_addr: u32) ->
|
249 | 258 |
|
250 | 259 | // The boot works by copying the interrupt vector table (IVT) of the respective app to the
|
251 | 260 | // base address in code RAM (0x0) and then performing a soft reset.
|
252 |
| -fn boot_app(syscfg: &pac::Sysconfig, cp: &cortex_m::Peripherals, app_sel: AppSel) -> ! { |
| 261 | +fn boot_app( |
| 262 | + syscfg: &pac::Sysconfig, |
| 263 | + cp: &cortex_m::Peripherals, |
| 264 | + app_sel: AppSel, |
| 265 | + timer: &mut CountdownTimer<pac::Tim0>, |
| 266 | +) -> ! { |
253 | 267 | if DEBUG_PRINTOUTS && RTT_PRINTOUT {
|
254 | 268 | rprintln!("booting app {:?}", app_sel);
|
255 | 269 | }
|
| 270 | + timer.delay_ms(BOOT_DELAY_MS); |
| 271 | + |
256 | 272 | // Clear all interrupts set.
|
257 | 273 | unsafe {
|
258 | 274 | cp.NVIC.icer[0].write(0xFFFFFFFF);
|
@@ -302,7 +318,6 @@ fn soft_reset(cp: &cortex_m::Peripherals) -> ! {
|
302 | 318 | }
|
303 | 319 | // Ensure completion of memory access.
|
304 | 320 | cortex_m::asm::dsb();
|
305 |
| - rprintln!("soft reset done"); |
306 | 321 |
|
307 | 322 | // Loop until the reset occurs.
|
308 | 323 | loop {
|
|
0 commit comments