stm32f4xx_hal/
rng.rs

1//! # Hardware random number generator.
2//!
3//!
4//! The build in random number generator (RNG) of an STM32F4 uses analog noise to
5//! provide random 32-bit values.
6//!
7//! Notes:
8//! - It takes 40 periods of `RNG_CLK` to generate a new random value.
9//! - The RNG requires the `PLL48_CLK` to be active ([more details](RngExt::constrain))
10//!
11//! For more details, see reference manual chapter 24.
12//!
13//! Minimal working example:
14//! ```
15//! let dp = pac::Peripherals::take().unwrap();
16//! let rcc = dp.RCC.constrain();
17//! let clocks = rcc.cfgr.require_pll48clk().freeze();
18//! let mut rand_source = dp.RNG.constrain(clocks);
19//! let rand_val = rand_source.next_u32();
20//! ```
21//!
22//! A full example can be found [in the examples folder on github](https://github.com/stm32-rs/stm32f4xx-hal/blob/master/examples/rng-display.rs)
23use core::cmp;
24use core::mem;
25
26use crate::pac::RNG;
27use crate::rcc::{Enable, Rcc, Reset};
28use core::num::NonZeroU32;
29use core::ops::Shl;
30use embedded_hal_02::blocking::rng;
31use fugit::RateExtU32;
32
33/// Random number generator specific errors
34#[derive(Debug, Eq, PartialEq, Copy, Clone)]
35pub enum ErrorKind {
36    /// The RNG_CLK was not correctly detected (fRNG_CLK< fHCLK/16).
37    /// See CECS in RNG peripheral documentation.
38    ClockError = 2,
39    /// RNG detected more than 64 consecutive bits of the same value (0 or 1) OR
40    /// more than 32 consecutive 01 pairs.
41    /// See SECS in RNG peripheral documentation.
42    SeedError = 4,
43}
44
45impl From<ErrorKind> for rand_core_06::Error {
46    fn from(err: ErrorKind) -> rand_core_06::Error {
47        let err_code = NonZeroU32::new(rand_core_06::Error::CUSTOM_START + err as u32).unwrap();
48        rand_core_06::Error::from(err_code)
49    }
50}
51
52/// Helper trait to implement the `constrain` method for the
53/// [RNG peripheral](crate::pac::RNG) which is how the [Rng] struct is
54/// created.
55///
56/// Usage:
57/// ```
58/// let dp = pac::Peripherals::take().unwrap();
59/// let rcc = dp.RCC.constrain();
60/// let clocks = rcc.cfgr.require_pll48clk().freeze();
61/// let mut rand_source = dp.RNG.constrain(clocks);
62/// ```
63pub trait RngExt {
64    /// Enables the hardware random generator and provides the [Rng] struct.
65    ///
66    /// The datasheet states, that the `RNG_CLK` must not be less than 1/16 HCLK
67    /// (HCLK is the CPU clock), otherwise all reads of the RNG would return a
68    /// ClockError (CECS error).
69    /// As the `RNG_CLK` always seems to be connected to the `PLL48_CLK` and the
70    /// maximum value of `HCLK` is 168MHz, this is always true as long as the `PLL48_CLK` is enabled.
71    /// This can be done with the [require_pll48clk](crate::rcc::Config::require_pll48clk) function.
72    ///
73    /// See reference manual section 24.4.2 for more details
74    ///
75    /// # Panics
76    ///
77    /// This function will panic if `PLL48_CLK < 1/16 HCLK`.
78    fn constrain(self, rcc: &mut Rcc) -> Rng;
79}
80
81impl RngExt for RNG {
82    fn constrain(self, rcc: &mut Rcc) -> Rng {
83        cortex_m::interrupt::free(|_| {
84            // enable RNG_CLK (peripheral clock)
85            RNG::enable(rcc);
86            RNG::reset(rcc);
87
88            // verify the clock configuration is valid
89            let hclk = rcc.clocks.hclk();
90            let rng_clk = rcc.clocks.pll48clk().unwrap_or_else(|| 0.Hz());
91            assert!(rng_clk >= (hclk / 16));
92
93            // enable the RNG peripheral
94            self.cr().modify(|_, w| w.rngen().set_bit());
95        });
96
97        Rng { rb: self }
98    }
99}
100
101/// Random number provider which provides access to all [rand_core::RngCore]
102/// functions.
103///
104/// Example use:
105///
106/// ```
107/// use rand_core::RngCore;
108///
109/// // ...
110///
111/// let mut rand_source = dp.RNG.constrain(clocks);
112/// let rand_u32: u32 = rand_source.next_u32();
113/// let rand_u64: u64 = rand_source.next_u64();
114/// ```
115pub struct Rng {
116    rb: RNG,
117}
118
119impl Rng {
120    /// Returns 32 bits of random data from RNDATA, or error.
121    /// May fail if, for example RNG_CLK is misconfigured.
122    fn next_random_word(&mut self) -> Result<u32, ErrorKind> {
123        loop {
124            let status = self.rb.sr().read();
125            if status.cecs().bit() {
126                return Err(ErrorKind::ClockError);
127            }
128            if status.secs().bit() {
129                return Err(ErrorKind::SeedError);
130            }
131            if status.drdy().bit() {
132                return Ok(self.rb.dr().read().rndata().bits());
133            }
134        }
135    }
136
137    fn try_fill_bytes(&mut self, buffer: &mut [u8]) -> Result<(), ErrorKind> {
138        const BATCH_SIZE: usize = 4 / mem::size_of::<u8>();
139        let mut i = 0_usize;
140        while i < buffer.len() {
141            let random_word = self.next_random_word()?;
142            let bytes = random_word.to_ne_bytes();
143            let n = cmp::min(BATCH_SIZE, buffer.len() - i);
144            buffer[i..i + n].copy_from_slice(&bytes[..n]);
145            i += n;
146        }
147        Ok(())
148    }
149
150    /// Releases ownership of the [`RNG`] peripheral object
151    /// (after which `self` can't be used anymore).
152    pub fn release(self) -> RNG {
153        self.rb
154    }
155}
156
157impl rng::Read for Rng {
158    type Error = rand_core_06::Error;
159
160    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
161        self.try_fill_bytes(buffer)?;
162        Ok(())
163    }
164}
165
166impl rand_core::RngCore for Rng {
167    fn next_u32(&mut self) -> u32 {
168        self.next_random_word().unwrap()
169    }
170
171    fn next_u64(&mut self) -> u64 {
172        let w1 = self.next_u32();
173        let w2 = self.next_u32();
174        (w1 as u64).shl(32) | (w2 as u64)
175    }
176
177    fn fill_bytes(&mut self, dest: &mut [u8]) {
178        self.try_fill_bytes(dest).unwrap()
179    }
180}
181
182impl rand_core_06::RngCore for Rng {
183    fn next_u32(&mut self) -> u32 {
184        self.next_random_word().unwrap()
185    }
186
187    fn next_u64(&mut self) -> u64 {
188        let w1 = self.next_u32();
189        let w2 = self.next_u32();
190        (w1 as u64).shl(32) | (w2 as u64)
191    }
192
193    fn fill_bytes(&mut self, dest: &mut [u8]) {
194        self.try_fill_bytes(dest).unwrap()
195    }
196
197    /// Fills buffer with random values, or returns an error
198    fn try_fill_bytes(&mut self, buffer: &mut [u8]) -> Result<(), rand_core_06::Error> {
199        self.try_fill_bytes(buffer)?;
200        Ok(())
201    }
202}