U0具备硬件RNG随机数发生器,相比软件算法得到的随机数,这个硬件RNG是真随机数。在加密时用它生成IV或者随机数,可以使得加密更加的安全。
; G. j2 V# ~" W* u% g* A' Y+ L* [; I$ X, Z" G' s
一、CUBE配置及函数讲解
* s( O% m0 d) C" R工程我们还是用之前生成的基础模板' v) d: N, i: l3 |) ?
首先在cube中开启RNG
; s; F% K! R2 ~4 o' Q8 W: X7 U
3 C8 W% y' V1 p 6 P* x% c* {$ I5 R- J m i% i6 C R
然后配置一下时钟,RNG的始终要求必须为48Mhz,我选择使用MSI(我一开始尝试了HSI48。但是初始化通不过,没跑通,那就只有换一个) # f& |- D" y# u( t: j4 R
7 U9 k, e) L6 v4 U' }3 s5 [3 ^( c
- t0 e) ?9 [9 I A9 M* ?- V然后把MSI的频率改成48000(也就是48M)
6 T c3 D6 H& y. f5 \1 A 然后生成代码
- C0 e/ v* s2 R( p
. s6 B" K5 ]* b4 B9 g
% l" @* ^; q# s7 \7 ~& `接下来开始写代码,库函数我没有在cube中修改,使用的是默认的HAL 首先看一下自动生成的代码 CUBE帮我生成了RNG的初始化函数
; ~5 x0 U6 z4 ^; j0 Y6 h
1 {8 I1 L/ T9 Y+ Y7 a) v
7 ]. |' A, E. @% T4 E3 P
7 X5 }+ r5 c9 n; k# w; Q$ J6 THAL_RNG_Init我就不进去看了,里面主要是做一些参数配置和RNG时钟enable。如果有想仔细研究的可以自行查看。当然想要研究的跟底层,我推荐更换LL库,回头配合寄存器手册,可以学习到最底层的寄存器% H+ w. H2 `; B$ D" l8 W
2 H- q5 n3 m. s1 a% X
3 X0 x+ D1 B: S4 |8 m. Q/ d现在简单讲一下HAL库我们会调用的函数 + {1 l; g; l/ m* m% ^6 \
# `* o) J( U" N% P+ m. @4 \3 f - E- [1 n- u8 e+ E( x1 f
阻塞式获取到随机数的函数:HAL_RNG_GenerateRandomNumber ; N7 Y& q; h" J7 }& C7 D% n
通过中断得到随机数:HAL_RNG_GenerateRandomNumber_IT : R2 \1 x' @3 A. ^
获取上一次得到过的随机数:HAL_RNG_ReadLastRandomNumber
1 e2 h1 P. z3 d! _ U6 g' T% N4 X5 B" t9 e p3 k0 s
从参数可以看到,我们每次获取的随机数类型是uint32_t
( w6 v* _# L+ }. w% K' f v. x+ ~* r5 L& G. D @
二、阻塞式获取到随机数及获取上一次得到过的随机数 0 d' ]5 D4 n4 Y* J& ?# C* i, g
首先设置一个uint32_t类型的全局变量,用于保存得到的随机数
( j7 f* p) Z8 c9 w) [, u- uint32_t randomData;0 g3 b8 @( p4 D6 N
复制代码
# X; g) T- L# C; a' v9 r ; B+ K1 h5 B+ G6 I: C
- S/ P7 i( ~: n初始化后就可以直接调用获取随机数函数,我做了一个测试函数,会连续调用2次获取随机数函数,并且生成后再次调用获取上一次得到过的随机数函数,看看他会不会得到两个不同的随机数。 * V7 E- D1 e6 C( c- y
- void GenerateRandomNumber_test()
" a4 {( S) L+ J1 W3 F - {& V* _) t+ m l9 B
- uint32_t lastRandomData;! a7 P5 U0 Z% j6 `* x1 L3 a; y
- printf("GenerateRandomNumber test\r\n");8 {5 b! C0 {* O. c0 A' ]$ K
- 7 C+ E5 J$ e; T1 v
- HAL_RNG_GenerateRandomNumber(&hrng, &randomData); D7 Q$ p$ D7 X
- printf("GenerateRandomNumber = %04X\r\n", randomData);8 J0 L! u1 ?) m7 `& |) m
- ( s: m$ q' R* e& G/ M. L
- lastRandomData = HAL_RNG_ReadLastRandomNumber(&hrng);
9 ?. Y+ Y6 r! |! F2 \- X - printf("lastRandomData = %04X\r\n", lastRandomData);
; m& d! F% {1 l; O! }+ G1 Z
1 f$ V. j7 W) U- M& n7 {- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);6 A) P+ e* x4 K; s% I: c3 {
- printf("GenerateRandomNumber = %04X\r\n", randomData);
+ R* U5 n0 I* m$ h* X8 A9 W( o5 V4 H( f - }
' C& x' \" T" S
复制代码
* x2 \4 A8 b4 g+ k( A4 I% F8 V7 n3 n 4 `+ s+ {. z. [) V1 n
; M9 }: B, S" M) r, K Q. ]
* u, w# s% c' B6 @6 T0 x
然后在main中调用 8 U: W$ f% f# c [+ |$ Z
% C9 X2 _) u' M) q 0 N4 L" [; X5 O9 `( W/ a4 C! g
编译下载,日志如下
S: d. l$ y! r) G) [, D
% I$ l: L5 X: I# }' e
& F% t8 t' R N! t' t/ Z+ \- D两个随机数已经生成,不重复。并且获取上一次得到的随机数也成功
6 k# R8 |4 d! S0 D
: m/ s$ W* v& b9 \/ {三、通过中断得到随机数
2 J$ p9 M( y' e7 w: }. E4 C/ ^4 x0 K0 X如果不想阻塞式获取随机数,那我们可以选择使用异步的通过中断获取随机数 ' \# v+ W% @5 l* y
首先需要修改一下CUBE,设置RNG的NVIC 7 Q, T- B1 E; {9 p
2 K- F$ |; p' e3 n9 s + T/ ~5 e) \7 o$ A' G7 h+ m
然后点击右上角的生成代码按钮(图片略) , U) E* v0 a% h( J7 a0 Y
刚才我们说了通过中断得到随机数为HAL_RNG_GenerateRandomNumber_IT。和之前的BSP的按键一样,中断相关的函数CUBE都帮我配置好了,用户层只要关注回调函数的实现即可。现在我们来看看成功生成随机数的回调函数、生成随机数失败的回调函数
* m! w x3 j4 h$ I2 N% w3 k
9 B5 R! l9 I9 [6 e7 w: ?9 t' b这两个函数在init时就注册好了
6 l. Q2 U/ r. \
! n+ r6 E& C0 v1 ]9 }6 U6 }) }9 f + a4 _8 H! j! i/ g1 X) [
这两个函数是HAL库中定义好的两个虚函数,回头我们就要来实现这两个函数。现在看看定义的虚函数
' p3 q: y8 q3 k' E; a) }- L
( ?, k0 {7 K R& L 3 k1 @& k9 A+ \; b, p) M4 W; R
接下来看看这两个函数是如何被调用的,首先来到stm32u0xx_it.c,看看RNG和CRYP的中断函数(他俩公用一个中断源)
2 ^6 K/ b: r$ O: @ W% x2 n" f
+ { ~ L/ @; g9 P" ~
% X. h) O) k) v' F$ `在HAL_RNG_IRQHandler中判断各种寄存器和清除对应寄存器的值等,然后还会调用ReadyDataCallback或者ErrorCallback。
; C& a: ^- M! K+ i/ K1 @5 U
5 x$ ^( z+ ?/ p8 G) ?# ^8 m f 7 r0 F) t* T. w
6 h j! U" I( I, y- c! @
简单的了解完后,我们开始写代码
% ^( ^9 H& I& A/ h( H2 g1 v" w- ?1 b* B. e6 s( ]' W, @
先把按键测试给打开,这样当按键按下后,我们调用一次HAL_RNG_GenerateRandomNumber_IT
- Q4 Y4 R; w( T0 V; _9 _) N
: X* @1 t* J0 n, l! u; Y
I7 D# s$ d% O8 Q* v3 Y2 g. Zwhile1中的按键测试函数中注释掉LED的翻转,添加HAL_RNG_GenerateRandomNumber_IT和打印 + m- |' w6 Y0 \' k/ a* P: H" U
- #if BUTTON_TEST
, F4 q$ Y3 f. V( N( G$ i% Q - /* BUTTON BSP测试 */+ _, U$ _- A( U g" ]. N- ^+ I) V g
- if (UserButtonState == BUTTON_PRESSED)0 s4 \8 \: h1 d! ?! n3 p( w4 ~
- {* c4 s) Z5 F- {9 ~1 T# [8 t1 u6 t
- UserButtonState = BUTTON_RELEASED;( f: c' ]+ Z6 A0 j2 _7 k6 i
- // BSP_LED_Toggle(LED_GREEN);' n2 Q$ X7 @! f! F9 J% O j8 c
- printf("start GenerateRandomNumber_IT\r\n");
1 r4 |( r# g ~9 _0 a0 r+ F - HAL_RNG_GenerateRandomNumber_IT(&hrng);: r6 N2 a& k+ X
- }: y; f9 i' w' ~" p
- #endif
复制代码 9 h* n% }& a" k! p2 v9 |
接下来实现一下之前说的两个虚函数
7 W' D' F0 ~: l( b5 D- void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)# g6 `$ T2 K }
- {
2 t9 j; [" \" Y - randomData = random32bit;
6 P" C5 X( a- P# b! ?+ A - printf("Generate RNG IT = %04X\r\n", randomData);
7 {$ f z% D" b( \2 \ - }
' A8 `' a0 v5 m8 X7 k - / g8 F/ l3 J& J! f9 L% ]
- void HAL_RNG_ErrorCallback(RNG_HandleTypeDef *hrng)
- p3 C* Z- z7 c+ P - {
; c) s2 R3 ]; i% Y8 _ - printf("Generate RNG IT ERROR\r\n");
5 N9 j/ D: @ x- b; P1 @ - Error_Handler();
* T5 u' B5 F% g) F. |1 D - }
+ o$ b! `. x' }
复制代码
# C; W' V1 D' Z
' ^0 d/ U8 u1 `$ Q* o r" a5 o2 x编译下载,日志如下
; r" F$ `( ~( h- D a
b1 G, o3 u2 V4 f# ]
3 G4 V. I S( N0 d! x9 {/ _$ M. j+ T
/ d1 u- p6 v' Y: B4 ^; `
今日关于RNG的测试都顺利完成,ST的HAL库还是做得不错的,让用户就关注业务相关的函数,不需要去具体了解每个芯片的各个寄存器,对于开发很友好 - m. h* s* [' z4 J3 R. t
# v0 X9 U$ s, ~) k |
大佬分析测试的很不错👍,看来我得写点别的了😄