stm32f7xx_hal/
rng.rs

1//! Interface to the true random number generator
2
3use core::cmp;
4use core::mem;
5
6use crate::pac::{RCC, RNG};
7use crate::rcc::{Enable, Reset};
8use core::num::NonZeroU32;
9use core::ops::Shl;
10use embedded_hal::blocking::rng::Read;
11use rand_core::RngCore;
12
13#[derive(Debug)]
14pub enum ErrorKind {
15    /// The RNG_CLK was not correctly detected (fRNG_CLK< fHCLK/16).
16    /// See CECS in RNG peripheral documentation.
17    ClockError = 2,
18    /// RNG detected more than 64 consecutive bits of the same value (0 or 1) OR
19    /// more than 32 consecutive 01 pairs.
20    /// See SECS in RNG peripheral documentation.
21    SeedError = 4,
22}
23
24impl From<ErrorKind> for rand_core::Error {
25    fn from(err: ErrorKind) -> rand_core::Error {
26        let err_code = NonZeroU32::new(rand_core::Error::CUSTOM_START + err as u32).unwrap();
27        rand_core::Error::from(err_code)
28    }
29}
30
31pub trait RngExt {
32    fn init(self) -> Rng;
33}
34
35impl RngExt for RNG {
36    /// Enable RNG_CLK and the RNG peripheral.
37    /// Note that clocks must already be configured such that RNG_CLK is not less than 1/16 HCLK,
38    /// otherwise all reads of the RNG would return a ClockError (CECS error).
39    fn init(self) -> Rng {
40        cortex_m::interrupt::free(|_| {
41            let rcc = unsafe { &*RCC::ptr() };
42
43            // need set enable pll for this operation
44            if rcc.cr.read().pllrdy().bit_is_clear() {
45                rcc.cr.modify(|_, w| w.pllon().set_bit());
46                // wait till pll is ready
47                while rcc.cr.read().pllrdy().bit_is_clear() {}
48            }
49            unsafe {
50                // enable RNG_CLK (peripheral clock)
51                RNG::enable_unchecked();
52                // give RNG_CLK time to start
53                RNG::is_enabled();
54                // reset the RNG
55                RNG::reset_unchecked();
56            }
57
58            // enable the RNG peripheral
59            self.cr.modify(|_, w| w.rngen().set_bit());
60            // hardware check for clock is used
61            // instead of software calculation, which may be inaccurate.
62            // until data is available we will check for CECS flag, if it is set
63            // means that clock error occured
64            while !self.sr.read().drdy().bit() {
65                assert!(!self.sr.read().cecs().bit());
66            }
67        });
68
69        Rng { rb: self }
70    }
71}
72
73pub struct Rng {
74    rb: RNG,
75}
76
77impl Rng {
78    /// Returns 32 bits of random data from RNDATA, or error.
79    /// May fail if, for example RNG_CLK is misconfigured.
80    pub fn get_rand(&mut self) -> Result<u32, ErrorKind> {
81        loop {
82            let status = self.rb.sr.read();
83            if status.cecs().bit() {
84                return Err(ErrorKind::ClockError);
85            }
86            if status.secs().bit() {
87                return Err(ErrorKind::SeedError);
88            }
89            if status.drdy().bit() {
90                return Ok(self.rb.dr.read().rndata().bits());
91            }
92        }
93    }
94
95    pub fn release(self) -> RNG {
96        self.rb
97    }
98}
99
100impl Read for Rng {
101    type Error = rand_core::Error;
102
103    fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> {
104        self.try_fill_bytes(buffer)
105    }
106}
107
108impl RngCore for Rng {
109    fn next_u32(&mut self) -> u32 {
110        self.get_rand().unwrap()
111    }
112
113    fn next_u64(&mut self) -> u64 {
114        let w1 = self.next_u32();
115        let w2 = self.next_u32();
116        (w1 as u64).shl(32) | (w2 as u64)
117    }
118
119    fn fill_bytes(&mut self, dest: &mut [u8]) {
120        self.try_fill_bytes(dest).unwrap()
121    }
122
123    /// Fills buffer with random values, or returns an error
124    fn try_fill_bytes(&mut self, buffer: &mut [u8]) -> Result<(), rand_core::Error> {
125        const BATCH_SIZE: usize = 4 / mem::size_of::<u8>();
126        let mut i = 0_usize;
127        while i < buffer.len() {
128            let random_word = self.get_rand()?;
129            let bytes = random_word.to_ne_bytes();
130            let n = cmp::min(BATCH_SIZE, buffer.len() - i);
131            buffer[i..i + n].copy_from_slice(&bytes[..n]);
132            i += n;
133        }
134        Ok(())
135    }
136}