From 18a5872a2586335496aec056e24edacef6fd76cb Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:09:41 +0100 Subject: feat: enable missing PPI channels and groups --- embassy-nrf/src/chips/nrf54l15_app.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index f5c9a8156..d0068eb20 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! { PPI00_CH7, PPI10_CH0, + PPI10_CH1, + PPI10_CH2, + PPI10_CH3, + PPI10_CH4, + PPI10_CH5, + PPI10_CH6, + PPI10_CH7, + PPI10_CH8, + PPI10_CH9, + PPI10_CH10, + PPI10_CH11, + PPI10_CH12, + PPI10_CH13, + PPI10_CH14, + PPI10_CH15, + PPI10_CH16, + PPI10_CH17, + PPI10_CH18, + PPI10_CH19, + PPI10_CH20, + PPI10_CH21, + PPI10_CH22, + PPI10_CH23, PPI20_CH0, PPI20_CH1, @@ -245,6 +268,11 @@ embassy_hal_internal::peripherals! { PPI00_GROUP1, PPI10_GROUP0, + PPI10_GROUP1, + PPI10_GROUP2, + PPI10_GROUP3, + PPI10_GROUP4, + PPI10_GROUP5, PPI20_GROUP0, PPI20_GROUP1, -- cgit From 729a7c2cc5e5fe1d9badb0a0f1c758ba2c57b6aa Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:10:45 +0100 Subject: 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. --- embassy-nrf/src/chips/nrf54l15_app.rs | 2 + embassy-nrf/src/cracen.rs | 161 ++++++++++++++++++++++++++++++++++ embassy-nrf/src/lib.rs | 4 +- examples/nrf54l15/Cargo.toml | 2 + examples/nrf54l15/src/bin/rng.rs | 29 ++++++ 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 embassy-nrf/src/cracen.rs create mode 100644 examples/nrf54l15/src/bin/rng.rs 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); impl_saadc_input!(P1_13, 1, 13); impl_saadc_input!(P1_14, 1, 14); +impl_cracen!(CRACEN, CRACEN, CRACEN); + embassy_hal_internal::interrupt_mod!( SWI00, 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 @@ +//! CRACEN - Cryptographic Accelerator Engine driver. + +#![macro_use] + +use crate::mode::{Async, Blocking, Mode}; +use crate::{Peri, interrupt, pac, peripherals}; +use core::marker::PhantomData; + +pub struct Cracen<'d, M: Mode> { + _peri: Peri<'d, peripherals::CRACEN>, + _p: PhantomData, +} + +impl<'d> Cracen<'d, Blocking> { + /// Create a new CRACEN driver. + pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self { + let r = pac::CRACEN; + + let me = Self { _peri, _p: PhantomData }; + + me.stop(); + me + } +} + +impl<'d, M: Mode> Cracen<'d, M> { + fn regs() -> pac::cracen::Cracen { + pac::CRACEN + } + + fn core() -> pac::cracencore::Cracencore { + pac::CRACENCORE + } + + fn start_rng(&self) { + let r = Self::regs(); + r.enable().write(|w| { + w.set_rng(true); + }); + + let r = Self::core(); + r.rngcontrol().control().write(|w| { + w.set_enable(true); + }); + + while r.rngcontrol().status().read().state() == pac::cracencore::vals::State::STARTUP {} + } + + fn stop(&self) { + let r = Self::regs(); + r.enable().write(|w| { + w.set_cryptomaster(false); + w.set_rng(false); + w.set_pkeikg(false); + }); + } + + /// Fill the buffer with random bytes, blocking version. + pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { + self.start_rng(); + + let r = Self::core(); + for chunk in dest.chunks_mut(4) { + while r.rngcontrol().fifolevel().read() == 0 {} + let word = r.rngcontrol().fifo(0).read().to_ne_bytes(); + let to_copy = word.len().min(chunk.len()); + chunk[..to_copy].copy_from_slice(&word[..to_copy]); + } + + self.stop(); + } + + /// Generate a random u32 + pub fn blocking_next_u32(&mut self) -> u32 { + let mut bytes = [0; 4]; + self.blocking_fill_bytes(&mut bytes); + // We don't care about the endianness, so just use the native one. + u32::from_ne_bytes(bytes) + } + + /// Generate a random u64 + pub fn blocking_next_u64(&mut self) -> u64 { + let mut bytes = [0; 8]; + self.blocking_fill_bytes(&mut bytes); + u64::from_ne_bytes(bytes) + } +} + +impl<'d, M: Mode> Drop for Cracen<'d, M> { + fn drop(&mut self) { + let r = Self::core(); + r.rngcontrol().control().write(|w| { + w.set_enable(false); + }); + + while r.rngcontrol().status().read().state() != pac::cracencore::vals::State::RESET {} + + let r = Self::regs(); + r.enable().write(|w| { + w.set_cryptomaster(false); + w.set_rng(false); + w.set_pkeikg(false); + }); + } +} + +impl<'d, M: Mode> rand_core_06::RngCore for Cracen<'d, M> { + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { + self.blocking_fill_bytes(dest); + Ok(()) + } +} + +impl<'d, M: Mode> rand_core_06::CryptoRng for Cracen<'d, M> {} + +impl<'d, M: Mode> rand_core_09::RngCore for Cracen<'d, M> { + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } +} + +impl<'d, M: Mode> rand_core_09::CryptoRng for Cracen<'d, M> {} + +pub(crate) trait SealedInstance { + fn regs() -> pac::cracen::Cracen; +} + +/// CRACEN peripheral instance. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: interrupt::typelevel::Interrupt; +} + +macro_rules! impl_cracen { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::cracen::SealedInstance for peripherals::$type { + fn regs() -> crate::pac::cracen::Cracen { + pac::$pac_type + } + } + impl crate::cracen::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +} 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; #[cfg(feature = "_net-driver")] pub mod embassy_net_802154_driver; +#[cfg(feature = "_nrf54l")] +pub mod cracen; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "_nrf5340")] pub mod reset; -#[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(not(feature = "_nrf54l"))] #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; pub 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 embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } +rand = { version = "0.9.0", default-features = false } + defmt = "1.0.1" defmt-rtt = "1.0.0" panic-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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::cracen::Cracen; +use embassy_nrf::{bind_interrupts, cracen, peripherals}; +use rand::Rng as _; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut rng = Cracen::new_blocking(p.CRACEN); + + // Async API + let mut bytes = [0; 4]; + rng.blocking_fill_bytes(&mut bytes); + defmt::info!("Some random bytes: {:?}", bytes); + + // Sync API with `rand` + defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10)); + + let mut bytes = [0; 1024]; + rng.blocking_fill_bytes(&mut bytes); + let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros()); + let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones()); + defmt::info!("Chance of zero: {}%", zero_count * 100 / (bytes.len() as u32 * 8)); + defmt::info!("Chance of one: {}%", one_count * 100 / (bytes.len() as u32 * 8)); +} -- cgit From 4e4da7854f8e162f3a8ffa0dae5595a1baf78952 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:12:46 +0100 Subject: feat: add nrf54 config to set clock speed --- embassy-nrf/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 530964107..bc386e820 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -285,6 +285,15 @@ pub use crate::pac::NVIC_PRIO_BITS; pub mod config { //! Configuration options used when initializing the HAL. + /// Clock speed + #[cfg(feature = "_nrf54l")] + pub enum ClockSpeed { + /// Run at 128 MHz. + CK128, + /// Run at 64 MHz. + CK64, + } + /// High frequency clock source. pub enum HfclkSource { /// Internal source @@ -554,6 +563,8 @@ pub mod config { pub time_interrupt_priority: crate::interrupt::Priority, /// Enable or disable the debug port. pub debug: Debug, + #[cfg(feature = "_nrf54l")] + pub clock_speed: ClockSpeed, } impl Default for Config { @@ -594,6 +605,8 @@ pub mod config { debug: Debug::NotConfigured, #[cfg(not(feature = "_ns"))] debug: Debug::Allowed, + #[cfg(feature = "_nrf54l")] + clock_speed: ClockSpeed::CK64, } } } @@ -700,6 +713,23 @@ pub fn init(config: config::Config) -> Peripherals { #[allow(unused_mut)] let mut needs_reset = false; + // set clock speed + #[cfg(feature = "_nrf54l")] + { + #[cfg(feature = "_s")] + let regs = pac::OSCILLATORS_S; + #[cfg(feature = "_ns")] + let regs = pac::OSCILLATORS_NS; + + use pac::oscillators::vals::Freq; + regs.pll().freq().write(|w| { + w.set_freq(match config.clock_speed { + config::ClockSpeed::CK64 => Freq::CK64M, + config::ClockSpeed::CK128 => Freq::CK128M, + }); + }); + } + // Workaround used in the nrf mdk: file system_nrf91.c , function SystemInit(), after `#if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)` #[cfg(all(feature = "_nrf91", feature = "_s"))] { -- cgit From a863db9fbae05d154e78d5d19db4dde786285d13 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:14:10 +0100 Subject: docs: update changelog --- embassy-nrf/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 - changed: support setting duty cycles with inverted polarity in `SimplePwm` - added: support setting the duty cycles of all channels at once in `SimplePwm` - changed: updated to nrf-pac with nrf52/nrf53/nrf91 register layout more similar to nrf54 -- added: support for nrf54l peripherals: uart, gpiote, twim, twis, spim, spis, dppi, pwm, saadc +- added: support for nrf54l peripherals: uart, gpiote, twim, twis, spim, spis, dppi, pwm, saadc, cracen +- added: support for changing nrf54l clock speed - bugfix: Do not write to UICR from non-secure code on nrf53 - bugfix: Add delay to uart init anomaly fix - changed: `BufferedUarte::read_ready` now uses the same definition for 'empty' so following read calls will not block when true is returned -- cgit From f2c1da56eb9690c9fa3edcd73d430e669fa7baa7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:29:04 +0100 Subject: fix: warnings --- embassy-nrf/src/cracen.rs | 17 ++++++----------- embassy-nrf/src/lib.rs | 1 + 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/embassy-nrf/src/cracen.rs b/embassy-nrf/src/cracen.rs index ddc592689..62e6f8c86 100644 --- a/embassy-nrf/src/cracen.rs +++ b/embassy-nrf/src/cracen.rs @@ -2,10 +2,13 @@ #![macro_use] -use crate::mode::{Async, Blocking, Mode}; +use crate::mode::{Blocking, Mode}; use crate::{Peri, interrupt, pac, peripherals}; use core::marker::PhantomData; +/// A wrapper around an nRF54 CRACEN peripheral. +/// +/// It has a blocking api through `rand`. pub struct Cracen<'d, M: Mode> { _peri: Peri<'d, peripherals::CRACEN>, _p: PhantomData, @@ -14,8 +17,6 @@ pub struct Cracen<'d, M: Mode> { impl<'d> Cracen<'d, Blocking> { /// Create a new CRACEN driver. pub fn new_blocking(_peri: Peri<'d, peripherals::CRACEN>) -> Self { - let r = pac::CRACEN; - let me = Self { _peri, _p: PhantomData }; me.stop(); @@ -136,9 +137,7 @@ impl<'d, M: Mode> rand_core_09::RngCore for Cracen<'d, M> { impl<'d, M: Mode> rand_core_09::CryptoRng for Cracen<'d, M> {} -pub(crate) trait SealedInstance { - fn regs() -> pac::cracen::Cracen; -} +pub(crate) trait SealedInstance {} /// CRACEN peripheral instance. #[allow(private_bounds)] @@ -149,11 +148,7 @@ pub trait Instance: SealedInstance + 'static + Send { macro_rules! impl_cracen { ($type:ident, $pac_type:ident, $irq:ident) => { - impl crate::cracen::SealedInstance for peripherals::$type { - fn regs() -> crate::pac::cracen::Cracen { - pac::$pac_type - } - } + impl crate::cracen::SealedInstance for peripherals::$type {} impl crate::cracen::Instance for peripherals::$type { type Interrupt = crate::interrupt::typelevel::$irq; } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index bc386e820..69ca4e0a1 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -563,6 +563,7 @@ pub mod config { pub time_interrupt_priority: crate::interrupt::Priority, /// Enable or disable the debug port. pub debug: Debug, + /// Clock speed configuration. #[cfg(feature = "_nrf54l")] pub clock_speed: ClockSpeed, } -- cgit From cce3b45fdfbcecc7d1ae92bd341fdc6f8bce53ff Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:30:38 +0100 Subject: chore: rustfmt --- embassy-nrf/src/cracen.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/cracen.rs b/embassy-nrf/src/cracen.rs index 62e6f8c86..47ef1cd87 100644 --- a/embassy-nrf/src/cracen.rs +++ b/embassy-nrf/src/cracen.rs @@ -2,9 +2,10 @@ #![macro_use] +use core::marker::PhantomData; + use crate::mode::{Blocking, Mode}; use crate::{Peri, interrupt, pac, peripherals}; -use core::marker::PhantomData; /// A wrapper around an nRF54 CRACEN peripheral. /// -- cgit From 4152facff6c14d4fc26d23b62fefdb50163d96f2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:37:19 +0100 Subject: fix: cracen only in secure mode --- embassy-nrf/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 69ca4e0a1..2f5ad352f 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -145,7 +145,7 @@ pub mod radio; #[cfg(feature = "_net-driver")] pub mod embassy_net_802154_driver; -#[cfg(feature = "_nrf54l")] +#[cfg(all(feature = "_nrf54l", feature = "_s"))] pub mod cracen; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "_nrf5340")] -- cgit From 43af352733fc93ce05304b3122e52a6a9da50e22 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 13:39:59 +0100 Subject: chore: warnings --- examples/nrf54l15/src/bin/rng.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/nrf54l15/src/bin/rng.rs b/examples/nrf54l15/src/bin/rng.rs index 3be035b9c..b2d7f906b 100644 --- a/examples/nrf54l15/src/bin/rng.rs +++ b/examples/nrf54l15/src/bin/rng.rs @@ -3,7 +3,6 @@ use embassy_executor::Spawner; use embassy_nrf::cracen::Cracen; -use embassy_nrf::{bind_interrupts, cracen, peripherals}; use rand::Rng as _; use {defmt_rtt as _, panic_probe as _}; -- cgit From 48d0d99752227b8f6834d30af63bfc4c959a10d1 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 4 Nov 2025 14:58:09 +0100 Subject: fix: more cracen secure mode only --- embassy-nrf/src/chips/nrf54l15_app.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index 285cdec07..0724f2ff6 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -461,6 +461,7 @@ embassy_hal_internal::peripherals! { GPIOTE30_CH3, // CRACEN + #[cfg(feature = "_s")] CRACEN, #[cfg(feature = "_s")] @@ -682,6 +683,7 @@ impl_saadc_input!(P1_12, 1, 12); impl_saadc_input!(P1_13, 1, 13); impl_saadc_input!(P1_14, 1, 14); +#[cfg(feature = "_s")] impl_cracen!(CRACEN, CRACEN, CRACEN); embassy_hal_internal::interrupt_mod!( -- cgit