U0具备硬件RNG随机数发生器,相比软件算法得到的随机数,这个硬件RNG是真随机数。在加密时用它生成IV或者随机数,可以使得加密更加的安全。
8 |. p0 T% H* s* \
5 O1 Z e0 U$ W" ^! R/ n一、CUBE配置及函数讲解
* d4 v. |7 H3 I工程我们还是用之前生成的基础模板
9 o. }# l$ f9 L. ]! q( e首先在cube中开启RNG
& Z( z5 x* ^# N& N2 q- Q" W
) h; b1 M0 h3 ~
4 F& t# s! m) P* g然后配置一下时钟,RNG的始终要求必须为48Mhz,我选择使用MSI(我一开始尝试了HSI48。但是初始化通不过,没跑通,那就只有换一个) : S* o$ D; f: ~6 s4 u2 |7 o
t7 i, J% V9 S7 o) ]# H( a6 g' i
9 n3 }. Y* T0 {
然后把MSI的频率改成48000(也就是48M)
; F+ Q: P; P6 S$ G6 B( n" e$ k! R 然后生成代码 , O$ W1 v c! c
' h& ?4 Y% p& a& c8 ?
4 W# [, ^& C D" a7 s/ i接下来开始写代码,库函数我没有在cube中修改,使用的是默认的HAL 首先看一下自动生成的代码 CUBE帮我生成了RNG的初始化函数
6 N5 R7 L5 k' Z x/ }
* }3 b' k6 w. m2 H) F
! N$ O' _6 ^+ D
4 g9 q; j2 d& f8 e# A% @
HAL_RNG_Init我就不进去看了,里面主要是做一些参数配置和RNG时钟enable。如果有想仔细研究的可以自行查看。当然想要研究的跟底层,我推荐更换LL库,回头配合寄存器手册,可以学习到最底层的寄存器' z6 g9 c s3 [
4 G( A4 u; r) F
3 N: `$ a2 Y' A; }/ A
现在简单讲一下HAL库我们会调用的函数
; S t8 q5 r4 f( J! A
& u+ O4 q# D/ w" ^" S- t$ H
% s* H6 q) Z0 Z- l阻塞式获取到随机数的函数:HAL_RNG_GenerateRandomNumber
8 _) y5 L1 M- @; p+ T& ]: I0 Z: X& F' w) E通过中断得到随机数:HAL_RNG_GenerateRandomNumber_IT $ w0 m( C1 j- Z4 a8 Z: j
获取上一次得到过的随机数:HAL_RNG_ReadLastRandomNumber / Z7 @$ Y; u& u1 w
/ k) T9 x# |7 f: a从参数可以看到,我们每次获取的随机数类型是uint32_t
+ N5 @* k- |- i: ~% h r# H4 L# I; j
二、阻塞式获取到随机数及获取上一次得到过的随机数
' v# i" @7 t6 K- T首先设置一个uint32_t类型的全局变量,用于保存得到的随机数 # k5 \. x' m5 c4 \0 t
- uint32_t randomData;+ t3 d" A/ k0 ?" D
复制代码
3 w# B/ {5 J* R- o3 q7 g1 [' H; a+ s" o
( }. P- [* u' k$ I) Y5 t8 d8 ]$ k, H1 f; N) g% d8 ]- d& z4 S o
初始化后就可以直接调用获取随机数函数,我做了一个测试函数,会连续调用2次获取随机数函数,并且生成后再次调用获取上一次得到过的随机数函数,看看他会不会得到两个不同的随机数。 7 o) w. _9 a A% m2 L' m. U
- void GenerateRandomNumber_test()
3 r. v& k4 F: m7 h. j* j, M - {
6 q0 v2 @2 `1 i; B5 h - uint32_t lastRandomData;
6 B3 R- d- ~3 n! t# T: B$ A# y" @ - printf("GenerateRandomNumber test\r\n");
( e# i0 j( g1 E7 B F5 E
1 [& N! v* i' O- G7 {3 Q* x' b- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);4 I6 ~! c0 c; g a* f
- printf("GenerateRandomNumber = %04X\r\n", randomData);0 M3 V: `4 d5 Y/ X# M
- 6 K% U7 g. K: I" e
- lastRandomData = HAL_RNG_ReadLastRandomNumber(&hrng);
' Q3 W- ?$ P0 g' M- K0 A - printf("lastRandomData = %04X\r\n", lastRandomData);
$ [5 {6 Q% x/ b' Q4 a% B" X7 @
3 L% ~. E3 v0 X6 a9 |2 q: o- HAL_RNG_GenerateRandomNumber(&hrng, &randomData);6 J' W1 u7 h/ }+ P
- printf("GenerateRandomNumber = %04X\r\n", randomData);: A V' \) K" z$ v. i
- }3 L; w7 i( }: v. J; U) ^
复制代码 / h. Z6 h" f1 {
) u0 H$ |% S* |9 ^6 V
' y/ V) r; M% ` 8 \* D" t, w- l* c9 R9 C" R
然后在main中调用 & r: A, x9 e; f& T C
$ L# w# t# ^3 }! `2 I
+ N0 X: g- n) K) l/ |9 u! B
编译下载,日志如下
) q# E$ { b( x9 w; W% X B4 L: z9 A
" g5 T3 A. d! D) r \7 @/ q' _, x( a7 O' N
两个随机数已经生成,不重复。并且获取上一次得到的随机数也成功
, @* z( x2 v. m1 S7 z. k: i( V( @: r5 |, z7 m
三、通过中断得到随机数 # b+ U0 N! X% f3 T6 G: N0 Q
如果不想阻塞式获取随机数,那我们可以选择使用异步的通过中断获取随机数
7 A G' p; ]5 e, ?6 l$ d首先需要修改一下CUBE,设置RNG的NVIC
) r' I' ^* r H' C, E. H& Q
6 ? d3 |/ u8 H7 I& r( E
- n- i" s# R. h5 c& b+ \
然后点击右上角的生成代码按钮(图片略)
' S( P& _3 J6 D/ N5 V2 Y; F刚才我们说了通过中断得到随机数为HAL_RNG_GenerateRandomNumber_IT。和之前的BSP的按键一样,中断相关的函数CUBE都帮我配置好了,用户层只要关注回调函数的实现即可。现在我们来看看成功生成随机数的回调函数、生成随机数失败的回调函数 # y& p5 P. ^' ^- X- f9 _
2 B$ z7 S3 b f/ a: N d; n这两个函数在init时就注册好了
; l3 R+ _) [$ j+ Y3 V# y ?% p
8 d' I& E$ r$ ]* h+ o }
0 z A) l- A# N3 r这两个函数是HAL库中定义好的两个虚函数,回头我们就要来实现这两个函数。现在看看定义的虚函数
5 P# C/ w4 W8 A( a
7 Z$ a% {1 k9 t* ^* u8 A. z: k# p) j8 k , y8 ~3 r- r% _
接下来看看这两个函数是如何被调用的,首先来到stm32u0xx_it.c,看看RNG和CRYP的中断函数(他俩公用一个中断源)
: F! `. b8 o% e2 b+ P/ P
4 }- N3 m, g q
3 @% \6 a, o4 ?/ h- g% d在HAL_RNG_IRQHandler中判断各种寄存器和清除对应寄存器的值等,然后还会调用ReadyDataCallback或者ErrorCallback。
* E" Z, `' R. S1 c8 a% @! @! ^
1 D' V, q9 C: R, `* ]5 ~! {! n5 ]- o
' N! |' L$ R6 M: H$ m2 ?: X0 l" K! `' A& c$ e
简单的了解完后,我们开始写代码 ) p* ~5 `5 \: g4 `" c4 z
& B; \6 o3 S5 \9 C0 w8 q. ?
先把按键测试给打开,这样当按键按下后,我们调用一次HAL_RNG_GenerateRandomNumber_IT
# G1 p1 T# m: i4 D+ P( b
0 N% c5 \% J6 J5 L" d7 G# j- F6 ?
" o/ _7 [4 K, A8 b2 j& ?while1中的按键测试函数中注释掉LED的翻转,添加HAL_RNG_GenerateRandomNumber_IT和打印 0 y) Q9 R* ^9 }. B6 E" t
- #if BUTTON_TEST# }( z7 | }( }# h6 K! _( _
- /* BUTTON BSP测试 */
. ~( q& s2 N9 R8 W5 ^$ j1 ] - if (UserButtonState == BUTTON_PRESSED)
* F7 Y' d7 s$ r6 d# i% T - {
. ]3 l* D, W( C! D- P9 A - UserButtonState = BUTTON_RELEASED;
. I* \( S/ q, k/ X - // BSP_LED_Toggle(LED_GREEN);, j* P5 w6 T# ~+ j
- printf("start GenerateRandomNumber_IT\r\n");
4 D' D4 L! m* a+ [: r$ ?" f - HAL_RNG_GenerateRandomNumber_IT(&hrng);/ ]* U3 m' d2 [) j$ U5 Z- Y; Y: Q1 p' j
- }
/ _3 O$ R' j; B* L U* v, I/ q - #endif
复制代码 0 z. E* ^$ ]0 E+ y4 z' x
接下来实现一下之前说的两个虚函数
S6 E. V, g, K( B0 N- void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)" n F2 S" J# a; w0 ]$ @
- {: e: |* K3 G5 k- a5 ?
- randomData = random32bit;/ w4 ]- Z5 c6 K0 N# L4 ^
- printf("Generate RNG IT = %04X\r\n", randomData);: ~/ V! r, x" \5 q& q
- }
- ?2 W$ M g8 d# k7 ]" X1 [0 D - & v, Y0 l3 o" C5 E8 \+ N4 I
- void HAL_RNG_ErrorCallback(RNG_HandleTypeDef *hrng)5 H% {4 F" l8 n. i0 S7 e- f
- {
, i7 D4 i9 X- z3 p - printf("Generate RNG IT ERROR\r\n");! w* C; p' v+ X* Y! o! ^
- Error_Handler();
( y- h4 x2 `( d" i2 `" f* L - } m! ^3 y4 J; w" M9 ` M
复制代码 4 {+ k y7 @) F: l3 q& R0 u
+ \& K# X0 h2 s编译下载,日志如下
' c( a6 Y9 X! j) o7 R( n6 d8 P7 i
F! u0 c4 U) Y9 e( G2 e
2 R# i4 |7 \! E
" d4 _4 j1 a2 @* X% J7 ?
$ v7 _4 C1 m) ^$ l2 ~今日关于RNG的测试都顺利完成,ST的HAL库还是做得不错的,让用户就关注业务相关的函数,不需要去具体了解每个芯片的各个寄存器,对于开发很友好 6 [9 g. Q7 c- |
8 h$ S! g$ l" Q3 q# x
|
大佬分析测试的很不错👍,看来我得写点别的了😄