aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-09 15:07:25 +0000
committerGitHub <[email protected]>2022-02-09 15:07:25 +0000
commit3d6b8bd9832d5a29cab4aa21434663e6ea6f4488 (patch)
tree5e457a46c63f9565e82b9dd401701cbd7aba20b7 /examples
parentd91bd0b9a69b8411f2a1d58bfad5d4dce51e7110 (diff)
parente990021b9a9d3acc309c21bd4ddf3ff090bb7999 (diff)
Merge #604
604: Add embassy-boot r=lulf a=lulf Continuation of https://github.com/embassy-rs/embassy/pull/588 Embassy-boot is a simple bootloader that works together with an application to provide firmware update capabilities with a minimal risk. The bootloader consists of a platform-independent part, which implements the swap algorithm, and a platform-dependent part (currently only for nRF) that provides addition functionality such as watchdog timers softdevice support. The bootloader is intended to be configurable for different flash sizes and architectures, and only requires that embedded-storage flash traits are implemented. The nRF version can be configured programatically as a library, or using linker scripts to set the partition locations for DFU, ACTIVE and STATE * DFU: Where the next firmware version should be written. This is used by the FirmwareUpdater * ACTIVE: Where the current firmware version resides. Written by bootloader when swap magic is set * STATE: Contains the bootloader magic and the copy progress. Can be 1-N pages long (depending on how much flash you have which will determine the copy progress index size Co-authored-by: Ulf Lilleengen <[email protected]> Co-authored-by: Ulf Lilleengen <[email protected]>
Diffstat (limited to 'examples')
-rw-r--r--examples/boot/.cargo/config.toml7
-rw-r--r--examples/boot/Cargo.toml19
-rw-r--r--examples/boot/README.md31
-rw-r--r--examples/boot/build.rs34
-rw-r--r--examples/boot/memory.x14
-rw-r--r--examples/boot/src/bin/a.rs49
-rw-r--r--examples/boot/src/bin/b.rs26
7 files changed, 180 insertions, 0 deletions
diff --git a/examples/boot/.cargo/config.toml b/examples/boot/.cargo/config.toml
new file mode 100644
index 000000000..d044e9b4c
--- /dev/null
+++ b/examples/boot/.cargo/config.toml
@@ -0,0 +1,7 @@
1[unstable]
2namespaced-features = true
3build-std = ["core"]
4build-std-features = ["panic_immediate_abort"]
5
6[build]
7target = "thumbv7em-none-eabi"
diff --git a/examples/boot/Cargo.toml b/examples/boot/Cargo.toml
new file mode 100644
index 000000000..36e2e169d
--- /dev/null
+++ b/examples/boot/Cargo.toml
@@ -0,0 +1,19 @@
1[package]
2authors = ["Ulf Lilleengen <[email protected]>"]
3edition = "2018"
4name = "embassy-boot-examples"
5version = "0.1.0"
6
7[dependencies]
8embassy = { version = "0.1.0", path = "../../embassy" }
9embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["time-driver-rtc1", "gpiote"] }
10embassy-boot-nrf = { version = "0.1.0", path = "../../embassy-boot/nrf" }
11embassy-traits = { version = "0.1.0", path = "../../embassy-traits" }
12
13defmt = { version = "0.3", optional = true }
14defmt-rtt = { version = "0.3", optional = true }
15panic-reset = { version = "0.1.1" }
16embedded-hal = { version = "0.2.6" }
17
18cortex-m = "0.7.3"
19cortex-m-rt = "0.7.0"
diff --git a/examples/boot/README.md b/examples/boot/README.md
new file mode 100644
index 000000000..b97513a9d
--- /dev/null
+++ b/examples/boot/README.md
@@ -0,0 +1,31 @@
1# Examples using bootloader
2
3Example for nRF52 demonstrating the bootloader. The example consists of application binaries, 'a'
4which allows you to press a button to start the DFU process, and 'b' which is the updated
5application.
6
7
8## Prerequisites
9
10* `cargo-binutils`
11* `cargo-flash`
12* `embassy-boot-nrf`
13
14## Usage
15
16
17
18```
19# Flash bootloader
20cargo flash --manifest-path ../../embassy-boot/nrf/Cargo.toml --release --features embassy-nrf/nrf52840 --chip nRF52840_xxAA
21# Build 'b'
22cargo build --release --features embassy-nrf/nrf52840 --bin b
23# Generate binary for 'b'
24cargo objcopy --release --features embassy-nrf/nrf52840 --bin b -- -O binary b.bin
25```
26
27# Flash `a` (which includes b.bin)
28
29```
30cargo flash --release --features embassy-nrf/nrf52840 --bin a --chip nRF52840_xxAA
31```
diff --git a/examples/boot/build.rs b/examples/boot/build.rs
new file mode 100644
index 000000000..cd1a264c4
--- /dev/null
+++ b/examples/boot/build.rs
@@ -0,0 +1,34 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34}
diff --git a/examples/boot/memory.x b/examples/boot/memory.x
new file mode 100644
index 000000000..dfb72103f
--- /dev/null
+++ b/examples/boot/memory.x
@@ -0,0 +1,14 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
5 FLASH : ORIGIN = 0x00007000, LENGTH = 64K
6 DFU : ORIGIN = 0x00017000, LENGTH = 68K
7 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
8}
9
10__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
11__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
12
13__bootloader_dfu_start = ORIGIN(DFU);
14__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
diff --git a/examples/boot/src/bin/a.rs b/examples/boot/src/bin/a.rs
new file mode 100644
index 000000000..88880e688
--- /dev/null
+++ b/examples/boot/src/bin/a.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)]
6
7use embassy_boot_nrf::updater;
8use embassy_nrf::{
9 gpio::{Input, Pull},
10 gpio::{Level, Output, OutputDrive},
11 nvmc::Nvmc,
12 Peripherals,
13};
14use embassy_traits::adapter::BlockingAsync;
15use embedded_hal::digital::v2::InputPin;
16use panic_reset as _;
17
18static APP_B: &[u8] = include_bytes!("../../b.bin");
19
20#[embassy::main]
21async fn main(_s: embassy::executor::Spawner, p: Peripherals) {
22 let mut button = Input::new(p.P0_11, Pull::Up);
23 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
24 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
25 //let mut button = Input::new(p.P1_02, Pull::Up);
26
27 let nvmc = Nvmc::new(p.NVMC);
28 let mut nvmc = BlockingAsync::new(nvmc);
29
30 loop {
31 button.wait_for_any_edge().await;
32 if button.is_low().unwrap() {
33 let mut updater = updater::new();
34 let mut offset = 0;
35 for chunk in APP_B.chunks(4096) {
36 let mut buf: [u8; 4096] = [0; 4096];
37 buf[..chunk.len()].copy_from_slice(chunk);
38 updater
39 .write_firmware(offset, &buf, &mut nvmc)
40 .await
41 .unwrap();
42 offset += chunk.len();
43 }
44 updater.mark_update(&mut nvmc).await.unwrap();
45 led.set_high();
46 cortex_m::peripheral::SCB::sys_reset();
47 }
48 }
49}
diff --git a/examples/boot/src/bin/b.rs b/examples/boot/src/bin/b.rs
new file mode 100644
index 000000000..18bb6330c
--- /dev/null
+++ b/examples/boot/src/bin/b.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)]
6
7use embassy::time::{Duration, Timer};
8use embassy_nrf::{
9 gpio::{Level, Output, OutputDrive},
10 Peripherals,
11};
12
13use panic_reset as _;
14
15#[embassy::main]
16async fn main(_s: embassy::executor::Spawner, p: Peripherals) {
17 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
18 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
19
20 loop {
21 led.set_high();
22 Timer::after(Duration::from_millis(300)).await;
23 led.set_low();
24 Timer::after(Duration::from_millis(300)).await;
25 }
26}