aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/build-xtensa.sh2
-rw-r--r--.vscode/settings.json1
-rwxr-xr-xci.sh2
-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/arch/std.rs15
-rw-r--r--embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr10
-rw-r--r--embassy-imxrt/Cargo.toml4
-rw-r--r--embassy-imxrt/src/dma.rs8
-rw-r--r--embassy-imxrt/src/flexcomm/mod.rs1
-rw-r--r--embassy-imxrt/src/flexcomm/spi.rs1011
-rw-r--r--embassy-imxrt/src/flexcomm/uart.rs4
-rw-r--r--embassy-mcxa/Cargo.toml5
-rw-r--r--embassy-mcxa/src/clocks/mod.rs2
-rw-r--r--embassy-mcxa/src/interrupt.rs1
-rw-r--r--embassy-mcxa/src/lib.rs1
-rw-r--r--embassy-mcxa/src/trng.rs678
-rw-r--r--embassy-mspm0/CHANGELOG.md3
-rw-r--r--embassy-mspm0/Cargo.toml145
-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-net-nrf91/CHANGELOG.md6
-rw-r--r--embassy-net-nrf91/Cargo.toml6
-rw-r--r--embassy-net-nrf91/src/lib.rs5
-rw-r--r--embassy-net-tuntap/Cargo.toml4
-rw-r--r--embassy-net-tuntap/src/lib.rs12
-rw-r--r--embassy-nrf/CHANGELOG.md3
-rw-r--r--embassy-nrf/Cargo.toml6
-rw-r--r--embassy-nrf/src/gpiote.rs15
-rw-r--r--embassy-nrf/src/lib.rs4
-rw-r--r--embassy-nrf/src/rramc.rs173
-rw-r--r--embassy-nrf/src/twim.rs2
-rw-r--r--embassy-stm32-wpan/Cargo.toml8
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/ble.rs12
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/mm.rs14
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/sys.rs6
-rw-r--r--embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs358
-rw-r--r--embassy-stm32-wpan/src/wba/linklayer_plat.rs1125
-rw-r--r--embassy-stm32/CHANGELOG.md3
-rw-r--r--embassy-stm32/Cargo.toml11
-rw-r--r--embassy-stm32/build.rs54
-rw-r--r--embassy-stm32/src/adc/adc4.rs21
-rw-r--r--embassy-stm32/src/adc/mod.rs8
-rw-r--r--embassy-stm32/src/adc/v4.rs8
-rw-r--r--embassy-stm32/src/hsem/mod.rs30
-rw-r--r--embassy-stm32/src/i2c/mod.rs2
-rw-r--r--embassy-stm32/src/ipcc.rs9
-rw-r--r--embassy-stm32/src/lib.rs3
-rw-r--r--embassy-stm32/src/low_power.rs112
-rw-r--r--embassy-stm32/src/rcc/l.rs9
-rw-r--r--embassy-stm32/src/rcc/mod.rs28
-rw-r--r--embassy-stm32/src/rcc/u5.rs10
-rw-r--r--embassy-stm32/src/rng.rs25
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs69
-rw-r--r--embassy-stm32/src/sdmmc/sd.rs58
-rw-r--r--embassy-stm32/src/sdmmc/sdio.rs27
-rw-r--r--embassy-stm32/src/spi/mod.rs2
-rw-r--r--embassy-stm32/src/timer/input_capture.rs42
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs10
-rw-r--r--embassy-sync/src/pipe.rs2
-rw-r--r--embassy-usb-dfu/Cargo.toml2
-rw-r--r--embassy-usb/src/msos.rs4
-rw-r--r--examples/boot/application/nrf/Cargo.toml4
-rw-r--r--examples/mcxa/Cargo.toml1
-rw-r--r--examples/mcxa/src/bin/trng.rs106
-rw-r--r--examples/mimxrt6/Cargo.toml2
-rw-r--r--examples/mimxrt6/src/bin/dma.rs26
-rw-r--r--examples/mimxrt6/src/bin/spi-async.rs35
-rw-r--r--examples/mimxrt6/src/bin/spi.rs51
-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.toml2
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/nrf54l15/Cargo.toml2
-rw-r--r--examples/nrf54l15/src/bin/rramc.rs (renamed from examples/nrf54l15/src/bin/nvmc.rs)0
-rw-r--r--examples/nrf54l15/src/bin/rramc_buffered.rs59
-rw-r--r--examples/nrf54lm20/Cargo.toml2
-rw-r--r--examples/nrf9151/ns/Cargo.toml2
-rw-r--r--examples/nrf9151/s/Cargo.toml2
-rw-r--r--examples/nrf9160/Cargo.toml2
-rw-r--r--examples/rp/src/bin/usb_webusb.rs11
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/std/src/bin/net_ppp.rs9
-rw-r--r--examples/std/src/bin/tick_cancel.rs47
-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/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--rust-toolchain-nightly.toml2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/nrf/Cargo.toml2
120 files changed, 4010 insertions, 999 deletions
diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh
index f07816861..cc56adb26 100755
--- a/.github/ci/build-xtensa.sh
+++ b/.github/ci/build-xtensa.sh
@@ -14,7 +14,7 @@ export PATH=$CARGO_HOME/bin:$PATH
14export CARGO_NET_GIT_FETCH_WITH_CLI=true 14export CARGO_NET_GIT_FETCH_WITH_CLI=true
15 15
16cargo install espup --locked 16cargo install espup --locked
17espup install --toolchain-version 1.88.0.0 17espup install --toolchain-version 1.90.0.0
18 18
19# Restore lockfiles 19# Restore lockfiles
20if [ -f /ci/cache/lockfiles.tar ]; then 20if [ -f /ci/cache/lockfiles.tar ]; then
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 4f78f70cf..1eecd158f 100755
--- a/ci.sh
+++ b/ci.sh
@@ -35,7 +35,7 @@ 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
39rm 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?
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 5fbb8cf13..8f1db7de7 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15- Added optional "earliest deadline first" EDF scheduling 15- Added optional "earliest deadline first" EDF scheduling
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 19
19## 0.9.1 - 2025-08-31 20## 0.9.1 - 2025-08-31
20 21
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
index c62ab723b..d4057144e 100644
--- a/embassy-executor/src/arch/std.rs
+++ b/embassy-executor/src/arch/std.rs
@@ -55,11 +55,24 @@ mod thread {
55 /// 55 ///
56 /// This function never returns. 56 /// This function never returns.
57 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 57 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
58 self.run_until(init, || false);
59 unreachable!()
60 }
61
62 /// Run the executor until a flag is raised.
63 ///
64 /// This function is identical to `Executor::run()` apart from offering a `done` flag to stop execution.
65 pub fn run_until(&'static mut self, init: impl FnOnce(Spawner), mut done: impl FnMut() -> bool) {
58 init(self.inner.spawner()); 66 init(self.inner.spawner());
59 67
60 loop { 68 loop {
61 unsafe { self.inner.poll() }; 69 unsafe { self.inner.poll() };
62 self.signaler.wait() 70
71 if done() {
72 break;
73 }
74
75 self.signaler.wait();
63 } 76 }
64 } 77 }
65 } 78 }
diff --git a/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
index 3c3c9503b..e5e069ade 100644
--- a/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
+++ b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
@@ -5,6 +5,10 @@ error[E0277]: task futures must resolve to `()` or `!`
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskReturnValue` is not implemented for `u32` 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskReturnValue` is not implemented for `u32`
6 | 6 |
7 = note: use `async fn` or change the return type to `impl Future<Output = ()>` 7 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
8 = help: the following other types implement trait `TaskReturnValue`: 8help: the following other types implement trait `TaskReturnValue`
9 () 9 --> src/lib.rs
10 <fn() -> ! as HasOutput>::Output 10 |
11 | impl TaskReturnValue for () {}
12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()`
13 | impl TaskReturnValue for Never {}
14 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<fn() -> ! as HasOutput>::Output`
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index c47756f10..81377579b 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -103,5 +103,5 @@ document-features = "0.2.7"
103paste = "1.0" 103paste = "1.0"
104 104
105# PACs 105# PACs
106mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } 106mimxrt685s-pac = { version = "0.5.0", optional = true, features = ["rt", "critical-section"] }
107mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } 107mimxrt633s-pac = { version = "0.5.0", optional = true, features = ["rt", "critical-section"] }
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/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs
index 27794042b..ed87c7fb4 100644
--- a/embassy-imxrt/src/flexcomm/mod.rs
+++ b/embassy-imxrt/src/flexcomm/mod.rs
@@ -1,5 +1,6 @@
1//! Implements Flexcomm interface wrapper for easier usage across modules 1//! Implements Flexcomm interface wrapper for easier usage across modules
2 2
3pub mod spi;
3pub mod uart; 4pub mod uart;
4 5
5use paste::paste; 6use paste::paste;
diff --git a/embassy-imxrt/src/flexcomm/spi.rs b/embassy-imxrt/src/flexcomm/spi.rs
new file mode 100644
index 000000000..9dd776ac7
--- /dev/null
+++ b/embassy-imxrt/src/flexcomm/spi.rs
@@ -0,0 +1,1011 @@
1//! Serial Peripheral Interface (SPI) driver.
2
3use core::future::{Future, poll_fn};
4use core::marker::PhantomData;
5use core::task::Poll;
6
7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::{Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10pub use embedded_hal_1::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
11use paste::paste;
12
13use crate::flexcomm::Clock;
14use crate::gpio::{AnyPin, GpioPin as Pin};
15use crate::interrupt;
16use crate::interrupt::typelevel::Interrupt;
17use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate};
18use crate::pac::spi0::cfg::{Cpha, Cpol};
19
20/// Driver move trait.
21#[allow(private_bounds)]
22pub trait IoMode: sealed::Sealed {}
23
24/// Blocking mode.
25pub struct Blocking;
26impl sealed::Sealed for Blocking {}
27impl IoMode for Blocking {}
28
29/// Async mode.
30pub struct Async;
31impl sealed::Sealed for Async {}
32impl IoMode for Async {}
33
34/// Spi errors.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37#[non_exhaustive]
38pub enum Error {
39 // No errors for now.
40}
41
42/// Spi driver.
43pub struct Spi<'a, M: IoMode> {
44 info: Info,
45 _phantom: PhantomData<&'a M>,
46}
47
48impl<'a> Spi<'a, Blocking> {
49 /// Create a SPI driver in blocking mode.
50 pub fn new_blocking<T: Instance>(
51 _inner: Peri<'a, T>,
52 sck: Peri<'a, impl SckPin<T> + 'a>,
53 mosi: Peri<'a, impl MosiPin<T> + 'a>,
54 miso: Peri<'a, impl MisoPin<T> + 'a>,
55 config: Config,
56 ) -> Self {
57 sck.as_sck();
58 mosi.as_mosi();
59 miso.as_miso();
60
61 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), Some(miso.into()), config)
62 }
63
64 /// Create a TX-only SPI driver in blocking mode.
65 pub fn new_blocking_txonly<T: Instance>(
66 _inner: Peri<'a, T>,
67 sck: Peri<'a, impl SckPin<T> + 'a>,
68 mosi: Peri<'a, impl MosiPin<T> + 'a>,
69 config: Config,
70 ) -> Self {
71 sck.as_sck();
72 mosi.as_mosi();
73
74 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), None, config)
75 }
76
77 /// Create an RX-only SPI driver in blocking mode.
78 pub fn new_blocking_rxonly<T: Instance>(
79 _inner: Peri<'a, T>,
80 sck: Peri<'a, impl SckPin<T> + 'a>,
81 miso: Peri<'a, impl MisoPin<T> + 'a>,
82 config: Config,
83 ) -> Self {
84 sck.as_sck();
85 miso.as_miso();
86
87 Self::new_inner(_inner, Some(sck.into()), None, Some(miso.into()), config)
88 }
89
90 /// Create an internal-loopback SPI driver in blocking mode.
91 ///
92 /// WARNING: This is only useful for testing as it doesn't use any
93 /// external pins.
94 pub fn new_blocking_loopback<T: Instance>(_inner: Peri<'a, T>, config: Config) -> Self {
95 Self::new_inner(_inner, None, None, None, config)
96 }
97}
98
99impl<'a, M: IoMode> Spi<'a, M> {
100 /// Read data from Spi blocking execution until done.
101 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
102 critical_section::with(|_| {
103 self.info
104 .regs
105 .fifostat()
106 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
107
108 for word in data.iter_mut() {
109 // wait until we have data in the RxFIFO.
110 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
111
112 self.info
113 .regs
114 .fifowr()
115 .write(|w| unsafe { w.txdata().bits(*word as u16).len().bits(7) });
116
117 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
118 }
119 });
120
121 self.flush()
122 }
123
124 /// Write data to Spi blocking execution until done.
125 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
126 critical_section::with(|_| {
127 self.info
128 .regs
129 .fifostat()
130 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
131
132 for (i, word) in data.iter().enumerate() {
133 // wait until we have space in the TxFIFO.
134 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
135
136 self.info.regs.fifowr().write(|w| {
137 unsafe { w.txdata().bits(*word as u16).len().bits(7) }
138 .rxignore()
139 .set_bit();
140
141 if i == data.len() - 1 {
142 w.eot().set_bit();
143 }
144
145 w
146 });
147 }
148 });
149
150 self.flush()
151 }
152
153 /// Transfer data to SPI blocking execution until done.
154 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
155 let len = read.len().max(write.len());
156
157 critical_section::with(|_| {
158 self.info
159 .regs
160 .fifostat()
161 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
162
163 for i in 0..len {
164 let wb = write.get(i).copied().unwrap_or(0);
165
166 // wait until we have space in the TxFIFO.
167 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
168
169 self.info.regs.fifowr().write(|w| {
170 unsafe { w.txdata().bits(wb as u16).len().bits(7) };
171
172 if i == len - 1 {
173 w.eot().set_bit();
174 }
175
176 w
177 });
178
179 // wait until we have data in the RxFIFO.
180 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
181
182 let rb = self.info.regs.fiford().read().rxdata().bits() as u8;
183
184 if let Some(r) = read.get_mut(i) {
185 *r = rb;
186 }
187 }
188 });
189
190 self.flush()
191 }
192
193 /// Transfer data in place to SPI blocking execution until done.
194 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
195 critical_section::with(|_| {
196 self.info
197 .regs
198 .fifostat()
199 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
200
201 for word in data {
202 // wait until we have space in the TxFIFO.
203 while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {}
204 self.info
205 .regs
206 .fifowr()
207 .write(|w| unsafe { w.txdata().bits(*word as u16) });
208
209 // wait until we have data in the RxFIFO.
210 while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {}
211 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
212 }
213 });
214
215 self.flush()
216 }
217
218 /// Block execution until Spi is done.
219 pub fn flush(&mut self) -> Result<(), Error> {
220 let regs = self.info.regs;
221 while regs.stat().read().mstidle().bit_is_clear() {}
222 Ok(())
223 }
224}
225
226impl<'a> Spi<'a, Async> {
227 /// Create a SPI driver in async mode.
228 pub fn new_async<T: Instance>(
229 _inner: Peri<'a, T>,
230 sck: Peri<'a, impl SckPin<T> + 'a>,
231 mosi: Peri<'a, impl MosiPin<T> + 'a>,
232 miso: Peri<'a, impl MisoPin<T> + 'a>,
233 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
234 config: Config,
235 ) -> Self {
236 sck.as_sck();
237 mosi.as_mosi();
238 miso.as_miso();
239
240 T::Interrupt::unpend();
241 unsafe { T::Interrupt::enable() };
242
243 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), Some(miso.into()), config)
244 }
245
246 /// Create a TX-only SPI driver in async mode.
247 pub fn new_async_txonly<T: Instance>(
248 _inner: Peri<'a, T>,
249 sck: Peri<'a, impl SckPin<T> + 'a>,
250 mosi: Peri<'a, impl MosiPin<T> + 'a>,
251 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
252 config: Config,
253 ) -> Self {
254 sck.as_sck();
255 mosi.as_mosi();
256
257 T::Interrupt::unpend();
258 unsafe { T::Interrupt::enable() };
259
260 Self::new_inner(_inner, Some(sck.into()), Some(mosi.into()), None, config)
261 }
262
263 /// Create an RX-only SPI driver in async mode.
264 pub fn new_async_rxonly<T: Instance>(
265 _inner: Peri<'a, T>,
266 sck: Peri<'a, impl SckPin<T> + 'a>,
267 miso: Peri<'a, impl MisoPin<T> + 'a>,
268 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
269 config: Config,
270 ) -> Self {
271 sck.as_sck();
272 miso.as_miso();
273
274 T::Interrupt::unpend();
275 unsafe { T::Interrupt::enable() };
276
277 Self::new_inner(_inner, Some(sck.into()), None, Some(miso.into()), config)
278 }
279
280 /// Create an internal-loopback SPI driver in async mode.
281 ///
282 /// WARNING: This is only useful for testing as it doesn't use any
283 /// external pins.
284 pub fn new_async_loopback<T: Instance>(
285 _inner: Peri<'a, T>,
286 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
287 config: Config,
288 ) -> Self {
289 T::Interrupt::unpend();
290 unsafe { T::Interrupt::enable() };
291
292 Self::new_inner(_inner, None, None, None, config)
293 }
294
295 /// Read data from Spi async execution until done.
296 pub async fn async_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
297 critical_section::with(|_| {
298 self.info
299 .regs
300 .fifostat()
301 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
302 });
303
304 for word in data.iter_mut() {
305 // wait until we have data in the RxFIFO.
306 self.wait_for(
307 |me| {
308 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
309 Poll::Ready(())
310 } else {
311 Poll::Pending
312 }
313 },
314 |me| {
315 me.info
316 .regs
317 .fifointenset()
318 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
319 },
320 )
321 .await;
322
323 self.info
324 .regs
325 .fifowr()
326 .write(|w| unsafe { w.txdata().bits(*word as u16).len().bits(7) });
327
328 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
329 }
330
331 self.async_flush().await;
332
333 Ok(())
334 }
335
336 /// Write data to Spi async execution until done.
337 pub async fn async_write(&mut self, data: &[u8]) -> Result<(), Error> {
338 critical_section::with(|_| {
339 self.info
340 .regs
341 .fifostat()
342 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
343 });
344
345 for (i, word) in data.iter().enumerate() {
346 // wait until we have space in the TxFIFO.
347 self.wait_for(
348 |me| {
349 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
350 Poll::Ready(())
351 } else {
352 Poll::Pending
353 }
354 },
355 |me| {
356 me.info
357 .regs
358 .fifointenset()
359 .write(|w| w.txlvl().set_bit().txerr().set_bit());
360 },
361 )
362 .await;
363
364 self.info.regs.fifowr().write(|w| {
365 unsafe { w.txdata().bits(*word as u16).len().bits(7) }
366 .rxignore()
367 .set_bit();
368
369 if i == data.len() - 1 {
370 w.eot().set_bit();
371 }
372
373 w
374 });
375 }
376
377 self.async_flush().await;
378
379 Ok(())
380 }
381
382 /// Transfer data to SPI async execution until done.
383 pub async fn async_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
384 let len = read.len().max(write.len());
385
386 critical_section::with(|_| {
387 self.info
388 .regs
389 .fifostat()
390 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
391 });
392
393 for i in 0..len {
394 let wb = write.get(i).copied().unwrap_or(0);
395
396 // wait until we have space in the TxFIFO.
397 self.wait_for(
398 |me| {
399 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
400 Poll::Ready(())
401 } else {
402 Poll::Pending
403 }
404 },
405 |me| {
406 me.info.regs.fifotrig().write(|w| w.txlvlena().set_bit());
407 me.info
408 .regs
409 .fifointenset()
410 .write(|w| w.txlvl().set_bit().txerr().set_bit());
411 },
412 )
413 .await;
414
415 self.info.regs.fifowr().write(|w| {
416 unsafe { w.txdata().bits(wb as u16).len().bits(7) };
417
418 if i == len - 1 {
419 w.eot().set_bit();
420 }
421
422 w
423 });
424
425 // wait until we have data in the RxFIFO.
426 self.wait_for(
427 |me| {
428 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
429 Poll::Ready(())
430 } else {
431 Poll::Pending
432 }
433 },
434 |me| {
435 me.info.regs.fifotrig().write(|w| w.rxlvlena().set_bit());
436 me.info
437 .regs
438 .fifointenset()
439 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
440 },
441 )
442 .await;
443
444 let rb = self.info.regs.fiford().read().rxdata().bits() as u8;
445
446 if let Some(r) = read.get_mut(i) {
447 *r = rb;
448 }
449 }
450
451 self.async_flush().await;
452
453 Ok(())
454 }
455
456 /// Transfer data in place to SPI async execution until done.
457 pub async fn async_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
458 critical_section::with(|_| {
459 self.info
460 .regs
461 .fifostat()
462 .modify(|_, w| w.txerr().set_bit().rxerr().set_bit());
463 });
464
465 for word in data {
466 // wait until we have space in the TxFIFO.
467 self.wait_for(
468 |me| {
469 if me.info.regs.fifostat().read().txnotfull().bit_is_set() {
470 Poll::Ready(())
471 } else {
472 Poll::Pending
473 }
474 },
475 |me| {
476 me.info
477 .regs
478 .fifointenset()
479 .write(|w| w.txlvl().set_bit().txerr().set_bit());
480 },
481 )
482 .await;
483
484 self.info
485 .regs
486 .fifowr()
487 .write(|w| unsafe { w.txdata().bits(*word as u16) });
488
489 // wait until we have data in the RxFIFO.
490 self.wait_for(
491 |me| {
492 if me.info.regs.fifostat().read().rxnotempty().bit_is_set() {
493 Poll::Ready(())
494 } else {
495 Poll::Pending
496 }
497 },
498 |me| {
499 me.info
500 .regs
501 .fifointenset()
502 .write(|w| w.rxlvl().set_bit().rxerr().set_bit());
503 },
504 )
505 .await;
506
507 *word = self.info.regs.fiford().read().rxdata().bits() as u8;
508 }
509
510 self.async_flush().await;
511
512 Ok(())
513 }
514
515 /// Async flush.
516 pub fn async_flush(&mut self) -> impl Future<Output = ()> + use<'_, 'a> {
517 self.wait_for(
518 |me| {
519 if me.info.regs.stat().read().mstidle().bit_is_set() {
520 Poll::Ready(())
521 } else {
522 Poll::Pending
523 }
524 },
525 |me| {
526 me.info.regs.intenset().write(|w| w.mstidleen().set_bit());
527 },
528 )
529 }
530
531 /// Calls `f` to check if we are ready or not.
532 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
533 fn wait_for<F, U, G>(&mut self, mut f: F, mut g: G) -> impl Future<Output = U> + use<'_, 'a, F, U, G>
534 where
535 F: FnMut(&mut Self) -> Poll<U>,
536 G: FnMut(&mut Self),
537 {
538 poll_fn(move |cx| {
539 // Register waker before checking condition, to ensure that wakes/interrupts
540 // aren't lost between f() and g()
541 self.info.waker.register(cx.waker());
542 let r = f(self);
543
544 if r.is_pending() {
545 g(self);
546 }
547
548 r
549 })
550 }
551}
552
553impl<'a, M: IoMode> Spi<'a, M> {
554 fn new_inner<T: Instance>(
555 _inner: Peri<'a, T>,
556 sck: Option<Peri<'a, AnyPin>>,
557 mosi: Option<Peri<'a, AnyPin>>,
558 miso: Option<Peri<'a, AnyPin>>,
559 config: Config,
560 ) -> Self {
561 // REVISIT: allow selecting from multiple clocks.
562 let clk = Self::clock(&config);
563
564 T::enable(clk);
565 T::into_spi();
566
567 Self::apply_config(T::info().regs, &config);
568
569 let info = T::info();
570 let regs = info.regs;
571
572 critical_section::with(|_| match (sck.is_some(), mosi.is_some(), miso.is_some()) {
573 (true, true, true) => {
574 regs.fifocfg().modify(|_, w| {
575 w.enabletx()
576 .set_bit()
577 .emptytx()
578 .set_bit()
579 .enablerx()
580 .set_bit()
581 .emptyrx()
582 .set_bit()
583 });
584 }
585 (true, false, true) => {
586 regs.fifocfg().modify(|_, w| {
587 w.enabletx()
588 .set_bit()
589 .emptytx()
590 .clear_bit()
591 .enablerx()
592 .set_bit()
593 .emptyrx()
594 .set_bit()
595 });
596 }
597 (true, true, false) => {
598 regs.fifocfg().modify(|_, w| {
599 w.enabletx()
600 .set_bit()
601 .emptytx()
602 .set_bit()
603 .enablerx()
604 .clear_bit()
605 .emptyrx()
606 .set_bit()
607 });
608 }
609 (false, _, _) => {
610 regs.fifocfg().modify(|_, w| {
611 w.enabletx()
612 .set_bit()
613 .emptytx()
614 .set_bit()
615 .enablerx()
616 .set_bit()
617 .emptyrx()
618 .set_bit()
619 });
620 regs.cfg().modify(|_, w| w.loop_().enabled());
621 }
622 _ => {}
623 });
624
625 Self {
626 info,
627 _phantom: PhantomData,
628 }
629 }
630
631 fn set_config(&mut self, config: &Config) {
632 Self::apply_config(self.info.regs, config);
633 }
634
635 fn clock(config: &Config) -> Clock {
636 const SFRO_CLOCK_SPEED_HZ: u32 = 16_000_000;
637
638 if config.frequency > SFRO_CLOCK_SPEED_HZ {
639 Clock::Ffro
640 } else {
641 Clock::Sfro
642 }
643 }
644
645 fn clock_frequency(clock: Clock) -> u32 {
646 match clock {
647 Clock::Sfro => 16_000_000,
648 Clock::Ffro => 48_000_000,
649 _ => unreachable!(),
650 }
651 }
652
653 fn apply_config(regs: &'static crate::pac::spi0::RegisterBlock, config: &Config) {
654 let polarity = if config.mode.polarity == Polarity::IdleLow {
655 Cpol::Low
656 } else {
657 Cpol::High
658 };
659
660 let phase = if config.mode.phase == Phase::CaptureOnFirstTransition {
661 Cpha::Change
662 } else {
663 Cpha::Capture
664 };
665
666 let clk = Self::clock(config);
667 let div = Self::clock_frequency(clk) / config.frequency - 1;
668
669 critical_section::with(|_| {
670 // disable SPI every time we need to modify configuration.
671 regs.cfg().modify(|_, w| w.enable().disabled());
672
673 regs.cfg().modify(|_, w| {
674 w.cpha()
675 .variant(phase)
676 .cpol()
677 .variant(polarity)
678 .loop_()
679 .disabled()
680 .master()
681 .master_mode()
682 });
683
684 regs.div().write(|w| unsafe { w.divval().bits(div as u16) });
685
686 regs.cfg().modify(|_, w| w.enable().enabled());
687 });
688 }
689}
690
691/// Spi config.
692#[derive(Clone)]
693pub struct Config {
694 /// Frequency in Hertz.
695 pub frequency: u32,
696 /// SPI operating mode.
697 pub mode: Mode,
698}
699
700impl Default for Config {
701 fn default() -> Self {
702 Self {
703 frequency: 1_000_000,
704 mode: MODE_0,
705 }
706 }
707}
708
709struct Info {
710 regs: &'static crate::pac::spi0::RegisterBlock,
711 waker: &'static AtomicWaker,
712}
713
714// SAFETY: safety for Send here is the same as the other accessors to
715// unsafe blocks: it must be done from a single executor context.
716//
717// This is a temporary workaround -- a better solution might be to
718// refactor Info to no longer maintain a reference to regs, but
719// instead look up the correct register set and then perform
720// operations within an unsafe block as we do for other peripherals
721unsafe impl Send for Info {}
722
723trait SealedInstance {
724 fn info() -> Info;
725}
726
727/// Spi interrupt handler.
728pub struct InterruptHandler<T: Instance> {
729 _phantom: PhantomData<T>,
730}
731
732impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
733 unsafe fn on_interrupt() {
734 let waker = T::info().waker;
735 let stat = T::info().regs.fifointstat().read();
736
737 if stat.perint().bit_is_set() {
738 T::info().regs.intenclr().write(|w| w.mstidle().clear_bit_by_one());
739 }
740
741 if stat.txlvl().bit_is_set() {
742 T::info().regs.fifointenclr().write(|w| w.txlvl().set_bit());
743 }
744
745 if stat.txerr().bit_is_set() {
746 T::info().regs.fifointenclr().write(|w| w.txerr().set_bit());
747 }
748
749 if stat.rxlvl().bit_is_set() {
750 T::info().regs.fifointenclr().write(|w| w.rxlvl().set_bit());
751 }
752
753 if stat.rxerr().bit_is_set() {
754 T::info().regs.fifointenclr().write(|w| w.rxerr().set_bit());
755 }
756
757 waker.wake();
758 }
759}
760
761/// Spi instance trait.
762#[allow(private_bounds)]
763pub trait Instance: crate::flexcomm::IntoSpi + SealedInstance + PeripheralType + 'static + Send {
764 /// Interrupt for this Spi instance.
765 type Interrupt: interrupt::typelevel::Interrupt;
766}
767
768macro_rules! impl_instance {
769 ($($n:expr),*) => {
770 $(
771 paste!{
772 impl SealedInstance for crate::peripherals::[<FLEXCOMM $n>] {
773 #[inline]
774 fn info() -> Info {
775 static WAKER: AtomicWaker = AtomicWaker::new();
776
777 Info {
778 regs: unsafe { &*crate::pac::[<Spi $n>]::ptr() },
779 waker: &WAKER,
780 }
781 }
782 }
783
784 impl Instance for crate::peripherals::[<FLEXCOMM $n>] {
785 type Interrupt = crate::interrupt::typelevel::[<FLEXCOMM $n>];
786 }
787 }
788 )*
789 }
790}
791
792impl_instance!(0, 1, 2, 3, 4, 5, 6, 7, 14);
793
794mod sealed {
795 /// Seal a trait
796 pub trait Sealed {}
797}
798
799impl<T: Pin> sealed::Sealed for T {}
800
801/// IO configuration trait for Spi clk
802pub trait SckPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
803 /// convert the pin to appropriate function for Spi clk usage.
804 fn as_sck(&self);
805}
806
807/// IO configuration trait for Spi mosi
808pub trait MosiPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
809 /// convert the pin to appropriate function for Spi mosi usage.
810 fn as_mosi(&self);
811}
812
813/// IO configuration trait for Spi miso
814pub trait MisoPin<T: Instance>: Pin + sealed::Sealed + PeripheralType {
815 /// convert the pin to appropriate function for Spi miso usage.
816 fn as_miso(&self);
817}
818
819macro_rules! impl_pin_trait {
820 ($fcn:ident, $mode:ident, $($pin:ident, $fn:ident),*) => {
821 paste! {
822 $(
823 impl [<$mode:camel Pin>]<crate::peripherals::$fcn> for crate::peripherals::$pin {
824 fn [<as_ $mode>](&self) {
825 // UM11147 table 530 pg 518
826 self.set_function(crate::iopctl::Function::$fn)
827 .set_pull(Pull::None)
828 .enable_input_buffer()
829 .set_slew_rate(SlewRate::Standard)
830 .set_drive_strength(DriveStrength::Normal)
831 .disable_analog_multiplex()
832 .set_drive_mode(DriveMode::PushPull)
833 .set_input_inverter(Inverter::Disabled);
834 }
835 }
836 )*
837 }
838 }
839}
840
841// FLEXCOMM0
842impl_pin_trait!(FLEXCOMM0, sck, PIO0_0, F1, PIO3_0, F5);
843impl_pin_trait!(FLEXCOMM0, miso, PIO0_1, F1, PIO3_1, F5);
844impl_pin_trait!(FLEXCOMM0, mosi, PIO0_2, F1, PIO3_2, F5);
845
846// FLEXCOMM1
847impl_pin_trait!(FLEXCOMM1, sck, PIO0_7, F1, PIO7_25, F1);
848impl_pin_trait!(FLEXCOMM1, miso, PIO0_8, F1, PIO7_26, F1);
849impl_pin_trait!(FLEXCOMM1, mosi, PIO0_9, F1, PIO7_28, F1);
850
851// FLEXCOMM2
852impl_pin_trait!(FLEXCOMM2, sck, PIO0_14, F1, PIO7_29, F5);
853impl_pin_trait!(FLEXCOMM2, miso, PIO0_15, F1, PIO7_30, F5);
854impl_pin_trait!(FLEXCOMM2, mosi, PIO0_16, F1, PIO7_31, F5);
855
856// FLEXCOMM3
857impl_pin_trait!(FLEXCOMM3, sck, PIO0_21, F1);
858impl_pin_trait!(FLEXCOMM3, miso, PIO0_22, F1);
859impl_pin_trait!(FLEXCOMM3, mosi, PIO0_23, F1);
860
861// FLEXCOMM4
862impl_pin_trait!(FLEXCOMM4, sck, PIO0_28, F1);
863impl_pin_trait!(FLEXCOMM4, miso, PIO0_29, F1);
864impl_pin_trait!(FLEXCOMM4, mosi, PIO0_30, F1);
865
866// FLEXCOMM5
867impl_pin_trait!(FLEXCOMM5, sck, PIO1_3, F1, PIO3_15, F5);
868impl_pin_trait!(FLEXCOMM5, miso, PIO1_4, F1, PIO3_16, F5);
869impl_pin_trait!(FLEXCOMM5, mosi, PIO1_5, F1, PIO3_17, F5);
870
871// FLEXCOMM6
872impl_pin_trait!(FLEXCOMM6, sck, PIO3_25, F1);
873impl_pin_trait!(FLEXCOMM6, miso, PIO3_26, F1);
874impl_pin_trait!(FLEXCOMM6, mosi, PIO3_27, F1);
875
876// FLEXCOMM7
877impl_pin_trait!(FLEXCOMM7, sck, PIO4_0, F1);
878impl_pin_trait!(FLEXCOMM7, miso, PIO4_1, F1);
879impl_pin_trait!(FLEXCOMM7, mosi, PIO4_2, F1);
880
881// FLEXCOMM14
882impl_pin_trait!(FLEXCOMM14, sck, PIO1_11, F1);
883impl_pin_trait!(FLEXCOMM14, miso, PIO1_12, F1);
884impl_pin_trait!(FLEXCOMM14, mosi, PIO1_13, F1);
885
886/// Spi Tx DMA trait.
887#[allow(private_bounds)]
888pub trait TxDma<T: Instance>: crate::dma::Channel {}
889
890/// Spi Rx DMA trait.
891#[allow(private_bounds)]
892pub trait RxDma<T: Instance>: crate::dma::Channel {}
893
894macro_rules! impl_dma {
895 ($fcn:ident, $mode:ident, $dma:ident) => {
896 paste! {
897 impl [<$mode Dma>]<crate::peripherals::$fcn> for crate::peripherals::$dma {}
898 }
899 };
900}
901
902impl_dma!(FLEXCOMM0, Rx, DMA0_CH0);
903impl_dma!(FLEXCOMM0, Tx, DMA0_CH1);
904
905impl_dma!(FLEXCOMM1, Rx, DMA0_CH2);
906impl_dma!(FLEXCOMM1, Tx, DMA0_CH3);
907
908impl_dma!(FLEXCOMM2, Rx, DMA0_CH4);
909impl_dma!(FLEXCOMM2, Tx, DMA0_CH5);
910
911impl_dma!(FLEXCOMM3, Rx, DMA0_CH6);
912impl_dma!(FLEXCOMM3, Tx, DMA0_CH7);
913
914impl_dma!(FLEXCOMM4, Rx, DMA0_CH8);
915impl_dma!(FLEXCOMM4, Tx, DMA0_CH9);
916
917impl_dma!(FLEXCOMM5, Rx, DMA0_CH10);
918impl_dma!(FLEXCOMM5, Tx, DMA0_CH11);
919
920impl_dma!(FLEXCOMM6, Rx, DMA0_CH12);
921impl_dma!(FLEXCOMM6, Tx, DMA0_CH13);
922
923impl_dma!(FLEXCOMM7, Rx, DMA0_CH14);
924impl_dma!(FLEXCOMM7, Tx, DMA0_CH15);
925
926impl_dma!(FLEXCOMM14, Rx, DMA0_CH16);
927impl_dma!(FLEXCOMM14, Tx, DMA0_CH17);
928
929// ==============================
930
931impl<'d, M: IoMode> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'d, M> {
932 type Error = Error;
933 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
934 self.blocking_transfer_in_place(words)?;
935 Ok(words)
936 }
937}
938
939impl<'d, M: IoMode> embedded_hal_02::blocking::spi::Write<u8> for Spi<'d, M> {
940 type Error = Error;
941
942 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
943 self.blocking_write(words)
944 }
945}
946
947impl embedded_hal_1::spi::Error for Error {
948 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
949 match *self {}
950 }
951}
952
953impl<'d, M: IoMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> {
954 type Error = Error;
955}
956
957impl<'d, M: IoMode> embedded_hal_1::spi::SpiBus<u8> for Spi<'d, M> {
958 fn flush(&mut self) -> Result<(), Self::Error> {
959 self.flush()
960 }
961
962 fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
963 self.blocking_read(words)
964 }
965
966 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
967 self.blocking_write(words)
968 }
969
970 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
971 self.blocking_transfer(read, write)
972 }
973
974 fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
975 self.blocking_transfer_in_place(words)
976 }
977}
978
979impl<'d> embedded_hal_async::spi::SpiBus<u8> for Spi<'d, Async> {
980 async fn flush(&mut self) -> Result<(), Self::Error> {
981 self.async_flush().await;
982
983 Ok(())
984 }
985
986 async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
987 self.async_write(words).await
988 }
989
990 async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
991 self.async_read(words).await
992 }
993
994 async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
995 self.async_transfer(read, write).await
996 }
997
998 async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
999 self.async_transfer_in_place(words).await
1000 }
1001}
1002
1003impl<'d, M: IoMode> SetConfig for Spi<'d, M> {
1004 type Config = Config;
1005 type ConfigError = ();
1006 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1007 self.set_config(config);
1008
1009 Ok(())
1010 }
1011}
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 cb985a2e9..76ce59f5a 100644
--- a/embassy-mcxa/Cargo.toml
+++ b/embassy-mcxa/Cargo.toml
@@ -39,7 +39,7 @@ embedded-hal-nb = { version = "1.0" }
39embedded-io = "0.6" 39embedded-io = "0.6"
40embedded-io-async = { version = "0.6.1" } 40embedded-io-async = { version = "0.6.1" }
41heapless = "0.8" 41heapless = "0.8"
42mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "02bd04a21ef8f8f67f88239ff5df765bb7e60fd8" } 42mcxa-pac = { version = "0.1.0", features = ["rt", "critical-section"] }
43nb = "1.1.0" 43nb = "1.1.0"
44paste = "1.0.15" 44paste = "1.0.15"
45maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } 45maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] }
@@ -48,6 +48,9 @@ maitake-sync = { version = "0.2.2", default-features = false, features = ["criti
48embassy-time = { version = "0.5.0", optional = true } 48embassy-time = { version = "0.5.0", optional = true }
49embassy-time-driver = { version = "0.2.1", optional = true } 49embassy-time-driver = { version = "0.2.1", optional = true }
50 50
51rand-core-06 = { package = "rand_core", version = "0.6" }
52rand-core-09 = { package = "rand_core", version = "0.9" }
53
51[features] 54[features]
52default = ["rt"] 55default = ["rt"]
53 56
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs
index ceb1e2a50..b41a1ba46 100644
--- a/embassy-mcxa/src/clocks/mod.rs
+++ b/embassy-mcxa/src/clocks/mod.rs
@@ -1076,4 +1076,6 @@ pub(crate) mod gate {
1076 1076
1077 // DMA0 peripheral - uses NoConfig since it has no selectable clock source 1077 // DMA0 peripheral - uses NoConfig since it has no selectable clock source
1078 impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); 1078 impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig);
1079 // TRNG peripheral - uses NoConfig since it has no selectable clock source
1080 impl_cc_gate!(TRNG0, mrcc_glb_cc1, mrcc_glb_rst1, trng0, NoConfig);
1079} 1081}
diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs
index 725f8d499..b662f7ee0 100644
--- a/embassy-mcxa/src/interrupt.rs
+++ b/embassy-mcxa/src/interrupt.rs
@@ -38,6 +38,7 @@ mod generated {
38 LPUART5, 38 LPUART5,
39 OS_EVENT, 39 OS_EVENT,
40 RTC, 40 RTC,
41 TRNG0
41 ); 42 );
42} 43}
43 44
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs
index 8d39728a7..76fd58210 100644
--- a/embassy-mcxa/src/lib.rs
+++ b/embassy-mcxa/src/lib.rs
@@ -19,6 +19,7 @@ pub mod lpuart;
19pub mod ostimer; 19pub mod ostimer;
20pub mod reset_reason; 20pub mod reset_reason;
21pub mod rtc; 21pub mod rtc;
22pub mod trng;
22 23
23use crate::interrupt::InterruptExt; 24use crate::interrupt::InterruptExt;
24pub use crate::pac::NVIC_PRIO_BITS; 25pub use crate::pac::NVIC_PRIO_BITS;
diff --git a/embassy-mcxa/src/trng.rs b/embassy-mcxa/src/trng.rs
new file mode 100644
index 000000000..ce37e4b2a
--- /dev/null
+++ b/embassy-mcxa/src/trng.rs
@@ -0,0 +1,678 @@
1//! True Random Number Generator
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::Peri;
6use embassy_hal_internal::interrupt::InterruptExt;
7use maitake_sync::WaitCell;
8use mcxa_pac::trng0::osc2_ctl::TrngEntCtl;
9
10use crate::clocks::enable_and_reset;
11use crate::clocks::periph_helpers::NoConfig;
12use crate::interrupt::typelevel;
13use crate::interrupt::typelevel::Handler;
14use crate::peripherals::TRNG0;
15
16static WAIT_CELL: WaitCell = WaitCell::new();
17
18#[allow(private_bounds)]
19pub trait Mode: sealed::SealedMode {}
20
21mod sealed {
22 pub trait SealedMode {}
23}
24
25macro_rules! define_mode {
26 ($mode:ident) => {
27 pub struct $mode;
28 impl sealed::SealedMode for $mode {}
29 impl Mode for $mode {}
30 };
31}
32
33define_mode!(Blocking);
34define_mode!(Async);
35
36/// TRNG Driver
37pub struct Trng<'d, M: Mode> {
38 _peri: Peri<'d, TRNG0>,
39 _phantom: PhantomData<M>,
40}
41
42impl<'d, M: Mode> Trng<'d, M> {
43 fn new_inner(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
44 _ = unsafe { enable_and_reset::<TRNG0>(&NoConfig) };
45
46 Self::configure(config);
47 Self {
48 _peri,
49 _phantom: PhantomData,
50 }
51 }
52
53 fn configure(config: Config) {
54 regs()
55 .mctl()
56 .modify(|_, w| w.rst_def().set_bit().prgm().enable().err().clear_bit_by_one());
57
58 regs().scml().write(|w| unsafe {
59 w.mono_max()
60 .bits(config.monobit_limit_max)
61 .mono_rng()
62 .bits(config.monobit_limit_range)
63 });
64
65 regs().scr1l().write(|w| unsafe {
66 w.run1_max()
67 .bits(config.run_length1_limit_max)
68 .run1_rng()
69 .bits(config.run_length1_limit_range)
70 });
71
72 regs().scr2l().write(|w| unsafe {
73 w.run2_max()
74 .bits(config.run_length2_limit_max)
75 .run2_rng()
76 .bits(config.run_length2_limit_range)
77 });
78
79 regs().scr3l().write(|w| unsafe {
80 w.run3_max()
81 .bits(config.run_length3_limit_max)
82 .run3_rng()
83 .bits(config.run_length3_limit_range)
84 });
85
86 regs().scr4l().write(|w| unsafe {
87 w.run4_max()
88 .bits(config.run_length4_limit_max)
89 .run4_rng()
90 .bits(config.run_length4_limit_range)
91 });
92
93 regs().scr5l().write(|w| unsafe {
94 w.run5_max()
95 .bits(config.run_length5_limit_max)
96 .run5_rng()
97 .bits(config.run_length5_limit_range)
98 });
99
100 regs().scr6pl().write(|w| unsafe {
101 w.run6p_max()
102 .bits(config.run_length6_limit_max)
103 .run6p_rng()
104 .bits(config.run_length6_limit_range)
105 });
106
107 regs()
108 .pkrmax()
109 .write(|w| unsafe { w.pkr_max().bits(config.poker_limit_max) });
110
111 regs()
112 .frqmax()
113 .write(|w| unsafe { w.frq_max().bits(config.freq_counter_max) });
114
115 regs()
116 .frqmin()
117 .write(|w| unsafe { w.frq_min().bits(config.freq_counter_min) });
118
119 regs()
120 .sblim()
121 .write(|w| unsafe { w.sb_lim().bits(config.sparse_bit_limit) });
122
123 regs().scmisc().write(|w| unsafe {
124 w.lrun_max()
125 .bits(config.long_run_limit_max)
126 .rty_ct()
127 .bits(config.retry_count)
128 });
129
130 regs()
131 .mctl()
132 .modify(|_, w| w.dis_slf_tst().variant(config.self_test.into()));
133
134 regs().sdctl().write(|w| unsafe {
135 w.samp_size()
136 .bits(config.sample_size)
137 .ent_dly()
138 .bits(config.entropy_delay)
139 });
140
141 regs()
142 .osc2_ctl()
143 .modify(|_, w| w.trng_ent_ctl().variant(config.osc_mode.into()));
144
145 regs().mctl().modify(|_, w| w.prgm().disable());
146
147 let _ = regs().ent(7).read().bits();
148
149 Self::start();
150 }
151
152 fn start() {
153 regs().mctl().modify(|_, w| w.trng_acc().set_bit());
154 }
155
156 fn stop() {
157 regs().mctl().modify(|_, w| w.trng_acc().clear_bit());
158 }
159
160 fn blocking_wait_for_generation() {
161 while regs().mctl().read().ent_val().bit_is_clear() {
162 if regs().mctl().read().err().bit_is_set() {
163 regs().mctl().modify(|_, w| w.err().clear_bit_by_one());
164 }
165 }
166 }
167
168 fn fill_chunk(chunk: &mut [u8]) {
169 let mut entropy = [0u32; 8];
170
171 for (i, item) in entropy.iter_mut().enumerate() {
172 *item = regs().ent(i).read().bits();
173 }
174
175 let entropy: [u8; 32] = unsafe { core::mem::transmute(entropy) };
176
177 chunk.copy_from_slice(&entropy[..chunk.len()]);
178 }
179
180 // Blocking API
181
182 /// Fill the buffer with random bytes, blocking version.
183 pub fn blocking_fill_bytes(&mut self, buf: &mut [u8]) {
184 if buf.is_empty() {
185 return; // nothing to fill
186 }
187
188 for chunk in buf.chunks_mut(32) {
189 Self::blocking_wait_for_generation();
190 Self::fill_chunk(chunk);
191 }
192 }
193
194 /// Return a random u32, blocking version.
195 pub fn blocking_next_u32(&mut self) -> u32 {
196 Self::blocking_wait_for_generation();
197 // New random bytes are generated only after reading ENT7
198 regs().ent(7).read().bits()
199 }
200
201 /// Return a random u64, blocking version.
202 pub fn blocking_next_u64(&mut self) -> u64 {
203 Self::blocking_wait_for_generation();
204
205 let mut result = u64::from(regs().ent(6).read().bits()) << 32;
206 // New random bytes are generated only after reading ENT7
207 result |= u64::from(regs().ent(7).read().bits());
208 result
209 }
210}
211
212impl<'d> Trng<'d, Blocking> {
213 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
214 pub fn new_blocking_128(_peri: Peri<'d, TRNG0>) -> Self {
215 Self::new_inner(
216 _peri,
217 Config {
218 sample_size: 128,
219 retry_count: 1,
220 long_run_limit_max: 29,
221 monobit_limit_max: 94,
222 monobit_limit_range: 61,
223 run_length1_limit_max: 39,
224 run_length1_limit_range: 39,
225 run_length2_limit_max: 24,
226 run_length2_limit_range: 25,
227 run_length3_limit_max: 17,
228 run_length3_limit_range: 18,
229 ..Default::default()
230 },
231 )
232 }
233
234 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
235 pub fn new_blocking_256(_peri: Peri<'d, TRNG0>) -> Self {
236 Self::new_inner(
237 _peri,
238 Config {
239 sample_size: 256,
240 retry_count: 1,
241 long_run_limit_max: 31,
242 monobit_limit_max: 171,
243 monobit_limit_range: 86,
244 run_length1_limit_max: 63,
245 run_length1_limit_range: 56,
246 run_length2_limit_max: 38,
247 run_length2_limit_range: 38,
248 run_length3_limit_max: 25,
249 run_length3_limit_range: 26,
250 ..Default::default()
251 },
252 )
253 }
254
255 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
256 pub fn new_blocking_512(_peri: Peri<'d, TRNG0>) -> Self {
257 Self::new_inner(_peri, Default::default())
258 }
259
260 /// Instantiates a new TRNG peripheral driver.
261 ///
262 /// NOTE: this constructor makes no attempt at validating the
263 /// parameters. If you get this wrong, the security guarantees of
264 /// the TRNG with regards to entropy may be violated
265 pub fn new_blocking_with_custom_config(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
266 Self::new_inner(_peri, config)
267 }
268}
269
270impl<'d> Trng<'d, Async> {
271 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
272 pub fn new_128(
273 _peri: Peri<'d, TRNG0>,
274 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
275 ) -> Self {
276 let inst = Self::new_inner(
277 _peri,
278 Config {
279 sample_size: 128,
280 retry_count: 1,
281 long_run_limit_max: 29,
282 monobit_limit_max: 94,
283 monobit_limit_range: 61,
284 run_length1_limit_max: 39,
285 run_length1_limit_range: 39,
286 run_length2_limit_max: 24,
287 run_length2_limit_range: 25,
288 run_length3_limit_max: 17,
289 run_length3_limit_range: 18,
290 ..Default::default()
291 },
292 );
293 crate::pac::Interrupt::TRNG0.unpend();
294 unsafe {
295 crate::pac::Interrupt::TRNG0.enable();
296 }
297 inst
298 }
299
300 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
301 pub fn new_256(
302 _peri: Peri<'d, TRNG0>,
303 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
304 ) -> Self {
305 let inst = Self::new_inner(
306 _peri,
307 Config {
308 sample_size: 256,
309 retry_count: 1,
310 long_run_limit_max: 31,
311 monobit_limit_max: 171,
312 monobit_limit_range: 86,
313 run_length1_limit_max: 63,
314 run_length1_limit_range: 56,
315 run_length2_limit_max: 38,
316 run_length2_limit_range: 38,
317 run_length3_limit_max: 25,
318 run_length3_limit_range: 26,
319 ..Default::default()
320 },
321 );
322 crate::pac::Interrupt::TRNG0.unpend();
323 unsafe {
324 crate::pac::Interrupt::TRNG0.enable();
325 }
326 inst
327 }
328
329 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
330 pub fn new_512(
331 _peri: Peri<'d, TRNG0>,
332 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
333 ) -> Self {
334 let inst = Self::new_inner(_peri, Default::default());
335 crate::pac::Interrupt::TRNG0.unpend();
336 unsafe {
337 crate::pac::Interrupt::TRNG0.enable();
338 }
339 inst
340 }
341
342 /// Instantiates a new TRNG peripheral driver.
343 ///
344 /// NOTE: this constructor makes no attempt at validating the
345 /// parameters. If you get this wrong, the security guarantees of
346 /// the TRNG with regards to entropy may be violated
347 pub fn new_with_custom_config(
348 _peri: Peri<'d, TRNG0>,
349 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
350 config: Config,
351 ) -> Self {
352 let inst = Self::new_inner(_peri, config);
353 crate::pac::Interrupt::TRNG0.unpend();
354 unsafe {
355 crate::pac::Interrupt::TRNG0.enable();
356 }
357 inst
358 }
359
360 fn enable_ints() {
361 regs().int_mask().write(|w| {
362 w.hw_err()
363 .set_bit()
364 .ent_val()
365 .set_bit()
366 .frq_ct_fail()
367 .set_bit()
368 .intg_flt()
369 .set_bit()
370 });
371 }
372
373 async fn wait_for_generation() -> Result<(), Error> {
374 WAIT_CELL
375 .wait_for(|| {
376 Self::enable_ints();
377 regs().mctl().read().ent_val().bit_is_set()
378 })
379 .await
380 .map_err(|_| Error::ErrorStatus)
381 }
382
383 // Async API
384
385 /// Fill the buffer with random bytes, async version.
386 pub async fn async_fill_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> {
387 if buf.is_empty() {
388 return Ok(()); // nothing to fill
389 }
390
391 for chunk in buf.chunks_mut(32) {
392 Self::wait_for_generation().await?;
393 Self::fill_chunk(chunk);
394 }
395
396 Ok(())
397 }
398
399 /// Return a random u32, async version.
400 pub async fn async_next_u32(&mut self) -> Result<u32, Error> {
401 Self::wait_for_generation().await?;
402 // New random bytes are generated only after reading ENT7
403 Ok(regs().ent(7).read().bits())
404 }
405
406 /// Return a random u64, async version.
407 pub async fn async_next_u64(&mut self) -> Result<u64, Error> {
408 Self::wait_for_generation().await?;
409
410 let mut result = u64::from(regs().ent(6).read().bits()) << 32;
411 // New random bytes are generated only after reading ENT7
412 result |= u64::from(regs().ent(7).read().bits());
413
414 Ok(result)
415 }
416}
417
418impl<M: Mode> Drop for Trng<'_, M> {
419 fn drop(&mut self) {
420 // wait until allowed to stop
421 while regs().mctl().read().tstop_ok().bit_is_clear() {}
422 // stop
423 Self::stop();
424 // reset the TRNG
425 regs().mctl().write(|w| w.rst_def().set_bit());
426 }
427}
428
429fn regs() -> &'static crate::pac::trng0::RegisterBlock {
430 unsafe { &*crate::pac::Trng0::ptr() }
431}
432
433/// Trng errors
434#[derive(Clone, Copy, Debug)]
435#[cfg_attr(feature = "defmt", derive(defmt::Format))]
436#[non_exhaustive]
437pub enum Error {
438 /// Integrity error.
439 IntegrityError,
440
441 /// Frequency counter fail
442 FrequencyCountFail,
443
444 /// Error status
445 ErrorStatus,
446
447 /// Buffer argument is invalid
448 InvalidBuffer,
449}
450
451/// TRNG interrupt handler.
452pub struct InterruptHandler;
453
454impl Handler<typelevel::TRNG0> for InterruptHandler {
455 unsafe fn on_interrupt() {
456 if regs().int_status().read().bits() != 0 {
457 regs().int_ctrl().write(|w| {
458 w.hw_err()
459 .clear_bit()
460 .ent_val()
461 .clear_bit()
462 .frq_ct_fail()
463 .clear_bit()
464 .intg_flt()
465 .clear_bit()
466 });
467 WAIT_CELL.wake();
468 }
469 }
470}
471
472/// True random number generator configuration parameters.
473#[derive(Clone, Copy, Debug)]
474#[cfg_attr(feature = "defmt", derive(defmt::Format))]
475#[non_exhaustive]
476pub struct Config {
477 /// Total number of Entropy samples that will be taken during
478 /// Entropy generation.
479 pub sample_size: u16,
480
481 /// Length (in system clocks) of each Entropy sample taken.
482 pub entropy_delay: u16,
483
484 /// Enable or disable internal self-tests.
485 pub self_test: SelfTest,
486
487 /// Frequency Counter Maximum Limit
488 pub freq_counter_max: u32,
489
490 /// Frequency Counter Minimum Limit
491 pub freq_counter_min: u32,
492
493 /// Statistical check monobit max limit
494 pub monobit_limit_max: u16,
495
496 /// Statistical check monobit range
497 pub monobit_limit_range: u16,
498
499 /// Statistical check run length 1 limit max
500 pub run_length1_limit_max: u16,
501
502 /// Statistical check run length 1 limit range
503 pub run_length1_limit_range: u16,
504
505 /// Statistical check run length 2 limit max
506 pub run_length2_limit_max: u16,
507
508 /// Statistical check run length 2 limit range
509 pub run_length2_limit_range: u16,
510
511 /// Statistical check run length 3 limit max
512 pub run_length3_limit_max: u16,
513
514 /// Statistical check run length 3 limit range
515 pub run_length3_limit_range: u16,
516
517 /// Statistical check run length 4 limit max
518 pub run_length4_limit_max: u16,
519
520 /// Statistical check run length 4 limit range
521 pub run_length4_limit_range: u16,
522
523 /// Statistical check run length 5 limit max
524 pub run_length5_limit_max: u16,
525
526 /// Statistical check run length 5 limit range
527 pub run_length5_limit_range: u16,
528
529 /// Statistical check run length 6 limit max
530 pub run_length6_limit_max: u16,
531
532 /// Statistical check run length 6 limit range
533 pub run_length6_limit_range: u16,
534
535 /// Retry count
536 pub retry_count: u8,
537
538 /// Long run limit max
539 pub long_run_limit_max: u8,
540
541 /// Sparse bit limit
542 pub sparse_bit_limit: u16,
543
544 /// Poker limit max
545 pub poker_limit_max: u32,
546
547 /// Oscillator mode
548 pub osc_mode: OscMode,
549}
550
551impl Default for Config {
552 fn default() -> Self {
553 Self {
554 sample_size: 512,
555 entropy_delay: 32_000,
556 self_test: SelfTest::Enabled,
557 freq_counter_max: 75_000,
558 freq_counter_min: 30_000,
559 monobit_limit_max: 317,
560 monobit_limit_range: 122,
561 run_length1_limit_max: 107,
562 run_length1_limit_range: 80,
563 run_length2_limit_max: 62,
564 run_length2_limit_range: 55,
565 run_length3_limit_max: 39,
566 run_length3_limit_range: 39,
567 run_length4_limit_max: 0,
568 run_length4_limit_range: 0,
569 run_length5_limit_max: 0,
570 run_length5_limit_range: 0,
571 run_length6_limit_max: 0,
572 run_length6_limit_range: 0,
573 retry_count: 1,
574 long_run_limit_max: 32,
575 sparse_bit_limit: 0,
576 poker_limit_max: 0,
577 osc_mode: OscMode::DualOscs,
578 }
579 }
580}
581
582/// Sample size.
583#[derive(Clone, Copy, Debug)]
584#[cfg_attr(feature = "defmt", derive(defmt::Format))]
585#[non_exhaustive]
586pub enum SampleSize {
587 /// 128 bits
588 _128,
589
590 /// 256 bits
591 _256,
592
593 /// 512 bits
594 _512,
595}
596
597/// Enable or disable internal self-tests.
598#[derive(Clone, Copy, Debug)]
599#[cfg_attr(feature = "defmt", derive(defmt::Format))]
600#[non_exhaustive]
601pub enum SelfTest {
602 /// Disabled.
603 Disabled,
604
605 /// Enabled.
606 Enabled,
607}
608
609impl From<SelfTest> for bool {
610 fn from(value: SelfTest) -> Self {
611 match value {
612 SelfTest::Disabled => true,
613 SelfTest::Enabled => false,
614 }
615 }
616}
617
618/// Oscillator mode.
619#[derive(Clone, Copy, Debug)]
620#[cfg_attr(feature = "defmt", derive(defmt::Format))]
621#[non_exhaustive]
622pub enum OscMode {
623 /// Single oscillator using OSC1.
624 SingleOsc1,
625
626 /// Dual oscillator.
627 DualOscs,
628
629 /// Single oscillator using OSC2.
630 SingleOsc2,
631}
632
633impl From<OscMode> for TrngEntCtl {
634 fn from(value: OscMode) -> Self {
635 match value {
636 OscMode::SingleOsc1 => Self::TrngEntCtlSingleOsc1,
637 OscMode::DualOscs => Self::TrngEntCtlDualOscs,
638 OscMode::SingleOsc2 => Self::TrngEntCtlSingleOsc2,
639 }
640 }
641}
642
643impl<'d, M: Mode> rand_core_06::RngCore for Trng<'d, M> {
644 fn next_u32(&mut self) -> u32 {
645 self.blocking_next_u32()
646 }
647
648 fn next_u64(&mut self) -> u64 {
649 self.blocking_next_u64()
650 }
651
652 fn fill_bytes(&mut self, dest: &mut [u8]) {
653 self.blocking_fill_bytes(dest);
654 }
655
656 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
657 self.blocking_fill_bytes(dest);
658 Ok(())
659 }
660}
661
662impl<'d, M: Mode> rand_core_06::CryptoRng for Trng<'d, M> {}
663
664impl<'d, M: Mode> rand_core_09::RngCore for Trng<'d, M> {
665 fn next_u32(&mut self) -> u32 {
666 self.blocking_next_u32()
667 }
668
669 fn next_u64(&mut self) -> u64 {
670 self.blocking_next_u64()
671 }
672
673 fn fill_bytes(&mut self, dest: &mut [u8]) {
674 self.blocking_fill_bytes(dest);
675 }
676}
677
678impl<'d, M: Mode> rand_core_09::CryptoRng for Trng<'d, M> {}
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..cf2346328 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -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-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..349ff2880 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" }
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-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-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index 9c53e66a7..0d7bfb5f0 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -8,6 +8,8 @@ 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.9.0 - 2025-12-15
12
11- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l 13- changed: apply trimming values from FICR.TRIMCNF on nrf53/54l
12- changed: do not panic on BufferedUarte overrun 14- changed: do not panic on BufferedUarte overrun
13- added: allow direct access to the input pin of `gpiote::InputChannel` 15- added: allow direct access to the input pin of `gpiote::InputChannel`
@@ -32,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
32* added: support for nrf54l10 and nrf54l05 34* added: support for nrf54l10 and nrf54l05
33* added: expose uicr write functions 35* added: expose uicr write functions
34* added: support for nrf54lm20a 36* added: support for nrf54lm20a
37- added: support buffered rram for nrf54
35 38
36## 0.8.0 - 2025-09-30 39## 0.8.0 - 2025-09-30
37 40
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index ee070f0c0..f8a6ef864 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"
@@ -223,10 +223,10 @@ embedded-io-async = { version = "0.6.1" }
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/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/lib.rs b/embassy-nrf/src/lib.rs
index db71dee10..584d0a0be 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -845,9 +845,9 @@ pub fn init(config: config::Config) -> Peripherals {
845 // Chips with a certain chip type-specific build code or higher have an 845 // Chips with a certain chip type-specific build code or higher have an
846 // improved APPROTECT ("hardware and software controlled access port protection") 846 // improved APPROTECT ("hardware and software controlled access port protection")
847 // which needs explicit action by the firmware to keep it unlocked 847 // which needs explicit action by the firmware to keep it unlocked
848 // See https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/working-with-the-nrf52-series-improved-approtect 848 // See https://docs.nordicsemi.com/bundle/ps_nrf52840/page/dif.html#d402e184
849 849
850 // UICR.APPROTECT = SwDisabled 850 // UICR.APPROTECT = HwDisabled
851 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); 851 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
852 needs_reset |= res == WriteResult::Written; 852 needs_reset |= res == WriteResult::Written;
853 // APPROTECT.DISABLE = SwDisabled 853 // APPROTECT.DISABLE = SwDisabled
diff --git a/embassy-nrf/src/rramc.rs b/embassy-nrf/src/rramc.rs
index 521ac4ee7..961e0a535 100644
--- a/embassy-nrf/src/rramc.rs
+++ b/embassy-nrf/src/rramc.rs
@@ -1,5 +1,6 @@
1//! Resistive Random-Access Memory Controller driver. 1//! Resistive Random-Access Memory Controller driver.
2 2
3use core::marker::PhantomData;
3use core::{ptr, slice}; 4use core::{ptr, slice};
4 5
5use embedded_storage::nor_flash::{ 6use embedded_storage::nor_flash::{
@@ -9,11 +10,28 @@ use embedded_storage::nor_flash::{
9use crate::peripherals::RRAMC; 10use crate::peripherals::RRAMC;
10use crate::{Peri, pac}; 11use crate::{Peri, pac};
11 12
13/// Unbuffered RRAMC mode.
14pub struct Unbuffered;
15
16/// Buffered RRAMC mode.
17pub struct Buffered<const BUFFER_SIZE_BYTES: usize>;
18
19trait SealedRramMode {}
20
21/// Operating modes for RRAMC
22#[allow(private_bounds)]
23pub trait RramMode: SealedRramMode {}
24
25impl SealedRramMode for Unbuffered {}
26impl RramMode for Unbuffered {}
27impl<const BUFFER_SIZE_BYTES: usize> SealedRramMode for Buffered<BUFFER_SIZE_BYTES> {}
28impl<const BUFFER_SIZE_BYTES: usize> RramMode for Buffered<BUFFER_SIZE_BYTES> {}
29
12// 30//
13// Export Nvmc alias and page size for downstream compatibility 31// Export Nvmc alias and page size for downstream compatibility
14// 32//
15/// RRAM-backed `Nvmc` compatibile driver. 33/// RRAM-backed `Nvmc` compatibile driver.
16pub type Nvmc<'d> = Rramc<'d>; 34pub type Nvmc<'d> = Rramc<'d, Unbuffered>;
17/// Emulated page size. RRAM does not use pages. This exists only for downstream compatibility. 35/// Emulated page size. RRAM does not use pages. This exists only for downstream compatibility.
18pub const PAGE_SIZE: usize = 4096; 36pub const PAGE_SIZE: usize = 4096;
19 37
@@ -44,16 +62,27 @@ impl NorFlashError for Error {
44 62
45/// Resistive Random-Access Memory Controller (RRAMC) that implements the `embedded-storage` 63/// Resistive Random-Access Memory Controller (RRAMC) that implements the `embedded-storage`
46/// traits. 64/// traits.
47pub struct Rramc<'d> { 65pub struct Rramc<'d, MODE: RramMode> {
48 _p: Peri<'d, RRAMC>, 66 _p: Peri<'d, RRAMC>,
67 _d: PhantomData<MODE>,
68}
69
70impl<'d> Rramc<'d, Unbuffered> {
71 /// Create Rramc driver.
72 pub fn new(_p: Peri<'d, RRAMC>) -> Rramc<'d, Unbuffered> {
73 Self { _p, _d: PhantomData }
74 }
49} 75}
50 76
51impl<'d> Rramc<'d> { 77impl<'d, const BUFFER_SIZE_BYTES: usize> Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {
52 /// Create Rramc driver. 78 /// Create Rramc driver.
53 pub fn new(_p: Peri<'d, RRAMC>) -> Self { 79 pub fn new_buffered(_p: Peri<'d, RRAMC>) -> Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {
54 Self { _p } 80 assert!(BUFFER_SIZE_BYTES > 0 && BUFFER_SIZE_BYTES <= 512);
81 Self { _p, _d: PhantomData }
55 } 82 }
83}
56 84
85impl<'d, MODE: RramMode> Rramc<'d, MODE> {
57 fn regs() -> pac::rramc::Rramc { 86 fn regs() -> pac::rramc::Rramc {
58 pac::RRAMC 87 pac::RRAMC
59 } 88 }
@@ -63,18 +92,48 @@ impl<'d> Rramc<'d> {
63 while !p.ready().read().ready() {} 92 while !p.ready().read().ready() {}
64 } 93 }
65 94
95 fn enable_read(&self) {
96 Self::regs().config().write(|w| w.set_wen(false));
97 }
98
99 fn finish_write(&mut self) {
100 self.enable_read();
101 self.wait_ready();
102 }
103}
104
105impl<'d> Rramc<'d, Unbuffered> {
106 fn wait_ready_write(&mut self) {
107 let p = Self::regs();
108 while !p.readynext().read().readynext() {}
109 }
110
111 fn enable_write(&self) {
112 Self::regs().config().write(|w| {
113 w.set_wen(true);
114 w.set_writebufsize(pac::rramc::vals::Writebufsize::UNBUFFERED)
115 });
116 }
117}
118
119impl<'d, const SIZE: usize> Rramc<'d, Buffered<SIZE>> {
66 fn wait_ready_write(&mut self) { 120 fn wait_ready_write(&mut self) {
67 let p = Self::regs(); 121 let p = Self::regs();
68 while !p.readynext().read().readynext() {} 122 while !p.readynext().read().readynext() {}
69 while !p.bufstatus().writebufempty().read().empty() {} 123 while !p.bufstatus().writebufempty().read().empty() {}
70 } 124 }
71 125
72 fn enable_read(&self) { 126 fn commit(&self) {
73 Self::regs().config().write(|w| w.set_wen(false)); 127 let p = Self::regs();
128 p.tasks_commitwritebuf().write_value(1);
129 while !p.bufstatus().writebufempty().read().empty() {}
74 } 130 }
75 131
76 fn enable_write(&self) { 132 fn enable_write(&self) {
77 Self::regs().config().write(|w| w.set_wen(true)); 133 Self::regs().config().write(|w| {
134 w.set_wen(true);
135 w.set_writebufsize(pac::rramc::vals::Writebufsize::from_bits(SIZE as _))
136 });
78 } 137 }
79} 138}
80 139
@@ -83,13 +142,13 @@ impl<'d> Rramc<'d> {
83// implement the traits for downstream compatibility. 142// implement the traits for downstream compatibility.
84// 143//
85 144
86impl<'d> MultiwriteNorFlash for Rramc<'d> {} 145impl<'d> MultiwriteNorFlash for Rramc<'d, Unbuffered> {}
87 146
88impl<'d> ErrorType for Rramc<'d> { 147impl<'d> ErrorType for Rramc<'d, Unbuffered> {
89 type Error = Error; 148 type Error = Error;
90} 149}
91 150
92impl<'d> ReadNorFlash for Rramc<'d> { 151impl<'d> ReadNorFlash for Rramc<'d, Unbuffered> {
93 const READ_SIZE: usize = 1; 152 const READ_SIZE: usize = 1;
94 153
95 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 154 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
@@ -107,7 +166,7 @@ impl<'d> ReadNorFlash for Rramc<'d> {
107 } 166 }
108} 167}
109 168
110impl<'d> NorFlash for Rramc<'d> { 169impl<'d> NorFlash for Rramc<'d, Unbuffered> {
111 const WRITE_SIZE: usize = WRITE_LINE_SIZE; 170 const WRITE_SIZE: usize = WRITE_LINE_SIZE;
112 const ERASE_SIZE: usize = PAGE_SIZE; 171 const ERASE_SIZE: usize = PAGE_SIZE;
113 172
@@ -139,11 +198,100 @@ impl<'d> NorFlash for Rramc<'d> {
139 self.wait_ready_write(); 198 self.wait_ready_write();
140 } 199 }
141 } 200 }
201 self.finish_write();
202 Ok(())
203 }
204
205 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
206 if offset as usize + bytes.len() > FLASH_SIZE {
207 return Err(Error::OutOfBounds);
208 }
209 if offset as usize % Self::WRITE_SIZE != 0 || bytes.len() % Self::WRITE_SIZE != 0 {
210 return Err(Error::Unaligned);
211 }
212
213 self.enable_write();
214 self.wait_ready();
215
216 unsafe {
217 let p_src = bytes.as_ptr() as *const u32;
218 let p_dst = offset as *mut u32;
219 let words = bytes.len() / 4;
220 for i in 0..words {
221 let w = ptr::read_unaligned(p_src.add(i));
222 ptr::write_volatile(p_dst.add(i), w);
223 if (i + 1) % (Self::WRITE_SIZE / 4) == 0 {
224 self.wait_ready_write();
225 }
226 }
227 }
142 228
143 self.enable_read(); 229 self.enable_read();
144 self.wait_ready(); 230 self.wait_ready();
145 Ok(()) 231 Ok(())
146 } 232 }
233}
234
235impl<'d, const BUFFER_SIZE_BYTES: usize> MultiwriteNorFlash for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {}
236
237impl<'d, const BUFFER_SIZE_BYTES: usize> ErrorType for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {
238 type Error = Error;
239}
240
241impl<'d, const BUFFER_SIZE_BYTES: usize> ReadNorFlash for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {
242 const READ_SIZE: usize = 1;
243
244 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
245 if offset as usize >= FLASH_SIZE || offset as usize + bytes.len() > FLASH_SIZE {
246 return Err(Error::OutOfBounds);
247 }
248
249 let flash_data = unsafe { slice::from_raw_parts(offset as *const u8, bytes.len()) };
250 bytes.copy_from_slice(flash_data);
251 Ok(())
252 }
253
254 fn capacity(&self) -> usize {
255 FLASH_SIZE
256 }
257}
258
259impl<'d, const BUFFER_SIZE_BYTES: usize> NorFlash for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {
260 const WRITE_SIZE: usize = WRITE_LINE_SIZE;
261 const ERASE_SIZE: usize = PAGE_SIZE;
262
263 // RRAM can overwrite in-place, so emulate page erases by overwriting the page bytes with 0xFF.
264 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
265 if to < from || to as usize > FLASH_SIZE {
266 return Err(Error::OutOfBounds);
267 }
268 if from as usize % Self::ERASE_SIZE != 0 || to as usize % Self::ERASE_SIZE != 0 {
269 return Err(Error::Unaligned);
270 }
271
272 self.enable_write();
273 self.wait_ready();
274
275 // Treat each emulated page separately so callers can rely on post‑erase read‑back
276 // returning 0xFF just like on real NOR flash.
277 let buf = [0xFFu8; BUFFER_SIZE_BYTES];
278 for page_addr in (from..to).step_by(Self::ERASE_SIZE) {
279 let page_end = page_addr + Self::ERASE_SIZE as u32;
280 for line_addr in (page_addr..page_end).step_by(BUFFER_SIZE_BYTES) {
281 unsafe {
282 let src = buf.as_ptr() as *const u32;
283 let dst = line_addr as *mut u32;
284 for i in 0..(Self::WRITE_SIZE / 4) {
285 core::ptr::write_volatile(dst.add(i), core::ptr::read_unaligned(src.add(i)));
286 }
287 }
288 self.wait_ready_write();
289 }
290 }
291 self.commit();
292 self.finish_write();
293 Ok(())
294 }
147 295
148 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { 296 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
149 if offset as usize + bytes.len() > FLASH_SIZE { 297 if offset as usize + bytes.len() > FLASH_SIZE {
@@ -169,6 +317,7 @@ impl<'d> NorFlash for Rramc<'d> {
169 } 317 }
170 } 318 }
171 319
320 self.commit();
172 self.enable_read(); 321 self.enable_read();
173 self.wait_ready(); 322 self.wait_ready();
174 Ok(()) 323 Ok(())
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index abf9a923f..6c38ab3fe 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -174,7 +174,7 @@ impl<'d> Twim<'d> {
174 }); 174 });
175 w.set_drive1(gpiovals::Drive::D); 175 w.set_drive1(gpiovals::Drive::D);
176 } 176 }
177 if config.sda_pullup { 177 if config.scl_pullup {
178 w.set_pull(gpiovals::Pull::PULLUP); 178 w.set_pull(gpiovals::Pull::PULLUP);
179 } 179 }
180 }); 180 });
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 103dedead..acf977ed5 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -41,12 +41,12 @@ log = { version = "0.4.17", optional = true }
41 41
42cortex-m = "0.7.6" 42cortex-m = "0.7.6"
43heapless = "0.8" 43heapless = "0.8"
44aligned = "0.4.1" 44aligned = "0.4.2"
45critical-section = "1.1" 45critical-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/sub/ble.rs b/embassy-stm32-wpan/src/wb55/sub/ble.rs
index afc4a510a..a822d6530 100644
--- a/embassy-stm32-wpan/src/wb55/sub/ble.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/ble.rs
@@ -73,7 +73,9 @@ impl<'a> Ble<'a> {
73 pub async fn tl_read(&mut self) -> EvtBox<Self> { 73 pub async fn tl_read(&mut self) -> EvtBox<Self> {
74 self.ipcc_ble_event_channel 74 self.ipcc_ble_event_channel
75 .receive(|| unsafe { 75 .receive(|| unsafe {
76 if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { 76 if let Some(node_ptr) =
77 critical_section::with(|cs| LinkedListNode::remove_head(cs, EVT_QUEUE.as_mut_ptr()))
78 {
77 Some(EvtBox::new(node_ptr.cast())) 79 Some(EvtBox::new(node_ptr.cast()))
78 } else { 80 } else {
79 None 81 None
@@ -128,12 +130,8 @@ impl<'a> hci::Controller for Ble<'a> {
128 self.tl_write(opcode.0, payload).await; 130 self.tl_write(opcode.0, payload).await;
129 } 131 }
130 132
131 #[allow(invalid_reference_casting)] 133 async fn controller_read_into(&mut self, buf: &mut [u8]) {
132 async fn controller_read_into(&self, buf: &mut [u8]) { 134 let evt_box = self.tl_read().await;
133 // A complete hack since I cannot update the trait
134 let s = unsafe { &mut *(self as *const _ as *mut Ble) };
135
136 let evt_box = s.tl_read().await;
137 let evt_serial = evt_box.serial(); 135 let evt_serial = evt_box.serial();
138 136
139 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/mm.rs b/embassy-stm32-wpan/src/wb55/sub/mm.rs
index cbb5f130b..0ca7d1835 100644
--- a/embassy-stm32-wpan/src/wb55/sub/mm.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/mm.rs
@@ -4,7 +4,6 @@ use core::mem::MaybeUninit;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use aligned::{A4, Aligned}; 6use aligned::{A4, Aligned};
7use cortex_m::interrupt;
8use embassy_stm32::ipcc::IpccTxChannel; 7use embassy_stm32::ipcc::IpccTxChannel;
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
10 9
@@ -52,7 +51,7 @@ impl<'a> MemoryManager<'a> {
52 loop { 51 loop {
53 poll_fn(|cx| unsafe { 52 poll_fn(|cx| unsafe {
54 MM_WAKER.register(cx.waker()); 53 MM_WAKER.register(cx.waker());
55 if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { 54 if critical_section::with(|cs| LinkedListNode::is_empty(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr())) {
56 Poll::Pending 55 Poll::Pending
57 } else { 56 } else {
58 Poll::Ready(()) 57 Poll::Ready(())
@@ -62,10 +61,9 @@ impl<'a> MemoryManager<'a> {
62 61
63 self.ipcc_mm_release_buffer_channel 62 self.ipcc_mm_release_buffer_channel
64 .send(|| { 63 .send(|| {
65 interrupt::free(|_| unsafe { 64 critical_section::with(|cs| unsafe {
66 // CS required while moving nodes 65 while let Some(node_ptr) = LinkedListNode::remove_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
67 while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { 66 LinkedListNode::insert_head(cs, FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
68 LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
69 } 67 }
70 }) 68 })
71 }) 69 })
@@ -77,8 +75,8 @@ impl<'a> MemoryManager<'a> {
77impl<'a> evt::MemoryManager for MemoryManager<'a> { 75impl<'a> evt::MemoryManager for MemoryManager<'a> {
78 /// SAFETY: passing a pointer to something other than a managed event packet is UB 76 /// SAFETY: passing a pointer to something other than a managed event packet is UB
79 unsafe fn drop_event_packet(evt: *mut EvtPacket) { 77 unsafe fn drop_event_packet(evt: *mut EvtPacket) {
80 interrupt::free(|_| unsafe { 78 critical_section::with(|cs| unsafe {
81 LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); 79 LinkedListNode::insert_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
82 }); 80 });
83 81
84 MM_WAKER.wake(); 82 MM_WAKER.wake();
diff --git a/embassy-stm32-wpan/src/wb55/sub/sys.rs b/embassy-stm32-wpan/src/wb55/sub/sys.rs
index 4376314c7..2e625a677 100644
--- a/embassy-stm32-wpan/src/wb55/sub/sys.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/sys.rs
@@ -87,10 +87,12 @@ impl<'a> Sys<'a> {
87 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, 87 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`,
88 /// as the embassy implementation avoids the need to call C public bindings, and instead 88 /// as the embassy implementation avoids the need to call C public bindings, and instead
89 /// handles the event channels directly. 89 /// handles the event channels directly.
90 pub async fn read<'b>(&mut self) -> EvtBox<mm::MemoryManager<'b>> { 90 pub async fn read(&mut self) -> EvtBox<mm::MemoryManager<'_>> {
91 self.ipcc_system_event_channel 91 self.ipcc_system_event_channel
92 .receive(|| unsafe { 92 .receive(|| unsafe {
93 if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { 93 if let Some(node_ptr) =
94 critical_section::with(|cs| LinkedListNode::remove_head(cs, SYSTEM_EVT_QUEUE.as_mut_ptr()))
95 {
94 Some(EvtBox::new(node_ptr.cast())) 96 Some(EvtBox::new(node_ptr.cast()))
95 } else { 97 } else {
96 None 98 None
diff --git a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
index d8bc29763..c84ee1bb6 100644
--- a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
+++ b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
@@ -11,9 +11,10 @@
11 unused_mut 11 unused_mut
12)] 12)]
13 13
14use core::fmt::Debug;
14use core::ptr; 15use core::ptr;
15 16
16use cortex_m::interrupt; 17use critical_section::CriticalSection;
17 18
18#[derive(Copy, Clone)] 19#[derive(Copy, Clone)]
19#[repr(C, packed(4))] 20#[repr(C, packed(4))]
@@ -42,216 +43,227 @@ impl LinkedListNode {
42 ); 43 );
43 } 44 }
44 45
45 pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool { 46 pub unsafe fn is_empty(_cs: CriticalSection, mut p_list_head: *mut LinkedListNode) -> bool {
46 interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head) 47 ptr::read_volatile(p_list_head).next == p_list_head
47 } 48 }
48 49
49 /// Insert `node` after `list_head` and before the next node 50 /// Insert `node` after `list_head` and before the next node
50 pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { 51 pub unsafe fn insert_head(
51 interrupt::free(|_| { 52 _cs: CriticalSection,
52 let mut list_head = ptr::read_volatile(p_list_head); 53 mut p_list_head: *mut LinkedListNode,
53 if p_list_head != list_head.next { 54 mut p_node: *mut LinkedListNode,
54 let mut node_next = ptr::read_volatile(list_head.next); 55 ) {
55 let node = LinkedListNode { 56 let mut list_head = ptr::read_volatile(p_list_head);
56 next: list_head.next, 57 if p_list_head != list_head.next {
57 prev: p_list_head, 58 let mut node_next = ptr::read_volatile(list_head.next);
58 }; 59 let node = LinkedListNode {
59 60 next: list_head.next,
60 list_head.next = p_node; 61 prev: p_list_head,
61 node_next.prev = p_node; 62 };
62 63
63 // All nodes must be written because they will all be seen by another core 64 list_head.next = p_node;
64 ptr::write_volatile(p_node, node); 65 node_next.prev = p_node;
65 ptr::write_volatile(node.next, node_next); 66
66 ptr::write_volatile(p_list_head, list_head); 67 // All nodes must be written because they will all be seen by another core
67 } else { 68 ptr::write_volatile(p_node, node);
68 let node = LinkedListNode { 69 ptr::write_volatile(node.next, node_next);
69 next: list_head.next, 70 ptr::write_volatile(p_list_head, list_head);
70 prev: p_list_head, 71 } else {
71 }; 72 let node = LinkedListNode {
72 73 next: list_head.next,
73 list_head.next = p_node; 74 prev: p_list_head,
74 list_head.prev = p_node; 75 };
75 76
76 // All nodes must be written because they will all be seen by another core 77 list_head.next = p_node;
77 ptr::write_volatile(p_node, node); 78 list_head.prev = p_node;
78 ptr::write_volatile(p_list_head, list_head); 79
79 } 80 // All nodes must be written because they will all be seen by another core
80 }); 81 ptr::write_volatile(p_node, node);
82 ptr::write_volatile(p_list_head, list_head);
83 }
81 } 84 }
82 85
83 /// Insert `node` before `list_tail` and after the second-to-last node 86 /// Insert `node` before `list_tail` and after the second-to-last node
84 pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { 87 pub unsafe fn insert_tail(
85 interrupt::free(|_| { 88 _cs: CriticalSection,
86 let mut list_tail = ptr::read_volatile(p_list_tail); 89 mut p_list_tail: *mut LinkedListNode,
87 if p_list_tail != list_tail.prev { 90 mut p_node: *mut LinkedListNode,
88 let mut node_prev = ptr::read_volatile(list_tail.prev); 91 ) {
89 let node = LinkedListNode { 92 let mut list_tail = ptr::read_volatile(p_list_tail);
90 next: p_list_tail, 93 if p_list_tail != list_tail.prev {
91 prev: list_tail.prev, 94 let mut node_prev = ptr::read_volatile(list_tail.prev);
92 }; 95 let node = LinkedListNode {
93 96 next: p_list_tail,
94 list_tail.prev = p_node; 97 prev: list_tail.prev,
95 node_prev.next = p_node; 98 };
96 99
97 // All nodes must be written because they will all be seen by another core 100 list_tail.prev = p_node;
98 ptr::write_volatile(p_node, node); 101 node_prev.next = p_node;
99 ptr::write_volatile(node.prev, node_prev); 102
100 ptr::write_volatile(p_list_tail, list_tail); 103 // All nodes must be written because they will all be seen by another core
101 } else { 104 ptr::write_volatile(p_node, node);
102 let node = LinkedListNode { 105 ptr::write_volatile(node.prev, node_prev);
103 next: p_list_tail, 106 ptr::write_volatile(p_list_tail, list_tail);
104 prev: list_tail.prev, 107 } else {
105 }; 108 let node = LinkedListNode {
106 109 next: p_list_tail,
107 list_tail.prev = p_node; 110 prev: list_tail.prev,
108 list_tail.next = p_node; 111 };
109 112
110 // All nodes must be written because they will all be seen by another core 113 list_tail.prev = p_node;
111 ptr::write_volatile(p_node, node); 114 list_tail.next = p_node;
112 ptr::write_volatile(p_list_tail, list_tail); 115
113 } 116 // All nodes must be written because they will all be seen by another core
114 }); 117 ptr::write_volatile(p_node, node);
118 ptr::write_volatile(p_list_tail, list_tail);
119 }
115 } 120 }
116 121
117 /// Remove `node` from the linked list 122 /// Remove `node` from the linked list
118 pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) { 123 pub unsafe fn remove_node(_cs: CriticalSection, mut p_node: *mut LinkedListNode) {
119 interrupt::free(|_| { 124 let node = ptr::read_unaligned(p_node);
120 // trace!("remove node: {:x}", p_node); 125
121 // apparently linked list nodes are not always aligned. 126 if node.next != node.prev {
122 // if more hardfaults occur, more of these may need to be converted to unaligned. 127 let mut node_next = ptr::read_volatile(node.next);
123 let node = ptr::read_unaligned(p_node); 128 let mut node_prev = ptr::read_volatile(node.prev);
124 // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next); 129
125 130 node_prev.next = node.next;
126 if node.next != node.prev { 131 node_next.prev = node.prev;
127 let mut node_next = ptr::read_volatile(node.next); 132
128 let mut node_prev = ptr::read_volatile(node.prev); 133 ptr::write_volatile(node.next, node_next);
129 134 ptr::write_volatile(node.prev, node_prev);
130 node_prev.next = node.next; 135 } else {
131 node_next.prev = node.prev; 136 let mut node_next = ptr::read_volatile(node.next);
132 137
133 ptr::write_volatile(node.next, node_next); 138 node_next.next = node.next;
134 ptr::write_volatile(node.prev, node_prev); 139 node_next.prev = node.prev;
135 } else { 140
136 let mut node_next = ptr::read_volatile(node.next); 141 ptr::write_volatile(node.next, node_next);
137 142 }
138 node_next.next = node.next;
139 node_next.prev = node.prev;
140
141 ptr::write_volatile(node.next, node_next);
142 }
143 });
144 } 143 }
145 144
146 /// Remove `list_head` and return a pointer to the `node`. 145 /// Remove `list_head` and return a pointer to the `node`.
147 pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> { 146 pub unsafe fn remove_head(
148 interrupt::free(|_| { 147 _cs: CriticalSection,
149 let list_head = ptr::read_volatile(p_list_head); 148 mut p_list_head: *mut LinkedListNode,
150 149 ) -> Option<*mut LinkedListNode> {
151 if list_head.next == p_list_head { 150 let list_head = ptr::read_volatile(p_list_head);
152 None 151
153 } else { 152 if list_head.next == p_list_head {
154 // Allowed because a removed node is not seen by another core 153 None
155 let p_node = list_head.next; 154 } else {
156 Self::remove_node(p_node); 155 // Allowed because a removed node is not seen by another core
157 156 let p_node = list_head.next;
158 Some(p_node) 157 Self::remove_node(_cs, p_node);
159 } 158
160 }) 159 Some(p_node)
160 }
161 } 161 }
162 162
163 /// Remove `list_tail` and return a pointer to the `node`. 163 /// Remove `list_tail` and return a pointer to the `node`.
164 pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> { 164 pub unsafe fn remove_tail(
165 interrupt::free(|_| { 165 _cs: CriticalSection,
166 let list_tail = ptr::read_volatile(p_list_tail); 166 mut p_list_tail: *mut LinkedListNode,
167 167 ) -> Option<*mut LinkedListNode> {
168 if list_tail.prev == p_list_tail { 168 let list_tail = ptr::read_volatile(p_list_tail);
169 None 169
170 } else { 170 if list_tail.prev == p_list_tail {
171 // Allowed because a removed node is not seen by another core 171 None
172 let p_node = list_tail.prev; 172 } else {
173 Self::remove_node(p_node); 173 // Allowed because a removed node is not seen by another core
174 174 let p_node = list_tail.prev;
175 Some(p_node) 175 Self::remove_node(_cs, p_node);
176 }
177 })
178 }
179 176
180 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { 177 Some(p_node)
181 interrupt::free(|_| { 178 }
182 (*node).next = (*ref_node).next; 179 }
183 (*node).prev = ref_node;
184 (*ref_node).next = node;
185 (*(*node).next).prev = node;
186 });
187 180
188 todo!("this function has not been converted to volatile semantics"); 181 pub unsafe fn insert_node_after(
182 _cs: CriticalSection,
183 mut p_node: *mut LinkedListNode,
184 mut p_ref_node: *mut LinkedListNode,
185 ) {
186 let mut node = ptr::read_volatile(p_node);
187 let mut ref_node = ptr::read_volatile(p_ref_node);
188 let mut prev_node = ptr::read_volatile(ref_node.next);
189
190 node.next = ref_node.next;
191 node.prev = p_ref_node;
192 ref_node.next = p_node;
193 prev_node.prev = p_node;
194
195 ptr::write_volatile(p_node, node);
196 ptr::write_volatile(p_ref_node, ref_node);
197 ptr::write_volatile(node.next, prev_node);
189 } 198 }
190 199
191 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { 200 pub unsafe fn insert_node_before(
192 interrupt::free(|_| { 201 _cs: CriticalSection,
193 (*node).next = ref_node; 202 mut node: *mut LinkedListNode,
194 (*node).prev = (*ref_node).prev; 203 mut ref_node: *mut LinkedListNode,
195 (*ref_node).prev = node; 204 ) {
196 (*(*node).prev).next = node; 205 (*node).next = ref_node;
197 }); 206 (*node).prev = (*ref_node).prev;
207 (*ref_node).prev = node;
208 (*(*node).prev).next = node;
198 209
199 todo!("this function has not been converted to volatile semantics"); 210 todo!("this function has not been converted to volatile semantics");
200 } 211 }
201 212
202 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize { 213 pub unsafe fn get_size(_cs: CriticalSection, mut list_head: *mut LinkedListNode) -> usize {
203 interrupt::free(|_| { 214 let mut size = 0;
204 let mut size = 0; 215 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
205 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
206 216
207 temp = (*list_head).next; 217 temp = (*list_head).next;
208 while temp != list_head { 218 while temp != list_head {
209 size += 1; 219 size += 1;
210 temp = (*temp).next 220 temp = (*temp).next
211 } 221 }
212 222
213 size 223 let _ = size;
214 });
215 224
216 todo!("this function has not been converted to volatile semantics"); 225 todo!("this function has not been converted to volatile semantics");
217 } 226 }
218 227
219 pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { 228 pub unsafe fn get_next_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
220 interrupt::free(|_| { 229 let ref_node = ptr::read_volatile(p_ref_node);
221 let ref_node = ptr::read_volatile(p_ref_node);
222 230
223 // Allowed because a removed node is not seen by another core 231 // Allowed because a removed node is not seen by another core
224 ref_node.next 232 ref_node.next
225 })
226 } 233 }
227 234
228 pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { 235 pub unsafe fn get_prev_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
229 interrupt::free(|_| { 236 let ref_node = ptr::read_volatile(p_ref_node);
230 let ref_node = ptr::read_volatile(p_ref_node);
231 237
232 // Allowed because a removed node is not seen by another core 238 // Allowed because a removed node is not seen by another core
233 ref_node.prev 239 ref_node.prev
234 })
235 } 240 }
236} 241}
237 242
238#[allow(dead_code)] 243pub struct DebuggableLinkedListNode(*const LinkedListNode);
239unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) { 244
240 info!("iterating list from node: {:x}", p_node); 245impl Debug for DebuggableLinkedListNode {
241 let mut p_current_node = p_node; 246 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 let mut i = 0; 247 // Safe because this is just reading memory, and using unaligned to do it
243 loop { 248 let p_node = self.0;
244 let current_node = ptr::read_volatile(p_current_node); 249
245 info!( 250 f.write_fmt(format_args!("iterating list from node: {:x}", p_node as usize))?;
246 "node (prev, current, next): {:x}, {:x}, {:x}", 251
247 current_node.prev, p_current_node, current_node.next 252 let mut p_current_node = p_node;
248 ); 253 for _ in 0..30 {
254 let current_node = unsafe { ptr::read_unaligned(p_current_node) };
255 f.write_fmt(format_args!(
256 "node (prev, current, next): {:x}, {:x}, {:x}",
257 current_node.prev as usize, p_current_node as usize, current_node.next as usize
258 ))?;
259
260 if current_node.next == p_node as *mut _ {
261 break;
262 }
249 263
250 i += 1; 264 p_current_node = current_node.next;
251 if i > 10 || current_node.next == p_node {
252 break;
253 } 265 }
254 266
255 p_current_node = current_node.next; 267 Ok(())
256 } 268 }
257} 269}
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..9e0d69078 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
@@ -93,6 +94,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
93- stm32: Add blocking_listen for blocking I2C driver 94- stm32: Add blocking_listen for blocking I2C driver
94- fix: stm32l47*/stm32l48* adc analog pin setup 95- fix: stm32l47*/stm32l48* adc analog pin setup
95- fix: keep stm32/sai: make NODIV independent of MCKDIV 96- fix: keep stm32/sai: make NODIV independent of MCKDIV
97- fix: Source system clock from MSIS before (de)configuring PLLs on STM32U5
98- feat: adc: allow DMA reads to loop through enabled channels
96 99
97## 0.4.0 - 2025-08-26 100## 0.4.0 - 2025-08-26
98 101
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 7989fc5d7..880df5f33 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -193,18 +193,18 @@ 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-658588478e426d68090a59ff8385bce5b407c2bc" }
204 204
205[build-dependencies] 205[build-dependencies]
206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 206#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"] } 207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc", default-features = false, features = ["metadata"] }
208 208
209proc-macro2 = "1.0.36" 209proc-macro2 = "1.0.36"
210quote = "1.0.15" 210quote = "1.0.15"
@@ -241,8 +241,9 @@ log = ["dep:log"]
241chrono = ["dep:chrono"] 241chrono = ["dep:chrono"]
242 242
243exti = [] 243exti = []
244low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 244low-power = [ "dep:embassy-executor", "time" ]
245low-power-debug-with-sleep = [] 245low-power-pender = [ "low-power" ]
246low-power-debug-with-sleep = [ "low-power" ]
246 247
247## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/) 248## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/)
248memory-x = [] 249memory-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/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 43509873f..491569c34 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -24,23 +24,23 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
24/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
25pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
26 26
27impl<'d, T: Instance> super::SealedSpecialConverter<super::VrefInt> for Adc4<'d, T> { 27impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC4 {
28 const CHANNEL: u8 = 0; 28 const CHANNEL: u8 = 0;
29} 29}
30 30
31impl<'d, T: Instance> super::SealedSpecialConverter<super::Temperature> for Adc4<'d, T> { 31impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC4 {
32 const CHANNEL: u8 = 13; 32 const CHANNEL: u8 = 13;
33} 33}
34 34
35impl<'d, T: Instance> super::SealedSpecialConverter<super::Vcore> for Adc4<'d, T> { 35impl super::SealedSpecialConverter<super::Vcore> for crate::peripherals::ADC4 {
36 const CHANNEL: u8 = 12; 36 const CHANNEL: u8 = 12;
37} 37}
38 38
39impl<'d, T: Instance> super::SealedSpecialConverter<super::Vbat> for Adc4<'d, T> { 39impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC4 {
40 const CHANNEL: u8 = 14; 40 const CHANNEL: u8 = 14;
41} 41}
42 42
43impl<'d, T: Instance> super::SealedSpecialConverter<super::Dac> for Adc4<'d, T> { 43impl super::SealedSpecialConverter<super::Dac> for crate::peripherals::ADC4 {
44 const CHANNEL: u8 = 21; 44 const CHANNEL: u8 = 21;
45} 45}
46 46
@@ -197,17 +197,6 @@ impl AdcRegs for crate::pac::adc::Adc4 {
197 } 197 }
198} 198}
199 199
200pub struct Adc4<'d, T: Instance> {
201 #[allow(unused)]
202 adc: crate::Peri<'d, T>,
203}
204
205#[derive(Copy, Clone, Debug)]
206pub enum Adc4Error {
207 InvalidSequence,
208 DMAError,
209}
210
211impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> { 200impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> {
212 /// Create a new ADC driver. 201 /// Create a new ADC driver.
213 pub fn new_adc4(adc: Peri<'d, T>) -> Self { 202 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index a6af1175a..17b1dae77 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -208,13 +208,13 @@ impl<'d, T: Instance> Adc<'d, T> {
208 T::regs().enable(); 208 T::regs().enable();
209 T::regs().convert(); 209 T::regs().convert();
210 210
211 unsafe { *T::regs().data() } 211 unsafe { core::ptr::read_volatile(T::regs().data()) }
212 } 212 }
213 213
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/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index 09fc2ab22..962816194 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -5,6 +5,8 @@ use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; 7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8#[cfg(stm32u5)]
9use crate::adc::DefaultInstance;
8use crate::adc::{AdcRegs, ConversionMode}; 10use crate::adc::{AdcRegs, ConversionMode};
9use crate::time::Hertz; 11use crate::time::Hertz;
10use crate::{Peri, pac, rcc}; 12use crate::{Peri, pac, rcc};
@@ -47,15 +49,15 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
47} 49}
48 50
49#[cfg(stm32u5)] 51#[cfg(stm32u5)]
50impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { 52impl<T: DefaultInstance> super::SealedSpecialConverter<super::VrefInt> for T {
51 const CHANNEL: u8 = 0; 53 const CHANNEL: u8 = 0;
52} 54}
53#[cfg(stm32u5)] 55#[cfg(stm32u5)]
54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { 56impl<T: DefaultInstance> super::SealedSpecialConverter<super::Temperature> for T {
55 const CHANNEL: u8 = 19; 57 const CHANNEL: u8 = 19;
56} 58}
57#[cfg(stm32u5)] 59#[cfg(stm32u5)]
58impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { 60impl<T: DefaultInstance> super::SealedSpecialConverter<super::Vbat> for T {
59 const CHANNEL: u8 = 18; 61 const CHANNEL: u8 = 18;
60} 62}
61 63
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index e62de0454..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,
@@ -148,6 +157,7 @@ impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
148 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to 157 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
149 /// check if the lock has been successful, carried out from the HSEM_Rx register. 158 /// check if the lock has been successful, carried out from the HSEM_Rx register.
150 pub async fn lock(&mut self, process_id: u8) -> HardwareSemaphoreMutex<'a, T> { 159 pub async fn lock(&mut self, process_id: u8) -> HardwareSemaphoreMutex<'a, T> {
160 let _scoped_block_stop = T::RCC_INFO.block_stop();
151 let core_id = CoreId::current(); 161 let core_id = CoreId::current();
152 162
153 poll_fn(|cx| { 163 poll_fn(|cx| {
@@ -155,9 +165,11 @@ impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
155 165
156 compiler_fence(Ordering::SeqCst); 166 compiler_fence(Ordering::SeqCst);
157 167
158 T::regs() 168 critical_section::with(|_| {
159 .ier(core_id.to_index()) 169 T::regs()
160 .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 });
161 173
162 match self.try_lock(process_id) { 174 match self.try_lock(process_id) {
163 Some(mutex) => Poll::Ready(mutex), 175 Some(mutex) => Poll::Ready(mutex),
@@ -241,7 +253,7 @@ impl<T: Instance> HardwareSemaphore<T> {
241 _peripheral: Peri<'d, T>, 253 _peripheral: Peri<'d, T>,
242 _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd, 254 _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd,
243 ) -> Self { 255 ) -> Self {
244 rcc::enable_and_reset::<T>(); 256 rcc::enable_and_reset_without_stop::<T>();
245 257
246 HardwareSemaphore { _type: PhantomData } 258 HardwareSemaphore { _type: PhantomData }
247 } 259 }
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/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 10c4a820b..74ce0b29e 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -10,6 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::peripherals::IPCC; 12use crate::peripherals::IPCC;
13use crate::rcc::SealedRccPeripheral;
13use crate::{interrupt, rcc}; 14use crate::{interrupt, rcc};
14 15
15/// Interrupt handler. 16/// Interrupt handler.
@@ -84,6 +85,7 @@ impl<'a> IpccTxChannel<'a> {
84 85
85 /// Send data to an IPCC channel. The closure is called to write the data when appropriate. 86 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
86 pub async fn send(&mut self, f: impl FnOnce()) { 87 pub async fn send(&mut self, f: impl FnOnce()) {
88 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
87 let regs = IPCC::regs(); 89 let regs = IPCC::regs();
88 90
89 self.flush().await; 91 self.flush().await;
@@ -98,6 +100,7 @@ impl<'a> IpccTxChannel<'a> {
98 100
99 /// Wait for the tx channel to become clear 101 /// Wait for the tx channel to become clear
100 pub async fn flush(&mut self) { 102 pub async fn flush(&mut self) {
103 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
101 let regs = IPCC::regs(); 104 let regs = IPCC::regs();
102 105
103 // This is a race, but is nice for debugging 106 // This is a race, but is nice for debugging
@@ -143,6 +146,7 @@ impl<'a> IpccRxChannel<'a> {
143 146
144 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. 147 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
145 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R { 148 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R {
149 let _scoped_block_stop = IPCC::RCC_INFO.block_stop();
146 let regs = IPCC::regs(); 150 let regs = IPCC::regs();
147 151
148 loop { 152 loop {
@@ -220,9 +224,12 @@ impl Ipcc {
220 + 'd, 224 + 'd,
221 _config: Config, 225 _config: Config,
222 ) -> Self { 226 ) -> Self {
223 rcc::enable_and_reset::<IPCC>(); 227 rcc::enable_and_reset_without_stop::<IPCC>();
224 IPCC::set_cpu2(true); 228 IPCC::set_cpu2(true);
225 229
230 // Verify rfwkpsel is set
231 let _ = IPCC::frequency();
232
226 let regs = IPCC::regs(); 233 let regs = IPCC::regs();
227 234
228 regs.cpu(0).cr().modify(|w| { 235 regs.cpu(0).cr().modify(|w| {
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..02116e08a 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 {
@@ -124,9 +144,9 @@ impl 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 {
@@ -170,24 +188,45 @@ impl Executor {
170 } 188 }
171 189
172 critical_section::with(|cs| { 190 critical_section::with(|cs| {
173 #[cfg(stm32wlex)] 191 #[cfg(any(stm32wlex, stm32wb))]
174 { 192 {
175 let es = crate::pac::PWR.extscr().read(); 193 let es = crate::pac::PWR.extscr().read();
194 #[cfg(stm32wlex)]
176 match (es.c1stopf(), es.c1stop2f()) { 195 match (es.c1stopf(), es.c1stop2f()) {
177 (true, false) => debug!("low power: wake from STOP1"), 196 (true, false) => debug!("low power: wake from STOP1"),
178 (false, true) => debug!("low power: wake from STOP2"), 197 (false, true) => debug!("low power: wake from STOP2"),
179 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"), 198 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"),
180 (false, false) => trace!("low power: stop mode not entered"), 199 (false, false) => trace!("low power: stop mode not entered"),
181 }; 200 };
201
202 #[cfg(stm32wb)]
203 match (es.c1stopf(), es.c2stopf()) {
204 (true, false) => debug!("low power: cpu1 wake from STOP"),
205 (false, true) => debug!("low power: cpu2 wake from STOP"),
206 (true, true) => debug!("low power: cpu1 and cpu2 wake from STOP"),
207 (false, false) => trace!("low power: stop mode not entered"),
208 };
182 crate::pac::PWR.extscr().modify(|w| { 209 crate::pac::PWR.extscr().modify(|w| {
183 w.set_c1cssf(false); 210 w.set_c1cssf(false);
184 }); 211 });
185 212
186 if es.c1stop2f() || es.c1stopf() { 213 let _has_stopped2 = {
214 #[cfg(stm32wb)]
215 {
216 es.c2stopf()
217 }
218
219 #[cfg(stm32wlex)]
220 {
221 es.c1stop2f()
222 }
223 };
224
225 #[cfg(not(stm32wb))]
226 if es.c1stopf() || _has_stopped2 {
187 // when we wake from any stop mode we need to re-initialize the rcc 227 // when we wake from any stop mode we need to re-initialize the rcc
188 crate::rcc::init(RCC_CONFIG.unwrap()); 228 crate::rcc::init(RCC_CONFIG.unwrap());
189 229 if _has_stopped2 {
190 if es.c1stop2f() {
191 // when we wake from STOP2, we need to re-initialize the time driver 230 // when we wake from STOP2, we need to re-initialize the time driver
192 get_driver().init_timer(cs); 231 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) 232 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
@@ -276,6 +315,20 @@ impl Executor {
276 315
277 drop(sem3_mutex); 316 drop(sem3_mutex);
278 317
318 // on PWR
319 RCC.apb1enr1().modify(|r| r.0 |= 1 << 28);
320 cortex_m::asm::dsb();
321
322 // off SMPS, on Bypass
323 PWR.cr5().modify(|r| {
324 let mut val = r.0;
325 val &= !(1 << 15); // sdeb = 0 (off SMPS)
326 val |= 1 << 14; // sdben = 1 (on Bypass)
327 r.0 = val
328 });
329
330 cortex_m::asm::delay(1000);
331
279 Ok(()) 332 Ok(())
280 } 333 }
281 334
@@ -304,7 +357,14 @@ impl Executor {
304 w.set_c1cssf(true); 357 w.set_c1cssf(true);
305 }); 358 });
306 359
307 compiler_fence(Ordering::SeqCst); 360 #[cfg(feature = "low-power-pender")]
361 if TASKS_PENDING.load(Ordering::Acquire) {
362 TASKS_PENDING.store(false, Ordering::Release);
363
364 return;
365 }
366
367 compiler_fence(Ordering::Acquire);
308 368
309 critical_section::with(|cs| { 369 critical_section::with(|cs| {
310 let _ = unsafe { RCC_CONFIG }?; 370 let _ = unsafe { RCC_CONFIG }?;
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 2e1cbd702..0d668103c 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -135,7 +135,14 @@ pub const WPAN_DEFAULT: Config = Config {
135 apb1_pre: APBPrescaler::DIV1, 135 apb1_pre: APBPrescaler::DIV1,
136 apb2_pre: APBPrescaler::DIV1, 136 apb2_pre: APBPrescaler::DIV1,
137 137
138 mux: super::mux::ClockMux::default(), 138 mux: {
139 use crate::pac::rcc::vals::Rfwkpsel;
140
141 let mut mux = super::mux::ClockMux::default();
142
143 mux.rfwkpsel = Rfwkpsel::LSE;
144 mux
145 },
139}; 146};
140 147
141fn msi_enable(range: MSIRange) { 148fn msi_enable(range: MSIRange) {
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 2a9a1595a..753ee1290 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(stm32wlex, 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(stm32wlex, 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..47cc29c6f 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);
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/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 12086cd3a..cfe18ef52 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -7,6 +7,7 @@ use core::marker::PhantomData;
7use core::slice; 7use core::slice;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use aligned::{A4, Aligned};
10use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
11use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
12use sdio_host::Cmd; 13use sdio_host::Cmd;
@@ -139,14 +140,36 @@ impl Default for Signalling {
139 } 140 }
140} 141}
141 142
143const fn aligned_mut(x: &mut [u32]) -> &mut Aligned<A4, [u8]> {
144 let len = x.len() * 4;
145 unsafe { core::mem::transmute(slice::from_raw_parts_mut(x.as_mut_ptr() as *mut u8, len)) }
146}
147
142const fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 148const fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
143 let len = x.len() * 4; 149 let len = x.len() * 4;
144 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}
152
153#[allow(unused)]
154const fn slice32_mut(x: &mut Aligned<A4, [u8]>) -> &mut [u32] {
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 u32, len) }
157}
158
159const fn aligned_ref(x: &[u32]) -> &Aligned<A4, [u8]> {
160 let len = x.len() * 4;
161 unsafe { core::mem::transmute(slice::from_raw_parts(x.as_ptr() as *const u8, len)) }
145} 162}
146 163
147const fn slice8_ref(x: &[u32]) -> &[u8] { 164const fn slice8_ref(x: &[u32]) -> &[u8] {
148 let len = x.len() * 4; 165 let len = x.len() * 4;
149 unsafe { slice::from_raw_parts(x.as_ptr() as _, len) } 166 unsafe { slice::from_raw_parts(x.as_ptr() as *const u8, len) }
167}
168
169#[allow(unused)]
170const fn slice32_ref(x: &Aligned<A4, [u8]>) -> &[u32] {
171 let len = (size_of_val(x) + 4 - 1) / 4;
172 unsafe { slice::from_raw_parts(x as *const Aligned<A4, [u8]> as *const u32, len) }
150} 173}
151 174
152/// Errors 175/// Errors
@@ -187,6 +210,11 @@ enum PowerCtrl {
187 On = 0b11, 210 On = 0b11,
188} 211}
189 212
213enum DatapathMode {
214 Block(BlockSize),
215 Byte,
216}
217
190fn get_waitresp_val(rlen: ResponseLen) -> u8 { 218fn get_waitresp_val(rlen: ResponseLen) -> u8 {
191 match rlen { 219 match rlen {
192 common_cmd::ResponseLen::Zero => 0, 220 common_cmd::ResponseLen::Zero => 0,
@@ -768,12 +796,16 @@ impl<'d> Sdmmc<'d> {
768 #[allow(unused_variables)] 796 #[allow(unused_variables)]
769 fn prepare_datapath_read<'a>( 797 fn prepare_datapath_read<'a>(
770 &'a self, 798 &'a self,
771 buffer: &'a mut [u32], 799 buffer: &'a mut Aligned<A4, [u8]>,
772 block_size: BlockSize, 800 mode: DatapathMode,
773 byte_mode: bool,
774 ) -> WrappedTransfer<'a> { 801 ) -> WrappedTransfer<'a> {
775 let regs = self.info.regs; 802 let regs = self.info.regs;
776 803
804 let (byte_mode, block_size) = match mode {
805 DatapathMode::Block(block_size) => (false, block_size as u8),
806 DatapathMode::Byte => (true, 0),
807 };
808
777 // Command AND Data state machines must be idle 809 // Command AND Data state machines must be idle
778 self.wait_idle(); 810 self.wait_idle();
779 self.clear_interrupt_flags(); 811 self.clear_interrupt_flags();
@@ -783,8 +815,11 @@ impl<'d> Sdmmc<'d> {
783 // SAFETY: No other functions use the dma 815 // SAFETY: No other functions use the dma
784 #[cfg(sdmmc_v1)] 816 #[cfg(sdmmc_v1)]
785 let transfer = unsafe { 817 let transfer = unsafe {
786 self.dma 818 self.dma.read_unchecked(
787 .read_unchecked(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) 819 regs.fifor().as_ptr() as *mut u32,
820 slice32_mut(buffer),
821 DMA_TRANSFER_OPTIONS,
822 )
788 }; 823 };
789 #[cfg(sdmmc_v2)] 824 #[cfg(sdmmc_v2)]
790 let transfer = { 825 let transfer = {
@@ -817,14 +852,14 @@ impl<'d> Sdmmc<'d> {
817 /// # Safety 852 /// # Safety
818 /// 853 ///
819 /// `buffer` must be valid for the whole transfer and word aligned 854 /// `buffer` must be valid for the whole transfer and word aligned
820 fn prepare_datapath_write<'a>( 855 fn prepare_datapath_write<'a>(&'a self, buffer: &'a Aligned<A4, [u8]>, mode: DatapathMode) -> WrappedTransfer<'a> {
821 &'a self,
822 buffer: &'a [u32],
823 block_size: BlockSize,
824 byte_mode: bool,
825 ) -> WrappedTransfer<'a> {
826 let regs = self.info.regs; 856 let regs = self.info.regs;
827 857
858 let (byte_mode, block_size) = match mode {
859 DatapathMode::Block(block_size) => (false, block_size as u8),
860 DatapathMode::Byte => (true, 0),
861 };
862
828 // Command AND Data state machines must be idle 863 // Command AND Data state machines must be idle
829 self.wait_idle(); 864 self.wait_idle();
830 self.clear_interrupt_flags(); 865 self.clear_interrupt_flags();
@@ -834,8 +869,11 @@ impl<'d> Sdmmc<'d> {
834 // SAFETY: No other functions use the dma 869 // SAFETY: No other functions use the dma
835 #[cfg(sdmmc_v1)] 870 #[cfg(sdmmc_v1)]
836 let transfer = unsafe { 871 let transfer = unsafe {
837 self.dma 872 self.dma.write_unchecked(
838 .write_unchecked(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) 873 slice32_ref(buffer),
874 regs.fifor().as_ptr() as *mut u32,
875 DMA_TRANSFER_OPTIONS,
876 )
839 }; 877 };
840 #[cfg(sdmmc_v2)] 878 #[cfg(sdmmc_v2)]
841 let transfer = { 879 let transfer = {
@@ -1141,6 +1179,7 @@ impl<'d> Drop for Sdmmc<'d> {
1141 fn drop(&mut self) { 1179 fn drop(&mut self) {
1142 // T::Interrupt::disable(); 1180 // T::Interrupt::disable();
1143 self.on_drop(); 1181 self.on_drop();
1182 self.info.rcc.disable_without_stop();
1144 1183
1145 critical_section::with(|_| { 1184 critical_section::with(|_| {
1146 self.clk.set_as_disconnected(); 1185 self.clk.set_as_disconnected();
diff --git a/embassy-stm32/src/sdmmc/sd.rs b/embassy-stm32/src/sdmmc/sd.rs
index 6190226b8..20318bbfa 100644
--- a/embassy-stm32/src/sdmmc/sd.rs
+++ b/embassy-stm32/src/sdmmc/sd.rs
@@ -5,7 +5,10 @@ use sdio_host::emmc::{EMMC, ExtCSD};
5use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; 5use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus};
6use sdio_host::{common_cmd, emmc_cmd, sd_cmd}; 6use sdio_host::{common_cmd, emmc_cmd, sd_cmd};
7 7
8use crate::sdmmc::{BlockSize, Error, Sdmmc, Signalling, block_size, bus_width_vals, slice8_mut, slice8_ref}; 8use crate::sdmmc::{
9 BlockSize, DatapathMode, Error, Sdmmc, Signalling, aligned_mut, aligned_ref, block_size, bus_width_vals,
10 slice8_mut, slice8_ref,
11};
9use crate::time::{Hertz, mhz}; 12use crate::time::{Hertz, mhz};
10 13
11/// Aligned data block for SDMMC transfers. 14/// Aligned data block for SDMMC transfers.
@@ -230,10 +233,8 @@ impl<'a, 'b> StorageDevice<'a, 'b, Card> {
230 }; 233 };
231 234
232 let buffer = &mut cmd_block.0[..64 / 4]; 235 let buffer = &mut cmd_block.0[..64 / 4];
233 236 let mode = DatapathMode::Block(block_size(size_of_val(buffer)));
234 let transfer = self 237 let transfer = self.sdmmc.prepare_datapath_read(aligned_mut(buffer), mode);
235 .sdmmc
236 .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false);
237 238
238 self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 239 self.sdmmc.cmd(sd_cmd::cmd6(set_function), true)?; // CMD6
239 240
@@ -272,7 +273,9 @@ impl<'a, 'b> StorageDevice<'a, 'b, Card> {
272 273
273 // Arm `OnDrop` after the buffer, so it will be dropped first 274 // Arm `OnDrop` after the buffer, so it will be dropped first
274 275
275 let transfer = self.sdmmc.prepare_datapath_read(scr, BlockSize::Size8, false); 276 let transfer = self
277 .sdmmc
278 .prepare_datapath_read(aligned_mut(scr), DatapathMode::Block(BlockSize::Size8));
276 self.sdmmc.cmd(sd_cmd::send_scr(), true)?; 279 self.sdmmc.cmd(sd_cmd::send_scr(), true)?;
277 280
278 self.sdmmc.complete_datapath_transfer(transfer, true).await?; 281 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
@@ -290,10 +293,9 @@ impl<'a, 'b> StorageDevice<'a, 'b, Card> {
290 self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP 293 self.sdmmc.cmd(common_cmd::app_cmd(rca), false)?; // APP
291 294
292 let buffer = &mut cmd_block.as_mut()[..64 / 4]; 295 let buffer = &mut cmd_block.as_mut()[..64 / 4];
296 let mode = DatapathMode::Block(block_size(size_of_val(buffer)));
293 297
294 let transfer = self 298 let transfer = self.sdmmc.prepare_datapath_read(aligned_mut(buffer), mode);
295 .sdmmc
296 .prepare_datapath_read(buffer, block_size(size_of_val(buffer)), false);
297 self.sdmmc.cmd(sd_cmd::sd_status(), true)?; 299 self.sdmmc.cmd(sd_cmd::sd_status(), true)?;
298 300
299 self.sdmmc.complete_datapath_transfer(transfer, true).await?; 301 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
@@ -398,9 +400,10 @@ impl<'a, 'b> StorageDevice<'a, 'b, Emmc> {
398 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false) 400 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)
399 .unwrap(); // CMD16 401 .unwrap(); // CMD16
400 402
401 let transfer = self 403 let transfer = self.sdmmc.prepare_datapath_read(
402 .sdmmc 404 aligned_mut(&mut data_block.0),
403 .prepare_datapath_read(&mut data_block.0, block_size(size_of::<DataBlock>()), false); 405 DatapathMode::Block(block_size(size_of::<DataBlock>())),
406 );
404 self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?; 407 self.sdmmc.cmd(emmc_cmd::send_ext_csd(), true)?;
405 408
406 self.sdmmc.complete_datapath_transfer(transfer, true).await?; 409 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
@@ -418,7 +421,7 @@ impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
418 421
419 /// Read a data block. 422 /// Read a data block.
420 #[inline] 423 #[inline]
421 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { 424 pub async fn read_block(&mut self, block_idx: u32, data_block: &mut DataBlock) -> Result<(), Error> {
422 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); 425 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
423 let card_capacity = self.info.get_capacity(); 426 let card_capacity = self.info.get_capacity();
424 427
@@ -431,9 +434,10 @@ impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
431 self.sdmmc 434 self.sdmmc
432 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 435 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
433 436
434 let transfer = self 437 let transfer = self.sdmmc.prepare_datapath_read(
435 .sdmmc 438 aligned_mut(&mut data_block.0),
436 .prepare_datapath_read(&mut buffer.0, block_size(size_of::<DataBlock>()), false); 439 DatapathMode::Block(block_size(size_of::<DataBlock>())),
440 );
437 self.sdmmc.cmd(common_cmd::read_single_block(address), true)?; 441 self.sdmmc.cmd(common_cmd::read_single_block(address), true)?;
438 442
439 self.sdmmc.complete_datapath_transfer(transfer, true).await?; 443 self.sdmmc.complete_datapath_transfer(transfer, true).await?;
@@ -464,9 +468,10 @@ impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
464 self.sdmmc 468 self.sdmmc
465 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16 469 .cmd(common_cmd::set_block_length(size_of::<DataBlock>() as u32), false)?; // CMD16
466 470
467 let transfer = self 471 let transfer = self.sdmmc.prepare_datapath_read(
468 .sdmmc 472 aligned_mut(buffer),
469 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); 473 DatapathMode::Block(block_size(size_of::<DataBlock>())),
474 );
470 self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?; 475 self.sdmmc.cmd(common_cmd::read_multiple_blocks(address), true)?;
471 476
472 self.sdmmc.complete_datapath_transfer(transfer, false).await?; 477 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
@@ -497,9 +502,10 @@ impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
497 #[cfg(sdmmc_v1)] 502 #[cfg(sdmmc_v1)]
498 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; 503 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
499 504
500 let transfer = self 505 let transfer = self.sdmmc.prepare_datapath_write(
501 .sdmmc 506 aligned_ref(&buffer.0),
502 .prepare_datapath_write(&buffer.0, block_size(size_of::<DataBlock>()), false); 507 DatapathMode::Block(block_size(size_of::<DataBlock>())),
508 );
503 509
504 #[cfg(sdmmc_v2)] 510 #[cfg(sdmmc_v2)]
505 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?; 511 self.sdmmc.cmd(common_cmd::write_single_block(address), true)?;
@@ -548,10 +554,10 @@ impl<'a, 'b, A: Addressable> StorageDevice<'a, 'b, A> {
548 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 554 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
549 555
550 // Setup write command 556 // Setup write command
551 let transfer = self 557 let transfer = self.sdmmc.prepare_datapath_write(
552 .sdmmc 558 aligned_ref(buffer),
553 .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), false); 559 DatapathMode::Block(block_size(size_of::<DataBlock>())),
554 560 );
555 #[cfg(sdmmc_v2)] 561 #[cfg(sdmmc_v2)]
556 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 562 self.sdmmc.cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25
557 563
diff --git a/embassy-stm32/src/sdmmc/sdio.rs b/embassy-stm32/src/sdmmc/sdio.rs
index 1412b21fc..e436d68cb 100644
--- a/embassy-stm32/src/sdmmc/sdio.rs
+++ b/embassy-stm32/src/sdmmc/sdio.rs
@@ -1,10 +1,11 @@
1use core::ops::{Deref, DerefMut}; 1use core::ops::{Deref, DerefMut};
2 2
3use aligned::{A4, Aligned};
3use sdio_host::common_cmd::{R1, Rz, cmd}; 4use sdio_host::common_cmd::{R1, Rz, cmd};
4use sdio_host::sd::BusWidth; 5use sdio_host::sd::BusWidth;
5use sdio_host::sd_cmd; 6use sdio_host::sd_cmd;
6 7
7use crate::sdmmc::{Error, Sdmmc, block_size, slice8_mut, slice8_ref}; 8use crate::sdmmc::{DatapathMode, Error, Sdmmc, aligned_mut, aligned_ref, block_size, slice8_mut, slice8_ref};
8use crate::time::Hertz; 9use crate::time::Hertz;
9 10
10/// Aligned data block for SDMMC transfers. 11/// Aligned data block for SDMMC transfers.
@@ -39,7 +40,7 @@ impl DerefMut for DataBlock {
39/// Storage Device 40/// Storage Device
40pub struct SerialDataInterface<'a, 'b> { 41pub struct SerialDataInterface<'a, 'b> {
41 /// Inner member 42 /// Inner member
42 pub sdmmc: &'a mut Sdmmc<'b>, 43 sdmmc: &'a mut Sdmmc<'b>,
43} 44}
44 45
45/// Card Storage Device 46/// Card Storage Device
@@ -101,9 +102,10 @@ impl<'a, 'b> SerialDataInterface<'a, 'b> {
101 ) 102 )
102 }; 103 };
103 104
104 let transfer = self 105 let transfer = self.sdmmc.prepare_datapath_read(
105 .sdmmc 106 aligned_mut(buffer),
106 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); 107 DatapathMode::Block(block_size(size_of::<DataBlock>())),
108 );
107 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; 109 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
108 110
109 self.sdmmc.complete_datapath_transfer(transfer, false).await?; 111 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
@@ -113,12 +115,10 @@ impl<'a, 'b> SerialDataInterface<'a, 'b> {
113 } 115 }
114 116
115 /// Read in multibyte mode using cmd53 117 /// Read in multibyte mode using cmd53
116 pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut [u32]) -> Result<(), Error> { 118 pub async fn cmd53_byte_read(&mut self, arg: u32, buffer: &mut Aligned<A4, [u8]>) -> Result<(), Error> {
117 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop(); 119 let _scoped_block_stop = self.sdmmc.info.rcc.block_stop();
118 120
119 let transfer = self 121 let transfer = self.sdmmc.prepare_datapath_read(buffer, DatapathMode::Byte);
120 .sdmmc
121 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), true);
122 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; 122 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
123 123
124 self.sdmmc.complete_datapath_transfer(transfer, false).await?; 124 self.sdmmc.complete_datapath_transfer(transfer, false).await?;
@@ -142,9 +142,10 @@ impl<'a, 'b> SerialDataInterface<'a, 'b> {
142 #[cfg(sdmmc_v1)] 142 #[cfg(sdmmc_v1)]
143 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; 143 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
144 144
145 let transfer = self 145 let transfer = self.sdmmc.prepare_datapath_write(
146 .sdmmc 146 aligned_ref(buffer),
147 .prepare_datapath_read(buffer, block_size(size_of::<DataBlock>()), false); 147 DatapathMode::Block(block_size(size_of::<DataBlock>())),
148 );
148 149
149 #[cfg(sdmmc_v2)] 150 #[cfg(sdmmc_v2)]
150 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; 151 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
@@ -164,7 +165,7 @@ impl<'a, 'b> SerialDataInterface<'a, 'b> {
164 165
165 let transfer = self 166 let transfer = self
166 .sdmmc 167 .sdmmc
167 .prepare_datapath_write(buffer, block_size(size_of::<DataBlock>()), true); 168 .prepare_datapath_write(aligned_ref(buffer), DatapathMode::Byte);
168 169
169 #[cfg(sdmmc_v2)] 170 #[cfg(sdmmc_v2)]
170 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?; 171 self.sdmmc.cmd(cmd::<Rz>(53, arg), true)?;
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/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-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 9a5f0fd1d..4ffa58778 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -97,6 +97,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
97 self.timer.get_channel_enable_state(self.channel) 97 self.timer.get_channel_enable_state(self.channel)
98 } 98 }
99 99
100 /// Get the frequency of the PWM channel.
101 pub fn get_frequency(&self) -> Hertz {
102 self.timer.get_frequency()
103 }
104
100 /// Get max duty value. 105 /// Get max duty value.
101 /// 106 ///
102 /// This value depends on the configured frequency and the timer's clock rate from RCC. 107 /// This value depends on the configured frequency and the timer's clock rate from RCC.
@@ -330,6 +335,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
330 self.inner.set_frequency_internal(freq * multiplier, 16); 335 self.inner.set_frequency_internal(freq * multiplier, 16);
331 } 336 }
332 337
338 /// Get the PWM driver frequency.
339 pub fn get_frequency(&self) -> Hertz {
340 self.inner.get_frequency()
341 }
342
333 /// Get max duty value. 343 /// Get max duty value.
334 /// 344 ///
335 /// This value depends on the configured frequency and the timer's clock rate from RCC. 345 /// This value depends on the configured frequency and the timer's clock rate from RCC.
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/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 d07cc4272..347659f5b 100644
--- a/examples/mcxa/Cargo.toml
+++ b/examples/mcxa/Cargo.toml
@@ -21,6 +21,7 @@ embassy-time-driver = "0.2.1"
21embedded-io-async = "0.6.1" 21embedded-io-async = "0.6.1"
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"
24static_cell = "2.1.1" 25static_cell = "2.1.1"
25tmp108 = "0.4.0" 26tmp108 = "0.4.0"
26 27
diff --git a/examples/mcxa/src/bin/trng.rs b/examples/mcxa/src/bin/trng.rs
new file mode 100644
index 000000000..5f6e2408c
--- /dev/null
+++ b/examples/mcxa/src/bin/trng.rs
@@ -0,0 +1,106 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use hal::bind_interrupts;
6use hal::config::Config;
7use hal::trng::{self, InterruptHandler, Trng};
8use rand_core::RngCore;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10
11bind_interrupts!(
12 struct Irqs {
13 TRNG0 => InterruptHandler;
14 }
15);
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let config = Config::default();
20 let mut p = hal::init(config);
21
22 defmt::info!("TRNG example");
23
24 let mut trng = Trng::new_blocking_128(p.TRNG0.reborrow());
25 let rand = trng.blocking_next_u32();
26 defmt::info!("128-bit {}", rand);
27
28 drop(trng);
29
30 let mut trng = Trng::new_blocking_256(p.TRNG0.reborrow());
31 let rand = trng.blocking_next_u32();
32 defmt::info!("256-bit {}", rand);
33
34 drop(trng);
35
36 let mut trng = Trng::new_blocking_512(p.TRNG0.reborrow());
37 let rand = trng.blocking_next_u32();
38 defmt::info!("512-bit {}", rand);
39
40 drop(trng);
41
42 let config = trng::Config::default();
43 let mut trng = Trng::new_blocking_with_custom_config(p.TRNG0.reborrow(), config);
44
45 defmt::info!("========== BLOCKING ==========");
46
47 defmt::info!("Generate 10 u32");
48 for _ in 0..10 {
49 let rand = trng.blocking_next_u32();
50 defmt::info!("{}", rand);
51 }
52
53 defmt::info!("Generate 10 u64");
54 for _ in 0..10 {
55 let rand = trng.blocking_next_u64();
56 defmt::info!("{}", rand);
57 }
58
59 let mut buf = [0_u8; 256];
60
61 defmt::info!("Generate 10 256-byte buffers");
62 for _ in 0..10 {
63 trng.blocking_fill_bytes(&mut buf);
64 defmt::info!("{:02x}", buf);
65 }
66
67 defmt::info!("RngCore");
68
69 for _ in 0..10 {
70 defmt::info!("u32: {}", trng.next_u32());
71 defmt::info!("u64: {}", trng.next_u64());
72 }
73
74 drop(trng);
75
76 defmt::info!("========== ASYNC ==========");
77
78 let mut trng = Trng::new_with_custom_config(p.TRNG0.reborrow(), Irqs, config);
79
80 defmt::info!("Generate 10 u32");
81 for _ in 0..10 {
82 let rand = trng.async_next_u32().await.unwrap();
83 defmt::info!("{}", rand);
84 }
85
86 defmt::info!("Generate 10 u64");
87 for _ in 0..10 {
88 let rand = trng.async_next_u64().await.unwrap();
89 defmt::info!("{}", rand);
90 }
91
92 let mut buf = [0_u8; 256];
93
94 defmt::info!("Generate 10 256-byte buffers");
95 for _ in 0..10 {
96 trng.async_fill_bytes(&mut buf).await.unwrap();
97 defmt::info!("{:02x}", buf);
98 }
99
100 defmt::info!("RngCore");
101
102 for _ in 0..10 {
103 defmt::info!("u32: {}", trng.next_u32());
104 defmt::info!("u64: {}", trng.next_u64());
105 }
106}
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
index dc09e97e7..ada112833 100644
--- a/examples/mimxrt6/Cargo.toml
+++ b/examples/mimxrt6/Cargo.toml
@@ -21,6 +21,8 @@ embedded-hal-async = "1.0.0"
21 21
22mimxrt600-fcb = "0.2.2" 22mimxrt600-fcb = "0.2.2"
23panic-probe = { version = "1.0.0", features = ["print-defmt"] } 23panic-probe = { version = "1.0.0", features = ["print-defmt"] }
24embedded-hal-bus = "0.3.0"
25is31fl3743b-driver = { version = "0.1.1", features = ["is_blocking"] }
24 26
25# cargo build/run 27# cargo build/run
26[profile.dev] 28[profile.dev]
diff --git a/examples/mimxrt6/src/bin/dma.rs b/examples/mimxrt6/src/bin/dma.rs
new file mode 100644
index 000000000..b490efc6b
--- /dev/null
+++ b/examples/mimxrt6/src/bin/dma.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_imxrt::dma::copy;
9use {defmt_rtt as _, panic_probe as _};
10
11const BUFLEN: usize = 1024;
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_imxrt::init(Default::default());
16
17 info!("Test memory-to-memory DMA transfers");
18
19 let src = [0x55u8; BUFLEN];
20 let mut dst = [0u8; BUFLEN];
21
22 unsafe { copy(p.DMA0_CH0, &src, &mut dst) }.await;
23 assert!(dst == src);
24
25 info!("DMA copy succeeded");
26}
diff --git a/examples/mimxrt6/src/bin/spi-async.rs b/examples/mimxrt6/src/bin/spi-async.rs
new file mode 100644
index 000000000..aa56f7c42
--- /dev/null
+++ b/examples/mimxrt6/src/bin/spi-async.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_imxrt::bind_interrupts;
7use embassy_imxrt::flexcomm::spi::{InterruptHandler, Spi};
8use embassy_imxrt::peripherals::FLEXCOMM5;
9use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 FLEXCOMM5 => InterruptHandler<FLEXCOMM5>;
13});
14
15const BUFLEN: usize = 1024;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_imxrt::init(Default::default());
20
21 info!("Initializing SPI");
22
23 let mut spi = Spi::new_async(p.FLEXCOMM5, p.PIO1_3, p.PIO1_5, p.PIO1_4, Irqs, Default::default());
24
25 let mut rxbuf = [0x55; BUFLEN];
26 let txbuf = [0xaa; BUFLEN];
27
28 for _ in 0..10 {
29 spi.async_transfer(&mut rxbuf, &txbuf).await.unwrap();
30 assert!(rxbuf.iter().all(|b| *b == 0xaa));
31 rxbuf.fill(0x55);
32 }
33
34 info!("SPI transfers succeeded");
35}
diff --git a/examples/mimxrt6/src/bin/spi.rs b/examples/mimxrt6/src/bin/spi.rs
new file mode 100644
index 000000000..4854432e8
--- /dev/null
+++ b/examples/mimxrt6/src/bin/spi.rs
@@ -0,0 +1,51 @@
1#![no_std]
2#![no_main]
3
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_imxrt::flexcomm::spi::Spi;
7use embassy_imxrt::gpio;
8use embassy_time::{Delay, Timer};
9use embedded_hal_bus::spi::ExclusiveDevice;
10use is31fl3743b_driver::{CSy, Is31fl3743b, SWx};
11use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_imxrt::init(Default::default());
16
17 info!("Initializing SPI");
18
19 let cs = gpio::Output::new(
20 p.PIO1_6,
21 gpio::Level::Low,
22 gpio::DriveMode::PushPull,
23 gpio::DriveStrength::Normal,
24 gpio::SlewRate::Standard,
25 );
26
27 let spi = Spi::new_blocking(p.FLEXCOMM5, p.PIO1_3, p.PIO1_5, p.PIO1_4, Default::default());
28 let delay = Delay;
29
30 // One SPI device only on the SPI bus
31 let spi_dev = ExclusiveDevice::new(spi, cs, delay).unwrap();
32
33 // Instantiate IS31FL3743B device
34 let mut driver = Is31fl3743b::new(spi_dev).unwrap();
35
36 // Enable phase delay to help reduce power noise
37 let _ = driver.enable_phase_delay();
38 // Set global current, check method documentation for more info
39 let _ = driver.set_global_current(90);
40
41 let _ = driver.set_led_peak_current_bulk(SWx::SW1, CSy::CS1, &[100; 11 * 18]);
42
43 // Driver is fully set up, we can now start turning on LEDs!
44 // Create a white breathing effect
45 loop {
46 for brightness in (0..=255_u8).chain((0..=255).rev()) {
47 let _ = driver.set_led_brightness_bulk(SWx::SW1, CSy::CS1, &[brightness; 11 * 18]);
48 Timer::after_micros(1).await;
49 }
50 }
51}
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..a57bd7b24 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/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", "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.6.0", features = ["defmt-03"] }
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 97efe58e8..b8d5dbfb1 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/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", "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.6.1" }
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
index f34df0f26..353d1b46e 100644
--- a/examples/nrf54l15/Cargo.toml
+++ b/examples/nrf54l15/Cargo.toml
@@ -10,7 +10,7 @@ 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.6.0", features = ["defmt-03"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16 16
diff --git a/examples/nrf54l15/src/bin/nvmc.rs b/examples/nrf54l15/src/bin/rramc.rs
index f990604cd..f990604cd 100644
--- a/examples/nrf54l15/src/bin/nvmc.rs
+++ b/examples/nrf54l15/src/bin/rramc.rs
diff --git a/examples/nrf54l15/src/bin/rramc_buffered.rs b/examples/nrf54l15/src/bin/rramc_buffered.rs
new file mode 100644
index 000000000..06c9585ed
--- /dev/null
+++ b/examples/nrf54l15/src/bin/rramc_buffered.rs
@@ -0,0 +1,59 @@
1#![no_std]
2#![no_main]
3
4use defmt::{info, unwrap};
5use embassy_executor::Spawner;
6use embassy_nrf::rramc::{Buffered, PAGE_SIZE, Rramc};
7use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 info!("Hello RRAMC NVMC!");
14
15 // Buffer 8 word lines
16 let mut f: Rramc<'_, Buffered<128>> = Rramc::new_buffered(p.RRAMC);
17
18 const ADDR: u32 = 0x80000;
19 let mut buf = [0u8; 4];
20
21 info!("Reading...");
22 unwrap!(f.read(ADDR, &mut buf));
23 info!("Read: {=[u8]:x}", buf);
24
25 info!("Erasing...");
26 unwrap!(f.erase(ADDR, ADDR + PAGE_SIZE as u32));
27
28 info!("Reading...");
29 unwrap!(f.read(ADDR, &mut buf));
30 info!("Read: {=[u8]:x}", buf);
31
32 info!("Writing...");
33 // 16 B (128-bit) write minimum
34 let out: [u8; 256] = [
35 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa,
36 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa,
37 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb,
38 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb,
39 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc,
40 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc,
41 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd,
42 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd,
43 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa,
44 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa,
45 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb,
46 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb,
47 0xcc, 0xcc, 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc,
48 0xcc, 0xcc, 0xdd, 0xdd, 0xdd, 0xdd, 0xaa, 0xaa, 0xaa, 0xaa, 0xbb, 0xbb, 0xbb, 0xbb, 0xcc, 0xcc, 0xcc, 0xcc,
49 0xdd, 0xdd, 0xdd, 0xdd,
50 ];
51 unwrap!(f.write(ADDR, &out));
52
53 info!("Reading...");
54 // Can read arbitrary sizes
55 for addr in (ADDR..ADDR + 256).step_by(4) {
56 unwrap!(f.read(addr, &mut buf));
57 info!("Read: {=[u8]:x}", buf);
58 }
59}
diff --git a/examples/nrf54lm20/Cargo.toml b/examples/nrf54lm20/Cargo.toml
index 5482fc77a..e3bf22b25 100644
--- a/examples/nrf54lm20/Cargo.toml
+++ b/examples/nrf54lm20/Cargo.toml
@@ -10,7 +10,7 @@ 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.6.0", features = ["defmt-03"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16 16
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..907b06e6d 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
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/std/Cargo.toml b/examples/std/Cargo.toml
index 6dc6a353d..0e3b3c6d5 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -10,7 +10,7 @@ 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.6.1" }
16embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] } 16embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] }
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
index 82272c798..685dbf3d3 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -52,7 +52,7 @@ async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: Seri
52 password: b"mypass", 52 password: b"mypass",
53 }; 53 };
54 54
55 runner 55 let r = runner
56 .run(port, config, |ipv4| { 56 .run(port, config, |ipv4| {
57 let Some(addr) = ipv4.address else { 57 let Some(addr) = ipv4.address else {
58 warn!("PPP did not provide an IP address."); 58 warn!("PPP did not provide an IP address.");
@@ -69,9 +69,10 @@ async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: Seri
69 }); 69 });
70 stack.set_config_v4(config); 70 stack.set_config_v4(config);
71 }) 71 })
72 .await 72 .await;
73 .unwrap(); 73 match r {
74 unreachable!() 74 Err(e) => panic!("{:?}", e),
75 }
75} 76}
76 77
77#[embassy_executor::task] 78#[embassy_executor::task]
diff --git a/examples/std/src/bin/tick_cancel.rs b/examples/std/src/bin/tick_cancel.rs
new file mode 100644
index 000000000..54e44790f
--- /dev/null
+++ b/examples/std/src/bin/tick_cancel.rs
@@ -0,0 +1,47 @@
1use std::sync::atomic::{AtomicBool, Ordering};
2use std::thread;
3use std::time::Duration;
4
5use embassy_executor::Executor;
6use embassy_time::Timer;
7use log::*;
8use static_cell::StaticCell;
9
10#[embassy_executor::task]
11async fn run() {
12 loop {
13 info!("tick");
14 Timer::after_secs(1).await;
15 }
16}
17
18static DONE: StaticCell<AtomicBool> = StaticCell::new();
19static EXECUTOR: StaticCell<Executor> = StaticCell::new();
20
21fn main() {
22 env_logger::builder()
23 .filter_level(log::LevelFilter::Debug)
24 .format_timestamp_nanos()
25 .init();
26
27 let done = DONE.init(AtomicBool::new(false));
28 let done_cb = || done.load(Ordering::Relaxed);
29
30 let server_thread = thread::spawn(move || {
31 let executor = EXECUTOR.init(Executor::new());
32 executor.run_until(
33 |spawner| {
34 spawner.spawn(run().unwrap());
35 },
36 done_cb,
37 );
38 info!("Executor finished");
39 });
40
41 thread::sleep(Duration::from_secs(5));
42
43 info!("Cancelling executor");
44 done.store(true, Ordering::Relaxed);
45
46 server_thread.join().unwrap();
47}
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/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/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index dde431bba..2a46473b7 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2025-09-26" 2channel = "nightly-2025-12-11"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 5d925c934..1f47bee1e 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "1.90" 2channel = "1.92"
3components = [ "rust-src", "rustfmt", "llvm-tools" ] 3components = [ "rust-src", "rustfmt", "llvm-tools" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 3a9b86cef..50f059b34 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/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-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.6.1", features = ["defmt-03"] }
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"] }