aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-11-04 14:09:02 +0000
committerGitHub <[email protected]>2025-11-04 14:09:02 +0000
commitdda429ce6642deaa490f8737e1373e2e2ba79655 (patch)
tree1654bda53f0297e171bca6c7c9620900c03764b8
parentb867072c7eefdd2cf0a19bacd86f4be820624ed9 (diff)
parent48d0d99752227b8f6834d30af63bfc4c959a10d1 (diff)
Merge pull request #4836 from embassy-rs/nrf54-more
further nRF54 improvements
-rw-r--r--embassy-nrf/CHANGELOG.md3
-rw-r--r--embassy-nrf/src/chips/nrf54l15_app.rs32
-rw-r--r--embassy-nrf/src/cracen.rs157
-rw-r--r--embassy-nrf/src/lib.rs35
-rw-r--r--examples/nrf54l15/Cargo.toml2
-rw-r--r--examples/nrf54l15/src/bin/rng.rs28
6 files changed, 255 insertions, 2 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index a0668c495..72ecb116a 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -18,7 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18- changed: support setting duty cycles with inverted polarity in `SimplePwm` 18- changed: support setting duty cycles with inverted polarity in `SimplePwm`
19- added: support setting the duty cycles of all channels at once in `SimplePwm` 19- added: support setting the duty cycles of all channels at once in `SimplePwm`
20- changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54 20- changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54
21- added: support for nrf54l peripherals: uart, gpiote, twim, twis, spim, spis, dppi, pwm, saadc 21- added: support for nrf54l peripherals: uart, gpiote, twim, twis, spim, spis, dppi, pwm, saadc, cracen
22- added: support for changing nrf54l clock speed
22- bugfix: Do not write to UICR from non-secure code on nrf53 23- bugfix: Do not write to UICR from non-secure code on nrf53
23- bugfix: Add delay to uart init anomaly fix 24- bugfix: Add delay to uart init anomaly fix
24- changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned 25- changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs
index f5c9a8156..0724f2ff6 100644
--- a/embassy-nrf/src/chips/nrf54l15_app.rs
+++ b/embassy-nrf/src/chips/nrf54l15_app.rs
@@ -218,6 +218,29 @@ embassy_hal_internal::peripherals! {
218 PPI00_CH7, 218 PPI00_CH7,
219 219
220 PPI10_CH0, 220 PPI10_CH0,
221 PPI10_CH1,
222 PPI10_CH2,
223 PPI10_CH3,
224 PPI10_CH4,
225 PPI10_CH5,
226 PPI10_CH6,
227 PPI10_CH7,
228 PPI10_CH8,
229 PPI10_CH9,
230 PPI10_CH10,
231 PPI10_CH11,
232 PPI10_CH12,
233 PPI10_CH13,
234 PPI10_CH14,
235 PPI10_CH15,
236 PPI10_CH16,
237 PPI10_CH17,
238 PPI10_CH18,
239 PPI10_CH19,
240 PPI10_CH20,
241 PPI10_CH21,
242 PPI10_CH22,
243 PPI10_CH23,
221 244
222 PPI20_CH0, 245 PPI20_CH0,
223 PPI20_CH1, 246 PPI20_CH1,
@@ -245,6 +268,11 @@ embassy_hal_internal::peripherals! {
245 PPI00_GROUP1, 268 PPI00_GROUP1,
246 269
247 PPI10_GROUP0, 270 PPI10_GROUP0,
271 PPI10_GROUP1,
272 PPI10_GROUP2,
273 PPI10_GROUP3,
274 PPI10_GROUP4,
275 PPI10_GROUP5,
248 276
249 PPI20_GROUP0, 277 PPI20_GROUP0,
250 PPI20_GROUP1, 278 PPI20_GROUP1,
@@ -433,6 +461,7 @@ embassy_hal_internal::peripherals! {
433 GPIOTE30_CH3, 461 GPIOTE30_CH3,
434 462
435 // CRACEN 463 // CRACEN
464 #[cfg(feature = "_s")]
436 CRACEN, 465 CRACEN,
437 466
438 #[cfg(feature = "_s")] 467 #[cfg(feature = "_s")]
@@ -654,6 +683,9 @@ impl_saadc_input!(P1_12, 1, 12);
654impl_saadc_input!(P1_13, 1, 13); 683impl_saadc_input!(P1_13, 1, 13);
655impl_saadc_input!(P1_14, 1, 14); 684impl_saadc_input!(P1_14, 1, 14);
656 685
686#[cfg(feature = "_s")]
687impl_cracen!(CRACEN, CRACEN, CRACEN);
688
657embassy_hal_internal::interrupt_mod!( 689embassy_hal_internal::interrupt_mod!(
658 SWI00, 690 SWI00,
659 SWI01, 691 SWI01,
diff --git a/embassy-nrf/src/cracen.rs b/embassy-nrf/src/cracen.rs
new file mode 100644
index 000000000..47ef1cd87
--- /dev/null
+++ b/embassy-nrf/src/cracen.rs
@@ -0,0 +1,157 @@
1//! CRACEN - Cryptographic Accelerator Engine driver.
2
3#![macro_use]
4
5use core::marker::PhantomData;
6
7use crate::mode::{Blocking, Mode};
8use crate::{Peri, interrupt, pac, peripherals};
9
10/// A wrapper around an nRF54 CRACEN peripheral.
11///
12/// It has a blocking api through `rand`.
13pub struct Cracen<'d, M: Mode> {
14 _peri: Peri<'d, peripherals::CRACEN>,
15 _p: PhantomData<M>,
16}
17
18impl<'d> Cracen<'d, Blocking> {
19 /// Create a new CRACEN driver.
20 pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self {
21 let me = Self { _peri, _p: PhantomData };
22
23 me.stop();
24 me
25 }
26}
27
28impl<'d, M: Mode> Cracen<'d, M> {
29 fn regs() -> pac::cracen::Cracen {
30 pac::CRACEN
31 }
32
33 fn core() -> pac::cracencore::Cracencore {
34 pac::CRACENCORE
35 }
36
37 fn start_rng(&self) {
38 let r = Self::regs();
39 r.enable().write(|w| {
40 w.set_rng(true);
41 });
42
43 let r = Self::core();
44 r.rngcontrol().control().write(|w| {
45 w.set_enable(true);
46 });
47
48 while r.rngcontrol().status().read().state() == pac::cracencore::vals::State::STARTUP {}
49 }
50
51 fn stop(&self) {
52 let r = Self::regs();
53 r.enable().write(|w| {
54 w.set_cryptomaster(false);
55 w.set_rng(false);
56 w.set_pkeikg(false);
57 });
58 }
59
60 /// Fill the buffer with random bytes, blocking version.
61 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
62 self.start_rng();
63
64 let r = Self::core();
65 for chunk in dest.chunks_mut(4) {
66 while r.rngcontrol().fifolevel().read() == 0 {}
67 let word = r.rngcontrol().fifo(0).read().to_ne_bytes();
68 let to_copy = word.len().min(chunk.len());
69 chunk[..to_copy].copy_from_slice(&word[..to_copy]);
70 }
71
72 self.stop();
73 }
74
75 /// Generate a random u32
76 pub fn blocking_next_u32(&mut self) -> u32 {
77 let mut bytes = [0; 4];
78 self.blocking_fill_bytes(&mut bytes);
79 // We don't care about the endianness, so just use the native one.
80 u32::from_ne_bytes(bytes)
81 }
82
83 /// Generate a random u64
84 pub fn blocking_next_u64(&mut self) -> u64 {
85 let mut bytes = [0; 8];
86 self.blocking_fill_bytes(&mut bytes);
87 u64::from_ne_bytes(bytes)
88 }
89}
90
91impl<'d, M: Mode> Drop for Cracen<'d, M> {
92 fn drop(&mut self) {
93 let r = Self::core();
94 r.rngcontrol().control().write(|w| {
95 w.set_enable(false);
96 });
97
98 while r.rngcontrol().status().read().state() != pac::cracencore::vals::State::RESET {}
99
100 let r = Self::regs();
101 r.enable().write(|w| {
102 w.set_cryptomaster(false);
103 w.set_rng(false);
104 w.set_pkeikg(false);
105 });
106 }
107}
108
109impl<'d, M: Mode> rand_core_06::RngCore for Cracen<'d, M> {
110 fn fill_bytes(&mut self, dest: &mut [u8]) {
111 self.blocking_fill_bytes(dest);
112 }
113 fn next_u32(&mut self) -> u32 {
114 self.blocking_next_u32()
115 }
116 fn next_u64(&mut self) -> u64 {
117 self.blocking_next_u64()
118 }
119 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
120 self.blocking_fill_bytes(dest);
121 Ok(())
122 }
123}
124
125impl<'d, M: Mode> rand_core_06::CryptoRng for Cracen<'d, M> {}
126
127impl<'d, M: Mode> rand_core_09::RngCore for Cracen<'d, M> {
128 fn fill_bytes(&mut self, dest: &mut [u8]) {
129 self.blocking_fill_bytes(dest);
130 }
131 fn next_u32(&mut self) -> u32 {
132 self.blocking_next_u32()
133 }
134 fn next_u64(&mut self) -> u64 {
135 self.blocking_next_u64()
136 }
137}
138
139impl<'d, M: Mode> rand_core_09::CryptoRng for Cracen<'d, M> {}
140
141pub(crate) trait SealedInstance {}
142
143/// CRACEN peripheral instance.
144#[allow(private_bounds)]
145pub trait Instance: SealedInstance + 'static + Send {
146 /// Interrupt for this peripheral.
147 type Interrupt: interrupt::typelevel::Interrupt;
148}
149
150macro_rules! impl_cracen {
151 ($type:ident, $pac_type:ident, $irq:ident) => {
152 impl crate::cracen::SealedInstance for peripherals::$type {}
153 impl crate::cracen::Instance for peripherals::$type {
154 type Interrupt = crate::interrupt::typelevel::$irq;
155 }
156 };
157}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 4c3b92a83..2f5ad352f 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -145,10 +145,12 @@ pub mod radio;
145#[cfg(feature = "_net-driver")] 145#[cfg(feature = "_net-driver")]
146pub mod embassy_net_802154_driver; 146pub mod embassy_net_802154_driver;
147 147
148#[cfg(all(feature = "_nrf54l", feature = "_s"))]
149pub mod cracen;
148#[cfg(not(feature = "_nrf54l"))] // TODO 150#[cfg(not(feature = "_nrf54l"))] // TODO
149#[cfg(feature = "_nrf5340")] 151#[cfg(feature = "_nrf5340")]
150pub mod reset; 152pub mod reset;
151#[cfg(not(feature = "_nrf54l"))] // TODO 153#[cfg(not(feature = "_nrf54l"))]
152#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] 154#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
153pub mod rng; 155pub mod rng;
154pub mod rtc; 156pub mod rtc;
@@ -283,6 +285,15 @@ pub use crate::pac::NVIC_PRIO_BITS;
283pub mod config { 285pub mod config {
284 //! Configuration options used when initializing the HAL. 286 //! Configuration options used when initializing the HAL.
285 287
288 /// Clock speed
289 #[cfg(feature = "_nrf54l")]
290 pub enum ClockSpeed {
291 /// Run at 128 MHz.
292 CK128,
293 /// Run at 64 MHz.
294 CK64,
295 }
296
286 /// High frequency clock source. 297 /// High frequency clock source.
287 pub enum HfclkSource { 298 pub enum HfclkSource {
288 /// Internal source 299 /// Internal source
@@ -552,6 +563,9 @@ pub mod config {
552 pub time_interrupt_priority: crate::interrupt::Priority, 563 pub time_interrupt_priority: crate::interrupt::Priority,
553 /// Enable or disable the debug port. 564 /// Enable or disable the debug port.
554 pub debug: Debug, 565 pub debug: Debug,
566 /// Clock speed configuration.
567 #[cfg(feature = "_nrf54l")]
568 pub clock_speed: ClockSpeed,
555 } 569 }
556 570
557 impl Default for Config { 571 impl Default for Config {
@@ -592,6 +606,8 @@ pub mod config {
592 debug: Debug::NotConfigured, 606 debug: Debug::NotConfigured,
593 #[cfg(not(feature = "_ns"))] 607 #[cfg(not(feature = "_ns"))]
594 debug: Debug::Allowed, 608 debug: Debug::Allowed,
609 #[cfg(feature = "_nrf54l")]
610 clock_speed: ClockSpeed::CK64,
595 } 611 }
596 } 612 }
597 } 613 }
@@ -698,6 +714,23 @@ pub fn init(config: config::Config) -> Peripherals {
698 #[allow(unused_mut)] 714 #[allow(unused_mut)]
699 let mut needs_reset = false; 715 let mut needs_reset = false;
700 716
717 // set clock speed
718 #[cfg(feature = "_nrf54l")]
719 {
720 #[cfg(feature = "_s")]
721 let regs = pac::OSCILLATORS_S;
722 #[cfg(feature = "_ns")]
723 let regs = pac::OSCILLATORS_NS;
724
725 use pac::oscillators::vals::Freq;
726 regs.pll().freq().write(|w| {
727 w.set_freq(match config.clock_speed {
728 config::ClockSpeed::CK64 => Freq::CK64M,
729 config::ClockSpeed::CK128 => Freq::CK128M,
730 });
731 });
732 }
733
701 // Workaround used in the nrf mdk: file system_nrf91.c , function SystemInit(), after `#if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)` 734 // Workaround used in the nrf mdk: file system_nrf91.c , function SystemInit(), after `#if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)`
702 #[cfg(all(feature = "_nrf91", feature = "_s"))] 735 #[cfg(all(feature = "_nrf91", feature = "_s"))]
703 { 736 {
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
index 14a80efe7..4ef77279f 100644
--- a/examples/nrf54l15/Cargo.toml
+++ b/examples/nrf54l15/Cargo.toml
@@ -14,6 +14,8 @@ embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defm
14embedded-io = { version = "0.6.0", features = ["defmt-03"] } 14embedded-io = { version = "0.6.0", features = ["defmt-03"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16 16
17rand = { version = "0.9.0", default-features = false }
18
17defmt = "1.0.1" 19defmt = "1.0.1"
18defmt-rtt = "1.0.0" 20defmt-rtt = "1.0.0"
19panic-probe = { version = "1.0.0", features = ["print-defmt"] } 21panic-probe = { version = "1.0.0", features = ["print-defmt"] }
diff --git a/examples/nrf54l15/src/bin/rng.rs b/examples/nrf54l15/src/bin/rng.rs
new file mode 100644
index 000000000..b2d7f906b
--- /dev/null
+++ b/examples/nrf54l15/src/bin/rng.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::cracen::Cracen;
6use rand::Rng as _;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut rng = Cracen::new_blocking(p.CRACEN);
13
14 // Async API
15 let mut bytes = [0; 4];
16 rng.blocking_fill_bytes(&mut bytes);
17 defmt::info!("Some random bytes: {:?}", bytes);
18
19 // Sync API with `rand`
20 defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10));
21
22 let mut bytes = [0; 1024];
23 rng.blocking_fill_bytes(&mut bytes);
24 let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
25 let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
26 defmt::info!("Chance of zero: {}%", zero_count * 100 / (bytes.len() as u32 * 8));
27 defmt::info!("Chance of one: {}%", one_count * 100 / (bytes.len() as u32 * 8));
28}