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

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

[复制链接]
攻城狮Melo 发布时间:2023-4-6 13:44
一、STM32的随机数发生器
6 T3 \' K; E1 U% q9 @        1.1 RGN 简介

% T( c0 S# H" B; Z        STM32的RGN(Random Number Generator,随机数发生器),是一个以连续模拟噪声为基础的随机数发生器,在主机读数时提供一个由模拟量发生器产生的 32 位随机数。
' c7 t% C5 W7 I
3 @8 \& C) H; V( O; e+ m
        RGN由实时熵源(模拟)和内部调节组件组成,它将全熵输出作为32位样本提供给应用程序。通常MCU中去读取两个连续随机数的间隔为 40 个 PLL48CLK时钟信号周期。产生随机数的模拟量发生器,由几个环形振荡器组成,振荡器的输出进行异或运算以产生馈入线性反馈移位寄存器(RNG_LFSR)种子,这些种子用于生成 32 位随机数。RGN支持中断功能,通过检测状态位(RNG_SR 寄存器),检测种子异常(RNG_FLAG_SECS)、时钟异常(RNG_SR_CECS)等现象,检测到错误时生成中断。% R% Z4 \! x1 ]: Z% {+ c9 i
% s. Z+ H4 q  G' P6 |, Z' G4 J6 x
        1.2 RNG配置说明0 q$ j5 N- z: T- S# K" G
        在CubeMX上开启RNG功能非常简单,只需要激活即可,在其参数栏设置无任何参数需要设置,在NVIC栏可以开启中断功能。
$ }$ j2 d3 b& |& M8 o* ~# Z* l- z; s/ N( K2 y  G; M
6c5500271ea54551b6dfb2258f57b6b1.png
2 q5 o; e* n8 Z. A- L' S
! y: D! I: q. q8 G4 m7 a
         RNG依赖时钟源可有在时钟树选择器设置,时钟频率大小可以通过倍频器、分频器设置,例如本文采用STM32L496VGTx芯片时,设置其PLL48CLK时钟依赖源PLLSAl1Q,输出时钟频率是48MHz,如下图所示。; m  V* [9 V+ f/ O$ N, q# N

! T- M6 U9 i. N, z
bfd00a447e8b40a2ada3feff5a9db078.png
5 U3 T7 r5 _* N- H
* w, T" |9 ?$ G) }' P. ?
         STM32的RGN内部通信通常是通过AHB总线实现,例如STM32L496VGTx芯片通过AHB2总线。5 [2 v$ u- Q% I4 u  f
9 c0 @5 q2 r0 f' C4 o# q. p
d07264915c5c436ab6a33677e4c23e7e.png
  k+ ~1 U4 }' z# s
: L6 {6 K# Y0 t6 Y         RNG在STM32芯片正常、睡眠的工模式下有效。
' a# D/ x5 e/ \6 `3 Q* L* y* D1 H7 m  n1 t7 U' h- E8 g
774abc141f7e400684de60aa97a0b5e4.png / D# H1 n( \$ i! P

0 }- Y. c$ f5 K; h4 t, u: r         在STM32L496VGTx芯片中,RNG的寄存器空间大小为0X3FF(1024),用于存储RNG的数据寄存器、状态寄存器、控制寄存器以及缓存参数、组件信息等。' K' o' M: r. J
  y8 p7 A  x' C' O7 o9 b
529c47a4c0b04f7ea77a8740cc6293c4.png ) J6 B0 X+ `7 w+ s+ Z7 k
/ R/ T; |2 D" M
二、创建RNG测试工程及HLA源码分析
8 |2 k* d2 c% m/ _! f4 |' j% `/ A         2.1 工程创建
& ?, K, _+ D3 |3 s
        本文为采用的是stm32L496VGTx-ali开发板来建立测试工程,并按本专栏前面的博文移植好了lpuart1串口调试及按键功能,请自行参考。
  }8 }8 G9 [; g1 z% z$ {. N; R) E3 N9 {1 N
现双击.ioc文件,打开CubeMX配置界面,开启RNG功能,并开启中断,时钟树上设置最终输出频率48MHz。$ t. Z( ?" z* T# M( M, E
- }: L% i, {+ N: _" h
6afc948c88ba476ead37ed7ea9ab24b0.png - S; W0 @2 s  u) v0 q% L9 S
: U7 S  M1 ]# Q) H3 Y
6e455e8c7f2641bab92415594e07705c.png
: j: J- i& X4 e! E' T$ N
# w; j+ X  Z- p3 f5 _' \& E         保成生成输出代码8 g, M3 A& ?$ k2 E/ v1 o$ W
0 e4 ~, f$ Y, A. a
        2.3 RNG的HLA库源码分析0 k( y  L( {1 b# i! I
        cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成rng.h和rng.c驱动文件。
/ S1 W; D% r# ?- Q+ ?. b5 Q- T0 |4 _+ v% ?4 E5 |: i, W
        在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函数。
' {& M) D" P4 \4 {  A8 N0 L: F
+ g7 Z. ?/ G" j: \, M
c1aa904de5fb4cc0bdbc3d0ae144e8c5.png
) m% d* v3 o7 I! e8 w+ ]$ @: f- u! p
         在stm32l4xx_hal_rng.c源文件中定义了HAL_RNG_Init函数,它做以下事情:诊断配置参数是否合规;
- d6 }  |, {0 l- T- t
: D- f* L" R1 z% @
a14b55c38d564dfd8549ce2e8261ccab.png
' }* J  j6 R- H0 H4 s/ {9 z( r/ h; ~$ J1 w, k
         以及调用HAL_RNG_MspInit函数完成CRC时钟开启及中断设置与开启(如果cubeMX配置开启中断功能的话);
! F8 d& G+ C& R
1 b: n0 g7 T/ v0 e$ e* y: n0 n
86a0aa84e2cb442e92ff09e879d6e13a.png
+ i1 T4 w. b* P; F6 G% u0 ^
1 y5 q& i* X% W' _6 {% [        最后开启RNG,检测种子、数据寄存器的有效性。
/ R% ^& l  X8 o( n0 F1 q8 |

2 C- i6 \* t/ U( [2 R0 w a7f7ea93c5124a0498a4db383d8e579f.png 3 _- S7 J5 l$ g1 p4 K# _! @

5 n! U3 I* O- Q" _' {0 m7 ^1 j
         再回到rng.c内,HAL_RNG_MspInit函数实现了RNG外设时钟设置(如果配置依赖外设的话)与开启,以及中断设置与开启(如果cubeMX配置开启中断功能的话)。
. \5 v7 F! v0 H% F# q  Z- T  P, H5 ~, s& l
bd11d809b4614cf4b3c50e6427bcc79b.png
7 j2 g$ o$ x# B" J. G  X7 P
! m- i% C% k. w: s7 w! y* 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。
2 U- |/ `3 S, j$ g# o
% ?8 ?  |% y' E3 r: h' g; j
ef6be0c76ac74bc58979a372f8488d21.png
6 |  S) @8 G3 j
) `6 A9 Y# z3 ], n; g, B         2.3 RNG使用设计9 A- t. S" e3 Y
        由于本文开启了RNG中断功能,在rng.c源码中,重新编码HAL_RNG_ReadyDataCallback函数如下:& {6 E5 ^3 U( z  n* p
  1. /* USER CODE BEGIN 1 */1 }& V, V  a( J6 I* M+ e; o
  2. void HAL_RNG_ReadyDataCallback(RNG_HandleTypeDef *hrng, uint32_t random32bit)
    : V; d0 O0 b% M. b, \0 ~/ d
  3. {4 [7 `- E$ s+ S
  4.         printf("RNG_ReadyDataCallback:%lu\r\n",random32bit);
    5 h6 a2 ~% O; T* p% s- W
  5. }
    2 n+ a$ }# m7 P) O  G3 u
  6. /* USER CODE END 1 */
复制代码

3 K+ T, N! c2 Q         在main.c源码文件中,添加各个外设及功能模块的头文件依赖。
2 S) \- i9 k* F8 [" B/ N  O
  1. /* Private includes ----------------------------------------------------------*/, P& y+ @3 v: G1 ?, [
  2. /* USER CODE BEGIN Includes */
    # S8 a  i: E( l5 x4 T5 Y: W
  3. #include "../../ICore/key/key.h"/ |, x$ M& J. U! w& `6 u
  4. #include "../../ICore/led/led.h"
    ; u  h* w. R. a- v5 Y& S& Z5 L
  5. #include "../../ICore/print/print.h"% |: N% y/ @& z% h
  6. #include "../../ICore/usart/usart.h"+ C6 f% l) g! X9 h1 N. x
  7. #include "../../ICore/delay/delay.h"8 ^' Y! b6 h2 P: V! }( Y" |
  8. /* USER CODE END Includes */
复制代码
$ \% }' Q; p5 [+ y; c
         在main.c源码文件中,添加RNG句柄声明,用于读取随机数时使用。7 o( ^: ~, ~* `$ f7 A6 _7 @. ~
  1. /* Private user code ---------------------------------------------------------*/" R% Y- L( j2 Z" ]* w
  2. /* USER CODE BEGIN 0 */
    5 }: C  A; m* |  _/ V$ _
  3. extern RNG_HandleTypeDef hrng;
    8 @$ w/ [' W2 a3 l
  4. /* USER CODE END 0 */
复制代码

8 j# m& T0 ?5 S$ Y: J" ~! e         在main函数内,启动串口中断功能及初始化其他辅助参数。1 Z% t# _0 m; g
  1.   /* Initialize all configured peripherals */
    & p8 L( t$ [# `' K6 l/ @0 i
  2.   MX_GPIO_Init();$ I7 k% {7 R; _9 S) R) y
  3.   MX_LPUART1_UART_Init();
    ! H( j6 q6 @. M# }4 U9 A5 K0 K
  4.   MX_RNG_Init();
    / {  J( E9 c' H. b
  5.   /* USER CODE BEGIN 2 */
    + q* f/ E/ J! Q3 x, `
  6.   ResetPrintInit(&hlpuart1);
    ' k3 P' I6 b( v
  7.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
    % ?+ G! y- A4 h
  8.   HLPUSART_RX_STA = 0;
    4 P8 }% N* L1 t1 @/ H1 r6 T1 y* H
  9.   //
    0 C. p  h4 K" ~5 D" p$ u& m' W
  10.   printf("app restart now!\r\n");; ?4 ~8 ~# m; [' I' y3 s* b+ l# c
  11.   uint32_t rng_val = 0;4 U; u0 |) [% j& J! I
  12.   /* USER CODE END 2 */
复制代码
1 Z7 J8 u3 i, C' ?, u" ^5 ]
        在main函数循环体内,通过按键触发调用不同的随机数获取函数,并打印输出到lpuart1上。  H7 O4 O  e  o* G6 ^
  1.   /* Infinite loop */4 [0 ^+ I3 k! N, Q* \
  2.   /* USER CODE BEGIN WHILE */% L1 T( _3 g0 U; l# j# \- H
  3.   while (1)
    + u: F$ O4 i8 ?8 U
  4.   {
    . j8 u0 @1 D9 ]6 d& P, R. E
  5.             if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
    # S6 Q  x& ^, g4 F( o) J; d
  6.                     //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);$ J" X! l, [0 f' V
  7.                     HLPUSART_RX_STA=0;//接收错误,重新开始
    ! r* P+ K- i/ w5 ?, Q( n
  8.                     HAL_Delay(100);//等待- r+ d8 |0 S. h% U2 c/ P
  9.             }5 ]' g! I1 q5 u0 B- R: q0 v" Z; A
  10.           if(KEY_0())7 @" t& f( ~- u; U8 ^/ T  Q
  11.           {
    : s9 M; I" M% z/ F
  12.                   rng_val = HAL_RNG_GetRandomNumber(&hrng);
    # y; ^4 |7 e: i
  13.                   printf("KEY_0->RNG_GetRandomNumber:%lu\r\n",rng_val);
    ! X+ ^2 T* i# F  ~
  14.           }
    5 l4 H1 g* U" y# ?: Z1 _0 H
  15.           if(KEY_1())
    ! K- N4 w8 k, s7 G
  16.             {
    2 J  w, ]8 ]$ i" }% [4 A0 [5 d
  17.                   rng_val = HAL_RNG_GetRandomNumber_IT(&hrng);( P9 R7 B/ a6 x) q& c7 G  g1 g! h
  18.                   printf("KEY_1->RNG_GetRandomNumber_IT:%lu\r\n",rng_val);
    / ^- ~0 i7 ~9 t$ [+ h9 [5 u# w' k
  19.             }+ X+ M7 }+ K& _9 F
  20.           if(KEY_2())
    0 S& |. U+ ~" A' X, D, ^, C0 l8 k
  21.             {
    ! I! N" }6 Z/ y
  22.                   rng_val = HAL_RNG_ReadLastRandomNumber(&hrng);+ N3 h/ t) G* G+ u. @% i
  23.                   printf("KEY_2->RNG_ReadLastRandomNumber:%lu\r\n",rng_val);/ [8 Y) C% R! T+ e: ~
  24.             }
    6 Q5 e0 a  c2 y- `" u% O/ Z$ Y% N3 }
  25.     /* USER CODE END WHILE */
复制代码
$ e, Z' l; P& A6 a' ~- z
三、编译及测试
5 h3 \0 A. M# u6 S% i( Z+ @        3.1 编译及下载
: Y' h. T( U4 @  \1 |! }$ b
        点击编译按钮确保编译正确输出,并配置运行配置后,点击运行完成下载
3 M9 u* r- g) D0 `
5 p$ h! y1 U! f
5259cc9e59ce4d57b99d0423e030f230.png # g4 m" q" `# Z3 ]' n
9 C' i- U- v& P: D
         3.2 测试
+ k, c. L! s* Y6 i        串口助手链接到开发板上,分别按键KEY0、KEY1、KEY2输出log如下图:: {$ `' f9 U' t* L; g
: Q8 v- ^5 V" c
9d0b9e5066b9489388d7a9d0d44be04c.png ! M6 j- z4 _, h* n7 t
5 o' x3 k: q; A# t( ?% U) w
         由于KEY1是中断方式读取随机数,因此我们前面重写的回调函数也会生效,但需要注意的是HAL_RNG_GetRandomNumber_IT先于HAL_RNG_ReadyDataCallback,读取了数据寄存器,连个函数是分别读取数据寄存器,因此得到的随机数是不一致的,实际项目中按需选择来应用。
0 s" o& z/ l2 Y% h  n$ v1 A7 L4 k
2 p2 n3 p8 \+ w; ]4 v/ S
952a2c1763a0432fa35a4e1fc750eddc.png
& ]  l3 j* T( _$ L1 k
3 h5 a# |: m7 |& l& _————————————————
# y9 J% t7 o; c2 R) y+ \版权声明:py_free-物联智能! o+ M  v( ]  n% _* j
如有侵权请联系删除
- m' C' R8 ^: J) k, W6 ~1 T  m
* p) g! h; l( u% a
赞 收藏 评论0 发布时间:2023-4-6 13:44

举报

0个回答

所属标签

相似技术帖

官网相关资源

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