1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//! Support for the Random Number Generator (RNG) peripheral.

use cortex_m::interrupt::free;

use crate::{
    pac::{RCC, RNG},
    rcc_en_reset,
};

use cfg_if::cfg_if;

/// Represents a RNG peripheral.
pub struct Rng {
    pub regs: RNG,
}

impl Rng {
    /// Initialize a RNG peripheral, including configuration register writes, and enabling and resetting
    /// its RCC peripheral clock.
    pub fn new(regs: RNG) -> Self {
        free(|_| {
            let rcc = unsafe { &(*RCC::ptr()) };

            cfg_if! {
                if #[cfg(feature = "g0")] {
                    rcc_en_reset!(ahb1, rng, rcc);
                } else if #[cfg(any(feature = "wb", feature = "wl"))] {
                    rcc_en_reset!(ahb3, rng, rcc);
                } else {
                    rcc_en_reset!(ahb2, rng, rcc);
                }
            }
        });

        #[cfg(feature = "l5")]
        regs.rng_cr.modify(|_, w| w.rngen().set_bit());
        #[cfg(not(feature = "l5"))]
        regs.cr.modify(|_, w| w.rngen().set_bit());

        Self { regs }
    }

    /// Load a random number from the data register
    pub fn read(&mut self) -> i32 {
        // When data is not ready (DRDY=”0”) RNG_DR returns zero.
        // It is recommended to always verify that RNG_DR is different from zero. Because when it is
        // the case a seed error occurred between RNG_SR polling and RND_DR output reading (rare
        // event).
        // todo: CHeck for 0? Check for DREDY?

        // https://github.com/stm32-rs/stm32-rs/issues/650 L5 error
        #[cfg(feature = "l5")]
        return self.regs.rng_dr.read().bits() as i32;
        #[cfg(not(feature = "l5"))]
        return self.regs.dr.read().bits() as i32;
    }

    /// Enable an interrupt. An interrupt isgenerated when a random number is ready or when an error
    /// occurs. Therefore at each interrupt, check that: No error occured (SEIS and CEIS bits should be set
    /// to 0 in the RNG_SR register. A random number is ready. The DRDY bit must be set to 1 in the
    /// RNG_SR register.
    pub fn enable_interrupt(&mut self) {
        #[cfg(feature = "l5")]
        self.regs.rng_cr.modify(|_, w| w.ie().set_bit());
        #[cfg(not(feature = "l5"))]
        self.regs.cr.modify(|_, w| w.ie().set_bit());
    }
}