Skip to content

Commit ec70ee8

Browse files
author
Henrik Snöman
committed
Added RNG
1 parent 5e7a293 commit ec70ee8

File tree

3 files changed

+268
-0
lines changed

3 files changed

+268
-0
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ ethernet = [] # Only STM32H563/73 have ethernet
4141
otfdec = [] # Only STM32H573/33 have OTFDEC
4242
sdmmc2 = [] # Only STM32H563/73 have SDMMC2
4343

44+
rand = ["dep:rand_core"]
45+
4446
rt = ["stm32h5/rt"]
4547
stm32h503 = ["stm32h5/stm32h503", "device-selected", "rm0492"]
4648
stm32h562 = ["stm32h5/stm32h562", "device-selected", "rm0481", "h56x_h573"]
@@ -61,6 +63,7 @@ embedded-hal = "1.0.0"
6163
defmt = { version = "0.3.8", optional = true }
6264
paste = "1.0.15"
6365
log = { version = "0.4.20", optional = true}
66+
rand_core = { version = "0.6", default-features = false, optional = true }
6467

6568
[dev-dependencies]
6669
log = { version = "0.4.20"}

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ pub mod icache;
5858
#[cfg(feature = "device-selected")]
5959
pub mod delay;
6060

61+
#[cfg(feature = "device-selected")]
62+
pub mod rng;
63+
6164
#[cfg(feature = "device-selected")]
6265
mod sealed {
6366
pub trait Sealed {}

src/rng.rs

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
// Note: Code taken from stm32h7xx-hal
2+
//! Random Number Generator
3+
//!
4+
//! # Examples
5+
//!
6+
//! - [Random Blinky](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/blinky_random.rs)
7+
8+
use core::cmp;
9+
use core::mem;
10+
11+
use crate::rcc::{rec, rec::RngClkSel};
12+
use crate::rcc::{CoreClocks, ResetEnable};
13+
use crate::stm32::RNG;
14+
use crate::time::Hertz;
15+
16+
#[derive(Debug)]
17+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18+
pub enum ErrorKind {
19+
ClockError = 0,
20+
SeedError = 1,
21+
}
22+
23+
pub trait KerClk {
24+
/// Return the kernel clock for the Random Number Generator
25+
///
26+
/// # Panics
27+
///
28+
/// Panics if the kernel clock is not running
29+
fn kernel_clk_unwrap(prec: rec::Rng, clocks: &CoreClocks) -> Hertz;
30+
}
31+
32+
impl KerClk for RNG {
33+
fn kernel_clk_unwrap(prec: rec::Rng, clocks: &CoreClocks) -> Hertz {
34+
match prec.get_kernel_clk_mux() {
35+
//RngClkSel::Hsi48 => {
36+
RngClkSel::Hsi48Ker => {
37+
clocks.hsi48_ck().expect("RNG: HSI48 must be enabled")
38+
}
39+
RngClkSel::Pll1Q => {
40+
clocks.pll1_q_ck().expect("RNG: PLL1_Q must be enabled")
41+
}
42+
RngClkSel::Lse => unimplemented!(),
43+
RngClkSel::Lsi => {
44+
clocks.lsi_ck().expect("RNG: LSI must be enabled")
45+
}
46+
}
47+
}
48+
}
49+
50+
pub trait RngExt {
51+
fn constrain(self, prec: rec::Rng, clocks: &CoreClocks) -> Rng;
52+
}
53+
54+
impl RngExt for RNG {
55+
fn constrain(self, prec: rec::Rng, clocks: &CoreClocks) -> Rng {
56+
let prec = prec.enable().reset();
57+
58+
let hclk = clocks.hclk();
59+
let rng_clk = Self::kernel_clk_unwrap(prec, clocks);
60+
61+
// Otherwise clock checker will always flag an error
62+
// See RM0433 Rev 6 Section 33.3.6
63+
assert!(rng_clk > hclk / 32, "RNG: Clock too slow");
64+
65+
self.cr().modify(|_, w| w.ced().clear_bit().rngen().set_bit());
66+
67+
Rng { rb: self }
68+
}
69+
}
70+
71+
pub trait RngCore<W> {
72+
fn gen(&mut self) -> Result<W, ErrorKind>;
73+
fn fill(&mut self, dest: &mut [W]) -> Result<(), ErrorKind>;
74+
}
75+
76+
pub struct Rng {
77+
rb: RNG,
78+
}
79+
80+
impl Rng {
81+
/// Returns 32 bits of randomness, or error
82+
pub fn value(&mut self) -> Result<u32, ErrorKind> {
83+
loop {
84+
let status = self.rb.sr().read();
85+
if status.cecs().bit() {
86+
return Err(ErrorKind::ClockError);
87+
}
88+
if status.secs().bit() {
89+
return Err(ErrorKind::SeedError);
90+
}
91+
if status.drdy().bit() {
92+
return Ok(self.rb.dr().read().rndata().bits());
93+
}
94+
}
95+
}
96+
97+
pub fn release(self) -> RNG {
98+
self.rb
99+
}
100+
101+
/// Returns a reference to the inner peripheral
102+
pub fn inner(&self) -> &RNG {
103+
&self.rb
104+
}
105+
106+
/// Returns a mutable reference to the inner peripheral
107+
pub fn inner_mut(&mut self) -> &mut RNG {
108+
&mut self.rb
109+
}
110+
}
111+
112+
impl core::iter::Iterator for Rng {
113+
type Item = u32;
114+
115+
fn next(&mut self) -> Option<u32> {
116+
self.value().ok()
117+
}
118+
}
119+
120+
macro_rules! rng_core {
121+
($($type:ty),+) => {
122+
$(
123+
impl RngCore<$type> for Rng {
124+
/// Returns a single element with random value, or error
125+
fn gen(&mut self) -> Result<$type, ErrorKind> {
126+
let val = self.value()?;
127+
Ok(val as $type)
128+
}
129+
130+
/// Fills buffer with random values, or return error
131+
fn fill(&mut self, buffer: &mut [$type]) -> Result<(), ErrorKind> {
132+
const BATCH_SIZE: usize = 4 / mem::size_of::<$type>();
133+
let mut i = 0_usize;
134+
while i < buffer.len() {
135+
let random_word = self.value()?;
136+
137+
// using to_ne_bytes does not work for u8 and would make the macro
138+
// implementation more complicated
139+
#[allow(clippy::transmute_num_to_bytes)]
140+
let bytes: [$type; BATCH_SIZE] = unsafe { mem::transmute(random_word) };
141+
let n = cmp::min(BATCH_SIZE, buffer.len() - i);
142+
buffer[i..i + n].copy_from_slice(&bytes[..n]);
143+
i += n;
144+
}
145+
Ok(())
146+
}
147+
}
148+
)+
149+
};
150+
}
151+
152+
// Only for types larger than 32 bits
153+
macro_rules! rng_core_large {
154+
($($type:ty),+) => {
155+
$(
156+
impl RngCore<$type> for Rng {
157+
fn gen(&mut self) -> Result<$type, ErrorKind> {
158+
const WORDS: usize = mem::size_of::<$type>() / mem::size_of::<u32>();
159+
let mut res: $type = 0;
160+
161+
for i in 0..WORDS {
162+
res |= (self.value()? as $type) << (i * (mem::size_of::<u32>() * 8))
163+
}
164+
165+
Ok(res)
166+
}
167+
168+
fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> {
169+
let len = dest.len() * (mem::size_of::<$type>() / mem::size_of::<u32>());
170+
let ptr = dest.as_mut_ptr() as *mut u32;
171+
let slice_u32 = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
172+
self.fill(slice_u32)
173+
}
174+
}
175+
)+
176+
};
177+
}
178+
179+
macro_rules! rng_core_transmute {
180+
($($type:ty = $from:ty),+) => {
181+
$(
182+
impl RngCore<$type> for Rng {
183+
fn gen(&mut self) -> Result<$type, ErrorKind> {
184+
let num = <Self as RngCore<$from>>::gen(self)?;
185+
Ok(unsafe { mem::transmute::<$from, $type>(num) })
186+
}
187+
188+
fn fill(&mut self, dest: &mut [$type]) -> Result<(), ErrorKind> {
189+
let unsigned_slice = unsafe { mem::transmute::<&mut [$type], &mut [$from]>(dest) };
190+
<Self as RngCore<$from>>::fill(self, unsigned_slice)
191+
}
192+
}
193+
)+
194+
};
195+
}
196+
197+
rng_core!(u8, u16, u32);
198+
199+
// Alignment of these types must be a multiple of mem::align_of::<32>()
200+
rng_core_large!(u64, u128);
201+
202+
// A and B must have the same alignment
203+
// rng_core_transmute!(A = B)
204+
// assert!(mem::align_of::<A>() == mem::align_of::<B>())
205+
rng_core_transmute!(
206+
i8 = u8,
207+
i16 = u16,
208+
i32 = u32,
209+
i64 = u64,
210+
i128 = u128,
211+
isize = usize
212+
);
213+
214+
// If usize is 32 bits, use the rng_core! impl
215+
#[cfg(target_pointer_width = "32")]
216+
rng_core!(usize);
217+
218+
// If usize is 64 bits, use the rng_core_large! impl
219+
#[cfg(target_pointer_width = "64")]
220+
rng_core_large!(usize);
221+
222+
// rand_core
223+
#[cfg(feature = "rand")]
224+
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
225+
impl rand_core::RngCore for Rng {
226+
/// Generate a random u32
227+
/// Panics if RNG fails.
228+
fn next_u32(&mut self) -> u32 {
229+
self.gen().unwrap()
230+
}
231+
232+
/// Generate a random u64
233+
/// Panics if RNG fails.
234+
fn next_u64(&mut self) -> u64 {
235+
self.gen().unwrap()
236+
}
237+
238+
/// Fill a slice with random data.
239+
/// Panics if RNG fails.
240+
fn fill_bytes(&mut self, dest: &mut [u8]) {
241+
self.fill(dest).unwrap()
242+
}
243+
244+
/// Try to fill a slice with random data. Return an error if RNG fails.
245+
fn try_fill_bytes(
246+
&mut self,
247+
dest: &mut [u8],
248+
) -> Result<(), rand_core::Error> {
249+
self.fill(dest).map_err(|e| {
250+
core::num::NonZeroU32::new(
251+
rand_core::Error::CUSTOM_START + e as u32,
252+
)
253+
// This should never fail as long as no enum variant is equal to 0
254+
.expect("Internal hal error")
255+
.into()
256+
})
257+
}
258+
}
259+
260+
#[cfg(feature = "rand")]
261+
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
262+
impl rand_core::CryptoRng for Rng {}

0 commit comments

Comments
 (0)