diff options
| -rw-r--r-- | embassy-nrf/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52805.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52810.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52811.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52820.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52832.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52833.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/chips/nrf52840.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/rng.rs | 154 | ||||
| -rw-r--r-- | examples/nrf/Cargo.toml | 1 | ||||
| -rw-r--r-- | examples/nrf/src/bin/rng.rs | 30 |
12 files changed, 208 insertions, 0 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index eeba1f54e..7b8e36414 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -33,6 +33,7 @@ embedded-hal = { version = "0.2.4" } | |||
| 33 | embedded-dma = { version = "0.1.2" } | 33 | embedded-dma = { version = "0.1.2" } |
| 34 | futures = { version = "0.3.5", default-features = false } | 34 | futures = { version = "0.3.5", default-features = false } |
| 35 | critical-section = "0.2.1" | 35 | critical-section = "0.2.1" |
| 36 | rand_core = "0.6.3" | ||
| 36 | 37 | ||
| 37 | nrf52805-pac = { version = "0.1.0", optional = true, features = [ "rt" ]} | 38 | nrf52805-pac = { version = "0.1.0", optional = true, features = [ "rt" ]} |
| 38 | nrf52810-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} | 39 | nrf52810-pac = { version = "0.9.0", optional = true, features = [ "rt" ]} |
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index f3ceb98e4..2b02c1afe 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -8,6 +8,9 @@ embassy_extras::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // RNG | ||
| 12 | RNG, | ||
| 13 | |||
| 11 | // UARTE | 14 | // UARTE |
| 12 | UARTE0, | 15 | UARTE0, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index dae260545..4c93d5046 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -8,6 +8,9 @@ embassy_extras::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // RNG | ||
| 12 | RNG, | ||
| 13 | |||
| 11 | // UARTE | 14 | // UARTE |
| 12 | UARTE0, | 15 | UARTE0, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 6f9edff35..f840214fa 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -8,6 +8,9 @@ embassy_extras::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // RNG | ||
| 12 | RNG, | ||
| 13 | |||
| 11 | // UARTE | 14 | // UARTE |
| 12 | UARTE0, | 15 | UARTE0, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 8bc50b6d3..180861f71 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -8,6 +8,9 @@ embassy_extras::peripherals! { | |||
| 8 | RTC0, | 8 | RTC0, |
| 9 | RTC1, | 9 | RTC1, |
| 10 | 10 | ||
| 11 | // RNG | ||
| 12 | RNG, | ||
| 13 | |||
| 11 | // UARTE | 14 | // UARTE |
| 12 | UARTE0, | 15 | UARTE0, |
| 13 | 16 | ||
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 6f3f7fc7b..1c38a7751 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -9,6 +9,9 @@ embassy_extras::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // RNG | ||
| 13 | RNG, | ||
| 14 | |||
| 12 | // UARTE | 15 | // UARTE |
| 13 | UARTE0, | 16 | UARTE0, |
| 14 | 17 | ||
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index a0240b196..bcb0fffc0 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -9,6 +9,9 @@ embassy_extras::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // RNG | ||
| 13 | RNG, | ||
| 14 | |||
| 12 | // UARTE | 15 | // UARTE |
| 13 | UARTE0, | 16 | UARTE0, |
| 14 | UARTE1, | 17 | UARTE1, |
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index d4dcfd063..ee8b5a89c 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -9,6 +9,9 @@ embassy_extras::peripherals! { | |||
| 9 | RTC1, | 9 | RTC1, |
| 10 | RTC2, | 10 | RTC2, |
| 11 | 11 | ||
| 12 | // RNG | ||
| 13 | RNG, | ||
| 14 | |||
| 12 | // QSPI | 15 | // QSPI |
| 13 | QSPI, | 16 | QSPI, |
| 14 | 17 | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index f39521594..c2e461cf1 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -33,6 +33,7 @@ pub mod ppi; | |||
| 33 | pub mod pwm; | 33 | pub mod pwm; |
| 34 | #[cfg(feature = "nrf52840")] | 34 | #[cfg(feature = "nrf52840")] |
| 35 | pub mod qspi; | 35 | pub mod qspi; |
| 36 | pub mod rng; | ||
| 36 | pub mod rtc; | 37 | pub mod rtc; |
| 37 | #[cfg(not(feature = "nrf52820"))] | 38 | #[cfg(not(feature = "nrf52820"))] |
| 38 | pub mod saadc; | 39 | pub mod saadc; |
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs new file mode 100644 index 000000000..40778c64c --- /dev/null +++ b/embassy-nrf/src/rng.rs | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | use core::convert::Infallible; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | |||
| 4 | use embassy::interrupt::InterruptExt; | ||
| 5 | use embassy::traits; | ||
| 6 | use embassy::util::OnDrop; | ||
| 7 | use embassy::util::Signal; | ||
| 8 | use embassy::util::Unborrow; | ||
| 9 | use embassy_extras::unborrow; | ||
| 10 | use futures::Future; | ||
| 11 | use rand_core::RngCore; | ||
| 12 | |||
| 13 | use crate::interrupt; | ||
| 14 | use crate::pac; | ||
| 15 | use crate::peripherals::RNG; | ||
| 16 | |||
| 17 | impl RNG { | ||
| 18 | fn regs() -> &'static pac::rng::RegisterBlock { | ||
| 19 | unsafe { &*pac::RNG::ptr() } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | static NEXT_BYTE: Signal<u8> = Signal::new(); | ||
| 24 | |||
| 25 | /// A wrapper around an nRF RNG peripheral. | ||
| 26 | /// | ||
| 27 | /// It has a non-blocking API, through `embassy::traits::Rng`, and a blocking api through `rand`. | ||
| 28 | pub struct Rng<'d> { | ||
| 29 | irq: interrupt::RNG, | ||
| 30 | phantom: PhantomData<&'d mut RNG>, | ||
| 31 | } | ||
| 32 | |||
| 33 | impl<'d> Rng<'d> { | ||
| 34 | pub fn new( | ||
| 35 | _rng: impl Unborrow<Target = RNG> + 'd, | ||
| 36 | irq: impl Unborrow<Target = interrupt::RNG> + 'd, | ||
| 37 | ) -> Self { | ||
| 38 | unborrow!(irq); | ||
| 39 | |||
| 40 | let this = Self { | ||
| 41 | irq, | ||
| 42 | phantom: PhantomData, | ||
| 43 | }; | ||
| 44 | |||
| 45 | this.stop(); | ||
| 46 | this.disable_irq(); | ||
| 47 | |||
| 48 | this.irq.set_handler(Self::on_interrupt); | ||
| 49 | this.irq.unpend(); | ||
| 50 | this.irq.enable(); | ||
| 51 | |||
| 52 | this | ||
| 53 | } | ||
| 54 | |||
| 55 | fn on_interrupt(_: *mut ()) { | ||
| 56 | NEXT_BYTE.signal(RNG::regs().value.read().value().bits()); | ||
| 57 | RNG::regs().events_valrdy.reset(); | ||
| 58 | } | ||
| 59 | |||
| 60 | fn stop(&self) { | ||
| 61 | RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | ||
| 62 | } | ||
| 63 | |||
| 64 | fn start(&self) { | ||
| 65 | RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | ||
| 66 | } | ||
| 67 | |||
| 68 | fn enable_irq(&self) { | ||
| 69 | RNG::regs().intenset.write(|w| w.valrdy().set()); | ||
| 70 | } | ||
| 71 | |||
| 72 | fn disable_irq(&self) { | ||
| 73 | RNG::regs().intenclr.write(|w| w.valrdy().clear()); | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Enable or disable the RNG's bias correction. | ||
| 77 | /// | ||
| 78 | /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. | ||
| 79 | /// However, this makes the generation of numbers slower. | ||
| 80 | /// | ||
| 81 | /// Defaults to disabled. | ||
| 82 | pub fn bias_correction(&self, enable: bool) { | ||
| 83 | RNG::regs().config.write(|w| w.dercen().bit(enable)) | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | impl<'d> Drop for Rng<'d> { | ||
| 88 | fn drop(&mut self) { | ||
| 89 | self.irq.disable() | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | impl<'d> traits::rng::Rng for Rng<'d> { | ||
| 94 | type Error = Infallible; | ||
| 95 | |||
| 96 | #[rustfmt::skip] // For some reason rustfmt removes the where clause | ||
| 97 | type RngFuture<'a> where 'd: 'a = impl Future<Output = Result<(), Self::Error>> + 'a; | ||
| 98 | |||
| 99 | fn fill_bytes<'a>(&'a mut self, dest: &'a mut [u8]) -> Self::RngFuture<'a> { | ||
| 100 | self.enable_irq(); | ||
| 101 | self.start(); | ||
| 102 | |||
| 103 | async move { | ||
| 104 | let on_drop = OnDrop::new(|| { | ||
| 105 | self.stop(); | ||
| 106 | self.disable_irq(); | ||
| 107 | }); | ||
| 108 | |||
| 109 | for byte in dest.iter_mut() { | ||
| 110 | *byte = NEXT_BYTE.wait().await; | ||
| 111 | } | ||
| 112 | |||
| 113 | // Trigger the teardown | ||
| 114 | drop(on_drop); | ||
| 115 | |||
| 116 | Ok(()) | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | impl<'d> RngCore for Rng<'d> { | ||
| 122 | fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
| 123 | self.start(); | ||
| 124 | |||
| 125 | for byte in dest.iter_mut() { | ||
| 126 | let regs = RNG::regs(); | ||
| 127 | while regs.events_valrdy.read().bits() == 0 {} | ||
| 128 | regs.events_valrdy.reset(); | ||
| 129 | *byte = regs.value.read().value().bits(); | ||
| 130 | } | ||
| 131 | |||
| 132 | self.stop(); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn next_u32(&mut self) -> u32 { | ||
| 136 | let mut bytes = [0; 4]; | ||
| 137 | self.fill_bytes(&mut bytes); | ||
| 138 | // We don't care about the endianness, so just use the native one. | ||
| 139 | u32::from_ne_bytes(bytes) | ||
| 140 | } | ||
| 141 | |||
| 142 | fn next_u64(&mut self) -> u64 { | ||
| 143 | let mut bytes = [0; 8]; | ||
| 144 | self.fill_bytes(&mut bytes); | ||
| 145 | u64::from_ne_bytes(bytes) | ||
| 146 | } | ||
| 147 | |||
| 148 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { | ||
| 149 | self.fill_bytes(dest); | ||
| 150 | Ok(()) | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | // TODO: Should `Rng` implement `CryptoRng`? It's 'suitable for cryptographic purposes' according to the specification. | ||
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml index fa1dab360..8db0ad53f 100644 --- a/examples/nrf/Cargo.toml +++ b/examples/nrf/Cargo.toml | |||
| @@ -29,3 +29,4 @@ cortex-m-rt = "0.6.13" | |||
| 29 | embedded-hal = { version = "0.2.4" } | 29 | embedded-hal = { version = "0.2.4" } |
| 30 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } | 30 | panic-probe = { version = "0.2.0", features = ["print-defmt"] } |
| 31 | futures = { version = "0.3.8", default-features = false, features = ["async-await"] } | 31 | futures = { version = "0.3.8", default-features = false, features = ["async-await"] } |
| 32 | rand = { version = "0.8.4", default-features = false } | ||
diff --git a/examples/nrf/src/bin/rng.rs b/examples/nrf/src/bin/rng.rs new file mode 100644 index 000000000..a4c204c2e --- /dev/null +++ b/examples/nrf/src/bin/rng.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(min_type_alias_impl_trait)] | ||
| 4 | #![feature(impl_trait_in_bindings)] | ||
| 5 | #![feature(type_alias_impl_trait)] | ||
| 6 | #![allow(incomplete_features)] | ||
| 7 | |||
| 8 | #[path = "../example_common.rs"] | ||
| 9 | mod example_common; | ||
| 10 | |||
| 11 | use defmt::panic; | ||
| 12 | use embassy::executor::Spawner; | ||
| 13 | use embassy_nrf::Peripherals; | ||
| 14 | use embassy_nrf::rng::Rng; | ||
| 15 | use embassy_nrf::interrupt; | ||
| 16 | use embassy::traits::rng::Rng as _; | ||
| 17 | use rand::Rng as _; | ||
| 18 | |||
| 19 | #[embassy::main] | ||
| 20 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 21 | let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); | ||
| 22 | |||
| 23 | // Async API | ||
| 24 | let mut bytes = [0; 4]; | ||
| 25 | rng.fill_bytes(&mut bytes).await.unwrap(); // nRF RNG is infallible | ||
| 26 | defmt::info!("Some random bytes: {:?}", bytes); | ||
| 27 | |||
| 28 | // Sync API with `rand` | ||
| 29 | defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); | ||
| 30 | } | ||
