diff options
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 | |||
| 14 | export CARGO_NET_GIT_FETCH_WITH_CLI=true | 14 | export CARGO_NET_GIT_FETCH_WITH_CLI=true |
| 15 | 15 | ||
| 16 | cargo install espup --locked | 16 | cargo install espup --locked |
| 17 | espup install --toolchain-version 1.88.0.0 | 17 | espup install --toolchain-version 1.90.0.0 |
| 18 | 18 | ||
| 19 | # Restore lockfiles | 19 | # Restore lockfiles |
| 20 | if [ -f /ci/cache/lockfiles.tar ]; then | 20 | if [ -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", |
| @@ -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 |
| 36 | rm -rf out/tests/mspm0g3507 | 36 | rm -rf out/tests/mspm0g3507 |
| 37 | 37 | ||
| 38 | # rm out/tests/stm32wb55rg/wpan_mac | 38 | rm out/tests/stm32wb55rg/wpan_mac |
| 39 | rm out/tests/stm32wb55rg/wpan_ble | 39 | rm 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] |
| 10 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] } | 11 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] } |
| 12 | embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } | 12 | embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } |
| 13 | 13 | ||
| 14 | defmt = "1.0.1" | 14 | defmt = "1.0.1" |
| 15 | defmt-rtt = "1.0.0" | 15 | defmt-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] |
| 2 | edition = "2024" | 2 | edition = "2024" |
| 3 | name = "embassy-boot-nrf" | 3 | name = "embassy-boot-nrf" |
| 4 | version = "0.9.0" | 4 | version = "0.10.0" |
| 5 | description = "Bootloader lib for nRF chips" | 5 | description = "Bootloader lib for nRF chips" |
| 6 | license = "MIT OR Apache-2.0" | 6 | license = "MIT OR Apache-2.0" |
| 7 | repository = "https://github.com/embassy-rs/embassy" | 7 | repository = "https://github.com/embassy-rs/embassy" |
| @@ -36,7 +36,7 @@ defmt = { version = "1.0.1", optional = true } | |||
| 36 | log = { version = "0.4.17", optional = true } | 36 | log = { version = "0.4.17", optional = true } |
| 37 | 37 | ||
| 38 | embassy-sync = { version = "0.7.2", path = "../embassy-sync" } | 38 | embassy-sync = { version = "0.7.2", path = "../embassy-sync" } |
| 39 | embassy-nrf = { version = "0.8.0", path = "../embassy-nrf", default-features = false } | 39 | embassy-nrf = { version = "0.9.0", path = "../embassy-nrf", default-features = false } |
| 40 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } | 40 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } |
| 41 | cortex-m = { version = "0.7.6" } | 41 | cortex-m = { version = "0.7.6" } |
| 42 | cortex-m-rt = { version = "0.7" } | 42 | cortex-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`: | 8 | help: 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" | |||
| 103 | paste = "1.0" | 103 | paste = "1.0" |
| 104 | 104 | ||
| 105 | # PACs | 105 | # PACs |
| 106 | mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } | 106 | mimxrt685s-pac = { version = "0.5.0", optional = true, features = ["rt", "critical-section"] } |
| 107 | mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } | 107 | mimxrt633s-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; | |||
| 16 | use crate::sealed::Sealed; | 16 | use crate::sealed::Sealed; |
| 17 | use crate::{BitIter, interrupt, pac, peripherals}; | 17 | use crate::{BitIter, interrupt, pac, peripherals}; |
| 18 | 18 | ||
| 19 | pub(crate) const MAX_CHUNK_SIZE: usize = 1024; | ||
| 20 | |||
| 19 | #[cfg(feature = "rt")] | 21 | #[cfg(feature = "rt")] |
| 20 | #[interrupt] | 22 | #[interrupt] |
| 21 | fn DMA0() { | 23 | fn 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. |
| 71 | pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> { | 73 | pub 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. |
| 89 | pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> { | 91 | pub 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 | ||
| 3 | pub mod spi; | ||
| 3 | pub mod uart; | 4 | pub mod uart; |
| 4 | 5 | ||
| 5 | use paste::paste; | 6 | use 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 | |||
| 3 | use core::future::{Future, poll_fn}; | ||
| 4 | use core::marker::PhantomData; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_embedded_hal::SetConfig; | ||
| 8 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | pub use embedded_hal_1::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity}; | ||
| 11 | use paste::paste; | ||
| 12 | |||
| 13 | use crate::flexcomm::Clock; | ||
| 14 | use crate::gpio::{AnyPin, GpioPin as Pin}; | ||
| 15 | use crate::interrupt; | ||
| 16 | use crate::interrupt::typelevel::Interrupt; | ||
| 17 | use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate}; | ||
| 18 | use crate::pac::spi0::cfg::{Cpha, Cpol}; | ||
| 19 | |||
| 20 | /// Driver move trait. | ||
| 21 | #[allow(private_bounds)] | ||
| 22 | pub trait IoMode: sealed::Sealed {} | ||
| 23 | |||
| 24 | /// Blocking mode. | ||
| 25 | pub struct Blocking; | ||
| 26 | impl sealed::Sealed for Blocking {} | ||
| 27 | impl IoMode for Blocking {} | ||
| 28 | |||
| 29 | /// Async mode. | ||
| 30 | pub struct Async; | ||
| 31 | impl sealed::Sealed for Async {} | ||
| 32 | impl 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] | ||
| 38 | pub enum Error { | ||
| 39 | // No errors for now. | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Spi driver. | ||
| 43 | pub struct Spi<'a, M: IoMode> { | ||
| 44 | info: Info, | ||
| 45 | _phantom: PhantomData<&'a M>, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'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 | |||
| 99 | impl<'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 | |||
| 226 | impl<'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 | |||
| 553 | impl<'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)] | ||
| 693 | pub struct Config { | ||
| 694 | /// Frequency in Hertz. | ||
| 695 | pub frequency: u32, | ||
| 696 | /// SPI operating mode. | ||
| 697 | pub mode: Mode, | ||
| 698 | } | ||
| 699 | |||
| 700 | impl Default for Config { | ||
| 701 | fn default() -> Self { | ||
| 702 | Self { | ||
| 703 | frequency: 1_000_000, | ||
| 704 | mode: MODE_0, | ||
| 705 | } | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | struct 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 | ||
| 721 | unsafe impl Send for Info {} | ||
| 722 | |||
| 723 | trait SealedInstance { | ||
| 724 | fn info() -> Info; | ||
| 725 | } | ||
| 726 | |||
| 727 | /// Spi interrupt handler. | ||
| 728 | pub struct InterruptHandler<T: Instance> { | ||
| 729 | _phantom: PhantomData<T>, | ||
| 730 | } | ||
| 731 | |||
| 732 | impl<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)] | ||
| 763 | pub trait Instance: crate::flexcomm::IntoSpi + SealedInstance + PeripheralType + 'static + Send { | ||
| 764 | /// Interrupt for this Spi instance. | ||
| 765 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 766 | } | ||
| 767 | |||
| 768 | macro_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 | |||
| 792 | impl_instance!(0, 1, 2, 3, 4, 5, 6, 7, 14); | ||
| 793 | |||
| 794 | mod sealed { | ||
| 795 | /// Seal a trait | ||
| 796 | pub trait Sealed {} | ||
| 797 | } | ||
| 798 | |||
| 799 | impl<T: Pin> sealed::Sealed for T {} | ||
| 800 | |||
| 801 | /// IO configuration trait for Spi clk | ||
| 802 | pub 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 | ||
| 808 | pub 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 | ||
| 814 | pub 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 | |||
| 819 | macro_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 | ||
| 842 | impl_pin_trait!(FLEXCOMM0, sck, PIO0_0, F1, PIO3_0, F5); | ||
| 843 | impl_pin_trait!(FLEXCOMM0, miso, PIO0_1, F1, PIO3_1, F5); | ||
| 844 | impl_pin_trait!(FLEXCOMM0, mosi, PIO0_2, F1, PIO3_2, F5); | ||
| 845 | |||
| 846 | // FLEXCOMM1 | ||
| 847 | impl_pin_trait!(FLEXCOMM1, sck, PIO0_7, F1, PIO7_25, F1); | ||
| 848 | impl_pin_trait!(FLEXCOMM1, miso, PIO0_8, F1, PIO7_26, F1); | ||
| 849 | impl_pin_trait!(FLEXCOMM1, mosi, PIO0_9, F1, PIO7_28, F1); | ||
| 850 | |||
| 851 | // FLEXCOMM2 | ||
| 852 | impl_pin_trait!(FLEXCOMM2, sck, PIO0_14, F1, PIO7_29, F5); | ||
| 853 | impl_pin_trait!(FLEXCOMM2, miso, PIO0_15, F1, PIO7_30, F5); | ||
| 854 | impl_pin_trait!(FLEXCOMM2, mosi, PIO0_16, F1, PIO7_31, F5); | ||
| 855 | |||
| 856 | // FLEXCOMM3 | ||
| 857 | impl_pin_trait!(FLEXCOMM3, sck, PIO0_21, F1); | ||
| 858 | impl_pin_trait!(FLEXCOMM3, miso, PIO0_22, F1); | ||
| 859 | impl_pin_trait!(FLEXCOMM3, mosi, PIO0_23, F1); | ||
| 860 | |||
| 861 | // FLEXCOMM4 | ||
| 862 | impl_pin_trait!(FLEXCOMM4, sck, PIO0_28, F1); | ||
| 863 | impl_pin_trait!(FLEXCOMM4, miso, PIO0_29, F1); | ||
| 864 | impl_pin_trait!(FLEXCOMM4, mosi, PIO0_30, F1); | ||
| 865 | |||
| 866 | // FLEXCOMM5 | ||
| 867 | impl_pin_trait!(FLEXCOMM5, sck, PIO1_3, F1, PIO3_15, F5); | ||
| 868 | impl_pin_trait!(FLEXCOMM5, miso, PIO1_4, F1, PIO3_16, F5); | ||
| 869 | impl_pin_trait!(FLEXCOMM5, mosi, PIO1_5, F1, PIO3_17, F5); | ||
| 870 | |||
| 871 | // FLEXCOMM6 | ||
| 872 | impl_pin_trait!(FLEXCOMM6, sck, PIO3_25, F1); | ||
| 873 | impl_pin_trait!(FLEXCOMM6, miso, PIO3_26, F1); | ||
| 874 | impl_pin_trait!(FLEXCOMM6, mosi, PIO3_27, F1); | ||
| 875 | |||
| 876 | // FLEXCOMM7 | ||
| 877 | impl_pin_trait!(FLEXCOMM7, sck, PIO4_0, F1); | ||
| 878 | impl_pin_trait!(FLEXCOMM7, miso, PIO4_1, F1); | ||
| 879 | impl_pin_trait!(FLEXCOMM7, mosi, PIO4_2, F1); | ||
| 880 | |||
| 881 | // FLEXCOMM14 | ||
| 882 | impl_pin_trait!(FLEXCOMM14, sck, PIO1_11, F1); | ||
| 883 | impl_pin_trait!(FLEXCOMM14, miso, PIO1_12, F1); | ||
| 884 | impl_pin_trait!(FLEXCOMM14, mosi, PIO1_13, F1); | ||
| 885 | |||
| 886 | /// Spi Tx DMA trait. | ||
| 887 | #[allow(private_bounds)] | ||
| 888 | pub trait TxDma<T: Instance>: crate::dma::Channel {} | ||
| 889 | |||
| 890 | /// Spi Rx DMA trait. | ||
| 891 | #[allow(private_bounds)] | ||
| 892 | pub trait RxDma<T: Instance>: crate::dma::Channel {} | ||
| 893 | |||
| 894 | macro_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 | |||
| 902 | impl_dma!(FLEXCOMM0, Rx, DMA0_CH0); | ||
| 903 | impl_dma!(FLEXCOMM0, Tx, DMA0_CH1); | ||
| 904 | |||
| 905 | impl_dma!(FLEXCOMM1, Rx, DMA0_CH2); | ||
| 906 | impl_dma!(FLEXCOMM1, Tx, DMA0_CH3); | ||
| 907 | |||
| 908 | impl_dma!(FLEXCOMM2, Rx, DMA0_CH4); | ||
| 909 | impl_dma!(FLEXCOMM2, Tx, DMA0_CH5); | ||
| 910 | |||
| 911 | impl_dma!(FLEXCOMM3, Rx, DMA0_CH6); | ||
| 912 | impl_dma!(FLEXCOMM3, Tx, DMA0_CH7); | ||
| 913 | |||
| 914 | impl_dma!(FLEXCOMM4, Rx, DMA0_CH8); | ||
| 915 | impl_dma!(FLEXCOMM4, Tx, DMA0_CH9); | ||
| 916 | |||
| 917 | impl_dma!(FLEXCOMM5, Rx, DMA0_CH10); | ||
| 918 | impl_dma!(FLEXCOMM5, Tx, DMA0_CH11); | ||
| 919 | |||
| 920 | impl_dma!(FLEXCOMM6, Rx, DMA0_CH12); | ||
| 921 | impl_dma!(FLEXCOMM6, Tx, DMA0_CH13); | ||
| 922 | |||
| 923 | impl_dma!(FLEXCOMM7, Rx, DMA0_CH14); | ||
| 924 | impl_dma!(FLEXCOMM7, Tx, DMA0_CH15); | ||
| 925 | |||
| 926 | impl_dma!(FLEXCOMM14, Rx, DMA0_CH16); | ||
| 927 | impl_dma!(FLEXCOMM14, Tx, DMA0_CH17); | ||
| 928 | |||
| 929 | // ============================== | ||
| 930 | |||
| 931 | impl<'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 | |||
| 939 | impl<'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 | |||
| 947 | impl embedded_hal_1::spi::Error for Error { | ||
| 948 | fn kind(&self) -> embedded_hal_1::spi::ErrorKind { | ||
| 949 | match *self {} | ||
| 950 | } | ||
| 951 | } | ||
| 952 | |||
| 953 | impl<'d, M: IoMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { | ||
| 954 | type Error = Error; | ||
| 955 | } | ||
| 956 | |||
| 957 | impl<'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 | |||
| 979 | impl<'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 | |||
| 1003 | impl<'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" } | |||
| 39 | embedded-io = "0.6" | 39 | embedded-io = "0.6" |
| 40 | embedded-io-async = { version = "0.6.1" } | 40 | embedded-io-async = { version = "0.6.1" } |
| 41 | heapless = "0.8" | 41 | heapless = "0.8" |
| 42 | mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "02bd04a21ef8f8f67f88239ff5df765bb7e60fd8" } | 42 | mcxa-pac = { version = "0.1.0", features = ["rt", "critical-section"] } |
| 43 | nb = "1.1.0" | 43 | nb = "1.1.0" |
| 44 | paste = "1.0.15" | 44 | paste = "1.0.15" |
| 45 | maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } | 45 | maitake-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 | |||
| 48 | embassy-time = { version = "0.5.0", optional = true } | 48 | embassy-time = { version = "0.5.0", optional = true } |
| 49 | embassy-time-driver = { version = "0.2.1", optional = true } | 49 | embassy-time-driver = { version = "0.2.1", optional = true } |
| 50 | 50 | ||
| 51 | rand-core-06 = { package = "rand_core", version = "0.6" } | ||
| 52 | rand-core-09 = { package = "rand_core", version = "0.9" } | ||
| 53 | |||
| 51 | [features] | 54 | [features] |
| 52 | default = ["rt"] | 55 | default = ["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; | |||
| 19 | pub mod ostimer; | 19 | pub mod ostimer; |
| 20 | pub mod reset_reason; | 20 | pub mod reset_reason; |
| 21 | pub mod rtc; | 21 | pub mod rtc; |
| 22 | pub mod trng; | ||
| 22 | 23 | ||
| 23 | use crate::interrupt::InterruptExt; | 24 | use crate::interrupt::InterruptExt; |
| 24 | pub use crate::pac::NVIC_PRIO_BITS; | 25 | pub 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 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use embassy_hal_internal::Peri; | ||
| 6 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 7 | use maitake_sync::WaitCell; | ||
| 8 | use mcxa_pac::trng0::osc2_ctl::TrngEntCtl; | ||
| 9 | |||
| 10 | use crate::clocks::enable_and_reset; | ||
| 11 | use crate::clocks::periph_helpers::NoConfig; | ||
| 12 | use crate::interrupt::typelevel; | ||
| 13 | use crate::interrupt::typelevel::Handler; | ||
| 14 | use crate::peripherals::TRNG0; | ||
| 15 | |||
| 16 | static WAIT_CELL: WaitCell = WaitCell::new(); | ||
| 17 | |||
| 18 | #[allow(private_bounds)] | ||
| 19 | pub trait Mode: sealed::SealedMode {} | ||
| 20 | |||
| 21 | mod sealed { | ||
| 22 | pub trait SealedMode {} | ||
| 23 | } | ||
| 24 | |||
| 25 | macro_rules! define_mode { | ||
| 26 | ($mode:ident) => { | ||
| 27 | pub struct $mode; | ||
| 28 | impl sealed::SealedMode for $mode {} | ||
| 29 | impl Mode for $mode {} | ||
| 30 | }; | ||
| 31 | } | ||
| 32 | |||
| 33 | define_mode!(Blocking); | ||
| 34 | define_mode!(Async); | ||
| 35 | |||
| 36 | /// TRNG Driver | ||
| 37 | pub struct Trng<'d, M: Mode> { | ||
| 38 | _peri: Peri<'d, TRNG0>, | ||
| 39 | _phantom: PhantomData<M>, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl<'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 | |||
| 212 | impl<'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 | |||
| 270 | impl<'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 | |||
| 418 | impl<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 | |||
| 429 | fn 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] | ||
| 437 | pub 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. | ||
| 452 | pub struct InterruptHandler; | ||
| 453 | |||
| 454 | impl 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] | ||
| 476 | pub 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 | |||
| 551 | impl 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] | ||
| 586 | pub 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] | ||
| 601 | pub enum SelfTest { | ||
| 602 | /// Disabled. | ||
| 603 | Disabled, | ||
| 604 | |||
| 605 | /// Enabled. | ||
| 606 | Enabled, | ||
| 607 | } | ||
| 608 | |||
| 609 | impl 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] | ||
| 622 | pub 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 | |||
| 633 | impl 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 | |||
| 643 | impl<'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 | |||
| 662 | impl<'d, M: Mode> rand_core_06::CryptoRng for Trng<'d, M> {} | ||
| 663 | |||
| 664 | impl<'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 | |||
| 678 | impl<'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" | |||
| 73 | micromath = "2.0.0" | 73 | micromath = "2.0.0" |
| 74 | 74 | ||
| 75 | # mspm0-metapac = { version = "" } | 75 | # mspm0-metapac = { version = "" } |
| 76 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852" } | 76 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-e91edd86813aa94cbb6737d34e4f1d22b8487cb6" } |
| 77 | 77 | ||
| 78 | [build-dependencies] | 78 | [build-dependencies] |
| 79 | proc-macro2 = "1.0.94" | 79 | proc-macro2 = "1.0.94" |
| @@ -81,7 +81,7 @@ quote = "1.0.40" | |||
| 81 | cfg_aliases = "0.2.1" | 81 | cfg_aliases = "0.2.1" |
| 82 | 82 | ||
| 83 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } | 83 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } |
| 84 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-f21b04e9de074af4965bf67ec3646cb9fe1b9852", default-features = false, features = ["metadata"] } | 84 | mspm0-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] |
| 87 | default = ["rt"] | 87 | default = ["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 | |||
| 157 | mspm0c1103dgs20 = ["mspm0-metapac/mspm0c1103dgs20"] | 156 | mspm0c1103dgs20 = ["mspm0-metapac/mspm0c1103dgs20"] |
| 158 | mspm0c1103dsg = ["mspm0-metapac/mspm0c1103dsg"] | ||
| 159 | mspm0c1103dyy = ["mspm0-metapac/mspm0c1103dyy"] | ||
| 160 | mspm0c1103ruk = ["mspm0-metapac/mspm0c1103ruk"] | 157 | mspm0c1103ruk = ["mspm0-metapac/mspm0c1103ruk"] |
| 158 | mspm0c1103dyy = ["mspm0-metapac/mspm0c1103dyy"] | ||
| 159 | mspm0c1103dsg = ["mspm0-metapac/mspm0c1103dsg"] | ||
| 161 | mspm0c1104dgs20 = ["mspm0-metapac/mspm0c1104dgs20"] | 160 | mspm0c1104dgs20 = ["mspm0-metapac/mspm0c1104dgs20"] |
| 162 | mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"] | ||
| 163 | mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] | ||
| 164 | mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] | 161 | mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] |
| 162 | mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] | ||
| 163 | mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"] | ||
| 165 | mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] | 164 | mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] |
| 166 | mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"] | 165 | mspm0c1105pt = ["mspm0-metapac/mspm0c1105pt"] |
| 167 | mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"] | 166 | mspm0c1105rgz = ["mspm0-metapac/mspm0c1105rgz"] |
| @@ -181,43 +180,54 @@ mspm0c1106rge = ["mspm0-metapac/mspm0c1106rge"] | |||
| 181 | mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"] | 180 | mspm0c1106dgs20 = ["mspm0-metapac/mspm0c1106dgs20"] |
| 182 | mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"] | 181 | mspm0c1106ruk = ["mspm0-metapac/mspm0c1106ruk"] |
| 183 | mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"] | 182 | mspm0c1106zcm = ["mspm0-metapac/mspm0c1106zcm"] |
| 184 | mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] | ||
| 185 | mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] | ||
| 186 | mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"] | ||
| 187 | mspm0g1105rge = ["mspm0-metapac/mspm0g1105rge"] | 183 | mspm0g1105rge = ["mspm0-metapac/mspm0g1105rge"] |
| 188 | mspm0g1105rgz = ["mspm0-metapac/mspm0g1105rgz"] | 184 | mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] |
| 189 | mspm0g1105rhb = ["mspm0-metapac/mspm0g1105rhb"] | 185 | mspm0g1105rhb = ["mspm0-metapac/mspm0g1105rhb"] |
| 190 | mspm0g1106dgs28 = ["mspm0-metapac/mspm0g1106dgs28"] | 186 | mspm0g1105rgz = ["mspm0-metapac/mspm0g1105rgz"] |
| 191 | mspm0g1106pm = ["mspm0-metapac/mspm0g1106pm"] | 187 | mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"] |
| 192 | mspm0g1106pt = ["mspm0-metapac/mspm0g1106pt"] | 188 | mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] |
| 193 | mspm0g1106rge = ["mspm0-metapac/mspm0g1106rge"] | 189 | mspm0g1106rge = ["mspm0-metapac/mspm0g1106rge"] |
| 194 | mspm0g1106rgz = ["mspm0-metapac/mspm0g1106rgz"] | 190 | mspm0g1106dgs28 = ["mspm0-metapac/mspm0g1106dgs28"] |
| 195 | mspm0g1106rhb = ["mspm0-metapac/mspm0g1106rhb"] | 191 | mspm0g1106rhb = ["mspm0-metapac/mspm0g1106rhb"] |
| 196 | mspm0g1107dgs28 = ["mspm0-metapac/mspm0g1107dgs28"] | 192 | mspm0g1106rgz = ["mspm0-metapac/mspm0g1106rgz"] |
| 197 | mspm0g1107pm = ["mspm0-metapac/mspm0g1107pm"] | 193 | mspm0g1106pt = ["mspm0-metapac/mspm0g1106pt"] |
| 198 | mspm0g1107pt = ["mspm0-metapac/mspm0g1107pt"] | 194 | mspm0g1106pm = ["mspm0-metapac/mspm0g1106pm"] |
| 199 | mspm0g1107rge = ["mspm0-metapac/mspm0g1107rge"] | 195 | mspm0g1107rge = ["mspm0-metapac/mspm0g1107rge"] |
| 200 | mspm0g1107rgz = ["mspm0-metapac/mspm0g1107rgz"] | 196 | mspm0g1107dgs28 = ["mspm0-metapac/mspm0g1107dgs28"] |
| 201 | mspm0g1107rhb = ["mspm0-metapac/mspm0g1107rhb"] | 197 | mspm0g1107rhb = ["mspm0-metapac/mspm0g1107rhb"] |
| 198 | mspm0g1107rgz = ["mspm0-metapac/mspm0g1107rgz"] | ||
| 199 | mspm0g1107pt = ["mspm0-metapac/mspm0g1107pt"] | ||
| 200 | mspm0g1107pm = ["mspm0-metapac/mspm0g1107pm"] | ||
| 202 | mspm0g1107ycj = ["mspm0-metapac/mspm0g1107ycj"] | 201 | mspm0g1107ycj = ["mspm0-metapac/mspm0g1107ycj"] |
| 203 | mspm0g1505pm = ["mspm0-metapac/mspm0g1505pm"] | ||
| 204 | mspm0g1505pt = ["mspm0-metapac/mspm0g1505pt"] | ||
| 205 | mspm0g1505rge = ["mspm0-metapac/mspm0g1505rge"] | 202 | mspm0g1505rge = ["mspm0-metapac/mspm0g1505rge"] |
| 206 | mspm0g1505rgz = ["mspm0-metapac/mspm0g1505rgz"] | ||
| 207 | mspm0g1505rhb = ["mspm0-metapac/mspm0g1505rhb"] | 203 | mspm0g1505rhb = ["mspm0-metapac/mspm0g1505rhb"] |
| 208 | mspm0g1506pm = ["mspm0-metapac/mspm0g1506pm"] | 204 | mspm0g1505rgz = ["mspm0-metapac/mspm0g1505rgz"] |
| 209 | mspm0g1506pt = ["mspm0-metapac/mspm0g1506pt"] | 205 | mspm0g1505pt = ["mspm0-metapac/mspm0g1505pt"] |
| 206 | mspm0g1505pm = ["mspm0-metapac/mspm0g1505pm"] | ||
| 210 | mspm0g1506rge = ["mspm0-metapac/mspm0g1506rge"] | 207 | mspm0g1506rge = ["mspm0-metapac/mspm0g1506rge"] |
| 211 | mspm0g1506rgz = ["mspm0-metapac/mspm0g1506rgz"] | ||
| 212 | mspm0g1506rhb = ["mspm0-metapac/mspm0g1506rhb"] | 208 | mspm0g1506rhb = ["mspm0-metapac/mspm0g1506rhb"] |
| 213 | mspm0g1507pm = ["mspm0-metapac/mspm0g1507pm"] | 209 | mspm0g1506rgz = ["mspm0-metapac/mspm0g1506rgz"] |
| 214 | mspm0g1507pt = ["mspm0-metapac/mspm0g1507pt"] | 210 | mspm0g1506pt = ["mspm0-metapac/mspm0g1506pt"] |
| 211 | mspm0g1506pm = ["mspm0-metapac/mspm0g1506pm"] | ||
| 215 | mspm0g1507rge = ["mspm0-metapac/mspm0g1507rge"] | 212 | mspm0g1507rge = ["mspm0-metapac/mspm0g1507rge"] |
| 216 | mspm0g1507rgz = ["mspm0-metapac/mspm0g1507rgz"] | ||
| 217 | mspm0g1507rhb = ["mspm0-metapac/mspm0g1507rhb"] | 213 | mspm0g1507rhb = ["mspm0-metapac/mspm0g1507rhb"] |
| 214 | mspm0g1507rgz = ["mspm0-metapac/mspm0g1507rgz"] | ||
| 215 | mspm0g1507pt = ["mspm0-metapac/mspm0g1507pt"] | ||
| 216 | mspm0g1507pm = ["mspm0-metapac/mspm0g1507pm"] | ||
| 218 | mspm0g1507ycj = ["mspm0-metapac/mspm0g1507ycj"] | 217 | mspm0g1507ycj = ["mspm0-metapac/mspm0g1507ycj"] |
| 219 | mspm0g1519rgz = ["mspm0-metapac/mspm0g1519rgz"] | 218 | mspm0g1518rhb = ["mspm0-metapac/mspm0g1518rhb"] |
| 219 | mspm0g1518rgz = ["mspm0-metapac/mspm0g1518rgz"] | ||
| 220 | mspm0g1518pt = ["mspm0-metapac/mspm0g1518pt"] | ||
| 221 | mspm0g1518pm = ["mspm0-metapac/mspm0g1518pm"] | ||
| 222 | mspm0g1518pz = ["mspm0-metapac/mspm0g1518pz"] | ||
| 223 | mspm0g1518pn = ["mspm0-metapac/mspm0g1518pn"] | ||
| 224 | mspm0g1518zaw = ["mspm0-metapac/mspm0g1518zaw"] | ||
| 220 | mspm0g1519rhb = ["mspm0-metapac/mspm0g1519rhb"] | 225 | mspm0g1519rhb = ["mspm0-metapac/mspm0g1519rhb"] |
| 226 | mspm0g1519rgz = ["mspm0-metapac/mspm0g1519rgz"] | ||
| 227 | mspm0g1519pt = ["mspm0-metapac/mspm0g1519pt"] | ||
| 228 | mspm0g1519pm = ["mspm0-metapac/mspm0g1519pm"] | ||
| 229 | mspm0g1519pz = ["mspm0-metapac/mspm0g1519pz"] | ||
| 230 | mspm0g1519pn = ["mspm0-metapac/mspm0g1519pn"] | ||
| 221 | mspm0g3105dgs20 = ["mspm0-metapac/mspm0g3105dgs20"] | 231 | mspm0g3105dgs20 = ["mspm0-metapac/mspm0g3105dgs20"] |
| 222 | mspm0g3105dgs28 = ["mspm0-metapac/mspm0g3105dgs28"] | 232 | mspm0g3105dgs28 = ["mspm0-metapac/mspm0g3105dgs28"] |
| 223 | mspm0g3105rhb = ["mspm0-metapac/mspm0g3105rhb"] | 233 | mspm0g3105rhb = ["mspm0-metapac/mspm0g3105rhb"] |
| @@ -228,77 +238,92 @@ mspm0g3107dgs20 = ["mspm0-metapac/mspm0g3107dgs20"] | |||
| 228 | mspm0g3107dgs28 = ["mspm0-metapac/mspm0g3107dgs28"] | 238 | mspm0g3107dgs28 = ["mspm0-metapac/mspm0g3107dgs28"] |
| 229 | mspm0g3107rhb = ["mspm0-metapac/mspm0g3107rhb"] | 239 | mspm0g3107rhb = ["mspm0-metapac/mspm0g3107rhb"] |
| 230 | mspm0g3505dgs28 = ["mspm0-metapac/mspm0g3505dgs28"] | 240 | mspm0g3505dgs28 = ["mspm0-metapac/mspm0g3505dgs28"] |
| 231 | mspm0g3505pm = ["mspm0-metapac/mspm0g3505pm"] | ||
| 232 | mspm0g3505pt = ["mspm0-metapac/mspm0g3505pt"] | ||
| 233 | mspm0g3505rgz = ["mspm0-metapac/mspm0g3505rgz"] | ||
| 234 | mspm0g3505rhb = ["mspm0-metapac/mspm0g3505rhb"] | 241 | mspm0g3505rhb = ["mspm0-metapac/mspm0g3505rhb"] |
| 242 | mspm0g3505rgz = ["mspm0-metapac/mspm0g3505rgz"] | ||
| 243 | mspm0g3505pt = ["mspm0-metapac/mspm0g3505pt"] | ||
| 244 | mspm0g3505pm = ["mspm0-metapac/mspm0g3505pm"] | ||
| 235 | mspm0g3506dgs28 = ["mspm0-metapac/mspm0g3506dgs28"] | 245 | mspm0g3506dgs28 = ["mspm0-metapac/mspm0g3506dgs28"] |
| 236 | mspm0g3506pm = ["mspm0-metapac/mspm0g3506pm"] | ||
| 237 | mspm0g3506pt = ["mspm0-metapac/mspm0g3506pt"] | ||
| 238 | mspm0g3506rgz = ["mspm0-metapac/mspm0g3506rgz"] | ||
| 239 | mspm0g3506rhb = ["mspm0-metapac/mspm0g3506rhb"] | 246 | mspm0g3506rhb = ["mspm0-metapac/mspm0g3506rhb"] |
| 247 | mspm0g3506rgz = ["mspm0-metapac/mspm0g3506rgz"] | ||
| 248 | mspm0g3506pt = ["mspm0-metapac/mspm0g3506pt"] | ||
| 249 | mspm0g3506pm = ["mspm0-metapac/mspm0g3506pm"] | ||
| 240 | mspm0g3507dgs28 = ["mspm0-metapac/mspm0g3507dgs28"] | 250 | mspm0g3507dgs28 = ["mspm0-metapac/mspm0g3507dgs28"] |
| 241 | mspm0g3507pm = ["mspm0-metapac/mspm0g3507pm"] | ||
| 242 | mspm0g3507pt = ["mspm0-metapac/mspm0g3507pt"] | ||
| 243 | mspm0g3507rgz = ["mspm0-metapac/mspm0g3507rgz"] | ||
| 244 | mspm0g3507rhb = ["mspm0-metapac/mspm0g3507rhb"] | 251 | mspm0g3507rhb = ["mspm0-metapac/mspm0g3507rhb"] |
| 252 | mspm0g3507rgz = ["mspm0-metapac/mspm0g3507rgz"] | ||
| 253 | mspm0g3507pt = ["mspm0-metapac/mspm0g3507pt"] | ||
| 254 | mspm0g3507pm = ["mspm0-metapac/mspm0g3507pm"] | ||
| 255 | mspm0g3518rhb = ["mspm0-metapac/mspm0g3518rhb"] | ||
| 256 | mspm0g3518rgz = ["mspm0-metapac/mspm0g3518rgz"] | ||
| 257 | mspm0g3518pt = ["mspm0-metapac/mspm0g3518pt"] | ||
| 258 | mspm0g3518pm = ["mspm0-metapac/mspm0g3518pm"] | ||
| 259 | mspm0g3518pz = ["mspm0-metapac/mspm0g3518pz"] | ||
| 260 | mspm0g3518pn = ["mspm0-metapac/mspm0g3518pn"] | ||
| 261 | mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] | ||
| 262 | mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] | ||
| 263 | mspm0g3519pt = ["mspm0-metapac/mspm0g3519pt"] | ||
| 245 | mspm0g3519pm = ["mspm0-metapac/mspm0g3519pm"] | 264 | mspm0g3519pm = ["mspm0-metapac/mspm0g3519pm"] |
| 246 | mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"] | ||
| 247 | mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] | 265 | mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] |
| 248 | mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] | 266 | mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"] |
| 249 | mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] | 267 | mspm0g3519zaw = ["mspm0-metapac/mspm0g3519zaw"] |
| 268 | mspm0g5187rhb = ["mspm0-metapac/mspm0g5187rhb"] | ||
| 269 | mspm0g5187rgz = ["mspm0-metapac/mspm0g5187rgz"] | ||
| 270 | mspm0g5187pt = ["mspm0-metapac/mspm0g5187pt"] | ||
| 271 | mspm0g5187pm = ["mspm0-metapac/mspm0g5187pm"] | ||
| 272 | mspm0g5187ruy = ["mspm0-metapac/mspm0g5187ruy"] | ||
| 273 | mspm0g5187ycj = ["mspm0-metapac/mspm0g5187ycj"] | ||
| 274 | mspm0g5187rge = ["mspm0-metapac/mspm0g5187rge"] | ||
| 250 | mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"] | 275 | mspm0h3216pt = ["mspm0-metapac/mspm0h3216pt"] |
| 251 | mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] | 276 | mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] |
| 252 | mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] | 277 | mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] |
| 253 | mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"] | ||
| 254 | mspm0l1105rge = ["mspm0-metapac/mspm0l1105rge"] | 278 | mspm0l1105rge = ["mspm0-metapac/mspm0l1105rge"] |
| 255 | mspm0l1105rtr = ["mspm0-metapac/mspm0l1105rtr"] | 279 | mspm0l1105rtr = ["mspm0-metapac/mspm0l1105rtr"] |
| 280 | mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"] | ||
| 281 | mspm0l1106rhb = ["mspm0-metapac/mspm0l1106rhb"] | ||
| 256 | mspm0l1106dgs20 = ["mspm0-metapac/mspm0l1106dgs20"] | 282 | mspm0l1106dgs20 = ["mspm0-metapac/mspm0l1106dgs20"] |
| 257 | mspm0l1106dgs28 = ["mspm0-metapac/mspm0l1106dgs28"] | 283 | mspm0l1106dgs28 = ["mspm0-metapac/mspm0l1106dgs28"] |
| 258 | mspm0l1106dyy = ["mspm0-metapac/mspm0l1106dyy"] | ||
| 259 | mspm0l1106rge = ["mspm0-metapac/mspm0l1106rge"] | 284 | mspm0l1106rge = ["mspm0-metapac/mspm0l1106rge"] |
| 260 | mspm0l1106rhb = ["mspm0-metapac/mspm0l1106rhb"] | ||
| 261 | mspm0l1106rtr = ["mspm0-metapac/mspm0l1106rtr"] | 285 | mspm0l1106rtr = ["mspm0-metapac/mspm0l1106rtr"] |
| 262 | mspm0l1227pm = ["mspm0-metapac/mspm0l1227pm"] | 286 | mspm0l1106dyy = ["mspm0-metapac/mspm0l1106dyy"] |
| 287 | mspm0l1227rhb = ["mspm0-metapac/mspm0l1227rhb"] | ||
| 263 | mspm0l1227pn = ["mspm0-metapac/mspm0l1227pn"] | 288 | mspm0l1227pn = ["mspm0-metapac/mspm0l1227pn"] |
| 289 | mspm0l1227rgz = ["mspm0-metapac/mspm0l1227rgz"] | ||
| 264 | mspm0l1227pt = ["mspm0-metapac/mspm0l1227pt"] | 290 | mspm0l1227pt = ["mspm0-metapac/mspm0l1227pt"] |
| 291 | mspm0l1227pm = ["mspm0-metapac/mspm0l1227pm"] | ||
| 265 | mspm0l1227rge = ["mspm0-metapac/mspm0l1227rge"] | 292 | mspm0l1227rge = ["mspm0-metapac/mspm0l1227rge"] |
| 266 | mspm0l1227rgz = ["mspm0-metapac/mspm0l1227rgz"] | 293 | mspm0l1228rhb = ["mspm0-metapac/mspm0l1228rhb"] |
| 267 | mspm0l1227rhb = ["mspm0-metapac/mspm0l1227rhb"] | ||
| 268 | mspm0l1228pm = ["mspm0-metapac/mspm0l1228pm"] | ||
| 269 | mspm0l1228pn = ["mspm0-metapac/mspm0l1228pn"] | 294 | mspm0l1228pn = ["mspm0-metapac/mspm0l1228pn"] |
| 295 | mspm0l1228rgz = ["mspm0-metapac/mspm0l1228rgz"] | ||
| 270 | mspm0l1228pt = ["mspm0-metapac/mspm0l1228pt"] | 296 | mspm0l1228pt = ["mspm0-metapac/mspm0l1228pt"] |
| 297 | mspm0l1228pm = ["mspm0-metapac/mspm0l1228pm"] | ||
| 271 | mspm0l1228rge = ["mspm0-metapac/mspm0l1228rge"] | 298 | mspm0l1228rge = ["mspm0-metapac/mspm0l1228rge"] |
| 272 | mspm0l1228rgz = ["mspm0-metapac/mspm0l1228rgz"] | ||
| 273 | mspm0l1228rhb = ["mspm0-metapac/mspm0l1228rhb"] | ||
| 274 | mspm0l1303rge = ["mspm0-metapac/mspm0l1303rge"] | 299 | mspm0l1303rge = ["mspm0-metapac/mspm0l1303rge"] |
| 300 | mspm0l1304rhb = ["mspm0-metapac/mspm0l1304rhb"] | ||
| 275 | mspm0l1304dgs20 = ["mspm0-metapac/mspm0l1304dgs20"] | 301 | mspm0l1304dgs20 = ["mspm0-metapac/mspm0l1304dgs20"] |
| 276 | mspm0l1304dgs28 = ["mspm0-metapac/mspm0l1304dgs28"] | 302 | mspm0l1304dgs28 = ["mspm0-metapac/mspm0l1304dgs28"] |
| 277 | mspm0l1304dyy = ["mspm0-metapac/mspm0l1304dyy"] | ||
| 278 | mspm0l1304rge = ["mspm0-metapac/mspm0l1304rge"] | 303 | mspm0l1304rge = ["mspm0-metapac/mspm0l1304rge"] |
| 279 | mspm0l1304rhb = ["mspm0-metapac/mspm0l1304rhb"] | ||
| 280 | mspm0l1304rtr = ["mspm0-metapac/mspm0l1304rtr"] | 304 | mspm0l1304rtr = ["mspm0-metapac/mspm0l1304rtr"] |
| 305 | mspm0l1304dyy = ["mspm0-metapac/mspm0l1304dyy"] | ||
| 281 | mspm0l1305dgs20 = ["mspm0-metapac/mspm0l1305dgs20"] | 306 | mspm0l1305dgs20 = ["mspm0-metapac/mspm0l1305dgs20"] |
| 282 | mspm0l1305dgs28 = ["mspm0-metapac/mspm0l1305dgs28"] | 307 | mspm0l1305dgs28 = ["mspm0-metapac/mspm0l1305dgs28"] |
| 283 | mspm0l1305dyy = ["mspm0-metapac/mspm0l1305dyy"] | ||
| 284 | mspm0l1305rge = ["mspm0-metapac/mspm0l1305rge"] | 308 | mspm0l1305rge = ["mspm0-metapac/mspm0l1305rge"] |
| 285 | mspm0l1305rtr = ["mspm0-metapac/mspm0l1305rtr"] | 309 | mspm0l1305rtr = ["mspm0-metapac/mspm0l1305rtr"] |
| 310 | mspm0l1305dyy = ["mspm0-metapac/mspm0l1305dyy"] | ||
| 311 | mspm0l1306rhb = ["mspm0-metapac/mspm0l1306rhb"] | ||
| 286 | mspm0l1306dgs20 = ["mspm0-metapac/mspm0l1306dgs20"] | 312 | mspm0l1306dgs20 = ["mspm0-metapac/mspm0l1306dgs20"] |
| 287 | mspm0l1306dgs28 = ["mspm0-metapac/mspm0l1306dgs28"] | 313 | mspm0l1306dgs28 = ["mspm0-metapac/mspm0l1306dgs28"] |
| 288 | mspm0l1306dyy = ["mspm0-metapac/mspm0l1306dyy"] | ||
| 289 | mspm0l1306rge = ["mspm0-metapac/mspm0l1306rge"] | 314 | mspm0l1306rge = ["mspm0-metapac/mspm0l1306rge"] |
| 290 | mspm0l1306rhb = ["mspm0-metapac/mspm0l1306rhb"] | 315 | mspm0l1306dyy = ["mspm0-metapac/mspm0l1306dyy"] |
| 291 | mspm0l1343dgs20 = ["mspm0-metapac/mspm0l1343dgs20"] | 316 | mspm0l1343dgs20 = ["mspm0-metapac/mspm0l1343dgs20"] |
| 292 | mspm0l1344dgs20 = ["mspm0-metapac/mspm0l1344dgs20"] | 317 | mspm0l1344dgs20 = ["mspm0-metapac/mspm0l1344dgs20"] |
| 293 | mspm0l1345dgs28 = ["mspm0-metapac/mspm0l1345dgs28"] | 318 | mspm0l1345dgs28 = ["mspm0-metapac/mspm0l1345dgs28"] |
| 294 | mspm0l1346dgs28 = ["mspm0-metapac/mspm0l1346dgs28"] | 319 | mspm0l1346dgs28 = ["mspm0-metapac/mspm0l1346dgs28"] |
| 320 | mspm0l2227rgz = ["mspm0-metapac/mspm0l2227rgz"] | ||
| 321 | mspm0l2227pt = ["mspm0-metapac/mspm0l2227pt"] | ||
| 295 | mspm0l2227pm = ["mspm0-metapac/mspm0l2227pm"] | 322 | mspm0l2227pm = ["mspm0-metapac/mspm0l2227pm"] |
| 296 | mspm0l2227pn = ["mspm0-metapac/mspm0l2227pn"] | 323 | mspm0l2227pn = ["mspm0-metapac/mspm0l2227pn"] |
| 297 | mspm0l2227pt = ["mspm0-metapac/mspm0l2227pt"] | 324 | mspm0l2228rgz = ["mspm0-metapac/mspm0l2228rgz"] |
| 298 | mspm0l2227rgz = ["mspm0-metapac/mspm0l2227rgz"] | 325 | mspm0l2228pt = ["mspm0-metapac/mspm0l2228pt"] |
| 299 | mspm0l2228pm = ["mspm0-metapac/mspm0l2228pm"] | 326 | mspm0l2228pm = ["mspm0-metapac/mspm0l2228pm"] |
| 300 | mspm0l2228pn = ["mspm0-metapac/mspm0l2228pn"] | 327 | mspm0l2228pn = ["mspm0-metapac/mspm0l2228pn"] |
| 301 | mspm0l2228pt = ["mspm0-metapac/mspm0l2228pt"] | ||
| 302 | mspm0l2228rgz = ["mspm0-metapac/mspm0l2228rgz"] | ||
| 303 | msps003f3pw20 = ["mspm0-metapac/msps003f3pw20"] | 328 | msps003f3pw20 = ["mspm0-metapac/msps003f3pw20"] |
| 304 | msps003f4pw20 = ["mspm0-metapac/msps003f4pw20"] | 329 | msps003f4pw20 = ["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 { | |||
| 730 | const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| { | 748 | const 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)] |
| 845 | pub struct PfType { | 846 | pub 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; | |||
| 12 | use mspm0_metapac::i2c::vals::CpuIntIidxStat; | 12 | use mspm0_metapac::i2c::vals::CpuIntIidxStat; |
| 13 | 13 | ||
| 14 | use crate::gpio::{AnyPin, SealedPin}; | 14 | use crate::gpio::{AnyPin, SealedPin}; |
| 15 | use crate::interrupt::InterruptExt; | ||
| 16 | use crate::mode::{Async, Blocking, Mode}; | ||
| 17 | use crate::pac::{self, i2c::vals}; | ||
| 18 | use crate::{i2c, i2c_target, interrupt, Peri}; | ||
| 19 | // Re-use I2c controller types | 15 | // Re-use I2c controller types |
| 20 | use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; | 16 | use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; |
| 17 | use crate::interrupt::InterruptExt; | ||
| 18 | use crate::mode::{Async, Blocking, Mode}; | ||
| 19 | use crate::pac::i2c::vals; | ||
| 20 | use crate::pac::{self}; | ||
| 21 | use 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. |
| 12 | pub(crate) mod fmt; | 12 | pub(crate) mod fmt; |
| 13 | |||
| 14 | // This must be declared early as well for | ||
| 15 | mod macros; | 13 | mod macros; |
| 16 | 14 | ||
| 17 | pub mod adc; | 15 | pub mod adc; |
| 18 | pub mod dma; | 16 | pub mod dma; |
| 19 | pub mod gpio; | 17 | pub mod gpio; |
| 18 | // TODO: I2C unicomm | ||
| 19 | #[cfg(not(unicomm))] | ||
| 20 | pub mod i2c; | 20 | pub mod i2c; |
| 21 | #[cfg(not(unicomm))] | ||
| 21 | pub mod i2c_target; | 22 | pub mod i2c_target; |
| 22 | #[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))] | 23 | #[cfg(any(mspm0g150x, mspm0g151x, mspm0g350x, mspm0g351x))] |
| 23 | pub mod mathacl; | 24 | pub mod mathacl; |
| 24 | pub mod timer; | 25 | pub mod timer; |
| 26 | // TODO: UART unicomm | ||
| 27 | #[cfg(not(unicomm))] | ||
| 25 | pub mod uart; | 28 | pub mod uart; |
| 26 | pub mod wwdt; | 29 | pub 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)] | ||
| 3 | macro_rules! new_pin { | 4 | macro_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; | |||
| 16 | compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet"); | 16 | compile_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)] | ||
| 20 | type T = peripherals::TIMB0; | ||
| 19 | #[cfg(time_driver_timg0)] | 21 | #[cfg(time_driver_timg0)] |
| 20 | type T = peripherals::TIMG0; | 22 | type 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] |
| 338 | fn TIMG0() { | 342 | fn 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] |
| 2 | name = "embassy-net-nrf91" | 2 | name = "embassy-net-nrf91" |
| 3 | version = "0.1.1" | 3 | version = "0.1.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | description = "embassy-net driver for Nordic nRF91-series cellular modems" | 5 | description = "embassy-net driver for Nordic nRF91-series cellular modems" |
| 6 | keywords = ["embedded", "nrf91", "embassy-net", "cellular"] | 6 | keywords = ["embedded", "nrf91", "embassy-net", "cellular"] |
| @@ -8,7 +8,7 @@ categories = ["embedded", "hardware-support", "no-std", "network-programming", " | |||
| 8 | license = "MIT OR Apache-2.0" | 8 | license = "MIT OR Apache-2.0" |
| 9 | repository = "https://github.com/embassy-rs/embassy" | 9 | repository = "https://github.com/embassy-rs/embassy" |
| 10 | documentation = "https://docs.embassy.dev/embassy-net-nrf91" | 10 | documentation = "https://docs.embassy.dev/embassy-net-nrf91" |
| 11 | publish = false | 11 | publish = true |
| 12 | 12 | ||
| 13 | [features] | 13 | [features] |
| 14 | defmt = ["dep:defmt", "heapless/defmt-03"] | 14 | defmt = ["dep:defmt", "heapless/defmt-03"] |
| @@ -18,7 +18,7 @@ log = ["dep:log"] | |||
| 18 | defmt = { version = "1.0.1", optional = true } | 18 | defmt = { version = "1.0.1", optional = true } |
| 19 | log = { version = "0.4.14", optional = true } | 19 | log = { version = "0.4.14", optional = true } |
| 20 | 20 | ||
| 21 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "52fd51ce762a3d3a81660dea62947e6d2d1e9d91" } | 21 | nrf-pac = { version = "0.2.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "7f450696f95591ce42f4da6e7d0402750ab1e50a" } |
| 22 | cortex-m = "0.7.7" | 22 | cortex-m = "0.7.7" |
| 23 | 23 | ||
| 24 | embassy-time = { version = "0.5.0", path = "../embassy-time" } | 24 | embassy-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))] |
| 316 | struct NoFreeBufs; | 316 | struct 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))] | ||
| 1065 | struct Message { | 1066 | struct 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] |
| 2 | name = "embassy-net-tuntap" | 2 | name = "embassy-net-tuntap" |
| 3 | version = "0.1.0" | 3 | version = "0.1.1" |
| 4 | description = "embassy-net driver for Linux TUN/TAP interfaces." | 4 | description = "embassy-net driver for Linux TUN/TAP interfaces." |
| 5 | keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] | 5 | keywords = ["embedded", "tuntap", "embassy-net", "ethernet", "async"] |
| 6 | categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] | 6 | categories = ["embedded", "hardware-support", "network-programming", "asynchronous"] |
| @@ -11,7 +11,7 @@ documentation = "https://docs.embassy.dev/embassy-net-tuntap" | |||
| 11 | 11 | ||
| 12 | [dependencies] | 12 | [dependencies] |
| 13 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } | 13 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } |
| 14 | async-io = "1.6.0" | 14 | async-io = "2.6.0" |
| 15 | log = "0.4.14" | 15 | log = "0.4.14" |
| 16 | libc = "0.2.101" | 16 | libc = "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")] |
| 3 | use std::io; | 3 | use std::io; |
| 4 | use std::io::{Read, Write}; | 4 | use std::io::{Read, Write}; |
| 5 | use std::os::fd::AsFd; | ||
| 5 | use std::os::unix::io::{AsRawFd, RawFd}; | 6 | use std::os::unix::io::{AsRawFd, RawFd}; |
| 7 | use std::os::unix::prelude::BorrowedFd; | ||
| 6 | use std::task::Context; | 8 | use std::task::Context; |
| 7 | 9 | ||
| 8 | use async_io::Async; | 10 | use async_io::Async; |
| @@ -69,6 +71,12 @@ impl AsRawFd for TunTap { | |||
| 69 | } | 71 | } |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 74 | impl AsFd for TunTap { | ||
| 75 | fn as_fd(&self) -> BorrowedFd<'_> { | ||
| 76 | unsafe { BorrowedFd::borrow_raw(self.fd) } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 72 | impl TunTap { | 80 | impl 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] |
| 2 | name = "embassy-nrf" | 2 | name = "embassy-nrf" |
| 3 | version = "0.8.0" | 3 | version = "0.9.0" |
| 4 | edition = "2024" | 4 | edition = "2024" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" | 6 | description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" |
| @@ -223,10 +223,10 @@ embedded-io-async = { version = "0.6.1" } | |||
| 223 | rand-core-06 = { package = "rand_core", version = "0.6" } | 223 | rand-core-06 = { package = "rand_core", version = "0.6" } |
| 224 | rand-core-09 = { package = "rand_core", version = "0.9" } | 224 | rand-core-09 = { package = "rand_core", version = "0.9" } |
| 225 | 225 | ||
| 226 | nrf-pac = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "52fd51ce762a3d3a81660dea62947e6d2d1e9d91" } | 226 | nrf-pac = { version = "0.2.0", git = "https://github.com/embassy-rs/nrf-pac.git", rev = "7f450696f95591ce42f4da6e7d0402750ab1e50a" } |
| 227 | 227 | ||
| 228 | defmt = { version = "1.0.1", optional = true } | 228 | defmt = { version = "1.0.1", optional = true } |
| 229 | bitflags = "2.4.2" | 229 | bitflags = "2.10.0" |
| 230 | log = { version = "0.4.14", optional = true } | 230 | log = { version = "0.4.14", optional = true } |
| 231 | cortex-m-rt = ">=0.6.15,<0.8" | 231 | cortex-m-rt = ">=0.6.15,<0.8" |
| 232 | cortex-m = "0.7.6" | 232 | cortex-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 |
| 30 | const CHANNELS_PER_PORT: usize = 8; | 30 | const 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 | ))] | ||
| 40 | const PIN_COUNT: usize = 48; | 33 | const PIN_COUNT: usize = 48; |
| 34 | #[cfg(any(feature = "_nrf54l15", feature = "_nrf54l10", feature = "_nrf54l05"))] | ||
| 35 | // Highest pin index is P2.10 => (2 * 32 + 10) = 74 | ||
| 36 | const PIN_COUNT: usize = 75; | ||
| 41 | #[cfg(feature = "_nrf54lm20")] | 37 | #[cfg(feature = "_nrf54lm20")] |
| 42 | const PIN_COUNT: usize = 66; | 38 | // Highest pin index is P3.12 => (3 * 32 + 12) = 108 |
| 39 | const 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 | ||
| 3 | use core::marker::PhantomData; | ||
| 3 | use core::{ptr, slice}; | 4 | use core::{ptr, slice}; |
| 4 | 5 | ||
| 5 | use embedded_storage::nor_flash::{ | 6 | use embedded_storage::nor_flash::{ |
| @@ -9,11 +10,28 @@ use embedded_storage::nor_flash::{ | |||
| 9 | use crate::peripherals::RRAMC; | 10 | use crate::peripherals::RRAMC; |
| 10 | use crate::{Peri, pac}; | 11 | use crate::{Peri, pac}; |
| 11 | 12 | ||
| 13 | /// Unbuffered RRAMC mode. | ||
| 14 | pub struct Unbuffered; | ||
| 15 | |||
| 16 | /// Buffered RRAMC mode. | ||
| 17 | pub struct Buffered<const BUFFER_SIZE_BYTES: usize>; | ||
| 18 | |||
| 19 | trait SealedRramMode {} | ||
| 20 | |||
| 21 | /// Operating modes for RRAMC | ||
| 22 | #[allow(private_bounds)] | ||
| 23 | pub trait RramMode: SealedRramMode {} | ||
| 24 | |||
| 25 | impl SealedRramMode for Unbuffered {} | ||
| 26 | impl RramMode for Unbuffered {} | ||
| 27 | impl<const BUFFER_SIZE_BYTES: usize> SealedRramMode for Buffered<BUFFER_SIZE_BYTES> {} | ||
| 28 | impl<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. |
| 16 | pub type Nvmc<'d> = Rramc<'d>; | 34 | pub 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. |
| 18 | pub const PAGE_SIZE: usize = 4096; | 36 | pub 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. |
| 47 | pub struct Rramc<'d> { | 65 | pub struct Rramc<'d, MODE: RramMode> { |
| 48 | _p: Peri<'d, RRAMC>, | 66 | _p: Peri<'d, RRAMC>, |
| 67 | _d: PhantomData<MODE>, | ||
| 68 | } | ||
| 69 | |||
| 70 | impl<'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 | ||
| 51 | impl<'d> Rramc<'d> { | 77 | impl<'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 | ||
| 85 | impl<'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 | |||
| 105 | impl<'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 | |||
| 119 | impl<'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 | ||
| 86 | impl<'d> MultiwriteNorFlash for Rramc<'d> {} | 145 | impl<'d> MultiwriteNorFlash for Rramc<'d, Unbuffered> {} |
| 87 | 146 | ||
| 88 | impl<'d> ErrorType for Rramc<'d> { | 147 | impl<'d> ErrorType for Rramc<'d, Unbuffered> { |
| 89 | type Error = Error; | 148 | type Error = Error; |
| 90 | } | 149 | } |
| 91 | 150 | ||
| 92 | impl<'d> ReadNorFlash for Rramc<'d> { | 151 | impl<'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 | ||
| 110 | impl<'d> NorFlash for Rramc<'d> { | 169 | impl<'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 | |||
| 235 | impl<'d, const BUFFER_SIZE_BYTES: usize> MultiwriteNorFlash for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> {} | ||
| 236 | |||
| 237 | impl<'d, const BUFFER_SIZE_BYTES: usize> ErrorType for Rramc<'d, Buffered<BUFFER_SIZE_BYTES>> { | ||
| 238 | type Error = Error; | ||
| 239 | } | ||
| 240 | |||
| 241 | impl<'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 | |||
| 259 | impl<'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 | ||
| 42 | cortex-m = "0.7.6" | 42 | cortex-m = "0.7.6" |
| 43 | heapless = "0.8" | 43 | heapless = "0.8" |
| 44 | aligned = "0.4.1" | 44 | aligned = "0.4.2" |
| 45 | critical-section = "1.1" | 45 | critical-section = "1.2" |
| 46 | 46 | ||
| 47 | bit_field = "0.10.2" | 47 | bit_field = "0.10.2" |
| 48 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } | 48 | stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } |
| 49 | stm32wb-hci = { version = "0.17.0", optional = true } | 49 | stm32wb-hci = { version = "0.17.3", optional = true } |
| 50 | futures-util = { version = "0.3.30", default-features = false } | 50 | futures-util = { version = "0.3.30", default-features = false } |
| 51 | bitflags = { version = "2.3.3", optional = true } | 51 | bitflags = { version = "2.3.3", optional = true } |
| 52 | 52 | ||
| @@ -57,7 +57,7 @@ wb55 = [] | |||
| 57 | wb55_ble = ["dep:stm32wb-hci"] | 57 | wb55_ble = ["dep:stm32wb-hci"] |
| 58 | wb55_mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"] | 58 | wb55_mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"] |
| 59 | 59 | ||
| 60 | wba = [ "dep:stm32-bindings" ] | 60 | wba = [ "dep:stm32-bindings", "dep:embassy-time" ] |
| 61 | wba_ble = [ "stm32-bindings/wba_wpan_mac" , "stm32-bindings/wba_wpan" ] | 61 | wba_ble = [ "stm32-bindings/wba_wpan_mac" , "stm32-bindings/wba_wpan" ] |
| 62 | wba_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" ] | 62 | wba_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; | |||
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use aligned::{A4, Aligned}; | 6 | use aligned::{A4, Aligned}; |
| 7 | use cortex_m::interrupt; | ||
| 8 | use embassy_stm32::ipcc::IpccTxChannel; | 7 | use embassy_stm32::ipcc::IpccTxChannel; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use 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> { | |||
| 77 | impl<'a> evt::MemoryManager for MemoryManager<'a> { | 75 | impl<'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 | ||
| 14 | use core::fmt::Debug; | ||
| 14 | use core::ptr; | 15 | use core::ptr; |
| 15 | 16 | ||
| 16 | use cortex_m::interrupt; | 17 | use 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)] | 243 | pub struct DebuggableLinkedListNode(*const LinkedListNode); |
| 239 | unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) { | 244 | |
| 240 | info!("iterating list from node: {:x}", p_node); | 245 | impl 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)] | ||
| 2 | fn 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 | |||
| 78 | use core::hint::spin_loop; | ||
| 79 | use core::ptr; | ||
| 80 | use core::sync::atomic::{AtomicBool, AtomicI32, AtomicPtr, AtomicU32, Ordering}; | ||
| 81 | |||
| 82 | use cortex_m::asm::{dsb, isb}; | ||
| 83 | use cortex_m::interrupt::InterruptNumber; | ||
| 84 | use cortex_m::peripheral::NVIC; | ||
| 85 | use cortex_m::register::basepri; | ||
| 86 | use critical_section; | ||
| 87 | #[cfg(feature = "defmt")] | ||
| 88 | use defmt::trace; | ||
| 89 | use embassy_stm32::NVIC_PRIO_BITS; | ||
| 90 | use embassy_time::{Duration, block_for}; | ||
| 91 | |||
| 92 | use 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) | ||
| 96 | const RADIO_SW_LOW_INTR_NUM: u32 = 43; | ||
| 97 | |||
| 98 | type Callback = unsafe extern "C" fn(); | ||
| 99 | |||
| 100 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| 101 | #[repr(transparent)] | ||
| 102 | struct RawInterrupt(u16); | ||
| 103 | |||
| 104 | impl RawInterrupt { | ||
| 105 | fn new(irq: u32) -> Self { | ||
| 106 | debug_assert!(irq <= u16::MAX as u32); | ||
| 107 | Self(irq as u16) | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | impl From<u32> for RawInterrupt { | ||
| 112 | fn from(value: u32) -> Self { | ||
| 113 | Self::new(value) | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | unsafe impl InterruptNumber for RawInterrupt { | ||
| 118 | fn number(self) -> u16 { | ||
| 119 | self.0 | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | static RADIO_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); | ||
| 124 | static LOW_ISR_CALLBACK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); | ||
| 125 | |||
| 126 | static IRQ_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 127 | |||
| 128 | static PRIO_HIGH_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 129 | static PRIO_LOW_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 130 | static PRIO_SYS_ISR_COUNTER: AtomicI32 = AtomicI32::new(0); | ||
| 131 | static LOCAL_BASEPRI_VALUE: AtomicU32 = AtomicU32::new(0); | ||
| 132 | |||
| 133 | static RADIO_SW_LOW_ISR_RUNNING_HIGH_PRIO: AtomicBool = AtomicBool::new(false); | ||
| 134 | static AHB5_SWITCHED_OFF: AtomicBool = AtomicBool::new(false); | ||
| 135 | static RADIO_SLEEP_TIMER_VAL: AtomicU32 = AtomicU32::new(0); | ||
| 136 | |||
| 137 | static PRNG_STATE: AtomicU32 = AtomicU32::new(0); | ||
| 138 | static 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. | ||
| 142 | static mut CS_RESTORE_STATE: Option<critical_section::RestoreState> = None; | ||
| 143 | |||
| 144 | fn read_system_core_clock() -> u32 { | ||
| 145 | 0 | ||
| 146 | } | ||
| 147 | |||
| 148 | fn 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 | |||
| 153 | fn 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 | |||
| 162 | fn priority_shift() -> u8 { | ||
| 163 | 8 - NVIC_PRIO_BITS as u8 | ||
| 164 | } | ||
| 165 | |||
| 166 | fn 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 | |||
| 178 | fn counter_release(counter: &AtomicI32) -> bool { | ||
| 179 | counter.fetch_sub(1, Ordering::SeqCst) <= 1 | ||
| 180 | } | ||
| 181 | |||
| 182 | fn counter_acquire(counter: &AtomicI32) -> bool { | ||
| 183 | counter.fetch_add(1, Ordering::SeqCst) == 0 | ||
| 184 | } | ||
| 185 | |||
| 186 | unsafe fn nvic_enable(irq: u32) { | ||
| 187 | NVIC::unmask(RawInterrupt::new(irq)); | ||
| 188 | dsb(); | ||
| 189 | isb(); | ||
| 190 | } | ||
| 191 | |||
| 192 | unsafe fn nvic_disable(irq: u32) { | ||
| 193 | NVIC::mask(RawInterrupt::new(irq)); | ||
| 194 | dsb(); | ||
| 195 | isb(); | ||
| 196 | } | ||
| 197 | |||
| 198 | unsafe fn nvic_set_pending(irq: u32) { | ||
| 199 | NVIC::pend(RawInterrupt::new(irq)); | ||
| 200 | dsb(); | ||
| 201 | isb(); | ||
| 202 | } | ||
| 203 | |||
| 204 | unsafe fn nvic_get_active(irq: u32) -> bool { | ||
| 205 | NVIC::is_active(RawInterrupt::new(irq)) | ||
| 206 | } | ||
| 207 | |||
| 208 | unsafe 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 | |||
| 217 | fn set_basepri_max(value: u8) { | ||
| 218 | unsafe { | ||
| 219 | if basepri::read() < value { | ||
| 220 | basepri::write(value); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | fn 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 | |||
| 254 | pub unsafe fn run_radio_high_isr() { | ||
| 255 | if let Some(cb) = load_callback(&RADIO_CALLBACK) { | ||
| 256 | cb(); | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | pub 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 | // { | 276 | pub 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 | // { | 299 | pub 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 | // { | 359 | pub 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 | // { | 371 | pub 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 | // { | 389 | pub 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 | // { | 413 | pub 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 | // { | 429 | pub 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 | // { | 460 | pub 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 | // { | 496 | pub 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 | // { | 514 | pub 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 | // { | 532 | pub 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 | // { | 570 | pub 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 | // { | 593 | pub 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 | // { | 619 | pub 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 | // { | 685 | pub 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 | // { | 749 | pub 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 | // { | 760 | pub 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 | // { | 771 | pub 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 | // { | 788 | pub 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 | // { | 805 | pub 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 | // { | 824 | pub 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 | // { | 841 | pub 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 | // { | 854 | pub 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 | // { | 864 | pub 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 | // { | 874 | pub 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 | // { | 884 | pub 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 | // { | 897 | pub 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)] | ||
| 905 | pub unsafe extern "C" fn LINKLAYER_DEBUG_SIGNAL_SET() { | ||
| 906 | trace!("LINKLAYER_DEBUG_SIGNAL_SET"); | ||
| 907 | todo!() | ||
| 908 | } | ||
| 909 | |||
| 910 | #[unsafe(no_mangle)] | ||
| 911 | pub unsafe extern "C" fn LINKLAYER_DEBUG_SIGNAL_RESET() { | ||
| 912 | trace!("LINKLAYER_DEBUG_SIGNAL_RESET"); | ||
| 913 | todo!() | ||
| 914 | } | ||
| 915 | |||
| 916 | #[unsafe(no_mangle)] | ||
| 917 | pub 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/), | |||
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | 6 | and 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 | ||
| 194 | static_assertions = { version = "1.1" } | 194 | static_assertions = { version = "1.1" } |
| 195 | volatile-register = { version = "0.2.1" } | 195 | volatile-register = { version = "0.2.1" } |
| 196 | bitflags = "2.4.2" | 196 | bitflags = "2.10.0" |
| 197 | 197 | ||
| 198 | block-device-driver = { version = "0.2" } | 198 | block-device-driver = { version = "0.2" } |
| 199 | aligned = "0.4.1" | 199 | aligned = "0.4.1" |
| 200 | heapless = "0.9.1" | 200 | heapless = "0.9.1" |
| 201 | 201 | ||
| 202 | #stm32-metapac = { version = "18" } | 202 | #stm32-metapac = { version = "18" } |
| 203 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74" } | 203 | stm32-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"]} |
| 207 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-497fb3042b49b765d8974aac87b8ab4fa3566d74", default-features = false, features = ["metadata"] } | 207 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc", default-features = false, features = ["metadata"] } |
| 208 | 208 | ||
| 209 | proc-macro2 = "1.0.36" | 209 | proc-macro2 = "1.0.36" |
| 210 | quote = "1.0.15" | 210 | quote = "1.0.15" |
| @@ -241,8 +241,9 @@ log = ["dep:log"] | |||
| 241 | chrono = ["dep:chrono"] | 241 | chrono = ["dep:chrono"] |
| 242 | 242 | ||
| 243 | exti = [] | 243 | exti = [] |
| 244 | low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] | 244 | low-power = [ "dep:embassy-executor", "time" ] |
| 245 | low-power-debug-with-sleep = [] | 245 | low-power-pender = [ "low-power" ] |
| 246 | low-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/) |
| 248 | memory-x = [] | 249 | memory-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. |
| 25 | pub const VREF_CALIB_MV: u32 = 3300; | 25 | pub const VREF_CALIB_MV: u32 = 3300; |
| 26 | 26 | ||
| 27 | impl<'d, T: Instance> super::SealedSpecialConverter<super::VrefInt> for Adc4<'d, T> { | 27 | impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC4 { |
| 28 | const CHANNEL: u8 = 0; | 28 | const CHANNEL: u8 = 0; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | impl<'d, T: Instance> super::SealedSpecialConverter<super::Temperature> for Adc4<'d, T> { | 31 | impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC4 { |
| 32 | const CHANNEL: u8 = 13; | 32 | const CHANNEL: u8 = 13; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | impl<'d, T: Instance> super::SealedSpecialConverter<super::Vcore> for Adc4<'d, T> { | 35 | impl super::SealedSpecialConverter<super::Vcore> for crate::peripherals::ADC4 { |
| 36 | const CHANNEL: u8 = 12; | 36 | const CHANNEL: u8 = 12; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | impl<'d, T: Instance> super::SealedSpecialConverter<super::Vbat> for Adc4<'d, T> { | 39 | impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC4 { |
| 40 | const CHANNEL: u8 = 14; | 40 | const CHANNEL: u8 = 14; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | impl<'d, T: Instance> super::SealedSpecialConverter<super::Dac> for Adc4<'d, T> { | 43 | impl 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 | ||
| 200 | pub struct Adc4<'d, T: Instance> { | ||
| 201 | #[allow(unused)] | ||
| 202 | adc: crate::Peri<'d, T>, | ||
| 203 | } | ||
| 204 | |||
| 205 | #[derive(Copy, Clone, Debug)] | ||
| 206 | pub enum Adc4Error { | ||
| 207 | InvalidSequence, | ||
| 208 | DMAError, | ||
| 209 | } | ||
| 210 | |||
| 211 | impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> { | 200 | impl<'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}; | |||
| 5 | use pac::adccommon::vals::Presc; | 5 | use pac::adccommon::vals::Presc; |
| 6 | 6 | ||
| 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 8 | #[cfg(stm32u5)] | ||
| 9 | use crate::adc::DefaultInstance; | ||
| 8 | use crate::adc::{AdcRegs, ConversionMode}; | 10 | use crate::adc::{AdcRegs, ConversionMode}; |
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | use crate::{Peri, pac, rcc}; | 12 | use 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)] |
| 50 | impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T { | 52 | impl<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)] |
| 54 | impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { | 56 | impl<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)] |
| 58 | impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | 60 | impl<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> { | |||
| 94 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> { | 94 | impl<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 | ||
| 121 | impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> { | 118 | impl<'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 | ||
| 11 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::peripherals::IPCC; | 12 | use crate::peripherals::IPCC; |
| 13 | use crate::rcc::SealedRccPeripheral; | ||
| 13 | use crate::{interrupt, rcc}; | 14 | use 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)] |
| 139 | pub mod xspi; | 139 | pub mod xspi; |
| 140 | 140 | ||
| 141 | #[cfg(feature = "low-power")] | ||
| 142 | pub 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. |
| 142 | pub(crate) mod _generated { | 145 | pub(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 @@ | |||
| 43 | use core::arch::asm; | 43 | use core::arch::asm; |
| 44 | use core::marker::PhantomData; | 44 | use core::marker::PhantomData; |
| 45 | use core::mem; | 45 | use core::mem; |
| 46 | use core::sync::atomic::{Ordering, compiler_fence}; | 46 | use core::sync::atomic::{AtomicBool, Ordering, compiler_fence}; |
| 47 | 47 | ||
| 48 | use cortex_m::peripheral::SCB; | 48 | use cortex_m::peripheral::SCB; |
| 49 | use critical_section::CriticalSection; | 49 | use critical_section::CriticalSection; |
| @@ -56,7 +56,27 @@ use crate::time_driver::get_driver; | |||
| 56 | 56 | ||
| 57 | const THREAD_PENDER: usize = usize::MAX; | 57 | const THREAD_PENDER: usize = usize::MAX; |
| 58 | 58 | ||
| 59 | static mut EXECUTOR_TAKEN: bool = false; | 59 | static EXECUTOR_TAKEN: AtomicBool = AtomicBool::new(false); |
| 60 | #[cfg(feature = "low-power-pender")] | ||
| 61 | static TASKS_PENDING: AtomicBool = AtomicBool::new(false); | ||
| 62 | |||
| 63 | #[cfg(feature = "low-power-pender")] | ||
| 64 | #[unsafe(export_name = "__pender")] | ||
| 65 | fn __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 |
| 62 | pub struct DeviceBusy { | 82 | pub 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 { | |||
| 150 | impl Executor { | 170 | impl 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 | ||
| 141 | fn msi_enable(range: MSIRange) { | 148 | fn 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 | ||
| 14 | static RNG_WAKER: AtomicWaker = AtomicWaker::new(); | 14 | static RNG_WAKER: AtomicWaker = AtomicWaker::new(); |
| 15 | 15 | ||
| 16 | /// WBA-specific health test configuration values for RNG | ||
| 17 | #[derive(Clone, Copy)] | ||
| 18 | #[allow(dead_code)] | ||
| 19 | enum 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 | |||
| 25 | impl 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; | |||
| 7 | use core::slice; | 7 | use core::slice; |
| 8 | use core::task::Poll; | 8 | use core::task::Poll; |
| 9 | 9 | ||
| 10 | use aligned::{A4, Aligned}; | ||
| 10 | use embassy_hal_internal::{Peri, PeripheralType}; | 11 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | use sdio_host::Cmd; | 13 | use sdio_host::Cmd; |
| @@ -139,14 +140,36 @@ impl Default for Signalling { | |||
| 139 | } | 140 | } |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 143 | const 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 | |||
| 142 | const fn slice8_mut(x: &mut [u32]) -> &mut [u8] { | 148 | const 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)] | ||
| 154 | const 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 | |||
| 159 | const 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 | ||
| 147 | const fn slice8_ref(x: &[u32]) -> &[u8] { | 164 | const 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)] | ||
| 170 | const 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 | ||
| 213 | enum DatapathMode { | ||
| 214 | Block(BlockSize), | ||
| 215 | Byte, | ||
| 216 | } | ||
| 217 | |||
| 190 | fn get_waitresp_val(rlen: ResponseLen) -> u8 { | 218 | fn 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}; | |||
| 5 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; | 5 | use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus}; |
| 6 | use sdio_host::{common_cmd, emmc_cmd, sd_cmd}; | 6 | use sdio_host::{common_cmd, emmc_cmd, sd_cmd}; |
| 7 | 7 | ||
| 8 | use crate::sdmmc::{BlockSize, Error, Sdmmc, Signalling, block_size, bus_width_vals, slice8_mut, slice8_ref}; | 8 | use crate::sdmmc::{ |
| 9 | BlockSize, DatapathMode, Error, Sdmmc, Signalling, aligned_mut, aligned_ref, block_size, bus_width_vals, | ||
| 10 | slice8_mut, slice8_ref, | ||
| 11 | }; | ||
| 9 | use crate::time::{Hertz, mhz}; | 12 | use 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 @@ | |||
| 1 | use core::ops::{Deref, DerefMut}; | 1 | use core::ops::{Deref, DerefMut}; |
| 2 | 2 | ||
| 3 | use aligned::{A4, Aligned}; | ||
| 3 | use sdio_host::common_cmd::{R1, Rz, cmd}; | 4 | use sdio_host::common_cmd::{R1, Rz, cmd}; |
| 4 | use sdio_host::sd::BusWidth; | 5 | use sdio_host::sd::BusWidth; |
| 5 | use sdio_host::sd_cmd; | 6 | use sdio_host::sd_cmd; |
| 6 | 7 | ||
| 7 | use crate::sdmmc::{Error, Sdmmc, block_size, slice8_mut, slice8_ref}; | 8 | use crate::sdmmc::{DatapathMode, Error, Sdmmc, aligned_mut, aligned_ref, block_size, slice8_mut, slice8_ref}; |
| 8 | use crate::time::Hertz; | 9 | use 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 |
| 40 | pub struct SerialDataInterface<'a, 'b> { | 41 | pub 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"] | |||
| 35 | defmt = { version = "1.0.1", optional = true } | 35 | defmt = { version = "1.0.1", optional = true } |
| 36 | log = { version = "0.4.17", optional = true } | 36 | log = { version = "0.4.17", optional = true } |
| 37 | 37 | ||
| 38 | bitflags = "2.4.1" | 38 | bitflags = "2.10.0" |
| 39 | cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } | 39 | cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } |
| 40 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } | 40 | embassy-boot = { version = "0.6.1", path = "../embassy-boot" } |
| 41 | embassy-futures = { version = "0.1.2", path = "../embassy-futures" } | 41 | embassy-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 | |||
| 9 | embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } | 9 | embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } |
| 10 | embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } | 11 | embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } |
| 12 | embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["gpiote", ] } | 12 | embassy-nrf = { version = "0.9.0", path = "../../../../embassy-nrf", features = ["gpiote", ] } |
| 13 | embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } | 13 | embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } |
| 14 | embassy-boot-nrf = { version = "0.9.0", path = "../../../../embassy-boot-nrf", features = [] } | 14 | embassy-boot-nrf = { version = "0.10.0", path = "../../../../embassy-boot-nrf", features = [] } |
| 15 | embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } | 15 | embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } |
| 16 | 16 | ||
| 17 | defmt = { version = "1.0.1", optional = true } | 17 | defmt = { 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" | |||
| 21 | embedded-io-async = "0.6.1" | 21 | embedded-io-async = "0.6.1" |
| 22 | heapless = "0.9.2" | 22 | heapless = "0.9.2" |
| 23 | panic-probe = { version = "1.0", features = ["print-defmt"] } | 23 | panic-probe = { version = "1.0", features = ["print-defmt"] } |
| 24 | rand_core = "0.9" | ||
| 24 | static_cell = "2.1.1" | 25 | static_cell = "2.1.1" |
| 25 | tmp108 = "0.4.0" | 26 | tmp108 = "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 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use hal::bind_interrupts; | ||
| 6 | use hal::config::Config; | ||
| 7 | use hal::trng::{self, InterruptHandler, Trng}; | ||
| 8 | use rand_core::RngCore; | ||
| 9 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!( | ||
| 12 | struct Irqs { | ||
| 13 | TRNG0 => InterruptHandler; | ||
| 14 | } | ||
| 15 | ); | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async 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 | ||
| 22 | mimxrt600-fcb = "0.2.2" | 22 | mimxrt600-fcb = "0.2.2" |
| 23 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | 23 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } |
| 24 | embedded-hal-bus = "0.3.0" | ||
| 25 | is31fl3743b-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 | |||
| 4 | extern crate embassy_imxrt_examples; | ||
| 5 | |||
| 6 | use defmt::info; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_imxrt::dma::copy; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | const BUFLEN: usize = 1024; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async 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 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_imxrt::bind_interrupts; | ||
| 7 | use embassy_imxrt::flexcomm::spi::{InterruptHandler, Spi}; | ||
| 8 | use embassy_imxrt::peripherals::FLEXCOMM5; | ||
| 9 | use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | FLEXCOMM5 => InterruptHandler<FLEXCOMM5>; | ||
| 13 | }); | ||
| 14 | |||
| 15 | const BUFLEN: usize = 1024; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async 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 | |||
| 4 | use defmt::info; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_imxrt::flexcomm::spi::Spi; | ||
| 7 | use embassy_imxrt::gpio; | ||
| 8 | use embassy_time::{Delay, Timer}; | ||
| 9 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 10 | use is31fl3743b_driver::{CSy, Is31fl3743b, SWx}; | ||
| 11 | use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async 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` | ||
| 3 | runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G5187 --protocol=swd" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv6m-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_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] | ||
| 2 | edition = "2024" | ||
| 3 | name = "embassy-mspm0-g5187-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | publish = false | ||
| 7 | |||
| 8 | [dependencies] | ||
| 9 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g5187pm", "defmt", "rt", "time-driver-any"] } | ||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 13 | panic-halt = "1.0.0" | ||
| 14 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 15 | cortex-m-rt = { version = "0.7.0"} | ||
| 16 | defmt = "1.0.1" | ||
| 17 | defmt-rtt = "1.0.0" | ||
| 18 | panic-probe = { version = "1.0.0", features = ["print-defmt"] } | ||
| 19 | panic-semihosting = "0.6.0" | ||
| 20 | |||
| 21 | [profile.release] | ||
| 22 | debug = 2 | ||
| 23 | |||
| 24 | [package.metadata.embassy] | ||
| 25 | build = [ | ||
| 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 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0G5187](https://www.ti.com/tool/LP-MSPM0G5187) board. | ||
| 14 | |||
| 15 | You 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 | |||
| 22 | If 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 | |||
| 27 | Embassy 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 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn 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 @@ | |||
| 1 | MEMORY | ||
| 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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::Config; | ||
| 7 | use embassy_mspm0::gpio::{Level, Output}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_halt as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::Config; | ||
| 7 | use embassy_mspm0::gpio::{Input, Level, Output, Pull}; | ||
| 8 | use {defmt_rtt as _, panic_halt as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async 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 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_mspm0::gpio::{Level, Output}; | ||
| 11 | use embassy_mspm0::wwdt::{ClosedWindowPercentage, Config, Timeout, Watchdog}; | ||
| 12 | use embassy_time::Timer; | ||
| 13 | use {defmt_rtt as _, panic_halt as _}; | ||
| 14 | |||
| 15 | #[embassy_executor::main] | ||
| 16 | async 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 = [ | |||
| 19 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync" } | 19 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync" } |
| 20 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } | 20 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } |
| 21 | embassy-time = { version = "0.5.0", path = "../../embassy-time" } | 21 | embassy-time = { version = "0.5.0", path = "../../embassy-time" } |
| 22 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 22 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 23 | 23 | ||
| 24 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 24 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 25 | cortex-m-rt = "0.7.0" | 25 | cortex-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] |
| 9 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 9 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 10 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 10 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 11 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } | 11 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } |
| 12 | 12 | ||
| 13 | defmt = "1.0.1" | 13 | defmt = "1.0.1" |
| 14 | defmt-rtt = "1.0.0" | 14 | defmt-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" } | |||
| 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 13 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 14 | 14 | ||
| 15 | defmt = "1.0.1" | 15 | defmt = "1.0.1" |
| 16 | defmt-rtt = "1.0.0" | 16 | defmt-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 |
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 12 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 13 | 13 | ||
| 14 | defmt = "1.0.1" | 14 | defmt = "1.0.1" |
| 15 | defmt-rtt = "1.0.0" | 15 | defmt-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" } | |||
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } | 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } |
| 14 | embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } | 14 | embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } |
| 15 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 15 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 16 | 16 | ||
| 17 | defmt = "1.0.1" | 17 | defmt = "1.0.1" |
| 18 | defmt-rtt = "1.0.0" | 18 | defmt-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" } | |||
| 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } | 13 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } |
| 14 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] } | 14 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] } |
| 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | 16 | embedded-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" } | |||
| 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 11 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 13 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 14 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 14 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } |
| 16 | embedded-io-async = { version = "0.6.1" } | 16 | embedded-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" } | |||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } | 13 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } |
| 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } |
| 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 15 | embedded-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 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::rramc::{Buffered, PAGE_SIZE, Rramc}; | ||
| 7 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async 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" } | |||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 13 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } | 13 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } |
| 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } | 14 | embedded-io = { version = "0.6.0", features = ["defmt-03"] } |
| 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 15 | embedded-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] |
| 9 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 9 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 10 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 10 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 11 | embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 11 | embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 12 | 12 | ||
| 13 | defmt = "1.0.1" | 13 | defmt = "1.0.1" |
| 14 | defmt-rtt = "1.0.0" | 14 | defmt-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] |
| 9 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 9 | embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 10 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 10 | embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 11 | embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 11 | embassy-nrf = { version = "0.9.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 12 | 12 | ||
| 13 | defmt = "1.0.1" | 13 | defmt = "1.0.1" |
| 14 | defmt-rtt = "1.0.0" | 14 | defmt-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] |
| 9 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } | 9 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 10 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 10 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 11 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 11 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 12 | embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } | 12 | embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } |
| 13 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } | 13 | embassy-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}; | |||
| 26 | use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; | 26 | use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; |
| 27 | use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; | 27 | use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; |
| 28 | use embassy_usb::msos::{self, windows_version}; | 28 | use embassy_usb::msos::{self, windows_version}; |
| 29 | use embassy_usb::types::InterfaceNumber; | ||
| 29 | use embassy_usb::{Builder, Config}; | 30 | use embassy_usb::{Builder, Config}; |
| 30 | use {defmt_rtt as _, panic_probe as _}; | 31 | use {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 | |||
| 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] } | 10 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] } |
| 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["log", "std", ] } | 11 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["log", "std", ] } |
| 12 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } | 12 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } |
| 13 | embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } | 13 | embassy-net-tuntap = { version = "0.1.1", path = "../../embassy-net-tuntap" } |
| 14 | embassy-net-ppp = { version = "0.2.1", path = "../../embassy-net-ppp", features = ["log"]} | 14 | embassy-net-ppp = { version = "0.2.1", path = "../../embassy-net-ppp", features = ["log"]} |
| 15 | embedded-io-async = { version = "0.6.1" } | 15 | embedded-io-async = { version = "0.6.1" } |
| 16 | embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] } | 16 | embedded-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 @@ | |||
| 1 | use std::sync::atomic::{AtomicBool, Ordering}; | ||
| 2 | use std::thread; | ||
| 3 | use std::time::Duration; | ||
| 4 | |||
| 5 | use embassy_executor::Executor; | ||
| 6 | use embassy_time::Timer; | ||
| 7 | use log::*; | ||
| 8 | use static_cell::StaticCell; | ||
| 9 | |||
| 10 | #[embassy_executor::task] | ||
| 11 | async fn run() { | ||
| 12 | loop { | ||
| 13 | info!("tick"); | ||
| 14 | Timer::after_secs(1).await; | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | static DONE: StaticCell<AtomicBool> = StaticCell::new(); | ||
| 19 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 20 | |||
| 21 | fn 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. |
| 10 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti", "low-power"] } | 10 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti", "low-power-pender"] } |
| 11 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } | 11 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } |
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 13 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 13 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["defmt"] } |
| 14 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 14 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 15 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } | 15 | embassy-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}; | |||
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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")] |
| 11 | async fn main(_spawner: Spawner) { | 11 | async 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")] |
| 17 | async fn main(_spawner: Spawner) { | 17 | async 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 | ||
| 27 | const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; | 27 | const 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")] |
| 30 | async fn main(_spawner: Spawner) { | 30 | async 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 | ||
| 39 | const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; | 39 | const 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")] |
| 42 | async fn main(spawner: Spawner) { | 42 | async 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")] |
| 27 | async fn main(spawner: Spawner) { | 27 | async 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")] |
| 45 | async fn main(spawner: Spawner) { | 45 | async 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")] |
| 29 | async fn main(spawner: Spawner) { | 29 | async 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")] |
| 19 | async fn main(_spawner: Spawner) { | 19 | async 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")] |
| 24 | async fn main(spawner: Spawner) { | 24 | async 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")] |
| 24 | async fn main(spawner: Spawner) { | 24 | async 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::*; | |||
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::Config; | 6 | use embassy_stm32::Config; |
| 7 | use embassy_stm32::rcc::{Sysclk, mux}; | 7 | use embassy_stm32::rcc::{Sysclk, mux}; |
| 8 | use embassy_stm32_wpan::bindings::mac::ST_MAC_callbacks_t; | 8 | use embassy_stm32_wpan::bindings::mac::{ST_MAC_callbacks_t, ST_MAC_init}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | static _MAC_CALLBACKS: ST_MAC_callbacks_t = ST_MAC_callbacks_t { | 11 | static _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] |
| 2 | channel = "nightly-2025-09-26" | 2 | channel = "nightly-2025-12-11" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] |
| 4 | targets = [ | 4 | targets = [ |
| 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] |
| 2 | channel = "1.90" | 2 | channel = "1.92" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools" ] |
| 4 | targets = [ | 4 | targets = [ |
| 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" } | |||
| 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] } | 12 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] } |
| 13 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 13 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 14 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 14 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 15 | embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 15 | embassy-nrf = { version = "0.9.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 16 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 16 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } |
| 17 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } | 17 | embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } |
| 18 | embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } | 18 | embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } |
