工作笔记-----stm32随机数发生器RNG配置问题
但是这里的随机值起始也是确定的,因为当一个函数内部变量没有被赋值时,他的值就是他被分配到的内存地址上上一次遗留的值,由于这是初始化代码,并没有执行到任务函数中,因此每次执行到这的时候该地址上的值都是一样的,所以这个值不会变,当然如果你改变了这句代码前的任何一个地方,都有可能让他变成一个新的值。上面配置的时钟源是PLLQ,但是这里选择的却是PLLSAI,因此没有时钟输入,如果你的RNG配置有问题,就
工作笔记-----STM32随机数发生器RNG的配置问题
@@ Author:明月清了个风
@@ Date: 2025/9/18
@@ PS:在配置使用随机数发生器RNG的过程中出现了问题,排查了一圈最后发现是串口部分的错误😆, 在此记录排查问题的过程,以供参考,文章内容分为以下三个部分
- 使用stm32cubemx配置RNG过程
- 出现的问题及排查过程
- 问题发生原因及分析
使用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.c
的SystemClock_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可能会在或短时间掉电后仍然保持原来的状态,因此进一步地,又尝试了长时间断电后发现这个值仍然没有变化。不太清楚除了改变代码/优化等级/编译方式会影响到这个随机值之外还有什么情况,好在问题原因也找到了。
更多推荐
所有评论(0)