Random Number Generator

For the STM32F407 Discovery Board with a default Mecrisp-Stellaris binary, 8 MHz HSE clock.

Operation

The RNG requires a special clock, and it can only be obtained from the PLL. In this project I use the default Mecrisp-Stellaris settings with the only special hardware config being:

“pll-on” (below) tells the MCU to use the HSE clock for the PLL and to wait until the PLL is ready and stable. The HSE clock is set up by the Mecrisp-Stellaris Kernel and is running by the time you see “Mecrisp-Stellaris x.x.x for STM32F407 by Matthias Koch” greeting message. The PLL is all that the RNG is waiting for now.

Once the PLL is running, the RNG is happy with the power up defaults and can begin generating random numbers.

Note

If the MCU was using the default MCI clock, all one need to do is enable the PLL and the RNG will run nicely using the RCC_PLLCFGR power up default config of $24003010.

print-random 1647364344  ok.
print-random 749262874  ok.
print-random 2962038891  ok.

Source Code

\ Program Name: rnd-f407.fs
\ Project: f407 rng 8mhz HSE clock
\ Created: Sun 14 Mar 2021 20:53:47 AEDT
\ Author Copyright 2021 by t.j.porter <terry@tjporter.com.au>
\ Purpose: Demonstrate the RNG
\ Intended Audience:
\ MCU: STM32F407
\ Board: F4 Disco
\ Core: Mecrisp-Stellaris RA 2.5.4 for STM32F407 by Matthias Koch
\ For use with a default Mecrisp-Stellaris with a serial terminal
\ license: MIT, please see COPYING
\
\ print-random 4141816465  ok.
\ print-random 3956190172  ok.
\ print-random 2788497613  ok.

\ compiletoram

\ comment out any of these previously loaded
$40023800 constant RCC ( Reset and clock control )
RCC $34 + constant RCC_AHB2ENR ( read-write )    \ AHB2 peripheral clock enable  register
RCC $0 + constant RCC_CR (  )  \ clock control register
RCC $4 + constant RCC_PLLCFGR ( read-write )  \ PLL configuration register
$50060800 constant RNG ( Random number generator )
RNG $0 + constant RNG_CR ( read-write ) \ control register
RNG $4 + constant RNG_SR ( )            \ status register
RNG $8 + constant RNG_DR ( read-only )  \ data register

: bit ( u -- u ) 1 swap lshift 1-foldable ;
: RCC_CR_PLLON ( -- x addr ) 24 bit RCC_CR ;            \ Main PLL PLL enable
: RCC_CR_PLLRDY? ( -- 1|0 ) 25 bit RCC_CR bit@ ;        \ Main PLL PLL clock ready  flag
: RCC_PLLCFGR_PLLSRC ( -- x addr ) 22 bit RCC_PLLCFGR ; \ 0: HSI clock selected as PLL, 1: HSE oscillator clock selected as PLL

: PLLCFGR-CNF ( -- )
  1 RCC_PLLCFGR_PLLSRC bis!  \ HSI clock selected as PLL clock source
;

: pll-on ( -- ) PLLCFGR-CNF RCC_CR_PLLON bis! begin RCC_CR_PLLRDY? until ;


0 variable rnd-sample
0 variable rnd-flag

: RCC_AHB2ENR_RNGEN ( -- x addr ) 6 bit RCC_AHB2ENR ;   \ RCC_AHB2ENR_RNGEN, Random number generator clock  enable
: RNG_CR_RNGEN ( -- x addr ) 2 bit RNG_CR ;             \ RNG_CR_RNGEN, Random number generator  enable
: RNG_SR_DRDY? ( -- x addr ) 0 bit RNG_SR bit@ ;        \ RNG_SR_DRDY, Random data ready yet ?
: RNG_SR_SECS? ( -- 1|0 ) 2 bit RNG_SR bit@ ;           \ RNG_SR_SECS, Seed error current status
: RNG_SR_CECS? ( -- 1|0 ) 1 bit RNG_SR bit@ ;           \ RNG_SR_CECS, Clock error current status
: RNG_DR_RNDATA? ( --  x ) RNG_DR @ ;                   \ RNG_DR_RNDATA, Random data output register

: init.rng ( -- )
  pll-on
  RCC_AHB2ENR_RNGEN bis!                                \ Enable Random number generator clock
  RNG_CR_RNGEN bis!                                     \ Enable Random number generator
;

: rng-check-errors ( -- )
  RNG_SR_SECS? if ." There has been a seed error, reinitializing the RNG " cr
     RNG_CR_RNGEN bic!
     RNG_CR_RNGEN bis!
     0 rnd-flag !
     then
  RNG_SR_CECS? if ." There is a RNG CLOCK problem, see page 768 of RM0090 Rev 18" cr exit
     then
 ;

: print-random ( -- )                          \ but check it's valid first.
  rng-check-errors
  RNG_DR_RNDATA?                               \ get the new random number
  rnd-flag @ 0= if                             \ is this the first random number generated since RNG_CR_RNGEN ?
     RNG_DR_RNDATA? rnd-sample !               \ yes, save it
     then                                      \ no, proceed to testing the new number against the old
  begin
     begin RNG_SR_DRDY? until                  \ Is a new random number ready ?
     RNG_DR_RNDATA? dup rnd-sample @ - 0= if   \ compare old and new random numbers
     rnd-sample !                              \ same! save new as old, delete new
  else drop then                               \ different, drop the copy
  dup                                          \ valid RN on the stack, make a copy for final printing
  0<>                                          \ is it greater than zero ? ( question: will the RNG generate 0 as a valid RN ?)
  until
  u.                                           \ yes, Print it
;

init.rng

print-random
print-random
print-random