Skip to content

Commit

Permalink
bootloader adaption
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed Sep 19, 2024
1 parent dfab81a commit a660b2c
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 147 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ debug-assertions = false # <-
lto = true
opt-level = 'z' # <-
overflow-checks = false # <-
# strip = true # Automatically strip symbols from the binary.
panic = "abort"
strip = true # Automatically strip symbols from the binary.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ example.

### Using VS Code

Assuming a working debug connection to your VA108xx board, you can debug using VS Code with
the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug). Please make sure that
[`objdump-multiarch` and `nm-multiarch`](https://forums.raspberrypi.com/viewtopic.php?t=333146)
Assuming a working debug connection to your VA416xx board, you can debug using VS Code with
the [`Cortex-Debug` plugin](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug).
Please make sure that [`objdump-multiarch` and `nm-multiarch`](https://forums.raspberrypi.com/viewtopic.php?t=333146)
are installed as well.

Some sample configuration files for VS code were provided and can be used by running
Expand Down
5 changes: 5 additions & 0 deletions bootloader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = "1"
panic-rtt-target = { version = "0.1.3" }
panic-halt = { version = "0.2" }
rtt-target = { version = "0.5" }
crc = "3"

[dependencies.va416xx-hal]
path = "../va416xx-hal"

[features]
default = ["rtt-panic"]
rtt-panic = []
44 changes: 30 additions & 14 deletions bootloader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

use cortex_m_rt::entry;
use crc::{Crc, CRC_32_ISO_HDLC};
#[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 va416xx_hal::{
Expand All @@ -42,6 +45,9 @@ const DEBUG_PRINTOUTS: bool = true;
// self-flash itself. It is recommended that you use a tool like probe-rs, Keil IDE, or a flash
// loader to boot a bootloader without this feature.
const FLASH_SELF: bool = false;
// Useful for debugging and see what the bootloader is doing. Enabled currently, because
// the binary stays small enough.
const RTT_PRINTOUT: bool = true;

// Important bootloader addresses and offsets, vector table information.

Expand Down Expand Up @@ -88,8 +94,10 @@ impl WdtInterface for OptWdt {

#[entry]
fn main() -> ! {
rtt_init_print!();
rprintln!("-- VA416xx bootloader --");
if RTT_PRINTOUT {
rtt_init_print!();
rprintln!("-- VA416xx bootloader --");
}
let mut dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
// Disable ROM protection.
Expand Down Expand Up @@ -133,18 +141,24 @@ fn main() -> ! {
nvm.write_data(0x0, &first_four_bytes);
nvm.write_data(0x4, bootloader_data);
if let Err(e) = nvm.verify_data(0x0, &first_four_bytes) {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
if RTT_PRINTOUT {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
}
}
if let Err(e) = nvm.verify_data(0x4, bootloader_data) {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
if RTT_PRINTOUT {
rprintln!("verification of self-flash to NVM failed: {:?}", e);
}
}

nvm.write_data(BOOTLOADER_CRC_ADDR, &bootloader_crc.to_be_bytes());
if let Err(e) = nvm.verify_data(BOOTLOADER_CRC_ADDR, &bootloader_crc.to_be_bytes()) {
rprintln!(
"error: CRC verification for bootloader self-flash failed: {:?}",
e
);
if RTT_PRINTOUT {
rprintln!(
"error: CRC verification for bootloader self-flash failed: {:?}",
e
);
}
}
}

Expand All @@ -156,7 +170,7 @@ fn main() -> ! {
} else if check_app_crc(AppSel::B, &opt_wdt) {
boot_app(AppSel::B, &cp)
} else {
if DEBUG_PRINTOUTS {
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.
Expand Down Expand Up @@ -184,7 +198,7 @@ fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
let crc_calc = digest.finalize();
wdt.feed();
if crc_exp == 0x0000 || crc_exp == 0xffff {
if DEBUG_PRINTOUTS {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("BL CRC blank - prog new CRC");
}
// Blank CRC, write it to NVM.
Expand All @@ -194,7 +208,7 @@ fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
// cortex_m::peripheral::SCB::sys_reset();
} else if crc_exp != crc_calc {
// Bootloader is corrupted. Try to run App A.
if DEBUG_PRINTOUTS {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!(
"bootloader CRC corrupt, read {} and expected {}. booting image A immediately",
crc_calc,
Expand All @@ -217,7 +231,7 @@ fn read_four_bytes_at_addr_zero(buf: &mut [u8; 4]) {
}
}
fn check_app_crc(app_sel: AppSel, wdt: &OptWdt) -> bool {
if DEBUG_PRINTOUTS {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("Checking image {:?}", app_sel);
}
if app_sel == AppSel::A {
Expand All @@ -237,7 +251,9 @@ fn check_app_given_addr(
let image_size = unsafe { (image_size_addr as *const u32).read_unaligned().to_be() };
// Sanity check.
if image_size > APP_A_END_ADDR - APP_A_START_ADDR - 8 {
rprintln!("detected invalid app size {}", image_size);
if RTT_PRINTOUT {
rprintln!("detected invalid app size {}", image_size);
}
return false;
}
wdt.feed();
Expand All @@ -252,7 +268,7 @@ fn check_app_given_addr(
}

fn boot_app(app_sel: AppSel, cp: &cortex_m::Peripherals) -> ! {
if DEBUG_PRINTOUTS {
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
rprintln!("booting app {:?}", app_sel);
}
let clkgen = unsafe { pac::Clkgen::steal() };
Expand Down
24 changes: 19 additions & 5 deletions examples/rtic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
#![no_main]
#![no_std]

use va416xx_hal::time::Hertz;

const EXTCLK_FREQ: Hertz = Hertz::from_raw(40_000_000);

#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
mod app {
use super::*;
use cortex_m::asm;
use embedded_hal::digital::StatefulOutputPin;
use panic_rtt_target as _;
Expand All @@ -13,6 +18,7 @@ mod app {
use va416xx_hal::{
gpio::{OutputReadablePushPull, Pin, PinsG, PG5},
pac,
prelude::*,
};

#[local]
Expand All @@ -23,14 +29,22 @@ mod app {
#[shared]
struct Shared {}

rtic_monotonics::systick_monotonic!(Mono, 10_000);
rtic_monotonics::systick_monotonic!(Mono, 1_000);

#[init]
fn init(_ctx: init::Context) -> (Shared, Local) {
fn init(mut cx: init::Context) -> (Shared, Local) {
rtt_init_default!();
rprintln!("-- Vorago RTIC template --");
let mut dp = pac::Peripherals::take().unwrap();
let portg = PinsG::new(&mut dp.sysconfig, dp.portg);
rprintln!("-- Vorago RTIC example application --");
// Use the external clock connected to XTAL_N.
let clocks = cx
.device
.clkgen
.constrain()
.xtal_n_clk_with_src_freq(EXTCLK_FREQ)
.freeze(&mut cx.device.sysconfig)
.unwrap();
Mono::start(cx.core.SYST, clocks.sysclk().raw());
let portg = PinsG::new(&mut cx.device.sysconfig, cx.device.portg);
let led = portg.pg5.into_readable_push_pull_output();
blinky::spawn().ok();
(Shared {}, Local { led })
Expand Down
42 changes: 19 additions & 23 deletions examples/simple/examples/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
//! If you do not use the loopback mode, MOSI and MISO need to be tied together on the board.
#![no_main]
#![no_std]

use cortex_m_rt::entry;
use embedded_hal::spi::{Mode, SpiBus, MODE_0};
use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print};
use simple_examples::peb1;
use va416xx_hal::spi::{clk_div_for_target_clock, Spi, TransferConfig};
use va416xx_hal::spi::{Spi, SpiClkConfig, TransferConfigWithHwcs};
use va416xx_hal::{
gpio::{PinsB, PinsC},
pac,
Expand All @@ -22,9 +21,8 @@ use va416xx_hal::{
pub enum ExampleSelect {
// Enter loopback mode. It is not necessary to tie MOSI/MISO together for this
Loopback,
// Send a test buffer and print everything received. You need to tie together MOSI/MISO in this
// mode.
TestBuffer,
// You need to tie together MOSI/MISO in this mode.
MosiMisoTiedTogether,
}

const EXAMPLE_SEL: ExampleSelect = ExampleSelect::Loopback;
Expand All @@ -50,21 +48,21 @@ fn main() -> ! {

let pins_b = PinsB::new(&mut dp.sysconfig, dp.portb);
let pins_c = PinsC::new(&mut dp.sysconfig, dp.portc);
// Configure SPI1 pins.
// Configure SPI0 pins.
let (sck, miso, mosi) = (
pins_b.pb15.into_funsel_1(),
pins_c.pc0.into_funsel_1(),
pins_c.pc1.into_funsel_1(),
);

let mut spi_cfg = SpiConfig::default().clk_div(
clk_div_for_target_clock(Hertz::from_raw(SPI_SPEED_KHZ), &clocks)
let mut spi_cfg = SpiConfig::default().clk_cfg(
SpiClkConfig::from_clk(Hertz::from_raw(SPI_SPEED_KHZ), &clocks)
.expect("invalid target clock"),
);
if EXAMPLE_SEL == ExampleSelect::Loopback {
spi_cfg = spi_cfg.loopback(true)
}
let transfer_cfg = TransferConfig::new_no_hw_cs(None, Some(SPI_MODE), BLOCKMODE, false);
let transfer_cfg = TransferConfigWithHwcs::new_no_hw_cs(None, Some(SPI_MODE), BLOCKMODE, false);
// Create SPI peripheral.
let mut spi0 = Spi::new(
&mut dp.sysconfig,
Expand All @@ -77,24 +75,22 @@ fn main() -> ! {
.expect("creating SPI peripheral failed");
spi0.set_fill_word(FILL_WORD);
loop {
let mut tx_buf: [u8; 3] = [1, 2, 3];
let mut rx_buf: [u8; 3] = [0; 3];
// Can't really verify correct reply here.
spi0.write(&[0x42]).expect("write failed");
// Need small delay.. otherwise we will read back the sent byte (which we don't want here).
// The write function will return as soon as all bytes were shifted out, ignoring the
// reply bytes.
delay_sysclk.delay_us(50);
// Because of the loopback mode, we should get back the fill word here.
spi0.read(&mut rx_buf[0..1]).unwrap();
assert_eq!(rx_buf[0], FILL_WORD);
let tx_buf: [u8; 4] = [1, 2, 3, 0];
let mut rx_buf: [u8; 4] = [0; 4];
// Can't really verify correct behaviour here. Just verify nothing crazy happens or it hangs up.
spi0.write(&[0x42, 0x43]).expect("write failed");

// Can't really verify correct behaviour here. Just verify nothing crazy happens or it hangs up.
spi0.read(&mut rx_buf[0..2]).unwrap();

spi0.transfer_in_place(&mut tx_buf)
let mut inplace_buf = tx_buf;
spi0.transfer_in_place(&mut inplace_buf)
.expect("SPI transfer_in_place failed");
assert_eq!([1, 2, 3], tx_buf);
assert_eq!([1, 2, 3, 0], inplace_buf);

spi0.transfer(&mut rx_buf, &tx_buf)
.expect("SPI transfer failed");
assert_eq!(rx_buf, tx_buf);
assert_eq!(rx_buf, [1, 2, 3, 0]);
delay_sysclk.delay_ms(500);
}
}
10 changes: 10 additions & 0 deletions va416xx-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

# [unreleased]

## Changed

- Simplification of clock configuration API for SPI HAL.

## Fixed

- Fixes for SPI peripheral: Flush implementation was incorrect and should now flush properly.
- Fixes for SPI example
- Fixes for RTIC example

# [v0.2.0] 2024-09-18

- Documentation improvements
Expand Down
Loading

0 comments on commit a660b2c

Please sign in to comment.