aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-11-04 13:10:45 +0100
committerUlf Lilleengen <[email protected]>2025-11-04 13:13:22 +0100
commit729a7c2cc5e5fe1d9badb0a0f1c758ba2c57b6aa (patch)
tree967f9fcb91f33b80fa7decc25a0c948927d607c0
parent18a5872a2586335496aec056e24edacef6fd76cb (diff)
feat: initial support for nrf54 CRACEN peripheral
The CRACEN peripheral supports random number generation, digest and key generation, and key exchange. The initial support implements random number generation.
-rw-r--r--embassy-nrf/src/chips/nrf54l15_app.rs2
-rw-r--r--embassy-nrf/src/cracen.rs161
-rw-r--r--embassy-nrf/src/lib.rs4
-rw-r--r--examples/nrf54l15/Cargo.toml2
-rw-r--r--examples/nrf54l15/src/bin/rng.rs29
5 files changed, 197 insertions, 1 deletions
diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs
index d0068eb20..285cdec07 100644
--- a/embassy-nrf/src/chips/nrf54l15_app.rs
+++ b/embassy-nrf/src/chips/nrf54l15_app.rs
@@ -682,6 +682,8 @@ impl_saadc_input!(P1_12, 1, 12);
682impl_saadc_input!(P1_13, 1, 13); 682impl_saadc_input!(P1_13, 1, 13);
683impl_saadc_input!(P1_14, 1, 14); 683impl_saadc_input!(P1_14, 1, 14);
684 684
685impl_cracen!(CRACEN, CRACEN, CRACEN);
686
685embassy_hal_internal::interrupt_mod!( 687embassy_hal_internal::interrupt_mod!(
686 SWI00, 688 SWI00,
687 SWI01, 689 SWI01,
diff --git a/embassy-nrf/src/cracen.rs b/embassy-nrf/src/cracen.rs
new file mode 100644
index 000000000..ddc592689
--- /dev/null
+++ b/embassy-nrf/src/cracen.rs
@@ -0,0 +1,161 @@
1//! CRACEN - Cryptographic Accelerator Engine driver.
2
3#![macro_use]
4
5use crate::mode::{Async, Blocking, Mode};
6use crate::{Peri, interrupt, pac, peripherals};
7use core::marker::PhantomData;
8
9pub struct Cracen<'d, M: Mode> {
10 _peri: Peri<'d, peripherals::CRACEN>,
11 _p: PhantomData<M>,
12}
13
14impl<'d> Cracen<'d, Blocking> {
15 /// Create a new CRACEN driver.
16 pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self {
17 let r = pac::CRACEN;
18
19 let me = Self { _peri, _p: PhantomData };
20
21 me.stop();
22 me
23 }
24}
25
26impl<'d, M: Mode> Cracen<'d, M> {
27 fn regs() -> pac::cracen::Cracen {
28 pac::CRACEN
29 }
30
31 fn core() -> pac::cracencore::Cracencore {
32 pac::CRACENCORE
33 }
34
35 fn start_rng(&self) {
36 let r = Self::regs();
37 r.enable().write(|w| {
38 w.set_rng(true);
39 });
40
41 let r = Self::core();
42 r.rngcontrol().control().write(|w| {
43 w.set_enable(true);
44 });
45
46 while r.rngcontrol().status().read().state() == pac::cracencore::vals::State::STARTUP {}
47 }
48
49 fn stop(&self) {
50 let r = Self::regs();
51 r.enable().write(|w| {
52 w.set_cryptomaster(false);
53 w.set_rng(false);
54 w.set_pkeikg(false);
55 });
56 }
57
58 /// Fill the buffer with random bytes, blocking version.
59 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
60 self.start_rng();
61
62 let r = Self::core();
63 for chunk in dest.chunks_mut(4) {
64 while r.rngcontrol().fifolevel().read() == 0 {}
65 let word = r.rngcontrol().fifo(0).read().to_ne_bytes();
66 let to_copy = word.len().min(chunk.len());
67 chunk[..to_copy].copy_from_slice(&word[..to_copy]);
68 }
69
70 self.stop();
71 }
72
73 /// Generate a random u32
74 pub fn blocking_next_u32(&mut self) -> u32 {
75 let mut bytes = [0; 4];
76 self.blocking_fill_bytes(&mut bytes);
77 // We don't care about the endianness, so just use the native one.
78 u32::from_ne_bytes(bytes)
79 }
80
81 /// Generate a random u64
82 pub fn blocking_next_u64(&mut self) -> u64 {
83 let mut bytes = [0; 8];
84 self.blocking_fill_bytes(&mut bytes);
85 u64::from_ne_bytes(bytes)
86 }
87}
88
89impl<'d, M: Mode> Drop for Cracen<'d, M> {
90 fn drop(&mut self) {
91 let r = Self::core();
92 r.rngcontrol().control().write(|w| {
93 w.set_enable(false);
94 });
95
96 while r.rngcontrol().status().read().state() != pac::cracencore::vals::State::RESET {}
97
98 let r = Self::regs();
99 r.enable().write(|w| {
100 w.set_cryptomaster(false);
101 w.set_rng(false);
102 w.set_pkeikg(false);
103 });
104 }
105}
106
107impl<'d, M: Mode> rand_core_06::RngCore for Cracen<'d, M> {
108 fn fill_bytes(&mut self, dest: &mut [u8]) {
109 self.blocking_fill_bytes(dest);
110 }
111 fn next_u32(&mut self) -> u32 {
112 self.blocking_next_u32()
113 }
114 fn next_u64(&mut self) -> u64 {
115 self.blocking_next_u64()
116 }
117 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
118 self.blocking_fill_bytes(dest);
119 Ok(())
120 }
121}
122
123impl<'d, M: Mode> rand_core_06::CryptoRng for Cracen<'d, M> {}
124
125impl<'d, M: Mode> rand_core_09::RngCore for Cracen<'d, M> {
126 fn fill_bytes(&mut self, dest: &mut [u8]) {
127 self.blocking_fill_bytes(dest);
128 }
129 fn next_u32(&mut self) -> u32 {
130 self.blocking_next_u32()
131 }
132 fn next_u64(&mut self) -> u64 {
133 self.blocking_next_u64()
134 }
135}
136
137impl<'d, M: Mode> rand_core_09::CryptoRng for Cracen<'d, M> {}
138
139pub(crate) trait SealedInstance {
140 fn regs() -> pac::cracen::Cracen;
141}
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 fn regs() -> crate::pac::cracen::Cracen {
154 pac::$pac_type
155 }
156 }
157 impl crate::cracen::Instance for peripherals::$type {
158 type Interrupt = crate::interrupt::typelevel::$irq;
159 }
160 };
161}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 4c3b92a83..530964107 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(feature = "_nrf54l")]
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;
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..3be035b9c
--- /dev/null
+++ b/examples/nrf54l15/src/bin/rng.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::cracen::Cracen;
6use embassy_nrf::{bind_interrupts, cracen, peripherals};
7use rand::Rng as _;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut rng = Cracen::new_blocking(p.CRACEN);
14
15 // Async API
16 let mut bytes = [0; 4];
17 rng.blocking_fill_bytes(&mut bytes);
18 defmt::info!("Some random bytes: {:?}", bytes);
19
20 // Sync API with `rand`
21 defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10));
22
23 let mut bytes = [0; 1024];
24 rng.blocking_fill_bytes(&mut bytes);
25 let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
26 let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
27 defmt::info!("Chance of zero: {}%", zero_count * 100 / (bytes.len() as u32 * 8));
28 defmt::info!("Chance of one: {}%", one_count * 100 / (bytes.len() as u32 * 8));
29}