aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
committerDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
commit4f2c36e447455e8d33607d586859d3d075cabf1d (patch)
tree003cd822d688acd7c074dd229663b4648d100f71 /docs
parent663732d85abbae400f2dbab2c411802a5b60e9b1 (diff)
parent661874d11de7d93ed52e08e020a9d4c7ee11122d (diff)
Merge branch 'main' into u0-lcd
Diffstat (limited to 'docs')
-rw-r--r--docs/examples/basic/.cargo/config.toml4
-rw-r--r--docs/examples/basic/Cargo.toml20
-rw-r--r--docs/examples/basic/src/main.rs33
-rw-r--r--docs/examples/layer-by-layer/.cargo/config.toml3
-rw-r--r--docs/examples/layer-by-layer/Cargo.toml5
-rw-r--r--docs/examples/layer-by-layer/blinky-async/Cargo.toml20
-rw-r--r--docs/examples/layer-by-layer/blinky-hal/Cargo.toml18
-rw-r--r--docs/examples/layer-by-layer/blinky-irq/Cargo.toml20
-rw-r--r--docs/examples/layer-by-layer/blinky-pac/Cargo.toml18
-rw-r--r--docs/examples/layer-by-layer/blinky-pac/src/main.rs48
-rw-r--r--docs/examples/layer-by-layer/memory.x5
-rw-r--r--docs/index.adoc1
-rw-r--r--docs/pages/basic_application.adoc2
-rw-r--r--docs/pages/best_practices.adoc2
-rw-r--r--docs/pages/bootloader.adoc18
-rw-r--r--docs/pages/embassy_in_the_wild.adoc19
-rw-r--r--docs/pages/faq.adoc146
-rw-r--r--docs/pages/getting_started.adoc4
-rw-r--r--docs/pages/hal.adoc6
-rw-r--r--docs/pages/imxrt.adoc16
-rw-r--r--docs/pages/layer_by_layer.adoc4
-rw-r--r--docs/pages/new_project.adoc28
-rw-r--r--docs/pages/nrf.adoc2
-rw-r--r--docs/pages/overview.adoc20
-rw-r--r--docs/pages/project_structure.adoc4
-rw-r--r--docs/pages/sharing_peripherals.adoc18
-rw-r--r--docs/pages/stm32.adoc2
-rw-r--r--docs/pages/system.adoc1
-rw-r--r--docs/pages/time_keeping.adoc4
29 files changed, 330 insertions, 161 deletions
diff --git a/docs/examples/basic/.cargo/config.toml b/docs/examples/basic/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/docs/examples/basic/.cargo/config.toml
+++ b/docs/examples/basic/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
index e82165032..fadda102b 100644
--- a/docs/examples/basic/Cargo.toml
+++ b/docs/examples/basic/Cargo.toml
@@ -1,18 +1,24 @@
1[package] 1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"] 2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018" 3edition = "2024"
4name = "embassy-basic-example" 4name = "embassy-basic-example"
5version = "0.1.0" 5version = "0.1.0"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8publish = false
8[dependencies] 9[dependencies]
9embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } 10embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt"] } 11embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] }
11embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 12embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
12 13
13defmt = "0.3" 14defmt = "1.0.1"
14defmt-rtt = "0.3" 15defmt-rtt = "1.0.0"
15 16
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "1.0.0", features = ["print-defmt"] }
20
21[package.metadata.embassy]
22build = [
23 { target = "thumbv7em-none-eabi" }
24]
diff --git a/docs/examples/basic/src/main.rs b/docs/examples/basic/src/main.rs
index 4412712c8..42797612c 100644
--- a/docs/examples/basic/src/main.rs
+++ b/docs/examples/basic/src/main.rs
@@ -3,24 +3,41 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive}; 6use embassy_nrf::Peri;
7use embassy_time::{Duration, Timer}; 7use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pull};
8use {defmt_rtt as _, panic_probe as _}; // global logger 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _};
9 10
11// Declare async tasks
10#[embassy_executor::task] 12#[embassy_executor::task]
11async fn blinker(mut led: Output<'static>, interval: Duration) { 13async fn blink(pin: Peri<'static, AnyPin>) {
14 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
15
12 loop { 16 loop {
17 // Timekeeping is globally available, no need to mess with hardware timers.
13 led.set_high(); 18 led.set_high();
14 Timer::after(interval).await; 19 Timer::after_millis(150).await;
15 led.set_low(); 20 led.set_low();
16 Timer::after(interval).await; 21 Timer::after_millis(150).await;
17 } 22 }
18} 23}
19 24
25// Main is itself an async task as well.
20#[embassy_executor::main] 26#[embassy_executor::main]
21async fn main(spawner: Spawner) { 27async fn main(spawner: Spawner) {
28 // Initialize the embassy-nrf HAL.
22 let p = embassy_nrf::init(Default::default()); 29 let p = embassy_nrf::init(Default::default());
23 30
24 let led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 31 // Spawned tasks run in the background, concurrently.
25 unwrap!(spawner.spawn(blinker(led, Duration::from_millis(300)))); 32 spawner.spawn(blink(p.P0_13.into()).unwrap());
33
34 let mut button = Input::new(p.P0_11, Pull::Up);
35 loop {
36 // Asynchronously wait for GPIO events, allowing other tasks
37 // to run, or the core to sleep.
38 button.wait_for_low().await;
39 info!("Button pressed!");
40 button.wait_for_high().await;
41 info!("Button released!");
42 }
26} 43}
diff --git a/docs/examples/layer-by-layer/.cargo/config.toml b/docs/examples/layer-by-layer/.cargo/config.toml
index 3012f05dc..f30d9e446 100644
--- a/docs/examples/layer-by-layer/.cargo/config.toml
+++ b/docs/examples/layer-by-layer/.cargo/config.toml
@@ -1,5 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip STM32L475VG" 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32L475VG"
3 4
4rustflags = [ 5rustflags = [
5 "-C", "link-arg=--nmagic", 6 "-C", "link-arg=--nmagic",
diff --git a/docs/examples/layer-by-layer/Cargo.toml b/docs/examples/layer-by-layer/Cargo.toml
index 0f233eae5..01666ec6e 100644
--- a/docs/examples/layer-by-layer/Cargo.toml
+++ b/docs/examples/layer-by-layer/Cargo.toml
@@ -3,14 +3,9 @@ resolver = "2"
3members = [ 3members = [
4 "blinky-pac", 4 "blinky-pac",
5 "blinky-hal", 5 "blinky-hal",
6 "blinky-irq",
7 "blinky-async", 6 "blinky-async",
8] 7]
9 8
10[patch.crates-io]
11embassy-executor = { path = "../../../embassy-executor" }
12embassy-stm32 = { path = "../../../embassy-stm32" }
13
14[profile.release] 9[profile.release]
15codegen-units = 1 10codegen-units = 1
16debug = 2 11debug = 2
diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
index 64f7e8403..797ae3097 100644
--- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
@@ -1,15 +1,21 @@
1[package] 1[package]
2name = "blinky-async" 2name = "blinky-async"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7publish = false
7[dependencies] 8[dependencies]
8cortex-m = "0.7" 9cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
9cortex-m-rt = "0.7" 10cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } 11embassy-stm32 = { version = "0.4.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "exti"] }
11embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] } 12embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] }
12 13
13defmt = "0.3.0" 14defmt = "1.0.1"
14defmt-rtt = "0.3.0" 15defmt-rtt = "1.0.0"
15panic-probe = { version = "0.3.0", features = ["print-defmt"] } 16panic-probe = { version = "1.0.0", features = ["print-defmt"] }
17
18[package.metadata.embassy]
19build = [
20 { target = "thumbv7em-none-eabi" }
21]
diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml
index c15de2db2..802b8b32e 100644
--- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml
@@ -1,14 +1,20 @@
1[package] 1[package]
2name = "blinky-hal" 2name = "blinky-hal"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7publish = false
7[dependencies] 8[dependencies]
8cortex-m = "0.7"
9cortex-m-rt = "0.7" 9cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x"] } 10cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
11embassy-stm32 = { version = "0.4.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x"] }
11 12
12defmt = "0.3.0" 13defmt = "1.0.1"
13defmt-rtt = "0.3.0" 14defmt-rtt = "1.0.0"
14panic-probe = { version = "0.3.0", features = ["print-defmt"] } 15panic-probe = { version = "1.0.0", features = ["print-defmt"] }
16
17[package.metadata.embassy]
18build = [
19 { target = "thumbv7em-none-eabi" }
20]
diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml
index 9733658b6..d1b893a1e 100644
--- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml
@@ -1,14 +1,22 @@
1[workspace]
2
1[package] 3[package]
2name = "blinky-irq" 4name = "blinky-irq"
3version = "0.1.0" 5version = "0.1.0"
4edition = "2021" 6edition = "2024"
5license = "MIT OR Apache-2.0" 7license = "MIT OR Apache-2.0"
6 8
9publish = false
7[dependencies] 10[dependencies]
8cortex-m = "0.7" 11cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
9cortex-m-rt = { version = "0.7" } 12cortex-m-rt = { version = "0.7" }
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "unstable-pac"] } 13embassy-stm32 = { version = "0.4.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "unstable-pac"] }
14
15defmt = "1.0.1"
16defmt-rtt = "1.0.0"
17panic-probe = { version = "1.0.0", features = ["print-defmt"] }
11 18
12defmt = "0.3.0" 19[package.metadata.embassy]
13defmt-rtt = "0.3.0" 20build = [
14panic-probe = { version = "0.3.0", features = ["print-defmt"] } 21 { target = "thumbv7em-none-eabi" }
22]
diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml
index f872b94cb..fa093a3af 100644
--- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml
@@ -1,14 +1,20 @@
1[package] 1[package]
2name = "blinky-pac" 2name = "blinky-pac"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7publish = false
7[dependencies] 8[dependencies]
8cortex-m = "0.7" 9cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
9cortex-m-rt = "0.7" 10cortex-m-rt = "0.7"
10stm32-metapac = { version = "1", features = ["stm32l475vg", "memory-x"] } 11stm32-metapac = { version = "16", features = ["stm32l475vg"] }
11 12
12defmt = "0.3.0" 13defmt = "1.0.1"
13defmt-rtt = "0.3.0" 14defmt-rtt = "1.0.0"
14panic-probe = { version = "0.3.0", features = ["print-defmt"] } 15panic-probe = { version = "1.0.0", features = ["print-defmt"] }
16
17[package.metadata.embassy]
18build = [
19 { target = "thumbv7em-none-eabi" }
20]
diff --git a/docs/examples/layer-by-layer/blinky-pac/src/main.rs b/docs/examples/layer-by-layer/blinky-pac/src/main.rs
index 990d46cb6..cfbd91306 100644
--- a/docs/examples/layer-by-layer/blinky-pac/src/main.rs
+++ b/docs/examples/layer-by-layer/blinky-pac/src/main.rs
@@ -8,46 +8,38 @@ use {defmt_rtt as _, panic_probe as _, stm32_metapac as pac};
8fn main() -> ! { 8fn main() -> ! {
9 // Enable GPIO clock 9 // Enable GPIO clock
10 let rcc = pac::RCC; 10 let rcc = pac::RCC;
11 unsafe { 11 rcc.ahb2enr().modify(|w| {
12 rcc.ahb2enr().modify(|w| { 12 w.set_gpioben(true);
13 w.set_gpioben(true); 13 w.set_gpiocen(true);
14 w.set_gpiocen(true); 14 });
15 });
16 15
17 rcc.ahb2rstr().modify(|w| { 16 rcc.ahb2rstr().modify(|w| {
18 w.set_gpiobrst(true); 17 w.set_gpiobrst(true);
19 w.set_gpiocrst(true); 18 w.set_gpiocrst(true);
20 w.set_gpiobrst(false); 19 w.set_gpiobrst(false);
21 w.set_gpiocrst(false); 20 w.set_gpiocrst(false);
22 }); 21 });
23 }
24 22
25 // Setup button 23 // Setup button
26 let gpioc = pac::GPIOC; 24 let gpioc = pac::GPIOC;
27 const BUTTON_PIN: usize = 13; 25 const BUTTON_PIN: usize = 13;
28 unsafe { 26 gpioc.pupdr().modify(|w| w.set_pupdr(BUTTON_PIN, vals::Pupdr::PULL_UP));
29 gpioc.pupdr().modify(|w| w.set_pupdr(BUTTON_PIN, vals::Pupdr::PULLUP)); 27 gpioc.otyper().modify(|w| w.set_ot(BUTTON_PIN, vals::Ot::PUSH_PULL));
30 gpioc.otyper().modify(|w| w.set_ot(BUTTON_PIN, vals::Ot::PUSHPULL)); 28 gpioc.moder().modify(|w| w.set_moder(BUTTON_PIN, vals::Moder::INPUT));
31 gpioc.moder().modify(|w| w.set_moder(BUTTON_PIN, vals::Moder::INPUT));
32 }
33 29
34 // Setup LED 30 // Setup LED
35 let gpiob = pac::GPIOB; 31 let gpiob = pac::GPIOB;
36 const LED_PIN: usize = 14; 32 const LED_PIN: usize = 14;
37 unsafe { 33 gpiob.pupdr().modify(|w| w.set_pupdr(LED_PIN, vals::Pupdr::FLOATING));
38 gpiob.pupdr().modify(|w| w.set_pupdr(LED_PIN, vals::Pupdr::FLOATING)); 34 gpiob.otyper().modify(|w| w.set_ot(LED_PIN, vals::Ot::PUSH_PULL));
39 gpiob.otyper().modify(|w| w.set_ot(LED_PIN, vals::Ot::PUSHPULL)); 35 gpiob.moder().modify(|w| w.set_moder(LED_PIN, vals::Moder::OUTPUT));
40 gpiob.moder().modify(|w| w.set_moder(LED_PIN, vals::Moder::OUTPUT));
41 }
42 36
43 // Main loop 37 // Main loop
44 loop { 38 loop {
45 unsafe { 39 if gpioc.idr().read().idr(BUTTON_PIN) == vals::Idr::LOW {
46 if gpioc.idr().read().idr(BUTTON_PIN) == vals::Idr::LOW { 40 gpiob.bsrr().write(|w| w.set_bs(LED_PIN, true));
47 gpiob.bsrr().write(|w| w.set_bs(LED_PIN, true)); 41 } else {
48 } else { 42 gpiob.bsrr().write(|w| w.set_br(LED_PIN, true));
49 gpiob.bsrr().write(|w| w.set_br(LED_PIN, true));
50 }
51 } 43 }
52 } 44 }
53} 45}
diff --git a/docs/examples/layer-by-layer/memory.x b/docs/examples/layer-by-layer/memory.x
new file mode 100644
index 000000000..69f5b28a1
--- /dev/null
+++ b/docs/examples/layer-by-layer/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 */
4 RAM : ORIGIN = 0x20000000, LENGTH = 640K /* SRAM */
5}
diff --git a/docs/index.adoc b/docs/index.adoc
index 9c6150196..80754d5a4 100644
--- a/docs/index.adoc
+++ b/docs/index.adoc
@@ -5,6 +5,7 @@
5:toc-placement: left 5:toc-placement: left
6:toclevels: 2 6:toclevels: 2
7:imagesdir: images 7:imagesdir: images
8:source-highlighter: rouge
8 9
9# Embassy Book 10# Embassy Book
10 11
diff --git a/docs/pages/basic_application.adoc b/docs/pages/basic_application.adoc
index 7b4ebda4f..5c4e3e8b3 100644
--- a/docs/pages/basic_application.adoc
+++ b/docs/pages/basic_application.adoc
@@ -4,7 +4,7 @@ So you've got one of the examples running, but what now? Let's go through a simp
4 4
5== Main 5== Main
6 6
7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here]. 7The full example can be found link:https://github.com/embassy-rs/embassy/tree/main/docs/examples/basic[here].
8 8
9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly. 9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
10 10
diff --git a/docs/pages/best_practices.adoc b/docs/pages/best_practices.adoc
index bfcedec06..eabaa9eb9 100644
--- a/docs/pages/best_practices.adoc
+++ b/docs/pages/best_practices.adoc
@@ -35,7 +35,7 @@ After the processing, another 1024 byte buffer will be placed on the stack to be
35 35
36Pass the data by reference and not by value on both, the way in and the way out. 36Pass the data by reference and not by value on both, the way in and the way out.
37For example, you could return a slice of the input buffer as the output. 37For example, you could return a slice of the input buffer as the output.
38Requiring the lifetime of the input slice and the output slice to be the same, the memory safetly of this procedure will be enforced by the compiler. 38Requiring the lifetime of the input slice and the output slice to be the same, the memory safety of this procedure will be enforced by the compiler.
39 39
40[,rust] 40[,rust]
41---- 41----
diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc
index 3b0cdb182..c010b0622 100644
--- a/docs/pages/bootloader.adoc
+++ b/docs/pages/bootloader.adoc
@@ -2,6 +2,13 @@
2 2
3`embassy-boot` a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. 3`embassy-boot` a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
4 4
5The update method used is referred to as an A/B partition update scheme.
6
7With a general-purpose OS, A/B partition update is accomplished by directly booting either the A or B partition depending on the update state.
8To accomplish the same goal in a way that is portable across all microcontrollers, `embassy-boot` swaps data page by page (in both directions) between the DFU and the Active partition when a firmware update is triggered. +
9Because the original Active application is moved into the DFU partition during this update, the operation can be reversed if the update is interrupted or the new firmware does not flag that it booted successfully. +
10See the design section for more details on how this is implemented.
11
5The bootloader can be used either as a library or be flashed directly if you are happy with the default configuration and capabilities. 12The bootloader can be used either as a library or be flashed directly if you are happy with the default configuration and capabilities.
6 13
7By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself. 14By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself.
@@ -19,6 +26,8 @@ The bootloader supports
19 26
20In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work. 27In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work.
21 28
29STM32L0x1 devices require the `flash-erase-zero` feature to be enabled.
30
22== Design 31== Design
23 32
24image::bootloader_flash.png[Bootloader flash layout] 33image::bootloader_flash.png[Bootloader flash layout]
@@ -34,14 +43,14 @@ Partition Size~dfu~= Partition Size~active~+ Page Size~active~
34+ 43+
35All values are specified in bytes. 44All values are specified in bytes.
36 45
37* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped. When the new firmware has been written to the DFU partition, a magic field is written to instruct the bootloader that the partitions should be swapped. This partition must be able to store a magic field as well as the partition swap progress. The partition size given by: 46* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped. When the new firmware has been written to the DFU partition, a magic field is written to instruct the bootloader that the partitions should be swapped. This partition must be able to store a magic field as well as the partition swap progress. The partition size is given by:
38+ 47+
39Partition Size~state~ = Write Size~state~ + (2 × Partition Size~active~ / Page Size~active~) 48Partition Size~state~ = (2 × Write Size~state~) + (4 × Write Size~state~ × Partition Size~active~ / Page Size~active~)
40+ 49+
41All values are specified in bytes. 50All values are specified in bytes.
42 51
43The partitions for ACTIVE (+BOOTLOADER), DFU and BOOTLOADER_STATE may be placed in separate flash. The page size used by the bootloader is determined by the lowest common multiple of the ACTIVE and DFU page sizes. 52The partitions for ACTIVE (+BOOTLOADER), DFU and BOOTLOADER_STATE may be placed in separate flash. The page size used by the bootloader is determined by the lowest common multiple of the ACTIVE and DFU page sizes.
44The BOOTLOADER_STATE partition must be big enough to store one word per page in the ACTIVE and DFU partitions combined. 53The BOOTLOADER_STATE partition must be big enough to store two words, plus four words per page in the ACTIVE partition.
45 54
46The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice. 55The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice.
47 56
@@ -86,8 +95,7 @@ Then, to sign your firmware given a declaration of `FIRMWARE_DIR` and a firmware
86 95
87[source, bash] 96[source, bash]
88---- 97----
89shasum -a 512 -b $FIRMWARE_DIR/myfirmware > $SECRETS_DIR/message.txt 98shasum -a 512 -b $FIRMWARE_DIR/myfirmware | head -c128 | xxd -p -r > $SECRETS_DIR/message.txt
90cat $SECRETS_DIR/message.txt | dd ibs=128 count=1 | xxd -p -r > $SECRETS_DIR/message.txt
91signify -S -s $SECRETS_DIR/key.sec -m $SECRETS_DIR/message.txt -x $SECRETS_DIR/message.txt.sig 99signify -S -s $SECRETS_DIR/key.sec -m $SECRETS_DIR/message.txt -x $SECRETS_DIR/message.txt.sig
92cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed 100cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed
93tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed 101tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed
diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc
index 76b1169bd..0792130eb 100644
--- a/docs/pages/embassy_in_the_wild.adoc
+++ b/docs/pages/embassy_in_the_wild.adoc
@@ -2,8 +2,22 @@
2 2
3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! 3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
4 4
5_newer entries at the top_
6
7* link:https://github.com/thataquarel/protovolt[ProtoV MINI: A USB-C mini lab power supply]
8** A dual-channel USB PD powered breadboard power supply based on the RP2040, running embedded graphics. Open-source schematics and firmware.
9* link:https://github.com/Dawson-HEP/opentrig/[Opentrig: A particle physics trigger and data acquisition system]
10** Digital event trigger with threshold, data acquisition system designed to interface with AIDA-2020 TLU systems, tested at the DESY II Test Beam Facility. Based on the RP2040, and Embassy's async event handling.
11* link:https://github.com/1-rafael-1/air-quality-monitor[Air Quality Monitor]
12** Air Quality Monitor based on rp2350 board, ens160 and aht21 sensors and ssd1306 display. Code and 3D printable enclosure included.
13* link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation]
14** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details.
15* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2]
16** A hobbyist project building a tracked robot with basic autonomous and manual drive mode.
17* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
18** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files.
5* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] 19* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
6** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! 20** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
7** Targets STM32, RP2040, nRF52 and ESP32 MCUs 21** Targets STM32, RP2040, nRF52 and ESP32 MCUs
8* link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware] 22* link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware]
9** Targets some STM32 MCUs 23** Targets some STM32 MCUs
@@ -13,10 +27,9 @@ Here are known examples of real-world projects which make use of Embassy. Feel f
13* link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] 27* link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system]
14** Targets nRF52 and uses nrf-softdevice 28** Targets nRF52 and uses nrf-softdevice
15 29
16* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop 30* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop
17firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are: 31firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are:
18** biopotentials (analog ports) 32** biopotentials (analog ports)
19** motion capture (6-axis accelerometers) 33** motion capture (6-axis accelerometers)
20** air quality (CO2, Temp, Humidity) 34** air quality (CO2, Temp, Humidity)
21** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]] 35** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]]
22
diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc
index a2f56a539..8098e12ac 100644
--- a/docs/pages/faq.adoc
+++ b/docs/pages/faq.adoc
@@ -4,18 +4,18 @@ These are a list of unsorted, commonly asked questions and answers.
4 4
5Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/pages/faq.adoc[this page], especially if someone in the chat answered a question for you! 5Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/pages/faq.adoc[this page], especially if someone in the chat answered a question for you!
6 6
7== How to deploy to RP2040 without a debugging probe. 7== How to deploy to RP2040 or RP235x without a debugging probe.
8 8
9Install link:https://github.com/JoNil/elf2uf2-rs[elf2uf2-rs] for converting the generated elf binary into a uf2 file. 9Install link:https://github.com/raspberrypi/pico-sdk-tools/releases[Picotool] for uploading the binary.
10 10
11Configure the runner to use this tool, add this to `.cargo/config.toml`: 11Configure the runner to use this tool, add this to `.cargo/config.toml`:
12[source,toml] 12[source,toml]
13---- 13----
14[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 14[target.'cfg(all(target_arch = "arm", target_os = "none"))']
15runner = "elf2uf2-rs --deploy --serial --verbose" 15runner = "picotool load --update --verify --execute -t elf"
16---- 16----
17 17
18The command-line parameters `--deploy` will detect your device and upload the binary, `--serial` starts a serial connection. See the documentation for more info. 18Picotool will detect your device and upload the binary, skipping identical flash sectors (the `--update` command-line flag), verify that the binary was written correctly (`--verify`), and then run your new code (`--execute`). Run `picotool help load` for more information.
19 19
20== Missing main macro 20== Missing main macro
21 21
@@ -92,17 +92,9 @@ If you see linker error like this:
92 >>> referenced by driver.rs:127 (src/driver.rs:127) 92 >>> referenced by driver.rs:127 (src/driver.rs:127)
93 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::now::hefb1f99d6e069842) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib 93 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::now::hefb1f99d6e069842) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
94 94
95 rust-lld: error: undefined symbol: _embassy_time_allocate_alarm 95 rust-lld: error: undefined symbol: _embassy_time_schedule_wake
96 >>> referenced by driver.rs:134 (src/driver.rs:134)
97 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::allocate_alarm::hf5145b6bd46706b2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
98
99 rust-lld: error: undefined symbol: _embassy_time_set_alarm_callback
100 >>> referenced by driver.rs:139 (src/driver.rs:139)
101 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm_callback::h24f92388d96eafd2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
102
103 rust-lld: error: undefined symbol: _embassy_time_set_alarm
104 >>> referenced by driver.rs:144 (src/driver.rs:144) 96 >>> referenced by driver.rs:144 (src/driver.rs:144)
105 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm::h530a5b1f444a6d5b) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib 97 >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::schedule_wake::h530a5b1f444a6d5b) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
106---- 98----
107 99
108You probably need to enable a time driver for your HAL (not in `embassy-time`!). For example with `embassy-stm32`, you might need to enable `time-driver-any`: 100You probably need to enable a time driver for your HAL (not in `embassy-time`!). For example with `embassy-stm32`, you might need to enable `time-driver-any`:
@@ -125,6 +117,20 @@ If you are in the early project setup phase and not using anything from the HAL,
125use embassy_stm32 as _; 117use embassy_stm32 as _;
126---- 118----
127 119
120Another common error you may experience is:
121
122[source,text]
123----
124 = note: rust-lld: error: undefined symbol: __pender
125 >>> referenced by mod.rs:373 (src/raw/mod.rs:373)
126 >>> embassy_executor-e78174e249bca7f4.embassy_executor.1e9d60fc90940543-cgu.0.rcgu.o:(embassy_executor::raw::Pender::pend::h0f19b6e01762e4cd) in archive [...]libembassy_executor-e78174e249bca7f4.rlib
127----
128
129There are two possible causes to this error:
130
131* You are using `embassy-executor` withuout enabling one of the architecture-specific features, but you are using a HAL that does not bring its own executors. For example, for Cortex-M (like the RP2040), you need to enable the `arch-cortex-m` feature of `embassy-executor`.
132* You are not using `embassy-executor`. In this case, you need to enable the one of the `generic-queue-X` features of `embassy-time`.
133
128== Error: `Only one package in the dependency graph may specify the same links value.` 134== Error: `Only one package in the dependency graph may specify the same links value.`
129 135
130You have multiple versions of the same crate in your dependency tree. This means that some of your 136You have multiple versions of the same crate in your dependency tree. This means that some of your
@@ -140,9 +146,9 @@ Example:
140[source,toml] 146[source,toml]
141---- 147----
142[patch.crates-io] 148[patch.crates-io]
143embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } 149embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" }
144embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } 150embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" }
145# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } 151# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" }
146---- 152----
147 153
148Note that the git revision should match any other embassy patches or git dependencies that you are using! 154Note that the git revision should match any other embassy patches or git dependencies that you are using!
@@ -158,35 +164,11 @@ Note that the git revision should match any other embassy patches or git depende
158* Set the following keys in the `[unstable]` section of your `.cargo/config.toml` 164* Set the following keys in the `[unstable]` section of your `.cargo/config.toml`
159 ** `build-std = ["core"]` 165 ** `build-std = ["core"]`
160 ** `build-std-features = ["panic_immediate_abort"]` 166 ** `build-std-features = ["panic_immediate_abort"]`
161* Enable feature `embassy-time/generic-queue`, disable feature `embassy-executor/integrated-timers`
162* When using `InterruptExecutor`: 167* When using `InterruptExecutor`:
163 ** disable `executor-thread` 168 ** disable `executor-thread`
164 ** make `main`` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }` 169 ** make `main` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }`
165 ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor. 170 ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor.
166 171
167== How do I set up the task arenas on stable?
168
169When you aren't using the `nightly` feature of `embassy-executor`, the executor uses a bump allocator, which may require configuration.
170
171Something like this error will occur at **compile time** if the task arena is *too large* for the target's RAM:
172
173[source,plain]
174----
175rust-lld: error: section '.bss' will not fit in region 'RAM': overflowed by _ bytes
176rust-lld: error: section '.uninit' will not fit in region 'RAM': overflowed by _ bytes
177----
178
179And this message will appear at **runtime** if the task arena is *too small* for the tasks running:
180
181[source,plain]
182----
183ERROR panicked at 'embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/'
184----
185
186NOTE: If all tasks are spawned at startup, this panic will occur immediately.
187
188Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html#task-arena[Task Arena Documentation] for more details.
189
190== Can I use manual ISRs alongside Embassy? 172== Can I use manual ISRs alongside Embassy?
191 173
192Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. 174Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task” flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project].
@@ -227,10 +209,10 @@ MEMORY
227_stack_start = ORIGIN(RAM) + LENGTH(RAM); 209_stack_start = ORIGIN(RAM) + LENGTH(RAM);
228``` 210```
229 211
230Please refer to the STM32 documentation for the specific values suitable for your board and setup. The STM32 Cube examples often contain a linker script `.ld` file. 212Please refer to the STM32 documentation for the specific values suitable for your board and setup. The STM32 Cube examples often contain a linker script `.ld` file.
231Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start. 213Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start.
232 214
233If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise. 215If you find a case where the memory.x is wrong, please report it on link:https://github.com/embassy-rs/stm32-data/issues/301[this Github issue] so other users are not caught by surprise.
234 216
235== The USB examples are not working on my board, is there anything else I need to configure? 217== The USB examples are not working on my board, is there anything else I need to configure?
236 218
@@ -286,7 +268,7 @@ General steps:
2861. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet. 2681. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet.
2872. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips. 2692. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips.
2883. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`. 2703. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`.
2894. In your code, access the defined memory region using `#[link_section = ".xxx"]` 2714. In your code, access the defined memory region using `#[unsafe(link_section = ".xxx")]`
2905. Copy data to that region before using BDMA. 2725. Copy data to that region before using BDMA.
291 273
292See link:https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/spi_bdma.rs[SMT32H7 SPI BDMA example] for more details. 274See link:https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/spi_bdma.rs[SMT32H7 SPI BDMA example] for more details.
@@ -353,7 +335,81 @@ There are two main ways to handle concurrency in Embassy:
353In general, either of these approaches will work. The main differences of these approaches are: 335In general, either of these approaches will work. The main differences of these approaches are:
354 336
355When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task. 337When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
338An example showcasing some methods for sharing things between tasks link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
356 339
357But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks. 340But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks.
358 341
359Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case. 342Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case.
343
344== splitting peripherals resources between tasks
345
346There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example]
347
348== My code/driver works in debug mode, but not release mode (or with LTO)
349
350Issues like these while implementing drivers often fall into one of the following general causes, which are a good list of common errors to check for:
351
3521. Some kind of race condition - the faster code means you miss an interrupt or something
3532. Some kind of UB, if you have unsafe code, or something like DMA with fences missing
3543. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds
3554. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary
3565. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time
357
358== How can I prevent the thread-mode executor from going to sleep? ==
359
360In some cases you might want to prevent the thread-mode executor from going to sleep, for example when doing so would result in current spikes that reduce analog performance.
361As a workaround, you can spawn a task that yields in a loop, preventing the executor from going to sleep. Note that this may increase power consumption.
362
363[source,rust]
364----
365#[embassy_executor::task]
366async fn idle() {
367 loop { embassy_futures::yield_now().await; }
368}
369----
370
371== Why is my bootloader restarting in loop?
372
373== Troubleshooting Bootloader Restart Loops
374
375If your bootloader restarts in a loop, there could be multiple reasons. Here are some things to check:
376
377=== Validate the `memory.x` File
378The bootloader performs critical checks when creating partitions using the addresses defined in `memory.x`. Ensure the following assertions hold true:
379
380[source,rust]
381----
382const {
383 core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
384 core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
385 core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
386 core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
387}
388
389// Ensure enough progress pages to store copy progress
390assert_eq!(0, Self::PAGE_SIZE % aligned_buf.len() as u32);
391assert!(aligned_buf.len() >= STATE::WRITE_SIZE);
392assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE);
393assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE);
394----
395
396If any of these assertions fail, the bootloader will likely restart in a loop. This failure might not log any messages (e.g., when using `defmt`). Confirm that your `memory.x` file and flash memory align with these requirements.
397
398=== Handling Panic Logging
399Some panic errors might log messages, but certain microcontrollers reset before the message is fully printed. To ensure panic messages are logged, add a delay using no-operation (NOP) instructions before the reset:
400
401[source,rust]
402----
403#[panic_handler]
404fn panic(_info: &core::panic::PanicInfo) -> ! {
405 for _ in 0..10_000_000 {
406 cortex_m::asm::nop();
407 }
408 cortex_m::asm::udf();
409}
410----
411
412=== Feed the watchdog
413
414
415Some `embassy-boot` implementations (like `embassy-boot-nrf` and `embassy-boot-rp`) rely on a watchdog timer to detect application failure. The bootloader will restart if your application code does not properly feed the watchdog timer. Make sure to feed it correctly.
diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc
index 017409018..d1f65a885 100644
--- a/docs/pages/getting_started.adoc
+++ b/docs/pages/getting_started.adoc
@@ -66,7 +66,7 @@ If everything worked correctly, you should see a blinking LED on your board, and
66[source] 66[source]
67---- 67----
68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s 68 Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
69 Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky` 69 Running `probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky`
70(HOST) INFO flashing program (71.36 KiB) 70(HOST) INFO flashing program (71.36 KiB)
71(HOST) INFO success! 71(HOST) INFO success!
72──────────────────────────────────────────────────────────────────────────────── 72────────────────────────────────────────────────────────────────────────────────
@@ -86,7 +86,7 @@ NOTE: How does the `+cargo run+` command know how to connect to our board and pr
86 86
87=== It didn’t work! 87=== It didn’t work!
88 88
89If you hare having issues when running `+cargo run --release+`, please check the following: 89If you are having issues when running `+cargo run --release+`, please check the following:
90 90
91* You are specifying the correct `+--chip+` on the command line, OR 91* You are specifying the correct `+--chip+` on the command line, OR
92* You have set `+.cargo/config.toml+`’s run line to the correct chip, AND 92* You have set `+.cargo/config.toml+`’s run line to the correct chip, AND
diff --git a/docs/pages/hal.adoc b/docs/pages/hal.adoc
index 14b85e1f1..3bbe94e02 100644
--- a/docs/pages/hal.adoc
+++ b/docs/pages/hal.adoc
@@ -4,7 +4,7 @@ Embassy provides HALs for several microcontroller families:
4 4
5* `embassy-nrf` for the nRF microcontrollers from Nordic Semiconductor 5* `embassy-nrf` for the nRF microcontrollers from Nordic Semiconductor
6* `embassy-stm32` for STM32 microcontrollers from ST Microelectronics 6* `embassy-stm32` for STM32 microcontrollers from ST Microelectronics
7* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers 7* `embassy-rp` for the Raspberry Pi RP2040 and RP235x microcontrollers
8 8
9These HALs implement async/await functionality for most peripherals while also implementing the 9These HALs implement async/await functionality for most peripherals while also implementing the
10async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor. 10async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor.
@@ -12,3 +12,7 @@ async traits in `embedded-hal` and `embedded-hal-async`. You can also use these
12For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use. 12For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use.
13 13
14For the WCH 32-bit RISC-V series, there is an link:https://github.com/ch32-rs/ch32-hal[ch32-hal], which you can use. 14For the WCH 32-bit RISC-V series, there is an link:https://github.com/ch32-rs/ch32-hal[ch32-hal], which you can use.
15
16For the Microchip PolarFire SoC, there is link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal].
17
18For the Puya Semiconductor PY32 series, there is link:https://github.com/py32-rs/py32-hal[py32-hal]. \ No newline at end of file
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc
new file mode 100644
index 000000000..87867e1e0
--- /dev/null
+++ b/docs/pages/imxrt.adoc
@@ -0,0 +1,16 @@
1= Embassy iMXRT HAL
2
3The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Embassy iMXRT HAL] is based on the following PACs (Peripheral Access Crate):
4
5* link:https://github.com/OpenDevicePartnership/mimxrt685s-pac[mimxrt685s-pac]
6* link:https://github.com/OpenDevicePartnership/mimxrt633s-pac[mimxrt633s-pac]
7
8== Peripherals
9
10The following peripherals have a HAL implementation at present
11
12* CRC
13* DMA
14* GPIO
15* RNG
16* UART
diff --git a/docs/pages/layer_by_layer.adoc b/docs/pages/layer_by_layer.adoc
index f87291c20..0692ee4fa 100644
--- a/docs/pages/layer_by_layer.adoc
+++ b/docs/pages/layer_by_layer.adoc
@@ -8,7 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
8 8
9== PAC version 9== PAC version
10 10
11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. 11The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does little to prevent you from configuring or coordinating those registers incorrectly.
12 12
13Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use. 13Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
14 14
@@ -76,7 +76,7 @@ The async version looks very similar to the HAL version, apart from a few minor
76* The peripheral initialization is done by the main macro, and is handed to the main task. 76* The peripheral initialization is done by the main macro, and is handed to the main task.
77* Before checking the button state, the application is awaiting a transition in the pin state (low -> high or high -> low). 77* Before checking the button state, the application is awaiting a transition in the pin state (low -> high or high -> low).
78 78
79When `button.await_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiButton`), so that whenever an interrupt is raised, the task awaiting the button will be woken up. 79When `button.wait_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiInput`), so that whenever an interrupt is raised, the task awaiting the button will be woken up.
80 80
81The minimal overhead of the executor and the ability to run multiple tasks "concurrently" combined with the enormous simplification of the application, makes `async` a great fit for embedded. 81The minimal overhead of the executor and the ability to run multiple tasks "concurrently" combined with the enormous simplification of the application, makes `async` a great fit for embedded.
82 82
diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc
index 346d9f0f8..906d89f36 100644
--- a/docs/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -1,6 +1,6 @@
1= Starting a new project 1= Starting a new project
2 2
3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. 3Once you’ve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project.
4 4
5== Tools for generating Embassy projects 5== Tools for generating Embassy projects
6 6
@@ -11,6 +11,8 @@ Once you’ve successfully xref:getting_started.adoc[run some example projects],
11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP) 11- link:https://github.com/lulf/embassy-template[embassy-template] (STM32, NRF, and RP)
12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP) 12- link:https://github.com/bentwire/embassy-rp2040-template[embassy-rp2040-template] (RP)
13 13
14=== esp-generate
15- link:https://github.com/esp-rs/esp-generate[esp-generate] (ESP32 using esp-hal)
14 16
15== Starting a project from scratch 17== Starting a project from scratch
16 18
@@ -73,22 +75,34 @@ Now that cargo knows what target to compile for (and probe-rs knows what chip to
73 75
74Looking in `examples/stm32g4/Cargo.toml`, we can see that the examples require a number of embassy crates. For blinky, we’ll only need three of them: `embassy-stm32`, `embassy-executor` and `embassy-time`. 76Looking in `examples/stm32g4/Cargo.toml`, we can see that the examples require a number of embassy crates. For blinky, we’ll only need three of them: `embassy-stm32`, `embassy-executor` and `embassy-time`.
75 77
76At the time of writing, the latest version of embassy isn‘t available on crates.io, so we need to install it straight from the git repository. The recommended way of doing so is as follows: 78
79At the time of writing, embassy is already published to crates.io. Therefore, dependencies can easily added via Cargo.toml.
80
81[source,toml]
82----
83[dependencies]
84embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] }
85embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] }
86embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
87----
88
89Prior, embassy needed to be installed straight from the git repository. Installing from git is still useful, if you want to checkout a specic revision of an embassy crate which is not yet published.
90The recommended way of doing so is as follows:
77 91
78* Copy the required `embassy-*` lines from the example `Cargo.toml` 92* Copy the required `embassy-*` lines from the example `Cargo.toml`
79* Make any necessary changes to `features`, e.g. requiring the `stm32g474re` feature of `embassy-stm32` 93* Make any necessary changes to `features`, e.g. requiring the `stm32g474re` feature of `embassy-stm32`
80* Remove the `path = ""` keys in the `embassy-*` entries 94* Remove the `path = ""` keys in the `embassy-*` entries
81* Create a `[patch.crates-io]` section, with entries for each embassy crate we need. These should all contain identical values: a link to the git repository, and a reference to the commit we’re checking out. Assuming you want the latest commit, you can find it by running `git ls-remote https://github.com/embassy-rs/embassy.git HEAD` 95* Create a `[patch.crates-io]` section, with entries for each embassy crate we need. These should all contain identical values: a link to the git repository, and a reference to the commit we’re checking out. Assuming you want the latest commit, you can find it by running `git ls-remote https://github.com/embassy-rs/embassy.git HEAD`
82 96
83NOTE: When using this method, it’s necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crate’s `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed. Hopefully this will no longer be necessary once embassy is released on crates.io! 97NOTE: When using this method, it’s necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crate’s `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed.
84 98
85At the time of writing, this method produces the following results: 99An example Cargo.toml file might look as follows:
86 100
87[source,toml] 101[source,toml]
88---- 102----
89[dependencies] 103[dependencies]
90embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]} 104embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]}
91embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 105embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] }
92embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 106embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
93 107
94[patch.crates-io] 108[patch.crates-io]
@@ -97,7 +111,7 @@ embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "7703f
97embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" } 111embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" }
98---- 112----
99 113
100There are a few other dependencies we need to build the project, but fortunately they’re much simpler to install. Copy their lines from the example `Cargo.toml` to the the `[dependencies]` section in the new `Cargo.toml`: 114There are a few other dependencies we need to build the project, but fortunately they’re much simpler to install. Copy their lines from the example `Cargo.toml` to the `[dependencies]` section in the new `Cargo.toml`:
101 115
102[source,toml] 116[source,toml]
103---- 117----
@@ -138,7 +152,7 @@ stm32g474-example
138# Before upgrading check that everything is available on all tier1 targets here: 152# Before upgrading check that everything is available on all tier1 targets here:
139# https://rust-lang.github.io/rustup-components-history 153# https://rust-lang.github.io/rustup-components-history
140[toolchain] 154[toolchain]
141channel = "nightly-2023-11-01" 155channel = "1.85"
142components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 156components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
143targets = ["thumbv7em-none-eabi"] 157targets = ["thumbv7em-none-eabi"]
144---- 158----
diff --git a/docs/pages/nrf.adoc b/docs/pages/nrf.adoc
index 1706087ae..de052b63f 100644
--- a/docs/pages/nrf.adoc
+++ b/docs/pages/nrf.adoc
@@ -1,6 +1,6 @@
1= Embassy nRF HAL 1= Embassy nRF HAL
2 2
3The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs]. 3The link:https://github.com/embassy-rs/embassy/tree/main/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
4 4
5== Timer driver 5== Timer driver
6 6
diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc
index 1b9381bfe..18eaaeb75 100644
--- a/docs/pages/overview.adoc
+++ b/docs/pages/overview.adoc
@@ -6,7 +6,7 @@ Embassy is a project to make async/await a first-class option for embedded devel
6 6
7When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task (known as a “thread”) can be executed if available, or the CPU can be put to sleep until another task is ready. 7When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task (known as a “thread”) can be executed if available, or the CPU can be put to sleep until another task is ready.
8 8
9Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. 9Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted if they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread.
10 10
11In other programming languages, these lightweight tasks are known as “coroutines” or ”goroutines”. In Rust, they are implemented with async. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. 11In other programming languages, these lightweight tasks are known as “coroutines” or ”goroutines”. In Rust, they are implemented with async. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute.
12 12
@@ -28,9 +28,12 @@ The Embassy project maintains HALs for select hardware, but you can still use HA
28 28
29* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. 29* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. 30* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. 31* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 as well as RP235x microcontroller.
32* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. 32* link:https://docs.embassy.dev/embassy-mspm0/[embassy-mspm0], for the Texas Instruments MSPM0 microcontrollers.
33* link:https://github.com/esp-rs/esp-hal[esp-hal], for the Espressif Systems ESP32 series of chips.
33* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. 34* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips.
35* link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC.
36* link:https://github.com/py32-rs/py32-hal[py32-hal], for the Puya Semiconductor PY32 series of chips.
34 37
35NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async, 38NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
36as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. 39as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
@@ -48,11 +51,11 @@ link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a w
48link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. 51link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
49 52
50=== Bootloader and DFU 53=== Bootloader and DFU
51link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. 54link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
52 55
53== What is DMA? 56== What is DMA?
54 57
55For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bits at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller. 58For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bytes at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller.
56 59
57The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them. 60The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them.
58 61
@@ -74,6 +77,11 @@ include::embassy_in_the_wild.adoc[leveloffset = 2]
74 77
75For more reading material on async Rust and Embassy: 78For more reading material on async Rust and Embassy:
76 79
77* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] 80* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparison of FreeRTOS and Embassy]
78* link:https://dev.to/apollolabsbin/series/20707[Tutorials] 81* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
79* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] 82* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
83
84Videos:
85
86* link:https://www.youtube.com/watch?v=pDd5mXBF4tY[Intro to Embassy]
87* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust]
diff --git a/docs/pages/project_structure.adoc b/docs/pages/project_structure.adoc
index 722ec8d9d..227508b97 100644
--- a/docs/pages/project_structure.adoc
+++ b/docs/pages/project_structure.adoc
@@ -85,9 +85,9 @@ A minimal example:
85[source,toml] 85[source,toml]
86---- 86----
87[toolchain] 87[toolchain]
88channel = "nightly-2023-08-19" # <- as of writing, this is the exact rust version embassy uses 88channel = "1.85" # <- as of writing, this is the exact rust version embassy uses
89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size" 89components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size"
90targets = [ 90targets = [
91 "thumbv6m-none-eabi" # <-change for your platform 91 "thumbv6m-none-eabi" # <- change for your platform
92] 92]
93---- 93----
diff --git a/docs/pages/sharing_peripherals.adoc b/docs/pages/sharing_peripherals.adoc
index 6bcd56b01..70b4210e6 100644
--- a/docs/pages/sharing_peripherals.adoc
+++ b/docs/pages/sharing_peripherals.adoc
@@ -8,7 +8,7 @@ The following examples shows different ways to use the on-board LED on a Raspber
8 8
9Using mutual exclusion is the simplest way to share a peripheral. 9Using mutual exclusion is the simplest way to share a peripheral.
10 10
11TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 11TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
12[,rust] 12[,rust]
13---- 13----
14use defmt::*; 14use defmt::*;
@@ -36,8 +36,8 @@ async fn main(spawner: Spawner) {
36 let dt = 100 * 1_000_000; 36 let dt = 100 * 1_000_000;
37 let k = 1.003; 37 let k = 1.003;
38 38
39 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt)))); 39 spawner.spawn(unwrap!(toggle_led(&LED, Duration::from_nanos(dt))));
40 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64)))); 40 spawner.spawn(unwrap!(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64))));
41} 41}
42 42
43// A pool size of 2 means you can spawn two instances of this task. 43// A pool size of 2 means you can spawn two instances of this task.
@@ -78,7 +78,7 @@ To indicate that the pin will be set to an Output. The `AnyPin` could have been
78 78
79A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things. 79A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things.
80 80
81TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 81TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
82[,rust] 82[,rust]
83---- 83----
84use defmt::*; 84use defmt::*;
@@ -103,8 +103,8 @@ async fn main(spawner: Spawner) {
103 let dt = 100 * 1_000_000; 103 let dt = 100 * 1_000_000;
104 let k = 1.003; 104 let k = 1.003;
105 105
106 unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt)))); 106 spawner.spawn(unwrap!(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt))));
107 unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos((dt as f64 * k) as u64)))); 107 spawner.spawn(unwrap!(toggle_led(CHANNEL.sender(), Duration::from_nanos((dt as f64 * k) as u64))));
108 108
109 loop { 109 loop {
110 match CHANNEL.receive().await { 110 match CHANNEL.receive().await {
@@ -126,3 +126,9 @@ async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>,
126 126
127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure 127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
128that the operation is completed before continuing to do other work in your task. 128that the operation is completed before continuing to do other work in your task.
129
130An example showcasing more methods for sharing link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
131
132== Sharing an I2C or SPI bus between multiple devices
133
134An example of how to deal with multiple devices sharing a common I2C or SPI bus link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/shared_bus.rs[can be found here].
diff --git a/docs/pages/stm32.adoc b/docs/pages/stm32.adoc
index 7bfc0592b..df139a420 100644
--- a/docs/pages/stm32.adoc
+++ b/docs/pages/stm32.adoc
@@ -1,6 +1,6 @@
1= Embassy STM32 HAL 1= Embassy STM32 HAL
2 2
3The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project. 3The link:https://github.com/embassy-rs/embassy/tree/main/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
4 4
5== The infinite variant problem 5== The infinite variant problem
6 6
diff --git a/docs/pages/system.adoc b/docs/pages/system.adoc
index 985f92b18..09241a8df 100644
--- a/docs/pages/system.adoc
+++ b/docs/pages/system.adoc
@@ -6,6 +6,7 @@ include::runtime.adoc[leveloffset = 2]
6include::bootloader.adoc[leveloffset = 2] 6include::bootloader.adoc[leveloffset = 2]
7include::time_keeping.adoc[leveloffset = 2] 7include::time_keeping.adoc[leveloffset = 2]
8include::hal.adoc[leveloffset = 2] 8include::hal.adoc[leveloffset = 2]
9include::imxrt.adoc[leveloffset = 2]
9include::nrf.adoc[leveloffset = 2] 10include::nrf.adoc[leveloffset = 2]
10include::stm32.adoc[leveloffset = 2] 11include::stm32.adoc[leveloffset = 2]
11include::sharing_peripherals.adoc[leveloffset = 2] 12include::sharing_peripherals.adoc[leveloffset = 2]
diff --git a/docs/pages/time_keeping.adoc b/docs/pages/time_keeping.adoc
index 17492a884..11ddb2b2b 100644
--- a/docs/pages/time_keeping.adoc
+++ b/docs/pages/time_keeping.adoc
@@ -16,7 +16,7 @@ The `embassy::time::Timer` type provides two timing methods.
16 16
17An example of a delay is provided as follows: 17An example of a delay is provided as follows:
18 18
19TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 19TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
20[,rust] 20[,rust]
21---- 21----
22use embassy::executor::{task, Executor}; 22use embassy::executor::{task, Executor};
@@ -41,7 +41,7 @@ that expect a generic delay implementation to be provided.
41 41
42An example of how this can be used: 42An example of how this can be used:
43 43
44TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 44TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
45[,rust] 45[,rust]
46---- 46----
47use embassy::executor::{task, Executor}; 47use embassy::executor::{task, Executor};