Add bootloader to CI
This commit is contained in:
parent
484e0acc63
commit
da61611f8f
34 changed files with 163 additions and 173 deletions
7
ci.sh
7
ci.sh
|
@ -58,6 +58,8 @@ cargo batch \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5ub,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5ub,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||||
|
--- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
@ -81,6 +83,11 @@ cargo batch \
|
||||||
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
||||||
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
||||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
||||||
|
--- build --release --manifest-path examples/boot/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/nrf --bin b \
|
||||||
|
--- build --release --manifest-path examples/boot/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/boot/stm32l0 --bin b \
|
||||||
|
--- build --release --manifest-path examples/boot/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/boot/stm32l1 --bin b \
|
||||||
|
--- build --release --manifest-path examples/boot/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32l4 --bin b \
|
||||||
|
--- build --release --manifest-path examples/boot/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/boot/stm32wl --bin b \
|
||||||
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/bluepill-stm32f103c8 \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/bluepill-stm32f103c8 \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/nucleo-stm32f429zi \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/nucleo-stm32f429zi \
|
||||||
|
|
|
@ -21,8 +21,3 @@ log = "0.4"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
futures = { version = "0.3", features = ["executor"] }
|
futures = { version = "0.3", features = ["executor"] }
|
||||||
|
|
||||||
[features]
|
|
||||||
write-4 = []
|
|
||||||
write-8 = []
|
|
||||||
invert-erase = []
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(generic_associated_types)]
|
#![feature(generic_associated_types)]
|
||||||
|
#![feature(generic_const_exprs)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
///! embassy-boot is a bootloader and firmware updater for embedded devices with flash
|
///! embassy-boot is a bootloader and firmware updater for embedded devices with flash
|
||||||
///! storage implemented using embedded-storage
|
///! storage implemented using embedded-storage
|
||||||
|
@ -17,24 +19,9 @@ mod fmt;
|
||||||
use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
||||||
use embedded_storage_async::nor_flash::AsyncNorFlash;
|
use embedded_storage_async::nor_flash::AsyncNorFlash;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "write-4", feature = "write-8",)))]
|
|
||||||
compile_error!("No write size/alignment specified. Must specify exactly one of the following features: write-4, write-8");
|
|
||||||
|
|
||||||
const BOOT_MAGIC: u8 = 0xD0;
|
const BOOT_MAGIC: u8 = 0xD0;
|
||||||
const SWAP_MAGIC: u8 = 0xF0;
|
const SWAP_MAGIC: u8 = 0xF0;
|
||||||
|
|
||||||
#[cfg(feature = "write-4")]
|
|
||||||
const WRITE_SIZE: usize = 4;
|
|
||||||
|
|
||||||
#[cfg(feature = "write-8")]
|
|
||||||
const WRITE_SIZE: usize = 8;
|
|
||||||
|
|
||||||
#[cfg(feature = "invert-erase")]
|
|
||||||
const ERASE_VALUE: u8 = 0x00;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "invert-erase"))]
|
|
||||||
const ERASE_VALUE: u8 = 0xFF;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Partition {
|
pub struct Partition {
|
||||||
|
@ -96,7 +83,7 @@ pub trait FlashProvider {
|
||||||
|
|
||||||
/// BootLoader works with any flash implementing embedded_storage and can also work with
|
/// BootLoader works with any flash implementing embedded_storage and can also work with
|
||||||
/// different page sizes and flash write sizes.
|
/// different page sizes and flash write sizes.
|
||||||
pub struct BootLoader<const PAGE_SIZE: usize> {
|
pub struct BootLoader<const PAGE_SIZE: usize, const WRITE_SIZE: usize, const ERASE_VALUE: u8> {
|
||||||
// Page with current state of bootloader. The state partition has the following format:
|
// Page with current state of bootloader. The state partition has the following format:
|
||||||
// | Range | Description |
|
// | Range | Description |
|
||||||
// | 0 - WRITE_SIZE | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
|
// | 0 - WRITE_SIZE | Magic indicating bootloader state. BOOT_MAGIC means boot, SWAP_MAGIC means swap. |
|
||||||
|
@ -108,7 +95,9 @@ pub struct BootLoader<const PAGE_SIZE: usize> {
|
||||||
dfu: Partition,
|
dfu: Partition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
|
impl<const PAGE_SIZE: usize, const WRITE_SIZE: usize, const ERASE_VALUE: u8>
|
||||||
|
BootLoader<PAGE_SIZE, WRITE_SIZE, ERASE_VALUE>
|
||||||
|
{
|
||||||
pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
|
pub fn new(active: Partition, dfu: Partition, state: Partition) -> Self {
|
||||||
assert_eq!(active.len() % PAGE_SIZE, 0);
|
assert_eq!(active.len() % PAGE_SIZE, 0);
|
||||||
assert_eq!(dfu.len() % PAGE_SIZE, 0);
|
assert_eq!(dfu.len() % PAGE_SIZE, 0);
|
||||||
|
@ -352,8 +341,6 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
|
||||||
self.copy_page_once_to_active(page * 2 + 1, dfu_page, active_page, p)?;
|
self.copy_page_once_to_active(page * 2 + 1, dfu_page, active_page, p)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("DONE COPYING");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +366,6 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
|
||||||
let flash = p.flash();
|
let flash = p.flash();
|
||||||
flash.read(self.state.from as u32, &mut magic)?;
|
flash.read(self.state.from as u32, &mut magic)?;
|
||||||
|
|
||||||
info!("Read magic: {:x}", magic);
|
|
||||||
if magic == [SWAP_MAGIC; WRITE_SIZE] {
|
if magic == [SWAP_MAGIC; WRITE_SIZE] {
|
||||||
Ok(State::Swap)
|
Ok(State::Swap)
|
||||||
} else {
|
} else {
|
||||||
|
@ -451,13 +437,9 @@ pub struct FirmwareUpdater {
|
||||||
dfu: Partition,
|
dfu: Partition,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "write-4")]
|
// NOTE: Aligned to the largest write size supported by flash
|
||||||
#[repr(align(4))]
|
#[repr(align(32))]
|
||||||
pub struct Aligned([u8; 4]);
|
pub struct Aligned<const N: usize>([u8; N]);
|
||||||
|
|
||||||
#[cfg(feature = "write-8")]
|
|
||||||
#[repr(align(8))]
|
|
||||||
pub struct Aligned([u8; 8]);
|
|
||||||
|
|
||||||
impl Default for FirmwareUpdater {
|
impl Default for FirmwareUpdater {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -480,6 +462,9 @@ impl Default for FirmwareUpdater {
|
||||||
&__bootloader_state_end as *const u32 as usize,
|
&__bootloader_state_end as *const u32 as usize,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
trace!("DFU: 0x{:x} - 0x{:x}", dfu.from, dfu.to);
|
||||||
|
trace!("STATE: 0x{:x} - 0x{:x}", state.from, state.to);
|
||||||
FirmwareUpdater::new(dfu, state)
|
FirmwareUpdater::new(dfu, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,14 +481,20 @@ impl FirmwareUpdater {
|
||||||
|
|
||||||
/// Instruct bootloader that DFU should commence at next boot.
|
/// Instruct bootloader that DFU should commence at next boot.
|
||||||
/// Must be provided with an aligned buffer to use for reading and writing magic;
|
/// Must be provided with an aligned buffer to use for reading and writing magic;
|
||||||
pub async fn mark_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error> {
|
pub async fn mark_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error>
|
||||||
let mut aligned = Aligned([0; WRITE_SIZE]);
|
where
|
||||||
|
[(); F::WRITE_SIZE]:,
|
||||||
|
{
|
||||||
|
let mut aligned = Aligned([0; { F::WRITE_SIZE }]);
|
||||||
self.set_magic(&mut aligned.0, SWAP_MAGIC, flash).await
|
self.set_magic(&mut aligned.0, SWAP_MAGIC, flash).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark firmware boot successfully
|
/// Mark firmware boot successfully
|
||||||
pub async fn mark_booted<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error> {
|
pub async fn mark_booted<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<(), F::Error>
|
||||||
let mut aligned = Aligned([0; WRITE_SIZE]);
|
where
|
||||||
|
[(); F::WRITE_SIZE]:,
|
||||||
|
{
|
||||||
|
let mut aligned = Aligned([0; { F::WRITE_SIZE }]);
|
||||||
self.set_magic(&mut aligned.0, BOOT_MAGIC, flash).await
|
self.set_magic(&mut aligned.0, BOOT_MAGIC, flash).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,7 +617,7 @@ mod tests {
|
||||||
flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
|
flash.0[0..4].copy_from_slice(&[BOOT_MAGIC; 4]);
|
||||||
let mut flash = SingleFlashProvider::new(&mut flash);
|
let mut flash = SingleFlashProvider::new(&mut flash);
|
||||||
|
|
||||||
let mut bootloader = BootLoader::<4096>::new(ACTIVE, DFU, STATE);
|
let mut bootloader = BootLoader::<4096, 4, 0xFF>::new(ACTIVE, DFU, STATE);
|
||||||
|
|
||||||
assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash).unwrap());
|
assert_eq!(State::Boot, bootloader.prepare_boot(&mut flash).unwrap());
|
||||||
}
|
}
|
||||||
|
@ -643,7 +634,7 @@ mod tests {
|
||||||
flash.0[i] = original[i - ACTIVE.from];
|
flash.0[i] = original[i - ACTIVE.from];
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bootloader = BootLoader::<4096>::new(ACTIVE, DFU, STATE);
|
let mut bootloader = BootLoader::<4096, 4, 0xFF>::new(ACTIVE, DFU, STATE);
|
||||||
let mut updater = FirmwareUpdater::new(DFU, STATE);
|
let mut updater = FirmwareUpdater::new(DFU, STATE);
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for chunk in update.chunks(4096) {
|
for chunk in update.chunks(4096) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmt-rtt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
embassy = { path = "../../embassy", default-features = false }
|
embassy = { path = "../../embassy", default-features = false }
|
||||||
embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
|
embassy-nrf = { path = "../../embassy-nrf", default-features = false, features = ["nightly"] }
|
||||||
embassy-boot = { path = "../boot", default-features = false, features = ["write-4"] }
|
embassy-boot = { path = "../boot", default-features = false }
|
||||||
cortex-m = { version = "0.7" }
|
cortex-m = { version = "0.7" }
|
||||||
cortex-m-rt = { version = "0.7" }
|
cortex-m-rt = { version = "0.7" }
|
||||||
embedded-storage = "0.3.0"
|
embedded-storage = "0.3.0"
|
||||||
|
|
|
@ -13,7 +13,7 @@ use embassy_nrf::{
|
||||||
use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
|
use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash};
|
||||||
|
|
||||||
pub struct BootLoader {
|
pub struct BootLoader {
|
||||||
boot: embassy_boot::BootLoader<PAGE_SIZE>,
|
boot: embassy_boot::BootLoader<PAGE_SIZE, 4, 0xFF>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BootLoader {
|
impl BootLoader {
|
||||||
|
|
|
@ -46,8 +46,5 @@ unsafe fn DefaultHandler(_: i16) -> ! {
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
unsafe {
|
cortex_m::asm::udf();
|
||||||
cortex_m::asm::udf();
|
|
||||||
core::hint::unreachable_unchecked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,10 +27,6 @@ defmt = [
|
||||||
"embassy-stm32/defmt",
|
"embassy-stm32/defmt",
|
||||||
]
|
]
|
||||||
debug = ["defmt-rtt"]
|
debug = ["defmt-rtt"]
|
||||||
flash-2k = ["embassy-boot/write-8"]
|
|
||||||
flash-128 = ["embassy-boot/write-4"]
|
|
||||||
flash-256 = ["embassy-boot/write-4"]
|
|
||||||
invert-erase = ["embassy-boot/invert-erase"]
|
|
||||||
thumbv6 = []
|
thumbv6 = []
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
@ -8,11 +8,11 @@ MEMORY
|
||||||
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
|
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
|
||||||
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
|
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
|
||||||
|
|
||||||
__bootloader_active_start = ORIGIN(ACTIVE);
|
__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
|
||||||
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
|
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
|
||||||
|
|
||||||
__bootloader_dfu_start = ORIGIN(DFU);
|
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH);
|
||||||
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
|
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH);
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
mod fmt;
|
mod fmt;
|
||||||
|
|
||||||
pub use embassy_boot::{FirmwareUpdater, FlashProvider, Partition, SingleFlashProvider, State};
|
pub use embassy_boot::{FirmwareUpdater, FlashProvider, Partition, SingleFlashProvider, State};
|
||||||
|
use embassy_stm32::flash::{ERASE_SIZE, ERASE_VALUE, WRITE_SIZE};
|
||||||
|
|
||||||
pub struct BootLoader<const PAGE_SIZE: usize> {
|
pub struct BootLoader {
|
||||||
boot: embassy_boot::BootLoader<PAGE_SIZE>,
|
boot: embassy_boot::BootLoader<ERASE_SIZE, WRITE_SIZE, ERASE_VALUE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
|
impl BootLoader {
|
||||||
/// Create a new bootloader instance using parameters from linker script
|
/// Create a new bootloader instance using parameters from linker script
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -65,6 +66,7 @@ impl<const PAGE_SIZE: usize> BootLoader<PAGE_SIZE> {
|
||||||
|
|
||||||
pub unsafe fn load(&mut self, start: usize) -> ! {
|
pub unsafe fn load(&mut self, start: usize) -> ! {
|
||||||
trace!("Loading app at 0x{:x}", start);
|
trace!("Loading app at 0x{:x}", start);
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut p = cortex_m::Peripherals::steal();
|
let mut p = cortex_m::Peripherals::steal();
|
||||||
#[cfg(not(feature = "thumbv6"))]
|
#[cfg(not(feature = "thumbv6"))]
|
||||||
p.SCB.invalidate_icache();
|
p.SCB.invalidate_icache();
|
||||||
|
|
|
@ -9,9 +9,6 @@ use defmt_rtt as _;
|
||||||
use embassy_boot_stm32::*;
|
use embassy_boot_stm32::*;
|
||||||
use embassy_stm32::flash::Flash;
|
use embassy_stm32::flash::Flash;
|
||||||
|
|
||||||
#[cfg(not(any(feature = "flash-2k", feature = "flash-256", feature = "flash-128")))]
|
|
||||||
compile_error!("No flash size specified. Must specify exactly one of the following features: flash-2k, flash-256, flash-128");
|
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = embassy_stm32::init(Default::default());
|
let p = embassy_stm32::init(Default::default());
|
||||||
|
@ -24,15 +21,7 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[cfg(feature = "flash-2k")]
|
let mut bl = BootLoader::default();
|
||||||
let mut bl: BootLoader<2048> = BootLoader::default();
|
|
||||||
|
|
||||||
#[cfg(feature = "flash-256")]
|
|
||||||
let mut bl: BootLoader<256> = BootLoader::default();
|
|
||||||
|
|
||||||
#[cfg(feature = "flash-128")]
|
|
||||||
let mut bl: BootLoader<128> = BootLoader::default();
|
|
||||||
|
|
||||||
let mut flash = Flash::unlock(p.FLASH);
|
let mut flash = Flash::unlock(p.FLASH);
|
||||||
let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash));
|
let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash));
|
||||||
core::mem::drop(flash);
|
core::mem::drop(flash);
|
||||||
|
@ -55,8 +44,5 @@ unsafe fn DefaultHandler(_: i16) -> ! {
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
unsafe {
|
cortex_m::asm::udf();
|
||||||
cortex_m::asm::udf();
|
|
||||||
core::hint::unreachable_unchecked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,59 +10,12 @@ use embedded_storage::nor_flash::{
|
||||||
ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
|
ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FLASH_BASE: usize = 0x8000000;
|
pub use crate::pac::ERASE_SIZE;
|
||||||
|
pub use crate::pac::ERASE_VALUE;
|
||||||
#[cfg(flash_l4)]
|
pub use crate::pac::FLASH_BASE;
|
||||||
mod config {
|
pub use crate::pac::FLASH_SIZE;
|
||||||
use super::*;
|
pub use crate::pac::WRITE_SIZE;
|
||||||
pub(crate) const FLASH_SIZE: usize = 0x100000;
|
const FLASH_END: usize = FLASH_BASE + FLASH_SIZE;
|
||||||
pub(crate) const FLASH_START: usize = FLASH_BASE;
|
|
||||||
pub(crate) const FLASH_END: usize = FLASH_START + FLASH_SIZE;
|
|
||||||
pub(crate) const PAGE_SIZE: usize = 2048;
|
|
||||||
pub(crate) const WORD_SIZE: usize = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(flash_wb)]
|
|
||||||
mod config {
|
|
||||||
use super::*;
|
|
||||||
pub(crate) const FLASH_SIZE: usize = 0x100000;
|
|
||||||
pub(crate) const FLASH_START: usize = FLASH_BASE;
|
|
||||||
pub(crate) const FLASH_END: usize = FLASH_START + FLASH_SIZE;
|
|
||||||
pub(crate) const PAGE_SIZE: usize = 4096;
|
|
||||||
pub(crate) const WORD_SIZE: usize = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(flash_wl)]
|
|
||||||
mod config {
|
|
||||||
use super::*;
|
|
||||||
pub(crate) const FLASH_SIZE: usize = 0x40000;
|
|
||||||
pub(crate) const FLASH_START: usize = FLASH_BASE;
|
|
||||||
pub(crate) const FLASH_END: usize = FLASH_START + FLASH_SIZE;
|
|
||||||
pub(crate) const PAGE_SIZE: usize = 2048;
|
|
||||||
pub(crate) const WORD_SIZE: usize = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(flash_l0)]
|
|
||||||
mod config {
|
|
||||||
use super::*;
|
|
||||||
pub(crate) const FLASH_SIZE: usize = 0x30000;
|
|
||||||
pub(crate) const FLASH_START: usize = FLASH_BASE;
|
|
||||||
pub(crate) const FLASH_END: usize = FLASH_START + FLASH_SIZE;
|
|
||||||
pub(crate) const PAGE_SIZE: usize = 128;
|
|
||||||
pub(crate) const WORD_SIZE: usize = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(flash_l1)]
|
|
||||||
mod config {
|
|
||||||
use super::*;
|
|
||||||
pub(crate) const FLASH_SIZE: usize = 0x80000;
|
|
||||||
pub(crate) const FLASH_START: usize = FLASH_BASE;
|
|
||||||
pub(crate) const FLASH_END: usize = FLASH_START + FLASH_SIZE;
|
|
||||||
pub(crate) const PAGE_SIZE: usize = 256;
|
|
||||||
pub(crate) const WORD_SIZE: usize = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
use config::*;
|
|
||||||
|
|
||||||
pub struct Flash<'d> {
|
pub struct Flash<'d> {
|
||||||
_inner: FLASH,
|
_inner: FLASH,
|
||||||
|
@ -114,6 +67,7 @@ impl<'d> Flash<'d> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
||||||
|
let offset = FLASH_BASE as u32 + offset;
|
||||||
if offset as usize >= FLASH_END || offset as usize + bytes.len() > FLASH_END {
|
if offset as usize >= FLASH_END || offset as usize + bytes.len() > FLASH_END {
|
||||||
return Err(Error::Size);
|
return Err(Error::Size);
|
||||||
}
|
}
|
||||||
|
@ -124,23 +78,25 @@ impl<'d> Flash<'d> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, offset: u32, buf: &[u8]) -> Result<(), Error> {
|
||||||
|
let offset = FLASH_BASE as u32 + offset;
|
||||||
if offset as usize + buf.len() > FLASH_END {
|
if offset as usize + buf.len() > FLASH_END {
|
||||||
return Err(Error::Size);
|
return Err(Error::Size);
|
||||||
}
|
}
|
||||||
if offset as usize % WORD_SIZE != 0 || buf.len() as usize % WORD_SIZE != 0 {
|
if offset as usize % WRITE_SIZE != 0 || buf.len() as usize % WRITE_SIZE != 0 {
|
||||||
return Err(Error::Unaligned);
|
return Err(Error::Unaligned);
|
||||||
}
|
}
|
||||||
|
trace!("Writing {} bytes at 0x{:x}", buf.len(), offset);
|
||||||
|
|
||||||
self.clear_all_err();
|
self.clear_all_err();
|
||||||
|
|
||||||
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
||||||
unsafe {
|
unsafe {
|
||||||
pac::FLASH.cr().write(|w| w.set_pg(true));
|
pac::FLASH.cr().write(|w| w.set_pg(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret: Result<(), Error> = Ok(());
|
let mut ret: Result<(), Error> = Ok(());
|
||||||
let mut offset = offset;
|
let mut offset = offset;
|
||||||
for chunk in buf.chunks(WORD_SIZE) {
|
for chunk in buf.chunks(WRITE_SIZE) {
|
||||||
for val in chunk.chunks(4) {
|
for val in chunk.chunks(4) {
|
||||||
unsafe {
|
unsafe {
|
||||||
write_volatile(
|
write_volatile(
|
||||||
|
@ -159,23 +115,25 @@ impl<'d> Flash<'d> {
|
||||||
|
|
||||||
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
||||||
unsafe {
|
unsafe {
|
||||||
pac::FLASH.cr().write(|w| w.set_pg(false));
|
pac::FLASH.cr().write(|w| w.set_pg(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
|
pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
|
||||||
|
let from = FLASH_BASE as u32 + from;
|
||||||
|
let to = FLASH_BASE as u32 + to;
|
||||||
if to < from || to as usize > FLASH_END {
|
if to < from || to as usize > FLASH_END {
|
||||||
return Err(Error::Size);
|
return Err(Error::Size);
|
||||||
}
|
}
|
||||||
if from as usize % PAGE_SIZE != 0 || to as usize % PAGE_SIZE != 0 {
|
if from as usize % ERASE_SIZE != 0 || to as usize % ERASE_SIZE != 0 {
|
||||||
return Err(Error::Unaligned);
|
return Err(Error::Unaligned);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clear_all_err();
|
self.clear_all_err();
|
||||||
|
|
||||||
for page in (from..to).step_by(PAGE_SIZE) {
|
for page in (from..to).step_by(ERASE_SIZE) {
|
||||||
#[cfg(any(flash_l0, flash_l1))]
|
#[cfg(any(flash_l0, flash_l1))]
|
||||||
unsafe {
|
unsafe {
|
||||||
pac::FLASH.pecr().modify(|w| {
|
pac::FLASH.pecr().modify(|w| {
|
||||||
|
@ -188,7 +146,7 @@ impl<'d> Flash<'d> {
|
||||||
|
|
||||||
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
#[cfg(any(flash_wl, flash_wb, flash_l4))]
|
||||||
unsafe {
|
unsafe {
|
||||||
let idx = page / PAGE_SIZE as u32;
|
let idx = page / ERASE_SIZE as u32;
|
||||||
|
|
||||||
pac::FLASH.cr().modify(|w| {
|
pac::FLASH.cr().modify(|w| {
|
||||||
w.set_per(true);
|
w.set_per(true);
|
||||||
|
@ -333,7 +291,7 @@ impl NorFlashError for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> ReadNorFlash for Flash<'d> {
|
impl<'d> ReadNorFlash for Flash<'d> {
|
||||||
const READ_SIZE: usize = WORD_SIZE;
|
const READ_SIZE: usize = WRITE_SIZE;
|
||||||
|
|
||||||
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_read(offset, bytes)
|
self.blocking_read(offset, bytes)
|
||||||
|
@ -345,8 +303,8 @@ impl<'d> ReadNorFlash for Flash<'d> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> NorFlash for Flash<'d> {
|
impl<'d> NorFlash for Flash<'d> {
|
||||||
const WRITE_SIZE: usize = WORD_SIZE;
|
const WRITE_SIZE: usize = WRITE_SIZE;
|
||||||
const ERASE_SIZE: usize = PAGE_SIZE;
|
const ERASE_SIZE: usize = ERASE_SIZE;
|
||||||
|
|
||||||
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||||
self.blocking_erase(from, to)
|
self.blocking_erase(from, to)
|
||||||
|
|
6
examples/boot/nrf/.cargo/config.toml
Normal file
6
examples/boot/nrf/.cargo/config.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
|
||||||
|
runner = "probe-run --chip nRF52840_xxAA"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "thumbv7em-none-eabi"
|
|
@ -6,7 +6,7 @@ version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
|
embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly", "nrf52840"] }
|
||||||
embassy-boot-nrf = { version = "0.1.0", path = "../../../embassy-boot/nrf" }
|
embassy-boot-nrf = { version = "0.1.0", path = "../../../embassy-boot/nrf" }
|
||||||
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,15 @@ application.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Flash bootloader
|
# Flash bootloader
|
||||||
cargo flash --manifest-path ../../embassy-boot/nrf/Cargo.toml --release --features embassy-nrf/nrf52840 --chip nRF52840_xxAA
|
cargo flash --manifest-path ../../../embassy-boot/nrf/Cargo.toml --features embassy-nrf/nrf52840 --release --chip nRF52840_xxAA
|
||||||
# Build 'b'
|
# Build 'b'
|
||||||
cargo build --release --features embassy-nrf/nrf52840 --bin b
|
cargo build --release --bin b
|
||||||
# Generate binary for 'b'
|
# Generate binary for 'b'
|
||||||
cargo objcopy --release --features embassy-nrf/nrf52840 --bin b -- -O binary b.bin
|
cargo objcopy --release --bin b -- -O binary b.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
# Flash `a` (which includes b.bin)
|
# Flash `a` (which includes b.bin)
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo flash --release --features embassy-nrf/nrf52840 --bin a --chip nRF52840_xxAA
|
cargo flash --release --bin a --chip nRF52840_xxAA
|
||||||
```
|
```
|
||||||
|
|
|
@ -7,7 +7,7 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32", features = ["flash-128", "invert-erase", "thumbv6"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32", features = ["thumbv6"] }
|
||||||
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
|
@ -15,7 +15,7 @@ application.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Flash bootloader
|
# Flash bootloader
|
||||||
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l072cz,flash-128,invert-erase,thumbv6 --chip STM32L072CZTx
|
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l072cz,thumbv6 --chip STM32L072CZTx
|
||||||
# Build 'b'
|
# Build 'b'
|
||||||
cargo build --release --bin b
|
cargo build --release --bin b
|
||||||
# Generate binary for 'b'
|
# Generate binary for 'b'
|
||||||
|
|
|
@ -8,8 +8,8 @@ MEMORY
|
||||||
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
|
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
|
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
|
|
||||||
__bootloader_dfu_start = ORIGIN(DFU);
|
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
|
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
|
||||||
|
|
|
@ -7,7 +7,7 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32", features = ["flash-256", "invert-erase"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32" }
|
||||||
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
|
@ -15,7 +15,7 @@ application.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Flash bootloader
|
# Flash bootloader
|
||||||
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l151cb-a,flash-256,invert-erase --chip STM32L151CBxxA
|
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l151cb-a --chip STM32L151CBxxA
|
||||||
# Build 'b'
|
# Build 'b'
|
||||||
cargo build --release --bin b
|
cargo build --release --bin b
|
||||||
# Generate binary for 'b'
|
# Generate binary for 'b'
|
||||||
|
|
|
@ -8,8 +8,8 @@ MEMORY
|
||||||
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
|
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
|
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
|
|
||||||
__bootloader_dfu_start = ORIGIN(DFU);
|
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
|
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
|
||||||
|
|
|
@ -7,7 +7,7 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32", features = ["flash-2k"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32" }
|
||||||
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
|
@ -15,7 +15,7 @@ application.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Flash bootloader
|
# Flash bootloader
|
||||||
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l475vg,flash-2k --chip STM32L475VG
|
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32l475vg --chip STM32L475VG
|
||||||
# Build 'b'
|
# Build 'b'
|
||||||
cargo build --release --bin b
|
cargo build --release --bin b
|
||||||
# Generate binary for 'b'
|
# Generate binary for 'b'
|
||||||
|
|
|
@ -5,11 +5,11 @@ MEMORY
|
||||||
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
|
BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
|
||||||
FLASH : ORIGIN = 0x08008000, LENGTH = 32K
|
FLASH : ORIGIN = 0x08008000, LENGTH = 32K
|
||||||
DFU : ORIGIN = 0x08010000, LENGTH = 36K
|
DFU : ORIGIN = 0x08010000, LENGTH = 36K
|
||||||
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 16K
|
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
|
||||||
}
|
}
|
||||||
|
|
||||||
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
|
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
|
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
|
|
||||||
__bootloader_dfu_start = ORIGIN(DFU);
|
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
|
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
|
||||||
|
|
|
@ -7,7 +7,7 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
embassy = { version = "0.1.0", path = "../../../embassy", features = ["nightly"] }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
|
embassy-stm32 = { version = "0.1.0", path = "../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
|
||||||
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32", features = ["flash-2k"] }
|
embassy-boot-stm32 = { version = "0.1.0", path = "../../../embassy-boot/stm32" }
|
||||||
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
embassy-traits = { version = "0.1.0", path = "../../../embassy-traits" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
|
@ -15,7 +15,7 @@ application.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Flash bootloader
|
# Flash bootloader
|
||||||
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4,flash-2k --chip STM32WLE5JCIx
|
cargo flash --manifest-path ../../../embassy-boot/stm32/Cargo.toml --release --features embassy-stm32/stm32wl55jc-cm4 --chip STM32WLE5JCIx
|
||||||
# Build 'b'
|
# Build 'b'
|
||||||
cargo build --release --bin b
|
cargo build --release --bin b
|
||||||
# Generate binary for 'b'
|
# Generate binary for 'b'
|
||||||
|
|
|
@ -8,8 +8,8 @@ MEMORY
|
||||||
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
|
RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K
|
||||||
}
|
}
|
||||||
|
|
||||||
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
|
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
|
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
|
||||||
|
|
||||||
__bootloader_dfu_start = ORIGIN(DFU);
|
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
|
||||||
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
|
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
|
||||||
|
|
|
@ -17,16 +17,18 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
|
||||||
|
|
||||||
#[embassy::main]
|
#[embassy::main]
|
||||||
async fn main(_s: embassy::executor::Spawner, p: Peripherals) {
|
async fn main(_s: embassy::executor::Spawner, p: Peripherals) {
|
||||||
let flash = Flash::new(p.FLASH);
|
let flash = Flash::unlock(p.FLASH);
|
||||||
let mut flash = BlockingAsync::new(flash);
|
let mut flash = BlockingAsync::new(flash);
|
||||||
|
|
||||||
let button = Input::new(p.PA0, Pull::Up);
|
let button = Input::new(p.PA0, Pull::Up);
|
||||||
let mut button = ExtiInput::new(button, p.EXTI0);
|
let mut button = ExtiInput::new(button, p.EXTI0);
|
||||||
|
|
||||||
let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
|
let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
|
||||||
|
led.set_high();
|
||||||
|
|
||||||
let mut updater = FirmwareUpdater::default();
|
let mut updater = FirmwareUpdater::default();
|
||||||
button.wait_for_falling_edge().await;
|
button.wait_for_falling_edge().await;
|
||||||
|
//defmt::info!("Starting update");
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for chunk in APP_B.chunks(2048) {
|
for chunk in APP_B.chunks(2048) {
|
||||||
let mut buf: [u8; 2048] = [0; 2048];
|
let mut buf: [u8; 2048] = [0; 2048];
|
||||||
|
@ -39,7 +41,7 @@ async fn main(_s: embassy::executor::Spawner, p: Peripherals) {
|
||||||
offset += chunk.len();
|
offset += chunk.len();
|
||||||
}
|
}
|
||||||
updater.mark_update(&mut flash).await.unwrap();
|
updater.mark_update(&mut flash).await.unwrap();
|
||||||
// defmt::info!("Marked as updated");
|
//defmt::info!("Marked as updated");
|
||||||
led.set_high();
|
led.set_low();
|
||||||
cortex_m::peripheral::SCB::sys_reset();
|
cortex_m::peripheral::SCB::sys_reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use panic_probe as _;
|
||||||
async fn main(_spawner: Spawner, p: Peripherals) {
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
info!("Hello Flash!");
|
info!("Hello Flash!");
|
||||||
|
|
||||||
const ADDR: u32 = 0x8026000;
|
const ADDR: u32 = 0x26000;
|
||||||
|
|
||||||
let mut f = Flash::unlock(p.FLASH);
|
let mut f = Flash::unlock(p.FLASH);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use panic_probe as _;
|
||||||
async fn main(_spawner: Spawner, p: Peripherals) {
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
info!("Hello Flash!");
|
info!("Hello Flash!");
|
||||||
|
|
||||||
const ADDR: u32 = 0x8026000;
|
const ADDR: u32 = 0x26000;
|
||||||
|
|
||||||
let mut f = Flash::unlock(p.FLASH);
|
let mut f = Flash::unlock(p.FLASH);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use panic_probe as _;
|
||||||
async fn main(_spawner: Spawner, p: Peripherals) {
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
info!("Hello Flash!");
|
info!("Hello Flash!");
|
||||||
|
|
||||||
const ADDR: u32 = 0x8036000;
|
const ADDR: u32 = 0x36000;
|
||||||
|
|
||||||
let mut f = Flash::unlock(p.FLASH);
|
let mut f = Flash::unlock(p.FLASH);
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 419701c835dd0da3c37d8de02c95115f500dfa6b
|
Subproject commit 5d25777521bfdb493674d43944b6df191606ef08
|
|
@ -16,6 +16,14 @@ pub struct MemoryRegion {
|
||||||
pub kind: MemoryRegionKind,
|
pub kind: MemoryRegionKind,
|
||||||
pub address: u32,
|
pub address: u32,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
|
pub settings: Option<FlashSettings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
||||||
|
pub struct FlashSettings {
|
||||||
|
pub erase_size: u32,
|
||||||
|
pub write_size: u32,
|
||||||
|
pub erase_value: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
||||||
|
|
|
@ -129,6 +129,40 @@ impl Gen {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
|
||||||
|
write!(
|
||||||
|
&mut extra,
|
||||||
|
"pub const FLASH_BASE: usize = {};\n",
|
||||||
|
flash.address,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
write!(
|
||||||
|
&mut extra,
|
||||||
|
"pub const FLASH_SIZE: usize = {};\n",
|
||||||
|
flash.size,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if let Some(settings) = &flash.settings {
|
||||||
|
write!(
|
||||||
|
&mut extra,
|
||||||
|
"pub const ERASE_SIZE: usize = {};\n",
|
||||||
|
settings.erase_size,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
write!(
|
||||||
|
&mut extra,
|
||||||
|
"pub const WRITE_SIZE: usize = {};\n",
|
||||||
|
settings.write_size,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
write!(
|
||||||
|
&mut extra,
|
||||||
|
"pub const ERASE_VALUE: u8 = {};\n",
|
||||||
|
settings.erase_value,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanups!
|
// Cleanups!
|
||||||
transform::sort::Sort {}.run(&mut ir).unwrap();
|
transform::sort::Sort {}.run(&mut ir).unwrap();
|
||||||
transform::Sanitize {}.run(&mut ir).unwrap();
|
transform::Sanitize {}.run(&mut ir).unwrap();
|
||||||
|
|
|
@ -15,6 +15,14 @@ pub struct MemoryRegion {
|
||||||
pub kind: MemoryRegionKind,
|
pub kind: MemoryRegionKind,
|
||||||
pub address: u32,
|
pub address: u32,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
|
pub settings: Option<FlashSettings>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct FlashSettings {
|
||||||
|
pub erase_size: u32,
|
||||||
|
pub write_size: u32,
|
||||||
|
pub erase_value: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
|
Loading…
Reference in a new issue