你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeIDE的CubeMX配置及HAL库实现经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 13:44
一、STM32的随机数发生器
5 J( M2 T: h) k0 H, S# F$ _        1.1 RGN 简介
1 T5 p$ h1 b* A6 p8 \- _- R
        STM32的RGN(Random Number Generator,随机数发生器),是一个以连续模拟噪声为基础的随机数发生器,在主机读数时提供一个由模拟量发生器产生的 32 位随机数。
9 L; s  V% m2 P$ ]% Z
! K& `1 O+ E1 m
        RGN由实时熵源(模拟)和内部调节组件组成,它将全熵输出作为32位样本提供给应用程序。通常MCU中去读取两个连续随机数的间隔为 40 个 PLL48CLK时钟信号周期。产生随机数的模拟量发生器,由几个环形振荡器组成,振荡器的输出进行异或运算以产生馈入线性反馈移位寄存器(RNG_LFSR)种子,这些种子用于生成 32 位随机数。RGN支持中断功能,通过检测状态位(RNG_SR 寄存器),检测种子异常(RNG_FLAG_SECS)、时钟异常(RNG_SR_CECS)等现象,检测到错误时生成中断。
' l7 l1 d2 h( G& ^
1 o$ h+ H" x2 e. u; c
        1.2 RNG配置说明
" J; w- K& ?2 U+ J        在CubeMX上开启RNG功能非常简单,只需要激活即可,在其参数栏设置无任何参数需要设置,在NVIC栏可以开启中断功能。
; m1 U7 i; k& s, q# Z* C
1 e$ O" n7 q" O+ l3 p* h
6c5500271ea54551b6dfb2258f57b6b1.png
  _; C" z4 n) {! z

, L: c5 J5 G9 w. g/ q1 ^! h         RNG依赖时钟源可有在时钟树选择器设置,时钟频率大小可以通过倍频器、分频器设置,例如本文采用STM32L496VGTx芯片时,设置其PLL48CLK时钟依赖源PLLSAl1Q,输出时钟频率是48MHz,如下图所示。
6 i! P6 X2 P  x' J, T
$ M; h( i: x5 x5 k
bfd00a447e8b40a2ada3feff5a9db078.png
. T" J1 q( E" w/ \8 V/ h/ Z# o. @6 \) q7 B, U( ?5 Z
         STM32的RGN内部通信通常是通过AHB总线实现,例如STM32L496VGTx芯片通过AHB2总线。  I; V* @3 F2 n

' |4 Z5 T  U- ?! G2 n& P+ K' N
d07264915c5c436ab6a33677e4c23e7e.png
" M3 N; ]# p0 w1 p2 P! \' K4 D$ W) ~; F3 n7 \$ Y& F7 ~, s0 ^
         RNG在STM32芯片正常、睡眠的工模式下有效。
0 h6 b5 O5 `8 S+ H0 R
$ n6 q5 [/ m% R8 x
774abc141f7e400684de60aa97a0b5e4.png
" o# _7 W1 h: e
& |- Z2 v# A) j* `: b& {         在STM32L496VGTx芯片中,RNG的寄存器空间大小为0X3FF(1024),用于存储RNG的数据寄存器、状态寄存器、控制寄存器以及缓存参数、组件信息等。
3 C. v. s1 k# i2 @/ I; ~7 O& ~, j; W. |
529c47a4c0b04f7ea77a8740cc6293c4.png
" _' P0 D$ \2 ]9 x( F6 Q' r: T7 e) h, d
二、创建RNG测试工程及HLA源码分析8 j5 }- [% w) `1 k8 c+ s
         2.1 工程创建
1 @' I+ {; B( o0 L
        本文为采用的是stm32L496VGTx-ali开发板来建立测试工程,并按本专栏前面的博文移植好了lpuart1串口调试及按键功能,请自行参考。1 k8 X, q. u8 b8 F4 F
: h& N+ ~4 i* k6 B& i+ r% F! o
现双击.ioc文件,打开CubeMX配置界面,开启RNG功能,并开启中断,时钟树上设置最终输出频率48MHz。
4 d5 J' u6 C) l0 i
7 T+ ~2 o* b+ w- b! \: }) R/ Y* {
6afc948c88ba476ead37ed7ea9ab24b0.png
  Z- C- Q2 ?* ~0 d# ]5 X8 Q
2 _; D) ~( y, i# M( u
6e455e8c7f2641bab92415594e07705c.png
8 Z# h- z# h9 S$ l7 U& d. c( I0 [1 L: D, b9 w+ b. c, B
         保成生成输出代码  `, u; g# s7 p, H0 l! u
3 M3 S: u9 r8 r3 L" E4 R6 t/ ?; ?
        2.3 RNG的HLA库源码分析
8 s0 S1 y' w# U9 a$ L; h2 j. B        cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成rng.h和rng.c驱动文件。
( R, z; t! w- B1 k' [; g
# v5 L, l3 s1 _) u        在rng.c文件中,主要定义了MX_RNG_Init函数和HAL_RNG_MspInit函数。MX_RNG_Init主要做两件事情,一是生成RNG句柄Instance(寄存器),二是调用HLA库的HAL_RNG_Init来实现真正的初始化设定。HAL_RNG_MspInit是HLA内的弱函数,根据实际配置CubeMX会生成新的函数,完成真正的MCU底层设置任务(MspInit,MCU Specific Package init,即指和MCU相关的初始化),覆盖原来的弱函数,而在HAL_RNG_Init函数中会调用到HAL_RNG_MspInit函数。5 f: u- H4 V: B3 g- V! {
/ }- D) \3 @9 S& V
c1aa904de5fb4cc0bdbc3d0ae144e8c5.png 1 v9 t+ A4 I& S* ^( b
4 h7 w( t6 w. Y5 j0 a
         在stm32l4xx_hal_rng.c源文件中定义了HAL_RNG_Init函数,它做以下事情:诊断配置参数是否合规;/ n: P8 {8 X% ~0 q

* K/ u. I! F5 q# ~
a14b55c38d564dfd8549ce2e8261ccab.png
5 }( P) d0 m- E' G: U
) P; l, D+ R# Q. f, ~         以及调用HAL_RNG_MspInit函数完成CRC时钟开启及中断设置与开启(如果cubeMX配置开启中断功能的话);
  H( z8 y1 D" I% f* q$ S% N; O1 Q- y% H" ]
86a0aa84e2cb442e92ff09e879d6e13a.png
, `& D/ u) E, f7 C; f# t- N9 J2 P! X
        最后开启RNG,检测种子、数据寄存器的有效性。. b; A8 n$ W! u8 c

$ L: M- d( w% C; N( q a7f7ea93c5124a0498a4db383d8e579f.png ' d5 `/ t  M* |3 F; k& d

- L! E, f4 u& \
         再回到rng.c内,HAL_RNG_MspInit函数实现了RNG外设时钟设置(如果配置依赖外设的话)与开启,以及中断设置与开启(如果cubeMX配置开启中断功能的话)。; c8 q  ^5 K2 w) b* u5 c- s; N

! m" r3 F2 p1 q- p9 i* i  F
bd11d809b4614cf4b3c50e6427bcc79b.png ! D. g- A, S: [) q) I
. w! n& ]$ w3 }/ ], i+ z! ~: r& C
         在stm32l4xx_hal_rng.c源文件除了定义初始化功外,还定义了RNG的MSP初始化及删除函数,各种方式读取随机数函数,状态读取函数,中断请求及中断回调函数等。较常用的是:读取随机数函数如HAL_RNG_GetRandomNumber、HAL_RNG_GetRandomNumber_IT、HAL_RNG_ReadLastRandomNumber,状态读取函数HAL_RNG_GetState,以及回调函数HAL_RNG_ReadyDataCallback和HAL_RNG_ErrorCallback。
