From 776be79f7bb10b09e795e2ea93bb795a653c9b4c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 24 Jun 2022 19:56:15 +0200 Subject: 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. --- examples/boot/bootloader/stm32/Cargo.toml | 57 ++++++++++++++++++++++++++++++ examples/boot/bootloader/stm32/README.md | 11 ++++++ examples/boot/bootloader/stm32/build.rs | 32 +++++++++++++++++ examples/boot/bootloader/stm32/memory.x | 18 ++++++++++ examples/boot/bootloader/stm32/src/main.rs | 46 ++++++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 examples/boot/bootloader/stm32/Cargo.toml create mode 100644 examples/boot/bootloader/stm32/README.md create mode 100644 examples/boot/bootloader/stm32/build.rs create mode 100644 examples/boot/bootloader/stm32/memory.x create mode 100644 examples/boot/bootloader/stm32/src/main.rs (limited to 'examples/boot/bootloader/stm32') diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml new file mode 100644 index 000000000..b99a8fbcd --- /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 000000000..a82b730b9 --- /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 000000000..3997702f6 --- /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 000000000..110c23259 --- /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 000000000..45c511ced --- /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 = 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(); +} -- cgit