U0具备硬件RNG随机数发生器,相比软件算法得到的随机数,这个硬件RNG是真随机数。在加密时用它生成IV或者随机数,可以使得加密更加的安全。" G* _* A5 Y6 d" ~0 U
/ F* x8 \& `# ?8 g _ P
一、CUBE配置及函数讲解
8 U$ `; B: S4 ~5 ^; R0 E# X* w; c2 [2 s工程我们还是用之前生成的基础模板8 J X6 U3 O$ a0 z0 ^8 |
首先在cube中开启RNG6 n+ ~0 W. @4 o7 M8 y$ ?
0 ?6 F! }( _# S/ J3 T- j( \
; Y, F, \; P/ O) C7 v然后配置一下时钟,RNG的始终要求必须为48Mhz,我选择使用MSI(我一开始尝试了HSI48。但是初始化通不过,没跑通,那就只有换一个) , [, H/ P6 z9 l: N
4 X. H$ p0 c/ v* Z1 Z0 K
4 n- O5 S! T% h) U; s然后把MSI的频率改成48000(也就是48M)
- @: D0 l" {% x% {8 t R' l( ` 然后生成代码 : p! F* u# z& ^9 b1 C
7 m" Z- Y: h v3 f. R$ C3 @
n, w9 y5 s& T6 [% d/ }2 [ C0 Q接下来开始写代码,库函数我没有在cube中修改,使用的是默认的HAL 首先看一下自动生成的代码 CUBE帮我生成了RNG的初始化函数
) |+ ^8 s# v/ t
' O; \9 H/ L) ^/ \3 I
( E1 P0 Y$ A$ X ) r0 G7 Q6 x" b0 e" j$ [
HAL_RNG_Init我就不进去看了,里面主要是做一些参数配置和RNG时钟enable。如果有想仔细研究的可以自行查看。当然想要研究的跟底层,我推荐更换LL库,回头配合寄存器手册,可以学习到最底层的寄存器- d) x9 @! [3 x5 ]4 x L
# P$ A% e2 S6 \3 P# ^3 R4 D
5 w' Z- }3 X# s9 r1 r, w6 g现在简单讲一下HAL库我们会调用的函数
" G- q# z+ |* \! v2 I# g2 K
; r4 `3 q2 P8 c - `5 D/ G C3 K4 a) a% f1 c/ s$ l
阻塞式获取到随机数的函数:HAL_RNG_GenerateRandomNumber + \8 r' u" @# u
通过中断得到随机数:HAL_RNG_GenerateRandomNumber_IT
" Y! N% R; s. m: c4 t6 `5 ~" {# N获取上一次得到过的随机数:HAL_RNG_ReadLastRandomNumber / ~7 j+ F( U) G
( @+ V( f6 U4 q) V& w" v
从参数可以看到,我们每次获取的随机数类型是uint32_t
" l& J( \' c6 ]" ^
4 e7 Z, q- g: \( o二、阻塞式获取到随机数及获取上一次得到过的随机数 , z$ X4 n2 N" V, \
首先设置一个uint32_t类型的全局变量,用于保存得到的随机数
$ n$ o1 z' D8 t5 E( s& q6 b1 B- uint32_t randomData;
3 k+ @( G/ l; \5 }
复制代码 + `6 E# r0 R+ E0 J8 B0 d6 @5 u5 q
: E+ J% `8 F' ]$ D; W( e
% t1 _) P/ g' G3 T初始化后就可以直接调用获取随机数函数,我做了一个测试函数,会连续调用2次获取随机数函数,并且生成后再次调用获取上一次得到过的随机数函数,看看他会不会得到两个不同的随机数。 ' H U+ E4 x6 I9 @
- void GenerateRandomNumber_test()/ a, c3 B. E5 _5 J0 T
- {
' L2 }: s4 Q) | P - uint32_t lastRandomData;
! W! |6 a* O `+ u z8 y - printf("GenerateRandomNumber test\r\n");0 U2 G& o# y9 u2 f h
- 1 e. C/ }# `( u% ]- q6 |
- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);) d) I" O, p6 Y
- printf("GenerateRandomNumber = %04X\r\n", randomData);
9 Y* R' i! g# W: P8 p - 5 w/ |; v' M6 i" @" ?
- lastRandomData = HAL_RNG_ReadLastRandomNumber(&hrng);
% S( k" t1 r( V+ J# r - printf("lastRandomData = %04X\r\n", lastRandomData);
N' Z# B, u" u- R2 r
5 D6 m. ~2 B7 o, I- R3 o- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);
3 H- ?2 y7 k( Z" ~, U* h: y - printf("GenerateRandomNumber = %04X\r\n", randomData);# z; o% a+ N; _/ M% c9 a/ C: g
- }
' K7 L$ V) [( m+ P! n2 h" Z' {* U) B
复制代码
2 p% K( Z5 r+ r+ P2 ^ q4 q8 u6 _
: ?: ]# J& A7 o R" @2 l
' V+ ?. }2 q- C5 ?2 r+ E5 Y& R
) @- `+ Y/ [3 T* z7 Y4 E然后在main中调用 8 ?6 f. ^3 V) [3 t+ {' P
1 r% b" u7 f1 y( a# V' Q' v- _
5 \2 K0 m# h; `4 Y" _6 L7 U# {编译下载,日志如下
2 l+ Z4 k9 R2 i* o0 }; E
1 ?( `7 g. w. r% J
+ s1 A" f+ y) q' c* j/ j两个随机数已经生成,不重复。并且获取上一次得到的随机数也成功 9 D9 V* g4 Z( }- N) P0 g
3 [: p) B5 x5 j7 L/ F
三、通过中断得到随机数
6 @2 F2 f4 h4 v M1 {如果不想阻塞式获取随机数,那我们可以选择使用异步的通过中断获取随机数 8 e/ m% z& I& z, a4 n: H4 X( D9 H
首先需要修改一下CUBE,设置RNG的NVIC
# ^) L: l$ A/ l) I
" z7 V( {# R& F P, b) [5 n
- P6 I* _+ d: v, @; K然后点击右上角的生成代码按钮(图片略)
- m! A3 }( v+ i. L3 C3 w! H* v0 j刚才我们说了通过中断得到随机数为HAL_RNG_GenerateRandomNumber_IT。和之前的BSP的按键一样,中断相关的函数CUBE都帮我配置好了,用户层只要关注回调函数的实现即可。现在我们来看看成功生成随机数的回调函数、生成随机数失败的回调函数 , ?. @* M1 L4 S- Z3 D+ Z! j
t' m1 i0 f, I8 x: Q) z这两个函数在init时就注册好了
0 g0 d7 }! p W7 o% D. [) y
3 E# c8 j2 n& J* ~2 q* I
5 A' U! l4 J+ ?4 n( l7 J这两个函数是HAL库中定义好的两个虚函数,回头我们就要来实现这两个函数。现在看看定义的虚函数 ! t& C" d2 m/ N: k$ k) w
( _/ j0 O$ D D! f$ H( D; \. I9 M3 q
2 B0 G$ y6 i' E1 E6 n/ ?/ ?接下来看看这两个函数是如何被调用的,首先来到stm32u0xx_it.c,看看RNG和CRYP的中断函数(他俩公用一个中断源)
$ m3 B2 |' x/ y) [2 R2 x! d
& d8 `8 a# ?4 Y * g+ x# v0 U' @) A3 i! W3 P
在HAL_RNG_IRQHandler中判断各种寄存器和清除对应寄存器的值等,然后还会调用ReadyDataCallback或者ErrorCallback。 7 ?# D6 x$ D9 A& F9 [
J3 Z% ~; ~$ W% R, P5 j - U+ W& q; E9 C* ]' P- K) B
* r: o: X6 S) }; V
简单的了解完后,我们开始写代码 8 t' O2 |) A( b8 l
; v; A/ I' u" h+ x0 n5 b Z
先把按键测试给打开,这样当按键按下后,我们调用一次HAL_RNG_GenerateRandomNumber_IT
% S3 F0 k6 }, Y) Y. K3 z6 a% ^
. E4 X2 q2 p, \) v( T
) F4 D! b- p- C2 v
while1中的按键测试函数中注释掉LED的翻转,添加HAL_RNG_GenerateRandomNumber_IT和打印 5 B, }% V. c) D# o& X% x
- #if BUTTON_TEST
; G- y: a3 t0 `6 d" u, C- Y - /* BUTTON BSP测试 */
' K+ H; Y8 k$ q) g5 [8 w: F+ s - if (UserButtonState == BUTTON_PRESSED)( r5 c7 r, M4 ^% m% N; g
- {" G" ^4 b, F- y
- UserButtonState = BUTTON_RELEASED;
9 V x/ ]( E* m3 B+ Q - // BSP_LED_Toggle(LED_GREEN);+ i/ M# l" F3 K0 h9 s5 E
- printf("start GenerateRandomNumber_IT\r\n");: O$ m" i. [, z1 T
- HAL_RNG_GenerateRandomNumber_IT(&hrng);
, E/ L* B0 }0 J& W* V# t+ X6 }8 { - }
/ P8 V! b' o& B; d - #endif
复制代码
, b% Y6 M6 J3 s, k接下来实现一下之前说的两个虚函数
; S; ~# b2 {. W: k+ H) t& x( b3 a- void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)9 j- P& C( {% p, o
- {
5 U7 G: _ I% S8 L C8 C& B - randomData = random32bit;; U' Q5 @9 w' R. f7 \! V: s
- printf("Generate RNG IT = %04X\r\n", randomData);- I' C% C1 L, V& _
- }
0 a# c1 y% \: P9 r
: x: [8 @- j7 S& r/ u- void HAL_RNG_ErrorCallback(RNG_HandleTypeDef *hrng)
/ |$ q/ K& U% h d5 x - {
2 D/ h+ n: M, W; t- a6 D+ E0 W6 G0 F - printf("Generate RNG IT ERROR\r\n");
2 @3 J O$ @1 B4 V - Error_Handler();- f$ O- C5 U4 A$ C
- }% A( ]2 `, n7 e, R
复制代码 : u* i. O! ?# I- m2 s0 n$ \
! U0 u" k) c) w5 M
编译下载,日志如下 ; Q* q3 M- e1 s2 j- e
0 \9 k# b9 d% s8 g; [) ~ * V- l, U, L. P1 S
0 V- s5 {. A; Q4 y" u0 }: d8 k7 m5 j( a: ], e( j/ d8 h
今日关于RNG的测试都顺利完成,ST的HAL库还是做得不错的,让用户就关注业务相关的函数,不需要去具体了解每个芯片的各个寄存器,对于开发很友好
6 ?& ~ U3 i$ I0 _9 P/ \* E# `7 H* S. z7 O
|
大佬分析测试的很不错👍,看来我得写点别的了😄