U0具备硬件RNG随机数发生器,相比软件算法得到的随机数,这个硬件RNG是真随机数。在加密时用它生成IV或者随机数,可以使得加密更加的安全。
* @' Y8 |( U9 l, d1 C6 l: p* K5 X+ ~! L7 P- P# P
一、CUBE配置及函数讲解4 N4 P2 i0 k2 M; f" ^, k" c
工程我们还是用之前生成的基础模板
, u# s3 a" j j: O# n首先在cube中开启RNG
7 z$ l/ r% M; M% @/ _9 q" s
. V' @0 F/ B; q4 `: w" \1 | $ S% q0 L5 ^; D6 A
然后配置一下时钟,RNG的始终要求必须为48Mhz,我选择使用MSI(我一开始尝试了HSI48。但是初始化通不过,没跑通,那就只有换一个)
, L# t/ q, A( M: u0 v) C; H& K
1 b- U; x, k+ J
3 s% C8 z& S: U& H% l然后把MSI的频率改成48000(也就是48M)
5 N. Y% w" J# y 然后生成代码 4 _. F0 Y, ]/ J; e6 W, F; N
+ E& ^2 M8 e% k/ J
3 u8 \ J* g2 V+ z3 W( ]2 j: x/ i G
接下来开始写代码,库函数我没有在cube中修改,使用的是默认的HAL 首先看一下自动生成的代码 CUBE帮我生成了RNG的初始化函数
6 j9 L, i( `) k6 y9 |* t9 A
3 `* k/ n2 t! A; _( H' I6 H
! v6 R" I' [6 Z! u/ _' e/ a5 R
4 B. C0 _$ K3 J; ?+ o Q) M& W6 IHAL_RNG_Init我就不进去看了,里面主要是做一些参数配置和RNG时钟enable。如果有想仔细研究的可以自行查看。当然想要研究的跟底层,我推荐更换LL库,回头配合寄存器手册,可以学习到最底层的寄存器2 h- S( S, S) ~
' Q* i( ?: t9 K% f! m9 x/ Y; F1 o! E* f% O8 t) h4 _0 S1 r8 s
现在简单讲一下HAL库我们会调用的函数
. { _# h1 K0 N Z) Z" b
) t$ r3 g/ X5 F
* j' f3 F6 h. }$ E( G阻塞式获取到随机数的函数:HAL_RNG_GenerateRandomNumber " l( F; b+ A3 a9 C8 a: W: F% K
通过中断得到随机数:HAL_RNG_GenerateRandomNumber_IT
7 m7 {/ Z7 P' u8 K% V& F; r: m. D获取上一次得到过的随机数:HAL_RNG_ReadLastRandomNumber
/ b" d/ I: A; @6 N' O
2 J6 c' N) G& q/ V6 {从参数可以看到,我们每次获取的随机数类型是uint32_t
2 t' Z! {! L0 y0 |1 L. [9 a( J7 ^6 Z/ t3 r: u! y J& Y
二、阻塞式获取到随机数及获取上一次得到过的随机数 : }5 L( V% Q% {1 w, @; r: n
首先设置一个uint32_t类型的全局变量,用于保存得到的随机数 ) Y# E% u) y9 \# N9 U
- uint32_t randomData;
, ^; G% ^) C2 z
复制代码
0 n. m# K# B; \* d- q- u& F$ Q
/ t8 S) P) ]( ?: Y9 s2 i F
k9 Q0 Z+ o; g- k& Y: G4 D初始化后就可以直接调用获取随机数函数,我做了一个测试函数,会连续调用2次获取随机数函数,并且生成后再次调用获取上一次得到过的随机数函数,看看他会不会得到两个不同的随机数。
& ?' @% Y) R! x2 j! E5 N- void GenerateRandomNumber_test()+ W& f" U$ t0 g. @
- {
) Q! y! h0 {0 B, X - uint32_t lastRandomData;
f4 ~. D* p8 {& q - printf("GenerateRandomNumber test\r\n");
P7 u4 ^8 f: V9 x8 M - + t1 ] C" t0 J( C
- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);* ]: ?3 u- n( `* I/ e
- printf("GenerateRandomNumber = %04X\r\n", randomData);
! k& ?" [" X& H
* v: }% I9 F P0 [& e- lastRandomData = HAL_RNG_ReadLastRandomNumber(&hrng); a1 s- ~5 W% M5 O" n0 P
- printf("lastRandomData = %04X\r\n", lastRandomData);& |, _; R- E; n& w9 p: Y# L- U# i
- 5 O4 B f5 d7 m
- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);% R( @* k% t' m9 @7 w/ H O5 m; g# ?
- printf("GenerateRandomNumber = %04X\r\n", randomData);1 x( J- e9 l! `( r. h
- }/ s* |: W! i5 m# w& ~" [
复制代码
7 p. X0 M/ _' Q O/ z; l W# w
1 f4 T1 ^2 p% v& n& }
) x1 j* _$ y9 O7 m
1 |! o# f5 g0 B7 R6 F+ f6 u) V然后在main中调用 5 a+ w8 O# k) n( T# x h4 Y5 ?
5 E; C3 W5 O& D: x* f0 D& o
8 G) _$ y+ I X- C5 }6 f2 l; N8 ~" x
编译下载,日志如下 3 W! T: H8 j9 c/ ]+ p
0 z9 e& ]# o- `2 k0 I [7 z
/ O6 V4 L) ]9 |2 Q* F两个随机数已经生成,不重复。并且获取上一次得到的随机数也成功
3 w7 ^3 {# m, `% w5 f: i! l. U- ^1 s1 j0 D7 o1 _* J: v
三、通过中断得到随机数
' y5 N. q G0 C/ T& X2 c* G如果不想阻塞式获取随机数,那我们可以选择使用异步的通过中断获取随机数
7 U" A+ X I* K8 P7 K+ \' `' ]/ l首先需要修改一下CUBE,设置RNG的NVIC * W5 U! X N, u. o
4 b, X. [: g6 R0 N* z
7 P1 b+ L4 u9 |+ V% C
然后点击右上角的生成代码按钮(图片略)
$ M p% O7 ?: t刚才我们说了通过中断得到随机数为HAL_RNG_GenerateRandomNumber_IT。和之前的BSP的按键一样,中断相关的函数CUBE都帮我配置好了,用户层只要关注回调函数的实现即可。现在我们来看看成功生成随机数的回调函数、生成随机数失败的回调函数 , `! K* `# g& p5 m8 f. s
6 i2 J8 |/ e( J& J这两个函数在init时就注册好了
& \' m* \, r: H* |% J5 B3 x0 H/ h
& i/ X% c8 r0 I
/ f8 T: ]8 n0 j( x这两个函数是HAL库中定义好的两个虚函数,回头我们就要来实现这两个函数。现在看看定义的虚函数
0 T2 F I7 c2 e7 t! z2 Q# W
0 d& A" U1 o% f/ o' U
+ ~$ o0 Z& A- K5 R3 g接下来看看这两个函数是如何被调用的,首先来到stm32u0xx_it.c,看看RNG和CRYP的中断函数(他俩公用一个中断源) 1 `# b* i V" K6 s0 l0 g
% K1 }4 @: o2 ` E2 j) y
! p% ?$ n4 v: b8 C; `$ T0 G5 w在HAL_RNG_IRQHandler中判断各种寄存器和清除对应寄存器的值等,然后还会调用ReadyDataCallback或者ErrorCallback。 0 s$ w- g' t4 L& ?2 x$ }
" Q1 j O4 @% o8 Y. I# `
U( a9 _ m, F p
( j$ r4 y6 M; k1 v简单的了解完后,我们开始写代码 * @# Q- Y) t0 X( |0 H
) w" c9 m# V6 u
先把按键测试给打开,这样当按键按下后,我们调用一次HAL_RNG_GenerateRandomNumber_IT
! n( K8 q5 C* R- i7 o1 v, V
# ^! t/ W5 Q$ F6 Y6 k& A" Y) s
d! R+ g0 k1 V2 E7 F$ y
while1中的按键测试函数中注释掉LED的翻转,添加HAL_RNG_GenerateRandomNumber_IT和打印 9 j% M' @ O! Q( B3 j) g+ c
- #if BUTTON_TEST
: K7 q8 |( k7 E - /* BUTTON BSP测试 */
# q |' H7 g" |, \& _$ y - if (UserButtonState == BUTTON_PRESSED)
& R4 {7 n7 r; |1 S# g- K - {
! I+ J$ x' m D% k* W - UserButtonState = BUTTON_RELEASED;
9 M8 I6 j: Y" J - // BSP_LED_Toggle(LED_GREEN);) i1 _ ^1 ?5 ^$ ^
- printf("start GenerateRandomNumber_IT\r\n");
/ Q3 y$ `' k' d: ?0 x - HAL_RNG_GenerateRandomNumber_IT(&hrng);
& V" ^# q0 R9 Y - }
/ g/ m9 V" H! k; w - #endif
复制代码 - E7 _ |8 u% H( T' e$ y% V
接下来实现一下之前说的两个虚函数
9 T' v; s2 }- \& q, u4 j- void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)
( k1 }& d. f& U8 O - {! b0 c9 {4 U! A. d# ~- t
- randomData = random32bit;- H- O( z9 i+ R6 O' g
- printf("Generate RNG IT = %04X\r\n", randomData);3 \% z, I4 N% S4 j: _, \
- }- b4 D; t" Y8 ^3 m9 o& [
, I7 W! H1 C. x) J1 d4 F- void HAL_RNG_ErrorCallback(RNG_HandleTypeDef *hrng)1 b8 s+ {0 t8 G* G, n% F
- {8 ?1 {2 m% r* y; o
- printf("Generate RNG IT ERROR\r\n");7 p# @0 L8 p5 A9 m- o8 \
- Error_Handler();+ P' b9 x* n2 z6 P
- }/ Q7 S) m- ~6 `+ U* ?7 m2 H# A
复制代码 + M' w- K, ?4 T1 B. {
! ]5 Z! ^$ n3 u- U2 `
编译下载,日志如下
M, ~, u- S8 D: Q
" s9 d* ?' L: W! m % d8 R6 H# a4 x0 l% ?9 ^
' }& T- ]# {' E
* p7 y1 L5 A5 j) s今日关于RNG的测试都顺利完成,ST的HAL库还是做得不错的,让用户就关注业务相关的函数,不需要去具体了解每个芯片的各个寄存器,对于开发很友好 ; u, l5 j0 ?; q9 N
) G: V3 E, J' ]
|
大佬分析测试的很不错👍,看来我得写点别的了😄