& J3 B" q( _8 D9 a% V
- U# z$ ~  i( l1 O" Q# M- D0 P
ef6be0c76ac74bc58979a372f8488d21.png
$ c0 T6 ]6 c6 j4 Q4 `; ~! l- ]& [4 O( ~, S* Z! K: G) j
         2.3 RNG使用设计
. j8 k/ F' i7 @8 {8 K! @6 n" ~        由于本文开启了RNG中断功能,在rng.c源码中,重新编码HAL_RNG_ReadyDataCallback函数如下:- z7 S! n$ E+ v9 L! V& r
  1. /* USER CODE BEGIN 1 */
    0 [) D% o5 |5 p' ~4 c; j& G/ q
  2. void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)
    ( E3 f: @( r% \
  3. {
    $ A5 L4 ?/ N2 o  {
  4.         printf("RNG_ReadyDataCallback:%lu\r\n",random32bit);+ g: ?# e# w% [
  5. }2 u, O& x9 _. m1 V
  6. /* USER CODE END 1 */
复制代码

. z$ y. s  j; z         在main.c源码文件中,添加各个外设及功能模块的头文件依赖。  E( o4 M: @6 T+ M4 H
  1. /* Private includes ----------------------------------------------------------*/6 ?. s$ p9 v5 S7 ^+ V" p9 r" N# H
  2. /* USER CODE BEGIN Includes */
    7 e; K$ Q1 p0 `9 H) C
  3. #include "../../ICore/key/key.h"0 I$ O) Y; I; y' C
  4. #include "../../ICore/led/led.h"4 Y" ]# S& V( R$ w* x: d/ Q
  5. #include "../../ICore/print/print.h"! Q% {2 Z* K7 w; c# m1 X
  6. #include "../../ICore/usart/usart.h"
    : Y: _& v/ c( h4 V8 M. w
  7. #include "../../ICore/delay/delay.h"# m% s! x' i; r; Q  o
  8. /* USER CODE END Includes */
复制代码

3 W% i! L: X; m& _$ T, s         在main.c源码文件中,添加RNG句柄声明,用于读取随机数时使用。
  F7 y1 y& l( V' y8 m
  1. /* Private user code ---------------------------------------------------------*/0 N+ ]% i; o! O# }/ O* X
  2. /* USER CODE BEGIN 0 */
      u- h4 q' I1 T. k
  3. extern RNG_HandleTypeDef hrng;4 }7 N0 _! \, E9 `. J; u) G  G
  4. /* USER CODE END 0 */
复制代码
9 T2 V% R# S7 L) C3 a; D! h; N1 w
         在main函数内,启动串口中断功能及初始化其他辅助参数。  n; }5 d' q( ~% R
  1.   /* Initialize all configured peripherals */
    $ O8 t8 F- ~: u# E7 |% T
  2.   MX_GPIO_Init();9 e6 e# B9 o1 v# g. p, P5 d; c$ K
  3.   MX_LPUART1_UART_Init();& v- B, ~$ m( v) Z, I
  4.   MX_RNG_Init();
    / B  C( {' T6 ~4 \( ?; V
  5.   /* USER CODE BEGIN 2 */" C& P6 X6 O; c- K* w
  6.   ResetPrintInit(&hlpuart1);4 V  T" e* j& C
  7.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断: N  o# z; c; \# w
  8.   HLPUSART_RX_STA = 0;; k6 g! q* k! N/ e
  9.   //
    + V: x, _# H9 k4 B1 A& I# x/ E. p
  10.   printf("app restart now!\r\n");
    : R. j5 L  [7 x6 S. x
  11.   uint32_t rng_val = 0;- u: B: r) B) o; Q. K! J9 y
  12.   /* USER CODE END 2 */
复制代码

8 {' b& L& }/ C1 i, N        在main函数循环体内,通过按键触发调用不同的随机数获取函数,并打印输出到lpuart1上。
! A6 H' I3 \1 D- T1 }) R
  1.   /* Infinite loop */
    5 u" K% P1 ~. A5 k2 X' @
  2.   /* USER CODE BEGIN WHILE */* V: z2 ]- j& k* g: J6 X0 _+ w
  3.   while (1)- @5 t: }" Y, l. w$ x
  4.   {% a3 g9 ], r% C' Q( @( l* {$ ^6 [9 x1 F
  5.             if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始; m7 N/ @% ]* ~
  6.                     //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);6 A# f5 q+ t' u6 w' [: c5 X- V
  7.                     HLPUSART_RX_STA=0;//接收错误,重新开始
    + E; o; F; @- d& A
  8.                     HAL_Delay(100);//等待
    5 r7 K2 T4 {$ Q  x5 R/ v8 G1 J* p' M
  9.             }
    ) p. ?$ m" r; u7 P, N
  10.           if(KEY_0())$ C4 K% b4 G6 B4 N9 j, n8 F
  11.           {4 S; m9 z6 w5 B0 h
  12.                   rng_val = HAL_RNG_GetRandomNumber(&hrng);
    , r2 [' v4 \! q: _& O4 I& R
  13.                   printf("KEY_0->RNG_GetRandomNumber:%lu\r\n",rng_val);- U0 V+ T: |( W; [: U" l
  14.           }
    6 c! M6 |3 @0 j: B2 |( L+ V
  15.           if(KEY_1())& U( c4 b- B3 o3 R3 J/ }6 E
  16.             {
    1 Z! t# o# p! A0 F; x
  17.                   rng_val = HAL_RNG_GetRandomNumber_IT(&hrng);
    $ i# Z1 ]6 e: Q; H2 p. n0 ^
  18.                   printf("KEY_1->RNG_GetRandomNumber_IT:%lu\r\n",rng_val);" I# M, G1 i2 H& V6 h
  19.             }
    ) t% }) M& k5 t2 D4 G
  20.           if(KEY_2())/ ?7 w  w+ h. Q7 c2 c
  21.             {
      u# o' ~! Z& G- k* f( y7 `
  22.                   rng_val = HAL_RNG_ReadLastRandomNumber(&hrng);, f4 Y- |' u! q4 C
  23.                   printf("KEY_2->RNG_ReadLastRandomNumber:%lu\r\n",rng_val);8 @/ t! q3 e7 x, a: c2 V
  24.             }( Z7 H. v, e8 e& v) v
  25.     /* USER CODE END WHILE */
