工作笔记-----STM32随机数发生器RNG的配置问题

@@ Author:明月清了个风

@@ Date: 2025/9/18

@@ PS:在配置使用随机数发生器RNG的过程中出现了问题,排查了一圈最后发现是串口部分的错误😆, 在此记录排查问题的过程,以供参考,文章内容分为以下三个部分

  1. 使用stm32cubemx配置RNG过程
  2. 出现的问题及排查过程
  3. 问题发生原因及分析

使用stm32cubemx配置RNG

根据stm32参考手册可知,RNG的时钟源有两个,分别为PLLQ和PLLSAIP

在这里插入图片描述

在这里插入图片描述

在cubemx中将上图红框中TO RNG设为48M即可(一般直接设置HCLK时钟值,然后cubemx会自己帮你设置好这里的),然后在Pinout & Configuration界面选择激活RNG即可,我这里没有使能中断

在这里插入图片描述

然后就配置好了,Parameter Settings那一栏没有参数需要设置。

出现的问题

由于我是在项目中临时加入了这个部分,因此已经有非常多的代码了,根据上面的步骤配置完后使用函数读取产生的随机数,如下:

random = HAL_RNG_GetRandomNumber(&hrng);

返回值一直为0,也就是生成随机数错误。

因此去查看RNG的状态寄存器,也就是RNG_SR,在初始化完后查看该寄存器的值,过程如下

在这里插入图片描述

即可看到初始化后RNG相关寄存器的值,其中状态寄存器SR显示CEIS错误,没有正确设置RNG时钟

在这里插入图片描述

如果根据第一部分cubemx的设置过程,在main.cSystemClock_Config()函数中会有这部分时钟初始化代码,这里就是设置了上面第一张图中的48MHz时钟为PLLQ时钟

PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_CLK48;
PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLL;  
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
    Error_Handler();
}

这里一共有两个选项可以设置,如下,第一个就是PLLQ,第二个就是PLLSAI

/** @defgroup RCCEx_CLK48_Clock_Source RCCEx CLK48 Clock Source
  * @{
  */
#define RCC_CLK48SOURCE_PLL         ((uint32_t)0x00000000U)
#define RCC_CLK48SOURCE_PLLSAIP     RCC_DCKCFGR2_CK48MSEL

很明显,cubemx生成的代码中设置的RNG时钟源为PLLQ,但是RNG_SR显示时钟错误,因此考虑PLL时钟配置错误,进一步去检查下面几个寄存器:

首先是RCC_CR寄存器中的PLLON位,含义如下

在这里插入图片描述

RCC_CR寄存器的PLLSAION寄存器,含义如下:

在这里插入图片描述

根据仿真可以看到,已经成功初始化了PLL时钟,也就是上面设置的PLLQ时钟没有问题

在这里插入图片描述

既然PLLQ时钟成功使能,RNG外设也使能了,RNG却没有时钟输入,考虑是否是时钟源选择错误,查看了手册发现没有选择RNG时钟输入这个选项,但是对于上面的48MHz时钟有一个统一的设置寄存器,就是RCC_DCKCFGR寄存器的CK48MSEL位,描述如下:

在这里插入图片描述

仿真查看该位的值可以发现,果然是这样出的问题

在这里插入图片描述

上面配置的时钟源是PLLQ,但是这里选择的却是PLLSAI,因此没有时钟输入,如果你的RNG配置有问题,就看上面这些寄存器应该可以排除问题了。

在我检查了所有与RNG初始化相关的代码后仍然没有发现是在哪里设置了这个位,因此考虑是否是别的地方改变了该位选择。我的初始化代码架构如下

SystemClock_Config();
xxx_init;
usart_init;
xxx_init;
rng_init;

通过仿真后发现,在SystemClock_Config()函数执行后,该位仍然正确,在串口初始化完后,这一位就错了,因此定位到问题是在串口的初始化中。

问题发生原因和解决方法

最后发现是串口3的初始化中错误的将串口3的时钟选择,写成了串口1的,如下

RCC_PeriphClkInit.Usart1ClockSelection = RCC_USART3CLKSOURCE_SYSCLK;

应该是

RCC_PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_SYSCLK;

那么RCC_PeriphClkInit.Usart3ClockSelection就会是默认值0,在后续的HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);执行过程中会执行__HAL_RCC_USART3_CONFIG(PeriphClkInit->Usart3ClockSelection);

也就是

#define __HAL_RCC_USART3_CONFIG(__USART3_CLKSOURCE__) \
          MODIFY_REG(RCC->DCKCFGR2, RCC_DCKCFGR2_USART3SEL, (uint32_t)(__USART3_CLKSOURCE__))

此时传入的参数PeriphClkInit->Usart3ClockSelection由于没有初始化,因此为一个随机值,如图

在这里插入图片描述

传入后通过上面的宏,也就是下面这个

#define READ_REG(REG)         ((REG))
#define WRITE_REG(REG, VAL)   ((REG) = (VAL))
#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

替换后就是执行下面的代码

MODIFY_REG(RCC->DCKCFGR2, RCC_DCKCFGR2_USART3SEL, 0x08026BF8)
    WRITE_REG((RCC->DCKCFGR2), (((RCC->DCKCFGR2) & (~(RCC_DCKCFGR2_USART3SEL))) | (0x08026BF8)))

正好会将上面的RCC_DCKCFGR的第27位设为1,

之所以是一个随机值是因为在初始化时没有赋初值,如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;  /* 这里没有给初值 */

但是这里的随机值起始也是确定的,因为当一个函数内部变量没有被赋值时,他的值就是他被分配到的内存地址上上一次遗留的值,由于这是初始化代码,并没有执行到任务函数中,因此每次执行到这的时候该地址上的值都是一样的,所以这个值不会变,当然如果你改变了这句代码前的任何一个地方,都有可能让他变成一个新的值

也就是说,如果我赋初值了反而可能不会发现这里的错误😂

查了一下说SRAM可能会在或短时间掉电后仍然保持原来的状态,因此进一步地,又尝试了长时间断电后发现这个值仍然没有变化。不太清楚除了改变代码/优化等级/编译方式会影响到这个随机值之外还有什么情况,好在问题原因也找到了。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