samd/mcu: Implement a hardware seed for the SAMD21 random module.
By using the phase jitter between the DFLL48M clock and the FDPLL96M clock. Even if both use the same reference source, they have a different jitter. SysTick is driven by FDPLL96M, the us counter by DFLL48M. As a random source, the us counter is read out on every SysTick and the value is used to accumulate a simple multiply, add and xor register. According to tests it creates about 30 bit random bit-flips per second. That mechanism will pass quite a few RNG tests, has a suitable frequency distribution and serves better than just the time after boot to seed the PRNG.
This commit is contained in:
parent
7e0b1bc95d
commit
76cf98c35b
|
@ -42,8 +42,10 @@ The :mod:`machine` module::
|
|||
machine.freq(96_000_000) # set the CPU frequency to 96 MHz
|
||||
|
||||
The range accepted by the function call is 1_000_000 to 200_000_000 (1 MHz to 200 MHz)
|
||||
for SAMD51 and 1_000_000 to 48_000_000 (1 MHz to 48 MHz) for SAMD21. The safe
|
||||
range for SAMD51 according to the data sheet is 96 MHz to 120 MHz.
|
||||
for SAMD51 and 1_000_000 to 54_000_000 (1 MHz to 54 MHz) for SAMD21. The safe
|
||||
range for SAMD51 according to the data sheet is up to 120 MHz, for the SAMD21 up to 48Mhz.
|
||||
Frequencies below 48Mhz are set by dividing 48Mhz by an integer, limiting the number of
|
||||
discrete frequencies to 24Mhz, 16Mhz, 12MHz, and so on.
|
||||
At frequencies below 8 MHz USB will be disabled. Changing the frequency below 48 MHz
|
||||
impacts the baud rates of UART, I2C and SPI. These have to be set again after
|
||||
changing the CPU frequency. The ms and µs timers are not affected by the frequency
|
||||
|
|
|
@ -78,8 +78,9 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
|
|||
// CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
|
||||
SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF;
|
||||
// Set the FDPLL ratio and enable the DPLL.
|
||||
int ldr = cpu_freq_arg / FDPLL_REF_FREQ - 1;
|
||||
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(ldr);
|
||||
int ldr = cpu_freq / FDPLL_REF_FREQ;
|
||||
int frac = ((cpu_freq - ldr * FDPLL_REF_FREQ) / (FDPLL_REF_FREQ / 16)) & 0x0f;
|
||||
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR((frac << 16 | ldr) - 1);
|
||||
SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;
|
||||
// Wait for the DPLL lock.
|
||||
while (!SYSCTRL->DPLLSTATUS.bit.LOCK) {
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#define MICROPY_PY_CMATH (0)
|
||||
#endif
|
||||
|
||||
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
|
||||
unsigned long trng_random_u32(void);
|
||||
|
||||
#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages;
|
||||
|
||||
#ifndef MICROPY_HW_UART_TXBUF
|
||||
|
|
|
@ -42,6 +42,9 @@ extern void EIC_Handler(void);
|
|||
const ISR isr_vector[];
|
||||
volatile uint32_t systick_ms;
|
||||
volatile uint32_t ticks_us64_upper;
|
||||
#if defined(MCU_SAMD21)
|
||||
volatile uint32_t rng_state;
|
||||
#endif
|
||||
|
||||
void Reset_Handler(void) __attribute__((naked));
|
||||
void Reset_Handler(void) {
|
||||
|
@ -91,6 +94,12 @@ void Default_Handler(void) {
|
|||
}
|
||||
|
||||
void SysTick_Handler(void) {
|
||||
#if defined(MCU_SAMD21)
|
||||
// Use the phase jitter between the clocks to get some entropy
|
||||
// and accumulate the random number register.
|
||||
rng_state = (rng_state * 32310901 + 1) ^ (REG_TC4_COUNT32_COUNT >> 1);
|
||||
#endif
|
||||
|
||||
uint32_t next_tick = systick_ms + 1;
|
||||
systick_ms = next_tick;
|
||||
|
||||
|
@ -99,6 +108,13 @@ void SysTick_Handler(void) {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(MCU_SAMD21)
|
||||
uint32_t trng_random_u32(void) {
|
||||
mp_hal_delay_ms(320); // wait for ten cycles of the rng_seed register
|
||||
return rng_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
void us_timer_IRQ(void) {
|
||||
#if defined(MCU_SAMD21)
|
||||
if (TC4->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {
|
||||
|
|
Loading…
Reference in New Issue