复制代码
8 e3 q' E2 k. K- I" ?2 ?
三、编译及测试) _+ X4 s9 k7 B
        3.1 编译及下载
! ~5 }( ?' t  }2 t
        点击编译按钮确保编译正确输出,并配置运行配置后,点击运行完成下载7 V6 O0 v. }% V& O
  N' F) U  n( s' m+ M6 {: G
5259cc9e59ce4d57b99d0423e030f230.png
# f0 w, p  Q0 g1 U/ K" l+ R/ ~! ^
7 W  u6 C- Q/ ^         3.2 测试
4 _" B' G; i6 `, N+ K$ Y% ?        串口助手链接到开发板上,分别按键KEY0、KEY1、KEY2输出log如下图:5 [, m0 D( I  L: ~
" C* y! E, z( b3 N
9d0b9e5066b9489388d7a9d0d44be04c.png # f1 K- B2 j. A4 T1 O# \

. ]$ [0 x+ ]8 Q: W5 k) k  z         由于KEY1是中断方式读取随机数,因此我们前面重写的回调函数也会生效,但需要注意的是HAL_RNG_GetRandomNumber_IT先于HAL_RNG_ReadyDataCallback,读取了数据寄存器,连个函数是分别读取数据寄存器,因此得到的随机数是不一致的,实际项目中按需选择来应用。. [, ^2 S+ t& K5 e
3 ]* b9 X; M9 v1 G) o1 o' p5 I/ ~
952a2c1763a0432fa35a4e1fc750eddc.png % |) H+ [7 j3 l7 W  C, ?  c+ S0 r$ I

3 x8 i8 s3 P. [4 q7 k) p+ ]————————————————2 r/ ~- |8 I9 l
版权声明:py_free-物联智能
' {+ k+ e$ Z3 g( ]3 h如有侵权请联系删除
! n  ?2 v  m9 u5 G& `$ f: C5 X
& |! {5 Z  X0 v& D) N
赞 收藏 评论0 发布时间:2023-4-6 13:44

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版