U0具备硬件RNG随机数发生器,相比软件算法得到的随机数,这个硬件RNG是真随机数。在加密时用它生成IV或者随机数,可以使得加密更加的安全。
: g k3 G1 o2 `7 {4 u. T1 w% h, H$ @' [3 A0 l
一、CUBE配置及函数讲解
0 A- \" P7 Z% x+ a# i' K工程我们还是用之前生成的基础模板& M3 j) V9 P( S9 B) F% Q$ Q
首先在cube中开启RNG
% Q# N5 x) H' `: W1 X
3 n# l+ `! g" I6 k, S W( e" o
( {4 ~ M0 ~8 R2 {5 U9 I; Q$ x然后配置一下时钟,RNG的始终要求必须为48Mhz,我选择使用MSI(我一开始尝试了HSI48。但是初始化通不过,没跑通,那就只有换一个) & y" L. l8 o* H( }" {1 p. J
* s% g# X/ o) I [+ i, q" s
5 s% f; c* P. h6 V然后把MSI的频率改成48000(也就是48M)
+ b! s w8 M7 A5 p7 E 然后生成代码
* P$ }% q5 }$ R: p. z2 G
; Q1 c2 f$ ^7 h4 N* v " P( } R1 @% ?- K7 U9 w' O
接下来开始写代码,库函数我没有在cube中修改,使用的是默认的HAL 首先看一下自动生成的代码 CUBE帮我生成了RNG的初始化函数
. M7 _# k! ~) K7 R. _; Z ; P" V( @7 n) e) s, ], D6 r4 F; T
* O7 f# D0 E8 L
! Z* c& c- z8 t* R' ^9 `- j
HAL_RNG_Init我就不进去看了,里面主要是做一些参数配置和RNG时钟enable。如果有想仔细研究的可以自行查看。当然想要研究的跟底层,我推荐更换LL库,回头配合寄存器手册,可以学习到最底层的寄存器
3 t8 v6 F0 B5 q
' X3 X2 o e+ S# l4 c7 a
+ V( o2 r$ ~" s1 ~现在简单讲一下HAL库我们会调用的函数
9 W* _# t& \+ p* v5 Q
* e1 j. v8 j- ^0 R, h- s, ~: E# w 7 F8 s' J+ ?7 w
阻塞式获取到随机数的函数:HAL_RNG_GenerateRandomNumber
0 }: Q1 g: d9 A" }通过中断得到随机数:HAL_RNG_GenerateRandomNumber_IT
( t! u7 U" v( J1 C# V* P获取上一次得到过的随机数:HAL_RNG_ReadLastRandomNumber
7 r% O y$ ?! A0 ` a, ]8 |
) l& e1 f' ^# q从参数可以看到,我们每次获取的随机数类型是uint32_t
( D+ A2 }! T6 m& F, ~6 @0 w" J8 _5 { K. f- G" m) c/ B$ @; D
二、阻塞式获取到随机数及获取上一次得到过的随机数 9 \4 w/ i* W0 y q" I' i
首先设置一个uint32_t类型的全局变量,用于保存得到的随机数 ; U4 [5 \! W/ E$ {
- uint32_t randomData;0 t7 G4 }% D# b' ~! E# o' i/ \) J
复制代码 * W S; ?3 L. K' z' R& b
+ M4 u, X$ L* m0 k, l7 o, C( H, p: }
$ g% t% L0 a! j) g, |2 O) m初始化后就可以直接调用获取随机数函数,我做了一个测试函数,会连续调用2次获取随机数函数,并且生成后再次调用获取上一次得到过的随机数函数,看看他会不会得到两个不同的随机数。
+ W0 e5 ]4 Q# g. [7 c- void GenerateRandomNumber_test()
* @: ]* W% M0 L# l& K- B* c - {
( D0 Q* U" L# ~- q" ` - uint32_t lastRandomData;
0 C5 U+ u; `4 S4 ?3 c4 M) q& q9 h& G - printf("GenerateRandomNumber test\r\n");3 G* U/ [) R1 V7 B7 Y3 f% w5 {
- " I% r7 N3 ]9 L, _. m6 m, j
- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);
# [8 O! q& U0 D4 E$ U/ P - printf("GenerateRandomNumber = %04X\r\n", randomData);* M ^# r4 o' Z, t" N/ I
- & O% m& X+ f7 U O! G2 l! i7 C& r$ c
- lastRandomData = HAL_RNG_ReadLastRandomNumber(&hrng);$ K2 x" o( N6 W6 D+ B4 J
- printf("lastRandomData = %04X\r\n", lastRandomData);
$ v8 l$ y* D; {
+ c l- K. A! I8 `6 O: G- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);( j# F) w5 S2 |
- printf("GenerateRandomNumber = %04X\r\n", randomData);
; \" |; }% J/ Q: L5 `* M - }9 l( s2 v8 }2 W( q; ?9 l8 k( i; ?
复制代码 , Y& B5 G/ j5 J7 D( {, b1 _: \
8 g1 H6 l3 ^1 `6 B, j5 _0 O
( ]% h8 ]9 l3 Y
f7 y& [- Y2 |/ k0 v
然后在main中调用 4 j! @/ k. P( @* l3 ?0 y i
, N7 W/ ]8 v8 w: x3 d' b2 H' J. c
% R1 n# w# C, h; Q8 c: x5 h& ]2 o
编译下载,日志如下 / Y0 e5 h8 ?1 m/ v0 q
: E8 D2 K% Y7 b5 b
( k& D6 S8 `. M5 M; v. |0 L两个随机数已经生成,不重复。并且获取上一次得到的随机数也成功
- N) n2 ]. }/ f& z. y. B" C
$ w& k2 z+ D6 J8 Z7 l$ i三、通过中断得到随机数
$ f* z% I% N0 ]如果不想阻塞式获取随机数,那我们可以选择使用异步的通过中断获取随机数
- k: r1 T; T0 ]: ?6 n+ H首先需要修改一下CUBE,设置RNG的NVIC 0 K! Y* L+ x, e5 J, |3 t8 X8 j
3 Q2 ^7 a& p% {( E) W U% v0 K# j# j
然后点击右上角的生成代码按钮(图片略) 0 c( V @4 M* ]0 W: E
刚才我们说了通过中断得到随机数为HAL_RNG_GenerateRandomNumber_IT。和之前的BSP的按键一样,中断相关的函数CUBE都帮我配置好了,用户层只要关注回调函数的实现即可。现在我们来看看成功生成随机数的回调函数、生成随机数失败的回调函数
) Q4 @4 j1 {& G7 N/ x" u, V+ k: p+ z. C7 n
这两个函数在init时就注册好了
; Y' `: h% [: e$ ]( m8 {
6 N5 ^9 `! U- e4 `7 U7 A9 _9 H
8 G2 Y. P$ l$ M0 C) e) _. ^4 _2 E
这两个函数是HAL库中定义好的两个虚函数,回头我们就要来实现这两个函数。现在看看定义的虚函数 6 i3 c( m! e5 S" r/ U2 i" }3 G
; I+ Q8 |. U' `5 }
$ g j V- ]- z* p( ]9 n接下来看看这两个函数是如何被调用的,首先来到stm32u0xx_it.c,看看RNG和CRYP的中断函数(他俩公用一个中断源) 3 C8 o6 a* T# |
/ t1 A, U' K. L4 v" r& X
v* O6 l1 g' S. R+ i+ n在HAL_RNG_IRQHandler中判断各种寄存器和清除对应寄存器的值等,然后还会调用ReadyDataCallback或者ErrorCallback。 * ~; c% l# D: f
- D1 |, I0 x3 i1 P; ^1 |3 r & J- X P- I8 {2 X8 O. U5 n
* W L; }0 |9 Q2 b) w; B简单的了解完后,我们开始写代码 s* Z: F) V/ {
. P) `. Q1 u9 i2 x% B/ \3 `先把按键测试给打开,这样当按键按下后,我们调用一次HAL_RNG_GenerateRandomNumber_IT
0 ^( Z8 p) G# y# i* h
: |! Y' y# A- t9 @
) z+ X: N, ^4 v, k9 d6 Z4 [while1中的按键测试函数中注释掉LED的翻转,添加HAL_RNG_GenerateRandomNumber_IT和打印 8 a& i: r* }" r2 {
- #if BUTTON_TEST1 ~. W! _( j8 I2 F+ p. f, ]
- /* BUTTON BSP测试 */$ ]6 R: q9 r0 K: i$ G
- if (UserButtonState == BUTTON_PRESSED)- V9 w% y% f5 @' E, E
- {% k# r/ e2 U! f" R5 t
- UserButtonState = BUTTON_RELEASED;
$ w: w- h2 y" d6 W; ` U' m( P$ ] - // BSP_LED_Toggle(LED_GREEN);1 M: J& @9 Q, g, `4 t
- printf("start GenerateRandomNumber_IT\r\n");
4 q6 C, F' ~9 X2 N5 c* m7 G - HAL_RNG_GenerateRandomNumber_IT(&hrng);
6 ^, \+ Y b7 [' z0 o$ }4 X0 A6 Q - }
' \5 v( j! D6 v( m) v9 l - #endif
复制代码
0 T0 V5 b' N' I& b8 Z接下来实现一下之前说的两个虚函数 - Q9 _$ t& M! C o% h2 M7 J {
- void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)
E- f) z" D( ~) {6 ^: Z( B - {. E. ]. t9 w! n% W2 F
- randomData = random32bit;
, L1 f3 O0 V. v p1 a - printf("Generate RNG IT = %04X\r\n", randomData);
/ `, X: l# [; ?+ K - }/ ]( A0 k4 c$ L6 |4 Y1 {
- , a8 Y) e; `! `! h" F
- void HAL_RNG_ErrorCallback(RNG_HandleTypeDef *hrng)& c) \2 E) n d3 f# B3 i ]& x
- {
2 i' k! `; v9 M6 p% W- a$ I4 C+ Y - printf("Generate RNG IT ERROR\r\n");
, a9 Z' d9 {& x - Error_Handler();! |" c6 W! c4 C4 B
- }
$ ~$ A. \3 g* ]2 }* Q% T$ W
复制代码 4 ]; b9 D# c8 W
# |9 }9 P' h# q2 m编译下载,日志如下 1 Y R. t( m+ p: U
6 B, t6 T/ \1 O! Z
* `* ]/ i% m3 Y- y8 m# e9 i
* O5 R9 e. i0 v8 S0 F) x& R! L; K) I; d# v. h; w/ C
今日关于RNG的测试都顺利完成,ST的HAL库还是做得不错的,让用户就关注业务相关的函数,不需要去具体了解每个芯片的各个寄存器,对于开发很友好
% {! u5 P; g1 B( A3 m4 E' l
/ A2 R) P5 S% U% ^$ ]6 {& c) w1 A |
大佬分析测试的很不错👍,看来我得写点别的了😄