aboutsummaryrefslogtreecommitdiff
path: root/examples/boot/bootloader
diff options
context:
space:
mode:
Diffstat (limited to 'examples/boot/bootloader')
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml18
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs12
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml16
-rw-r--r--examples/boot/bootloader/rp/memory.x2
-rw-r--r--examples/boot/bootloader/rp/src/main.rs6
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml14
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/src/main.rs8
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml14
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs8
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml22
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/README.md58
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/memory.x8
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short1
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/src/main.rs54
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/.cargo/config.toml8
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/Cargo.toml70
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/README.md63
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/build.rs27
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/memory.x18
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/secrets/key.pub.short1
-rw-r--r--examples/boot/bootloader/stm32wba-dfu/src/main.rs158
21 files changed, 529 insertions, 57 deletions
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index 9d5d51a13..1fea2b7d7 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -1,18 +1,19 @@
1[package] 1[package]
2edition = "2021" 2edition = "2024"
3name = "nrf-bootloader-example" 3name = "nrf-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Bootloader for nRF chips" 5description = "Bootloader for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7publish = false
7 8
8[dependencies] 9[dependencies]
9defmt = { version = "0.3", optional = true } 10defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 11defmt-rtt = { version = "1.0.0", optional = true }
11 12
12embassy-nrf = { path = "../../../../embassy-nrf", features = [] } 13embassy-nrf = { path = "../../../../embassy-nrf", features = [] }
13embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } 14embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 16embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 17cortex-m-rt = { version = "0.7" }
17cfg-if = "1.0.0" 18cfg-if = "1.0.0"
18 19
@@ -57,3 +58,12 @@ debug = false
57debug-assertions = false 58debug-assertions = false
58opt-level = 0 59opt-level = 0
59overflow-checks = false 60overflow-checks = false
61
62[package.metadata.embassy]
63build = [
64 { target = "thumbv7em-none-eabi", features = ["embassy-nrf/nrf52840"] },
65 { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9160-ns"] },
66 { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9120-ns"] },
67 { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9151-ns"] },
68 { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns"] }
69]
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 67c700437..76c4c1048 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -8,7 +8,7 @@ use cortex_m_rt::{entry, exception};
8use defmt_rtt as _; 8use defmt_rtt as _;
9use embassy_boot_nrf::*; 9use embassy_boot_nrf::*;
10use embassy_nrf::nvmc::Nvmc; 10use embassy_nrf::nvmc::Nvmc;
11use embassy_nrf::wdt; 11use embassy_nrf::wdt::{self, HaltConfig, SleepConfig};
12use embassy_sync::blocking_mutex::Mutex; 12use embassy_sync::blocking_mutex::Mutex;
13 13
14#[entry] 14#[entry]
@@ -25,8 +25,8 @@ fn main() -> ! {
25 25
26 let mut wdt_config = wdt::Config::default(); 26 let mut wdt_config = wdt::Config::default();
27 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds 27 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
28 wdt_config.run_during_sleep = true; 28 wdt_config.action_during_sleep = SleepConfig::RUN;
29 wdt_config.run_during_debug_halt = false; 29 wdt_config.action_during_debug_halt = HaltConfig::PAUSE;
30 30
31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); 31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
32 let flash = Mutex::new(RefCell::new(flash)); 32 let flash = Mutex::new(RefCell::new(flash));
@@ -38,8 +38,8 @@ fn main() -> ! {
38 unsafe { bl.load(active_offset) } 38 unsafe { bl.load(active_offset) }
39} 39}
40 40
41#[no_mangle] 41#[unsafe(no_mangle)]
42#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 42#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
43unsafe extern "C" fn HardFault() { 43unsafe extern "C" fn HardFault() {
44 cortex_m::peripheral::SCB::sys_reset(); 44 cortex_m::peripheral::SCB::sys_reset();
45} 45}
@@ -47,7 +47,7 @@ unsafe extern "C" fn HardFault() {
47#[exception] 47#[exception]
48unsafe fn DefaultHandler(_: i16) -> ! { 48unsafe fn DefaultHandler(_: i16) -> ! {
49 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 49 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
50 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; 50 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
51 51
52 panic!("DefaultHandler #{:?}", irqn); 52 panic!("DefaultHandler #{:?}", irqn);
53} 53}
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index c15c980ca..188bcab36 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -1,17 +1,18 @@
1[package] 1[package]
2edition = "2021" 2edition = "2024"
3name = "rp-bootloader-example" 3name = "rp-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Example bootloader for RP2040 chips" 5description = "Example bootloader for RP2040 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7publish = false
7 8
8[dependencies] 9[dependencies]
9defmt = { version = "0.3", optional = true } 10defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 11defmt-rtt = { version = "1.0.0", optional = true }
11 12
12embassy-rp = { path = "../../../../embassy-rp", features = [] } 13embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] }
13embassy-boot-rp = { path = "../../../../embassy-boot-rp" } 14embassy-boot-rp = { path = "../../../../embassy-boot-rp" }
14embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 15embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
15embassy-time = { path = "../../../../embassy-time", features = [] } 16embassy-time = { path = "../../../../embassy-time", features = [] }
16 17
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
@@ -31,3 +32,8 @@ defmt = [
31[profile.release] 32[profile.release]
32debug = true 33debug = true
33opt-level = 's' 34opt-level = 's'
35
36[package.metadata.embassy]
37build = [
38 { target = "thumbv6m-none-eabi" }
39]
diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x
index c3b54976e..88b5bbb15 100644
--- a/examples/boot/bootloader/rp/memory.x
+++ b/examples/boot/bootloader/rp/memory.x
@@ -2,7 +2,7 @@ MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K 5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100
6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K 6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K 7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
8 DFU : ORIGIN = 0x10087000, LENGTH = 516K 8 DFU : ORIGIN = 0x10087000, LENGTH = 516K
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
index 25b1657b8..7ebefd374 100644
--- a/examples/boot/bootloader/rp/src/main.rs
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -34,8 +34,8 @@ fn main() -> ! {
34 unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } 34 unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) }
35} 35}
36 36
37#[no_mangle] 37#[unsafe(no_mangle)]
38#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 38#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
39unsafe extern "C" fn HardFault() { 39unsafe extern "C" fn HardFault() {
40 cortex_m::peripheral::SCB::sys_reset(); 40 cortex_m::peripheral::SCB::sys_reset();
41} 41}
@@ -43,7 +43,7 @@ unsafe extern "C" fn HardFault() {
43#[exception] 43#[exception]
44unsafe fn DefaultHandler(_: i16) -> ! { 44unsafe fn DefaultHandler(_: i16) -> ! {
45 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 45 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
46 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; 46 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
47 47
48 panic!("DefaultHandler #{:?}", irqn); 48 panic!("DefaultHandler #{:?}", irqn);
49} 49}
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
index b91b05412..cf68921dc 100644
--- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -1,13 +1,14 @@
1[package] 1[package]
2edition = "2021" 2edition = "2024"
3name = "stm32-bootloader-dual-bank-flash-example" 3name = "stm32-bootloader-dual-bank-flash-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Example bootloader for dual-bank flash STM32 chips" 5description = "Example bootloader for dual-bank flash STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7publish = false
7 8
8[dependencies] 9[dependencies]
9defmt = { version = "0.3", optional = true } 10defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 11defmt-rtt = { version = "1.0.0", optional = true }
11 12
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } 13embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 14embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
@@ -15,7 +16,7 @@ cortex-m = { version = "0.7.6", features = [
15 "inline-asm", 16 "inline-asm",
16 "critical-section-single-core", 17 "critical-section-single-core",
17] } 18] }
18embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 19embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
19cortex-m-rt = { version = "0.7" } 20cortex-m-rt = { version = "0.7" }
20embedded-storage = "0.3.1" 21embedded-storage = "0.3.1"
21embedded-storage-async = "0.4.0" 22embedded-storage-async = "0.4.0"
@@ -54,3 +55,8 @@ debug = false
54debug-assertions = false 55debug-assertions = false
55opt-level = 0 56opt-level = 0
56overflow-checks = false 57overflow-checks = false
58
59[package.metadata.embassy]
60build = [
61 { target = "thumbv7em-none-eabi", features = ["embassy-stm32/stm32h743zi"] }
62]
diff --git a/examples/boot/bootloader/stm32-dual-bank/src/main.rs b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
index 4d2e82d26..f0063fb5c 100644
--- a/examples/boot/bootloader/stm32-dual-bank/src/main.rs
+++ b/examples/boot/bootloader/stm32-dual-bank/src/main.rs
@@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")] 7#[cfg(feature = "defmt")]
8use defmt_rtt as _; 8use defmt_rtt as _;
9use embassy_boot_stm32::*; 9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{Flash, BANK1_REGION}; 10use embassy_stm32::flash::{BANK1_REGION, Flash};
11use embassy_sync::blocking_mutex::Mutex; 11use embassy_sync::blocking_mutex::Mutex;
12 12
13#[entry] 13#[entry]
@@ -33,8 +33,8 @@ fn main() -> ! {
33 unsafe { bl.load(BANK1_REGION.base + active_offset) } 33 unsafe { bl.load(BANK1_REGION.base + active_offset) }
34} 34}
35 35
36#[no_mangle] 36#[unsafe(no_mangle)]
37#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 37#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
38unsafe extern "C" fn HardFault() { 38unsafe extern "C" fn HardFault() {
39 cortex_m::peripheral::SCB::sys_reset(); 39 cortex_m::peripheral::SCB::sys_reset();
40} 40}
@@ -42,7 +42,7 @@ unsafe extern "C" fn HardFault() {
42#[exception] 42#[exception]
43unsafe fn DefaultHandler(_: i16) -> ! { 43unsafe fn DefaultHandler(_: i16) -> ! {
44 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 44 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
45 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; 45 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
46 46
47 panic!("DefaultHandler #{:?}", irqn); 47 panic!("DefaultHandler #{:?}", irqn);
48} 48}
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 541186949..e457310b9 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -1,18 +1,19 @@
1[package] 1[package]
2edition = "2021" 2edition = "2024"
3name = "stm32-bootloader-example" 3name = "stm32-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Example bootloader for STM32 chips" 5description = "Example bootloader for STM32 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7publish = false
7 8
8[dependencies] 9[dependencies]
9defmt = { version = "0.3", optional = true } 10defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 11defmt-rtt = { version = "1.0.0", optional = true }
11 12
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } 13embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 14embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 16embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 17cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1" 18embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 19embedded-storage-async = "0.4.0"
@@ -56,3 +57,8 @@ debug = false
56debug-assertions = false 57debug-assertions = false
57opt-level = 0 58opt-level = 0
58overflow-checks = false 59overflow-checks = false
60
61[package.metadata.embassy]
62build = [
63 { target = "thumbv7em-none-eabi", features = ["embassy-stm32/stm32l496zg"] }
64]
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 99a7a6a6b..383ad912d 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -7,7 +7,7 @@ use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")] 7#[cfg(feature = "defmt")]
8use defmt_rtt as _; 8use defmt_rtt as _;
9use embassy_boot_stm32::*; 9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{Flash, BANK1_REGION}; 10use embassy_stm32::flash::{BANK1_REGION, Flash};
11use embassy_sync::blocking_mutex::Mutex; 11use embassy_sync::blocking_mutex::Mutex;
12 12
13#[entry] 13#[entry]
@@ -32,8 +32,8 @@ fn main() -> ! {
32 unsafe { bl.load(BANK1_REGION.base + active_offset) } 32 unsafe { bl.load(BANK1_REGION.base + active_offset) }
33} 33}
34 34
35#[no_mangle] 35#[unsafe(no_mangle)]
36#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 36#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
37unsafe extern "C" fn HardFault() { 37unsafe extern "C" fn HardFault() {
38 cortex_m::peripheral::SCB::sys_reset(); 38 cortex_m::peripheral::SCB::sys_reset();
39} 39}
@@ -41,7 +41,7 @@ unsafe extern "C" fn HardFault() {
41#[exception] 41#[exception]
42unsafe fn DefaultHandler(_: i16) -> ! { 42unsafe fn DefaultHandler(_: i16) -> ! {
43 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 43 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
44 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; 44 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
45 45
46 panic!("DefaultHandler #{:?}", irqn); 46 panic!("DefaultHandler #{:?}", irqn);
47} 47}
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 9950ed7b6..75b7081df 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -1,25 +1,26 @@
1[package] 1[package]
2edition = "2021" 2edition = "2024"
3name = "stm32wb-dfu-bootloader-example" 3name = "stm32wb-dfu-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Example USB DFUbootloader for the STM32WB series of chips" 5description = "Example USB DFUbootloader for the STM32WB series of chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7publish = false
7 8
8[dependencies] 9[dependencies]
9defmt = { version = "0.3", optional = true } 10defmt = { version = "1.0.1", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 11defmt-rtt = { version = "1.0.0", optional = true }
11 12
12embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } 13embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } 14embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 16embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
16cortex-m-rt = { version = "0.7" } 17cortex-m-rt = { version = "0.7" }
17embedded-storage = "0.3.1" 18embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 19embedded-storage-async = "0.4.0"
19cfg-if = "1.0.0" 20cfg-if = "1.0.0"
20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } 21embassy-usb-dfu = { version = "0.2.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] }
21embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb", default-features = false } 22embassy-usb = { version = "0.5.1", path = "../../../../embassy-usb", default-features = false }
22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } 23embassy-futures = { version = "0.1.2", path = "../../../../embassy-futures" }
23 24
24[features] 25[features]
25defmt = [ 26defmt = [
@@ -30,6 +31,7 @@ defmt = [
30 "embassy-usb/defmt", 31 "embassy-usb/defmt",
31 "embassy-usb-dfu/defmt" 32 "embassy-usb-dfu/defmt"
32] 33]
34verify = ["embassy-usb-dfu/ed25519-salty"]
33 35
34[profile.dev] 36[profile.dev]
35debug = 2 37debug = 2
@@ -61,3 +63,9 @@ debug = false
61debug-assertions = false 63debug-assertions = false
62opt-level = 0 64opt-level = 0
63overflow-checks = false 65overflow-checks = false
66
67[package.metadata.embassy]
68build = [
69 { target = "thumbv7em-none-eabi", features = ["embassy-stm32/stm32wb55rg"] },
70 { target = "thumbv7em-none-eabi", features = ["embassy-stm32/stm32wb55rg", "verify"] }
71]
diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md
index d5c6ea57c..99a7002c4 100644
--- a/examples/boot/bootloader/stm32wb-dfu/README.md
+++ b/examples/boot/bootloader/stm32wb-dfu/README.md
@@ -1,11 +1,63 @@
1# Bootloader for STM32 1# Bootloader for STM32
2 2
3The bootloader uses `embassy-boot` to interact with the flash. 3This bootloader implementation uses `embassy-boot` and `embassy-usb-dfu` to manage firmware updates and interact with the flash memory on STM32WB55 devices.
4 4
5# Usage 5## Prerequisites
6 6
7Flash the bootloader 7- Rust toolchain with `cargo` installed
8- `cargo-flash` for flashing the bootloader
9- `dfu-util` for firmware updates
10- `cargo-binutils` for binary generation
11
12## Usage
13
14### 1. Flash the Bootloader
15
16First, flash the bootloader to your device:
8 17
9``` 18```
10cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx 19cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx
11``` 20```
21
22### 2. Build and Flash Application
23
24Generate your application binary and flash it using DFU:
25
26```
27cargo objcopy --release -- -O binary fw.bin
28dfu-util -d c0de:cafe -w -D fw.bin
29```
30
31### 3. Sign Updates Before Flashing (Optional)
32
33Currently, embassy-usb-dfu only supports a limited implementation of the generic support for ed25519-based update verfication in embassy-boot. This implementation assumes that a signature is simply concatenated to the end of an update binary. For more details, please see https://embassy.dev/book/#_verification and/or refer to the documentation for embassy-boot-dfu.
34
35To sign (and then verify) application updates, you will first need to generate a key pair:
36
37```
38signify-openbsd -G -n -p secrets/key.pub -s secrets/key.sec
39tail -n1 secrets/key.pub | base64 -d -i - | dd ibs=10 skip=1 > secrets/key.pub.short
40```
41
42Then you will need to sign all you binaries with the private key:
43
44```
45cargo objcopy --release -- -O binary fw.bin
46shasum -a 512 -b fw.bin | head -c128 | xxd -p -r > target/fw-hash.txt
47signify-openbsd -S -s secrets/key.sec -m target/fw-hash.txt -x target/fw-hash.sig
48cp fw.bin fw-signed.bin
49tail -n1 target/fw-hash.sig | base64 -d -i - | dd ibs=10 skip=1 >> fw-signed.bin
50dfu-util -d c0de:cafe -w -D fw-signed.bin
51```
52
53Finally, as shown in this example with the `verify` feature flag enabled, you then need to embed the public key into your bootloader so that it can verify update signatures.
54
55N.B. Please note that the exact steps above are NOT a good example of how to manage your keys securely. In a production environment, you should take great care to ensure that (at least the private key) is protected and not leaked into your version control system.
56
57## Troubleshooting
58
59- Make sure your device is in DFU mode before flashing
60- Verify the USB VID:PID matches your device (c0de:cafe)
61- Check USB connections if the device is not detected
62- Make sure the transfer size option of `dfu-util` matches the bootloader configuration. By default, `dfu-util` will use the transfer size reported by the device, but you can override it with the `-t` option if needed.
63- Make sure `control_buf` size is larger than or equal to the `usb_dfu` `BLOCK_SIZE` parameter (in this example, both are set to 4096 bytes).
diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x
index 858062631..77c4d2ee2 100644
--- a/examples/boot/bootloader/stm32wb-dfu/memory.x
+++ b/examples/boot/bootloader/stm32wb-dfu/memory.x
@@ -1,10 +1,10 @@
1MEMORY 1MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 24K 4 FLASH : ORIGIN = 0x08000000, LENGTH = 48K
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K 6 ACTIVE : ORIGIN = 0x0800D000, LENGTH = 120K
7 DFU : ORIGIN = 0x08028000, LENGTH = 132K 7 DFU : ORIGIN = 0x0802B000, LENGTH = 120K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
9} 9}
10 10
diff --git a/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short
new file mode 100644
index 000000000..7a4de8585
--- /dev/null
+++ b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short
@@ -0,0 +1 @@
gB��p�M�S��z��Kg��!�F���!4�r \ No newline at end of file
diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
index 093b39f9d..9ee82846d 100644
--- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs
+++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs
@@ -7,19 +7,30 @@ use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")] 7#[cfg(feature = "defmt")]
8use defmt_rtt as _; 8use defmt_rtt as _;
9use embassy_boot_stm32::*; 9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{Flash, BANK1_REGION, WRITE_SIZE}; 10use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE};
11use embassy_stm32::rcc::WPAN_DEFAULT; 11use embassy_stm32::rcc::WPAN_DEFAULT;
12use embassy_stm32::usb::Driver; 12use embassy_stm32::usb::Driver;
13use embassy_stm32::{bind_interrupts, peripherals, usb}; 13use embassy_stm32::{bind_interrupts, peripherals, usb};
14use embassy_sync::blocking_mutex::Mutex; 14use embassy_sync::blocking_mutex::Mutex;
15use embassy_usb::Builder; 15use embassy_usb::{Builder, msos};
16use embassy_usb_dfu::consts::DfuAttributes; 16use embassy_usb_dfu::consts::DfuAttributes;
17use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; 17use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu};
18 18
19bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
20 USB_LP => usb::InterruptHandler<peripherals::USB>; 20 USB_LP => usb::InterruptHandler<peripherals::USB>;
21}); 21});
22 22
23// This is a randomly generated GUID to allow clients on Windows to find your device.
24//
25// N.B. update to a custom GUID for your own device!
26const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
27
28// This is a randomly generated example key.
29//
30// N.B. Please replace with your own!
31#[cfg(feature = "verify")]
32static PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../secrets/key.pub.short");
33
23#[entry] 34#[entry]
24fn main() -> ! { 35fn main() -> ! {
25 let mut config = embassy_stm32::Config::default(); 36 let mut config = embassy_stm32::Config::default();
@@ -52,7 +63,13 @@ fn main() -> ! {
52 let mut config_descriptor = [0; 256]; 63 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256]; 64 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 4096]; 65 let mut control_buf = [0; 4096];
55 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); 66
67 #[cfg(not(feature = "verify"))]
68 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
69
70 #[cfg(feature = "verify")]
71 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate, PUBLIC_SIGNING_KEY);
72
56 let mut builder = Builder::new( 73 let mut builder = Builder::new(
57 driver, 74 driver,
58 config, 75 config,
@@ -62,7 +79,28 @@ fn main() -> ! {
62 &mut control_buf, 79 &mut control_buf,
63 ); 80 );
64 81
65 usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); 82 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
83 // Otherwise users need to do this manually using a tool like Zadig.
84 //
85 // It seems these always need to be at added at the device level for this to work and for
86 // composite devices they also need to be added on the function level (as shown later).
87 //
88 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
89 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
90 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
91 "DeviceInterfaceGUIDs",
92 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
93 ));
94
95 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, |func| {
96 // You likely don't have to add these function level headers if your USB device is not composite
97 // (i.e. if your device does not expose another interface in addition to DFU)
98 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
99 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
100 "DeviceInterfaceGUIDs",
101 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
102 ));
103 });
66 104
67 let mut dev = builder.build(); 105 let mut dev = builder.build();
68 embassy_futures::block_on(dev.run()); 106 embassy_futures::block_on(dev.run());
@@ -71,8 +109,8 @@ fn main() -> ! {
71 unsafe { bl.load(BANK1_REGION.base + active_offset) } 109 unsafe { bl.load(BANK1_REGION.base + active_offset) }
72} 110}
73 111
74#[no_mangle] 112#[unsafe(no_mangle)]
75#[cfg_attr(target_os = "none", link_section = ".HardFault.user")] 113#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
76unsafe extern "C" fn HardFault() { 114unsafe extern "C" fn HardFault() {
77 cortex_m::peripheral::SCB::sys_reset(); 115 cortex_m::peripheral::SCB::sys_reset();
78} 116}
@@ -80,7 +118,7 @@ unsafe extern "C" fn HardFault() {
80#[exception] 118#[exception]
81unsafe fn DefaultHandler(_: i16) -> ! { 119unsafe fn DefaultHandler(_: i16) -> ! {
82 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32; 120 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
83 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16; 121 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
84 122
85 panic!("DefaultHandler #{:?}", irqn); 123 panic!("DefaultHandler #{:?}", irqn);
86} 124}
diff --git a/examples/boot/bootloader/stm32wba-dfu/.cargo/config.toml b/examples/boot/bootloader/stm32wba-dfu/.cargo/config.toml
new file mode 100644
index 000000000..1896068d8
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip STM32WBA65RI"
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/boot/bootloader/stm32wba-dfu/Cargo.toml b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml
new file mode 100644
index 000000000..eee2b2f71
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/Cargo.toml
@@ -0,0 +1,70 @@
1[package]
2edition = "2024"
3name = "stm32wba6-dfu-bootloader-example"
4version = "0.1.0"
5description = "Example USB DFUbootloader for the STM32WBA series of chips"
6license = "MIT OR Apache-2.0"
7publish = false
8
9[dependencies]
10defmt = { version = "1.0.1", optional = true }
11defmt-rtt = { version = "1.0.0", optional = true }
12
13embassy-stm32 = { path = "../../../../embassy-stm32", features = [] }
14embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" }
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
17cortex-m-rt = { version = "0.7" }
18embedded-storage = "0.3.1"
19embedded-storage-async = "0.4.0"
20cfg-if = "1.0.0"
21embassy-usb-dfu = { version = "0.2.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] }
22embassy-usb = { version = "0.5.1", path = "../../../../embassy-usb", default-features = false }
23embassy-futures = { version = "0.1.2", path = "../../../../embassy-futures" }
24
25[features]
26defmt = [
27 "dep:defmt",
28 "dep:defmt-rtt",
29 "embassy-boot-stm32/defmt",
30 "embassy-stm32/defmt",
31 "embassy-usb/defmt",
32 "embassy-usb-dfu/defmt"
33]
34verify = ["embassy-usb-dfu/ed25519-salty"]
35
36[profile.dev]
37debug = 2
38debug-assertions = true
39incremental = false
40opt-level = 'z'
41overflow-checks = true
42
43[profile.release]
44codegen-units = 1
45debug = 2
46debug-assertions = false
47incremental = false
48lto = 'fat'
49opt-level = 'z'
50overflow-checks = false
51
52# do not optimize proc-macro crates = faster builds from scratch
53[profile.dev.build-override]
54codegen-units = 8
55debug = false
56debug-assertions = false
57opt-level = 0
58overflow-checks = false
59
60[profile.release.build-override]
61codegen-units = 8
62debug = false
63debug-assertions = false
64opt-level = 0
65overflow-checks = false
66
67[package.metadata.embassy]
68build = [
69 { target = "thumbv8m.main-none-eabihf", features = ["embassy-stm32/stm32wba65ri", "verify"] }
70]
diff --git a/examples/boot/bootloader/stm32wba-dfu/README.md b/examples/boot/bootloader/stm32wba-dfu/README.md
new file mode 100644
index 000000000..d50164255
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/README.md
@@ -0,0 +1,63 @@
1# Bootloader for STM32
2
3This bootloader implementation uses `embassy-boot` and `embassy-usb-dfu` to manage firmware updates and interact with the flash memory on STM32WB55 devices.
4
5## Prerequisites
6
7- Rust toolchain with `cargo` installed
8- `cargo-flash` for flashing the bootloader
9- `dfu-util` for firmware updates
10- `cargo-binutils` for binary generation
11
12## Usage
13
14### 1. Flash the Bootloader
15
16First, flash the bootloader to your device:
17
18```
19cargo flash --features embassy-stm32/stm32wba65ri --release --chip STM32WBA65RI
20```
21
22### 2. Build and Flash Application
23
24Generate your application binary and flash it using DFU:
25
26```
27cargo objcopy --release -- -O binary fw.bin
28dfu-util -d c0de:cafe -w -D fw.bin
29```
30
31### 3. Sign Updates Before Flashing (Optional)
32
33Currently, embassy-usb-dfu only supports a limited implementation of the generic support for ed25519-based update verfication in embassy-boot. This implementation assumes that a signature is simply concatenated to the end of an update binary. For more details, please see https://embassy.dev/book/#_verification and/or refer to the documentation for embassy-boot-dfu.
34
35To sign (and then verify) application updates, you will first need to generate a key pair:
36
37```
38signify-openbsd -G -n -p secrets/key.pub -s secrets/key.sec
39tail -n1 secrets/key.pub | base64 -d -i - | dd ibs=10 skip=1 > secrets/key.pub.short
40```
41
42Then you will need to sign all you binaries with the private key:
43
44```
45cargo objcopy --release -- -O binary fw.bin
46shasum -a 512 -b fw.bin | head -c128 | xxd -p -r > target/fw-hash.txt
47signify-openbsd -S -s secrets/key.sec -m target/fw-hash.txt -x target/fw-hash.sig
48cp fw.bin fw-signed.bin
49tail -n1 target/fw-hash.sig | base64 -d -i - | dd ibs=10 skip=1 >> fw-signed.bin
50dfu-util -d c0de:cafe -w -D fw-signed.bin
51```
52
53Finally, as shown in this example with the `verify` feature flag enabled, you then need to embed the public key into your bootloader so that it can verify update signatures.
54
55N.B. Please note that the exact steps above are NOT a good example of how to manage your keys securely. In a production environment, you should take great care to ensure that (at least the private key) is protected and not leaked into your version control system.
56
57## Troubleshooting
58
59- Make sure your device is in DFU mode before flashing
60- Verify the USB VID:PID matches your device (c0de:cafe)
61- Check USB connections if the device is not detected
62- Make sure the transfer size option of `dfu-util` matches the bootloader configuration. By default, `dfu-util` will use the transfer size reported by the device, but you can override it with the `-t` option if needed.
63- Make sure `control_buf` size is larger than or equal to the `usb_dfu` `BLOCK_SIZE` parameter (in this example, both are set to 4096 bytes).
diff --git a/examples/boot/bootloader/stm32wba-dfu/build.rs b/examples/boot/bootloader/stm32wba-dfu/build.rs
new file mode 100644
index 000000000..fd605991f
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/build.rs
@@ -0,0 +1,27 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 println!("cargo:rustc-link-arg-bins=--nmagic");
23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
24 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
25 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
26 }
27}
diff --git a/examples/boot/bootloader/stm32wba-dfu/memory.x b/examples/boot/bootloader/stm32wba-dfu/memory.x
new file mode 100644
index 000000000..105c9e960
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/memory.x
@@ -0,0 +1,18 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 80K
5 BOOTLOADER_STATE : ORIGIN = 0x08014000, LENGTH = 8K
6 ACTIVE : ORIGIN = 0x08016000, LENGTH = 120K
7 DFU : ORIGIN = 0x0803C000, LENGTH = 160K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 400K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(FLASH);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(FLASH);
13
14__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(FLASH);
15__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(FLASH);
16
17__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(FLASH);
18__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(FLASH); \ No newline at end of file
diff --git a/examples/boot/bootloader/stm32wba-dfu/secrets/key.pub.short b/examples/boot/bootloader/stm32wba-dfu/secrets/key.pub.short
new file mode 100644
index 000000000..7a4de8585
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/secrets/key.pub.short
@@ -0,0 +1 @@
gB��p�M�S��z��Kg��!�F���!4�r \ No newline at end of file
diff --git a/examples/boot/bootloader/stm32wba-dfu/src/main.rs b/examples/boot/bootloader/stm32wba-dfu/src/main.rs
new file mode 100644
index 000000000..b33a75d95
--- /dev/null
+++ b/examples/boot/bootloader/stm32wba-dfu/src/main.rs
@@ -0,0 +1,158 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")]
8use defmt_rtt as _;
9use embassy_boot_stm32::*;
10use embassy_stm32::flash::{BANK1_REGION, Flash, WRITE_SIZE};
11use embassy_stm32::usb::Driver;
12use embassy_stm32::{Config, bind_interrupts, peripherals, usb};
13use embassy_sync::blocking_mutex::Mutex;
14use embassy_usb::{Builder, msos};
15use embassy_usb_dfu::consts::DfuAttributes;
16use embassy_usb_dfu::{Control, ResetImmediate, usb_dfu};
17
18bind_interrupts!(struct Irqs {
19 USB_OTG_HS => usb::InterruptHandler<peripherals::USB_OTG_HS>;
20});
21
22// This is a randomly generated GUID to allow clients on Windows to find your device.
23//
24// N.B. update to a custom GUID for your own device!
25const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
26
27// This is a randomly generated example key.
28//
29// N.B. Please replace with your own!
30#[cfg(feature = "verify")]
31static PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../secrets/key.pub.short");
32
33#[entry]
34fn main() -> ! {
35 let mut config = Config::default();
36
37 {
38 use embassy_stm32::rcc::*;
39 config.rcc.pll1 = Some(Pll {
40 source: PllSource::HSI,
41 prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz
42 mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO
43 divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
44 divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz
45 divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USB_OTG_HS)
46 frac: Some(0), // Fractional part (disabled)
47 });
48
49 config.rcc.ahb_pre = AHBPrescaler::DIV1;
50 config.rcc.apb1_pre = APBPrescaler::DIV1;
51 config.rcc.apb2_pre = APBPrescaler::DIV1;
52 config.rcc.apb7_pre = APBPrescaler::DIV1;
53 config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
54
55 config.rcc.voltage_scale = VoltageScale::RANGE1;
56 config.rcc.mux.otghssel = mux::Otghssel::PLL1_P;
57 config.rcc.sys = Sysclk::PLL1_R;
58 }
59
60 let p = embassy_stm32::init(config);
61
62 // Prevent a hard fault when accessing flash 'too early' after boot.
63 #[cfg(feature = "defmt")]
64 for _ in 0..10000000 {
65 cortex_m::asm::nop();
66 }
67
68 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
69 let flash = Mutex::new(RefCell::new(layout.bank1_region));
70
71 let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash);
72 let active_offset = config.active.offset();
73 let bl = BootLoader::prepare::<_, _, _, 2048>(config);
74
75 // Create the driver, from the HAL.
76 let mut ep_out_buffer = [0u8; 256];
77 let mut config = embassy_stm32::usb::Config::default();
78
79 config.vbus_detection = false;
80
81 if bl.state == State::DfuDetach {
82 let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PD6, p.PD7, &mut ep_out_buffer, config);
83 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
84 config.manufacturer = Some("Embassy");
85 config.product = Some("USB-DFU Bootloader example");
86 config.serial_number = Some("1235678");
87
88 let fw_config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash, &flash);
89 let mut buffer = AlignedBuffer([0; WRITE_SIZE]);
90 let updater = BlockingFirmwareUpdater::new(fw_config, &mut buffer.0[..]);
91
92 let mut config_descriptor = [0; 256];
93 let mut bos_descriptor = [0; 256];
94 let mut control_buf = [0; 4096];
95
96 #[cfg(not(feature = "verify"))]
97 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate);
98
99 #[cfg(feature = "verify")]
100 let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate, PUBLIC_SIGNING_KEY);
101
102 let mut builder = Builder::new(
103 driver,
104 config,
105 &mut config_descriptor,
106 &mut bos_descriptor,
107 &mut [],
108 &mut control_buf,
109 );
110
111 // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows.
112 // Otherwise users need to do this manually using a tool like Zadig.
113 //
114 // It seems these always need to be at added at the device level for this to work and for
115 // composite devices they also need to be added on the function level (as shown later).
116
117 builder.msos_descriptor(msos::windows_version::WIN8_1, 2);
118 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
119 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
120 "DeviceInterfaceGUIDs",
121 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
122 ));
123
124 usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, |func| {
125 // You likely don't have to add these function level headers if your USB device is not composite
126 // (i.e. if your device does not expose another interface in addition to DFU)
127 func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
128 func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
129 "DeviceInterfaceGUIDs",
130 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
131 ));
132 });
133
134 let mut dev = builder.build();
135 embassy_futures::block_on(dev.run());
136 }
137
138 unsafe { bl.load(BANK1_REGION.base + active_offset) }
139}
140
141#[unsafe(no_mangle)]
142#[cfg_attr(target_os = "none", unsafe(link_section = ".HardFault.user"))]
143unsafe extern "C" fn HardFault() {
144 cortex_m::peripheral::SCB::sys_reset();
145}
146
147#[exception]
148unsafe fn DefaultHandler(_: i16) -> ! {
149 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
150 let irqn = unsafe { core::ptr::read_volatile(SCB_ICSR) } as u8 as i16 - 16;
151
152 panic!("DefaultHandler #{:?}", irqn);
153}
154
155#[panic_handler]
156fn panic(_info: &core::panic::PanicInfo) -> ! {
157 cortex_m::asm::udf();
158}