diff options
author | Ulf Lilleengen <ulf.lilleengen@gmail.com> | 2022-06-24 19:56:15 +0200 |
---|---|---|
committer | Ulf Lilleengen <ulf.lilleengen@gmail.com> | 2022-06-24 19:56:15 +0200 |
commit | 776be79f7bb10b09e795e2ea93bb795a653c9b4c (patch) | |
tree | 269046d330ee503c84049bb8fc47baf0297ecb80 /examples/boot/bootloader | |
parent | 84628d36cf743193cbf0e7d47ef1cfa9fb590890 (diff) | |
download | embassy-776be79f7bb10b09e795e2ea93bb795a653c9b4c.zip |
Move bootloader main to examples
This should remove some confusion around embassy-boot-* being a library
vs. a binary. The binary is now an example bootloader instead.
Diffstat (limited to 'examples/boot/bootloader')
-rw-r--r-- | examples/boot/bootloader/nrf/.cargo/config.toml | 20 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/Cargo.toml | 58 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/README.md | 11 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/build.rs | 37 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/memory-bm.x | 18 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/memory-s140.x | 31 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/memory.x | 18 | ||||
-rw-r--r-- | examples/boot/bootloader/nrf/src/main.rs | 48 | ||||
-rw-r--r-- | examples/boot/bootloader/stm32/Cargo.toml | 57 | ||||
-rw-r--r-- | examples/boot/bootloader/stm32/README.md | 11 | ||||
-rw-r--r-- | examples/boot/bootloader/stm32/build.rs | 32 | ||||
-rw-r--r-- | examples/boot/bootloader/stm32/memory.x | 18 | ||||
-rw-r--r-- | examples/boot/bootloader/stm32/src/main.rs | 46 |
13 files changed, 405 insertions, 0 deletions
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml new file mode 100644 index 00000000..1060800a --- /dev/null +++ b/examples/boot/bootloader/nrf/.cargo/config.toml @@ -0,0 +1,20 @@ +[unstable] +build-std = ["core"] +build-std-features = ["panic_immediate_abort"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +#runner = "./fruitrunner" +runner = "probe-run --chip nrf52840_xxAA" + +rustflags = [ + # Code-size optimizations. + "-Z", "trap-unreachable=no", + #"-C", "no-vectorize-loops", + "-C", "force-frame-pointers=yes", +] + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml new file mode 100644 index 00000000..8eb98623 --- /dev/null +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -0,0 +1,58 @@ +[package] +edition = "2021" +name = "nrf-bootloader-example" +version = "0.1.0" +description = "Bootloader for nRF chips" + +[dependencies] +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.3", optional = true } + +embassy = { path = "../../../../embassy", default-features = false } +embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } +embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } +cortex-m = { version = "0.7" } +cortex-m-rt = { version = "0.7" } +cfg-if = "1.0.0" + +[features] +defmt = [ + "dep:defmt", + "embassy-boot-nrf/defmt", + "embassy-nrf/defmt", +] +softdevice = [ + "embassy-boot-nrf/softdevice", +] +debug = ["defmt-rtt"] + +[profile.dev] +debug = 2 +debug-assertions = true +incremental = false +opt-level = 'z' +overflow-checks = true + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 'z' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false diff --git a/examples/boot/bootloader/nrf/README.md b/examples/boot/bootloader/nrf/README.md new file mode 100644 index 00000000..23497a03 --- /dev/null +++ b/examples/boot/bootloader/nrf/README.md @@ -0,0 +1,11 @@ +# Bootloader for nRF + +The bootloader uses `embassy-boot` to interact with the flash. + +# Usage + +Flash the bootloader + +``` +cargo flash --features embassy-nrf/nrf52832 --release --chip nRF52832_xxAA +``` diff --git a/examples/boot/bootloader/nrf/build.rs b/examples/boot/bootloader/nrf/build.rs new file mode 100644 index 00000000..e1da6932 --- /dev/null +++ b/examples/boot/bootloader/nrf/build.rs @@ -0,0 +1,37 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } +} diff --git a/examples/boot/bootloader/nrf/memory-bm.x b/examples/boot/bootloader/nrf/memory-bm.x new file mode 100644 index 00000000..8a32b905 --- /dev/null +++ b/examples/boot/bootloader/nrf/memory-bm.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K + ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K + DFU : ORIGIN = 0x00017000, LENGTH = 68K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); + +__bootloader_active_start = ORIGIN(ACTIVE); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE); + +__bootloader_dfu_start = ORIGIN(DFU); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); diff --git a/examples/boot/bootloader/nrf/memory-s140.x b/examples/boot/bootloader/nrf/memory-s140.x new file mode 100644 index 00000000..105db997 --- /dev/null +++ b/examples/boot/bootloader/nrf/memory-s140.x @@ -0,0 +1,31 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + MBR : ORIGIN = 0x00000000, LENGTH = 4K + SOFTDEVICE : ORIGIN = 0x00001000, LENGTH = 155648 + ACTIVE : ORIGIN = 0x00027000, LENGTH = 425984 + DFU : ORIGIN = 0x0008F000, LENGTH = 430080 + FLASH : ORIGIN = 0x000f9000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x000ff000, LENGTH = 4K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 0x2fff8 + uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4 +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); + +__bootloader_active_start = ORIGIN(ACTIVE); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE); + +__bootloader_dfu_start = ORIGIN(DFU); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); + +__bootloader_start = ORIGIN(FLASH); + +SECTIONS +{ + .uicr_bootloader_start_address : + { + LONG(__bootloader_start) + } > uicr_bootloader_start_address +} diff --git a/examples/boot/bootloader/nrf/memory.x b/examples/boot/bootloader/nrf/memory.x new file mode 100644 index 00000000..8a32b905 --- /dev/null +++ b/examples/boot/bootloader/nrf/memory.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K + ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K + DFU : ORIGIN = 0x00017000, LENGTH = 68K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE); + +__bootloader_active_start = ORIGIN(ACTIVE); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE); + +__bootloader_dfu_start = ORIGIN(DFU); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU); diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs new file mode 100644 index 00000000..bc7e0755 --- /dev/null +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::{entry, exception}; +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot_nrf::*; +use embassy_nrf::nvmc::Nvmc; + +#[entry] +fn main() -> ! { + let p = embassy_nrf::init(Default::default()); + + // Uncomment this if you are debugging the bootloader with debugger/RTT attached, + // as it prevents a hard fault when accessing flash 'too early' after boot. + /* + for i in 0..10000000 { + cortex_m::asm::nop(); + } + */ + + let mut bl = BootLoader::default(); + let start = bl.prepare(&mut SingleFlashProvider::new(&mut WatchdogFlash::start( + Nvmc::new(p.NVMC), + p.WDT, + 5, + ))); + unsafe { bl.load(start) } +} + +#[no_mangle] +#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +unsafe extern "C" fn HardFault() { + cortex_m::peripheral::SCB::sys_reset(); +} + +#[exception] +unsafe fn DefaultHandler(_: i16) -> ! { + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{:?}", irqn); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml new file mode 100644 index 00000000..b99a8fbc --- /dev/null +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -0,0 +1,57 @@ +[package] +edition = "2021" +name = "stm32-bootloader-example" +version = "0.1.0" +description = "Example bootloader for STM32 chips" + +[dependencies] +defmt = { version = "0.3", optional = true } +defmt-rtt = { version = "0.3", optional = true } + +embassy = { path = "../../../../embassy", default-features = false } +embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } +embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } +cortex-m = { version = "0.7" } +cortex-m-rt = { version = "0.7" } +embedded-storage = "0.3.0" +embedded-storage-async = "0.3.0" +cfg-if = "1.0.0" + +[features] +defmt = [ + "dep:defmt", + "embassy-boot-stm32/defmt", + "embassy-stm32/defmt", +] +debug = ["defmt-rtt"] + +[profile.dev] +debug = 2 +debug-assertions = true +incremental = false +opt-level = 'z' +overflow-checks = true + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = 'fat' +opt-level = 'z' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false diff --git a/examples/boot/bootloader/stm32/README.md b/examples/boot/bootloader/stm32/README.md new file mode 100644 index 00000000..a82b730b --- /dev/null +++ b/examples/boot/bootloader/stm32/README.md @@ -0,0 +1,11 @@ +# Bootloader for STM32 + +The bootloader uses `embassy-boot` to interact with the flash. + +# Usage + +Flash the bootloader + +``` +cargo flash --features embassy-stm32/stm32wl55jc-cm4 --release --chip STM32WLE5JCIx +``` diff --git a/examples/boot/bootloader/stm32/build.rs b/examples/boot/bootloader/stm32/build.rs new file mode 100644 index 00000000..3997702f --- /dev/null +++ b/examples/boot/bootloader/stm32/build.rs @@ -0,0 +1,32 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } + + let target = env::var("TARGET").unwrap(); + if target.starts_with("thumbv6m-") { + println!("cargo:rustc-cfg=armv6m"); + } +} diff --git a/examples/boot/bootloader/stm32/memory.x b/examples/boot/bootloader/stm32/memory.x new file mode 100644 index 00000000..110c2325 --- /dev/null +++ b/examples/boot/bootloader/stm32/memory.x @@ -0,0 +1,18 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x08000000, LENGTH = 24K + BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K + ACTIVE : ORIGIN = 0x08008000, LENGTH = 32K + DFU : ORIGIN = 0x08010000, LENGTH = 36K + RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K +} + +__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH); +__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH); + +__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH); +__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH); + +__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH); +__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH); diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs new file mode 100644 index 00000000..45c511ce --- /dev/null +++ b/examples/boot/bootloader/stm32/src/main.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::{entry, exception}; +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot_stm32::*; +use embassy_stm32::flash::{Flash, ERASE_SIZE}; + +#[entry] +fn main() -> ! { + let p = embassy_stm32::init(Default::default()); + + // Uncomment this if you are debugging the bootloader with debugger/RTT attached, + // as it prevents a hard fault when accessing flash 'too early' after boot. + /* + for i in 0..10000000 { + cortex_m::asm::nop(); + } + */ + + let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default(); + let mut flash = Flash::unlock(p.FLASH); + let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash)); + core::mem::drop(flash); + unsafe { bl.load(start) } +} + +#[no_mangle] +#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] +unsafe extern "C" fn HardFault() { + cortex_m::peripheral::SCB::sys_reset(); +} + +#[exception] +unsafe fn DefaultHandler(_: i16) -> ! { + const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; + let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; + + panic!("DefaultHandler #{:?}", irqn); +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + cortex_m::asm::udf(); +} |