aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json1
-rwxr-xr-xci.sh4
-rw-r--r--cyw43/Cargo.toml6
-rw-r--r--cyw43/src/bluetooth.rs8
-rw-r--r--docs/examples/basic/Cargo.toml2
-rw-r--r--embassy-boot-nrf/CHANGELOG.md4
-rw-r--r--embassy-boot-nrf/Cargo.toml4
-rw-r--r--embassy-executor/CHANGELOG.md1
-rw-r--r--embassy-executor/src/raw/mod.rs6
-rw-r--r--embassy-executor/src/raw/waker.rs13
-rw-r--r--embassy-executor/src/raw/waker_turbo.rs4
-rw-r--r--embassy-imxrt/Cargo.toml4
-rw-r--r--embassy-imxrt/src/dma.rs8
-rw-r--r--embassy-imxrt/src/flexcomm/uart.rs4
-rw-r--r--embassy-mcxa/Cargo.toml4
-rw-r--r--embassy-mcxa/src/clkout.rs8
-rw-r--r--embassy-mcxa/src/clocks/config.rs136
-rw-r--r--embassy-mcxa/src/clocks/mod.rs567
-rw-r--r--embassy-mcxa/src/dma.rs2
-rw-r--r--embassy-mcxa/src/gpio.rs20
-rw-r--r--embassy-mcxa/src/i2c/mod.rs7
-rw-r--r--embassy-mcxa/src/lib.rs24
-rw-r--r--embassy-mcxa/src/lpuart/mod.rs21
-rw-r--r--embassy-mcxa/src/reset_reason.rs187
-rw-r--r--embassy-mspm0/CHANGELOG.md3
-rw-r--r--embassy-mspm0/Cargo.toml149
-rw-r--r--embassy-mspm0/build.rs52
-rw-r--r--embassy-mspm0/src/gpio.rs4
-rw-r--r--embassy-mspm0/src/i2c_target.rs9
-rw-r--r--embassy-mspm0/src/lib.rs16
-rw-r--r--embassy-mspm0/src/macros.rs1
-rw-r--r--embassy-mspm0/src/time_driver.rs4
-rw-r--r--embassy-mspm0/src/uart/buffered.rs4
-rw-r--r--embassy-net-nrf91/CHANGELOG.md6
-rw-r--r--embassy-net-nrf91/Cargo.toml8
-rw-r--r--embassy-net-nrf91/src/lib.rs5
-rw-r--r--embassy-net-ppp/Cargo.toml2
-rw-r--r--embassy-net-tuntap/Cargo.toml4
-rw-r--r--embassy-net-tuntap/src/lib.rs12
-rw-r--r--embassy-net/Cargo.toml4
-rw-r--r--embassy-net/src/tcp.rs16
-rw-r--r--embassy-nrf/CHANGELOG.md4
-rw-r--r--embassy-nrf/Cargo.toml10
-rw-r--r--embassy-nrf/src/buffered_uarte/v1.rs9
-rw-r--r--embassy-nrf/src/buffered_uarte/v2.rs8
-rw-r--r--embassy-nrf/src/gpiote.rs15
-rw-r--r--embassy-nrf/src/time_driver.rs4
-rw-r--r--embassy-nrf/src/uarte.rs20
-rw-r--r--embassy-nxp/Cargo.toml2
-rw-r--r--embassy-nxp/src/usart/lpc55.rs9
-rw-r--r--embassy-rp/Cargo.toml4
-rw-r--r--embassy-rp/src/pio_programs/uart.rs4
-rw-r--r--embassy-rp/src/uart/mod.rs8
-rw-r--r--embassy-stm32-wpan/Cargo.toml4
-rw-r--r--embassy-stm32-wpan/src/wb55/mod.rs2
-rw-r--r--embassy-stm32-wpan/src/wb55/shci.rs122
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/ble.rs8
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/sys.rs45
-rw-r--r--embassy-stm32-wpan/src/wba/linklayer_plat.rs1125
-rw-r--r--embassy-stm32/CHANGELOG.md4
-rw-r--r--embassy-stm32/Cargo.toml19
-rw-r--r--embassy-stm32/build.rs54
-rw-r--r--embassy-stm32/src/adc/mod.rs6
-rw-r--r--embassy-stm32/src/hsem/mod.rs27
-rw-r--r--embassy-stm32/src/i2c/mod.rs2
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--embassy-stm32/src/low_power.rs153
-rw-r--r--embassy-stm32/src/rcc/c0.rs6
-rw-r--r--embassy-stm32/src/rcc/f013.rs6
-rw-r--r--embassy-stm32/src/rcc/g0.rs6
-rw-r--r--embassy-stm32/src/rcc/g4.rs6
-rw-r--r--embassy-stm32/src/rcc/h.rs6
-rw-r--r--embassy-stm32/src/rcc/hsi48.rs21
-rw-r--r--embassy-stm32/src/rcc/l.rs11
-rw-r--r--embassy-stm32/src/rcc/mod.rs28
-rw-r--r--embassy-stm32/src/rcc/u5.rs21
-rw-r--r--embassy-stm32/src/rcc/wba.rs5
-rw-r--r--embassy-stm32/src/rng.rs25
-rw-r--r--embassy-stm32/src/rtc/low_power.rs98
-rw-r--r--embassy-stm32/src/rtc/mod.rs16
-rw-r--r--embassy-stm32/src/rtc/v3.rs4
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs13
-rw-r--r--embassy-stm32/src/spi/mod.rs2
-rw-r--r--embassy-stm32/src/time_driver.rs23
-rw-r--r--embassy-stm32/src/timer/input_capture.rs42
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/pipe.rs2
-rw-r--r--embassy-usb-dfu/Cargo.toml2
-rw-r--r--embassy-usb-driver/Cargo.toml1
-rw-r--r--embassy-usb-driver/src/lib.rs1
-rw-r--r--embassy-usb/Cargo.toml2
-rw-r--r--embassy-usb/src/class/cdc_acm.rs51
-rw-r--r--embassy-usb/src/msos.rs4
-rw-r--r--examples/boot/application/nrf/Cargo.toml4
-rw-r--r--examples/mcxa/Cargo.toml2
-rw-r--r--examples/mcxa/src/bin/clkout.rs104
-rw-r--r--examples/mcxa/src/bin/reset-reason.rs4
-rw-r--r--examples/mspm0g3507/Cargo.toml2
-rw-r--r--examples/mspm0g5187/.cargo/config.toml9
-rw-r--r--examples/mspm0g5187/Cargo.toml27
-rw-r--r--examples/mspm0g5187/README.md27
-rw-r--r--examples/mspm0g5187/build.rs37
-rw-r--r--examples/mspm0g5187/memory.x6
-rw-r--r--examples/mspm0g5187/src/bin/blinky.rs25
-rw-r--r--examples/mspm0g5187/src/bin/button.rs33
-rw-r--r--examples/mspm0g5187/src/bin/wwdt.rs54
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml2
-rw-r--r--examples/nrf51/Cargo.toml2
-rw-r--r--examples/nrf52810/Cargo.toml2
-rw-r--r--examples/nrf52840-edf/Cargo.toml2
-rw-r--r--examples/nrf52840-rtic/Cargo.toml2
-rw-r--r--examples/nrf52840/Cargo.toml6
-rw-r--r--examples/nrf5340/Cargo.toml4
-rw-r--r--examples/nrf54l15/Cargo.toml6
-rw-r--r--examples/nrf54lm20/Cargo.toml6
-rw-r--r--examples/nrf9151/ns/Cargo.toml2
-rw-r--r--examples/nrf9151/s/Cargo.toml2
-rw-r--r--examples/nrf9160/Cargo.toml6
-rw-r--r--examples/rp/Cargo.toml4
-rw-r--r--examples/rp/src/bin/usb_webusb.rs11
-rw-r--r--examples/rp235x/Cargo.toml2
-rw-r--r--examples/std/Cargo.toml6
-rw-r--r--examples/stm32f4/Cargo.toml4
-rw-r--r--examples/stm32f7/Cargo.toml2
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32h5/Cargo.toml4
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h723/Cargo.toml4
-rw-r--r--examples/stm32h742/Cargo.toml2
-rw-r--r--examples/stm32h755cm4/Cargo.toml4
-rw-r--r--examples/stm32h755cm7/Cargo.toml4
-rw-r--r--examples/stm32h7b0/Cargo.toml4
-rw-r--r--examples/stm32h7rs/Cargo.toml4
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l4/Cargo.toml4
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32n6/Cargo.toml2
-rw-r--r--examples/stm32wb/Cargo.toml4
-rw-r--r--examples/stm32wb/src/bin/blinky.rs2
-rw-r--r--examples/stm32wb/src/bin/button_exti.rs2
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs2
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs2
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs2
-rw-r--r--examples/stm32wb/src/bin/mac_ffd_net.rs2
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs2
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs2
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs2
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs2
-rw-r--r--examples/stm32wba/src/bin/mac_ffd.rs8
-rw-r--r--examples/stm32wl5x-lp/.cargo/config.toml9
-rw-r--r--examples/stm32wl5x-lp/Cargo.toml39
-rw-r--r--examples/stm32wl5x-lp/build.rs5
-rw-r--r--examples/stm32wl5x-lp/memory.x15
-rw-r--r--examples/stm32wl5x-lp/src/bin/blinky.rs57
-rw-r--r--examples/stm32wle5/Cargo.toml2
-rw-r--r--examples/stm32wle5/src/bin/adc.rs18
-rw-r--r--examples/stm32wle5/src/bin/blinky.rs22
-rw-r--r--examples/stm32wle5/src/bin/button_exti.rs18
-rw-r--r--examples/stm32wle5/src/bin/i2c.rs20
-rw-r--r--tests/mspm0/Cargo.toml4
-rw-r--r--tests/nrf/Cargo.toml4
-rw-r--r--tests/rp/Cargo.toml2
-rw-r--r--tests/stm32/src/bin/stop.rs2
163 files changed, 3045 insertions, 1072 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 73dfa53a4..2b99a313d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -34,6 +34,7 @@
34 // "examples/mspm0c1104/Cargo.toml", 34 // "examples/mspm0c1104/Cargo.toml",
35 // "examples/mspm0g3507/Cargo.toml", 35 // "examples/mspm0g3507/Cargo.toml",
36 // "examples/mspm0g3519/Cargo.toml", 36 // "examples/mspm0g3519/Cargo.toml",
37 // "examples/mspm0g5187/Cargo.toml",
37 // "examples/mspm0l1306/Cargo.toml", 38 // "examples/mspm0l1306/Cargo.toml",
38 // "examples/mspm0l2228/Cargo.toml", 39 // "examples/mspm0l2228/Cargo.toml",
39 // "examples/nrf52840-rtic/Cargo.toml", 40 // "examples/nrf52840-rtic/Cargo.toml",
diff --git a/ci.sh b/ci.sh
index e489982a7..1eecd158f 100755
--- a/ci.sh
+++ b/ci.sh
@@ -35,8 +35,8 @@ rm -rf out/tests/nrf5340-dk
35# disabled because these boards are not on the shelf 35# disabled because these boards are not on the shelf
36rm -rf out/tests/mspm0g3507 36rm -rf out/tests/mspm0g3507
37 37
38# rm out/tests/stm32wb55rg/wpan_mac 38rm out/tests/stm32wb55rg/wpan_mac
39# rm out/tests/stm32wb55rg/wpan_ble 39rm out/tests/stm32wb55rg/wpan_ble
40 40
41# unstable, I think it's running out of RAM? 41# unstable, I think it's running out of RAM?
42rm out/tests/stm32f207zg/eth 42rm out/tests/stm32f207zg/eth
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 6d7647697..c4f5c0ebd 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/cyw43" 10documentation = "https://docs.embassy.dev/cyw43"
11 11
12[features] 12[features]
13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"] 13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt"]
14log = ["dep:log"] 14log = ["dep:log"]
15bluetooth = ["dep:bt-hci", "dep:embedded-io-async"] 15bluetooth = ["dep:bt-hci", "dep:embedded-io-async"]
16 16
@@ -35,8 +35,8 @@ num_enum = { version = "0.5.7", default-features = false }
35heapless = "0.8.0" 35heapless = "0.8.0"
36 36
37# Bluetooth deps 37# Bluetooth deps
38embedded-io-async = { version = "0.6.0", optional = true } 38embedded-io-async = { version = "0.7.0", optional = true }
39bt-hci = { version = "0.6.0", optional = true } 39bt-hci = { git = "https://github.com/embassy-rs/bt-hci", rev = "51791fd4d422449dd0eca5ddead32886101215f7", optional = true }
40 40
41[package.metadata.embassy] 41[package.metadata.embassy]
42build = [ 42build = [
diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs
index 332b7048d..256451fae 100644
--- a/cyw43/src/bluetooth.rs
+++ b/cyw43/src/bluetooth.rs
@@ -490,6 +490,14 @@ impl From<FromHciBytesError> for Error {
490 } 490 }
491} 491}
492 492
493impl core::fmt::Display for Error {
494 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
495 core::fmt::Debug::fmt(self, f)
496 }
497}
498
499impl core::error::Error for Error {}
500
493impl<'d> embedded_io_async::ErrorType for BtDriver<'d> { 501impl<'d> embedded_io_async::ErrorType for BtDriver<'d> {
494 type Error = Error; 502 type Error = Error;
495} 503}
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
index fadda102b..495e484f8 100644
--- a/docs/examples/basic/Cargo.toml
+++ b/docs/examples/basic/Cargo.toml
@@ -9,7 +9,7 @@ publish = false
9[dependencies] 9[dependencies]
10embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } 10embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] }
11embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] } 11embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] }
12embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 12embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
13 13
14defmt = "1.0.1" 14defmt = "1.0.1"
15defmt-rtt = "1.0.0" 15defmt-rtt = "1.0.0"
diff --git a/embassy-boot-nrf/CHANGELOG.md b/embassy-boot-nrf/CHANGELOG.md
index 54b7c8067..5bf8cf4b0 100644
--- a/embassy-boot-nrf/CHANGELOG.md
+++ b/embassy-boot-nrf/CHANGELOG.md
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11## 0.10.0 - 2025-12-15
12
13- Bumped embassy-nrf to 0.9.0
14
11## 0.9.0 - 2025-09-30 15## 0.9.0 - 2025-09-30
12 16
13- Bumped embassy-nrf to 0.8.0 17- Bumped embassy-nrf to 0.8.0
diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml
index 787a28d70..4f6d9ed2e 100644
--- a/embassy-boot-nrf/Cargo.toml
+++ b/embassy-boot-nrf/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2024" 2edition = "2024"
3name = "embassy-boot-nrf" 3name = "embassy-boot-nrf"
4version = "0.9.0" 4version = "0.10.0"
5description = "Bootloader lib for nRF chips" 5description = "Bootloader lib for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -36,7 +36,7 @@ defmt = { version = "1.0.1", optional = true }
36log = { version = "0.4.17", optional = true } 36log = { version = "0.4.17", optional = true }
37 37
38embassy-sync = { version = "0.7.2", path = "../embassy-sync" } 38embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
39embassy-nrf = { version = "0.8.0", path = "../embassy-nrf", default-features = false } 39embassy-nrf = { version = "0.9.0", path = "../embassy-nrf", default-features = false }
40embassy-boot = { version = "0.6.1", path = "../embassy-boot" } 40embassy-boot = { version = "0.6.1", path = "../embassy-boot" }
41cortex-m = { version = "0.7.6" } 41cortex-m = { version = "0.7.6" }
42cortex-m-rt = { version = "0.7" } 42cortex-m-rt = { version = "0.7" }
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 8f1db7de7..cc4027fca 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16- Migrate `cortex-ar` to `aarch32-cpu`. The feature name `arch-cortex-ar` remains the same and 16- Migrate `cortex-ar` to `aarch32-cpu`. The feature name `arch-cortex-ar` remains the same and
17 legacy ARM architectures are not supported. 17 legacy ARM architectures are not supported.
18- Added `run_until` to `arch-std` variant of `Executor`. 18- Added `run_until` to `arch-std` variant of `Executor`.
19- Added `__try_embassy_time_queue_item_from_waker`
19 20
20## 0.9.1 - 2025-08-31 21## 0.9.1 - 2025-08-31
21 22
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index ab845ed3b..2b7560de6 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -49,6 +49,7 @@ use self::run_queue::{RunQueue, RunQueueItem};
49use self::state::State; 49use self::state::State;
50use self::util::{SyncUnsafeCell, UninitCell}; 50use self::util::{SyncUnsafeCell, UninitCell};
51pub use self::waker::task_from_waker; 51pub use self::waker::task_from_waker;
52use self::waker::try_task_from_waker;
52use super::SpawnToken; 53use super::SpawnToken;
53use crate::{Metadata, SpawnError}; 54use crate::{Metadata, SpawnError};
54 55
@@ -57,6 +58,11 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static
57 unsafe { task_from_waker(waker).timer_queue_item() } 58 unsafe { task_from_waker(waker).timer_queue_item() }
58} 59}
59 60
61#[unsafe(no_mangle)]
62extern "Rust" fn __try_embassy_time_queue_item_from_waker(waker: &Waker) -> Option<&'static mut TimerQueueItem> {
63 unsafe { try_task_from_waker(waker).map(|task| task.timer_queue_item()) }
64}
65
60/// Raw task header for use in task pointers. 66/// Raw task header for use in task pointers.
61/// 67///
62/// A task can be in one of the following states: 68/// A task can be in one of the following states:
diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs
index 2706f0fdf..8416f9f93 100644
--- a/embassy-executor/src/raw/waker.rs
+++ b/embassy-executor/src/raw/waker.rs
@@ -32,13 +32,18 @@ pub(crate) unsafe fn from_task(p: TaskRef) -> Waker {
32/// 32///
33/// Panics if the waker is not created by the Embassy executor. 33/// Panics if the waker is not created by the Embassy executor.
34pub fn task_from_waker(waker: &Waker) -> TaskRef { 34pub fn task_from_waker(waker: &Waker) -> TaskRef {
35 unwrap!(
36 try_task_from_waker(waker),
37 "Found waker not created by the Embassy executor. Unless the generic timer queue is enabled, `embassy_time::Timer` only works with the Embassy executor."
38 )
39}
40
41pub(crate) fn try_task_from_waker(waker: &Waker) -> Option<TaskRef> {
35 // make sure to compare vtable addresses. Doing `==` on the references 42 // make sure to compare vtable addresses. Doing `==` on the references
36 // will compare the contents, which is slower. 43 // will compare the contents, which is slower.
37 if waker.vtable() as *const _ != &VTABLE as *const _ { 44 if waker.vtable() as *const _ != &VTABLE as *const _ {
38 panic!( 45 return None;
39 "Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor."
40 )
41 } 46 }
42 // safety: our wakers are always created with `TaskRef::as_ptr` 47 // safety: our wakers are always created with `TaskRef::as_ptr`
43 unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) } 48 Some(unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) })
44} 49}
diff --git a/embassy-executor/src/raw/waker_turbo.rs b/embassy-executor/src/raw/waker_turbo.rs
index 919bcc61a..ee33e7633 100644
--- a/embassy-executor/src/raw/waker_turbo.rs
+++ b/embassy-executor/src/raw/waker_turbo.rs
@@ -25,6 +25,10 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef {
25 unsafe { TaskRef::from_ptr(ptr as *const TaskHeader) } 25 unsafe { TaskRef::from_ptr(ptr as *const TaskHeader) }
26} 26}
27 27
28pub(crate) fn try_task_from_waker(waker: &Waker) -> Option<TaskRef> {
29 Some(task_from_waker(waker))
30}
31
28#[inline(never)] 32#[inline(never)]
29#[unsafe(no_mangle)] 33#[unsafe(no_mangle)]
30fn _turbo_wake(ptr: NonNull<()>) { 34fn _turbo_wake(ptr: NonNull<()>) {
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index 81377579b..5ffa054f1 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -85,8 +85,8 @@ cfg-if = "1.0.0"
85cortex-m-rt = ">=0.7.3,<0.8" 85cortex-m-rt = ">=0.7.3,<0.8"
86cortex-m = "0.7.6" 86cortex-m = "0.7.6"
87critical-section = "1.1" 87critical-section = "1.1"
88embedded-io = { version = "0.6.1" } 88embedded-io = { version = "0.7.1" }
89embedded-io-async = { version = "0.6.1" } 89embedded-io-async = { version = "0.7.0" }
90fixed = "1.23.1" 90fixed = "1.23.1"
91 91
92rand-core-06 = { package = "rand_core", version = "0.6" } 92rand-core-06 = { package = "rand_core", version = "0.6" }
diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs
index e71a27e0e..eaa09870d 100644
--- a/embassy-imxrt/src/dma.rs
+++ b/embassy-imxrt/src/dma.rs
@@ -16,6 +16,8 @@ use crate::peripherals::DMA0;
16use crate::sealed::Sealed; 16use crate::sealed::Sealed;
17use crate::{BitIter, interrupt, pac, peripherals}; 17use crate::{BitIter, interrupt, pac, peripherals};
18 18
19pub(crate) const MAX_CHUNK_SIZE: usize = 1024;
20
19#[cfg(feature = "rt")] 21#[cfg(feature = "rt")]
20#[interrupt] 22#[interrupt]
21fn DMA0() { 23fn DMA0() {
@@ -69,7 +71,7 @@ pub(crate) unsafe fn init() {
69/// 71///
70/// SAFETY: Slice must point to a valid location reachable by DMA. 72/// SAFETY: Slice must point to a valid location reachable by DMA.
71pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> { 73pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
72 let count = ((to.len() / W::size() as usize) - 1) as isize; 74 let count = (to.len().div_ceil(W::size() as usize) - 1) as isize;
73 75
74 copy_inner( 76 copy_inner(
75 ch, 77 ch,
@@ -87,7 +89,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to:
87/// 89///
88/// SAFETY: Slice must point to a valid location reachable by DMA. 90/// SAFETY: Slice must point to a valid location reachable by DMA.
89pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> { 91pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
90 let count = ((from.len() / W::size() as usize) - 1) as isize; 92 let count = (from.len().div_ceil(W::size() as usize) - 1) as isize;
91 93
92 copy_inner( 94 copy_inner(
93 ch, 95 ch,
@@ -109,7 +111,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mu
109 let to_len = to.len(); 111 let to_len = to.len();
110 assert_eq!(from_len, to_len); 112 assert_eq!(from_len, to_len);
111 113
112 let count = ((from_len / W::size() as usize) - 1) as isize; 114 let count = (from_len.div_ceil(W::size() as usize) - 1) as isize;
113 115
114 copy_inner( 116 copy_inner(
115 ch, 117 ch,
diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs
index 2b759ba84..d13b32e93 100644
--- a/embassy-imxrt/src/flexcomm/uart.rs
+++ b/embassy-imxrt/src/flexcomm/uart.rs
@@ -598,7 +598,7 @@ impl<'a> UartTx<'a, Async> {
598 regs.fifocfg().modify(|_, w| w.dmatx().disabled()); 598 regs.fifocfg().modify(|_, w| w.dmatx().disabled());
599 }); 599 });
600 600
601 for chunk in buf.chunks(1024) { 601 for chunk in buf.chunks(dma::MAX_CHUNK_SIZE) {
602 regs.fifocfg().modify(|_, w| w.dmatx().enabled()); 602 regs.fifocfg().modify(|_, w| w.dmatx().enabled());
603 603
604 let ch = self.tx_dma.as_mut().unwrap().reborrow(); 604 let ch = self.tx_dma.as_mut().unwrap().reborrow();
@@ -726,7 +726,7 @@ impl<'a> UartRx<'a, Async> {
726 regs.fifocfg().modify(|_, w| w.dmarx().disabled()); 726 regs.fifocfg().modify(|_, w| w.dmarx().disabled());
727 }); 727 });
728 728
729 for chunk in buf.chunks_mut(1024) { 729 for chunk in buf.chunks_mut(dma::MAX_CHUNK_SIZE) {
730 regs.fifocfg().modify(|_, w| w.dmarx().enabled()); 730 regs.fifocfg().modify(|_, w| w.dmarx().enabled());
731 731
732 let ch = self.rx_dma.as_mut().unwrap().reborrow(); 732 let ch = self.rx_dma.as_mut().unwrap().reborrow();
diff --git a/embassy-mcxa/Cargo.toml b/embassy-mcxa/Cargo.toml
index 76ce59f5a..0d9663879 100644
--- a/embassy-mcxa/Cargo.toml
+++ b/embassy-mcxa/Cargo.toml
@@ -36,8 +36,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
36embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 36embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
37embedded-hal-async = { version = "1.0" } 37embedded-hal-async = { version = "1.0" }
38embedded-hal-nb = { version = "1.0" } 38embedded-hal-nb = { version = "1.0" }
39embedded-io = "0.6" 39embedded-io = "0.7"
40embedded-io-async = { version = "0.6.1" } 40embedded-io-async = { version = "0.7.0" }
41heapless = "0.8" 41heapless = "0.8"
42mcxa-pac = { version = "0.1.0", features = ["rt", "critical-section"] } 42mcxa-pac = { version = "0.1.0", features = ["rt", "critical-section"] }
43nb = "1.1.0" 43nb = "1.1.0"
diff --git a/embassy-mcxa/src/clkout.rs b/embassy-mcxa/src/clkout.rs
index 5b21f24b0..3495eb886 100644
--- a/embassy-mcxa/src/clkout.rs
+++ b/embassy-mcxa/src/clkout.rs
@@ -20,6 +20,7 @@ pub struct ClockOut<'a> {
20} 20}
21 21
22/// Selected clock source to output 22/// Selected clock source to output
23#[derive(Copy, Clone)]
23pub enum ClockOutSel { 24pub enum ClockOutSel {
24 /// 12MHz Internal Oscillator 25 /// 12MHz Internal Oscillator
25 Fro12M, 26 Fro12M,
@@ -36,6 +37,7 @@ pub enum ClockOutSel {
36} 37}
37 38
38/// Configuration for the ClockOut 39/// Configuration for the ClockOut
40#[derive(Copy, Clone)]
39pub struct Config { 41pub struct Config {
40 /// Selected Source Clock 42 /// Selected Source Clock
41 pub sel: ClockOutSel, 43 pub sel: ClockOutSel,
@@ -157,6 +159,12 @@ mod sealed {
157 fn mux(&self) { 159 fn mux(&self) {
158 self.set_function(crate::pac::port0::pcr0::Mux::$func); 160 self.set_function(crate::pac::port0::pcr0::Mux::$func);
159 self.set_pull(Pull::Disabled); 161 self.set_pull(Pull::Disabled);
162
163 // TODO: we may want to expose these as options to allow the slew rate
164 // and drive strength for clocks if they are particularly high speed.
165 //
166 // self.set_drive_strength(crate::pac::port0::pcr0::Dse::Dse1);
167 // self.set_slew_rate(crate::pac::port0::pcr0::Sre::Sre0);
160 } 168 }
161 } 169 }
162 }; 170 };
diff --git a/embassy-mcxa/src/clocks/config.rs b/embassy-mcxa/src/clocks/config.rs
index 0563b8917..4beca5f27 100644
--- a/embassy-mcxa/src/clocks/config.rs
+++ b/embassy-mcxa/src/clocks/config.rs
@@ -119,6 +119,140 @@ pub struct ClocksConfig {
119 pub sirc: SircConfig, 119 pub sirc: SircConfig,
120 /// FRO16K clock source 120 /// FRO16K clock source
121 pub fro16k: Option<Fro16KConfig>, 121 pub fro16k: Option<Fro16KConfig>,
122 /// SOSC, clk_in clock source
123 pub sosc: Option<SoscConfig>,
124 /// SPLL
125 pub spll: Option<SpllConfig>,
126}
127
128// SOSC
129
130/// The mode of the external reference clock
131#[derive(Copy, Clone)]
132pub enum SoscMode {
133 /// Passive crystal oscillators
134 CrystalOscillator,
135 /// Active external reference clock
136 ActiveClock,
137}
138
139/// SOSC/clk_in configuration
140#[derive(Copy, Clone)]
141pub struct SoscConfig {
142 /// Mode of the external reference clock
143 pub mode: SoscMode,
144 /// Specific frequency of the external reference clock
145 pub frequency: u32,
146 /// Power state of the external reference clock
147 pub power: PoweredClock,
148}
149
150// SPLL
151
152/// PLL1/SPLL configuration
153pub struct SpllConfig {
154 /// Input clock source for the PLL1/SPLL
155 pub source: SpllSource,
156 /// Mode of operation for the PLL1/SPLL
157 pub mode: SpllMode,
158 /// Power state of the SPLL
159 pub power: PoweredClock,
160 /// Is the "pll1_clk_div" clock enabled?
161 pub pll1_clk_div: Option<Div8>,
162}
163
164/// Input clock source for the PLL1/SPLL
165pub enum SpllSource {
166 /// External Oscillator (8-50MHz)
167 Sosc,
168 /// Fast Internal Oscillator (45MHz)
169 // NOTE: Figure 69 says "firc_45mhz"/"clk_45m", not "fro_hf_gated",
170 // so this is is always 45MHz.
171 Firc,
172 /// S Internal Oscillator (12M)
173 Sirc,
174 // TODO: the reference manual hints that ROSC is possible,
175 // however the minimum input frequency is 32K, but ROSC is 16K.
176 // Some diagrams show this option, and some diagrams omit it.
177 // SVD shows it as "reserved".
178 //
179 // /// Realtime Internal Oscillator (16K Osc)
180 // Rosc,
181}
182
183/// Mode of operation for the SPLL/PLL1
184///
185/// NOTE: Currently, only "Mode 1" normal operational modes are implemented,
186/// as described in the Reference Manual.
187#[non_exhaustive]
188pub enum SpllMode {
189 /// Mode 1a does not use the Pre/Post dividers.
190 ///
191 /// `Fout = m_mult x SpllSource`
192 ///
193 /// Both of the following constraints must be met:
194 ///
195 /// * Fout: 275MHz to 550MHz
196 /// * Fout: 4.3MHz to 2x Max CPU Frequency
197 Mode1a {
198 /// PLL Multiplier. Must be in the range 1..=65535.
199 m_mult: u16,
200 },
201
202 /// Mode 1b does not use the Pre-divider.
203 ///
204 /// * `if !bypass_p2_div: Fout = (M / (2 x P)) x Fin`
205 /// * `if bypass_p2_div: Fout = (M / P ) x Fin`
206 ///
207 /// Both of the following constraints must be met:
208 ///
209 /// * Fcco: 275MHz to 550MHz
210 /// * `Fcco = m_mult x SpllSource`
211 /// * Fout: 4.3MHz to 2x Max CPU Frequency
212 Mode1b {
213 /// PLL Multiplier. `m_mult` must be in the range 1..=65535.
214 m_mult: u16,
215 /// Post Divider. `p_div` must be in the range 1..=31.
216 p_div: u8,
217 /// Bonus post divider
218 bypass_p2_div: bool,
219 },
220
221 /// Mode 1c does use the Pre-divider, but does not use the Post-divider
222 ///
223 /// `Fout = (M / N) x Fin`
224 ///
225 /// Both of the following constraints must be met:
226 ///
227 /// * Fout: 275MHz to 550MHz
228 /// * Fout: 4.3MHz to 2x Max CPU Frequency
229 Mode1c {
230 /// PLL Multiplier. `m_mult` must be in the range 1..=65535.
231 m_mult: u16,
232 /// Pre Divider. `n_div` must be in the range 1..=255.
233 n_div: u8,
234 },
235
236 /// Mode 1b uses both the Pre and Post dividers.
237 ///
238 /// * `if !bypass_p2_div: Fout = (M / (N x 2 x P)) x Fin`
239 /// * `if bypass_p2_div: Fout = (M / ( N x P )) x Fin`
240 ///
241 /// Both of the following constraints must be met:
242 ///
243 /// * Fcco: 275MHz to 550MHz
244 /// * `Fcco = (m_mult x SpllSource) / (n_div x p_div (x 2))`
245 /// * Fout: 4.3MHz to 2x Max CPU Frequency
246 Mode1d {
247 /// PLL Multiplier. `m_mult` must be in the range 1..=65535.
248 m_mult: u16,
249 /// Pre Divider. `n_div` must be in the range 1..=255.
250 n_div: u8,
251 /// Post Divider. `p_div` must be in the range 1..=31.
252 p_div: u8,
253 /// Bonus post divider
254 bypass_p2_div: bool,
255 },
122} 256}
123 257
124// FIRC/FRO180M 258// FIRC/FRO180M
@@ -199,6 +333,8 @@ impl Default for ClocksConfig {
199 vsys_domain_active: true, 333 vsys_domain_active: true,
200 vdd_core_domain_active: true, 334 vdd_core_domain_active: true,
201 }), 335 }),
336 sosc: None,
337 spll: None,
202 } 338 }
203 } 339 }
204} 340}
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs
index 037f0a656..04559fd04 100644
--- a/embassy-mcxa/src/clocks/mod.rs
+++ b/embassy-mcxa/src/clocks/mod.rs
@@ -87,6 +87,8 @@ pub fn init(settings: ClocksConfig) -> Result<(), ClockError> {
87 operator.configure_firc_clocks()?; 87 operator.configure_firc_clocks()?;
88 operator.configure_sirc_clocks()?; 88 operator.configure_sirc_clocks()?;
89 operator.configure_fro16k_clocks()?; 89 operator.configure_fro16k_clocks()?;
90 operator.configure_sosc()?;
91 operator.configure_spll()?;
90 92
91 // For now, just use FIRC as the main/cpu clock, which should already be 93 // For now, just use FIRC as the main/cpu clock, which should already be
92 // the case on reset 94 // the case on reset
@@ -136,6 +138,7 @@ pub fn with_clocks<R: 'static, F: FnOnce(&Clocks) -> R>(f: F) -> Option<R> {
136#[non_exhaustive] 138#[non_exhaustive]
137pub struct Clocks { 139pub struct Clocks {
138 /// The `clk_in` is a clock provided by an external oscillator 140 /// The `clk_in` is a clock provided by an external oscillator
141 /// AKA SOSC
139 pub clk_in: Option<Clock>, 142 pub clk_in: Option<Clock>,
140 143
141 // FRO180M stuff 144 // FRO180M stuff
@@ -197,6 +200,9 @@ pub struct Clocks {
197 200
198 /// `pll1_clk` is the output of the main system PLL, `pll1`. 201 /// `pll1_clk` is the output of the main system PLL, `pll1`.
199 pub pll1_clk: Option<Clock>, 202 pub pll1_clk: Option<Clock>,
203
204 /// `pll1_clk_div` is a configurable frequency clock, sourced from `pll1_clk`
205 pub pll1_clk_div: Option<Clock>,
200} 206}
201 207
202/// `ClockError` is the main error returned when configuring or checking clock state 208/// `ClockError` is the main error returned when configuring or checking clock state
@@ -433,60 +439,49 @@ pub unsafe fn pulse_reset<G: Gate>() {
433/// selected clocks are active at a suitable level at time of construction. These methods 439/// selected clocks are active at a suitable level at time of construction. These methods
434/// return the frequency of the requested clock, in Hertz, or a [`ClockError`]. 440/// return the frequency of the requested clock, in Hertz, or a [`ClockError`].
435impl Clocks { 441impl Clocks {
436 /// Ensure the `fro_lf_div` clock is active and valid at the given power state. 442 fn ensure_clock_active(
437 pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 443 &self,
438 let Some(clk) = self.fro_lf_div.as_ref() else { 444 clock: &Option<Clock>,
445 name: &'static str,
446 at_level: &PoweredClock,
447 ) -> Result<u32, ClockError> {
448 let Some(clk) = clock.as_ref() else {
439 return Err(ClockError::BadConfig { 449 return Err(ClockError::BadConfig {
440 clock: "fro_lf_div", 450 clock: name,
441 reason: "required but not active", 451 reason: "required but not active",
442 }); 452 });
443 }; 453 };
444 if !clk.power.meets_requirement_of(at_level) { 454 if !clk.power.meets_requirement_of(at_level) {
445 return Err(ClockError::BadConfig { 455 return Err(ClockError::BadConfig {
446 clock: "fro_lf_div", 456 clock: name,
447 reason: "not low power active", 457 reason: "not low power active",
448 }); 458 });
449 } 459 }
450 Ok(clk.frequency) 460 Ok(clk.frequency)
451 } 461 }
452 462
463 /// Ensure the `fro_lf_div` clock is active and valid at the given power state.
464 #[inline]
465 pub fn ensure_fro_lf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
466 self.ensure_clock_active(&self.fro_lf_div, "fro_lf_div", at_level)
467 }
468
453 /// Ensure the `fro_hf` clock is active and valid at the given power state. 469 /// Ensure the `fro_hf` clock is active and valid at the given power state.
470 #[inline]
454 pub fn ensure_fro_hf_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 471 pub fn ensure_fro_hf_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
455 let Some(clk) = self.fro_hf.as_ref() else { 472 self.ensure_clock_active(&self.fro_hf, "fro_hf", at_level)
456 return Err(ClockError::BadConfig {
457 clock: "fro_hf",
458 reason: "required but not active",
459 });
460 };
461 if !clk.power.meets_requirement_of(at_level) {
462 return Err(ClockError::BadConfig {
463 clock: "fro_hf",
464 reason: "not low power active",
465 });
466 }
467 Ok(clk.frequency)
468 } 473 }
469 474
470 /// Ensure the `fro_hf_div` clock is active and valid at the given power state. 475 /// Ensure the `fro_hf_div` clock is active and valid at the given power state.
476 #[inline]
471 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 477 pub fn ensure_fro_hf_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
472 let Some(clk) = self.fro_hf_div.as_ref() else { 478 self.ensure_clock_active(&self.fro_hf_div, "fro_hf_div", at_level)
473 return Err(ClockError::BadConfig {
474 clock: "fro_hf_div",
475 reason: "required but not active",
476 });
477 };
478 if !clk.power.meets_requirement_of(at_level) {
479 return Err(ClockError::BadConfig {
480 clock: "fro_hf_div",
481 reason: "not low power active",
482 });
483 }
484 Ok(clk.frequency)
485 } 479 }
486 480
487 /// Ensure the `clk_in` clock is active and valid at the given power state. 481 /// Ensure the `clk_in` clock is active and valid at the given power state.
488 pub fn ensure_clk_in_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { 482 #[inline]
489 Err(ClockError::NotImplemented { clock: "clk_in" }) 483 pub fn ensure_clk_in_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
484 self.ensure_clock_active(&self.clk_in, "clk_in", at_level)
490 } 485 }
491 486
492 /// Ensure the `clk_16k_vsys` clock is active and valid at the given power state. 487 /// Ensure the `clk_16k_vsys` clock is active and valid at the given power state.
@@ -516,30 +511,21 @@ impl Clocks {
516 } 511 }
517 512
518 /// Ensure the `clk_1m` clock is active and valid at the given power state. 513 /// Ensure the `clk_1m` clock is active and valid at the given power state.
514 #[inline]
519 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> { 515 pub fn ensure_clk_1m_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
520 let Some(clk) = self.clk_1m.as_ref() else { 516 self.ensure_clock_active(&self.clk_1m, "clk_1m", at_level)
521 return Err(ClockError::BadConfig {
522 clock: "clk_1m",
523 reason: "required but not active",
524 });
525 };
526 if !clk.power.meets_requirement_of(at_level) {
527 return Err(ClockError::BadConfig {
528 clock: "clk_1m",
529 reason: "not low power active",
530 });
531 }
532 Ok(clk.frequency)
533 } 517 }
534 518
535 /// Ensure the `pll1_clk` clock is active and valid at the given power state. 519 /// Ensure the `pll1_clk` clock is active and valid at the given power state.
536 pub fn ensure_pll1_clk_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { 520 #[inline]
537 Err(ClockError::NotImplemented { clock: "pll1_clk" }) 521 pub fn ensure_pll1_clk_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
522 self.ensure_clock_active(&self.pll1_clk, "pll1_clk", at_level)
538 } 523 }
539 524
540 /// Ensure the `pll1_clk_div` clock is active and valid at the given power state. 525 /// Ensure the `pll1_clk_div` clock is active and valid at the given power state.
541 pub fn ensure_pll1_clk_div_active(&self, _at_level: &PoweredClock) -> Result<u32, ClockError> { 526 #[inline]
542 Err(ClockError::NotImplemented { clock: "pll1_clk_div" }) 527 pub fn ensure_pll1_clk_div_active(&self, at_level: &PoweredClock) -> Result<u32, ClockError> {
528 self.ensure_clock_active(&self.pll1_clk_div, "pll1_clk_div", at_level)
543 } 529 }
544 530
545 /// Ensure the `CPU_CLK` or `SYSTEM_CLK` is active 531 /// Ensure the `CPU_CLK` or `SYSTEM_CLK` is active
@@ -811,7 +797,7 @@ impl ClockOperator<'_> {
811 Ok(()) 797 Ok(())
812 } 798 }
813 799
814 /// Configure the FRO16K/clk_16k clock family 800 /// Configure the ROSC/FRO16K/clk_16k clock family
815 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> { 801 fn configure_fro16k_clocks(&mut self) -> Result<(), ClockError> {
816 let Some(fro16k) = self.config.fro16k.as_ref() else { 802 let Some(fro16k) = self.config.fro16k.as_ref() else {
817 return Ok(()); 803 return Ok(());
@@ -851,6 +837,485 @@ impl ClockOperator<'_> {
851 837
852 Ok(()) 838 Ok(())
853 } 839 }
840
841 fn ensure_ldo_active(&mut self) {
842 // TODO: Config for the LDO? For now, just enable
843 // using the default settings:
844 // LDOBYPASS: 0/not bypassed
845 // VOUT_SEL: 0b100: 1.1v
846 // LDOEN: 0/Disabled
847 let already_enabled = {
848 let ldocsr = self.scg0.ldocsr().read();
849 ldocsr.ldoen().is_enabled() && ldocsr.vout_ok().is_enabled()
850 };
851 if !already_enabled {
852 self.scg0.ldocsr().modify(|_r, w| w.ldoen().enabled());
853 while self.scg0.ldocsr().read().vout_ok().is_disabled() {}
854 }
855 }
856
857 /// Configure the SOSC/clk_in oscillator
858 fn configure_sosc(&mut self) -> Result<(), ClockError> {
859 let Some(parts) = self.config.sosc.as_ref() else {
860 return Ok(());
861 };
862
863 // Enable (and wait for) LDO to be active
864 self.ensure_ldo_active();
865
866 // TODO: something something pins? This seems to work when the pins are
867 // not enabled, even if GPIO hasn't been initialized at all yet.
868 let eref = match parts.mode {
869 config::SoscMode::CrystalOscillator => pac::scg0::sosccfg::Erefs::Internal,
870 config::SoscMode::ActiveClock => pac::scg0::sosccfg::Erefs::External,
871 };
872 let freq = parts.frequency;
873
874 // TODO: Fix PAC names here
875 //
876 // #[doc = "0: Frequency range select of 8-16 MHz."]
877 // Freq16to20mhz = 0,
878 // #[doc = "1: Frequency range select of 16-25 MHz."]
879 // LowFreq = 1,
880 // #[doc = "2: Frequency range select of 25-40 MHz."]
881 // MediumFreq = 2,
882 // #[doc = "3: Frequency range select of 40-50 MHz."]
883 // HighFreq = 3,
884 let range = match freq {
885 0..8_000_000 => {
886 return Err(ClockError::BadConfig {
887 clock: "clk_in",
888 reason: "freq too low",
889 });
890 }
891 8_000_000..16_000_000 => pac::scg0::sosccfg::Range::Freq16to20mhz,
892 16_000_000..25_000_000 => pac::scg0::sosccfg::Range::LowFreq,
893 25_000_000..40_000_000 => pac::scg0::sosccfg::Range::MediumFreq,
894 40_000_000..50_000_001 => pac::scg0::sosccfg::Range::HighFreq,
895 50_000_001.. => {
896 return Err(ClockError::BadConfig {
897 clock: "clk_in",
898 reason: "freq too high",
899 });
900 }
901 };
902
903 // Set source/erefs and range
904 self.scg0.sosccfg().modify(|_r, w| {
905 w.erefs().variant(eref);
906 w.range().variant(range);
907 w
908 });
909
910 // Disable lock
911 self.scg0.sosccsr().modify(|_r, w| w.lk().clear_bit());
912
913 // TODO: We could enable the SOSC clock monitor. There are some things to
914 // figure out first:
915 //
916 // * This requires SIRC to be enabled, not sure which branch. Maybe fro12m_root?
917 // * If SOSC needs to work in deep sleep, AND the monitor is enabled:
918 // * SIRC also need needs to be low power
919 // * We need to decide if we need an interrupt or a reset if the monitor trips
920
921 // Apply remaining config
922 self.scg0.sosccsr().modify(|_r, w| {
923 // For now, just disable the monitor. See above.
924 w.sosccm().disabled();
925
926 // Set deep sleep mode
927 match parts.power {
928 PoweredClock::NormalEnabledDeepSleepDisabled => {
929 w.soscsten().clear_bit();
930 }
931 PoweredClock::AlwaysEnabled => {
932 w.soscsten().set_bit();
933 }
934 }
935
936 // Enable SOSC
937 w.soscen().enabled()
938 });
939
940 // Wait for SOSC to be valid, check for errors
941 while !self.scg0.sosccsr().read().soscvld().bit_is_set() {}
942 if self.scg0.sosccsr().read().soscerr().is_enabled_and_error() {
943 return Err(ClockError::BadConfig {
944 clock: "clk_in",
945 reason: "soscerr is set",
946 });
947 }
948
949 // Re-lock the sosc
950 self.scg0.sosccsr().modify(|_r, w| w.lk().set_bit());
951
952 self.clocks.clk_in = Some(Clock {
953 frequency: freq,
954 power: parts.power,
955 });
956
957 Ok(())
958 }
959
960 fn configure_spll(&mut self) -> Result<(), ClockError> {
961 // # Vocab
962 //
963 // | Name | Meaning |
964 // | :--- | :--- |
965 // | Fin | Frequency of clkin |
966 // | clkout | Output clock of the PLL |
967 // | Fout | Frequency of clkout (depends on mode) |
968 // | clkref | PLL Reference clock, the input clock to the PFD |
969 // | Fref | Frequency of clkref, Fref = Fin / N |
970 // | Fcco | Frequency of the output clock of the CCO, Fcco = M * Fref |
971 // | N | Predivider value |
972 // | M | Feedback divider value |
973 // | P | Postdivider value |
974 // | Tpon | PLL start-up time |
975
976 // No PLL? Nothing to do!
977 let Some(cfg) = self.config.spll.as_ref() else {
978 return Ok(());
979 };
980
981 // Ensure the LDO is active
982 self.ensure_ldo_active();
983
984 // match on the source, ensure it is active already
985 let res = match cfg.source {
986 config::SpllSource::Sosc => self
987 .clocks
988 .clk_in
989 .as_ref()
990 .map(|c| (c, pac::scg0::spllctrl::Source::Sosc))
991 .ok_or("sosc not active"),
992 config::SpllSource::Firc => self
993 .clocks
994 .clk_45m
995 .as_ref()
996 .map(|c| (c, pac::scg0::spllctrl::Source::Firc))
997 .ok_or("firc not active"),
998 config::SpllSource::Sirc => self
999 .clocks
1000 .fro_12m
1001 .as_ref()
1002 .map(|c| (c, pac::scg0::spllctrl::Source::Sirc))
1003 .ok_or("sirc not active"),
1004 };
1005 // This checks if active
1006 let (clk, variant) = res.map_err(|s| ClockError::BadConfig {
1007 clock: "spll",
1008 reason: s,
1009 })?;
1010 // This checks the correct power reqs
1011 if !clk.power.meets_requirement_of(&cfg.power) {
1012 return Err(ClockError::BadConfig {
1013 clock: "spll",
1014 reason: "needs low power source",
1015 });
1016 }
1017
1018 // Bandwidth calc
1019 //
1020 // > In normal applications, you must calculate the bandwidth manually by using the feedback divider M (ranging from 1 to 216-1),
1021 // > Equation 1, and Equation 2. The PLL is automatically stable in such case. In normal applications, SPLLCTRL[BANDDIRECT] must
1022 // > be 0; in this case, the bandwidth changes as a function of M.
1023 if clk.frequency == 0 {
1024 return Err(ClockError::BadConfig {
1025 clock: "spll",
1026 reason: "internal error",
1027 });
1028 }
1029
1030 // These are calculated differently depending on the mode.
1031 let f_in = clk.frequency;
1032 let bp_pre: bool;
1033 let bp_post: bool;
1034 let bp_post2: bool;
1035 let m: u16;
1036 let p: Option<u8>;
1037 let n: Option<u8>;
1038
1039 // Calculate both Fout and Fcco so we can ensure they don't overflow
1040 // and are in range
1041 let fout: Option<u32>;
1042 let fcco: Option<u32>;
1043
1044 let m_check = |m: u16| {
1045 if !(1..=u16::MAX).contains(&m) {
1046 Err(ClockError::BadConfig {
1047 clock: "spll",
1048 reason: "m_mult out of range",
1049 })
1050 } else {
1051 Ok(m)
1052 }
1053 };
1054 let p_check = |p: u8| {
1055 if !(1..=31).contains(&p) {
1056 Err(ClockError::BadConfig {
1057 clock: "spll",
1058 reason: "p_div out of range",
1059 })
1060 } else {
1061 Ok(p)
1062 }
1063 };
1064 let n_check = |n: u8| {
1065 if !(1..=u8::MAX).contains(&n) {
1066 Err(ClockError::BadConfig {
1067 clock: "spll",
1068 reason: "n_div out of range",
1069 })
1070 } else {
1071 Ok(n)
1072 }
1073 };
1074
1075 match cfg.mode {
1076 // Fout = M x Fin
1077 config::SpllMode::Mode1a { m_mult } => {
1078 bp_pre = true;
1079 bp_post = true;
1080 bp_post2 = false;
1081 m = m_check(m_mult)?;
1082 p = None;
1083 n = None;
1084 fcco = f_in.checked_mul(m_mult as u32);
1085 fout = fcco;
1086 }
1087 // if !bypass_p2_div: Fout = (M / (2 x P)) x Fin
1088 // if bypass_p2_div: Fout = (M / P ) x Fin
1089 config::SpllMode::Mode1b {
1090 m_mult,
1091 p_div,
1092 bypass_p2_div,
1093 } => {
1094 bp_pre = true;
1095 bp_post = false;
1096 bp_post2 = bypass_p2_div;
1097 m = m_check(m_mult)?;
1098 p = Some(p_check(p_div)?);
1099 n = None;
1100 let mut div = p_div as u32;
1101 if !bypass_p2_div {
1102 div *= 2;
1103 }
1104 fcco = f_in.checked_mul(m_mult as u32);
1105 fout = (f_in / div).checked_mul(m_mult as u32);
1106 }
1107 // Fout = (M / N) x Fin
1108 config::SpllMode::Mode1c { m_mult, n_div } => {
1109 bp_pre = false;
1110 bp_post = true;
1111 bp_post2 = false;
1112 m = m_check(m_mult)?;
1113 p = None;
1114 n = Some(n_check(n_div)?);
1115 fcco = (f_in / (n_div as u32)).checked_mul(m_mult as u32);
1116 fout = fcco;
1117 }
1118 // if !bypass_p2_div: Fout = (M / (N x 2 x P)) x Fin
1119 // if bypass_p2_div: Fout = (M / ( N x P )) x Fin
1120 config::SpllMode::Mode1d {
1121 m_mult,
1122 n_div,
1123 p_div,
1124 bypass_p2_div,
1125 } => {
1126 bp_pre = false;
1127 bp_post = false;
1128 bp_post2 = bypass_p2_div;
1129 m = m_check(m_mult)?;
1130 p = Some(p_check(p_div)?);
1131 n = Some(n_check(n_div)?);
1132 // This can't overflow: u8 x u8 (x 2) always fits in u32
1133 let mut div = (p_div as u32) * (n_div as u32);
1134 if !bypass_p2_div {
1135 div *= 2;
1136 }
1137 fcco = (f_in / (n_div as u32)).checked_mul(m_mult as u32);
1138 fout = (f_in / div).checked_mul(m_mult as u32);
1139 }
1140 };
1141
1142 // Dump all the PLL calcs if needed for debugging
1143 #[cfg(feature = "defmt")]
1144 {
1145 defmt::debug!("f_in: {:?}", f_in);
1146 defmt::debug!("bp_pre: {:?}", bp_pre);
1147 defmt::debug!("bp_post: {:?}", bp_post);
1148 defmt::debug!("bp_post2: {:?}", bp_post2);
1149 defmt::debug!("m: {:?}", m);
1150 defmt::debug!("p: {:?}", p);
1151 defmt::debug!("n: {:?}", n);
1152 defmt::debug!("fout: {:?}", fout);
1153 defmt::debug!("fcco: {:?}", fcco);
1154 }
1155
1156 // Ensure the Fcco and Fout calcs didn't overflow
1157 let fcco = fcco.ok_or(ClockError::BadConfig {
1158 clock: "spll",
1159 reason: "fcco invalid1",
1160 })?;
1161 let fout = fout.ok_or(ClockError::BadConfig {
1162 clock: "spll",
1163 reason: "fout invalid",
1164 })?;
1165
1166 // Fcco: 275MHz to 550MHz
1167 if !(275_000_000..=550_000_000).contains(&fcco) {
1168 return Err(ClockError::BadConfig {
1169 clock: "spll",
1170 reason: "fcco invalid2",
1171 });
1172 }
1173
1174 // TODO: Different for different CPUs?
1175 const CPU_MAX_FREQ: u32 = 180_000_000;
1176
1177 // Fout: 4.3MHz to 2x Max CPU Frequency
1178 if !(4_300_000..=(2 * CPU_MAX_FREQ)).contains(&fout) {
1179 return Err(ClockError::BadConfig {
1180 clock: "spll",
1181 reason: "fout invalid",
1182 });
1183 }
1184
1185 // A = floor(m / 4) + 1
1186 let selp_a = (m / 4) + 1;
1187 // SELP = A if A < 31
1188 // = 31 if A >= 31
1189 let selp = selp_a.min(31);
1190
1191 // A = 1 if M >= 8000
1192 // = floor(8000 / M) if 8000 > M >= 122
1193 // = 2 x floor(M / 4) / 3 if 122 > M >= 1
1194 let seli_a = if m >= 8000 {
1195 1
1196 } else if m >= 122 {
1197 8000 / m
1198 } else {
1199 (2 * (m / 4)) / 3
1200 };
1201 // SELI = A if A < 63
1202 // = 63 if A >= 63
1203 let seli = seli_a.min(63);
1204 // SELR must be 0.
1205 let selr = 0;
1206
1207 self.scg0.spllctrl().modify(|_r, w| {
1208 w.source().variant(variant);
1209 unsafe {
1210 w.selp().bits(selp as u8);
1211 w.seli().bits(seli as u8);
1212 w.selr().bits(selr);
1213 }
1214 w
1215 });
1216
1217 if let Some(n) = n {
1218 self.scg0.spllndiv().modify(|_r, w| unsafe { w.ndiv().bits(n) });
1219 }
1220 if let Some(p) = p {
1221 self.scg0.spllpdiv().modify(|_r, w| unsafe { w.pdiv().bits(p) });
1222 }
1223 self.scg0.spllmdiv().modify(|_r, w| unsafe { w.mdiv().bits(m) });
1224
1225 self.scg0.spllctrl().modify(|_r, w| {
1226 w.bypassprediv().bit(bp_pre);
1227 w.bypasspostdiv().bit(bp_post);
1228 w.bypasspostdiv2().bit(bp_post2);
1229
1230 // TODO: support FRM?
1231 w.frm().disabled();
1232
1233 w
1234 });
1235
1236 // Unlock
1237 self.scg0.spllcsr().modify(|_r, w| w.lk().write_enabled());
1238
1239 // TODO: Support clock monitors?
1240 // self.scg0.spllcsr().modify(|_r, w| w.spllcm().?);
1241
1242 self.scg0.trim_lock().write(|w| unsafe {
1243 w.trim_lock_key().bits(0x5a5a);
1244 w.trim_unlock().not_locked()
1245 });
1246
1247 // SPLLLOCK_CNFG: The lock time programmed in this register must be
1248 // equal to meet the PLL 500μs lock time plus the 300 refclk count startup.
1249 //
1250 // LOCK_TIME = 500μs/T ref + 300, F ref = F in /N (input frequency divided by pre-divider ratio).
1251 //
1252 // 500us is 1/2000th of a second, therefore Fref / 2000 is the number of cycles in 500us.
1253 let f_ref = if let Some(n) = n { f_in / (n as u32) } else { f_in };
1254 let lock_time = f_ref.div_ceil(2000) + 300;
1255 self.scg0
1256 .splllock_cnfg()
1257 .write(|w| unsafe { w.lock_time().bits(lock_time) });
1258
1259 // TODO: Support Spread spectrum?
1260
1261 self.scg0.spllcsr().modify(|_r, w| {
1262 w.spllclken().enabled();
1263 w.spllpwren().enabled();
1264 w.spllsten().bit(matches!(cfg.power, PoweredClock::AlwaysEnabled));
1265 w
1266 });
1267
1268 // Wait for SPLL to set up
1269 loop {
1270 let csr = self.scg0.spllcsr().read();
1271 if csr.spll_lock().is_enabled_and_valid() {
1272 if csr.spllerr().is_enabled_and_error() {
1273 return Err(ClockError::BadConfig {
1274 clock: "spll",
1275 reason: "spllerr is set",
1276 });
1277 }
1278 break;
1279 }
1280 }
1281
1282 // Re-lock SPLL CSR
1283 self.scg0.spllcsr().modify(|_r, w| w.lk().write_disabled());
1284
1285 // Store clock state
1286 self.clocks.pll1_clk = Some(Clock {
1287 frequency: fout,
1288 power: cfg.power,
1289 });
1290
1291 // Do we enable the `pll1_clk_div` output?
1292 if let Some(d) = cfg.pll1_clk_div.as_ref() {
1293 // Halt and reset the div; then set our desired div.
1294 self.syscon.pll1clkdiv().write(|w| {
1295 w.halt().halt();
1296 w.reset().asserted();
1297 unsafe { w.div().bits(d.into_bits()) };
1298 w
1299 });
1300 // Then unhalt it, and reset it
1301 self.syscon.pll1clkdiv().write(|w| {
1302 w.halt().run();
1303 w.reset().released();
1304 w
1305 });
1306
1307 // Wait for clock to stabilize
1308 while self.syscon.pll1clkdiv().read().unstab().is_ongoing() {}
1309
1310 // Store off the clock info
1311 self.clocks.pll1_clk_div = Some(Clock {
1312 frequency: fout / d.into_divisor(),
1313 power: cfg.power,
1314 });
1315 }
1316
1317 Ok(())
1318 }
854} 1319}
855 1320
856// 1321//
diff --git a/embassy-mcxa/src/dma.rs b/embassy-mcxa/src/dma.rs
index 8d519d99b..b68f55e65 100644
--- a/embassy-mcxa/src/dma.rs
+++ b/embassy-mcxa/src/dma.rs
@@ -1924,7 +1924,7 @@ impl Iterator for TransferErrorRawIter {
1924 1924
1925 for (mask, var) in TransferErrorRaw::MAP { 1925 for (mask, var) in TransferErrorRaw::MAP {
1926 // If the bit is set... 1926 // If the bit is set...
1927 if self.0 | mask != 0 { 1927 if self.0 & mask != 0 {
1928 // clear the bit 1928 // clear the bit
1929 self.0 &= !mask; 1929 self.0 &= !mask;
1930 // and return the answer 1930 // and return the answer
diff --git a/embassy-mcxa/src/gpio.rs b/embassy-mcxa/src/gpio.rs
index 65f8df985..29d66656d 100644
--- a/embassy-mcxa/src/gpio.rs
+++ b/embassy-mcxa/src/gpio.rs
@@ -81,7 +81,7 @@ fn GPIO4() {
81 irq_handler(4, crate::pac::Gpio4::ptr()); 81 irq_handler(4, crate::pac::Gpio4::ptr());
82} 82}
83 83
84pub(crate) unsafe fn init() { 84pub(crate) unsafe fn interrupt_init() {
85 use embassy_hal_internal::interrupt::InterruptExt; 85 use embassy_hal_internal::interrupt::InterruptExt;
86 86
87 crate::pac::interrupt::GPIO0.enable(); 87 crate::pac::interrupt::GPIO0.enable();
@@ -320,8 +320,12 @@ impl GpioPin for AnyPin {}
320 320
321macro_rules! impl_pin { 321macro_rules! impl_pin {
322 ($peri:ident, $port:expr, $pin:expr, $block:ident) => { 322 ($peri:ident, $port:expr, $pin:expr, $block:ident) => {
323 impl_pin!(crate::peripherals, $peri, $port, $pin, $block);
324 };
325
326 ($perip:path, $peri:ident, $port:expr, $pin:expr, $block:ident) => {
323 paste! { 327 paste! {
324 impl SealedPin for crate::peripherals::$peri { 328 impl SealedPin for $perip::$peri {
325 fn pin_port(&self) -> usize { 329 fn pin_port(&self) -> usize {
326 $port * 32 + $pin 330 $port * 32 + $pin
327 } 331 }
@@ -372,15 +376,15 @@ macro_rules! impl_pin {
372 } 376 }
373 } 377 }
374 378
375 impl GpioPin for crate::peripherals::$peri {} 379 impl GpioPin for $perip::$peri {}
376 380
377 impl From<crate::peripherals::$peri> for AnyPin { 381 impl From<$perip::$peri> for AnyPin {
378 fn from(value: crate::peripherals::$peri) -> Self { 382 fn from(value: $perip::$peri) -> Self {
379 value.degrade() 383 value.degrade()
380 } 384 }
381 } 385 }
382 386
383 impl crate::peripherals::$peri { 387 impl $perip::$peri {
384 /// Convenience helper to obtain a type-erased handle to this pin. 388 /// Convenience helper to obtain a type-erased handle to this pin.
385 pub fn degrade(&self) -> AnyPin { 389 pub fn degrade(&self) -> AnyPin {
386 AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg()) 390 AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg())
@@ -453,8 +457,8 @@ impl_pin!(P1_26, 1, 26, Gpio1);
453impl_pin!(P1_27, 1, 27, Gpio1); 457impl_pin!(P1_27, 1, 27, Gpio1);
454impl_pin!(P1_28, 1, 28, Gpio1); 458impl_pin!(P1_28, 1, 28, Gpio1);
455impl_pin!(P1_29, 1, 29, Gpio1); 459impl_pin!(P1_29, 1, 29, Gpio1);
456impl_pin!(P1_30, 1, 30, Gpio1); 460impl_pin!(crate::internal_peripherals, P1_30, 1, 30, Gpio1);
457impl_pin!(P1_31, 1, 31, Gpio1); 461impl_pin!(crate::internal_peripherals, P1_31, 1, 31, Gpio1);
458 462
459impl_pin!(P2_0, 2, 0, Gpio2); 463impl_pin!(P2_0, 2, 0, Gpio2);
460impl_pin!(P2_1, 2, 1, Gpio2); 464impl_pin!(P2_1, 2, 1, Gpio2);
diff --git a/embassy-mcxa/src/i2c/mod.rs b/embassy-mcxa/src/i2c/mod.rs
index 9a014224a..55c933f71 100644
--- a/embassy-mcxa/src/i2c/mod.rs
+++ b/embassy-mcxa/src/i2c/mod.rs
@@ -180,8 +180,11 @@ impl_pin!(P1_12, LPI2C1, Mux2, SdaPin);
180impl_pin!(P1_13, LPI2C1, Mux2, SclPin); 180impl_pin!(P1_13, LPI2C1, Mux2, SclPin);
181impl_pin!(P1_14, LPI2C1, Mux2, SclPin); 181impl_pin!(P1_14, LPI2C1, Mux2, SclPin);
182impl_pin!(P1_15, LPI2C1, Mux2, SdaPin); 182impl_pin!(P1_15, LPI2C1, Mux2, SdaPin);
183impl_pin!(P1_30, LPI2C0, Mux3, SdaPin); 183// NOTE: P1_30 and P1_31 are typically used for the external oscillator
184impl_pin!(P1_31, LPI2C0, Mux3, SclPin); 184// For now, we just don't give users these pins.
185//
186// impl_pin!(P1_30, LPI2C0, Mux3, SdaPin);
187// impl_pin!(P1_31, LPI2C0, Mux3, SclPin);
185impl_pin!(P3_27, LPI2C3, Mux2, SclPin); 188impl_pin!(P3_27, LPI2C3, Mux2, SclPin);
186impl_pin!(P3_28, LPI2C3, Mux2, SdaPin); 189impl_pin!(P3_28, LPI2C3, Mux2, SdaPin);
187// impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin? 190// impl_pin!(P3_29, LPI2C3, Mux2, HreqPin); What is this HREQ pin?
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs
index 6383353db..76fd58210 100644
--- a/embassy-mcxa/src/lib.rs
+++ b/embassy-mcxa/src/lib.rs
@@ -175,8 +175,18 @@ embassy_hal_internal::peripherals!(
175 P1_27, 175 P1_27,
176 P1_28, 176 P1_28,
177 P1_29, 177 P1_29,
178 P1_30, 178 // TODO: These pins are optionally used as the clock sources for SOSC.
179 P1_31, 179 // Ideally, we'd want to have a custom version of the `peripheral!` macro
180 // that presented these as `Option<Peri<'_, P1_30>>` instead of `Peri<'_, P1_30>`
181 // when the user DOES enable the external SOSC. For now, I'm guessing MOST designs
182 // will have an external clock sitting on these pins anyway, so we just notch them
183 // out from the `Peripherals` struct given to users.
184 //
185 // If you find this and want your extra two pins to be available: please open an
186 // embassy issue to discuss how we could do this.
187 //
188 // P1_30,
189 // P1_31,
180 190
181 P2_0, 191 P2_0,
182 P2_1, 192 P2_1,
@@ -337,6 +347,14 @@ embassy_hal_internal::peripherals!(
337 WWDT0, 347 WWDT0,
338); 348);
339 349
350// See commented out items above to understand why we create the instances
351// here but don't give them to the user.
352pub(crate) mod internal_peripherals {
353 embassy_hal_internal::peripherals_definition!(P1_30, P1_31,);
354
355 pub(crate) use peripherals::*;
356}
357
340// Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. 358// Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it.
341 359
342// Re-export interrupt traits and types 360// Re-export interrupt traits and types
@@ -369,7 +387,7 @@ pub fn init(cfg: crate::config::Config) -> Peripherals {
369 crate::clocks::init(cfg.clock_cfg).unwrap(); 387 crate::clocks::init(cfg.clock_cfg).unwrap();
370 388
371 unsafe { 389 unsafe {
372 crate::gpio::init(); 390 crate::gpio::interrupt_init();
373 } 391 }
374 392
375 // Initialize DMA controller (clock, reset, configuration) 393 // Initialize DMA controller (clock, reset, configuration)
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs
index bce3986b5..ae511e8d3 100644
--- a/embassy-mcxa/src/lpuart/mod.rs
+++ b/embassy-mcxa/src/lpuart/mod.rs
@@ -568,6 +568,27 @@ pub enum Error {
568 ClockSetup(ClockError), 568 ClockSetup(ClockError),
569} 569}
570 570
571impl core::fmt::Display for Error {
572 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
573 match self {
574 Error::Read => write!(f, "Read error"),
575 Error::Overrun => write!(f, "Buffer overflow"),
576 Error::Noise => write!(f, "Noise error"),
577 Error::Framing => write!(f, "Framing error"),
578 Error::Parity => write!(f, "Parity error"),
579 Error::Fail => write!(f, "Failure"),
580 Error::InvalidArgument => write!(f, "Invalid argument"),
581 Error::UnsupportedBaudrate => write!(f, "Unsupported baud rate"),
582 Error::RxFifoEmpty => write!(f, "RX FIFO empty"),
583 Error::TxFifoFull => write!(f, "TX FIFO full"),
584 Error::TxBusy => write!(f, "TX busy"),
585 Error::ClockSetup(e) => write!(f, "Clock setup error: {:?}", e),
586 }
587 }
588}
589
590impl core::error::Error for Error {}
591
571/// A specialized Result type for LPUART operations 592/// A specialized Result type for LPUART operations
572pub type Result<T> = core::result::Result<T, Error>; 593pub type Result<T> = core::result::Result<T, Error>;
573 594
diff --git a/embassy-mcxa/src/reset_reason.rs b/embassy-mcxa/src/reset_reason.rs
index f9a9ce096..1787690a7 100644
--- a/embassy-mcxa/src/reset_reason.rs
+++ b/embassy-mcxa/src/reset_reason.rs
@@ -6,45 +6,158 @@
6 6
7/// Reads the most recent reset reason from the Core Mode Controller 7/// Reads the most recent reset reason from the Core Mode Controller
8/// (CMC). 8/// (CMC).
9pub fn reset_reason() -> ResetReason { 9pub fn reset_reason() -> ResetReasonRaw {
10 let regs = unsafe { &*crate::pac::Cmc::steal() }; 10 let regs = unsafe { &*crate::pac::Cmc::steal() };
11 let srs = regs.srs().read().bits();
12 ResetReasonRaw(srs)
13}
14
15/// Raw reset reason bits. Can be queried or all reasons can be iterated over
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[derive(Copy, Clone, Debug)]
18pub struct ResetReasonRaw(u32);
19
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[derive(Copy, Clone, Debug)]
22pub struct ResetReasonRawIter(u32);
23
24impl ResetReasonRaw {
25 const MAP: &[(u32, ResetReason)] = &[
26 (1 << 0, ResetReason::WakeUp),
27 (1 << 1, ResetReason::Por),
28 (1 << 2, ResetReason::VoltageDetect),
29 (1 << 4, ResetReason::Warm),
30 (1 << 5, ResetReason::Fatal),
31 (1 << 8, ResetReason::Pin),
32 (1 << 9, ResetReason::Dap),
33 (1 << 10, ResetReason::ResetAckTimeout),
34 (1 << 11, ResetReason::LowPowerAckTimeout),
35 (1 << 12, ResetReason::SystemClockGeneration),
36 (1 << 13, ResetReason::Wwdt0),
37 (1 << 14, ResetReason::Software),
38 (1 << 15, ResetReason::Lockup),
39 (1 << 26, ResetReason::Cdog0),
40 (1 << 27, ResetReason::Cdog1),
41 (1 << 28, ResetReason::Jtag),
42 ];
43
44 /// Convert to an iterator of contained reset reasons
45 pub fn into_iter(self) -> ResetReasonRawIter {
46 ResetReasonRawIter(self.0)
47 }
48
49 /// Wake up
50 #[inline]
51 pub fn is_wakeup(&self) -> bool {
52 (self.0 & (1 << 0)) != 0
53 }
54
55 /// Power-on Reset
56 #[inline]
57 pub fn is_por(&self) -> bool {
58 (self.0 & (1 << 1)) != 0
59 }
60
61 /// Voltage detect
62 #[inline]
63 pub fn is_voltage_detect(&self) -> bool {
64 (self.0 & (1 << 2)) != 0
65 }
66
67 /// Warm
68 #[inline]
69 pub fn is_warm(&self) -> bool {
70 (self.0 & (1 << 4)) != 0
71 }
72
73 /// Fatal
74 #[inline]
75 pub fn is_fatal(&self) -> bool {
76 (self.0 & (1 << 5)) != 0
77 }
78
79 /// Pin
80 #[inline]
81 pub fn is_pin(&self) -> bool {
82 (self.0 & (1 << 8)) != 0
83 }
84
85 /// DAP
86 #[inline]
87 pub fn is_dap(&self) -> bool {
88 (self.0 & (1 << 9)) != 0
89 }
90
91 /// Reset ack timeout
92 #[inline]
93 pub fn is_reset_ack_timeout(&self) -> bool {
94 (self.0 & (1 << 10)) != 0
95 }
96
97 /// Low power ack timeout
98 #[inline]
99 pub fn is_low_power_ack_timeout(&self) -> bool {
100 (self.0 & (1 << 11)) != 0
101 }
102
103 /// System clock generation
104 #[inline]
105 pub fn is_system_clock_generation(&self) -> bool {
106 (self.0 & (1 << 12)) != 0
107 }
108
109 /// Watchdog 0
110 #[inline]
111 pub fn is_watchdog0(&self) -> bool {
112 (self.0 & (1 << 13)) != 0
113 }
114
115 /// Software
116 pub fn is_software(&self) -> bool {
117 (self.0 & (1 << 14)) != 0
118 }
119
120 /// Lockup
121 pub fn is_lockup(&self) -> bool {
122 (self.0 & (1 << 15)) != 0
123 }
124
125 /// Code watchdog 0
126 pub fn is_code_watchdog0(&self) -> bool {
127 (self.0 & (1 << 26)) != 0
128 }
129
130 /// Code watchdog 1
131 pub fn is_code_watchdog1(&self) -> bool {
132 (self.0 & (1 << 27)) != 0
133 }
134
135 /// JTAG
136 pub fn is_jtag(&self) -> bool {
137 (self.0 & (1 << 28)) != 0
138 }
139}
11 140
12 let srs = regs.srs().read(); 141impl Iterator for ResetReasonRawIter {
13 142 type Item = ResetReason;
14 if srs.wakeup().is_enabled() { 143
15 ResetReason::WakeUp 144 fn next(&mut self) -> Option<Self::Item> {
16 } else if srs.por().bit_is_set() { 145 if self.0 == 0 {
17 ResetReason::Por 146 return None;
18 } else if srs.vd().bit_is_set() { 147 }
19 ResetReason::VoltageDetect 148
20 } else if srs.warm().bit_is_set() { 149 for (mask, var) in ResetReasonRaw::MAP {
21 ResetReason::Warm 150 // If the bit is set...
22 } else if srs.fatal().bit_is_set() { 151 if self.0 & mask != 0 {
23 ResetReason::Fatal 152 // clear the bit
24 } else if srs.pin().bit_is_set() { 153 self.0 &= !mask;
25 ResetReason::Pin 154 // and return the answer
26 } else if srs.dap().bit_is_set() { 155 return Some(*var);
27 ResetReason::Dap 156 }
28 } else if srs.rstack().bit_is_set() { 157 }
29 ResetReason::ResetAckTimeout 158
30 } else if srs.lpack().bit_is_set() { 159 // Shouldn't happen, but oh well.
31 ResetReason::LowPowerAckTimeout 160 None
32 } else if srs.scg().bit_is_set() {
33 ResetReason::SystemClockGeneration
34 } else if srs.wwdt0().bit_is_set() {
35 ResetReason::Wwdt0
36 } else if srs.sw().bit_is_set() {
37 ResetReason::Software
38 } else if srs.lockup().bit_is_set() {
39 ResetReason::Lockup
40 } else if srs.cdog0().bit_is_set() {
41 ResetReason::Cdog0
42 } else if srs.cdog1().bit_is_set() {
43 ResetReason::Cdog1
44 } else if srs.jtag().bit_is_set() {
45 ResetReason::Jtag
46 } else {
47 ResetReason::Tamper
48 } 161 }
49} 162}
50 163
diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md
index 6972a8472..19275f35a 100644
--- a/embassy-mspm0/CHANGELOG.md
+++ b/embassy-mspm0/CHANGELOG.md
@@ -19,4 +19,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19- feat: Add i2c target implementation (#4605) 19- feat: Add i2c target implementation (#4605)
20- fix: group irq handlers must check for NO_INTR (#4785) 20- fix: group irq handlers must check for NO_INTR (#4785)
21- feat: Add read_reset_cause function 21- feat: Add read_reset_cause function
22- feat: Add module Mathacl & example for mspm0g3507 (#4897) \ No newline at end of file 22- feat: Add module Mathacl & example for mspm0g3507 (#4897)
23- feat: Add MSPM0G5187 supportt
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
index 254e0209b..c7f5de6a1 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -61,8 +61,8 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["un
61embedded-hal = { version = "1.0" } 61embedded-hal = { version = "1.0" }
62embedded-hal-nb = { version = "1.0" } 62embedded-hal-nb = { version = "1.0" }
63embedded-hal-async = { version = "1.0" } 63embedded-hal-async = { version = "1.0" }
64embedded-io = "0.6.1" 64embedded-io = { version = "0.7.1" }
65embedded-io-async = "0.6.1" 65embedded-io-async = { version = "0.7.0" }
66 66
67defmt = { version = "1.0.1", optional = true } 67defmt = { version = "1.0.1", optional = true }
68fixed = "1.29" 68fixed = "1.29"
@@ -73,7 +73,7 @@ critical-section = "1.2.0"
73micromath = "2.0.0" 73micromath = "2.0.0"
74 74
75# mspm0-metapac = { version = "" } 75# mspm0-metapac = { version = "" }
76mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852" } 76mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e91edd86813aa94cbb6737d34e4f1d22b8487cb6" }
77 77
78[build-dependencies] 78[build-dependencies]
79proc-macro2 = "1.0.94" 79proc-macro2 = "1.0.94"
@@ -81,7 +81,7 @@ quote = "1.0.40"
81cfg_aliases = "0.2.1" 81cfg_aliases = "0.2.1"
82 82
83# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } 83# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
84mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852", default-features = false, features = ["metadata"] } 84mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e91edd86813aa94cbb6737d34e4f1d22b8487cb6", default-features = false, features = ["metadata"] }
85 85
86[features] 86[features]
87default = ["rt"] 87default = ["rt"]
@@ -153,15 +153,14 @@ time-driver-tima1 = ["_time-driver"]
153#! 153#!
154#! **Important:** Do not forget to adapt the target chip in your toolchain, 154#! **Important:** Do not forget to adapt the target chip in your toolchain,
155#! e.g. in `.cargo/config.toml`. 155#! e.g. in `.cargo/config.toml`.
156
157mspm0c1103dgs20 = ["mspm0-metapac/mspm0c1103dgs20"] 156mspm0c1103dgs20 = ["mspm0-metapac/mspm0c1103dgs20"]
158mspm0c1103dsg = ["mspm0-metapac/mspm0c1103dsg"]
159mspm0c1103dyy = ["mspm0-metapac/mspm0c1103dyy"]
160mspm0c1103ruk = ["mspm0-metapac/mspm0c1103ruk"] 157mspm0c1103ruk = ["mspm0-metapac/mspm0c1103ruk"]
158mspm0c1103dyy = ["mspm0-metapac/mspm0c1103dyy"]
159mspm0c1103dsg = ["mspm0-metapac/mspm0c1103dsg"]
161mspm0c1104dgs20 = ["mspm0-metapac/mspm0c1104dgs20"] 160mspm0c1104dgs20 = ["mspm0-metapac/mspm0c1104dgs20"]
162mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"]
163mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"]
164mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] 161mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"]
162mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"]
163mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"]
165mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] 164mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"]
166mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"] 165mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"]
167mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"] 166mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"]
@@ -181,43 +180,54 @@ mspm0c1106rge = ["mspm0-metapac/mspm0c1106rge"]
181mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"] 180mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"]
182mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"] 181mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"]
183mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"] 182mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"]
184mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"]
185mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"]
186mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"]
187mspm0g1105rge = ["mspm0-metapac/mspm0g1105rge"] 183mspm0g1105rge = ["mspm0-metapac/mspm0g1105rge"]
188mspm0g1105rgz = ["mspm0-metapac/mspm0g1105rgz"] 184mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"]
189mspm0g1105rhb = ["mspm0-metapac/mspm0g1105rhb"] 185mspm0g1105rhb = ["mspm0-metapac/mspm0g1105rhb"]
190mspm0g1106dgs28 = ["mspm0-metapac/mspm0g1106dgs28"] 186mspm0g1105rgz = ["mspm0-metapac/mspm0g1105rgz"]
191mspm0g1106pm = ["mspm0-metapac/mspm0g1106pm"] 187mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"]
192mspm0g1106pt = ["mspm0-metapac/mspm0g1106pt"] 188mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"]
193mspm0g1106rge = ["mspm0-metapac/mspm0g1106rge"] 189mspm0g1106rge = ["mspm0-metapac/mspm0g1106rge"]
194mspm0g1106rgz = ["mspm0-metapac/mspm0g1106rgz"] 190mspm0g1106dgs28 = ["mspm0-metapac/mspm0g1106dgs28"]
195mspm0g1106rhb = ["mspm0-metapac/mspm0g1106rhb"] 191mspm0g1106rhb = ["mspm0-metapac/mspm0g1106rhb"]
196mspm0g1107dgs28 = ["mspm0-metapac/mspm0g1107dgs28"] 192mspm0g1106rgz = ["mspm0-metapac/mspm0g1106rgz"]
197mspm0g1107pm = ["mspm0-metapac/mspm0g1107pm"] 193mspm0g1106pt = ["mspm0-metapac/mspm0g1106pt"]
198mspm0g1107pt = ["mspm0-metapac/mspm0g1107pt"] 194mspm0g1106pm = ["mspm0-metapac/mspm0g1106pm"]
199mspm0g1107rge = ["mspm0-metapac/mspm0g1107rge"] 195mspm0g1107rge = ["mspm0-metapac/mspm0g1107rge"]
200mspm0g1107rgz = ["mspm0-metapac/mspm0g1107rgz"] 196mspm0g1107dgs28 = ["mspm0-metapac/mspm0g1107dgs28"]
201mspm0g1107rhb = ["mspm0-metapac/mspm0g1107rhb"] 197mspm0g1107rhb = ["mspm0-metapac/mspm0g1107rhb"]
198mspm0g1107rgz = ["mspm0-metapac/mspm0g1107rgz"]
199mspm0g1107pt = ["mspm0-metapac/mspm0g1107pt"]
200mspm0g1107pm = ["mspm0-metapac/mspm0g1107pm"]
202mspm0g1107ycj = ["mspm0-metapac/mspm0g1107ycj"] 201mspm0g1107ycj = ["mspm0-metapac/mspm0g1107ycj"]
203mspm0g1505pm = ["mspm0-metapac/mspm0g1505pm"]
204mspm0g1505pt = ["mspm0-metapac/mspm0g1505pt"]
205mspm0g1505rge = ["mspm0-metapac/mspm0g1505rge"] 202mspm0g1505rge = ["mspm0-metapac/mspm0g1505rge"]
206mspm0g1505rgz = ["mspm0-metapac/mspm0g1505rgz"]
207mspm0g1505rhb = ["mspm0-metapac/mspm0g1505rhb"] 203mspm0g1505rhb = ["mspm0-metapac/mspm0g1505rhb"]
208mspm0g1506pm = ["mspm0-metapac/mspm0g1506pm"] 204mspm0g1505rgz = ["mspm0-metapac/mspm0g1505rgz"]
209mspm0g1506pt = ["mspm0-metapac/mspm0g1506pt"] 205mspm0g1505pt = ["mspm0-metapac/mspm0g1505pt"]
206mspm0g1505pm = ["mspm0-metapac/mspm0g1505pm"]
210mspm0g1506rge = ["mspm0-metapac/mspm0g1506rge"] 207mspm0g1506rge = ["mspm0-metapac/mspm0g1506rge"]
211mspm0g1506rgz = ["mspm0-metapac/mspm0g1506rgz"]
212mspm0g1506rhb = ["mspm0-metapac/mspm0g1506rhb"] 208mspm0g1506rhb = ["mspm0-metapac/mspm0g1506rhb"]
213mspm0g1507pm = ["mspm0-metapac/mspm0g1507pm"] 209mspm0g1506rgz = ["mspm0-metapac/mspm0g1506rgz"]
214mspm0g1507pt = ["mspm0-metapac/mspm0g1507pt"] 210mspm0g1506pt = ["mspm0-metapac/mspm0g1506pt"]
211mspm0g1506pm = ["mspm0-metapac/mspm0g1506pm"]
215mspm0g1507rge = ["mspm0-metapac/mspm0g1507rge"] 212mspm0g1507rge = ["mspm0-metapac/mspm0g1507rge"]
216mspm0g1507rgz = ["mspm0-metapac/mspm0g1507rgz"]
217mspm0g1507rhb = ["mspm0-metapac/mspm0g1507rhb"] 213mspm0g1507rhb = ["mspm0-metapac/mspm0g1507rhb"]
214mspm0g1507rgz = ["mspm0-metapac/mspm0g1507rgz"]
215mspm0g1507pt = ["mspm0-metapac/mspm0g1507pt"]
216mspm0g1507pm = ["mspm0-metapac/mspm0g1507pm"]
218mspm0g1507ycj = ["mspm0-metapac/mspm0g1507ycj"] 217mspm0g1507ycj = ["mspm0-metapac/mspm0g1507ycj"]
219mspm0g1519rgz = ["mspm0-metapac/mspm0g1519rgz"] 218mspm0g1518rhb = ["mspm0-metapac/mspm0g1518rhb"]
219mspm0g1518rgz = ["mspm0-metapac/mspm0g1518rgz"]
220mspm0g1518pt = ["mspm0-metapac/mspm0g1518pt"]
221mspm0g1518pm = ["mspm0-metapac/mspm0g1518pm"]
222mspm0g1518pz = ["mspm0-metapac/mspm0g1518pz"]
223mspm0g1518pn = ["mspm0-metapac/mspm0g1518pn"]
224mspm0g1518zaw = ["mspm0-metapac/mspm0g1518zaw"]
220mspm0g1519rhb = ["mspm0-metapac/mspm0g1519rhb"] 225mspm0g1519rhb = ["mspm0-metapac/mspm0g1519rhb"]
226mspm0g1519rgz = ["mspm0-metapac/mspm0g1519rgz"]
227mspm0g1519pt = ["mspm0-metapac/mspm0g1519pt"]
228mspm0g1519pm = ["mspm0-metapac/mspm0g1519pm"]
229mspm0g1519pz = ["mspm0-metapac/mspm0g1519pz"]
230mspm0g1519pn = ["mspm0-metapac/mspm0g1519pn"]
221mspm0g3105dgs20 = ["mspm0-metapac/mspm0g3105dgs20"] 231mspm0g3105dgs20 = ["mspm0-metapac/mspm0g3105dgs20"]
222mspm0g3105dgs28 = ["mspm0-metapac/mspm0g3105dgs28"] 232mspm0g3105dgs28 = ["mspm0-metapac/mspm0g3105dgs28"]
223mspm0g3105rhb = ["mspm0-metapac/mspm0g3105rhb"] 233mspm0g3105rhb = ["mspm0-metapac/mspm0g3105rhb"]
@@ -228,77 +238,92 @@ mspm0g3107dgs20 = ["mspm0-metapac/mspm0g3107dgs20"]
228mspm0g3107dgs28 = ["mspm0-metapac/mspm0g3107dgs28"] 238mspm0g3107dgs28 = ["mspm0-metapac/mspm0g3107dgs28"]
229mspm0g3107rhb = ["mspm0-metapac/mspm0g3107rhb"] 239mspm0g3107rhb = ["mspm0-metapac/mspm0g3107rhb"]
230mspm0g3505dgs28 = ["mspm0-metapac/mspm0g3505dgs28"] 240mspm0g3505dgs28 = ["mspm0-metapac/mspm0g3505dgs28"]
231mspm0g3505pm = ["mspm0-metapac/mspm0g3505pm"]
232mspm0g3505pt = ["mspm0-metapac/mspm0g3505pt"]
233mspm0g3505rgz = ["mspm0-metapac/mspm0g3505rgz"]
234mspm0g3505rhb = ["mspm0-metapac/mspm0g3505rhb"] 241mspm0g3505rhb = ["mspm0-metapac/mspm0g3505rhb"]
242mspm0g3505rgz = ["mspm0-metapac/mspm0g3505rgz"]
243mspm0g3505pt = ["mspm0-metapac/mspm0g3505pt"]
244mspm0g3505pm = ["mspm0-metapac/mspm0g3505pm"]
235mspm0g3506dgs28 = ["mspm0-metapac/mspm0g3506dgs28"] 245mspm0g3506dgs28 = ["mspm0-metapac/mspm0g3506dgs28"]
236mspm0g3506pm = ["mspm0-metapac/mspm0g3506pm"]
237mspm0g3506pt = ["mspm0-metapac/mspm0g3506pt"]
238mspm0g3506rgz = ["mspm0-metapac/mspm0g3506rgz"]
239mspm0g3506rhb = ["mspm0-metapac/mspm0g3506rhb"] 246mspm0g3506rhb = ["mspm0-metapac/mspm0g3506rhb"]
247mspm0g3506rgz = ["mspm0-metapac/mspm0g3506rgz"]
248mspm0g3506pt = ["mspm0-metapac/mspm0g3506pt"]
249mspm0g3506pm = ["mspm0-metapac/mspm0g3506pm"]
240mspm0g3507dgs28 = ["mspm0-metapac/mspm0g3507dgs28"] 250mspm0g3507dgs28 = ["mspm0-metapac/mspm0g3507dgs28"]
241mspm0g3507pm = ["mspm0-metapac/mspm0g3507pm"]
242mspm0g3507pt = ["mspm0-metapac/mspm0g3507pt"]
243mspm0g3507rgz = ["mspm0-metapac/mspm0g3507rgz"]
244mspm0g3507rhb = ["mspm0-metapac/mspm0g3507rhb"] 251mspm0g3507rhb = ["mspm0-metapac/mspm0g3507rhb"]
252mspm0g3507rgz = ["mspm0-metapac/mspm0g3507rgz"]
253mspm0g3507pt = ["mspm0-metapac/mspm0g3507pt"]
254mspm0g3507pm = ["mspm0-metapac/mspm0g3507pm"]
255mspm0g3518rhb = ["mspm0-metapac/mspm0g3518rhb"]
256mspm0g3518rgz = ["mspm0-metapac/mspm0g3518rgz"]
257mspm0g3518pt = ["mspm0-metapac/mspm0g3518pt"]
258mspm0g3518pm = ["mspm0-metapac/mspm0g3518pm"]
259mspm0g3518pz = ["mspm0-metapac/mspm0g3518pz"]
260mspm0g3518pn = ["mspm0-metapac/mspm0g3518pn"]
261mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"]
262mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"]
263mspm0g3519pt = ["mspm0-metapac/mspm0g3519pt"]
245mspm0g3519pm = ["mspm0-metapac/mspm0g3519pm"] 264mspm0g3519pm = ["mspm0-metapac/mspm0g3519pm"]
246mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"]
247mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] 265mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"]
248mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] 266mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"]
249mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] 267mspm0g3519zaw = ["mspm0-metapac/mspm0g3519zaw"]
268mspm0g5187rhb = ["mspm0-metapac/mspm0g5187rhb"]
269mspm0g5187rgz = ["mspm0-metapac/mspm0g5187rgz"]
270mspm0g5187pt = ["mspm0-metapac/mspm0g5187pt"]
271mspm0g5187pm = ["mspm0-metapac/mspm0g5187pm"]
272mspm0g5187ruy = ["mspm0-metapac/mspm0g5187ruy"]
273mspm0g5187ycj = ["mspm0-metapac/mspm0g5187ycj"]
274mspm0g5187rge = ["mspm0-metapac/mspm0g5187rge"]
250mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"] 275mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"]
251mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] 276mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"]
252mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] 277mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"]
253mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"]
254mspm0l1105rge = ["mspm0-metapac/mspm0l1105rge"] 278mspm0l1105rge = ["mspm0-metapac/mspm0l1105rge"]
255mspm0l1105rtr = ["mspm0-metapac/mspm0l1105rtr"] 279mspm0l1105rtr = ["mspm0-metapac/mspm0l1105rtr"]
280mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"]
281mspm0l1106rhb = ["mspm0-metapac/mspm0l1106rhb"]
256mspm0l1106dgs20 = ["mspm0-metapac/mspm0l1106dgs20"] 282mspm0l1106dgs20 = ["mspm0-metapac/mspm0l1106dgs20"]
257mspm0l1106dgs28 = ["mspm0-metapac/mspm0l1106dgs28"] 283mspm0l1106dgs28 = ["mspm0-metapac/mspm0l1106dgs28"]
258mspm0l1106dyy = ["mspm0-metapac/mspm0l1106dyy"]
259mspm0l1106rge = ["mspm0-metapac/mspm0l1106rge"] 284mspm0l1106rge = ["mspm0-metapac/mspm0l1106rge"]
260mspm0l1106rhb = ["mspm0-metapac/mspm0l1106rhb"]
261mspm0l1106rtr = ["mspm0-metapac/mspm0l1106rtr"] 285mspm0l1106rtr = ["mspm0-metapac/mspm0l1106rtr"]
262mspm0l1227pm = ["mspm0-metapac/mspm0l1227pm"] 286mspm0l1106dyy = ["mspm0-metapac/mspm0l1106dyy"]
287mspm0l1227rhb = ["mspm0-metapac/mspm0l1227rhb"]
263mspm0l1227pn = ["mspm0-metapac/mspm0l1227pn"] 288mspm0l1227pn = ["mspm0-metapac/mspm0l1227pn"]
289mspm0l1227rgz = ["mspm0-metapac/mspm0l1227rgz"]
264mspm0l1227pt = ["mspm0-metapac/mspm0l1227pt"] 290mspm0l1227pt = ["mspm0-metapac/mspm0l1227pt"]
291mspm0l1227pm = ["mspm0-metapac/mspm0l1227pm"]
265mspm0l1227rge = ["mspm0-metapac/mspm0l1227rge"] 292mspm0l1227rge = ["mspm0-metapac/mspm0l1227rge"]
266mspm0l1227rgz = ["mspm0-metapac/mspm0l1227rgz"] 293mspm0l1228rhb = ["mspm0-metapac/mspm0l1228rhb"]
267mspm0l1227rhb = ["mspm0-metapac/mspm0l1227rhb"]
268mspm0l1228pm = ["mspm0-metapac/mspm0l1228pm"]
269mspm0l1228pn = ["mspm0-metapac/mspm0l1228pn"] 294mspm0l1228pn = ["mspm0-metapac/mspm0l1228pn"]
295mspm0l1228rgz = ["mspm0-metapac/mspm0l1228rgz"]
270mspm0l1228pt = ["mspm0-metapac/mspm0l1228pt"] 296mspm0l1228pt = ["mspm0-metapac/mspm0l1228pt"]
297mspm0l1228pm = ["mspm0-metapac/mspm0l1228pm"]
271mspm0l1228rge = ["mspm0-metapac/mspm0l1228rge"] 298mspm0l1228rge = ["mspm0-metapac/mspm0l1228rge"]
272mspm0l1228rgz = ["mspm0-metapac/mspm0l1228rgz"]
273mspm0l1228rhb = ["mspm0-metapac/mspm0l1228rhb"]
274mspm0l1303rge = ["mspm0-metapac/mspm0l1303rge"] 299mspm0l1303rge = ["mspm0-metapac/mspm0l1303rge"]
300mspm0l1304rhb = ["mspm0-metapac/mspm0l1304rhb"]
275mspm0l1304dgs20 = ["mspm0-metapac/mspm0l1304dgs20"] 301mspm0l1304dgs20 = ["mspm0-metapac/mspm0l1304dgs20"]
276mspm0l1304dgs28 = ["mspm0-metapac/mspm0l1304dgs28"] 302mspm0l1304dgs28 = ["mspm0-metapac/mspm0l1304dgs28"]
277mspm0l1304dyy = ["mspm0-metapac/mspm0l1304dyy"]
278mspm0l1304rge = ["mspm0-metapac/mspm0l1304rge"] 303mspm0l1304rge = ["mspm0-metapac/mspm0l1304rge"]
279mspm0l1304rhb = ["mspm0-metapac/mspm0l1304rhb"]
280mspm0l1304rtr = ["mspm0-metapac/mspm0l1304rtr"] 304mspm0l1304rtr = ["mspm0-metapac/mspm0l1304rtr"]
305mspm0l1304dyy = ["mspm0-metapac/mspm0l1304dyy"]
281mspm0l1305dgs20 = ["mspm0-metapac/mspm0l1305dgs20"] 306mspm0l1305dgs20 = ["mspm0-metapac/mspm0l1305dgs20"]
282mspm0l1305dgs28 = ["mspm0-metapac/mspm0l1305dgs28"] 307mspm0l1305dgs28 = ["mspm0-metapac/mspm0l1305dgs28"]
283mspm0l1305dyy = ["mspm0-metapac/mspm0l1305dyy"]
284mspm0l1305rge = ["mspm0-metapac/mspm0l1305rge"] 308mspm0l1305rge = ["mspm0-metapac/mspm0l1305rge"]
285mspm0l1305rtr = ["mspm0-metapac/mspm0l1305rtr"] 309mspm0l1305rtr = ["mspm0-metapac/mspm0l1305rtr"]
310mspm0l1305dyy = ["mspm0-metapac/mspm0l1305dyy"]
311mspm0l1306rhb = ["mspm0-metapac/mspm0l1306rhb"]
286mspm0l1306dgs20 = ["mspm0-metapac/mspm0l1306dgs20"] 312mspm0l1306dgs20 = ["mspm0-metapac/mspm0l1306dgs20"]
287mspm0l1306dgs28 = ["mspm0-metapac/mspm0l1306dgs28"] 313mspm0l1306dgs28 = ["mspm0-metapac/mspm0l1306dgs28"]
288mspm0l1306dyy = ["mspm0-metapac/mspm0l1306dyy"]
289mspm0l1306rge = ["mspm0-metapac/mspm0l1306rge"] 314mspm0l1306rge = ["mspm0-metapac/mspm0l1306rge"]
290mspm0l1306rhb = ["mspm0-metapac/mspm0l1306rhb"] 315mspm0l1306dyy = ["mspm0-metapac/mspm0l1306dyy"]
291mspm0l1343dgs20 = ["mspm0-metapac/mspm0l1343dgs20"] 316mspm0l1343dgs20 = ["mspm0-metapac/mspm0l1343dgs20"]
292mspm0l1344dgs20 = ["mspm0-metapac/mspm0l1344dgs20"] 317mspm0l1344dgs20 = ["mspm0-metapac/mspm0l1344dgs20"]
293mspm0l1345dgs28 = ["mspm0-metapac/mspm0l1345dgs28"] 318mspm0l1345dgs28 = ["mspm0-metapac/mspm0l1345dgs28"]
294mspm0l1346dgs28 = ["mspm0-metapac/mspm0l1346dgs28"] 319mspm0l1346dgs28 = ["mspm0-metapac/mspm0l1346dgs28"]
320mspm0l2227rgz = ["mspm0-metapac/mspm0l2227rgz"]
321mspm0l2227pt = ["mspm0-metapac/mspm0l2227pt"]
295mspm0l2227pm = ["mspm0-metapac/mspm0l2227pm"] 322mspm0l2227pm = ["mspm0-metapac/mspm0l2227pm"]
296mspm0l2227pn = ["mspm0-metapac/mspm0l2227pn"] 323mspm0l2227pn = ["mspm0-metapac/mspm0l2227pn"]
297mspm0l2227pt = ["mspm0-metapac/mspm0l2227pt"] 324mspm0l2228rgz = ["mspm0-metapac/mspm0l2228rgz"]
298mspm0l2227rgz = ["mspm0-metapac/mspm0l2227rgz"] 325mspm0l2228pt = ["mspm0-metapac/mspm0l2228pt"]
299mspm0l2228pm = ["mspm0-metapac/mspm0l2228pm"] 326mspm0l2228pm = ["mspm0-metapac/mspm0l2228pm"]
300mspm0l2228pn = ["mspm0-metapac/mspm0l2228pn"] 327mspm0l2228pn = ["mspm0-metapac/mspm0l2228pn"]
301mspm0l2228pt = ["mspm0-metapac/mspm0l2228pt"]
302mspm0l2228rgz = ["mspm0-metapac/mspm0l2228rgz"]
303msps003f3pw20 = ["mspm0-metapac/msps003f3pw20"] 328msps003f3pw20 = ["mspm0-metapac/msps003f3pw20"]
304msps003f4pw20 = ["mspm0-metapac/msps003f4pw20"] 329msps003f4pw20 = ["mspm0-metapac/msps003f4pw20"] \ No newline at end of file
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs
index 0fe056c4e..ac40adbdf 100644
--- a/embassy-mspm0/build.rs
+++ b/embassy-mspm0/build.rs
@@ -31,7 +31,7 @@ fn generate_code(cfgs: &mut CfgSet) {
31 PathBuf::from(env::var_os("OUT_DIR").unwrap()).display(), 31 PathBuf::from(env::var_os("OUT_DIR").unwrap()).display(),
32 ); 32 );
33 33
34 cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); 34 cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1", "unicomm"]);
35 35
36 let chip_name = match env::vars() 36 let chip_name = match env::vars()
37 .map(|(a, _)| a) 37 .map(|(a, _)| a)
@@ -116,6 +116,10 @@ fn get_chip_cfgs(chip_name: &str) -> Vec<String> {
116 cfgs.push("mspm0g351x".to_string()); 116 cfgs.push("mspm0g351x".to_string());
117 } 117 }
118 118
119 if chip_name.starts_with("mspm0g518") {
120 cfgs.push("mspm0g518x".to_string());
121 }
122
119 if chip_name.starts_with("mspm0h321") { 123 if chip_name.starts_with("mspm0h321") {
120 cfgs.push("mspm0h321x".to_string()); 124 cfgs.push("mspm0h321x".to_string());
121 } 125 }
@@ -300,6 +304,15 @@ fn get_singletons(cfgs: &mut common::CfgSet) -> Vec<Singleton> {
300 // by the HAL. 304 // by the HAL.
301 "iomux" | "cpuss" => true, 305 "iomux" | "cpuss" => true,
302 306
307 // Unicomm instances get their own singletons, but we need to enable a cfg for unicomm drivers.
308 "unicomm" => {
309 cfgs.enable("unicomm");
310 false
311 }
312
313 // TODO: Remove after TIMB is fixed
314 "tim" if peripheral.name.starts_with("TIMB") => true,
315
303 _ => false, 316 _ => false,
304 }; 317 };
305 318
@@ -423,6 +436,8 @@ fn time_driver(singletons: &mut Vec<Singleton>, cfgs: &mut CfgSet) {
423 // Verify the selected timer is available 436 // Verify the selected timer is available
424 let selected_timer = match time_driver.as_ref().map(|x| x.as_ref()) { 437 let selected_timer = match time_driver.as_ref().map(|x| x.as_ref()) {
425 None => "", 438 None => "",
439 // TODO: Fix TIMB0
440 // Some("timb0") => "TIMB0",
426 Some("timg0") => "TIMG0", 441 Some("timg0") => "TIMG0",
427 Some("timg1") => "TIMG1", 442 Some("timg1") => "TIMG1",
428 Some("timg2") => "TIMG2", 443 Some("timg2") => "TIMG2",
@@ -440,16 +455,17 @@ fn time_driver(singletons: &mut Vec<Singleton>, cfgs: &mut CfgSet) {
440 Some("tima1") => "TIMA1", 455 Some("tima1") => "TIMA1",
441 Some("any") => { 456 Some("any") => {
442 // Order of timer candidates: 457 // Order of timer candidates:
443 // 1. 16-bit, 2 channel 458 // 1. Basic timers
444 // 2. 16-bit, 2 channel with shadow registers 459 // 2. 16-bit, 2 channel
445 // 3. 16-bit, 4 channel 460 // 3. 16-bit, 2 channel with shadow registers
446 // 4. 16-bit with QEI 461 // 4. 16-bit, 4 channel
447 // 5. Advanced timers 462 // 5. 16-bit with QEI
463 // 6. Advanced timers
448 // 464 //
449 // TODO: Select RTC first if available
450 // TODO: 32-bit timers are not considered yet 465 // TODO: 32-bit timers are not considered yet
451 [ 466 [
452 // 16-bit, 2 channel 467 // basic timers. No PWM pins
468 // "TIMB0", // 16-bit, 2 channel
453 "TIMG0", "TIMG1", "TIMG2", "TIMG3", // 16-bit, 2 channel with shadow registers 469 "TIMG0", "TIMG1", "TIMG2", "TIMG3", // 16-bit, 2 channel with shadow registers
454 "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel 470 "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel
455 "TIMG14", // 16-bit with QEI 471 "TIMG14", // 16-bit with QEI
@@ -519,6 +535,8 @@ fn generate_timers() -> TokenStream {
519 .peripherals 535 .peripherals
520 .iter() 536 .iter()
521 .filter(|p| p.name.starts_with("TIM")) 537 .filter(|p| p.name.starts_with("TIM"))
538 // TODO: Fix TIMB when used at time driver.
539 .filter(|p| !p.name.starts_with("TIMB"))
522 .map(|peripheral| { 540 .map(|peripheral| {
523 let name = Ident::new(&peripheral.name, Span::call_site()); 541 let name = Ident::new(&peripheral.name, Span::call_site());
524 let timers = &*TIMERS; 542 let timers = &*TIMERS;
@@ -730,6 +748,24 @@ struct TimerDesc {
730const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| { 748const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| {
731 let mut map = HashMap::new(); 749 let mut map = HashMap::new();
732 map.insert( 750 map.insert(
751 "TIMB0".into(),
752 TimerDesc {
753 bits: 16,
754 prescaler: true,
755 repeat_counter: false,
756 ccp_channels_internal: 2,
757 ccp_channels_external: 2,
758 external_pwm_channels: 0,
759 phase_load: false,
760 shadow_load: false,
761 shadow_ccs: false,
762 deadband: false,
763 fault_handler: false,
764 qei_hall: false,
765 },
766 );
767
768 map.insert(
733 "TIMG0".into(), 769 "TIMG0".into(),
734 TimerDesc { 770 TimerDesc {
735 bits: 16, 771 bits: 16,
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs
index d8eb42dc2..709102c59 100644
--- a/embassy-mspm0/src/gpio.rs
+++ b/embassy-mspm0/src/gpio.rs
@@ -841,6 +841,7 @@ impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
841 } 841 }
842} 842}
843 843
844#[cfg_attr(mspm0g518x, allow(dead_code))]
844#[derive(Copy, Clone)] 845#[derive(Copy, Clone)]
845pub struct PfType { 846pub struct PfType {
846 pull: Pull, 847 pull: Pull,
@@ -948,6 +949,7 @@ pub(crate) trait SealedPin {
948 }); 949 });
949 } 950 }
950 951
952 #[cfg_attr(mspm0g518x, allow(dead_code))]
951 fn update_pf(&self, ty: PfType) { 953 fn update_pf(&self, ty: PfType) {
952 let pincm = pac::IOMUX.pincm(self._pin_cm() as usize); 954 let pincm = pac::IOMUX.pincm(self._pin_cm() as usize);
953 let pf = pincm.read().pf(); 955 let pf = pincm.read().pf();
@@ -955,6 +957,7 @@ pub(crate) trait SealedPin {
955 set_pf(self._pin_cm() as usize, pf, ty); 957 set_pf(self._pin_cm() as usize, pf, ty);
956 } 958 }
957 959
960 #[cfg_attr(mspm0g518x, allow(dead_code))]
958 fn set_as_pf(&self, pf: u8, ty: PfType) { 961 fn set_as_pf(&self, pf: u8, ty: PfType) {
959 set_pf(self._pin_cm() as usize, pf, ty) 962 set_pf(self._pin_cm() as usize, pf, ty)
960 } 963 }
@@ -967,6 +970,7 @@ pub(crate) trait SealedPin {
967 /// 970 ///
968 /// Note that this also disables the internal weak pull-up and pull-down resistors. 971 /// Note that this also disables the internal weak pull-up and pull-down resistors.
969 #[inline] 972 #[inline]
973 #[cfg_attr(mspm0g518x, allow(dead_code))]
970 fn set_as_disconnected(&self) { 974 fn set_as_disconnected(&self) {
971 self.set_as_analog(); 975 self.set_as_analog();
972 } 976 }
diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs
index 86be91415..e371fa903 100644
--- a/embassy-mspm0/src/i2c_target.rs
+++ b/embassy-mspm0/src/i2c_target.rs
@@ -12,12 +12,13 @@ use embassy_embedded_hal::SetConfig;
12use mspm0_metapac::i2c::vals::CpuIntIidxStat; 12use mspm0_metapac::i2c::vals::CpuIntIidxStat;
13 13
14use crate::gpio::{AnyPin, SealedPin}; 14use crate::gpio::{AnyPin, SealedPin};
15use crate::interrupt::InterruptExt;
16use crate::mode::{Async, Blocking, Mode};
17use crate::pac::{self, i2c::vals};
18use crate::{i2c, i2c_target, interrupt, Peri};
19// Re-use I2c controller types 15// Re-use I2c controller types
20use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; 16use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State};
17use crate::interrupt::InterruptExt;
18use crate::mode::{Async, Blocking, Mode};
19use crate::pac::i2c::vals;
20use crate::pac::{self};
21use crate::{Peri, i2c, i2c_target, interrupt};
21 22
22#[non_exhaustive] 23#[non_exhaustive]
23#[derive(Clone, Copy, PartialEq, Eq, Debug)] 24#[derive(Clone, Copy, PartialEq, Eq, Debug)]
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index c43c81853..548fb33ca 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -8,20 +8,23 @@
8)] 8)]
9#![doc = include_str!("../README.md")] 9#![doc = include_str!("../README.md")]
10 10
11// This mod MUST go first, so that the others see its macros. 11// These mods MUST go first, so that the others see the macros.
12pub(crate) mod fmt; 12pub(crate) mod fmt;
13
14// This must be declared early as well for
15mod macros; 13mod macros;
16 14
17pub mod adc; 15pub mod adc;
18pub mod dma; 16pub mod dma;
19pub mod gpio; 17pub mod gpio;
18// TODO: I2C unicomm
19#[cfg(not(unicomm))]
20pub mod i2c; 20pub mod i2c;
21#[cfg(not(unicomm))]
21pub mod i2c_target; 22pub mod i2c_target;
22#[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))] 23#[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))]
23pub mod mathacl; 24pub mod mathacl;
24pub mod timer; 25pub mod timer;
26// TODO: UART unicomm
27#[cfg(not(unicomm))]
25pub mod uart; 28pub mod uart;
26pub mod wwdt; 29pub mod wwdt;
27 30
@@ -276,7 +279,7 @@ pub enum ResetCause {
276 /// WWDT0 violation 279 /// WWDT0 violation
277 BootrstWwdt0Violation, 280 BootrstWwdt0Violation,
278 /// WWDT1 violation (G-series only) 281 /// WWDT1 violation (G-series only)
279 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x))] 282 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0g518x))]
280 SysrstWwdt1Violation, 283 SysrstWwdt1Violation,
281 /// BSL exit (if present) 284 /// BSL exit (if present)
282 SysrstBslExit, 285 SysrstBslExit,
@@ -326,7 +329,8 @@ pub fn read_reset_cause() -> Result<ResetCause, u8> {
326 mspm0g151x, 329 mspm0g151x,
327 mspm0g310x, 330 mspm0g310x,
328 mspm0g350x, 331 mspm0g350x,
329 mspm0g351x 332 mspm0g351x,
333 mspm0g518x,
330 )))] 334 )))]
331 Id::BOOTNONPMUPARITY => Ok(BootrstNonPmuParityFault), 335 Id::BOOTNONPMUPARITY => Ok(BootrstNonPmuParityFault),
332 Id::BOOTCLKFAIL => Ok(BootrstClockFault), 336 Id::BOOTCLKFAIL => Ok(BootrstClockFault),
@@ -335,7 +339,7 @@ pub fn read_reset_cause() -> Result<ResetCause, u8> {
335 Id::BOOTWWDT0 => Ok(BootrstWwdt0Violation), 339 Id::BOOTWWDT0 => Ok(BootrstWwdt0Violation),
336 Id::SYSBSLEXIT => Ok(SysrstBslExit), 340 Id::SYSBSLEXIT => Ok(SysrstBslExit),
337 Id::SYSBSLENTRY => Ok(SysrstBslEntry), 341 Id::SYSBSLENTRY => Ok(SysrstBslEntry),
338 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x))] 342 #[cfg(any(mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0g518x))]
339 Id::SYSWWDT1 => Ok(SysrstWwdt1Violation), 343 Id::SYSWWDT1 => Ok(SysrstWwdt1Violation),
340 #[cfg(not(any(mspm0c110x, mspm0c1105_c1106, mspm0g351x, mspm0g151x)))] 344 #[cfg(not(any(mspm0c110x, mspm0c1105_c1106, mspm0g351x, mspm0g151x)))]
341 Id::SYSFLASHECC => Ok(SysrstFlashEccError), 345 Id::SYSFLASHECC => Ok(SysrstFlashEccError),
diff --git a/embassy-mspm0/src/macros.rs b/embassy-mspm0/src/macros.rs
index 5355e7d59..3a12a528a 100644
--- a/embassy-mspm0/src/macros.rs
+++ b/embassy-mspm0/src/macros.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3#[allow(unused)]
3macro_rules! new_pin { 4macro_rules! new_pin {
4 ($name: ident, $pf_type: expr) => {{ 5 ($name: ident, $pf_type: expr) => {{
5 let pin = $name; 6 let pin = $name;
diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs
index 0743c667b..b42ff61c2 100644
--- a/embassy-mspm0/src/time_driver.rs
+++ b/embassy-mspm0/src/time_driver.rs
@@ -16,6 +16,8 @@ use crate::timer::SealedTimer;
16compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet"); 16compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet");
17 17
18// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers. 18// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers.
19#[cfg(time_driver_timb0)]
20type T = peripherals::TIMB0;
19#[cfg(time_driver_timg0)] 21#[cfg(time_driver_timg0)]
20type T = peripherals::TIMG0; 22type T = peripherals::TIMG0;
21#[cfg(time_driver_timg1)] 23#[cfg(time_driver_timg1)]
@@ -333,6 +335,8 @@ pub(crate) fn init(cs: CriticalSection) {
333 DRIVER.init(cs); 335 DRIVER.init(cs);
334} 336}
335 337
338// TODO: TIMB0
339
336#[cfg(time_driver_timg0)] 340#[cfg(time_driver_timg0)]
337#[interrupt] 341#[interrupt]
338fn TIMG0() { 342fn TIMG0() {
diff --git a/embassy-mspm0/src/uart/buffered.rs b/embassy-mspm0/src/uart/buffered.rs
index 89e6bcc7b..d1b75b177 100644
--- a/embassy-mspm0/src/uart/buffered.rs
+++ b/embassy-mspm0/src/uart/buffered.rs
@@ -436,6 +436,10 @@ impl embedded_io_async::Write for BufferedUart<'_> {
436 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 436 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
437 self.tx.write_inner(buf).await 437 self.tx.write_inner(buf).await
438 } 438 }
439
440 async fn flush(&mut self) -> Result<(), Self::Error> {
441 self.tx.flush_inner().await
442 }
439} 443}
440 444
441impl embedded_io_async::Write for BufferedUartTx<'_> { 445impl embedded_io_async::Write for BufferedUartTx<'_> {
diff --git a/embassy-net-nrf91/CHANGELOG.md b/embassy-net-nrf91/CHANGELOG.md
index 11974ac04..66a576b72 100644
--- a/embassy-net-nrf91/CHANGELOG.md
+++ b/embassy-net-nrf91/CHANGELOG.md
@@ -8,8 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54 11## 0.1.0 - 2025-12-15
12 12
13## 0.1.1 - 2025-08-14 13- Initial release
14
15- First release with changelog.
diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml
index cd9bf2987..c5c582fc3 100644
--- a/embassy-net-nrf91/Cargo.toml
+++ b/embassy-net-nrf91/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-net-nrf91" 2name = "embassy-net-nrf91"
3version = "0.1.1" 3version = "0.1.0"
4edition = "2024" 4edition = "2024"
5description = "embassy-net driver for Nordic nRF91-series cellular modems" 5description = "embassy-net driver for Nordic nRF91-series cellular modems"
6keywords = ["embedded", "nrf91", "embassy-net", "cellular"] 6keywords = ["embedded", "nrf91", "embassy-net", "cellular"]
@@ -8,7 +8,7 @@ categories = ["embedded", "hardware-support", "no-std", "network-programming", "
8license = "MIT OR Apache-2.0" 8license = "MIT OR Apache-2.0"
9repository = "https://github.com/embassy-rs/embassy" 9repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/embassy-net-nrf91" 10documentation = "https://docs.embassy.dev/embassy-net-nrf91"
11publish = false 11publish = true
12 12
13[features] 13[features]
14defmt = ["dep:defmt", "heapless/defmt-03"] 14defmt = ["dep:defmt", "heapless/defmt-03"]
@@ -18,7 +18,7 @@ log = ["dep:log"]
18defmt = { version = "1.0.1", optional = true } 18defmt = { version = "1.0.1", optional = true }
19log = { version = "0.4.14", optional = true } 19log = { version = "0.4.14", optional = true }
20 20
21nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "52fd51ce762a3d3a81660dea62947e6d2d1e9d91" } 21nrf-pac = { version = "0.2.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "7f450696f95591ce42f4da6e7d0402750ab1e50a" }
22cortex-m = "0.7.7" 22cortex-m = "0.7.7"
23 23
24embassy-time = { version = "0.5.0", path = "../embassy-time" } 24embassy-time = { version = "0.5.0", path = "../embassy-time" }
@@ -27,7 +27,7 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
27embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel" } 27embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel" }
28 28
29heapless = "0.8" 29heapless = "0.8"
30embedded-io = "0.6.1" 30embedded-io = { version = "0.7.1" }
31at-commands = "0.5.4" 31at-commands = "0.5.4"
32 32
33[package.metadata.embassy] 33[package.metadata.embassy]
diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs
index dd4812aae..2ffa2890f 100644
--- a/embassy-net-nrf91/src/lib.rs
+++ b/embassy-net-nrf91/src/lib.rs
@@ -311,7 +311,7 @@ struct PendingRequest {
311 waker: Waker, 311 waker: Waker,
312} 312}
313 313
314#[derive(Copy, Clone, PartialEq, Eq)] 314#[derive(Copy, Clone, PartialEq, Eq, Debug)]
315#[cfg_attr(feature = "defmt", derive(defmt::Format))] 315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
316struct NoFreeBufs; 316struct NoFreeBufs;
317 317
@@ -1061,7 +1061,8 @@ struct ListItem {
1061} 1061}
1062 1062
1063#[repr(C)] 1063#[repr(C)]
1064#[derive(defmt::Format, Clone, Copy)] 1064#[derive(Clone, Copy)]
1065#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1065struct Message { 1066struct Message {
1066 id: u32, 1067 id: u32,
1067 1068
diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml
index 45ee2f6b5..1dda5017f 100644
--- a/embassy-net-ppp/Cargo.toml
+++ b/embassy-net-ppp/Cargo.toml
@@ -17,7 +17,7 @@ log = ["dep:log", "ppproto/log"]
17defmt = { version = "1.0.1", optional = true } 17defmt = { version = "1.0.1", optional = true }
18log = { version = "0.4.14", optional = true } 18log = { version = "0.4.14", optional = true }
19 19
20embedded-io-async = { version = "0.6.1" } 20embedded-io-async = { version = "0.7.0" }
21embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel" } 21embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel" }
22embassy-futures = { version = "0.1.2", path = "../embassy-futures" } 22embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
23ppproto = { version = "0.2.1"} 23ppproto = { version = "0.2.1"}
diff --git a/embassy-net-tuntap/Cargo.toml b/embassy-net-tuntap/Cargo.toml
index 77668b445..95dc1e1f0 100644
--- a/embassy-net-tuntap/Cargo.toml
+++ b/embassy-net-tuntap/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-net-tuntap" 2name = "embassy-net-tuntap"
3version = "0.1.0" 3version = "0.1.1"
4description = "embassy-net driver for Linux TUN/TAP interfaces." 4description = "embassy-net driver for Linux TUN/TAP interfaces."
5keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] 5keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"]
6categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] 6categories = ["embedded", "hardware-support", "network-programming", "asynchronous"]
@@ -11,7 +11,7 @@ documentation = "https://docs.embassy.dev/embassy-net-tuntap"
11 11
12[dependencies] 12[dependencies]
13embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 13embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
14async-io = "1.6.0" 14async-io = "2.6.0"
15log = "0.4.14" 15log = "0.4.14"
16libc = "0.2.101" 16libc = "0.2.101"
17 17
diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs
index 2ff23f462..33a251248 100644
--- a/embassy-net-tuntap/src/lib.rs
+++ b/embassy-net-tuntap/src/lib.rs
@@ -2,7 +2,9 @@
2#![doc = include_str!("../README.md")] 2#![doc = include_str!("../README.md")]
3use std::io; 3use std::io;
4use std::io::{Read, Write}; 4use std::io::{Read, Write};
5use std::os::fd::AsFd;
5use std::os::unix::io::{AsRawFd, RawFd}; 6use std::os::unix::io::{AsRawFd, RawFd};
7use std::os::unix::prelude::BorrowedFd;
6use std::task::Context; 8use std::task::Context;
7 9
8use async_io::Async; 10use async_io::Async;
@@ -69,6 +71,12 @@ impl AsRawFd for TunTap {
69 } 71 }
70} 72}
71 73
74impl AsFd for TunTap {
75 fn as_fd(&self) -> BorrowedFd<'_> {
76 unsafe { BorrowedFd::borrow_raw(self.fd) }
77 }
78}
79
72impl TunTap { 80impl TunTap {
73 /// Create a new TUN/TAP device. 81 /// Create a new TUN/TAP device.
74 pub fn new(name: &str) -> io::Result<TunTap> { 82 pub fn new(name: &str) -> io::Result<TunTap> {
@@ -164,7 +172,7 @@ impl Driver for TunTapDevice {
164 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 172 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
165 let mut buf = vec![0; self.device.get_ref().mtu]; 173 let mut buf = vec![0; self.device.get_ref().mtu];
166 loop { 174 loop {
167 match self.device.get_mut().read(&mut buf) { 175 match unsafe { self.device.get_mut() }.read(&mut buf) {
168 Ok(n) => { 176 Ok(n) => {
169 buf.truncate(n); 177 buf.truncate(n);
170 return Some(( 178 return Some((
@@ -233,7 +241,7 @@ impl<'a> embassy_net_driver::TxToken for TxToken<'a> {
233 let result = f(&mut buffer); 241 let result = f(&mut buffer);
234 242
235 // todo handle WouldBlock with async 243 // todo handle WouldBlock with async
236 match self.device.get_mut().write(&buffer) { 244 match unsafe { self.device.get_mut() }.write(&buffer) {
237 Ok(_) => {} 245 Ok(_) => {}
238 Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"), 246 Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"),
239 Err(e) => panic!("transmit error: {:?}", e), 247 Err(e) => panic!("transmit error: {:?}", e),
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 4c8075c43..d66ba1133 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -109,9 +109,9 @@ smoltcp = { version = "0.12.0", default-features = false, features = [
109embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 109embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
110embassy-time = { version = "0.5.0", path = "../embassy-time" } 110embassy-time = { version = "0.5.0", path = "../embassy-time" }
111embassy-sync = { version = "0.7.2", path = "../embassy-sync" } 111embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
112embedded-io-async = { version = "0.6.1" } 112embedded-io-async = { version = "0.7.0" }
113 113
114managed = { version = "0.8.0", default-features = false, features = [ "map" ] } 114managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
115heapless = { version = "0.8", default-features = false } 115heapless = { version = "0.8", default-features = false }
116embedded-nal-async = "0.8.0" 116embedded-nal-async = "0.9.0"
117document-features = "0.2.7" 117document-features = "0.2.7"
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index b4db7b88c..74672df1c 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -670,6 +670,13 @@ impl<'d> TcpIo<'d> {
670mod embedded_io_impls { 670mod embedded_io_impls {
671 use super::*; 671 use super::*;
672 672
673 impl core::fmt::Display for ConnectError {
674 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
675 f.write_str("ConnectError")
676 }
677 }
678 impl core::error::Error for ConnectError {}
679
673 impl embedded_io_async::Error for ConnectError { 680 impl embedded_io_async::Error for ConnectError {
674 fn kind(&self) -> embedded_io_async::ErrorKind { 681 fn kind(&self) -> embedded_io_async::ErrorKind {
675 match self { 682 match self {
@@ -681,6 +688,15 @@ mod embedded_io_impls {
681 } 688 }
682 } 689 }
683 690
691 impl core::fmt::Display for Error {
692 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
693 match self {
694 Self::ConnectionReset => f.write_str("ConnectionReset"),
695 }
696 }
697 }
698 impl core::error::Error for Error {}
699
684 impl embedded_io_async::Error for Error { 700 impl embedded_io_async::Error for Error {
685 fn kind(&self) -> embedded_io_async::ErrorKind { 701 fn kind(&self) -> embedded_io_async::ErrorKind {
686 match self { 702 match self {
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index 56bb15f42..921835417 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- bugfix: avoid hang if calling now() before syscounter is enabled on nrf54
12
13## 0.9.0 - 2025-12-15
14
11- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l 15- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l
12- changed: do not panic on BufferedUarte overrun 16- changed: do not panic on BufferedUarte overrun
13- added: allow direct access to the input pin of `gpiote::InputChannel` 17- added: allow direct access to the input pin of `gpiote::InputChannel`
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index ee070f0c0..a8070aa45 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-nrf" 2name = "embassy-nrf"
3version = "0.8.0" 3version = "0.9.0"
4edition = "2024" 4edition = "2024"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" 6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
@@ -217,16 +217,16 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures", optional = t
217embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 217embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
218embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 218embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
219embedded-hal-async = { version = "1.0" } 219embedded-hal-async = { version = "1.0" }
220embedded-io = { version = "0.6.0" } 220embedded-io = { version = "0.7.1" }
221embedded-io-async = { version = "0.6.1" } 221embedded-io-async = { version = "0.7.0" }
222 222
223rand-core-06 = { package = "rand_core", version = "0.6" } 223rand-core-06 = { package = "rand_core", version = "0.6" }
224rand-core-09 = { package = "rand_core", version = "0.9" } 224rand-core-09 = { package = "rand_core", version = "0.9" }
225 225
226nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "52fd51ce762a3d3a81660dea62947e6d2d1e9d91" } 226nrf-pac = { version = "0.2.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "7f450696f95591ce42f4da6e7d0402750ab1e50a" }
227 227
228defmt = { version = "1.0.1", optional = true } 228defmt = { version = "1.0.1", optional = true }
229bitflags = "2.4.2" 229bitflags = "2.10.0"
230log = { version = "0.4.14", optional = true } 230log = { version = "0.4.14", optional = true }
231cortex-m-rt = ">=0.6.15,<0.8" 231cortex-m-rt = ">=0.6.15,<0.8"
232cortex-m = "0.7.6" 232cortex-m = "0.7.6"
diff --git a/embassy-nrf/src/buffered_uarte/v1.rs b/embassy-nrf/src/buffered_uarte/v1.rs
index ec360f7d0..c14cdfadb 100644
--- a/embassy-nrf/src/buffered_uarte/v1.rs
+++ b/embassy-nrf/src/buffered_uarte/v1.rs
@@ -874,6 +874,15 @@ impl<'a> Drop for BufferedUarteRx<'a> {
874 } 874 }
875} 875}
876 876
877impl core::fmt::Display for Error {
878 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
879 match *self {
880 Error::Overrun => write!(f, "Buffer Overrun"),
881 }
882 }
883}
884impl core::error::Error for Error {}
885
877mod _embedded_io { 886mod _embedded_io {
878 use super::*; 887 use super::*;
879 888
diff --git a/embassy-nrf/src/buffered_uarte/v2.rs b/embassy-nrf/src/buffered_uarte/v2.rs
index d0d2d97d1..4a6360b69 100644
--- a/embassy-nrf/src/buffered_uarte/v2.rs
+++ b/embassy-nrf/src/buffered_uarte/v2.rs
@@ -50,6 +50,14 @@ pub enum Error {
50 // No errors for now 50 // No errors for now
51} 51}
52 52
53impl core::fmt::Display for Error {
54 fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 match *self {}
56 }
57}
58
59impl core::error::Error for Error {}
60
53impl State { 61impl State {
54 pub(crate) const fn new() -> Self { 62 pub(crate) const fn new() -> Self {
55 Self { 63 Self {
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 1f6000b13..6b9d2d1da 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -29,17 +29,14 @@ const CHANNEL_COUNT: usize = 12;
29/// Max channels per port 29/// Max channels per port
30const CHANNELS_PER_PORT: usize = 8; 30const CHANNELS_PER_PORT: usize = 8;
31 31
32#[cfg(any( 32#[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))]
33 feature = "nrf52833",
34 feature = "nrf52840",
35 feature = "_nrf5340",
36 feature = "_nrf54l15",
37 feature = "_nrf54l10",
38 feature = "_nrf54l05"
39))]
40const PIN_COUNT: usize = 48; 33const PIN_COUNT: usize = 48;
34#[cfg(any(feature = "_nrf54l15", feature = "_nrf54l10", feature = "_nrf54l05"))]
35// Highest pin index is P2.10 => (2 * 32 + 10) = 74
36const PIN_COUNT: usize = 75;
41#[cfg(feature = "_nrf54lm20")] 37#[cfg(feature = "_nrf54lm20")]
42const PIN_COUNT: usize = 66; 38// Highest pin index is P3.12 => (3 * 32 + 12) = 108
39const PIN_COUNT: usize = 109;
43#[cfg(not(any( 40#[cfg(not(any(
44 feature = "nrf52833", 41 feature = "nrf52833",
45 feature = "nrf52840", 42 feature = "nrf52840",
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 35f65bd64..21d94cc30 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -79,6 +79,10 @@ fn calc_now(period: u32, counter: u32) -> u64 {
79#[cfg(feature = "_grtc")] 79#[cfg(feature = "_grtc")]
80fn syscounter() -> u64 { 80fn syscounter() -> u64 {
81 let r = rtc(); 81 let r = rtc();
82 if !r.mode().read().syscounteren() {
83 return 0;
84 }
85
82 r.syscounter(0).active().write(|w| w.set_active(true)); 86 r.syscounter(0).active().write(|w| w.set_active(true));
83 loop { 87 loop {
84 let countl: u32 = r.syscounter(0).syscounterl().read(); 88 let countl: u32 = r.syscounter(0).syscounterl().read();
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 049830aed..ef5d6c6d1 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -1092,6 +1092,20 @@ mod eh02 {
1092 } 1092 }
1093} 1093}
1094 1094
1095impl core::fmt::Display for Error {
1096 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1097 match *self {
1098 Self::BufferTooLong => f.write_str("BufferTooLong"),
1099 Self::BufferNotInRAM => f.write_str("BufferNotInRAM"),
1100 Self::Framing => f.write_str("Framing"),
1101 Self::Parity => f.write_str("Parity"),
1102 Self::Overrun => f.write_str("Overrun"),
1103 Self::Break => f.write_str("Break"),
1104 }
1105 }
1106}
1107impl core::error::Error for Error {}
1108
1095mod _embedded_io { 1109mod _embedded_io {
1096 use super::*; 1110 use super::*;
1097 1111
@@ -1121,6 +1135,9 @@ mod _embedded_io {
1121 self.write(buf).await?; 1135 self.write(buf).await?;
1122 Ok(buf.len()) 1136 Ok(buf.len())
1123 } 1137 }
1138 async fn flush(&mut self) -> Result<(), Self::Error> {
1139 Ok(())
1140 }
1124 } 1141 }
1125 1142
1126 impl<'d> embedded_io_async::Write for UarteTx<'d> { 1143 impl<'d> embedded_io_async::Write for UarteTx<'d> {
@@ -1128,5 +1145,8 @@ mod _embedded_io {
1128 self.write(buf).await?; 1145 self.write(buf).await?;
1129 Ok(buf.len()) 1146 Ok(buf.len())
1130 } 1147 }
1148 async fn flush(&mut self) -> Result<(), Self::Error> {
1149 Ok(())
1150 }
1131 } 1151 }
1132} 1152}
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index b78c26c77..d5ef38531 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -35,7 +35,7 @@ log = { version = "0.4.27", optional = true }
35embassy-time = { version = "0.5.0", path = "../embassy-time", optional = true } 35embassy-time = { version = "0.5.0", path = "../embassy-time", optional = true }
36embassy-time-driver = { version = "0.2.1", path = "../embassy-time-driver", optional = true } 36embassy-time-driver = { version = "0.2.1", path = "../embassy-time-driver", optional = true }
37embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-utils", optional = true } 37embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-utils", optional = true }
38embedded-io = "0.6.1" 38embedded-io = { version = "0.7.1" }
39embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 39embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
40## Chip dependencies 40## Chip dependencies
41nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "af5122e1cbe1483833c5d2e5af96b26a34ed5d62"} 41nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "af5122e1cbe1483833c5d2e5af96b26a34ed5d62"}
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
index d77f08fd8..319e29054 100644
--- a/embassy-nxp/src/usart/lpc55.rs
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -51,6 +51,15 @@ impl embedded_io::Error for Error {
51 } 51 }
52 } 52 }
53} 53}
54
55impl core::fmt::Display for Error {
56 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57 core::fmt::Debug::fmt(self, f)
58 }
59}
60
61impl core::error::Error for Error {}
62
54/// Word length. 63/// Word length.
55#[derive(Clone, Copy, PartialEq, Eq, Debug)] 64#[derive(Clone, Copy, PartialEq, Eq, Debug)]
56pub enum DataBits { 65pub enum DataBits {
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 8e4bb927f..585acc064 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -167,8 +167,8 @@ cortex-m-rt = ">=0.6.15,<0.8"
167cortex-m = "0.7.6" 167cortex-m = "0.7.6"
168critical-section = "1.2.0" 168critical-section = "1.2.0"
169chrono = { version = "0.4", default-features = false, optional = true } 169chrono = { version = "0.4", default-features = false, optional = true }
170embedded-io = { version = "0.6.1" } 170embedded-io = { version = "0.7.1" }
171embedded-io-async = { version = "0.6.1" } 171embedded-io-async = { version = "0.7.0" }
172embedded-storage = { version = "0.3" } 172embedded-storage = { version = "0.3" }
173embedded-storage-async = { version = "0.4.1" } 173embedded-storage-async = { version = "0.4.1" }
174fixed = "1.28.0" 174fixed = "1.28.0"
diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs
index d59596dd1..a16d89a75 100644
--- a/embassy-rp/src/pio_programs/uart.rs
+++ b/embassy-rp/src/pio_programs/uart.rs
@@ -90,6 +90,10 @@ impl<PIO: Instance, const SM: usize> Write for PioUartTx<'_, PIO, SM> {
90 } 90 }
91 Ok(buf.len()) 91 Ok(buf.len())
92 } 92 }
93
94 async fn flush(&mut self) -> Result<(), Infallible> {
95 Ok(())
96 }
93} 97}
94 98
95/// This struct represents a Uart Rx program loaded into pio instruction memory. 99/// This struct represents a Uart Rx program loaded into pio instruction memory.
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index b7b569dd5..f53b2f88e 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -118,6 +118,14 @@ pub enum Error {
118 Framing, 118 Framing,
119} 119}
120 120
121impl core::fmt::Display for Error {
122 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123 core::fmt::Debug::fmt(self, f)
124 }
125}
126
127impl core::error::Error for Error {}
128
121/// Read To Break error 129/// Read To Break error
122#[derive(Debug, Eq, PartialEq, Copy, Clone)] 130#[derive(Debug, Eq, PartialEq, Copy, Clone)]
123#[cfg_attr(feature = "defmt", derive(defmt::Format))] 131#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 9624c7932..acf977ed5 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -46,7 +46,7 @@ critical-section = "1.2"
46 46
47bit_field = "0.10.2" 47bit_field = "0.10.2"
48stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 48stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
49stm32wb-hci = { version = "0.17.0", optional = true } 49stm32wb-hci = { version = "0.17.3", optional = true }
50futures-util = { version = "0.3.30", default-features = false } 50futures-util = { version = "0.3.30", default-features = false }
51bitflags = { version = "2.3.3", optional = true } 51bitflags = { version = "2.3.3", optional = true }
52 52
@@ -57,7 +57,7 @@ wb55 = []
57wb55_ble = ["dep:stm32wb-hci"] 57wb55_ble = ["dep:stm32wb-hci"]
58wb55_mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"] 58wb55_mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"]
59 59
60wba = [ "dep:stm32-bindings" ] 60wba = [ "dep:stm32-bindings", "dep:embassy-time" ]
61wba_ble = [ "stm32-bindings/wba_wpan_mac" , "stm32-bindings/wba_wpan" ] 61wba_ble = [ "stm32-bindings/wba_wpan_mac" , "stm32-bindings/wba_wpan" ]
62wba_mac = [ "stm32-bindings/wba_wpan_mac", "stm32-bindings/wba_wpan_ble" , "stm32-bindings/lib_wba5_linklayer15_4", "stm32-bindings/lib_wba_mac_lib" , "stm32-bindings/wba_wpan" ] 62wba_mac = [ "stm32-bindings/wba_wpan_mac", "stm32-bindings/wba_wpan_ble" , "stm32-bindings/lib_wba5_linklayer15_4", "stm32-bindings/lib_wba_mac_lib" , "stm32-bindings/wba_wpan" ]
63 63
diff --git a/embassy-stm32-wpan/src/wb55/mod.rs b/embassy-stm32-wpan/src/wb55/mod.rs
index 95cfe09f1..814303a05 100644
--- a/embassy-stm32-wpan/src/wb55/mod.rs
+++ b/embassy-stm32-wpan/src/wb55/mod.rs
@@ -176,7 +176,7 @@ impl<'d> TlMbox<'d> {
176 let mm = sub::mm::MemoryManager::new(ipcc_mm_release_buffer_channel); 176 let mm = sub::mm::MemoryManager::new(ipcc_mm_release_buffer_channel);
177 let mut sys = sub::sys::Sys::new(ipcc_system_cmd_rsp_channel, ipcc_system_event_channel); 177 let mut sys = sub::sys::Sys::new(ipcc_system_cmd_rsp_channel, ipcc_system_event_channel);
178 178
179 debug!("sys event: {}", sys.read().await.payload()); 179 debug!("sys event: {}", sys.read_ready().await);
180 180
181 Self { 181 Self {
182 sys_subsystem: sys, 182 sys_subsystem: sys,
diff --git a/embassy-stm32-wpan/src/wb55/shci.rs b/embassy-stm32-wpan/src/wb55/shci.rs
index 3faa79209..3eb9525d3 100644
--- a/embassy-stm32-wpan/src/wb55/shci.rs
+++ b/embassy-stm32-wpan/src/wb55/shci.rs
@@ -12,6 +12,28 @@ const fn opcode(ogf: u16, ocf: u16) -> isize {
12 ((ogf << 10) + ocf) as isize 12 ((ogf << 10) + ocf) as isize
13} 13}
14 14
15pub(crate) trait SealedSchiFromPacket: Sized {
16 unsafe fn from_packet(cmd_buf: *const CmdPacket) -> Result<Self, ()>;
17}
18
19#[allow(private_bounds)]
20pub trait SchiFromPacket: SealedSchiFromPacket {}
21impl<T: SealedSchiFromPacket> SchiFromPacket for T {}
22
23trait ShciFromEventSerial: TryFrom<u8, Error = ()> {}
24
25impl<T: ShciFromEventSerial> SealedSchiFromPacket for T {
26 unsafe fn from_packet(cmd_buf: *const CmdPacket) -> Result<Self, ()> {
27 let p_cmd_serial = (cmd_buf as *mut u8).add(size_of::<PacketHeader>());
28 let p_evt_payload = p_cmd_serial.add(size_of::<EvtStub>());
29
30 compiler_fence(Ordering::Acquire);
31 let cc_evt = ptr::read_unaligned(p_evt_payload as *const CcEvt);
32
33 cc_evt.payload[0].try_into()
34 }
35}
36
15#[allow(dead_code)] 37#[allow(dead_code)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))] 38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub enum SchiCommandStatus { 39pub enum SchiCommandStatus {
@@ -25,37 +47,20 @@ pub enum SchiCommandStatus {
25 ShciFusCmdNotSupported = 0xFF, 47 ShciFusCmdNotSupported = 0xFF,
26} 48}
27 49
28impl SchiCommandStatus { 50impl ShciFromEventSerial for SchiCommandStatus {}
29 pub unsafe fn from_packet(cmd_buf: *const CmdPacket) -> Result<Self, ()> {
30 let p_cmd_serial = (cmd_buf as *mut u8).add(size_of::<PacketHeader>());
31 let p_evt_payload = p_cmd_serial.add(size_of::<EvtStub>());
32
33 compiler_fence(Ordering::Acquire);
34 let cc_evt = ptr::read_unaligned(p_evt_payload as *const CcEvt);
35
36 cc_evt.payload[0].try_into()
37 }
38}
39
40impl TryFrom<u8> for SchiCommandStatus { 51impl TryFrom<u8> for SchiCommandStatus {
41 type Error = (); 52 type Error = ();
42 53
43 fn try_from(v: u8) -> Result<Self, Self::Error> { 54 fn try_from(v: u8) -> Result<Self, Self::Error> {
44 match v { 55 match v {
45 x if x == SchiCommandStatus::ShciSuccess as u8 => Ok(SchiCommandStatus::ShciSuccess), 56 0x00 => Ok(Self::ShciSuccess),
46 x if x == SchiCommandStatus::ShciUnknownCmd as u8 => Ok(SchiCommandStatus::ShciUnknownCmd), 57 0x01 => Ok(Self::ShciUnknownCmd),
47 x if x == SchiCommandStatus::ShciMemoryCapacityExceededErrCode as u8 => { 58 0x07 => Ok(Self::ShciMemoryCapacityExceededErrCode),
48 Ok(SchiCommandStatus::ShciMemoryCapacityExceededErrCode) 59 0x11 => Ok(Self::ShciErrUnsupportedFeature),
49 } 60 0x12 => Ok(Self::ShciErrInvalidHciCmdParams),
50 x if x == SchiCommandStatus::ShciErrUnsupportedFeature as u8 => { 61 0x42 => Ok(Self::ShciErrInvalidParams), /* only used for release < v1.13.0 */
51 Ok(SchiCommandStatus::ShciErrUnsupportedFeature) 62 0x92 => Ok(Self::ShciErrInvalidParamsV2), /* available for release >= v1.13.0 */
52 } 63 0xFF => Ok(Self::ShciFusCmdNotSupported),
53 x if x == SchiCommandStatus::ShciErrInvalidHciCmdParams as u8 => {
54 Ok(SchiCommandStatus::ShciErrInvalidHciCmdParams)
55 }
56 x if x == SchiCommandStatus::ShciErrInvalidParams as u8 => Ok(SchiCommandStatus::ShciErrInvalidParams), /* only used for release < v1.13.0 */
57 x if x == SchiCommandStatus::ShciErrInvalidParamsV2 as u8 => Ok(SchiCommandStatus::ShciErrInvalidParamsV2), /* available for release >= v1.13.0 */
58 x if x == SchiCommandStatus::ShciFusCmdNotSupported as u8 => Ok(SchiCommandStatus::ShciFusCmdNotSupported),
59 _ => Err(()), 64 _ => Err(()),
60 } 65 }
61 } 66 }
@@ -107,6 +112,71 @@ pub enum ShciOpcode {
107 Mac802_15_4DeInit = opcode(SHCI_OGF, 0x78), 112 Mac802_15_4DeInit = opcode(SHCI_OGF, 0x78),
108} 113}
109 114
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub enum ShciFusGetStateErrorCode {
117 FusStateErrorNoError = 0x00,
118 FusStateErrorImgNotFound = 0x01,
119 FusStateErrorImgCorrupt = 0x02,
120 FusStateErrorImgNotAuthentic = 0x03,
121 FusStateErrorImgNotEnoughSpace = 0x04,
122 FusStateErrorImageUsrAbort = 0x05,
123 FusStateErrorImageErsError = 0x06,
124 FusStateErrorImageWrtError = 0x07,
125 FusStateErrorAuthTagStNotFound = 0x08,
126 FusStateErrorAuthTagCustNotFound = 0x09,
127 FusStateErrorAuthKeyLocked = 0x0A,
128 FusStateErrorFwRollbackError = 0x11,
129 FusStateErrorStateNotRunning = 0xFE,
130 FusStateErrorErrUnknown = 0xFF,
131}
132
133impl ShciFromEventSerial for ShciFusGetStateErrorCode {}
134impl TryFrom<u8> for ShciFusGetStateErrorCode {
135 type Error = ();
136
137 fn try_from(v: u8) -> Result<Self, Self::Error> {
138 match v {
139 0x00 => Ok(Self::FusStateErrorNoError),
140 0x01 => Ok(Self::FusStateErrorImgNotFound),
141 0x02 => Ok(Self::FusStateErrorImgCorrupt),
142 0x03 => Ok(Self::FusStateErrorImgNotAuthentic),
143 0x04 => Ok(Self::FusStateErrorImgNotEnoughSpace),
144 0x05 => Ok(Self::FusStateErrorImageUsrAbort),
145 0x06 => Ok(Self::FusStateErrorImageErsError),
146 0x07 => Ok(Self::FusStateErrorImageWrtError),
147 0x08 => Ok(Self::FusStateErrorAuthTagStNotFound),
148 0x09 => Ok(Self::FusStateErrorAuthTagCustNotFound),
149 0x0A => Ok(Self::FusStateErrorAuthKeyLocked),
150 0x11 => Ok(Self::FusStateErrorFwRollbackError),
151 0xFE => Ok(Self::FusStateErrorStateNotRunning),
152 0xFF => Ok(Self::FusStateErrorErrUnknown),
153 _ => Err(()),
154 }
155 }
156}
157
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
159pub enum SchiSysEventReady {
160 WirelessFwRunning = 0x00,
161 FusFwRunning = 0x01,
162 NvmBackupRunning = 0x10,
163 NvmRestoreRunning = 0x11,
164}
165
166impl TryFrom<u8> for SchiSysEventReady {
167 type Error = ();
168
169 fn try_from(v: u8) -> Result<Self, Self::Error> {
170 match v {
171 0x00 => Ok(Self::WirelessFwRunning),
172 0x01 => Ok(Self::FusFwRunning),
173 0x10 => Ok(Self::NvmBackupRunning),
174 0x11 => Ok(Self::NvmRestoreRunning),
175 _ => Err(()),
176 }
177 }
178}
179
110pub const SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE: u8 = 1 << 0; 180pub const SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE: u8 = 1 << 0;
111pub const SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 1; 181pub const SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 1;
112pub const SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 2; 182pub const SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE: u8 = 1 << 2;
diff --git a/embassy-stm32-wpan/src/wb55/sub/ble.rs b/embassy-stm32-wpan/src/wb55/sub/ble.rs
index a2558d735..a822d6530 100644
--- a/embassy-stm32-wpan/src/wb55/sub/ble.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/ble.rs
@@ -130,12 +130,8 @@ impl<'a> hci::Controller for Ble<'a> {
130 self.tl_write(opcode.0, payload).await; 130 self.tl_write(opcode.0, payload).await;
131 } 131 }
132 132
133 #[allow(invalid_reference_casting)] 133 async fn controller_read_into(&mut self, buf: &mut [u8]) {
134 async fn controller_read_into(&self, buf: &mut [u8]) { 134 let evt_box = self.tl_read().await;
135 // A complete hack since I cannot update the trait
136 let s = unsafe { &mut *(self as *const _ as *mut Ble) };
137
138 let evt_box = s.tl_read().await;
139 let evt_serial = evt_box.serial(); 135 let evt_serial = evt_box.serial();
140 136
141 buf[..evt_serial.len()].copy_from_slice(evt_serial); 137 buf[..evt_serial.len()].copy_from_slice(evt_serial);
diff --git a/embassy-stm32-wpan/src/wb55/sub/sys.rs b/embassy-stm32-wpan/src/wb55/sub/sys.rs
index 2e625a677..3d774eeb7 100644
--- a/embassy-stm32-wpan/src/wb55/sub/sys.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/sys.rs
@@ -1,3 +1,5 @@
1use core::slice;
2
1use embassy_stm32::ipcc::{IpccRxChannel, IpccTxChannel}; 3use embassy_stm32::ipcc::{IpccRxChannel, IpccTxChannel};
2 4
3use crate::cmd::CmdPacket; 5use crate::cmd::CmdPacket;
@@ -5,12 +7,17 @@ use crate::consts::TlPacketType;
5use crate::evt::EvtBox; 7use crate::evt::EvtBox;
6#[cfg(feature = "wb55_ble")] 8#[cfg(feature = "wb55_ble")]
7use crate::shci::ShciBleInitCmdParam; 9use crate::shci::ShciBleInitCmdParam;
8use crate::shci::{SchiCommandStatus, ShciOpcode}; 10use crate::shci::{SchiCommandStatus, SchiFromPacket, SchiSysEventReady, ShciFusGetStateErrorCode, ShciOpcode};
9use crate::sub::mm; 11use crate::sub::mm;
10use crate::tables::{SysTable, WirelessFwInfoTable}; 12use crate::tables::{SysTable, WirelessFwInfoTable};
11use crate::unsafe_linked_list::LinkedListNode; 13use crate::unsafe_linked_list::LinkedListNode;
12use crate::wb55::{SYS_CMD_BUF, SYSTEM_EVT_QUEUE, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; 14use crate::wb55::{SYS_CMD_BUF, SYSTEM_EVT_QUEUE, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
13 15
16const fn slice8_ref(x: &[u32]) -> &[u8] {
17 let len = x.len() * 4;
18 unsafe { slice::from_raw_parts(x.as_ptr() as *const u8, len) }
19}
20
14/// A guard that, once constructed, allows for sys commands to be sent to CPU2. 21/// A guard that, once constructed, allows for sys commands to be sent to CPU2.
15pub struct Sys<'a> { 22pub struct Sys<'a> {
16 ipcc_system_cmd_rsp_channel: IpccTxChannel<'a>, 23 ipcc_system_cmd_rsp_channel: IpccTxChannel<'a>,
@@ -55,15 +62,15 @@ impl<'a> Sys<'a> {
55 } 62 }
56 63
57 /// `HW_IPCC_SYS_CmdEvtNot` 64 /// `HW_IPCC_SYS_CmdEvtNot`
58 pub async fn write_and_get_response( 65 pub async fn write_and_get_response<T: SchiFromPacket>(
59 &mut self, 66 &mut self,
60 opcode: ShciOpcode, 67 opcode: ShciOpcode,
61 payload: &[u8], 68 payload: &[u8],
62 ) -> Result<SchiCommandStatus, ()> { 69 ) -> Result<T, ()> {
63 self.write(opcode, payload).await; 70 self.write(opcode, payload).await;
64 self.ipcc_system_cmd_rsp_channel.flush().await; 71 self.ipcc_system_cmd_rsp_channel.flush().await;
65 72
66 unsafe { SchiCommandStatus::from_packet(SYS_CMD_BUF.as_ptr()) } 73 unsafe { T::from_packet(SYS_CMD_BUF.as_ptr()) }
67 } 74 }
68 75
69 #[cfg(feature = "wb55_mac")] 76 #[cfg(feature = "wb55_mac")]
@@ -82,6 +89,36 @@ impl<'a> Sys<'a> {
82 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await 89 self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
83 } 90 }
84 91
92 pub async fn shci_c2_fus_getstate(&mut self) -> Result<ShciFusGetStateErrorCode, ()> {
93 self.write_and_get_response(ShciOpcode::FusStartWirelessStack, &[])
94 .await
95 }
96
97 /// Send a request to CPU2 to start the wireless stack
98 pub async fn shci_c2_fus_startws(&mut self) -> Result<SchiCommandStatus, ()> {
99 self.write_and_get_response(ShciOpcode::FusStartWirelessStack, &[])
100 .await
101 }
102
103 /// Send a request to CPU2 to upgrade the firmware
104 pub async fn shci_c2_fus_fwupgrade(&mut self, fw_src_add: u32, fw_dst_add: u32) -> Result<SchiCommandStatus, ()> {
105 let buf = [fw_src_add, fw_dst_add];
106 let len = if fw_dst_add != 0 {
107 2
108 } else if fw_src_add != 0 {
109 1
110 } else {
111 0
112 };
113
114 self.write_and_get_response(ShciOpcode::FusFirmwareUpgrade, slice8_ref(&buf[..len]))
115 .await
116 }
117
118 pub async fn read_ready(&mut self) -> Result<SchiSysEventReady, ()> {
119 self.read().await.payload()[0].try_into()
120 }
121
85 /// `HW_IPCC_SYS_EvtNot` 122 /// `HW_IPCC_SYS_EvtNot`
86 /// 123 ///
87 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, 124 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`,
diff --git a/embassy-stm32-wpan/src/wba/linklayer_plat.rs b/embassy-stm32-wpan/src/wba/linklayer_plat.rs
index c011b3bcb..e6a342b52 100644
--- a/embassy-stm32-wpan/src/wba/linklayer_plat.rs
+++ b/embassy-stm32-wpan/src/wba/linklayer_plat.rs
@@ -1,6 +1,3 @@
1#[allow(dead_code)]
2fn test_fn() {}
3
4// /* USER CODE BEGIN Header */ 1// /* USER CODE BEGIN Header */
5// /** 2// /**
6// ****************************************************************************** 3// ******************************************************************************
@@ -72,131 +69,339 @@ fn test_fn() {}
72// uint8_t AHB5_SwitchedOff = 0; 69// uint8_t AHB5_SwitchedOff = 0;
73// uint32_t radio_sleep_timer_val = 0; 70// uint32_t radio_sleep_timer_val = 0;
74// 71//
72// /* USER CODE BEGIN LINKLAYER_PLAT 0 */
73//
74// /* USER CODE END LINKLAYER_PLAT 0 */
75#![cfg(feature = "wba")]
76#![allow(clippy::missing_safety_doc)]
77
78use core::hint::spin_loop;
79use core::ptr;
80use core::sync::atomic::{AtomicBool, AtomicI32, AtomicPtr, AtomicU32, Ordering};
81
82use cortex_m::asm::{dsb, isb};
83use cortex_m::interrupt::InterruptNumber;
84use cortex_m::peripheral::NVIC;
85use cortex_m::register::basepri;
86use critical_section;
87#[cfg(feature = "defmt")]
88use defmt::trace;
89use embassy_stm32::NVIC_PRIO_BITS;
90use embassy_time::{Duration, block_for};
91
92use super::bindings::{link_layer, mac};
93
94// Missing constant from stm32-bindings - RADIO_SW_LOW interrupt number
95// For STM32WBA, this is typically RADIO_IRQ_BUSY (interrupt 43)
96const RADIO_SW_LOW_INTR_NUM: u32 = 43;
97
98type Callback = unsafe extern "C" fn();
99
100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
101#[repr(transparent)]
102struct RawInterrupt(u16);
103
104impl RawInterrupt {
105 fn new(irq: u32) -> Self {
106 debug_assert!(irq <= u16::MAX as u32);
107 Self(irq as u16)
108 }
109}
110
111impl From<u32> for RawInterrupt {
112 fn from(value: u32) -> Self {
113 Self::new(value)
114 }
115}
116
117unsafe impl InterruptNumber for RawInterrupt {
118 fn number(self) -> u16 {
119 self.0
120 }
121}
122
123static RADIO_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
124static LOW_ISR_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
125
126static IRQ_COUNTER: AtomicI32 = AtomicI32::new(0);
127
128static PRIO_HIGH_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
129static PRIO_LOW_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
130static PRIO_SYS_ISR_COUNTER: AtomicI32 = AtomicI32::new(0);
131static LOCAL_BASEPRI_VALUE: AtomicU32 = AtomicU32::new(0);
132
133static RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO: AtomicBool = AtomicBool::new(false);
134static AHB5_SWITCHED_OFF: AtomicBool = AtomicBool::new(false);
135static RADIO_SLEEP_TIMER_VAL: AtomicU32 = AtomicU32::new(0);
136
137static PRNG_STATE: AtomicU32 = AtomicU32::new(0);
138static PRNG_INIT: AtomicBool = AtomicBool::new(false);
139
140// Critical-section restore token for IRQ enable/disable pairing.
141// Only written when the IRQ disable counter transitions 0->1, and consumed when it transitions 1->0.
142static mut CS_RESTORE_STATE: Option<critical_section::RestoreState> = None;
143
144fn read_system_core_clock() -> u32 {
145 0
146}
147
148fn store_callback(slot: &AtomicPtr<()>, cb: Option<Callback>) {
149 let ptr = cb.map_or(ptr::null_mut(), |f| f as *mut ());
150 slot.store(ptr, Ordering::Release);
151}
152
153fn load_callback(slot: &AtomicPtr<()>) -> Option<Callback> {
154 let ptr = slot.load(Ordering::Acquire);
155 if ptr.is_null() {
156 None
157 } else {
158 Some(unsafe { core::mem::transmute::<*mut (), Callback>(ptr) })
159 }
160}
161
162fn priority_shift() -> u8 {
163 8 - NVIC_PRIO_BITS as u8
164}
165
166fn pack_priority(raw: u32) -> u8 {
167 let shift = priority_shift();
168 let priority_bits = NVIC_PRIO_BITS as u32;
169 let mask = if priority_bits >= 32 {
170 u32::MAX
171 } else {
172 (1u32 << priority_bits) - 1
173 };
174 let clamped = raw & mask;
175 (clamped << u32::from(shift)) as u8
176}
177
178fn counter_release(counter: &AtomicI32) -> bool {
179 counter.fetch_sub(1, Ordering::SeqCst) <= 1
180}
181
182fn counter_acquire(counter: &AtomicI32) -> bool {
183 counter.fetch_add(1, Ordering::SeqCst) == 0
184}
185
186unsafe fn nvic_enable(irq: u32) {
187 NVIC::unmask(RawInterrupt::new(irq));
188 dsb();
189 isb();
190}
191
192unsafe fn nvic_disable(irq: u32) {
193 NVIC::mask(RawInterrupt::new(irq));
194 dsb();
195 isb();
196}
197
198unsafe fn nvic_set_pending(irq: u32) {
199 NVIC::pend(RawInterrupt::new(irq));
200 dsb();
201 isb();
202}
203
204unsafe fn nvic_get_active(irq: u32) -> bool {
205 NVIC::is_active(RawInterrupt::new(irq))
206}
207
208unsafe fn nvic_set_priority(irq: u32, priority: u8) {
209 // STM32WBA is ARMv8-M, which uses byte-accessible IPR registers
210 let nvic = &*NVIC::PTR;
211 nvic.ipr[irq as usize].write(priority);
212
213 dsb();
214 isb();
215}
216
217fn set_basepri_max(value: u8) {
218 unsafe {
219 if basepri::read() < value {
220 basepri::write(value);
221 }
222 }
223}
224
225fn prng_next() -> u32 {
226 #[inline]
227 fn xorshift(mut x: u32) -> u32 {
228 x ^= x << 13;
229 x ^= x >> 17;
230 x ^= x << 5;
231 x
232 }
233
234 if !PRNG_INIT.load(Ordering::Acquire) {
235 let seed = unsafe {
236 let timer = link_layer::ll_intf_cmn_get_slptmr_value();
237 let core_clock = read_system_core_clock();
238 timer ^ core_clock ^ 0x6C8E_9CF5
239 };
240 PRNG_STATE.store(seed, Ordering::Relaxed);
241 PRNG_INIT.store(true, Ordering::Release);
242 }
243
244 let mut current = PRNG_STATE.load(Ordering::Relaxed);
245 loop {
246 let next = xorshift(current);
247 match PRNG_STATE.compare_exchange_weak(current, next, Ordering::AcqRel, Ordering::Relaxed) {
248 Ok(_) => return next,
249 Err(v) => current = v,
250 }
251 }
252}
253
254pub unsafe fn run_radio_high_isr() {
255 if let Some(cb) = load_callback(&RADIO_CALLBACK) {
256 cb();
257 }
258}
259
260pub unsafe fn run_radio_sw_low_isr() {
261 if let Some(cb) = load_callback(&LOW_ISR_CALLBACK) {
262 cb();
263 }
264
265 if RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO.swap(false, Ordering::AcqRel) {
266 nvic_set_priority(RADIO_SW_LOW_INTR_NUM, pack_priority(mac::RADIO_SW_LOW_INTR_PRIO));
267 }
268}
269
75// /** 270// /**
76// * @brief Configure the necessary clock sources for the radio. 271// * @brief Configure the necessary clock sources for the radio.
77// * @param None 272// * @param None
78// * @retval None 273// * @retval None
79// */ 274// */
80// void LINKLAYER_PLAT_ClockInit() 275#[unsafe(no_mangle)]
81// { 276pub unsafe extern "C" fn LINKLAYER_PLAT_ClockInit() {
82// uint32_t linklayer_slp_clk_src = LL_RCC_RADIOSLEEPSOURCE_NONE; 277 // uint32_t linklayer_slp_clk_src = LL_RCC_RADIOSLEEPSOURCE_NONE;
83// 278 //
84// /* Get the Link Layer sleep timer clock source */ 279 // /* Get the Link Layer sleep timer clock source */
85// linklayer_slp_clk_src = LL_RCC_RADIO_GetSleepTimerClockSource(); 280 // linklayer_slp_clk_src = LL_RCC_RADIO_GetSleepTimerClockSource();
86// if(linklayer_slp_clk_src == LL_RCC_RADIOSLEEPSOURCE_NONE) 281 // if(linklayer_slp_clk_src == LL_RCC_RADIOSLEEPSOURCE_NONE)
87// { 282 // {
88// /* If there is no clock source defined, should be selected before */ 283 // /* If there is no clock source defined, should be selected before */
89// assert_param(0); 284 // assert_param(0);
90// } 285 // }
91// 286 //
92// /* Enable AHB5ENR peripheral clock (bus CLK) */ 287 // /* Enable AHB5ENR peripheral clock (bus CLK) */
93// __HAL_RCC_RADIO_CLK_ENABLE(); 288 // __HAL_RCC_RADIO_CLK_ENABLE();
94// } 289 trace!("LINKLAYER_PLAT_ClockInit: get_slptmr_value");
95// 290 let _ = link_layer::ll_intf_cmn_get_slptmr_value();
291}
292
96// /** 293// /**
97// * @brief Link Layer active waiting loop. 294// * @brief Link Layer active waiting loop.
98// * @param delay: delay in us 295// * @param delay: delay in us
99// * @retval None 296// * @retval None
100// */ 297// */
101// void LINKLAYER_PLAT_DelayUs(uint32_t delay) 298#[unsafe(no_mangle)]
102// { 299pub unsafe extern "C" fn LINKLAYER_PLAT_DelayUs(delay: u32) {
103// static uint8_t lock = 0; 300 // static uint8_t lock = 0;
104// uint32_t t0; 301 // uint32_t t0;
105// uint32_t primask_bit; 302 // uint32_t primask_bit;
106// 303 //
107// /* Enter critical section */ 304 // /* Enter critical section */
108// primask_bit= __get_PRIMASK(); 305 // primask_bit= __get_PRIMASK();
109// __disable_irq(); 306 // __disable_irq();
110// 307 //
111// if (lock == 0U) 308 // if (lock == 0U)
112// { 309 // {
113// /* Initialize counter */ 310 // /* Initialize counter */
114// /* Reset cycle counter to prevent overflow 311 // /* Reset cycle counter to prevent overflow
115// As a us counter, it is assumed than even with re-entrancy, 312 // As a us counter, it is assumed than even with re-entrancy,
116// overflow will never happen before re-initializing this counter */ 313 // overflow will never happen before re-initializing this counter */
117// DWT->CYCCNT = 0U; 314 // DWT->CYCCNT = 0U;
118// /* Enable DWT by safety but should be useless (as already set) */ 315 // /* Enable DWT by safety but should be useless (as already set) */
119// SET_BIT(DCB->DEMCR, DCB_DEMCR_TRCENA_Msk); 316 // SET_BIT(DCB->DEMCR, DCB_DEMCR_TRCENA_Msk);
120// /* Enable counter */ 317 // /* Enable counter */
121// SET_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk); 318 // SET_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk);
122// } 319 // }
123// /* Increment 're-entrance' counter */ 320 // /* Increment 're-entrance' counter */
124// lock++; 321 // lock++;
125// /* Get starting time stamp */ 322 // /* Get starting time stamp */
126// t0 = DWT->CYCCNT; 323 // t0 = DWT->CYCCNT;
127// /* Exit critical section */ 324 // /* Exit critical section */
128// __set_PRIMASK(primask_bit); 325 // __set_PRIMASK(primask_bit);
129// 326 //
130// /* Turn us into cycles */ 327 // /* Turn us into cycles */
131// delay = delay * (SystemCoreClock / 1000000U); 328 // delay = delay * (SystemCoreClock / 1000000U);
132// delay += t0; 329 // delay += t0;
133// 330 //
134// /* Busy waiting loop */ 331 // /* Busy waiting loop */
135// while (DWT->CYCCNT < delay) 332 // while (DWT->CYCCNT < delay)
136// { 333 // {
137// }; 334 // };
138// 335 //
139// /* Enter critical section */ 336 // /* Enter critical section */
140// primask_bit= __get_PRIMASK(); 337 // primask_bit= __get_PRIMASK();
141// __disable_irq(); 338 // __disable_irq();
142// if (lock == 1U) 339 // if (lock == 1U)
143// { 340 // {
144// /* Disable counter */ 341 // /* Disable counter */
145// CLEAR_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk); 342 // CLEAR_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk);
146// } 343 // }
147// /* Decrement 're-entrance' counter */ 344 // /* Decrement 're-entrance' counter */
148// lock--; 345 // lock--;
149// /* Exit critical section */ 346 // /* Exit critical section */
150// __set_PRIMASK(primask_bit); 347 // __set_PRIMASK(primask_bit);
151// 348 //
152// } 349 trace!("LINKLAYER_PLAT_DelayUs: delay={}", delay);
153// 350 block_for(Duration::from_micros(u64::from(delay)));
351}
352
154// /** 353// /**
155// * @brief Link Layer assertion API 354// * @brief Link Layer assertion API
156// * @param condition: conditional statement to be checked. 355// * @param condition: conditional statement to be checked.
157// * @retval None 356// * @retval None
158// */ 357// */
159// void LINKLAYER_PLAT_Assert(uint8_t condition) 358#[unsafe(no_mangle)]
160// { 359pub unsafe extern "C" fn LINKLAYER_PLAT_Assert(condition: u8) {
161// assert_param(condition); 360 if condition == 0 {
162// } 361 panic!("LINKLAYER_PLAT assertion failed");
163// 362 }
363}
364
164// /** 365// /**
165// * @brief Enable/disable the Link Layer active clock (baseband clock). 366// * @brief Enable/disable the Link Layer active clock (baseband clock).
166// * @param enable: boolean value to enable (1) or disable (0) the clock. 367// * @param enable: boolean value to enable (1) or disable (0) the clock.
167// * @retval None 368// * @retval None
168// */ 369// */
169// void LINKLAYER_PLAT_WaitHclkRdy(void) 370#[unsafe(no_mangle)]
170// { 371pub unsafe extern "C" fn LINKLAYER_PLAT_WaitHclkRdy() {
171// /* Wait on radio bus clock readiness if it has been turned of */ 372 trace!("LINKLAYER_PLAT_WaitHclkRdy");
172// if (AHB5_SwitchedOff == 1) 373 if AHB5_SWITCHED_OFF.swap(false, Ordering::AcqRel) {
173// { 374 let reference = RADIO_SLEEP_TIMER_VAL.load(Ordering::Acquire);
174// AHB5_SwitchedOff = 0; 375 trace!("LINKLAYER_PLAT_WaitHclkRdy: reference={}", reference);
175// while (radio_sleep_timer_val == ll_intf_cmn_get_slptmr_value()); 376 while reference == link_layer::ll_intf_cmn_get_slptmr_value() {
176// } 377 spin_loop();
177// } 378 }
178// 379 }
380}
381
179// /** 382// /**
180// * @brief Notify the Link Layer platform layer the system will enter in WFI 383// * @brief Notify the Link Layer platform layer the system will enter in WFI
181// * and AHB5 clock may be turned of regarding the 2.4Ghz radio state. 384// * and AHB5 clock may be turned of regarding the 2.4Ghz radio state.
182// * @param None 385// * @param None
183// * @retval None 386// * @retval None
184// */ 387// */
185// void LINKLAYER_PLAT_NotifyWFIEnter(void) 388#[unsafe(no_mangle)]
186// { 389pub unsafe extern "C" fn LINKLAYER_PLAT_NotifyWFIEnter() {
187// /* Check if Radio state will allow the AHB5 clock to be cut */ 390 // /* Check if Radio state will allow the AHB5 clock to be cut */
188// 391 //
189// /* AHB5 clock will be cut in the following cases: 392 // /* AHB5 clock will be cut in the following cases:
190// * - 2.4GHz radio is not in ACTIVE mode (in SLEEP or DEEPSLEEP mode). 393 // * - 2.4GHz radio is not in ACTIVE mode (in SLEEP or DEEPSLEEP mode).
191// * - RADIOSMEN and STRADIOCLKON bits are at 0. 394 // * - RADIOSMEN and STRADIOCLKON bits are at 0.
192// */ 395 // */
193// if((LL_PWR_GetRadioMode() != LL_PWR_RADIO_ACTIVE_MODE) || 396 // if((LL_PWR_GetRadioMode() != LL_PWR_RADIO_ACTIVE_MODE) ||
194// ((__HAL_RCC_RADIO_IS_CLK_SLEEP_ENABLED() == 0) && (LL_RCC_RADIO_IsEnabledSleepTimerClock() == 0))) 397 // ((__HAL_RCC_RADIO_IS_CLK_SLEEP_ENABLED() == 0) && (LL_RCC_RADIO_IsEnabledSleepTimerClock() == 0)))
195// { 398 // {
196// AHB5_SwitchedOff = 1; 399 // AHB5_SwitchedOff = 1;
197// } 400 // }
198// } 401 trace!("LINKLAYER_PLAT_NotifyWFIEnter");
199// 402 AHB5_SWITCHED_OFF.store(true, Ordering::Release);
403}
404
200// /** 405// /**
201// * @brief Notify the Link Layer platform layer the system exited WFI and AHB5 406// * @brief Notify the Link Layer platform layer the system exited WFI and AHB5
202// * clock may be resynchronized as is may have been turned of during 407// * clock may be resynchronized as is may have been turned of during
@@ -204,172 +409,202 @@ fn test_fn() {}
204// * @param None 409// * @param None
205// * @retval None 410// * @retval None
206// */ 411// */
207// void LINKLAYER_PLAT_NotifyWFIExit(void) 412#[unsafe(no_mangle)]
208// { 413pub unsafe extern "C" fn LINKLAYER_PLAT_NotifyWFIExit() {
209// /* Check if AHB5 clock has been turned of and needs resynchronisation */ 414 trace!("LINKLAYER_PLAT_NotifyWFIExit");
210// if (AHB5_SwitchedOff) 415 // /* Check if AHB5 clock has been turned of and needs resynchronisation */
211// { 416 if AHB5_SWITCHED_OFF.load(Ordering::Acquire) {
212// /* Read sleep register as earlier as possible */ 417 // /* Read sleep register as earlier as possible */
213// radio_sleep_timer_val = ll_intf_cmn_get_slptmr_value(); 418 let value = link_layer::ll_intf_cmn_get_slptmr_value();
214// } 419 RADIO_SLEEP_TIMER_VAL.store(value, Ordering::Release);
215// } 420 }
216// 421}
422
217// /** 423// /**
218// * @brief Active wait on bus clock readiness. 424// * @brief Active wait on bus clock readiness.
219// * @param None 425// * @param None
220// * @retval None 426// * @retval None
221// */ 427// */
222// void LINKLAYER_PLAT_AclkCtrl(uint8_t enable) 428#[unsafe(no_mangle)]
223// { 429pub unsafe extern "C" fn LINKLAYER_PLAT_AclkCtrl(_enable: u8) {
224// if(enable != 0u) 430 trace!("LINKLAYER_PLAT_AclkCtrl: enable={}", _enable);
225// { 431 if _enable != 0 {
226// #if (CFG_SCM_SUPPORTED == 1) 432 // #if (CFG_SCM_SUPPORTED == 1)
227// /* SCM HSE BEGIN */ 433 // /* SCM HSE BEGIN */
228// /* Polling on HSE32 activation */ 434 // /* Polling on HSE32 activation */
229// SCM_HSE_WaitUntilReady(); 435 // SCM_HSE_WaitUntilReady();
230// /* Enable RADIO baseband clock (active CLK) */ 436 // /* Enable RADIO baseband clock (active CLK) */
231// HAL_RCCEx_EnableRadioBBClock(); 437 // HAL_RCCEx_EnableRadioBBClock();
232// /* SCM HSE END */ 438 // /* SCM HSE END */
233// #else 439 // #else
234// /* Enable RADIO baseband clock (active CLK) */ 440 // /* Enable RADIO baseband clock (active CLK) */
235// HAL_RCCEx_EnableRadioBBClock(); 441 // HAL_RCCEx_EnableRadioBBClock();
236// /* Polling on HSE32 activation */ 442 // /* Polling on HSE32 activation */
237// while ( LL_RCC_HSE_IsReady() == 0); 443 // while ( LL_RCC_HSE_IsReady() == 0);
238// #endif /* CFG_SCM_SUPPORTED */ 444 // #endif /* CFG_SCM_SUPPORTED */
239// } 445 // NOTE: Add a proper assertion once a typed `Radio` peripheral exists in embassy-stm32
240// else 446 // that exposes the baseband clock enable status via RCC.
241// { 447 } else {
242// /* Disable RADIO baseband clock (active CLK) */ 448 // /* Disable RADIO baseband clock (active CLK) */
243// HAL_RCCEx_DisableRadioBBClock(); 449 // HAL_RCCEx_DisableRadioBBClock();
244// } 450 }
245// } 451}
246// 452
247// /** 453// /**
248// * @brief Link Layer RNG request. 454// * @brief Link Layer RNG request.
249// * @param ptr_rnd: pointer to the variable that hosts the number. 455// * @param ptr_rnd: pointer to the variable that hosts the number.
250// * @param len: number of byte of anthropy to get. 456// * @param len: number of byte of anthropy to get.
251// * @retval None 457// * @retval None
252// */ 458// */
253// void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len) 459#[unsafe(no_mangle)]
254// { 460pub unsafe extern "C" fn LINKLAYER_PLAT_GetRNG(ptr_rnd: *mut u8, len: u32) {
255// uint32_t nb_remaining_rng = len; 461 // uint32_t nb_remaining_rng = len;
256// uint32_t generated_rng; 462 // uint32_t generated_rng;
257// 463 //
258// /* Get the requested RNGs (4 bytes by 4bytes) */ 464 // /* Get the requested RNGs (4 bytes by 4bytes) */
259// while(nb_remaining_rng >= 4) 465 // while(nb_remaining_rng >= 4)
260// { 466 // {
261// generated_rng = 0; 467 // generated_rng = 0;
262// HW_RNG_Get(1, &generated_rng); 468 // HW_RNG_Get(1, &generated_rng);
263// memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, 4); 469 // memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, 4);
264// nb_remaining_rng -=4; 470 // nb_remaining_rng -=4;
265// } 471 // }
266// 472 //
267// /* Get the remaining number of RNGs */ 473 // /* Get the remaining number of RNGs */
268// if(nb_remaining_rng>0){ 474 // if(nb_remaining_rng>0){
269// generated_rng = 0; 475 // generated_rng = 0;
270// HW_RNG_Get(1, &generated_rng); 476 // HW_RNG_Get(1, &generated_rng);
271// memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, nb_remaining_rng); 477 // memcpy((ptr_rnd+(len-nb_remaining_rng)), &generated_rng, nb_remaining_rng);
272// } 478 // }
273// } 479 trace!("LINKLAYER_PLAT_GetRNG: ptr_rnd={:?}, len={}", ptr_rnd, len);
274// 480 if ptr_rnd.is_null() || len == 0 {
481 return;
482 }
483
484 for i in 0..len {
485 let byte = (prng_next() >> ((i & 3) * 8)) as u8;
486 ptr::write_volatile(ptr_rnd.add(i as usize), byte);
487 }
488}
489
275// /** 490// /**
276// * @brief Initialize Link Layer radio high priority interrupt. 491// * @brief Initialize Link Layer radio high priority interrupt.
277// * @param intr_cb: function pointer to assign for the radio high priority ISR routine. 492// * @param intr_cb: function pointer to assign for the radio high priority ISR routine.
278// * @retval None 493// * @retval None
279// */ 494// */
280// void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)()) 495#[unsafe(no_mangle)]
281// { 496pub unsafe extern "C" fn LINKLAYER_PLAT_SetupRadioIT(intr_cb: Option<Callback>) {
282// radio_callback = intr_cb; 497 trace!("LINKLAYER_PLAT_SetupRadioIT: intr_cb={:?}", intr_cb);
283// HAL_NVIC_SetPriority((IRQn_Type) RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH, 0); 498 store_callback(&RADIO_CALLBACK, intr_cb);
284// HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_INTR_NUM); 499
285// } 500 if intr_cb.is_some() {
286// 501 nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_HIGH));
502 nvic_enable(mac::RADIO_INTR_NUM);
503 } else {
504 nvic_disable(mac::RADIO_INTR_NUM);
505 }
506}
507
287// /** 508// /**
288// * @brief Initialize Link Layer SW low priority interrupt. 509// * @brief Initialize Link Layer SW low priority interrupt.
289// * @param intr_cb: function pointer to assign for the SW low priority ISR routine. 510// * @param intr_cb: function pointer to assign for the SW low priority ISR routine.
290// * @retval None 511// * @retval None
291// */ 512// */
292// void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)()) 513#[unsafe(no_mangle)]
293// { 514pub unsafe extern "C" fn LINKLAYER_PLAT_SetupSwLowIT(intr_cb: Option<Callback>) {
294// low_isr_callback = intr_cb; 515 trace!("LINKLAYER_PLAT_SetupSwLowIT: intr_cb={:?}", intr_cb);
295// 516 store_callback(&LOW_ISR_CALLBACK, intr_cb);
296// HAL_NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO, 0); 517
297// HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_SW_LOW_INTR_NUM); 518 if intr_cb.is_some() {
298// } 519 nvic_set_priority(RADIO_SW_LOW_INTR_NUM, pack_priority(mac::RADIO_SW_LOW_INTR_PRIO));
299// 520 nvic_enable(RADIO_SW_LOW_INTR_NUM);
521 } else {
522 nvic_disable(RADIO_SW_LOW_INTR_NUM);
523 }
524}
525
300// /** 526// /**
301// * @brief Trigger the link layer SW low interrupt. 527// * @brief Trigger the link layer SW low interrupt.
302// * @param None 528// * @param None
303// * @retval None 529// * @retval None
304// */ 530// */
305// void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority) 531#[unsafe(no_mangle)]
306// { 532pub unsafe extern "C" fn LINKLAYER_PLAT_TriggerSwLowIT(priority: u8) {
307// uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW; 533 trace!("LINKLAYER_PLAT_TriggerSwLowIT: priority={}", priority);
308// 534 let active = nvic_get_active(RADIO_SW_LOW_INTR_NUM);
309// /* Check if a SW low interrupt as already been raised. 535
310// * Nested call far radio low isr are not supported 536 // /* Check if a SW low interrupt as already been raised.
311// **/ 537 // * Nested call far radio low isr are not supported
312// 538 // **/
313// if(NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0) 539 if !active {
314// { 540 let prio = if priority == 0 {
315// /* No nested SW low ISR, default behavior */ 541 // /* No nested SW low ISR, default behavior */
316// 542 pack_priority(mac::RADIO_SW_LOW_INTR_PRIO)
317// if(priority == 0) 543 } else {
318// { 544 pack_priority(mac::RADIO_INTR_PRIO_LOW)
319// low_isr_priority = RADIO_SW_LOW_INTR_PRIO; 545 };
320// } 546 nvic_set_priority(RADIO_SW_LOW_INTR_NUM, prio);
321// 547 } else if priority != 0 {
322// HAL_NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, low_isr_priority, 0); 548 // /* Nested call detected */
323// } 549 // /* No change for SW radio low interrupt priority for the moment */
324// else 550 //
325// { 551 // if(priority != 0)
326// /* Nested call detected */ 552 // {
327// /* No change for SW radio low interrupt priority for the moment */ 553 // /* At the end of current SW radio low ISR, this pending SW low interrupt
328// 554 // * will run with RADIO_INTR_PRIO_LOW priority
329// if(priority != 0) 555 // **/
330// { 556 // radio_sw_low_isr_is_running_high_prio = 1;
331// /* At the end of current SW radio low ISR, this pending SW low interrupt 557 // }
332// * will run with RADIO_INTR_PRIO_LOW priority 558 RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO.store(true, Ordering::Release);
333// **/ 559 }
334// radio_sw_low_isr_is_running_high_prio = 1; 560
335// } 561 nvic_set_pending(RADIO_SW_LOW_INTR_NUM);
336// } 562}
337// 563
338// HAL_NVIC_SetPendingIRQ((IRQn_Type) RADIO_SW_LOW_INTR_NUM);
339// }
340//
341// /** 564// /**
342// * @brief Enable interrupts. 565// * @brief Enable interrupts.
343// * @param None 566// * @param None
344// * @retval None 567// * @retval None
345// */ 568// */
346// void LINKLAYER_PLAT_EnableIRQ(void) 569#[unsafe(no_mangle)]
347// { 570pub unsafe extern "C" fn LINKLAYER_PLAT_EnableIRQ() {
348// irq_counter = max(0,irq_counter-1); 571 trace!("LINKLAYER_PLAT_EnableIRQ");
349// 572 // irq_counter = max(0,irq_counter-1);
350// if(irq_counter == 0) 573 //
351// { 574 // if(irq_counter == 0)
352// /* When irq_counter reaches 0, restore primask bit */ 575 // {
353// __set_PRIMASK(primask_bit); 576 // /* When irq_counter reaches 0, restore primask bit */
354// } 577 // __set_PRIMASK(primask_bit);
355// } 578 // }
356// 579 if counter_release(&IRQ_COUNTER) {
580 // When the counter reaches zero, restore prior interrupt state using the captured token.
581 if let Some(token) = CS_RESTORE_STATE.take() {
582 critical_section::release(token);
583 }
584 }
585}
586
357// /** 587// /**
358// * @brief Disable interrupts. 588// * @brief Disable interrupts.
359// * @param None 589// * @param None
360// * @retval None 590// * @retval None
361// */ 591// */
362// void LINKLAYER_PLAT_DisableIRQ(void) 592#[unsafe(no_mangle)]
363// { 593pub unsafe extern "C" fn LINKLAYER_PLAT_DisableIRQ() {
364// if(irq_counter == 0) 594 trace!("LINKLAYER_PLAT_DisableIRQ");
365// { 595 // if(irq_counter == 0)
366// /* Save primask bit at first interrupt disablement */ 596 // {
367// primask_bit= __get_PRIMASK(); 597 // /* Save primask bit at first interrupt disablement */
368// } 598 // primask_bit= __get_PRIMASK();
369// __disable_irq(); 599 // }
370// irq_counter ++; 600 // __disable_irq();
371// } 601 // irq_counter ++;
372// 602 if counter_acquire(&IRQ_COUNTER) {
603 // Capture and disable using critical-section API on first disable.
604 CS_RESTORE_STATE = Some(critical_section::acquire());
605 }
606}
607
373// /** 608// /**
374// * @brief Enable specific interrupt group. 609// * @brief Enable specific interrupt group.
375// * @param isr_type: mask for interrupt group to enable. 610// * @param isr_type: mask for interrupt group to enable.
@@ -380,43 +615,62 @@ fn test_fn() {}
380// * lower priority that link layer SW low interrupt. 615// * lower priority that link layer SW low interrupt.
381// * @retval None 616// * @retval None
382// */ 617// */
383// void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type) 618#[unsafe(no_mangle)]
384// { 619pub unsafe extern "C" fn LINKLAYER_PLAT_EnableSpecificIRQ(isr_type: u8) {
385// if( (isr_type & LL_HIGH_ISR_ONLY) != 0 ) 620 trace!("LINKLAYER_PLAT_EnableSpecificIRQ: isr_type={}", isr_type);
386// { 621 // if( (isr_type & LL_HIGH_ISR_ONLY) != 0 )
387// prio_high_isr_counter--; 622 // {
388// if(prio_high_isr_counter == 0) 623 // prio_high_isr_counter--;
389// { 624 // if(prio_high_isr_counter == 0)
390// /* When specific counter for link layer high ISR reaches 0, interrupt is enabled */ 625 // {
391// HAL_NVIC_EnableIRQ(RADIO_INTR_NUM); 626 // /* When specific counter for link layer high ISR reaches 0, interrupt is enabled */
392// /* USER CODE BEGIN LINKLAYER_PLAT_EnableSpecificIRQ_1 */ 627 // HAL_NVIC_EnableIRQ(RADIO_INTR_NUM);
393// 628 // /* USER CODE BEGIN LINKLAYER_PLAT_EnableSpecificIRQ_1 */
394// /* USER CODE END LINKLAYER_PLAT_EnableSpecificIRQ_1 */ 629 //
395// } 630 // /* USER CODE END LINKLAYER_PLAT_EnableSpecificIRQ_1 */
396// } 631 // }
397// 632 // }
398// if( (isr_type & LL_LOW_ISR_ONLY) != 0 ) 633 //
399// { 634 // if( (isr_type & LL_LOW_ISR_ONLY) != 0 )
400// prio_low_isr_counter--; 635 // {
401// if(prio_low_isr_counter == 0) 636 // prio_low_isr_counter--;
402// { 637 // if(prio_low_isr_counter == 0)
403// /* When specific counter for link layer SW low ISR reaches 0, interrupt is enabled */ 638 // {
404// HAL_NVIC_EnableIRQ(RADIO_SW_LOW_INTR_NUM); 639 // /* When specific counter for link layer SW low ISR reaches 0, interrupt is enabled */
405// } 640 // HAL_NVIC_EnableIRQ(RADIO_SW_LOW_INTR_NUM);
406// 641 // }
407// } 642 //
408// 643 // }
409// if( (isr_type & SYS_LOW_ISR) != 0 ) 644 //
410// { 645 // if( (isr_type & SYS_LOW_ISR) != 0 )
411// prio_sys_isr_counter--; 646 // {
412// if(prio_sys_isr_counter == 0) 647 // prio_sys_isr_counter--;
413// { 648 // if(prio_sys_isr_counter == 0)
414// /* Restore basepri value */ 649 // {
415// __set_BASEPRI(local_basepri_value); 650 // /* Restore basepri value */
416// } 651 // __set_BASEPRI(local_basepri_value);
417// } 652 // }
418// } 653 // }
419// 654 if (isr_type & link_layer::LL_HIGH_ISR_ONLY as u8) != 0 {
655 if counter_release(&PRIO_HIGH_ISR_COUNTER) {
656 nvic_enable(mac::RADIO_INTR_NUM);
657 }
658 }
659
660 if (isr_type & link_layer::LL_LOW_ISR_ONLY as u8) != 0 {
661 if counter_release(&PRIO_LOW_ISR_COUNTER) {
662 nvic_enable(RADIO_SW_LOW_INTR_NUM);
663 }
664 }
665
666 if (isr_type & link_layer::SYS_LOW_ISR as u8) != 0 {
667 if counter_release(&PRIO_SYS_ISR_COUNTER) {
668 let stored = LOCAL_BASEPRI_VALUE.load(Ordering::Relaxed) as u8;
669 basepri::write(stored);
670 }
671 }
672}
673
420// /** 674// /**
421// * @brief Disable specific interrupt group. 675// * @brief Disable specific interrupt group.
422// * @param isr_type: mask for interrupt group to disable. 676// * @param isr_type: mask for interrupt group to disable.
@@ -427,219 +681,240 @@ fn test_fn() {}
427// * lower priority that link layer SW low interrupt. 681// * lower priority that link layer SW low interrupt.
428// * @retval None 682// * @retval None
429// */ 683// */
430// void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type) 684#[unsafe(no_mangle)]
431// { 685pub unsafe extern "C" fn LINKLAYER_PLAT_DisableSpecificIRQ(isr_type: u8) {
432// if( (isr_type & LL_HIGH_ISR_ONLY) != 0 ) 686 // if( (isr_type & LL_HIGH_ISR_ONLY) != 0 )
433// { 687 // {
434// prio_high_isr_counter++; 688 // prio_high_isr_counter++;
435// if(prio_high_isr_counter == 1) 689 // if(prio_high_isr_counter == 1)
436// { 690 // {
437// /* USER CODE BEGIN LINKLAYER_PLAT_DisableSpecificIRQ_1 */ 691 // /* USER CODE BEGIN LINKLAYER_PLAT_DisableSpecificIRQ_1 */
438// 692 //
439// /* USER CODE END LINKLAYER_PLAT_DisableSpecificIRQ_1 */ 693 // /* USER CODE END LINKLAYER_PLAT_DisableSpecificIRQ_1 */
440// /* When specific counter for link layer high ISR value is 1, interrupt is disabled */ 694 // /* When specific counter for link layer high ISR value is 1, interrupt is disabled */
441// HAL_NVIC_DisableIRQ(RADIO_INTR_NUM); 695 // HAL_NVIC_DisableIRQ(RADIO_INTR_NUM);
442// } 696 // }
443// } 697 // }
444// 698 //
445// if( (isr_type & LL_LOW_ISR_ONLY) != 0 ) 699 // if( (isr_type & LL_LOW_ISR_ONLY) != 0 )
446// { 700 // {
447// prio_low_isr_counter++; 701 // prio_low_isr_counter++;
448// if(prio_low_isr_counter == 1) 702 // if(prio_low_isr_counter == 1)
449// { 703 // {
450// /* When specific counter for link layer SW low ISR value is 1, interrupt is disabled */ 704 // /* When specific counter for link layer SW low ISR value is 1, interrupt is disabled */
451// HAL_NVIC_DisableIRQ(RADIO_SW_LOW_INTR_NUM); 705 // HAL_NVIC_DisableIRQ(RADIO_SW_LOW_INTR_NUM);
452// } 706 // }
453// } 707 // }
454// 708 //
455// if( (isr_type & SYS_LOW_ISR) != 0 ) 709 // if( (isr_type & SYS_LOW_ISR) != 0 )
456// { 710 // {
457// prio_sys_isr_counter++; 711 // prio_sys_isr_counter++;
458// if(prio_sys_isr_counter == 1) 712 // if(prio_sys_isr_counter == 1)
459// { 713 // {
460// /* Save basepri register value */ 714 // /* Save basepri register value */
461// local_basepri_value = __get_BASEPRI(); 715 // local_basepri_value = __get_BASEPRI();
462// 716 //
463// /* Mask all other interrupts with lower priority that link layer SW low ISR */ 717 // /* Mask all other interrupts with lower priority that link layer SW low ISR */
464// __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW<<4); 718 // __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW<<4);
465// } 719 // }
466// } 720 // }
467// } 721 trace!("LINKLAYER_PLAT_DisableSpecificIRQ: isr_type={}", isr_type);
468// 722 if (isr_type & link_layer::LL_HIGH_ISR_ONLY as u8) != 0 {
723 if counter_acquire(&PRIO_HIGH_ISR_COUNTER) {
724 nvic_disable(mac::RADIO_INTR_NUM);
725 }
726 }
727
728 if (isr_type & link_layer::LL_LOW_ISR_ONLY as u8) != 0 {
729 if counter_acquire(&PRIO_LOW_ISR_COUNTER) {
730 nvic_disable(RADIO_SW_LOW_INTR_NUM);
731 }
732 }
733
734 if (isr_type & link_layer::SYS_LOW_ISR as u8) != 0 {
735 if counter_acquire(&PRIO_SYS_ISR_COUNTER) {
736 let current = basepri::read();
737 LOCAL_BASEPRI_VALUE.store(current.into(), Ordering::Relaxed);
738 set_basepri_max(pack_priority(mac::RADIO_INTR_PRIO_LOW));
739 }
740 }
741}
742
469// /** 743// /**
470// * @brief Enable link layer high priority ISR only. 744// * @brief Enable link layer high priority ISR only.
471// * @param None 745// * @param None
472// * @retval None 746// * @retval None
473// */ 747// */
474// void LINKLAYER_PLAT_EnableRadioIT(void) 748#[unsafe(no_mangle)]
475// { 749pub unsafe extern "C" fn LINKLAYER_PLAT_EnableRadioIT() {
476// /* USER CODE BEGIN LINKLAYER_PLAT_EnableRadioIT_1 */ 750 trace!("LINKLAYER_PLAT_EnableRadioIT");
477// 751 nvic_enable(mac::RADIO_INTR_NUM);
478// /* USER CODE END LINKLAYER_PLAT_EnableRadioIT_1 */ 752}
479// 753
480// HAL_NVIC_EnableIRQ((IRQn_Type) RADIO_INTR_NUM);
481//
482// /* USER CODE BEGIN LINKLAYER_PLAT_EnableRadioIT_2 */
483//
484// /* USER CODE END LINKLAYER_PLAT_EnableRadioIT_2 */
485// }
486//
487// /** 754// /**
488// * @brief Disable link layer high priority ISR only. 755// * @brief Disable link layer high priority ISR only.
489// * @param None 756// * @param None
490// * @retval None 757// * @retval None
491// */ 758// */
492// void LINKLAYER_PLAT_DisableRadioIT(void) 759#[unsafe(no_mangle)]
493// { 760pub unsafe extern "C" fn LINKLAYER_PLAT_DisableRadioIT() {
494// /* USER CODE BEGIN LINKLAYER_PLAT_DisableRadioIT_1 */ 761 trace!("LINKLAYER_PLAT_DisableRadioIT");
495// 762 nvic_disable(mac::RADIO_INTR_NUM);
496// /* USER CODE END LINKLAYER_PLAT_DisableRadioIT_1 */ 763}
497// 764
498// HAL_NVIC_DisableIRQ((IRQn_Type) RADIO_INTR_NUM);
499//
500// /* USER CODE BEGIN LINKLAYER_PLAT_DisableRadioIT_2 */
501//
502// /* USER CODE END LINKLAYER_PLAT_DisableRadioIT_2 */
503// }
504//
505// /** 765// /**
506// * @brief Link Layer notification for radio activity start. 766// * @brief Link Layer notification for radio activity start.
507// * @param None 767// * @param None
508// * @retval None 768// * @retval None
509// */ 769// */
510// void LINKLAYER_PLAT_StartRadioEvt(void) 770#[unsafe(no_mangle)]
511// { 771pub unsafe extern "C" fn LINKLAYER_PLAT_StartRadioEvt() {
512// __HAL_RCC_RADIO_CLK_SLEEP_ENABLE(); 772 trace!("LINKLAYER_PLAT_StartRadioEvt");
513// NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH); 773 // __HAL_RCC_RADIO_CLK_SLEEP_ENABLE();
514// #if (CFG_SCM_SUPPORTED == 1) 774 // NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH);
515// scm_notifyradiostate(SCM_RADIO_ACTIVE); 775 // #if (CFG_SCM_SUPPORTED == 1)
516// #endif /* CFG_SCM_SUPPORTED */ 776 // scm_notifyradiostate(SCM_RADIO_ACTIVE);
517// } 777 // #endif /* CFG_SCM_SUPPORTED */
518// 778 nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_HIGH));
779 nvic_enable(mac::RADIO_INTR_NUM);
780}
781
519// /** 782// /**
520// * @brief Link Layer notification for radio activity end. 783// * @brief Link Layer notification for radio activity end.
521// * @param None 784// * @param None
522// * @retval None 785// * @retval None
523// */ 786// */
524// void LINKLAYER_PLAT_StopRadioEvt(void) 787#[unsafe(no_mangle)]
525// { 788pub unsafe extern "C" fn LINKLAYER_PLAT_StopRadioEvt() {
526// __HAL_RCC_RADIO_CLK_SLEEP_DISABLE(); 789 trace!("LINKLAYER_PLAT_StopRadioEvt");
527// NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW); 790 // {
528// #if (CFG_SCM_SUPPORTED == 1) 791 // __HAL_RCC_RADIO_CLK_SLEEP_DISABLE();
529// scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE); 792 // NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW);
530// #endif /* CFG_SCM_SUPPORTED */ 793 // #if (CFG_SCM_SUPPORTED == 1)
531// } 794 // scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE);
532// 795 // #endif /* CFG_SCM_SUPPORTED */
796 nvic_set_priority(mac::RADIO_INTR_NUM, pack_priority(mac::RADIO_INTR_PRIO_LOW));
797}
798
533// /** 799// /**
534// * @brief Link Layer notification for RCO calibration start. 800// * @brief Link Layer notification for RCO calibration start.
535// * @param None 801// * @param None
536// * @retval None 802// * @retval None
537// */ 803// */
538// void LINKLAYER_PLAT_RCOStartClbr(void) 804#[unsafe(no_mangle)]
539// { 805pub unsafe extern "C" fn LINKLAYER_PLAT_RCOStartClbr() {
540// #if (CFG_LPM_LEVEL != 0) 806 trace!("LINKLAYER_PLAT_RCOStartClbr");
541// PWR_DisableSleepMode(); 807 // #if (CFG_LPM_LEVEL != 0)
542// /* Disabling stop mode prevents also from entering in standby */ 808 // PWR_DisableSleepMode();
543// UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_DISABLE); 809 // /* Disabling stop mode prevents also from entering in standby */
544// #endif /* (CFG_LPM_LEVEL != 0) */ 810 // UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_DISABLE);
545// #if (CFG_SCM_SUPPORTED == 1) 811 // #endif /* (CFG_LPM_LEVEL != 0) */
546// scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_32MHZ); 812 // #if (CFG_SCM_SUPPORTED == 1)
547// while (LL_PWR_IsActiveFlag_VOS() == 0); 813 // scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_32MHZ);
548// #endif /* (CFG_SCM_SUPPORTED == 1) */ 814 // while (LL_PWR_IsActiveFlag_VOS() == 0);
549// } 815 // #endif /* (CFG_SCM_SUPPORTED == 1) */
550// 816}
817
551// /** 818// /**
552// * @brief Link Layer notification for RCO calibration end. 819// * @brief Link Layer notification for RCO calibration end.
553// * @param None 820// * @param None
554// * @retval None 821// * @retval None
555// */ 822// */
556// void LINKLAYER_PLAT_RCOStopClbr(void) 823#[unsafe(no_mangle)]
557// { 824pub unsafe extern "C" fn LINKLAYER_PLAT_RCOStopClbr() {
558// #if (CFG_LPM_LEVEL != 0) 825 trace!("LINKLAYER_PLAT_RCOStopClbr");
559// PWR_EnableSleepMode(); 826 // #if (CFG_LPM_LEVEL != 0)
560// UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_ENABLE); 827 // PWR_EnableSleepMode();
561// #endif /* (CFG_LPM_LEVEL != 0) */ 828 // UTIL_LPM_SetStopMode(1U << CFG_LPM_LL_HW_RCO_CLBR, UTIL_LPM_ENABLE);
562// #if (CFG_SCM_SUPPORTED == 1) 829 // #endif /* (CFG_LPM_LEVEL != 0) */
563// scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_16MHZ); 830 // #if (CFG_SCM_SUPPORTED == 1)
564// #endif /* (CFG_SCM_SUPPORTED == 1) */ 831 // scm_setsystemclock(SCM_USER_LL_HW_RCO_CLBR, HSE_16MHZ);
565// } 832 // #endif /* (CFG_SCM_SUPPORTED == 1) */
566// 833}
834
567// /** 835// /**
568// * @brief Link Layer requests temperature. 836// * @brief Link Layer requests temperature.
569// * @param None 837// * @param None
570// * @retval None 838// * @retval None
571// */ 839// */
572// void LINKLAYER_PLAT_RequestTemperature(void) 840#[unsafe(no_mangle)]
573// { 841pub unsafe extern "C" fn LINKLAYER_PLAT_RequestTemperature() {
574// #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1) 842 trace!("LINKLAYER_PLAT_RequestTemperature");
575// ll_sys_bg_temperature_measurement(); 843 // #if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1)
576// #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */ 844 // ll_sys_bg_temperature_measurement();
577// } 845 // #endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */
578// 846}
847
579// /** 848// /**
580// * @brief PHY Start calibration. 849// * @brief PHY Start calibration.
581// * @param None 850// * @param None
582// * @retval None 851// * @retval None
583// */ 852// */
584// void LINKLAYER_PLAT_PhyStartClbr(void) 853#[unsafe(no_mangle)]
585// { 854pub unsafe extern "C" fn LINKLAYER_PLAT_PhyStartClbr() {
586// /* USER CODE BEGIN LINKLAYER_PLAT_PhyStartClbr_0 */ 855 trace!("LINKLAYER_PLAT_PhyStartClbr");
587// 856}
588// /* USER CODE END LINKLAYER_PLAT_PhyStartClbr_0 */ 857
589//
590// /* USER CODE BEGIN LINKLAYER_PLAT_PhyStartClbr_1 */
591//
592// /* USER CODE END LINKLAYER_PLAT_PhyStartClbr_1 */
593// }
594//
595// /** 858// /**
596// * @brief PHY Stop calibration. 859// * @brief PHY Stop calibration.
597// * @param None 860// * @param None
598// * @retval None 861// * @retval None
599// */ 862// */
600// void LINKLAYER_PLAT_PhyStopClbr(void) 863#[unsafe(no_mangle)]
601// { 864pub unsafe extern "C" fn LINKLAYER_PLAT_PhyStopClbr() {
602// /* USER CODE BEGIN LINKLAYER_PLAT_PhyStopClbr_0 */ 865 trace!("LINKLAYER_PLAT_PhyStopClbr");
603// 866}
604// /* USER CODE END LINKLAYER_PLAT_PhyStopClbr_0 */ 867
605//
606// /* USER CODE BEGIN LINKLAYER_PLAT_PhyStopClbr_1 */
607//
608// /* USER CODE END LINKLAYER_PLAT_PhyStopClbr_1 */
609// }
610//
611// /** 868// /**
612// * @brief Notify the upper layer that new Link Layer timings have been applied. 869// * @brief Notify the upper layer that new Link Layer timings have been applied.
613// * @param evnt_timing[in]: Evnt_timing_t pointer to structure contains drift time , execution time and scheduling time 870// * @param evnt_timing[in]: Evnt_timing_t pointer to structure contains drift time , execution time and scheduling time
614// * @retval None. 871// * @retval None.
615// */ 872// */
616// void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t * p_evnt_timing) 873#[unsafe(no_mangle)]
617// { 874pub unsafe extern "C" fn LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(_timings: *const link_layer::Evnt_timing_t) {
618// /* USER CODE BEGIN LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT_0 */ 875 trace!("LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT: timings={:?}", _timings);
619// 876}
620// /* USER CODE END LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT_0 */ 877
621// }
622//
623// /** 878// /**
624// * @brief Get the ST company ID. 879// * @brief Get the ST company ID.
625// * @param None 880// * @param None
626// * @retval Company ID 881// * @retval Company ID
627// */ 882// */
628// uint32_t LINKLAYER_PLAT_GetSTCompanyID(void) 883#[unsafe(no_mangle)]
629// { 884pub unsafe extern "C" fn LINKLAYER_PLAT_GetSTCompanyID() -> u32 {
630// return LL_FLASH_GetSTCompanyID(); 885 trace!("LINKLAYER_PLAT_GetSTCompanyID");
631// } 886 // STMicroelectronics Bluetooth SIG Company Identifier
632// 887 // TODO: Pull in update from latest stm32-generated-data
888 0x0030
889}
890
633// /** 891// /**
634// * @brief Get the Unique Device Number (UDN). 892// * @brief Get the Unique Device Number (UDN).
635// * @param None 893// * @param None
636// * @retval UDN 894// * @retval UDN
637// */ 895// */
638// uint32_t LINKLAYER_PLAT_GetUDN(void) 896#[unsafe(no_mangle)]
639// { 897pub unsafe extern "C" fn LINKLAYER_PLAT_GetUDN() -> u32 {
640// return LL_FLASH_GetUDN(); 898 trace!("LINKLAYER_PLAT_GetUDN");
641// } 899 // Read the first 32 bits of the STM32 unique 96-bit ID
642// 900 let uid = embassy_stm32::uid::uid();
643// /* USER CODE BEGIN LINKLAYER_PLAT 0 */ 901 u32::from_le_bytes([uid[0], uid[1], uid[2], uid[3]])
644// 902}
645// /* USER CODE END LINKLAYER_PLAT 0 */ 903
904#[unsafe(no_mangle)]
905pub unsafe extern "C" fn LINKLAYER_DEBUG_SIGNAL_SET() {
906 trace!("LINKLAYER_DEBUG_SIGNAL_SET");
907 todo!()
908}
909
910#[unsafe(no_mangle)]
911pub unsafe extern "C" fn LINKLAYER_DEBUG_SIGNAL_RESET() {
912 trace!("LINKLAYER_DEBUG_SIGNAL_RESET");
913 todo!()
914}
915
916#[unsafe(no_mangle)]
917pub unsafe extern "C" fn LINKLAYER_DEBUG_SIGNAL_TOGGLE() {
918 trace!("LINKLAYER_DEBUG_SIGNAL_TOGGLE");
919 todo!()
920}
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 38f22b1c3..ae2c0168b 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9- Add `receive_waveform` method in `InputCapture`, allowing asynchronous input capture with DMA.
9 10
10- fix: stm32: GPDMA driver reset ignored during channel configuration 11- fix: stm32: GPDMA driver reset ignored during channel configuration
11- fix: stm32: SPI driver SSOE and SSM manegment, add `nss_output_disable` to SPI Config 12- fix: stm32: SPI driver SSOE and SSM manegment, add `nss_output_disable` to SPI Config
@@ -72,6 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
72- low-power: update rtc api to allow reconfig 73- low-power: update rtc api to allow reconfig
73- adc: consolidate ringbuffer 74- adc: consolidate ringbuffer
74- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716)) 75- feat: Added RTC low-power support for STM32WLEx ([#4716](https://github.com/embassy-rs/embassy/pull/4716))
76- feat: Added low-power support for STM32WL5x ([#5108](https://github.com/embassy-rs/embassy/pull/5108))
75- fix: Correct STM32WBA VREFBUFTRIM values 77- fix: Correct STM32WBA VREFBUFTRIM values
76- low_power: remove stop_with rtc and initialize in init if low-power feature enabled. 78- low_power: remove stop_with rtc and initialize in init if low-power feature enabled.
77- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847)) 79- feat: stm32/dsi support zero parameter commands in `write_cmd` ([#4847](https://github.com/embassy-rs/embassy/pull/4847))
@@ -93,6 +95,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
93- stm32: Add blocking_listen for blocking I2C driver 95- stm32: Add blocking_listen for blocking I2C driver
94- fix: stm32l47*/stm32l48* adc analog pin setup 96- fix: stm32l47*/stm32l48* adc analog pin setup
95- fix: keep stm32/sai: make NODIV independent of MCKDIV 97- fix: keep stm32/sai: make NODIV independent of MCKDIV
98- fix: Source system clock from MSIS before (de)configuring PLLs on STM32U5
99- feat: adc: allow DMA reads to loop through enabled channels
96 100
97## 0.4.0 - 2025-08-26 101## 0.4.0 - 2025-08-26
98 102
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 7989fc5d7..55eba2695 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -184,8 +184,8 @@ vcell = "0.1.3"
184nb = "1.0.0" 184nb = "1.0.0"
185stm32-fmc = "0.4.0" 185stm32-fmc = "0.4.0"
186cfg-if = "1.0.0" 186cfg-if = "1.0.0"
187embedded-io = { version = "0.6.0" } 187embedded-io = { version = "0.7.1" }
188embedded-io-async = { version = "0.6.1" } 188embedded-io-async = { version = "0.7.0" }
189chrono = { version = "^0.4", default-features = false, optional = true } 189chrono = { version = "^0.4", default-features = false, optional = true }
190bit_field = "0.10.2" 190bit_field = "0.10.2"
191trait-set = "0.3.0" 191trait-set = "0.3.0"
@@ -193,18 +193,20 @@ document-features = "0.2.7"
193 193
194static_assertions = { version = "1.1" } 194static_assertions = { version = "1.1" }
195volatile-register = { version = "0.2.1" } 195volatile-register = { version = "0.2.1" }
196bitflags = "2.4.2" 196bitflags = "2.10.0"
197 197
198block-device-driver = { version = "0.2" } 198block-device-driver = { version = "0.2" }
199aligned = "0.4.1" 199aligned = "0.4.1"
200heapless = "0.9.1" 200heapless = "0.9.1"
201 201
202#stm32-metapac = { version = "18" } 202#stm32-metapac = { version = "18" }
203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74" } 203stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c0123f4251e21282c3f26114d2f6f9360c1191f1" }
204#stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }
204 205
205[build-dependencies] 206[build-dependencies]
206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 207#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74", default-features = false, features = ["metadata"] } 208stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-c0123f4251e21282c3f26114d2f6f9360c1191f1", default-features = false, features = ["metadata"] }
209#stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] }
208 210
209proc-macro2 = "1.0.36" 211proc-macro2 = "1.0.36"
210quote = "1.0.15" 212quote = "1.0.15"
@@ -228,7 +230,7 @@ defmt = [
228 "embassy-sync/defmt", 230 "embassy-sync/defmt",
229 "embassy-embedded-hal/defmt", 231 "embassy-embedded-hal/defmt",
230 "embassy-hal-internal/defmt", 232 "embassy-hal-internal/defmt",
231 "embedded-io-async/defmt-03", 233 "embedded-io-async/defmt",
232 "embassy-usb-driver/defmt", 234 "embassy-usb-driver/defmt",
233 "embassy-net-driver/defmt", 235 "embassy-net-driver/defmt",
234 "embassy-time?/defmt", 236 "embassy-time?/defmt",
@@ -241,8 +243,9 @@ log = ["dep:log"]
241chrono = ["dep:chrono"] 243chrono = ["dep:chrono"]
242 244
243exti = [] 245exti = []
244low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 246low-power = [ "dep:embassy-executor", "time", "chrono" ]
245low-power-debug-with-sleep = [] 247low-power-pender = [ "low-power" ]
248low-power-debug-with-sleep = [ "low-power" ]
246 249
247## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/) 250## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/)
248memory-x = [] 251memory-x = []
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 46d6290e7..a3b863340 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -950,6 +950,60 @@ fn main() {
950 } 950 }
951 } 951 }
952 952
953 if kind == "gpio" {
954 for p in METADATA.peripherals {
955 // set all GPIOs to analog mode except for PA13 and PA14 which are SWDIO and SWDCLK
956 if p.registers.is_some()
957 && p.registers.as_ref().unwrap().kind == "gpio"
958 && p.registers.as_ref().unwrap().version != "v1"
959 {
960 let port = format_ident!("{}", p.name);
961 if p.name == "GPIOA" {
962 gg.extend(quote! {
963 // leave PA13 and PA14 as unchanged
964 crate::pac::#port.moder().modify(|w| {
965 w.set_moder(0, crate::pac::gpio::vals::Moder::ANALOG);
966 w.set_moder(1, crate::pac::gpio::vals::Moder::ANALOG);
967 w.set_moder(2, crate::pac::gpio::vals::Moder::ANALOG);
968 w.set_moder(3, crate::pac::gpio::vals::Moder::ANALOG);
969 w.set_moder(4, crate::pac::gpio::vals::Moder::ANALOG);
970 w.set_moder(5, crate::pac::gpio::vals::Moder::ANALOG);
971 w.set_moder(6, crate::pac::gpio::vals::Moder::ANALOG);
972 w.set_moder(7, crate::pac::gpio::vals::Moder::ANALOG);
973 w.set_moder(8, crate::pac::gpio::vals::Moder::ANALOG);
974 w.set_moder(9, crate::pac::gpio::vals::Moder::ANALOG);
975 w.set_moder(10, crate::pac::gpio::vals::Moder::ANALOG);
976 w.set_moder(11, crate::pac::gpio::vals::Moder::ANALOG);
977 w.set_moder(12, crate::pac::gpio::vals::Moder::ANALOG);
978 w.set_moder(15, crate::pac::gpio::vals::Moder::ANALOG);
979 });
980 });
981 } else {
982 gg.extend(quote! {
983 crate::pac::#port.moder().modify(|w| {
984 w.set_moder(0, crate::pac::gpio::vals::Moder::ANALOG);
985 w.set_moder(1, crate::pac::gpio::vals::Moder::ANALOG);
986 w.set_moder(2, crate::pac::gpio::vals::Moder::ANALOG);
987 w.set_moder(3, crate::pac::gpio::vals::Moder::ANALOG);
988 w.set_moder(4, crate::pac::gpio::vals::Moder::ANALOG);
989 w.set_moder(5, crate::pac::gpio::vals::Moder::ANALOG);
990 w.set_moder(6, crate::pac::gpio::vals::Moder::ANALOG);
991 w.set_moder(7, crate::pac::gpio::vals::Moder::ANALOG);
992 w.set_moder(8, crate::pac::gpio::vals::Moder::ANALOG);
993 w.set_moder(9, crate::pac::gpio::vals::Moder::ANALOG);
994 w.set_moder(10, crate::pac::gpio::vals::Moder::ANALOG);
995 w.set_moder(11, crate::pac::gpio::vals::Moder::ANALOG);
996 w.set_moder(12, crate::pac::gpio::vals::Moder::ANALOG);
997 w.set_moder(13, crate::pac::gpio::vals::Moder::ANALOG);
998 w.set_moder(14, crate::pac::gpio::vals::Moder::ANALOG);
999 w.set_moder(15, crate::pac::gpio::vals::Moder::ANALOG);
1000 });
1001 });
1002 }
1003 }
1004 }
1005 }
1006
953 let fname = format_ident!("init_{}", kind); 1007 let fname = format_ident!("init_{}", kind);
954 g.extend(quote! { 1008 g.extend(quote! {
955 pub unsafe fn #fname(){ 1009 pub unsafe fn #fname(){
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index da432f6ce..17b1dae77 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -214,7 +214,7 @@ impl<'d, T: Instance> Adc<'d, T> {
214 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] 214 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
215 /// Read one or multiple ADC regular channels using DMA. 215 /// Read one or multiple ADC regular channels using DMA.
216 /// 216 ///
217 /// `sequence` iterator and `readings` must have the same length. 217 /// `readings` must have a length that is a multiple of the length of the `sequence` iterator.
218 /// 218 ///
219 /// Example 219 /// Example
220 /// ```rust,ignore 220 /// ```rust,ignore
@@ -253,8 +253,8 @@ impl<'d, T: Instance> Adc<'d, T> {
253 ) { 253 ) {
254 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); 254 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
255 assert!( 255 assert!(
256 sequence.len() == readings.len(), 256 readings.len() % sequence.len() == 0,
257 "Sequence length must be equal to readings length" 257 "Readings length must be a multiple of sequence length"
258 ); 258 );
259 assert!( 259 assert!(
260 sequence.len() <= 16, 260 sequence.len() <= 16,
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index b5fa3c897..e5c68acbd 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -94,17 +94,14 @@ pub struct HardwareSemaphoreInterruptHandler<T: Instance> {
94impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> { 94impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> {
95 unsafe fn on_interrupt() { 95 unsafe fn on_interrupt() {
96 let core_id = CoreId::current(); 96 let core_id = CoreId::current();
97 let isr = T::regs().isr(core_id.to_index()).read();
97 98
98 for number in 0..5 { 99 for number in 0..5 {
99 if T::regs().isr(core_id.to_index()).read().isf(number as usize) { 100 if isr.isf(number as usize) {
100 T::regs() 101 T::regs()
101 .icr(core_id.to_index()) 102 .icr(core_id.to_index())
102 .write(|w| w.set_isc(number as usize, true)); 103 .write(|w| w.set_isc(number as usize, true));
103 104
104 T::regs()
105 .ier(core_id.to_index())
106 .modify(|w| w.set_ise(number as usize, false));
107
108 T::state().waker_for(number).wake(); 105 T::state().waker_for(number).wake();
109 } 106 }
110 } 107 }
@@ -120,6 +117,18 @@ pub struct HardwareSemaphoreMutex<'a, T: Instance> {
120 117
121impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> { 118impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> {
122 fn drop(&mut self) { 119 fn drop(&mut self) {
120 let core_id = CoreId::current();
121
122 T::regs()
123 .icr(core_id.to_index())
124 .write(|w| w.set_isc(self.index as usize, true));
125
126 critical_section::with(|_| {
127 T::regs()
128 .ier(core_id.to_index())
129 .modify(|w| w.set_ise(self.index as usize, false));
130 });
131
123 HardwareSemaphoreChannel::<'a, T> { 132 HardwareSemaphoreChannel::<'a, T> {
124 index: self.index, 133 index: self.index,
125 _lifetime: PhantomData, 134 _lifetime: PhantomData,
@@ -156,9 +165,11 @@ impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
156 165
157 compiler_fence(Ordering::SeqCst); 166 compiler_fence(Ordering::SeqCst);
158 167
159 T::regs() 168 critical_section::with(|_| {
160 .ier(core_id.to_index()) 169 T::regs()
161 .modify(|w| w.set_ise(self.index as usize, true)); 170 .ier(core_id.to_index())
171 .modify(|w| w.set_ise(self.index as usize, true));
172 });
162 173
163 match self.try_lock(process_id) { 174 match self.try_lock(process_id) {
164 Some(mutex) => Poll::Ready(mutex), 175 Some(mutex) => Poll::Ready(mutex),
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 0bf430ffc..0aa2d1da9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -129,7 +129,7 @@ impl<'d> Drop for I2CDropGuard<'d> {
129 x.set_as_disconnected() 129 x.set_as_disconnected()
130 } 130 }
131 131
132 self.info.rcc.disable(); 132 self.info.rcc.disable_without_stop();
133 } 133 }
134} 134}
135 135
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 2f783bf64..a0b2f045c 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -138,6 +138,9 @@ pub mod wdg;
138#[cfg(xspi)] 138#[cfg(xspi)]
139pub mod xspi; 139pub mod xspi;
140 140
141#[cfg(feature = "low-power")]
142pub use low_power::Executor;
143
141// This must go last, so that it sees all the impl_foo! macros defined earlier. 144// This must go last, so that it sees all the impl_foo! macros defined earlier.
142pub(crate) mod _generated { 145pub(crate) mod _generated {
143 #![allow(dead_code)] 146 #![allow(dead_code)]
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 2388abe3c..71befcf34 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -3,31 +3,31 @@
3//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating 3//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
4//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which 4//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
5//! can use knowledge of which peripherals are currently blocked upon to transparently and safely 5//! can use knowledge of which peripherals are currently blocked upon to transparently and safely
6//! enter such low-power modes (currently, only `STOP2`) when idle. 6//! enter such low-power modes including `STOP1` and `STOP2` when idle.
7//! 7//!
8//! The executor determines which peripherals are active by their RCC state; consequently, 8//! The executor determines which peripherals are active by their RCC state; consequently,
9//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few 9//! low-power states can only be entered if peripherals which block stop have been `drop`'d and if
10//! exceptions to this rule: 10//! peripherals that do not block stop are busy. Peripherals which never block stop include:
11//! 11//!
12//! * `GPIO` 12//! * `GPIO`
13//! * `RTC` 13//! * `RTC`
14//! 14//!
15//! Other peripherals which block stop when busy include (this list may be stale):
16//!
17//! * `I2C`
18//! * `USART`
19//!
15//! Since entering and leaving low-power modes typically incurs a significant latency, the 20//! Since entering and leaving low-power modes typically incurs a significant latency, the
16//! low-power executor will only attempt to enter when the next timer event is at least 21//! low-power executor will only attempt to enter when the next timer event is at least
17//! [`time_driver::min_stop_pause`] in the future. 22//! [`config.min_stop_pause`] in the future.
18//! 23//!
19//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
20//! consequently one must define their entrypoint manually. Moreover, you must relinquish control
21//! of the `RTC` peripheral to the executor. This will typically look like
22//! 24//!
23//! ```rust,no_run 25//! ```rust,no_run
24//! use embassy_executor::Spawner; 26//! use embassy_executor::Spawner;
25//! use embassy_stm32::low_power;
26//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27//! use embassy_time::Duration; 27//! use embassy_time::Duration;
28//! 28//!
29//! #[embassy_executor::main(executor = "low_power::Executor")] 29//! #[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
30//! async fn async_main(spawner: Spawner) { 30//! async fn main(spawner: Spawner) {
31//! // initialize the platform... 31//! // initialize the platform...
32//! let mut config = embassy_stm32::Config::default(); 32//! let mut config = embassy_stm32::Config::default();
33//! // the default value, but can be adjusted 33//! // the default value, but can be adjusted
@@ -43,7 +43,7 @@
43use core::arch::asm; 43use core::arch::asm;
44use core::marker::PhantomData; 44use core::marker::PhantomData;
45use core::mem; 45use core::mem;
46use core::sync::atomic::{Ordering, compiler_fence}; 46use core::sync::atomic::{AtomicBool, Ordering, compiler_fence};
47 47
48use cortex_m::peripheral::SCB; 48use cortex_m::peripheral::SCB;
49use critical_section::CriticalSection; 49use critical_section::CriticalSection;
@@ -56,7 +56,27 @@ use crate::time_driver::get_driver;
56 56
57const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
58 58
59static mut EXECUTOR_TAKEN: bool = false; 59static EXECUTOR_TAKEN: AtomicBool = AtomicBool::new(false);
60#[cfg(feature = "low-power-pender")]
61static TASKS_PENDING: AtomicBool = AtomicBool::new(false);
62
63#[cfg(feature = "low-power-pender")]
64#[unsafe(export_name = "__pender")]
65fn __pender(context: *mut ()) {
66 unsafe {
67 // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt
68 // request number given to `InterruptExecutor::start`.
69
70 let context = context as usize;
71
72 // Try to make Rust optimize the branching away if we only use thread mode.
73 if context == THREAD_PENDER {
74 TASKS_PENDING.store(true, Ordering::Release);
75 core::arch::asm!("sev");
76 return;
77 }
78 }
79}
60 80
61/// Prevent the device from going into the stop mode if held 81/// Prevent the device from going into the stop mode if held
62pub struct DeviceBusy { 82pub struct DeviceBusy {
@@ -116,17 +136,17 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
116 }) 136 })
117} 137}
118 138
119#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] 139#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wl, stm32u0))]
120use crate::pac::pwr::vals::Lpms; 140use crate::pac::pwr::vals::Lpms;
121 141
122#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))] 142#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wl, stm32u0))]
123impl Into<Lpms> for StopMode { 143impl Into<Lpms> for StopMode {
124 fn into(self) -> Lpms { 144 fn into(self) -> Lpms {
125 match self { 145 match self {
126 StopMode::Stop1 => Lpms::STOP1, 146 StopMode::Stop1 => Lpms::STOP1,
127 #[cfg(not(any(stm32wb, stm32wba)))] 147 #[cfg(not(stm32wba))]
128 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2, 148 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2,
129 #[cfg(any(stm32wb, stm32wba))] 149 #[cfg(stm32wba)]
130 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? 150 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
131 } 151 }
132 } 152 }
@@ -150,12 +170,10 @@ pub struct Executor {
150impl Executor { 170impl Executor {
151 /// Create a new Executor. 171 /// Create a new Executor.
152 pub fn new() -> Self { 172 pub fn new() -> Self {
153 unsafe { 173 if EXECUTOR_TAKEN.load(Ordering::Acquire) {
154 if EXECUTOR_TAKEN { 174 panic!("Low power executor can only be taken once.");
155 panic!("Low power executor can only be taken once."); 175 } else {
156 } else { 176 EXECUTOR_TAKEN.store(true, Ordering::Release);
157 EXECUTOR_TAKEN = true;
158 }
159 } 177 }
160 178
161 Self { 179 Self {
@@ -166,28 +184,61 @@ impl Executor {
166 184
167 pub(crate) unsafe fn on_wakeup_irq_or_event() { 185 pub(crate) unsafe fn on_wakeup_irq_or_event() {
168 if !get_driver().is_stopped() { 186 if !get_driver().is_stopped() {
187 trace!("low power: time driver not stopped!");
169 return; 188 return;
170 } 189 }
171 190
172 critical_section::with(|cs| { 191 critical_section::with(|cs| {
173 #[cfg(stm32wlex)] 192 #[cfg(any(stm32wl, stm32wb))]
174 { 193 {
175 let es = crate::pac::PWR.extscr().read(); 194 let es = crate::pac::PWR.extscr().read();
195 #[cfg(stm32wl)]
176 match (es.c1stopf(), es.c1stop2f()) { 196 match (es.c1stopf(), es.c1stop2f()) {
177 (true, false) => debug!("low power: wake from STOP1"), 197 (true, false) => debug!("low power: cpu1 wake from STOP1"),
178 (false, true) => debug!("low power: wake from STOP2"), 198 (false, true) => debug!("low power: cpu1 wake from STOP2"),
179 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), 199 (true, true) => debug!("low power: cpu1 wake from STOP1 and STOP2 ???"),
200 (false, false) => trace!("low power: cpu1 stop mode not entered"),
201 };
202 #[cfg(stm32wl5x)]
203 // TODO: only for the current cpu
204 match (es.c2stopf(), es.c2stop2f()) {
205 (true, false) => debug!("low power: cpu2 wake from STOP1"),
206 (false, true) => debug!("low power: cpu2 wake from STOP2"),
207 (true, true) => debug!("low power: cpu2 wake from STOP1 and STOP2 ???"),
208 (false, false) => trace!("low power: cpu2 stop mode not entered"),
209 };
210
211 #[cfg(stm32wb)]
212 match (es.c1stopf(), es.c2stopf()) {
213 (true, false) => debug!("low power: cpu1 wake from STOP"),
214 (false, true) => debug!("low power: cpu2 wake from STOP"),
215 (true, true) => debug!("low power: cpu1 and cpu2 wake from STOP"),
180 (false, false) => trace!("low power: stop mode not entered"), 216 (false, false) => trace!("low power: stop mode not entered"),
181 }; 217 };
182 crate::pac::PWR.extscr().modify(|w| {
183 w.set_c1cssf(false);
184 });
185 218
186 if es.c1stop2f() || es.c1stopf() { 219 let _has_stopped2 = {
220 #[cfg(stm32wb)]
221 {
222 es.c2stopf()
223 }
224
225 #[cfg(stm32wlex)]
226 {
227 es.c1stop2f()
228 }
229
230 #[cfg(stm32wl5x)]
231 {
232 // TODO: I think we could just use c1stop2f() here as it won't enter a stop mode unless BOTH cpus will enter it.
233 es.c1stop2f() | es.c2stop2f()
234 }
235 };
236
237 #[cfg(not(stm32wb))]
238 if es.c1stopf() || _has_stopped2 {
187 // when we wake from any stop mode we need to re-initialize the rcc 239 // when we wake from any stop mode we need to re-initialize the rcc
188 crate::rcc::init(RCC_CONFIG.unwrap()); 240 crate::rcc::init(RCC_CONFIG.unwrap());
189 241 if _has_stopped2 {
190 if es.c1stop2f() {
191 // when we wake from STOP2, we need to re-initialize the time driver 242 // when we wake from STOP2, we need to re-initialize the time driver
192 get_driver().init_timer(cs); 243 get_driver().init_timer(cs);
193 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer) 244 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
@@ -196,6 +247,13 @@ impl Executor {
196 REFCOUNT_STOP1 = 0; 247 REFCOUNT_STOP1 = 0;
197 } 248 }
198 } 249 }
250 // Clear all stop flags
251 #[cfg(stm32wl)]
252 crate::pac::PWR.extscr().modify(|w| {
253 w.set_c1cssf(true);
254 #[cfg(stm32wl5x)]
255 w.set_c2cssf(true);
256 });
199 } 257 }
200 get_driver().resume_time(cs); 258 get_driver().resume_time(cs);
201 259
@@ -276,6 +334,20 @@ impl Executor {
276 334
277 drop(sem3_mutex); 335 drop(sem3_mutex);
278 336
337 // on PWR
338 RCC.apb1enr1().modify(|r| r.0 |= 1 << 28);
339 cortex_m::asm::dsb();
340
341 // off SMPS, on Bypass
342 PWR.cr5().modify(|r| {
343 let mut val = r.0;
344 val &= !(1 << 15); // sdeb = 0 (off SMPS)
345 val |= 1 << 14; // sdben = 1 (on Bypass)
346 r.0 = val
347 });
348
349 cortex_m::asm::delay(1000);
350
279 Ok(()) 351 Ok(())
280 } 352 }
281 353
@@ -284,7 +356,7 @@ impl Executor {
284 #[cfg(all(stm32wb, feature = "low-power"))] 356 #[cfg(all(stm32wb, feature = "low-power"))]
285 self.configure_stop_stm32wb(_cs)?; 357 self.configure_stop_stm32wb(_cs)?;
286 358
287 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))] 359 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wl))]
288 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 360 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
289 #[cfg(stm32h5)] 361 #[cfg(stm32h5)]
290 crate::pac::PWR.pmcr().modify(|v| { 362 crate::pac::PWR.pmcr().modify(|v| {
@@ -299,12 +371,21 @@ impl Executor {
299 fn configure_pwr(&self) { 371 fn configure_pwr(&self) {
300 Self::get_scb().clear_sleepdeep(); 372 Self::get_scb().clear_sleepdeep();
301 // Clear any previous stop flags 373 // Clear any previous stop flags
302 #[cfg(stm32wlex)] 374 #[cfg(stm32wl)]
303 crate::pac::PWR.extscr().modify(|w| { 375 crate::pac::PWR.extscr().modify(|w| {
304 w.set_c1cssf(true); 376 w.set_c1cssf(true);
377 #[cfg(stm32wl5x)]
378 w.set_c2cssf(true);
305 }); 379 });
306 380
307 compiler_fence(Ordering::SeqCst); 381 #[cfg(feature = "low-power-pender")]
382 if TASKS_PENDING.load(Ordering::Acquire) {
383 TASKS_PENDING.store(false, Ordering::Release);
384
385 return;
386 }
387
388 compiler_fence(Ordering::Acquire);
308 389
309 critical_section::with(|cs| { 390 critical_section::with(|cs| {
310 let _ = unsafe { RCC_CONFIG }?; 391 let _ = unsafe { RCC_CONFIG }?;
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 99f22273d..7801078c3 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -185,6 +185,12 @@ pub(crate) unsafe fn init(config: Config) {
185 RCC.cr().modify(|w| w.set_hsion(false)); 185 RCC.cr().modify(|w| w.set_hsion(false));
186 } 186 }
187 187
188 // Disable the HSI48, if not used
189 #[cfg(crs)]
190 if config.hsi48.is_none() {
191 super::disable_hsi48();
192 }
193
188 config.mux.init(); 194 config.mux.init();
189 195
190 set_clocks!( 196 set_clocks!(
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 1155b6acd..92cf9fca7 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -480,6 +480,12 @@ pub(crate) unsafe fn init(config: Config) {
480 }; 480 };
481 */ 481 */
482 482
483 // Disable the HSI48, if not used
484 #[cfg(crs)]
485 if config.hsi48.is_none() {
486 super::disable_hsi48();
487 }
488
483 config.mux.init(); 489 config.mux.init();
484 490
485 set_clocks!( 491 set_clocks!(
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index ce6398afd..2665c20f9 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -294,6 +294,12 @@ pub(crate) unsafe fn init(config: Config) {
294 RCC.cr().modify(|w| w.set_hsion(false)); 294 RCC.cr().modify(|w| w.set_hsion(false));
295 } 295 }
296 296
297 // Disable the HSI48, if not used
298 #[cfg(crs)]
299 if config.hsi48.is_none() {
300 super::disable_hsi48();
301 }
302
297 if config.low_power_run { 303 if config.low_power_run {
298 assert!(sys <= Hertz(2_000_000)); 304 assert!(sys <= Hertz(2_000_000));
299 PWR.cr1().modify(|w| w.set_lpr(true)); 305 PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index da13e16aa..0dd3713c8 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -300,6 +300,12 @@ pub(crate) unsafe fn init(config: Config) {
300 RCC.cr().modify(|w| w.set_hsion(false)); 300 RCC.cr().modify(|w| w.set_hsion(false));
301 } 301 }
302 302
303 // Disable the HSI48, if not used
304 #[cfg(crs)]
305 if config.hsi48.is_none() {
306 super::disable_hsi48();
307 }
308
303 if config.low_power_run { 309 if config.low_power_run {
304 assert!(sys <= Hertz(2_000_000)); 310 assert!(sys <= Hertz(2_000_000));
305 PWR.cr1().modify(|w| w.set_lpr(true)); 311 PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 485edd390..2fe2a435c 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -671,6 +671,12 @@ pub(crate) unsafe fn init(config: Config) {
671 RCC.cr().modify(|w| w.set_hsion(false)); 671 RCC.cr().modify(|w| w.set_hsion(false));
672 } 672 }
673 673
674 // Disable the HSI48, if not used
675 #[cfg(crs)]
676 if config.hsi48.is_none() {
677 super::disable_hsi48();
678 }
679
674 // IO compensation cell - Requires CSI clock and SYSCFG 680 // IO compensation cell - Requires CSI clock and SYSCFG
675 #[cfg(any(stm32h7))] // TODO h5, h7rs 681 #[cfg(any(stm32h7))] // TODO h5, h7rs
676 if csi.is_some() { 682 if csi.is_some() {
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index 49be4af5e..50ac162a4 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -66,3 +66,24 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
66 66
67 HSI48_FREQ 67 HSI48_FREQ
68} 68}
69
70pub(crate) fn disable_hsi48() {
71 // disable CRS if it is enabled
72 rcc::disable::<crate::peripherals::CRS>();
73
74 // Disable HSI48
75 #[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0, stm32c071)))]
76 let r = RCC.crrcr();
77 #[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32c071))]
78 let r = RCC.cr();
79 #[cfg(any(stm32f0))]
80 let r = RCC.cr2();
81
82 r.modify(|w| w.set_hsi48on(false));
83
84 // Disable VREFINT reference for HSI48 oscillator
85 #[cfg(stm32l0)]
86 crate::pac::SYSCFG.cfgr3().modify(|w| {
87 w.set_enref_hsi48(false);
88 });
89}
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 0d668103c..55f383374 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -385,6 +385,17 @@ pub(crate) unsafe fn init(config: Config) {
385 while !RCC.extcfgr().read().c2hpref() {} 385 while !RCC.extcfgr().read().c2hpref() {}
386 } 386 }
387 387
388 // Disable HSI if not used
389 if !config.hsi {
390 RCC.cr().modify(|w| w.set_hsion(false));
391 }
392
393 // Disable the HSI48, if not used
394 #[cfg(crs)]
395 if config.hsi48.is_none() {
396 super::disable_hsi48();
397 }
398
388 config.mux.init(); 399 config.mux.init();
389 400
390 set_clocks!( 401 set_clocks!(
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 2a9a1595a..c0a50615e 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -312,6 +312,15 @@ impl RccInfo {
312 } 312 }
313 313
314 #[allow(dead_code)] 314 #[allow(dead_code)]
315 fn increment_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
316 #[cfg(all(any(stm32wl, stm32wb), feature = "low-power"))]
317 match self.stop_mode {
318 StopMode::Stop1 | StopMode::Stop2 => increment_stop_refcount(_cs, StopMode::Stop2),
319 _ => {}
320 }
321 }
322
323 #[allow(dead_code)]
315 pub(crate) fn increment_stop_refcount(&self) { 324 pub(crate) fn increment_stop_refcount(&self) {
316 #[cfg(feature = "low-power")] 325 #[cfg(feature = "low-power")]
317 critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs)) 326 critical_section::with(|cs| self.increment_stop_refcount_with_cs(cs))
@@ -324,6 +333,15 @@ impl RccInfo {
324 } 333 }
325 334
326 #[allow(dead_code)] 335 #[allow(dead_code)]
336 fn decrement_minimum_stop_refcount_with_cs(&self, _cs: CriticalSection) {
337 #[cfg(all(any(stm32wl, stm32wb), feature = "low-power"))]
338 match self.stop_mode {
339 StopMode::Stop1 | StopMode::Stop2 => decrement_stop_refcount(_cs, StopMode::Stop2),
340 _ => {}
341 }
342 }
343
344 #[allow(dead_code)]
327 pub(crate) fn decrement_stop_refcount(&self) { 345 pub(crate) fn decrement_stop_refcount(&self) {
328 #[cfg(feature = "low-power")] 346 #[cfg(feature = "low-power")]
329 critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs)) 347 critical_section::with(|cs| self.decrement_stop_refcount_with_cs(cs))
@@ -339,7 +357,10 @@ impl RccInfo {
339 357
340 #[allow(dead_code)] 358 #[allow(dead_code)]
341 pub(crate) fn enable_and_reset_without_stop(&self) { 359 pub(crate) fn enable_and_reset_without_stop(&self) {
342 critical_section::with(|cs| self.enable_and_reset_with_cs(cs)) 360 critical_section::with(|cs| {
361 self.enable_and_reset_with_cs(cs);
362 self.increment_minimum_stop_refcount_with_cs(cs);
363 })
343 } 364 }
344 365
345 // TODO: should this be `unsafe`? 366 // TODO: should this be `unsafe`?
@@ -353,7 +374,10 @@ impl RccInfo {
353 // TODO: should this be `unsafe`? 374 // TODO: should this be `unsafe`?
354 #[allow(dead_code)] 375 #[allow(dead_code)]
355 pub(crate) fn disable_without_stop(&self) { 376 pub(crate) fn disable_without_stop(&self) {
356 critical_section::with(|cs| self.disable_with_cs(cs)) 377 critical_section::with(|cs| {
378 self.disable_with_cs(cs);
379 self.decrement_minimum_stop_refcount_with_cs(cs);
380 })
357 } 381 }
358 382
359 #[allow(dead_code)] 383 #[allow(dead_code)]
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 7b0dcb63f..9f37107a3 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -343,6 +343,16 @@ pub(crate) unsafe fn init(config: Config) {
343 343
344 let hsi48 = config.hsi48.map(super::init_hsi48); 344 let hsi48 = config.hsi48.map(super::init_hsi48);
345 345
346 // There's a possibility that a bootloader that ran before us has configured the system clock
347 // source to be PLL1_R. In that case we'd get forever stuck on (de)configuring PLL1 as the chip
348 // prohibits disabling PLL1 when it's used as a source for system clock. Change the system
349 // clock source to MSIS which doesn't suffer from this conflict. The correct source per the
350 // provided config is then set further down.
351 // See https://github.com/embassy-rs/embassy/issues/5072
352 let default_system_clock_source = Config::default().sys;
353 RCC.cfgr1().modify(|w| w.set_sw(default_system_clock_source));
354 while RCC.cfgr1().read().sws() != default_system_clock_source {}
355
346 let pll_input = PllInput { hse, hsi, msi: msis }; 356 let pll_input = PllInput { hse, hsi, msi: msis };
347 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); 357 let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
348 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); 358 let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
@@ -457,6 +467,17 @@ pub(crate) unsafe fn init(config: Config) {
457 let lse = config.ls.lse.map(|l| l.frequency); 467 let lse = config.ls.lse.map(|l| l.frequency);
458 let lsi = config.ls.lsi.then_some(LSI_FREQ); 468 let lsi = config.ls.lsi.then_some(LSI_FREQ);
459 469
470 // Disable HSI if not used
471 if !config.hsi {
472 RCC.cr().modify(|w| w.set_hsion(false));
473 }
474
475 // Disable the HSI48, if not used
476 #[cfg(crs)]
477 if config.hsi48.is_none() {
478 super::disable_hsi48();
479 }
480
460 config.mux.init(); 481 config.mux.init();
461 482
462 set_clocks!( 483 set_clocks!(
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 2528996d5..4ab3067bc 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -269,6 +269,11 @@ pub(crate) unsafe fn init(config: Config) {
269 269
270 let lsi = config.ls.lsi.then_some(LSI_FREQ); 270 let lsi = config.ls.lsi.then_some(LSI_FREQ);
271 271
272 // Disable HSI if not used
273 if !config.hsi {
274 RCC.cr().modify(|w| w.set_hsion(false));
275 }
276
272 config.mux.init(); 277 config.mux.init();
273 278
274 set_clocks!( 279 set_clocks!(
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index dada9bda1..b8dfc7ecf 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -13,6 +13,23 @@ use crate::{Peri, interrupt, pac, peripherals, rcc};
13 13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 15
16/// WBA-specific health test configuration values for RNG
17#[derive(Clone, Copy)]
18#[allow(dead_code)]
19enum Htcfg {
20 /// WBA-specific health test configuration (0x0000AAC7)
21 /// Corresponds to configuration A, B, and C thresholds as recommended in the reference manual
22 WbaRecommended = 0x0000_AAC7,
23}
24
25impl Htcfg {
26 /// Convert to the raw u32 value for register access
27 #[allow(dead_code)]
28 fn value(self) -> u32 {
29 self as u32
30 }
31}
32
16/// RNG error 33/// RNG error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)] 34#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))] 35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -100,7 +117,7 @@ impl<'d, T: Instance> Rng<'d, T> {
100 // wait for CONDRST to be set 117 // wait for CONDRST to be set
101 while !T::regs().cr().read().condrst() {} 118 while !T::regs().cr().read().condrst() {}
102 119
103 // TODO for WBA6, the HTCR reg is different 120 // Set health test configuration values
104 #[cfg(not(rng_wba6))] 121 #[cfg(not(rng_wba6))]
105 { 122 {
106 // magic number must be written immediately before every read or write access to HTCR 123 // magic number must be written immediately before every read or write access to HTCR
@@ -111,6 +128,12 @@ impl<'d, T: Instance> Rng<'d, T> {
111 .htcr() 128 .htcr()
112 .write(|w| w.set_htcfg(pac::rng::vals::Htcfg::RECOMMENDED)); 129 .write(|w| w.set_htcfg(pac::rng::vals::Htcfg::RECOMMENDED));
113 } 130 }
131 #[cfg(rng_wba6)]
132 {
133 // For WBA6, set RNG_HTCR0 to the recommended value for configurations A, B, and C
134 // This value corresponds to the health test thresholds specified in the reference manual
135 T::regs().htcr(0).write(|w| w.0 = Htcfg::WbaRecommended.value());
136 }
114 137
115 // finish conditioning 138 // finish conditioning
116 T::regs().cr().modify(|reg| { 139 T::regs().cr().modify(|reg| {
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index f049d6b12..e15eddc22 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,64 +1,12 @@
1#[cfg(feature = "time")] 1use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc};
2use embassy_time::{Duration, TICK_HZ}; 2use embassy_time::{Duration, Instant, TICK_HZ};
3 3
4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte}; 4use super::Rtc;
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel; 6use crate::pac::rtc::vals::Wucksel;
7use crate::peripherals::RTC; 7use crate::peripherals::RTC;
8use crate::rtc::{RtcTimeProvider, SealedInstance}; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
9 9
10/// Represents an instant in time that can be substracted to compute a duration
11pub(super) struct RtcInstant {
12 /// 0..59
13 second: u8,
14 /// 0..256
15 subsecond: u16,
16}
17
18impl RtcInstant {
19 #[cfg(not(rtc_v2_f2))]
20 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
21 if second > 59 {
22 Err(DateTimeError::InvalidSecond)
23 } else {
24 Ok(Self { second, subsecond })
25 }
26 }
27}
28
29#[cfg(feature = "defmt")]
30impl defmt::Format for RtcInstant {
31 fn format(&self, fmt: defmt::Formatter) {
32 defmt::write!(
33 fmt,
34 "{}:{}",
35 self.second,
36 RTC::regs().prer().read().prediv_s() - self.subsecond,
37 )
38 }
39}
40
41#[cfg(feature = "time")]
42impl core::ops::Sub for RtcInstant {
43 type Output = embassy_time::Duration;
44
45 fn sub(self, rhs: Self) -> Self::Output {
46 let second = if self.second < rhs.second {
47 self.second + 60
48 } else {
49 self.second
50 };
51
52 let psc = RTC::regs().prer().read().prediv_s() as u32;
53
54 let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
55 let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
56 let rtc_ticks = self_ticks - other_ticks;
57
58 Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
59 }
60}
61
62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) { 10fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
63 *[ 11 *[
64 (Wucksel::DIV2, 2), 12 (Wucksel::DIV2, 2),
@@ -72,22 +20,15 @@ fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
72} 20}
73 21
74impl Rtc { 22impl Rtc {
75 /// Return the current instant. 23 pub(super) fn calc_epoch(&self) -> DateTime<Utc> {
76 fn instant(&self) -> Result<RtcInstant, RtcError> { 24 let now: NaiveDateTime = RtcTimeProvider::new().now().unwrap().into();
77 RtcTimeProvider::new().read(|_, tr, ss| {
78 let second = bcd2_to_byte((tr.st(), tr.su()));
79 25
80 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 26 now.and_utc() - TimeDelta::microseconds(Instant::now().as_micros().try_into().unwrap())
81 })
82 } 27 }
83 28
84 /// start the wakeup alarm and with a duration that is as close to but less than 29 /// start the wakeup alarm and with a duration that is as close to but less than
85 /// the requested duration, and record the instant the wakeup alarm was started 30 /// the requested duration, and record the instant the wakeup alarm was started
86 pub(crate) fn start_wakeup_alarm( 31 pub(crate) fn start_wakeup_alarm(&mut self, requested_duration: embassy_time::Duration) {
87 &mut self,
88 requested_duration: embassy_time::Duration,
89 cs: critical_section::CriticalSection,
90 ) {
91 // Panic if the rcc mod knows we're not using low-power rtc 32 // Panic if the rcc mod knows we're not using low-power rtc
92 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 33 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
93 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); 34 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
@@ -122,27 +63,19 @@ impl Rtc {
122 regs.cr().modify(|w| w.set_wutie(true)); 63 regs.cr().modify(|w| w.set_wutie(true));
123 }); 64 });
124 65
125 let instant = self.instant().unwrap();
126 trace!( 66 trace!(
127 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}", 67 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {})",
128 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(), 68 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
129 prescaler as u32, 69 prescaler as u32,
130 rtc_ticks, 70 rtc_ticks,
131 instant,
132 ); 71 );
133
134 assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
135 } 72 }
136 73
137 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 74 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
138 /// was called, otherwise none 75 /// was called, otherwise none
139 pub(crate) fn stop_wakeup_alarm( 76 pub(crate) fn stop_wakeup_alarm(&mut self) -> embassy_time::Instant {
140 &mut self,
141 cs: critical_section::CriticalSection,
142 ) -> Option<embassy_time::Duration> {
143 let instant = self.instant().unwrap();
144 if RTC::regs().cr().read().wute() { 77 if RTC::regs().cr().read().wute() {
145 trace!("rtc: stop wakeup alarm at {}", instant); 78 trace!("rtc: stop wakeup alarm");
146 79
147 self.write(false, |regs| { 80 self.write(false, |regs| {
148 regs.cr().modify(|w| w.set_wutie(false)); 81 regs.cr().modify(|w| w.set_wutie(false));
@@ -166,10 +99,13 @@ impl Rtc {
166 }); 99 });
167 } 100 }
168 101
169 self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time) 102 let datetime: NaiveDateTime = RtcTimeProvider::new().now().expect("failed to read now").into();
103 let offset = datetime.and_utc() - self.epoch;
104
105 Instant::from_micros(offset.num_microseconds().unwrap().try_into().unwrap())
170 } 106 }
171 107
172 pub(crate) fn enable_wakeup_line(&self) { 108 pub(super) fn enable_wakeup_line(&mut self) {
173 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 109 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
174 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 110 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
175 111
@@ -178,11 +114,11 @@ impl Rtc {
178 use crate::pac::EXTI; 114 use crate::pac::EXTI;
179 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 115 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
180 116
181 #[cfg(not(stm32wb))] 117 #[cfg(not(any(stm32wb, stm32wl5x)))]
182 { 118 {
183 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 119 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
184 } 120 }
185 #[cfg(stm32wb)] 121 #[cfg(any(stm32wb, stm32wl5x))]
186 { 122 {
187 EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 123 EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
188 } 124 }
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index e88bd7ab2..94ba13ae1 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,7 +5,7 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::{Cell, RefCell, RefMut}; 8use core::cell::{RefCell, RefMut};
9#[cfg(feature = "low-power")] 9#[cfg(feature = "low-power")]
10use core::ops; 10use core::ops;
11 11
@@ -163,7 +163,7 @@ impl<'a> ops::DerefMut for RtcBorrow<'a> {
163/// RTC driver. 163/// RTC driver.
164pub struct Rtc { 164pub struct Rtc {
165 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
166 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<low_power::RtcInstant>>>, 166 epoch: chrono::DateTime<chrono::Utc>,
167 _private: (), 167 _private: (),
168} 168}
169 169
@@ -225,7 +225,7 @@ impl Rtc {
225 225
226 let mut this = Self { 226 let mut this = Self {
227 #[cfg(feature = "low-power")] 227 #[cfg(feature = "low-power")]
228 stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 228 epoch: chrono::DateTime::from_timestamp_secs(0).unwrap(),
229 _private: (), 229 _private: (),
230 }; 230 };
231 231
@@ -243,7 +243,10 @@ impl Rtc {
243 } 243 }
244 244
245 #[cfg(feature = "low-power")] 245 #[cfg(feature = "low-power")]
246 this.enable_wakeup_line(); 246 {
247 this.enable_wakeup_line();
248 this.epoch = this.calc_epoch();
249 }
247 250
248 this 251 this
249 } 252 }
@@ -293,6 +296,11 @@ impl Rtc {
293 }); 296 });
294 }); 297 });
295 298
299 #[cfg(feature = "low-power")]
300 {
301 self.epoch = self.calc_epoch();
302 }
303
296 Ok(()) 304 Ok(())
297 } 305 }
298 306
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index f7ebea73e..49c9778df 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(any(stm32g4, stm32wlex))] { 134 if #[cfg(any(stm32g4, stm32wl))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(any(stm32g4, stm32wlex))] { 145 if #[cfg(any(stm32g4, stm32wl))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index e716fc348..cfe18ef52 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -142,34 +142,34 @@ impl Default for Signalling {
142 142
143const fn aligned_mut(x: &mut [u32]) -> &mut Aligned<A4, [u8]> { 143const fn aligned_mut(x: &mut [u32]) -> &mut Aligned<A4, [u8]> {
144 let len = x.len() * 4; 144 let len = x.len() * 4;
145 unsafe { core::mem::transmute(slice::from_raw_parts_mut(x.as_mut_ptr() as _, len)) } 145 unsafe { core::mem::transmute(slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u8, len)) }
146} 146}
147 147
148const fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 148const fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
149 let len = x.len() * 4; 149 let len = x.len() * 4;
150 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } 150 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u8, len) }
151} 151}
152 152
153#[allow(unused)] 153#[allow(unused)]
154const fn slice32_mut(x: &mut Aligned<A4, [u8]>) -> &mut [u32] { 154const fn slice32_mut(x: &mut Aligned<A4, [u8]>) -> &mut [u32] {
155 let len = (size_of_val(x) + 4 - 1) / 4; 155 let len = (size_of_val(x) + 4 - 1) / 4;
156 unsafe { slice::from_raw_parts_mut(x as *mut Aligned<A4, [u8]> as *mut _, len) } 156 unsafe { slice::from_raw_parts_mut(x as *mut Aligned<A4, [u8]> as *mut u32, len) }
157} 157}
158 158
159const fn aligned_ref(x: &[u32]) -> &Aligned<A4, [u8]> { 159const fn aligned_ref(x: &[u32]) -> &Aligned<A4, [u8]> {
160 let len = x.len() * 4; 160 let len = x.len() * 4;
161 unsafe { core::mem::transmute(slice::from_raw_parts(x.as_ptr() as _, len)) } 161 unsafe { core::mem::transmute(slice::from_raw_parts(x.as_ptr() as *const u8, len)) }
162} 162}
163 163
164const fn slice8_ref(x: &[u32]) -> &[u8] { 164const fn slice8_ref(x: &[u32]) -> &[u8] {
165 let len = x.len() * 4; 165 let len = x.len() * 4;
166 unsafe { slice::from_raw_parts(x.as_ptr() as _, len) } 166 unsafe { slice::from_raw_parts(x.as_ptr() as *const u8, len) }
167} 167}
168 168
169#[allow(unused)] 169#[allow(unused)]
170const fn slice32_ref(x: &Aligned<A4, [u8]>) -> &[u32] { 170const fn slice32_ref(x: &Aligned<A4, [u8]>) -> &[u32] {
171 let len = (size_of_val(x) + 4 - 1) / 4; 171 let len = (size_of_val(x) + 4 - 1) / 4;
172 unsafe { slice::from_raw_parts(x as *const Aligned<A4, [u8]> as *const _, len) } 172 unsafe { slice::from_raw_parts(x as *const Aligned<A4, [u8]> as *const u32, len) }
173} 173}
174 174
175/// Errors 175/// Errors
@@ -1179,6 +1179,7 @@ impl<'d> Drop for Sdmmc<'d> {
1179 fn drop(&mut self) { 1179 fn drop(&mut self) {
1180 // T::Interrupt::disable(); 1180 // T::Interrupt::disable();
1181 self.on_drop(); 1181 self.on_drop();
1182 self.info.rcc.disable_without_stop();
1182 1183
1183 critical_section::with(|_| { 1184 critical_section::with(|_| {
1184 self.clk.set_as_disconnected(); 1185 self.clk.set_as_disconnected();
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index af51b79b4..13ff31a34 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1126,7 +1126,7 @@ impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
1126 self.miso.as_ref().map(|x| x.set_as_disconnected()); 1126 self.miso.as_ref().map(|x| x.set_as_disconnected());
1127 self.nss.as_ref().map(|x| x.set_as_disconnected()); 1127 self.nss.as_ref().map(|x| x.set_as_disconnected());
1128 1128
1129 self.info.rcc.disable(); 1129 self.info.rcc.disable_without_stop();
1130 } 1130 }
1131} 1131}
1132 1132
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index ed5d902bd..59ec58575 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -251,8 +251,8 @@ impl RtcDriver {
251 251
252 #[cfg(feature = "low-power")] 252 #[cfg(feature = "low-power")]
253 /// Add the given offset to the current time 253 /// Add the given offset to the current time
254 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 254 fn set_time(&self, instant: u64, cs: CriticalSection) {
255 let (period, counter) = calc_period_counter(self.now() + offset.as_ticks()); 255 let (period, counter) = calc_period_counter(core::cmp::max(self.now(), instant));
256 256
257 self.period.store(period, Ordering::SeqCst); 257 self.period.store(period, Ordering::SeqCst);
258 regs_gp16().cnt().write(|w| w.set_cnt(counter)); 258 regs_gp16().cnt().write(|w| w.set_cnt(counter));
@@ -269,10 +269,17 @@ impl RtcDriver {
269 #[cfg(feature = "low-power")] 269 #[cfg(feature = "low-power")]
270 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 270 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
271 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 271 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
272 if !regs_gp16().cr1().read().cen() 272 if !regs_gp16().cr1().read().cen() {
273 && let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs) 273 self.set_time(
274 { 274 self.rtc
275 self.add_time(offset, cs); 275 .borrow(cs)
276 .borrow_mut()
277 .as_mut()
278 .unwrap()
279 .stop_wakeup_alarm()
280 .as_ticks(),
281 cs,
282 );
276 } 283 }
277 } 284 }
278 285
@@ -287,7 +294,7 @@ impl RtcDriver {
287 #[cfg(feature = "low-power")] 294 #[cfg(feature = "low-power")]
288 /// Set the rtc but panic if it's already been set 295 /// Set the rtc but panic if it's already been set
289 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) { 296 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
290 rtc.stop_wakeup_alarm(cs); 297 rtc.stop_wakeup_alarm();
291 298
292 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()); 299 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
293 } 300 }
@@ -310,7 +317,7 @@ impl RtcDriver {
310 .borrow_mut() 317 .borrow_mut()
311 .as_mut() 318 .as_mut()
312 .unwrap() 319 .unwrap()
313 .start_wakeup_alarm(time_until_next_alarm, cs); 320 .start_wakeup_alarm(time_until_next_alarm);
314 321
315 regs_gp16().cr1().modify(|w| w.set_cen(false)); 322 regs_gp16().cr1().modify(|w| w.set_cen(false));
316 // save the count for the timer as its lost in STOP2 for stm32wlex 323 // save the count for the timer as its lost in STOP2 for stm32wlex
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 3e1482b67..905f2de1a 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -156,6 +156,48 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
156 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate) 156 self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate)
157 .await 157 .await
158 } 158 }
159
160 /// Capture a sequence of timer input edges into a buffer using DMA
161 pub async fn receive_waveform<M>(&mut self, dma: Peri<'_, impl super::Dma<T, M>>, buf: &mut [u16])
162 where
163 M: TimerChannel,
164 {
165 #[allow(clippy::let_unit_value)] // eg. stm32f334
166 let req = dma.request();
167
168 let original_enable_state = self.is_enabled(M::CHANNEL);
169 let original_cc_dma_enable_state = self.inner.get_cc_dma_enable_state(M::CHANNEL);
170
171 self.inner.set_input_ti_selection(M::CHANNEL, InputTISelection::Normal);
172 self.inner
173 .set_input_capture_mode(M::CHANNEL, InputCaptureMode::BothEdges);
174
175 if !original_cc_dma_enable_state {
176 self.inner.set_cc_dma_enable_state(M::CHANNEL, true);
177 }
178
179 if !original_enable_state {
180 self.enable(M::CHANNEL);
181 }
182
183 unsafe {
184 use crate::dma::{Transfer, TransferOptions};
185
186 Transfer::new_read(
187 dma,
188 req,
189 self.inner.regs_gp16().ccr(M::CHANNEL.index()).as_ptr() as *mut u16,
190 buf,
191 TransferOptions::default(),
192 )
193 .await
194 };
195
196 // restore output compare state
197 if !original_enable_state {
198 self.disable(M::CHANNEL);
199 }
200 }
159} 201}
160 202
161#[must_use = "futures do nothing unless you `.await` or poll them"] 203#[must_use = "futures do nothing unless you `.await` or poll them"]
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index 0c28cec7d..86c87b7b1 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -41,7 +41,7 @@ futures-core = { version = "0.3.31", default-features = false }
41critical-section = "1.1" 41critical-section = "1.1"
42heapless = "0.8" 42heapless = "0.8"
43cfg-if = "1.0.0" 43cfg-if = "1.0.0"
44embedded-io-async = { version = "0.6.1" } 44embedded-io-async = { version = "0.7.0" }
45 45
46[dev-dependencies] 46[dev-dependencies]
47futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } 47futures-executor = { version = "0.3.17", features = [ "thread-pool" ] }
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index 215a556d9..d6c21299a 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -393,7 +393,7 @@ where
393 /// Attempt to immediately write some bytes to the pipe. 393 /// Attempt to immediately write some bytes to the pipe.
394 /// 394 ///
395 /// This method will either write a nonzero amount of bytes to the pipe immediately, 395 /// This method will either write a nonzero amount of bytes to the pipe immediately,
396 /// or return an error if the pipe is empty. See [`write`](Self::write) for a variant 396 /// or return an error if the pipe is full. See [`write`](Self::write) for a variant
397 /// that waits instead of returning an error. 397 /// that waits instead of returning an error.
398 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> { 398 pub fn try_write(&self, buf: &[u8]) -> Result<usize, TryWriteError> {
399 self.try_write_with_context(None, buf) 399 self.try_write_with_context(None, buf)
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 8b32582c0..4f952a047 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -35,7 +35,7 @@ features = ["defmt", "cortex-m", "dfu"]
35defmt = { version = "1.0.1", optional = true } 35defmt = { version = "1.0.1", optional = true }
36log = { version = "0.4.17", optional = true } 36log = { version = "0.4.17", optional = true }
37 37
38bitflags = "2.4.1" 38bitflags = "2.10.0"
39cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } 39cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
40embassy-boot = { version = "0.6.1", path = "../embassy-boot" } 40embassy-boot = { version = "0.6.1", path = "../embassy-boot" }
41embassy-futures = { version = "0.1.2", path = "../embassy-futures" } 41embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml
index 3f43f60a3..a11658213 100644
--- a/embassy-usb-driver/Cargo.toml
+++ b/embassy-usb-driver/Cargo.toml
@@ -19,6 +19,7 @@ target = "thumbv7em-none-eabi"
19features = ["defmt"] 19features = ["defmt"]
20 20
21[dependencies] 21[dependencies]
22# TODO: remove before releasing embassy-usb-driver v0.3
22embedded-io-async = "0.6.1" 23embedded-io-async = "0.6.1"
23defmt = { version = "1", optional = true } 24defmt = { version = "1", optional = true }
24 25
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index f19e0a401..782f130f6 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -429,6 +429,7 @@ pub enum EndpointError {
429 Disabled, 429 Disabled,
430} 430}
431 431
432// TODO: remove before releasing embassy-usb-driver v0.3
432impl embedded_io_async::Error for EndpointError { 433impl embedded_io_async::Error for EndpointError {
433 fn kind(&self) -> embedded_io_async::ErrorKind { 434 fn kind(&self) -> embedded_io_async::ErrorKind {
434 match self { 435 match self {
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 3d1e005e4..6c3ddc1db 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -66,7 +66,7 @@ embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-
66defmt = { version = "1", optional = true } 66defmt = { version = "1", optional = true }
67log = { version = "0.4.14", optional = true } 67log = { version = "0.4.14", optional = true }
68heapless = "0.8" 68heapless = "0.8"
69embedded-io-async = "0.6.1" 69embedded-io-async = { version = "0.7.0" }
70 70
71# for HID 71# for HID
72usbd-hid = { version = "0.9.0", optional = true } 72usbd-hid = { version = "0.9.0", optional = true }
diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs
index ab2311f4e..56acdb2a6 100644
--- a/embassy-usb/src/class/cdc_acm.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -33,6 +33,30 @@ const REQ_SET_LINE_CODING: u8 = 0x20;
33const REQ_GET_LINE_CODING: u8 = 0x21; 33const REQ_GET_LINE_CODING: u8 = 0x21;
34const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22; 34const REQ_SET_CONTROL_LINE_STATE: u8 = 0x22;
35 35
36/// CDC ACM error.
37#[derive(Clone, Debug)]
38pub enum CdcAcmError {
39 /// USB is not connected.
40 NotConnected,
41}
42
43impl core::fmt::Display for CdcAcmError {
44 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45 match *self {
46 Self::NotConnected => f.write_str("NotConnected"),
47 }
48 }
49}
50
51impl core::error::Error for CdcAcmError {}
52impl embedded_io_async::Error for CdcAcmError {
53 fn kind(&self) -> embedded_io_async::ErrorKind {
54 match *self {
55 Self::NotConnected => embedded_io_async::ErrorKind::NotConnected,
56 }
57 }
58}
59
36/// Internal state for CDC-ACM 60/// Internal state for CDC-ACM
37pub struct State<'a> { 61pub struct State<'a> {
38 control: MaybeUninit<Control<'a>>, 62 control: MaybeUninit<Control<'a>>,
@@ -421,14 +445,21 @@ impl<'d, D: Driver<'d>> Sender<'d, D> {
421} 445}
422 446
423impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for Sender<'d, D> { 447impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for Sender<'d, D> {
424 type Error = EndpointError; 448 type Error = CdcAcmError;
425} 449}
426 450
427impl<'d, D: Driver<'d>> embedded_io_async::Write for Sender<'d, D> { 451impl<'d, D: Driver<'d>> embedded_io_async::Write for Sender<'d, D> {
428 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 452 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
429 let len = core::cmp::min(buf.len(), self.max_packet_size() as usize); 453 let len = core::cmp::min(buf.len(), self.max_packet_size() as usize);
430 self.write_packet(&buf[..len]).await?; 454 match self.write_packet(&buf[..len]).await {
431 Ok(len) 455 Ok(()) => Ok(len),
456 Err(EndpointError::BufferOverflow) => unreachable!(),
457 Err(EndpointError::Disabled) => Err(CdcAcmError::NotConnected),
458 }
459 }
460
461 async fn flush(&mut self) -> Result<(), Self::Error> {
462 Ok(())
432 } 463 }
433} 464}
434 465
@@ -539,7 +570,7 @@ impl<'d, D: Driver<'d>> BufferedReceiver<'d, D> {
539} 570}
540 571
541impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for BufferedReceiver<'d, D> { 572impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for BufferedReceiver<'d, D> {
542 type Error = EndpointError; 573 type Error = CdcAcmError;
543} 574}
544 575
545impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> { 576impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> {
@@ -552,14 +583,22 @@ impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> {
552 // If the caller's buffer is large enough to contain an entire packet, read directly into 583 // If the caller's buffer is large enough to contain an entire packet, read directly into
553 // that instead of buffering the packet internally. 584 // that instead of buffering the packet internally.
554 if buf.len() > self.receiver.max_packet_size() as usize { 585 if buf.len() > self.receiver.max_packet_size() as usize {
555 return self.receiver.read_packet(buf).await; 586 return match self.receiver.read_packet(buf).await {
587 Ok(n) => Ok(n),
588 Err(EndpointError::BufferOverflow) => unreachable!(),
589 Err(EndpointError::Disabled) => Err(CdcAcmError::NotConnected),
590 };
556 } 591 }
557 592
558 // Otherwise read a packet into the internal buffer, and return some of it to the caller. 593 // Otherwise read a packet into the internal buffer, and return some of it to the caller.
559 // 594 //
560 // It's important that `start` and `end` be updated in this order so they're left in a 595 // It's important that `start` and `end` be updated in this order so they're left in a
561 // consistent state if the `read` future is dropped mid-execution, e.g. from a timeout. 596 // consistent state if the `read` future is dropped mid-execution, e.g. from a timeout.
562 self.end = self.receiver.read_packet(&mut self.buffer).await?; 597 match self.receiver.read_packet(&mut self.buffer).await {
598 Ok(n) => self.end = n,
599 Err(EndpointError::BufferOverflow) => unreachable!(),
600 Err(EndpointError::Disabled) => return Err(CdcAcmError::NotConnected),
601 }
563 self.start = 0; 602 self.start = 0;
564 return Ok(self.read_from_buffer(buf)); 603 return Ok(self.read_from_buffer(buf));
565 } 604 }
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs
index 66689871e..6d7f87061 100644
--- a/embassy-usb/src/msos.rs
+++ b/embassy-usb/src/msos.rs
@@ -110,10 +110,6 @@ impl<'d> MsOsDescriptorWriter<'d> {
110 !self.is_empty(), 110 !self.is_empty(),
111 "device features may only be added after the header is written" 111 "device features may only be added after the header is written"
112 ); 112 );
113 assert!(
114 self.config_mark.is_none(),
115 "device features must be added before the first configuration subset"
116 );
117 self.write(desc); 113 self.write(desc);
118 } 114 }
119 115
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 79286e295..ccaa24e3e 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -9,9 +9,9 @@ publish = false
9embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } 9embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
10embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } 10embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
11embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } 11embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] }
12embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["gpiote", ] } 12embassy-nrf = { version = "0.9.0", path = "../../../../embassy-nrf", features = ["gpiote", ] }
13embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } 13embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] }
14embassy-boot-nrf = { version = "0.9.0", path = "../../../../embassy-boot-nrf", features = [] } 14embassy-boot-nrf = { version = "0.10.0", path = "../../../../embassy-boot-nrf", features = [] }
15embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } 15embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" }
16 16
17defmt = { version = "1.0.1", optional = true } 17defmt = { version = "1.0.1", optional = true }
diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml
index 347659f5b..29d319375 100644
--- a/examples/mcxa/Cargo.toml
+++ b/examples/mcxa/Cargo.toml
@@ -18,7 +18,7 @@ embassy-mcxa = { path = "../../embassy-mcxa", features = ["defmt", "unstable-pac
18embassy-sync = "0.7.2" 18embassy-sync = "0.7.2"
19embassy-time = "0.5.0" 19embassy-time = "0.5.0"
20embassy-time-driver = "0.2.1" 20embassy-time-driver = "0.2.1"
21embedded-io-async = "0.6.1" 21embedded-io-async = "0.7.0"
22heapless = "0.9.2" 22heapless = "0.9.2"
23panic-probe = { version = "1.0", features = ["print-defmt"] } 23panic-probe = { version = "1.0", features = ["print-defmt"] }
24rand_core = "0.9" 24rand_core = "0.9"
diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs
index 1e52912d3..c0e8c330d 100644
--- a/examples/mcxa/src/bin/clkout.rs
+++ b/examples/mcxa/src/bin/clkout.rs
@@ -4,6 +4,7 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; 5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4};
6use embassy_mcxa::clocks::PoweredClock; 6use embassy_mcxa::clocks::PoweredClock;
7use embassy_mcxa::clocks::config::{SoscConfig, SoscMode, SpllConfig, SpllMode, SpllSource};
7use embassy_mcxa::gpio::{DriveStrength, Level, Output, SlewRate}; 8use embassy_mcxa::gpio::{DriveStrength, Level, Output, SlewRate};
8use embassy_time::Timer; 9use embassy_time::Timer;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
@@ -11,58 +12,81 @@ use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11/// Demonstrate CLKOUT, using Pin P4.2 12/// Demonstrate CLKOUT, using Pin P4.2
12#[embassy_executor::main] 13#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
14 let p = hal::init(hal::config::Config::default()); 15 let mut cfg = hal::config::Config::default();
16 cfg.clock_cfg.sosc = Some(SoscConfig {
17 mode: SoscMode::CrystalOscillator,
18 frequency: 8_000_000,
19 power: PoweredClock::NormalEnabledDeepSleepDisabled,
20 });
21 cfg.clock_cfg.spll = Some(SpllConfig {
22 source: SpllSource::Sirc,
23 // 12MHz
24 // 12 x 32 => 384MHz
25 // 384 / (16 x 2) => 12.0MHz
26 mode: SpllMode::Mode1b {
27 m_mult: 32,
28 p_div: 16,
29 bypass_p2_div: false,
30 },
31 power: PoweredClock::NormalEnabledDeepSleepDisabled,
32 pll1_clk_div: None,
33 });
34
35 let p = hal::init(cfg);
36
15 let mut pin = p.P4_2; 37 let mut pin = p.P4_2;
16 let mut clkout = p.CLKOUT; 38 let mut clkout = p.CLKOUT;
17 39
18 loop { 40 const K16_CONFIG: Config = Config {
19 defmt::info!("Set Low..."); 41 sel: ClockOutSel::Clk16K,
20 let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); 42 div: Div4::no_div(),
21 Timer::after_millis(500).await; 43 level: PoweredClock::NormalEnabledDeepSleepDisabled,
44 };
45 const M4_CONFIG: Config = Config {
46 sel: ClockOutSel::Fro12M,
47 div: const { Div4::from_divisor(3).unwrap() },
48 level: PoweredClock::NormalEnabledDeepSleepDisabled,
49 };
50 const K512_CONFIG: Config = Config {
51 sel: ClockOutSel::ClkIn,
52 div: const { Div4::from_divisor(16).unwrap() },
53 level: PoweredClock::NormalEnabledDeepSleepDisabled,
54 };
55 const M1_CONFIG: Config = Config {
56 sel: ClockOutSel::Pll1Clk,
57 div: const { Div4::from_divisor(12).unwrap() },
58 level: PoweredClock::NormalEnabledDeepSleepDisabled,
59 };
22 60
61 #[rustfmt::skip]
62 let configs = [
63 ("16K -> /1 = 16K", K16_CONFIG),
64 ("12M -> /3 = 4M", M4_CONFIG),
65 ("8M -> /16 = 512K", K512_CONFIG),
66 ("12M-> /12 = 1M", M1_CONFIG),
67 ];
68
69 loop {
23 defmt::info!("Set High..."); 70 defmt::info!("Set High...");
24 output.set_high(); 71 let mut output = Output::new(pin.reborrow(), Level::High, DriveStrength::Normal, SlewRate::Slow);
25 Timer::after_millis(400).await; 72 Timer::after_millis(250).await;
26 73
27 defmt::info!("Set Low..."); 74 defmt::info!("Set Low...");
28 output.set_low(); 75 output.set_low();
29 Timer::after_millis(500).await; 76 Timer::after_millis(750).await;
30 77
31 defmt::info!("16k..."); 78 for (name, conf) in configs.iter() {
32 // Run Clock Out with the 16K clock 79 defmt::info!("Running {=str}", name);
33 let _clock_out = ClockOut::new(
34 clkout.reborrow(),
35 pin.reborrow(),
36 Config {
37 sel: ClockOutSel::Clk16K,
38 div: Div4::no_div(),
39 level: PoweredClock::NormalEnabledDeepSleepDisabled,
40 },
41 )
42 .unwrap();
43 80
44 Timer::after_millis(3000).await; 81 let _clock_out = ClockOut::new(clkout.reborrow(), pin.reborrow(), *conf).unwrap();
45
46 defmt::info!("Set Low...");
47 drop(_clock_out);
48 82
49 let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); 83 Timer::after_millis(3000).await;
50 Timer::after_millis(500).await;
51 84
52 // Run Clock Out with the 12M clock, divided by 3 85 defmt::info!("Set Low...");
53 defmt::info!("4M..."); 86 drop(_clock_out);
54 let _clock_out = ClockOut::new(
55 clkout.reborrow(),
56 pin.reborrow(),
57 Config {
58 sel: ClockOutSel::Fro12M,
59 div: const { Div4::from_divisor(3).unwrap() },
60 level: PoweredClock::NormalEnabledDeepSleepDisabled,
61 },
62 )
63 .unwrap();
64 87
65 // Let it run for 3 seconds... 88 let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow);
66 Timer::after_millis(3000).await; 89 Timer::after_millis(500).await;
90 }
67 } 91 }
68} 92}
diff --git a/examples/mcxa/src/bin/reset-reason.rs b/examples/mcxa/src/bin/reset-reason.rs
index c244fbe04..2d48a92b1 100644
--- a/examples/mcxa/src/bin/reset-reason.rs
+++ b/examples/mcxa/src/bin/reset-reason.rs
@@ -11,5 +11,7 @@ async fn main(_spawner: Spawner) {
11 let config = Config::default(); 11 let config = Config::default();
12 let _p = hal::init(config); 12 let _p = hal::init(config);
13 13
14 defmt::info!("Reset Reason: '{}'", reset_reason()); 14 for reason in reset_reason().into_iter() {
15 defmt::info!("Reset Reason: '{}'", reason);
16 }
15} 17}
diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml
index 8c230f038..f4fc7e09f 100644
--- a/examples/mspm0g3507/Cargo.toml
+++ b/examples/mspm0g3507/Cargo.toml
@@ -18,7 +18,7 @@ defmt-rtt = "1.0.0"
18panic-probe = { version = "1.0.0", features = ["print-defmt"] } 18panic-probe = { version = "1.0.0", features = ["print-defmt"] }
19panic-semihosting = "0.6.0" 19panic-semihosting = "0.6.0"
20 20
21embedded-io-async = "0.6.1" 21embedded-io-async = { version = "0.7.0" }
22 22
23[profile.release] 23[profile.release]
24debug = 2 24debug = 2
diff --git a/examples/mspm0g5187/.cargo/config.toml b/examples/mspm0g5187/.cargo/config.toml
new file mode 100644
index 000000000..ea407b411
--- /dev/null
+++ b/examples/mspm0g5187/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace MSPM0G5187 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G5187 --protocol=swd"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/mspm0g5187/Cargo.toml b/examples/mspm0g5187/Cargo.toml
new file mode 100644
index 000000000..3d64a127a
--- /dev/null
+++ b/examples/mspm0g5187/Cargo.toml
@@ -0,0 +1,27 @@
1[package]
2edition = "2024"
3name = "embassy-mspm0-g5187-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g5187pm", "defmt", "rt", "time-driver-any"] }
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
11embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt"] }
13panic-halt = "1.0.0"
14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15cortex-m-rt = { version = "0.7.0"}
16defmt = "1.0.1"
17defmt-rtt = "1.0.0"
18panic-probe = { version = "1.0.0", features = ["print-defmt"] }
19panic-semihosting = "0.6.0"
20
21[profile.release]
22debug = 2
23
24[package.metadata.embassy]
25build = [
26 { target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0g5187" }
27]
diff --git a/examples/mspm0g5187/README.md b/examples/mspm0g5187/README.md
new file mode 100644
index 000000000..12e7846fb
--- /dev/null
+++ b/examples/mspm0g5187/README.md
@@ -0,0 +1,27 @@
1# Examples for MSPM0G5187
2
3Run individual examples with
4```
5cargo run --bin <module-name>
6```
7for example
8```
9cargo run --bin blinky
10```
11
12## Checklist before running examples
13A large number of the examples are written for the [LP-MSPM0G5187](https://www.ti.com/tool/LP-MSPM0G5187) board.
14
15You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
16
17* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G5187 it should be `probe-rs run --chip MSPM0G5187`. (use `probe-rs chip list` to find your chip)
18* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0G3519 it should be `mspm0g3519pz`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
19* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
20* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
21
22If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
23
24* Which example you are trying to run
25* Which chip and board you are using
26
27Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
diff --git a/examples/mspm0g5187/build.rs b/examples/mspm0g5187/build.rs
new file mode 100644
index 000000000..2d777c2d3
--- /dev/null
+++ b/examples/mspm0g5187/build.rs
@@ -0,0 +1,37 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35 // You must tell cargo to link interrupt groups if the rt feature is enabled.
36 println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x");
37}
diff --git a/examples/mspm0g5187/memory.x b/examples/mspm0g5187/memory.x
new file mode 100644
index 000000000..37e381fbd
--- /dev/null
+++ b/examples/mspm0g5187/memory.x
@@ -0,0 +1,6 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 128K
4 /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
5 RAM : ORIGIN = 0x20200000, LENGTH = 32K
6}
diff --git a/examples/mspm0g5187/src/bin/blinky.rs b/examples/mspm0g5187/src/bin/blinky.rs
new file mode 100644
index 000000000..47eaf1535
--- /dev/null
+++ b/examples/mspm0g5187/src/bin/blinky.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::Config;
7use embassy_mspm0::gpio::{Level, Output};
8use embassy_time::Timer;
9use {defmt_rtt as _, panic_halt as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) -> ! {
13 info!("Hello world!");
14 let p = embassy_mspm0::init(Config::default());
15
16 let mut led1 = Output::new(p.PA0, Level::Low);
17 led1.set_inversion(true);
18
19 loop {
20 Timer::after_millis(400).await;
21
22 info!("Toggle");
23 led1.toggle();
24 }
25}
diff --git a/examples/mspm0g5187/src/bin/button.rs b/examples/mspm0g5187/src/bin/button.rs
new file mode 100644
index 000000000..2ed15e354
--- /dev/null
+++ b/examples/mspm0g5187/src/bin/button.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_mspm0::Config;
7use embassy_mspm0::gpio::{Input, Level, Output, Pull};
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) -> ! {
12 info!("Hello world!");
13
14 let p = embassy_mspm0::init(Config::default());
15
16 let led1 = p.PA0;
17 let s2 = p.PA7;
18
19 let mut led1 = Output::new(led1, Level::Low);
20
21 let mut s2 = Input::new(s2, Pull::Up);
22
23 // led1 is active low
24 led1.set_high();
25
26 loop {
27 s2.wait_for_falling_edge().await;
28
29 info!("Switch 2 was pressed");
30
31 led1.toggle();
32 }
33}
diff --git a/examples/mspm0g5187/src/bin/wwdt.rs b/examples/mspm0g5187/src/bin/wwdt.rs
new file mode 100644
index 000000000..a5de781f3
--- /dev/null
+++ b/examples/mspm0g5187/src/bin/wwdt.rs
@@ -0,0 +1,54 @@
1//! Example of using window watchdog timer in the MSPM0G5187 chip.
2//!
3//! It tests the use case when watchdog timer is expired and when watchdog is pet too early.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::gpio::{Level, Output};
11use embassy_mspm0::wwdt::{ClosedWindowPercentage, Config, Timeout, Watchdog};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_halt as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) -> ! {
17 info!("Hello world!");
18
19 let p = embassy_mspm0::init(Default::default());
20 let mut conf = Config::default();
21 conf.timeout = Timeout::Sec1;
22
23 // watchdog also resets the system if the pet comes too early,
24 // less than 250 msec == 25% from 1 sec
25 conf.closed_window = ClosedWindowPercentage::TwentyFive;
26 let mut wdt = Watchdog::new(p.WWDT0, conf);
27 info!("Started the watchdog timer");
28
29 let mut led1 = Output::new(p.PA0, Level::High);
30 led1.set_inversion(true);
31 Timer::after_millis(900).await;
32
33 for _ in 1..=5 {
34 info!("pet watchdog");
35 led1.toggle();
36 wdt.pet();
37 Timer::after_millis(500).await;
38 }
39
40 // watchdog timeout test
41 info!("Stopped the pet command, device will reset in less than 1 second");
42 loop {
43 led1.toggle();
44 Timer::after_millis(500).await;
45 }
46
47 // watchdog "too early" test
48 // info!("Device will reset when the pet comes too early");
49 // loop {
50 // led1.toggle();
51 // wdt.pet();
52 // Timer::after_millis(200).await;
53 // }
54}
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 5caabf228..3d6b5e60a 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -19,7 +19,7 @@ log = [
19embassy-sync = { version = "0.7.2", path = "../../embassy-sync" } 19embassy-sync = { version = "0.7.2", path = "../../embassy-sync" }
20embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } 20embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] }
21embassy-time = { version = "0.5.0", path = "../../embassy-time" } 21embassy-time = { version = "0.5.0", path = "../../embassy-time" }
22embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 22embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
23 23
24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index c7492f562..e8375952b 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 11embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
index 1711a3d8d..73d129f91 100644
--- a/examples/nrf52810/Cargo.toml
+++ b/examples/nrf52810/Cargo.toml
@@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 14
15defmt = "1.0.1" 15defmt = "1.0.1"
16defmt-rtt = "1.0.0" 16defmt-rtt = "1.0.0"
diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml
index 8b1db4652..8066a1150 100644
--- a/examples/nrf52840-edf/Cargo.toml
+++ b/examples/nrf52840-edf/Cargo.toml
@@ -9,7 +9,7 @@ publish = false
9# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled 9# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] } 10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13 13
14defmt = "1.0.1" 14defmt = "1.0.1"
15defmt-rtt = "1.0.0" 15defmt-rtt = "1.0.0"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index 26b21598f..13a7724fa 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -12,7 +12,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] }
14embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } 14embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] }
15embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 15embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
16 16
17defmt = "1.0.1" 17defmt = "1.0.1"
18defmt-rtt = "1.0.0" 18defmt-rtt = "1.0.0"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 1fe3d2419..15c187328 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -10,11 +10,11 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } 13embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embedded-io = { version = "0.6.0", features = ["defmt-03"] } 16embedded-io = { version = "0.7.1", features = ["defmt"] }
17embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 17embedded-io-async = { version = "0.7.0", features = ["defmt"] }
18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
19embassy-net-enc28j60 = { version = "0.2.1", path = "../../embassy-net-enc28j60", features = ["defmt"] } 19embassy-net-enc28j60 = { version = "0.2.1", path = "../../embassy-net-enc28j60", features = ["defmt"] }
20 20
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 97efe58e8..c54a84d22 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -10,10 +10,10 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 13embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embedded-io-async = { version = "0.6.1" } 16embedded-io-async = { version = "0.7.0" }
17 17
18defmt = "1.0.1" 18defmt = "1.0.1"
19defmt-rtt = "1.0.0" 19defmt-rtt = "1.0.0"
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
index f34df0f26..9940443ff 100644
--- a/examples/nrf54l15/Cargo.toml
+++ b/examples/nrf54l15/Cargo.toml
@@ -10,9 +10,9 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] }
14embedded-io = { version = "0.6.0", features = ["defmt-03"] } 14embedded-io = { version = "0.7.0", features = ["defmt"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.7.0", features = ["defmt"] }
16 16
17rand = { version = "0.9.0", default-features = false } 17rand = { version = "0.9.0", default-features = false }
18 18
diff --git a/examples/nrf54lm20/Cargo.toml b/examples/nrf54lm20/Cargo.toml
index 5482fc77a..78ce60596 100644
--- a/examples/nrf54lm20/Cargo.toml
+++ b/examples/nrf54lm20/Cargo.toml
@@ -10,9 +10,9 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] }
14embedded-io = { version = "0.6.0", features = ["defmt-03"] } 14embedded-io = { version = "0.7.0", features = ["defmt"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.7.0", features = ["defmt"] }
16 16
17rand = { version = "0.9.0", default-features = false } 17rand = { version = "0.9.0", default-features = false }
18 18
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
index 7f1f5239a..f6d6aab6f 100644
--- a/examples/nrf9151/ns/Cargo.toml
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
index ce71cc456..1c9e7fb35 100644
--- a/examples/nrf9151/s/Cargo.toml
+++ b/examples/nrf9151/s/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index ae3b2eeb1..bad7fdc79 100644
--- a/examples/nrf9160/Cargo.toml
+++ b/examples/nrf9160/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } 12embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] }
13embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } 13embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
14 14
@@ -20,8 +20,8 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
20cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
21panic-probe = { version = "1.0.0", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
22static_cell = { version = "2" } 22static_cell = { version = "2" }
23embedded-io = "0.6.1" 23embedded-io = { version = "0.7.1" }
24embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 24embedded-io-async = { version = "0.7.0", features = ["defmt"] }
25 25
26[profile.release] 26[profile.release]
27debug = 2 27debug = 2
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index e247f6f7a..1a5712dd3 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -26,7 +26,7 @@ fixed = "1.23.1"
26fixed-macro = "1.2" 26fixed-macro = "1.2"
27 27
28# for web request example 28# for web request example
29reqwless = { version = "0.13.0", features = ["defmt"] } 29reqwless = { git = "https://github.com/drogue-iot/reqwless", rev = "68f703dfc16e6f7f964b7238c922c0d433118872", features = ["defmt"] }
30serde = { version = "1.0.203", default-features = false, features = ["derive"] } 30serde = { version = "1.0.203", default-features = false, features = ["derive"] }
31serde-json-core = "0.5.1" 31serde-json-core = "0.5.1"
32 32
@@ -50,7 +50,7 @@ usbd-hid = "0.9.0"
50embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 50embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
51embedded-hal-async = "1.0" 51embedded-hal-async = "1.0"
52embedded-hal-bus = { version = "0.1", features = ["async"] } 52embedded-hal-bus = { version = "0.1", features = ["async"] }
53embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 53embedded-io-async = { version = "0.7.0", features = ["defmt"] }
54embedded-storage = { version = "0.3" } 54embedded-storage = { version = "0.3" }
55static_cell = "2.1" 55static_cell = "2.1"
56portable-atomic = { version = "1.5", features = ["critical-section"] } 56portable-atomic = { version = "1.5", features = ["critical-section"] }
diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs
index 5cecb92f0..edc9a0c52 100644
--- a/examples/rp/src/bin/usb_webusb.rs
+++ b/examples/rp/src/bin/usb_webusb.rs
@@ -26,6 +26,7 @@ use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
26use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; 26use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb};
27use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; 27use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut};
28use embassy_usb::msos::{self, windows_version}; 28use embassy_usb::msos::{self, windows_version};
29use embassy_usb::types::InterfaceNumber;
29use embassy_usb::{Builder, Config}; 30use embassy_usb::{Builder, Config};
30use {defmt_rtt as _, panic_probe as _}; 31use {defmt_rtt as _, panic_probe as _};
31 32
@@ -56,7 +57,7 @@ async fn main(_spawner: Spawner) {
56 let mut config_descriptor = [0; 256]; 57 let mut config_descriptor = [0; 256];
57 let mut bos_descriptor = [0; 256]; 58 let mut bos_descriptor = [0; 256];
58 let mut control_buf = [0; 64]; 59 let mut control_buf = [0; 64];
59 let mut msos_descriptor = [0; 256]; 60 let mut msos_descriptor = [0; 512];
60 61
61 let webusb_config = WebUsbConfig { 62 let webusb_config = WebUsbConfig {
62 max_packet_size: 64, 63 max_packet_size: 64,
@@ -83,6 +84,14 @@ async fn main(_spawner: Spawner) {
83 // In principle you might want to call msos_feature() just on a specific function, 84 // In principle you might want to call msos_feature() just on a specific function,
84 // if your device also has other functions that still use standard class drivers. 85 // if your device also has other functions that still use standard class drivers.
85 builder.msos_descriptor(windows_version::WIN8_1, 0); 86 builder.msos_descriptor(windows_version::WIN8_1, 0);
87 builder.msos_writer().configuration(0);
88 builder.msos_writer().function(InterfaceNumber(0));
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 builder.msos_writer().function(InterfaceNumber(1));
86 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); 95 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
87 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( 96 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
88 "DeviceInterfaceGUIDs", 97 "DeviceInterfaceGUIDs",
diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml
index 16dfb5b77..bc2bcf5b6 100644
--- a/examples/rp235x/Cargo.toml
+++ b/examples/rp235x/Cargo.toml
@@ -51,7 +51,7 @@ usbd-hid = "0.9.0"
51embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 51embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
52embedded-hal-async = "1.0" 52embedded-hal-async = "1.0"
53embedded-hal-bus = { version = "0.1", features = ["async"] } 53embedded-hal-bus = { version = "0.1", features = ["async"] }
54embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 54embedded-io-async = { version = "0.7.0", features = ["defmt"] }
55embedded-storage = { version = "0.3" } 55embedded-storage = { version = "0.3" }
56static_cell = "2.1" 56static_cell = "2.1"
57portable-atomic = { version = "1.5", features = ["critical-section"] } 57portable-atomic = { version = "1.5", features = ["critical-section"] }
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 6dc6a353d..06f1ba67e 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -10,10 +10,10 @@ embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["lo
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] } 10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["log", "std", ] } 11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["log", "std", ] }
12embassy-net = { version = "0.7.1", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } 12embassy-net = { version = "0.7.1", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
13embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 13embassy-net-tuntap = { version = "0.1.1", path = "../../embassy-net-tuntap" }
14embassy-net-ppp = { version = "0.2.1", path = "../../embassy-net-ppp", features = ["log"]} 14embassy-net-ppp = { version = "0.2.1", path = "../../embassy-net-ppp", features = ["log"]}
15embedded-io-async = { version = "0.6.1" } 15embedded-io-async = { version = "0.7.0" }
16embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] } 16embedded-io-adapters = { version = "0.7.0", features = ["futures-03"] }
17critical-section = { version = "1.1", features = ["std"] } 17critical-section = { version = "1.1", features = ["std"] }
18 18
19async-io = "1.6.0" 19async-io = "1.6.0"
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index b4555045a..5bcf66ade 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -23,8 +23,8 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
23cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25embedded-hal-bus = { version = "0.2", features = ["async"] } 25embedded-hal-bus = { version = "0.2", features = ["async"] }
26embedded-io = { version = "0.6.0" } 26embedded-io = { version = "0.7.1" }
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.7.0" }
28panic-probe = { version = "1.0.0", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29futures-util = { version = "0.3.30", default-features = false } 29futures-util = { version = "0.3.30", default-features = false }
30heapless = { version = "0.8", default-features = false } 30heapless = { version = "0.8", default-features = false }
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 565277394..a952b770b 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -12,7 +12,7 @@ embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["de
12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embedded-io-async = { version = "0.6.1" } 15embedded-io-async = { version = "0.7.0" }
16embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defmt"] } 16embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18 18
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 16f28500d..a25a01e59 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -24,7 +24,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] }
24heapless = { version = "0.8", default-features = false } 24heapless = { version = "0.8", default-features = false }
25portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 25portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
26 26
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.7.0" }
28 28
29[profile.release] 29[profile.release]
30debug = 2 30debug = 2
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 512186c3d..f674a2936 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -23,8 +23,8 @@ cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.7.0" }
27embedded-nal-async = "0.8.0" 27embedded-nal-async = "0.9.0"
28panic-probe = { version = "1.0.0", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30critical-section = "1.1" 30critical-section = "1.1"
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 09b734054..8f4b2bf4f 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -24,8 +24,8 @@ cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 25embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
26embedded-hal-async = { version = "1.0" } 26embedded-hal-async = { version = "1.0" }
27embedded-nal-async = "0.8.0" 27embedded-nal-async = "0.9.0"
28embedded-io-async = { version = "0.6.1" } 28embedded-io-async = { version = "0.7.0" }
29panic-probe = { version = "1.0.0", features = ["print-defmt"] } 29panic-probe = { version = "1.0.0", features = ["print-defmt"] }
30heapless = { version = "0.8", default-features = false } 30heapless = { version = "0.8", default-features = false }
31critical-section = "1.1" 31critical-section = "1.1"
diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml
index 93a5109e2..8b3f8dc55 100644
--- a/examples/stm32h723/Cargo.toml
+++ b/examples/stm32h723/Cargo.toml
@@ -21,8 +21,8 @@ cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 22embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
23embedded-hal-async = { version = "1.0" } 23embedded-hal-async = { version = "1.0" }
24embedded-nal-async = "0.8.0" 24embedded-nal-async = "0.9.0"
25embedded-io-async = { version = "0.6.1" } 25embedded-io-async = { version = "0.7.0" }
26panic-probe = { version = "1.0.0", features = ["print-defmt"] } 26panic-probe = { version = "1.0.0", features = ["print-defmt"] }
27heapless = { version = "0.8", default-features = false } 27heapless = { version = "0.8", default-features = false }
28critical-section = "1.1" 28critical-section = "1.1"
diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml
index 9b5e5d93d..7ff4dfbe4 100644
--- a/examples/stm32h742/Cargo.toml
+++ b/examples/stm32h742/Cargo.toml
@@ -33,7 +33,7 @@ embassy-net = { version = "0.7.1", path = "../../embassy-net", features = [
33 "dhcpv4", 33 "dhcpv4",
34 "medium-ethernet", 34 "medium-ethernet",
35] } 35] }
36embedded-io-async = { version = "0.6.1" } 36embedded-io-async = { version = "0.7.0" }
37embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = [ 37embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = [
38 "defmt", 38 "defmt",
39] } 39] }
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
index d69f0228e..e5be0056f 100644
--- a/examples/stm32h755cm4/Cargo.toml
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -24,8 +24,8 @@ cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 25embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
26embedded-hal-async = { version = "1.0" } 26embedded-hal-async = { version = "1.0" }
27embedded-nal-async = "0.8.0" 27embedded-nal-async = "0.9.0"
28embedded-io-async = { version = "0.6.1" } 28embedded-io-async = { version = "0.7.0" }
29panic-probe = { version = "1.0.0", features = ["print-defmt"] } 29panic-probe = { version = "1.0.0", features = ["print-defmt"] }
30heapless = { version = "0.8", default-features = false } 30heapless = { version = "0.8", default-features = false }
31critical-section = "1.1" 31critical-section = "1.1"
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
index f4e1e53b7..42c05549b 100644
--- a/examples/stm32h755cm7/Cargo.toml
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -24,8 +24,8 @@ cortex-m-rt = "0.7.0"
24embedded-hal = "0.2.6" 24embedded-hal = "0.2.6"
25embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 25embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
26embedded-hal-async = { version = "1.0" } 26embedded-hal-async = { version = "1.0" }
27embedded-nal-async = "0.8.0" 27embedded-nal-async = "0.9.0"
28embedded-io-async = { version = "0.6.1" } 28embedded-io-async = { version = "0.7.0" }
29panic-probe = { version = "1.0.0", features = ["print-defmt"] } 29panic-probe = { version = "1.0.0", features = ["print-defmt"] }
30heapless = { version = "0.8", default-features = false } 30heapless = { version = "0.8", default-features = false }
31critical-section = "1.1" 31critical-section = "1.1"
diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml
index 0509d394d..434bfebce 100644
--- a/examples/stm32h7b0/Cargo.toml
+++ b/examples/stm32h7b0/Cargo.toml
@@ -23,8 +23,8 @@ cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = "0.8.0" 26embedded-nal-async = "0.9.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.7.0" }
28panic-probe = { version = "1.0.0", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30critical-section = "1.1" 30critical-section = "1.1"
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml
index ab525ad91..74664432f 100644
--- a/examples/stm32h7rs/Cargo.toml
+++ b/examples/stm32h7rs/Cargo.toml
@@ -23,8 +23,8 @@ cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = "0.8.0" 26embedded-nal-async = "0.9.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.7.0" }
28panic-probe = { version = "1.0.0", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30critical-section = "1.1" 30critical-section = "1.1"
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index a9c71d655..c06c761c9 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -18,8 +18,8 @@ defmt = "1.0.1"
18defmt-rtt = "1.0.0" 18defmt-rtt = "1.0.0"
19 19
20embedded-storage = "0.3.1" 20embedded-storage = "0.3.1"
21embedded-io = { version = "0.6.0" } 21embedded-io = { version = "0.7.1" }
22embedded-io-async = { version = "0.6.1" } 22embedded-io-async = { version = "0.7.0" }
23 23
24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 936472199..995c8c694 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -16,8 +16,8 @@ embassy-usb = { version = "0.5.0", path = "../../embassy-usb", features = ["defm
16embassy-net-adin1110 = { version = "0.3.1", path = "../../embassy-net-adin1110" } 16embassy-net-adin1110 = { version = "0.3.1", path = "../../embassy-net-adin1110" }
17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } 17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] }
18embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } 18embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
19embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 19embedded-io-async = { version = "0.7.0", features = ["defmt"] }
20embedded-io = { version = "0.6.0", features = ["defmt-03"] } 20embedded-io = { version = "0.7.1", features = ["defmt"] }
21 21
22defmt = "1.0.1" 22defmt = "1.0.1"
23defmt-rtt = "1.0.0" 23defmt-rtt = "1.0.0"
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 586b00836..b6d14ce25 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -24,7 +24,7 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing
24cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
25embedded-hal = "0.2.6" 25embedded-hal = "0.2.6"
26heapless = { version = "0.8", default-features = false } 26heapless = { version = "0.8", default-features = false }
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.7.0" }
28static_cell = "2" 28static_cell = "2"
29 29
30[profile.release] 30[profile.release]
diff --git a/examples/stm32n6/Cargo.toml b/examples/stm32n6/Cargo.toml
index 5ad5b97ce..fdfaed531 100644
--- a/examples/stm32n6/Cargo.toml
+++ b/examples/stm32n6/Cargo.toml
@@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-io-async = { version = "0.6.1" } 26embedded-io-async = { version = "0.7.0" }
27embedded-nal-async = "0.8.0" 27embedded-nal-async = "0.8.0"
28panic-probe = { version = "1.0.0", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 83f7cb56b..496500f75 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -7,10 +7,10 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9# Change stm32wb55rg to your chip name in both dependencies, if necessary. 9# Change stm32wb55rg to your chip name in both dependencies, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti", "low-power"] } 10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti", "low-power-pender"] }
11embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 11embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["defmt"] }
14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
15embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } 15embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true }
16 16
diff --git a/examples/stm32wb/src/bin/blinky.rs b/examples/stm32wb/src/bin/blinky.rs
index f37e8b1d8..e2737fcd5 100644
--- a/examples/stm32wb/src/bin/blinky.rs
+++ b/examples/stm32wb/src/bin/blinky.rs
@@ -7,7 +7,7 @@ use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_time::Timer; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
11async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!"); 13 info!("Hello World!");
diff --git a/examples/stm32wb/src/bin/button_exti.rs b/examples/stm32wb/src/bin/button_exti.rs
index 3c58eb556..37a207519 100644
--- a/examples/stm32wb/src/bin/button_exti.rs
+++ b/examples/stm32wb/src/bin/button_exti.rs
@@ -13,7 +13,7 @@ bind_interrupts!(
13 EXTI4 => exti::InterruptHandler<interrupt::typelevel::EXTI4>; 13 EXTI4 => exti::InterruptHandler<interrupt::typelevel::EXTI4>;
14}); 14});
15 15
16#[embassy_executor::main] 16#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
17async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
19 info!("Hello World!"); 19 info!("Hello World!");
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index 413b1ac8f..a679e6fb1 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs{
26 26
27const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; 27const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
28 28
29#[embassy_executor::main] 29#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
30async fn main(_spawner: Spawner) { 30async fn main(_spawner: Spawner) {
31 /* 31 /*
32 How to make this work: 32 How to make this work:
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
index 3484f1844..10c7fd0ba 100644
--- a/examples/stm32wb/src/bin/gatt_server.rs
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -38,7 +38,7 @@ bind_interrupts!(struct Irqs{
38 38
39const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; 39const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
40 40
41#[embassy_executor::main] 41#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
42async fn main(spawner: Spawner) { 42async fn main(spawner: Spawner) {
43 /* 43 /*
44 How to make this work: 44 How to make this work:
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
index 4bab6ea9f..cd15968d2 100644
--- a/examples/stm32wb/src/bin/mac_ffd.rs
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -23,7 +23,7 @@ async fn run_mm_queue(mut memory_manager: mm::MemoryManager<'static>) {
23 memory_manager.run_queue().await; 23 memory_manager.run_queue().await;
24} 24}
25 25
26#[embassy_executor::main] 26#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
27async fn main(spawner: Spawner) { 27async fn main(spawner: Spawner) {
28 /* 28 /*
29 How to make this work: 29 How to make this work:
diff --git a/examples/stm32wb/src/bin/mac_ffd_net.rs b/examples/stm32wb/src/bin/mac_ffd_net.rs
index b4789e3ee..244b35243 100644
--- a/examples/stm32wb/src/bin/mac_ffd_net.rs
+++ b/examples/stm32wb/src/bin/mac_ffd_net.rs
@@ -41,7 +41,7 @@ async fn run_net(mut runner: embassy_net::Runner<'static, Driver<'static>>) -> !
41 runner.run().await 41 runner.run().await
42} 42}
43 43
44#[embassy_executor::main] 44#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
45async fn main(spawner: Spawner) { 45async fn main(spawner: Spawner) {
46 /* 46 /*
47 How to make this work: 47 How to make this work:
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
index dae3c5200..f3e65c66b 100644
--- a/examples/stm32wb/src/bin/mac_rfd.rs
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -25,7 +25,7 @@ async fn run_mm_queue(mut memory_manager: mm::MemoryManager<'static>) {
25 memory_manager.run_queue().await; 25 memory_manager.run_queue().await;
26} 26}
27 27
28#[embassy_executor::main] 28#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
29async fn main(spawner: Spawner) { 29async fn main(spawner: Spawner) {
30 /* 30 /*
31 How to make this work: 31 How to make this work:
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
index 0902e28e8..adb6eff7b 100644
--- a/examples/stm32wb/src/bin/tl_mbox.rs
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs{
15 IPCC_C1_TX => TransmitInterruptHandler; 15 IPCC_C1_TX => TransmitInterruptHandler;
16}); 16});
17 17
18#[embassy_executor::main] 18#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
19async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
20 /* 20 /*
21 How to make this work: 21 How to make this work:
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 763dc32cd..376b808de 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -20,7 +20,7 @@ async fn run_mm_queue(mut memory_manager: mm::MemoryManager<'static>) {
20 memory_manager.run_queue().await; 20 memory_manager.run_queue().await;
21} 21}
22 22
23#[embassy_executor::main] 23#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
24async fn main(spawner: Spawner) { 24async fn main(spawner: Spawner) {
25 /* 25 /*
26 How to make this work: 26 How to make this work:
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index 235a48241..697e061c1 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -20,7 +20,7 @@ async fn run_mm_queue(mut memory_manager: mm::MemoryManager<'static>) {
20 memory_manager.run_queue().await; 20 memory_manager.run_queue().await;
21} 21}
22 22
23#[embassy_executor::main] 23#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
24async fn main(spawner: Spawner) { 24async fn main(spawner: Spawner) {
25 /* 25 /*
26 How to make this work: 26 How to make this work:
diff --git a/examples/stm32wba/src/bin/mac_ffd.rs b/examples/stm32wba/src/bin/mac_ffd.rs
index b15fb3452..329a73c6d 100644
--- a/examples/stm32wba/src/bin/mac_ffd.rs
+++ b/examples/stm32wba/src/bin/mac_ffd.rs
@@ -5,7 +5,7 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::Config; 6use embassy_stm32::Config;
7use embassy_stm32::rcc::{Sysclk, mux}; 7use embassy_stm32::rcc::{Sysclk, mux};
8use embassy_stm32_wpan::bindings::mac::ST_MAC_callbacks_t; 8use embassy_stm32_wpan::bindings::mac::{ST_MAC_callbacks_t, ST_MAC_init};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11static _MAC_CALLBACKS: ST_MAC_callbacks_t = ST_MAC_callbacks_t { 11static _MAC_CALLBACKS: ST_MAC_callbacks_t = ST_MAC_callbacks_t {
@@ -50,9 +50,9 @@ async fn main(_spawner: Spawner) {
50 let _p = embassy_stm32::init(config); 50 let _p = embassy_stm32::init(config);
51 info!("Hello World!"); 51 info!("Hello World!");
52 52
53 // let status = unsafe { ST_MAC_init(&_MAC_CALLBACKS as *const _ as *mut _) }; 53 let status = unsafe { ST_MAC_init(&_MAC_CALLBACKS as *const _ as *mut _) };
54 // 54
55 // info!("mac init: {}", status); 55 info!("mac init: {}", status);
56 56
57 cortex_m::asm::bkpt(); 57 cortex_m::asm::bkpt();
58} 58}
diff --git a/examples/stm32wl5x-lp/.cargo/config.toml b/examples/stm32wl5x-lp/.cargo/config.toml
new file mode 100644
index 000000000..969068656
--- /dev/null
+++ b/examples/stm32wl5x-lp/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip STM32WLE5JCIx --connect-under-reset"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/stm32wl5x-lp/Cargo.toml b/examples/stm32wl5x-lp/Cargo.toml
new file mode 100644
index 000000000..b1823fb8a
--- /dev/null
+++ b/examples/stm32wl5x-lp/Cargo.toml
@@ -0,0 +1,39 @@
1[package]
2edition = "2024"
3name = "embassy-stm32wl5x-lp"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9# Change stm32wl55jc-cm4 to your chip name, if necessary.
10embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono", "low-power-pender"] }
11embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal" }
15
16defmt = "1.0.1"
17defmt-rtt = { version = "1.1.0", optional = true }
18defmt-serial = { git = "https://github.com/gauteh/defmt-serial", rev = "411ae7fa909b4fd2667885aff687e009b9108190", optional = true }
19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0"
22embedded-hal = "1.0.0"
23embedded-storage = "0.3.1"
24panic-probe = { version = "1.0.0", features = ["print-defmt"] }
25chrono = { version = "^0.4", default-features = false }
26static_cell = { version = "2.1.1", default-features = false }
27
28[profile.release]
29debug = 2
30
31[package.metadata.embassy]
32build = [
33 { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/stm32wl" }
34]
35
36[features]
37default = ["defmt-serial"]
38defmt-rtt = ["dep:defmt-rtt"]
39defmt-serial = ["dep:defmt-serial"]
diff --git a/examples/stm32wl5x-lp/build.rs b/examples/stm32wl5x-lp/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32wl5x-lp/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32wl5x-lp/memory.x b/examples/stm32wl5x-lp/memory.x
new file mode 100644
index 000000000..4590867a8
--- /dev/null
+++ b/examples/stm32wl5x-lp/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K
5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
6 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128
7}
8
9SECTIONS
10{
11 .shared_data :
12 {
13 *(.shared_data)
14 } > SHARED_RAM
15}
diff --git a/examples/stm32wl5x-lp/src/bin/blinky.rs b/examples/stm32wl5x-lp/src/bin/blinky.rs
new file mode 100644
index 000000000..60b671a77
--- /dev/null
+++ b/examples/stm32wl5x-lp/src/bin/blinky.rs
@@ -0,0 +1,57 @@
1// This example is configured for the nucleo-wl55jc board. Curret monitor should show just a few microamps when the device is in stop2 mode.
2#![no_std]
3#![no_main]
4
5use core::mem::MaybeUninit;
6
7use defmt::*;
8#[cfg(feature = "defmt-rtt")]
9use defmt_rtt as _;
10use embassy_executor::Spawner;
11use embassy_stm32::SharedData;
12use embassy_stm32::gpio::{Level, Output, Speed};
13use embassy_time::Timer;
14use panic_probe as _;
15
16#[unsafe(link_section = ".shared_data")]
17static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
18
19#[embassy_executor::main(executor = "embassy_stm32::Executor", entry = "cortex_m_rt::entry")]
20async fn async_main(_spawner: Spawner) {
21 let mut config = embassy_stm32::Config::default();
22 config.rcc.ls = embassy_stm32::rcc::LsConfig::default_lsi();
23 config.rcc.msi = Some(embassy_stm32::rcc::MSIRange::RANGE4M);
24 config.rcc.sys = embassy_stm32::rcc::Sysclk::MSI;
25 #[cfg(feature = "defmt-serial")]
26 {
27 // disable debug during sleep to reduce power consumption since we are
28 // using defmt-serial on LPUART1.
29 config.enable_debug_during_sleep = false;
30 }
31 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
32
33 #[cfg(feature = "defmt-serial")]
34 {
35 use embassy_stm32::mode::Blocking;
36 use embassy_stm32::usart::Uart;
37 use static_cell::StaticCell;
38 let config = embassy_stm32::usart::Config::default();
39 let uart = Uart::new_blocking(p.LPUART1, p.PA3, p.PA2, config).expect("failed to configure UART!");
40 static SERIAL: StaticCell<Uart<'static, Blocking>> = StaticCell::new();
41 defmt_serial::defmt_serial(SERIAL.init(uart));
42 }
43
44 info!("Hello World!");
45
46 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
47
48 loop {
49 info!("low");
50 led.set_low();
51 Timer::after_millis(5000).await;
52
53 info!("high");
54 led.set_high();
55 Timer::after_millis(5000).await;
56 }
57}
diff --git a/examples/stm32wle5/Cargo.toml b/examples/stm32wle5/Cargo.toml
index f2fc4dd3d..64c81c761 100644
--- a/examples/stm32wle5/Cargo.toml
+++ b/examples/stm32wle5/Cargo.toml
@@ -15,7 +15,7 @@ embassy-embedded-hal = { version = "0.5.0", path = "../../embassy-embedded-hal"
15 15
16defmt = "1.0.1" 16defmt = "1.0.1"
17defmt-rtt = { version = "1.1.0", optional = true } 17defmt-rtt = { version = "1.1.0", optional = true }
18defmt-serial = { version = "0.10.0", optional = true } 18defmt-serial = { git = "https://github.com/gauteh/defmt-serial", rev = "411ae7fa909b4fd2667885aff687e009b9108190", optional = true }
19 19
20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
diff --git a/examples/stm32wle5/src/bin/adc.rs b/examples/stm32wle5/src/bin/adc.rs
index ea91fb063..8cc84ccdf 100644
--- a/examples/stm32wle5/src/bin/adc.rs
+++ b/examples/stm32wle5/src/bin/adc.rs
@@ -34,24 +34,6 @@ async fn async_main(_spawner: Spawner) {
34 // Initialize STM32WL peripherals (use default config like wio-e5-async example) 34 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
35 let p = embassy_stm32::init(config); 35 let p = embassy_stm32::init(config);
36 36
37 // start with all GPIOs as analog to reduce power consumption
38 for r in [
39 embassy_stm32::pac::GPIOA,
40 embassy_stm32::pac::GPIOB,
41 embassy_stm32::pac::GPIOC,
42 embassy_stm32::pac::GPIOH,
43 ] {
44 r.moder().modify(|w| {
45 for i in 0..16 {
46 // don't reset these if probe-rs should stay connected!
47 #[cfg(feature = "defmt-rtt")]
48 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
49 continue;
50 }
51 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
52 }
53 });
54 }
55 #[cfg(feature = "defmt-serial")] 37 #[cfg(feature = "defmt-serial")]
56 { 38 {
57 use embassy_stm32::mode::Blocking; 39 use embassy_stm32::mode::Blocking;
diff --git a/examples/stm32wle5/src/bin/blinky.rs b/examples/stm32wle5/src/bin/blinky.rs
index 9f0c04672..3b7eb7761 100644
--- a/examples/stm32wle5/src/bin/blinky.rs
+++ b/examples/stm32wle5/src/bin/blinky.rs
@@ -32,24 +32,6 @@ async fn async_main(_spawner: Spawner) {
32 // Initialize STM32WL peripherals (use default config like wio-e5-async example) 32 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
33 let p = embassy_stm32::init(config); 33 let p = embassy_stm32::init(config);
34 34
35 // start with all GPIOs as analog to reduce power consumption
36 for r in [
37 embassy_stm32::pac::GPIOA,
38 embassy_stm32::pac::GPIOB,
39 embassy_stm32::pac::GPIOC,
40 embassy_stm32::pac::GPIOH,
41 ] {
42 r.moder().modify(|w| {
43 for i in 0..16 {
44 // don't reset these if probe-rs should stay connected!
45 #[cfg(feature = "defmt-rtt")]
46 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
47 continue;
48 }
49 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
50 }
51 });
52 }
53 #[cfg(feature = "defmt-serial")] 35 #[cfg(feature = "defmt-serial")]
54 { 36 {
55 use embassy_stm32::mode::Blocking; 37 use embassy_stm32::mode::Blocking;
@@ -67,10 +49,10 @@ async fn async_main(_spawner: Spawner) {
67 loop { 49 loop {
68 info!("low"); 50 info!("low");
69 led.set_low(); 51 led.set_low();
70 Timer::after_millis(500).await; 52 Timer::after_millis(15000).await;
71 53
72 info!("high"); 54 info!("high");
73 led.set_high(); 55 led.set_high();
74 Timer::after_millis(500).await; 56 Timer::after_millis(15000).await;
75 } 57 }
76} 58}
diff --git a/examples/stm32wle5/src/bin/button_exti.rs b/examples/stm32wle5/src/bin/button_exti.rs
index f248b6147..9ffc39948 100644
--- a/examples/stm32wle5/src/bin/button_exti.rs
+++ b/examples/stm32wle5/src/bin/button_exti.rs
@@ -39,24 +39,6 @@ async fn async_main(_spawner: Spawner) {
39 // Initialize STM32WL peripherals (use default config like wio-e5-async example) 39 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
40 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init(config);
41 41
42 // start with all GPIOs as analog to reduce power consumption
43 for r in [
44 embassy_stm32::pac::GPIOA,
45 embassy_stm32::pac::GPIOB,
46 embassy_stm32::pac::GPIOC,
47 embassy_stm32::pac::GPIOH,
48 ] {
49 r.moder().modify(|w| {
50 for i in 0..16 {
51 // don't reset these if probe-rs should stay connected!
52 #[cfg(feature = "defmt-rtt")]
53 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
54 continue;
55 }
56 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
57 }
58 });
59 }
60 #[cfg(feature = "defmt-serial")] 42 #[cfg(feature = "defmt-serial")]
61 { 43 {
62 use embassy_stm32::mode::Blocking; 44 use embassy_stm32::mode::Blocking;
diff --git a/examples/stm32wle5/src/bin/i2c.rs b/examples/stm32wle5/src/bin/i2c.rs
index 68c17a672..8e7a6e2d8 100644
--- a/examples/stm32wle5/src/bin/i2c.rs
+++ b/examples/stm32wle5/src/bin/i2c.rs
@@ -40,24 +40,6 @@ async fn async_main(_spawner: Spawner) {
40 // Initialize STM32WL peripherals (use default config like wio-e5-async example) 40 // Initialize STM32WL peripherals (use default config like wio-e5-async example)
41 let p = embassy_stm32::init(config); 41 let p = embassy_stm32::init(config);
42 42
43 // start with all GPIOs as analog to reduce power consumption
44 for r in [
45 embassy_stm32::pac::GPIOA,
46 embassy_stm32::pac::GPIOB,
47 embassy_stm32::pac::GPIOC,
48 embassy_stm32::pac::GPIOH,
49 ] {
50 r.moder().modify(|w| {
51 for i in 0..16 {
52 // don't reset these if probe-rs should stay connected!
53 #[cfg(feature = "defmt-rtt")]
54 if config.enable_debug_during_sleep && r == embassy_stm32::pac::GPIOA && [13, 14].contains(&i) {
55 continue;
56 }
57 w.set_moder(i, embassy_stm32::pac::gpio::vals::Moder::ANALOG);
58 }
59 });
60 }
61 #[cfg(feature = "defmt-serial")] 43 #[cfg(feature = "defmt-serial")]
62 { 44 {
63 use embassy_stm32::mode::Blocking; 45 use embassy_stm32::mode::Blocking;
@@ -79,7 +61,7 @@ async fn async_main(_spawner: Spawner) {
79 let mut i2c = I2c::new(p.I2C2, p.PB15, p.PA15, IrqsI2C, p.DMA1_CH6, p.DMA1_CH7, { 61 let mut i2c = I2c::new(p.I2C2, p.PB15, p.PA15, IrqsI2C, p.DMA1_CH6, p.DMA1_CH7, {
80 let mut config = i2c::Config::default(); 62 let mut config = i2c::Config::default();
81 config.frequency = Hertz::khz(100); 63 config.frequency = Hertz::khz(100);
82 config.timeout = Duration::from_millis(500); 64 config.timeout = Duration::from_millis(1000);
83 config 65 config
84 }); 66 });
85 67
diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml
index df52b538d..56b027feb 100644
--- a/tests/mspm0/Cargo.toml
+++ b/tests/mspm0/Cargo.toml
@@ -26,8 +26,8 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-sin
26cortex-m-rt = "0.7.0" 26cortex-m-rt = "0.7.0"
27embedded-hal = { package = "embedded-hal", version = "1.0" } 27embedded-hal = { package = "embedded-hal", version = "1.0" }
28embedded-hal-async = { version = "1.0" } 28embedded-hal-async = { version = "1.0" }
29embedded-io = { version = "0.6.1", features = ["defmt-03"] } 29embedded-io = { version = "0.7.1", features = ["defmt"] }
30embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 30embedded-io-async = { version = "0.7.0", features = ["defmt"] }
31panic-probe = { version = "1.0.0", features = ["print-defmt"] } 31panic-probe = { version = "1.0.0", features = ["print-defmt"] }
32static_cell = "2" 32static_cell = "2"
33portable-atomic = { version = "1.5", features = ["critical-section"] } 33portable-atomic = { version = "1.5", features = ["critical-section"] }
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 3a9b86cef..b1e0a68c2 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -12,8 +12,8 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] }
13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
15embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } 15embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] }
16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 16embedded-io-async = { version = "0.7.0", features = ["defmt"] }
17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
19embassy-net-enc28j60 = { version = "0.2.1", path = "../../embassy-net-enc28j60", features = ["defmt"] } 19embassy-net-enc28j60 = { version = "0.2.1", path = "../../embassy-net-enc28j60", features = ["defmt"] }
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 4dfe6904e..375a613d2 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -35,7 +35,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
35embedded-hal-async = { version = "1.0" } 35embedded-hal-async = { version = "1.0" }
36embedded-hal-bus = { version = "0.1", features = ["async"] } 36embedded-hal-bus = { version = "0.1", features = ["async"] }
37panic-probe = { version = "1.0.0", features = ["print-defmt"] } 37panic-probe = { version = "1.0.0", features = ["print-defmt"] }
38embedded-io-async = { version = "0.6.1" } 38embedded-io-async = { version = "0.7.0" }
39embedded-storage = { version = "0.3" } 39embedded-storage = { version = "0.3" }
40static_cell = "2" 40static_cell = "2"
41portable-atomic = { version = "1.5", features = ["critical-section"] } 41portable-atomic = { version = "1.5", features = ["critical-section"] }
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
index 83c375bc5..75dacbe7e 100644
--- a/tests/stm32/src/bin/stop.rs
+++ b/tests/stm32/src/bin/stop.rs
@@ -60,10 +60,12 @@ async fn async_main(spawner: Spawner) {
60 60
61 let (rtc, _time_provider) = Rtc::new(p.RTC); 61 let (rtc, _time_provider) = Rtc::new(p.RTC);
62 62
63 info!("set datetime");
63 critical_section::with(|cs| { 64 critical_section::with(|cs| {
64 rtc.borrow_mut(cs).set_datetime(now.into()).expect("datetime not set"); 65 rtc.borrow_mut(cs).set_datetime(now.into()).expect("datetime not set");
65 }); 66 });
66 67
68 info!("spawn");
67 spawner.spawn(task_1().unwrap()); 69 spawner.spawn(task_1().unwrap());
68 spawner.spawn(task_2().unwrap()); 70 spawner.spawn(task_2().unwrap());
69} 71}