STM32F4_随机数发生器(RNG)

目录

1. 随机数发生器RNG是什么

2. RNG随机发生器框图

3. 运行RNG

4. RNG寄存器

4.1 RNG控制寄存器:RNG_CR

4.2 RNG状态寄存器:RNG_SR

4.3 RNG数据寄存器:RNG_DR

5. 库函数配置随机数发生器

6. 实验程序

6.1 main.c

6.2 RNG.c

6.3 RNG.h


1. 随机数发生器RNG是什么

        RNG全称Random number generator;RNG处理器是一个以连续模拟噪音为基础的随机数发生器,在主机读数时提供一个32位的随机数。

        RNG的主要特性有:提供由模拟量发生器产生的32位随机数,两个连续随机数的间隔为40个PLL48CLK时钟信号周期

                                         通过监视RNG熵来标识异常行为(产生稳定值,或产生稳定的值序列)

                                         可被禁止以降低功效

2. RNG随机发生器框图

        首先模拟种子源源不断的生成随机数据给馈送线性反馈移位寄存器LFSR,当LFSR存储满之后,会一并给数据寄存器RNG_DR;在模拟种子生成随机数据的过程中,会有时钟检查器和故障检测器时刻检测产生的随机数是否正确,并通过状态寄存器RNG_SR相关位显示,随机数发生器通过RNG_CLK时钟支持; 

RNG随机数发生器采用模拟电路实现。此电路产生馈入线性反馈移位寄存器(RNG_LFSR)的种子,用于生成32位随机数。

该模拟电路由几个环形振荡器组成,振荡器的输出进行异或运算以产生种子。RNG_LFSR由专用时钟(PLL48CLK)按恒定频率提供时钟信息,因此随机数的质量和HCLK频率无关。当将大量种子引入RNG_LFSR后,RNG_LFSR的内容会传给数据寄存器(RNG_DR)。

系统会监视模拟种子和专用时钟PLL48CLK。状态位(RNG_SR寄存器中)指示何时在种子上出现异常序列,或指示何时PLL48LCK时钟频率过低。检测到错误时生成中断。

3. 运行RNG

想要运行随机数发生器RNG,需要

1. 如果需要随机数发生器RNG,进行中断(将RNG_CR控制寄存器的IE位置1)。准备好随机数时或者出现错误时生成中断。

2. 通过将RNG_CR控制寄存器中的RNGEN位置1使能随机数产生。这会激活模拟部分、RNG_LFSR和错误检测器。

3. 每次中断时,检查确认未出现错误(RNG_SR寄存器中的SEIS和CEIS位应为0),并且随机数已准备就绪(RNG_SR寄存器中的DRDY位为1)。然后即可读取RNG_DR寄存器中的内容。

这里检查未出现错误时,RNG_SR寄存器的SEIS和CEIS位为0;如果SEIS和CEIS其中之一为1,则表示随机数发生器出现错误;

①:如果CEIS位的值为1,则表示时钟出现了错误

出现时钟错误时,RNG无法再产生随机数,这时的PLL48CLK时钟已经不正确了。检查时钟控制器是否正常配置,是否可提供RNG时钟,然后将CEIS位清零。当CECS位为0时,RNG可以正常工作。时钟错误对产生的上一个随机数没有影响,因此RNG_DR数据寄存器的内容可以使用。

②:如果SEIS位的值为1,则表示种子出现了错误

出现种子错误时,只要SECS位为1,就会中断随机数产生。如果RNG_DR寄存器中有可用随机数,不能使用该随机数,因为它可能没有足够的熵。

总结:出现错误时,应将SEIS位清零,然后将RNGEN位清零并置1,以便重新初始化和重新启动RNG。

按照FIPS PUB(联邦信息处理标准出版物)140-2的要求,将RNGEN位置1后产生的第一个随机数不应使用,应保存起来,与产生的下一个随机数进行比较。随后产生的每一个随机数都需要与产生的上一个随机数进行比较。如果任何一对进行比较的随机数数字相等,则表示连续随机数发生器测试失败。

4. RNG寄存器

4.1 RNG控制寄存器:RNG_CR

RNG控制寄存器:RNG_CR(RNG control register)

位31:4  保留,必须保持复位值

位3   IE:中断使能(Interrupt enable)

                0:禁止RNG中断

                1:使能RNG中断。只要RNG_SR寄存器中DRDY=1或SEIS=1或CEIS=1,就会挂起中断。

位2   RNGEN:随机数发生器使能(Random number generator enable)

                0:禁止随机数发生器

                1:使能随机数发生器

位1:0   保留,必须保持复位值

4.2 RNG状态寄存器:RNG_SR

RNG状态寄存器:RNG_SR(RNG status register)

位31:3   保留,必须保持复位值

位6   SEIS:种子错误中断状态(Seed error interrupt status)

                0:未检测到错误序列

                1:检测到以下错误序列之一:

                        超过64个连续位具有相同值

                        超过32个连续交替的0和1        

                如果RNG_CR寄存器中IE=1,则会挂起中断

位5   CEIS:时钟错误中断状态(Clock error interrupt status)

        此位与CECS同时设置,通过向其写入0来清零。

                0:正确检测到PLL48CLK时钟

                1:未正确检测到PLL48LCK时钟

        如果RNG_CR寄存器中IE=1,则会挂起中断。

位 2  SECS:种子错误当前状态 (Seed error current status)

                0:目前未检测到错误序列。如果 SEIS 位置 1,则意味着已检测到错误序列并已恢复正常。

                1:检测到以下错误序列之一:

                        —超过 64 个连续位具有相同值(0 或 1)

                        —超过 32 个连续交替的 0 和 1 (0101010101...01)

位 1  CECS:时钟错误当前状态 (Clock error current status)

                0:正确检测到 PLL48CLK 时钟。如果 CEIS 位置 1,则意味着已检测到时钟错误并已恢复正常。

                1:未正确检测到 PLL48CLK 时钟

位 0  DRDY:数据就绪 (Data ready)

                0:RNG_DR 寄存器尚未有效,无可用随机数据

                1:RNG_DR 寄存器包含有效随机数据   注意:如果 RNG_CR 寄存器中 IE = 1,则会挂起中断。读取 RNG_DR 寄存器后,此位恢复到 0,直到计算出新的有效值。

4.3 RNG数据寄存器:RNG_DR

RNG数据寄存器:RNG_DR(RNG data register)

RNG_DR寄存器是只读寄存器,在读取时提供32位随机数值。读取后,此寄存器在最多40个PLL48CLK时钟周期后,提供新的随机数值。在读取RNDATA值之前,软件必须检查DRDY位是否已经置1。

5. 库函数配置随机数发生器

1. 使能随机数发生器时钟

随机数发生器时钟来自于PLL48LCK,通过AHB2ENR寄存器使能。

RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);      //开启RNG时钟 

2. 使能随机发生器

使能随机发生器需要设置RNG_CR控制寄存器的最低位为1,使能随机数发生器。(这里注意:如果需要设置中断服务函数,那么还需要使能RNG中断)

RNG_Cmd(ENABLE);      //使能RNG随机数发生器

3. 判断DRDY位,读取随机数值

DRDY位是状态寄存器的最低位,是显示数据是否就绪的状态位;当该位为0时,表示数据寄存器尚未有效,无可用随机数据。当该位为1时,表示数据寄存器已经包含有效随机的数据。

通过以上的分析,我们明确了在读取随机数值之前,必须先判断状态寄存器的最低位DRDY是否为1,如果该位为1,则可以读取数据寄存器的随机数值;如果该位不为1,则需要等待。

FlagStatus RNG_GetFlagStatus(uint8_t RNG_FLAG);   //获取随机数发生器状态函数

while(RNG_GetFlagStatus(RNG_FLAG_DRDY)==RESET);    //判断入口参数是否有效,若无效,等待就绪

uint32_t RNG_GetRandomNumber(void);    //当判断入口参数有效以后,读取随机数发生器产生随机数

6. 实验程序

STM32F4随机数的实验现象是:通过KEY0获取随机数,并将获取到的随机数显示在LCD上,通过DS0指示程序运行状态。

6.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"
#include "Key.h"
#include "RNG.h"

//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}
int main(void)
{
	u32 random;
	u8 t=0;
	delay_init(168);
	uart_init(115200);
	LED_Init();
	Key_Init();
	LCD_Init();
	POINT_COLOR=RED;
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
	LCD_ShowString(30,70,200,16,16,"RNG Test");
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2023/20/23");
	while(RNG_Init())//因为RNG存在一个等待状态位是否有效的过程,所以只要初始化RNG成功,也就意味着状态位有效,可以执行下述读取随机数的程序
	//因为初始化RNG随机数发生器返回0表示初始化成功,一旦初始化返回值为1,则进入该while循环中,打印错误信息
	{
		LCD_ShowString(30,130,200,16,16,"RNG Error!");
		delay_ms(200);
		LCD_ShowString(30,130,200,16,16,"RNG Trying……");
	}
	LCD_ShowString(30,130,200,16,16,"RNG Ready!  ");
	LCD_ShowString(30,150,200,16,16,"KEY0:Get Random Num");
	LCD_ShowString(30,180,200,16,16,"Random Num:");
	LCD_ShowString(30,210,200,16,16,"Random Num[0-9]:");
	POINT_COLOR=BLUE;
	while(1)
	{
		delay_ms(10);
		if(KEY0==0)
		{
			random=RNG_GetRandomNum();//获取随机数
			LCD_ShowNum(30+8*11,180,random,10,16);//显示随机数
			//30+8*11的意思是x起始坐标为30,LCD屏是按照字节来存放的,1位8个字节,Random Num占11位
		}
		if(t%20==0)//t是200ms的整数倍
		{
			LED0=!LED0;//每200ms,LED0翻转一次
			random=RNG_GetRandomRange(0,9);//获取0-9之间的随机数
			LCD_ShowNum(30+8*16,210,random,1,16);//显示范围内的随机数
		}
		delay_ms(10);
		t++;
	}
}

6.2 RNG.c

#include "stm32f4xx.h"                 
#include "RNG.h"
#include "delay.h"

//RNG初始化
//返回值0成功;返回值1失败
u8 RNG_Init(void)
{
	u16 retry=0;
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG,ENABLE);//使能RNG时钟
	RNG_Cmd(ENABLE);//使能RNG随机数发生器
	
	while(RNG_GetFlagStatus(RNG_FLAG_DRDY)==RESET&&retry<10000)
	//判断入口参数是否有效,因为状态寄存器的最低位DRDY为1时,随机数才会有效
	//所以直到状态位为1时才会离开该语句,该语句判断状态位为0时,会一直在此等待。
	{
		retry++;
		delay_us(100);
	}
	if(retry>=10000)   //随机数发生器工作不正常
		return 1;
	return 0;
}
//获取随机数
//返回值:获取得到的随机数
u32 RNG_GetRandomNum(void)
{
	while(RNG_GetFlagStatus(RNG_FLAG_DRDY)==RESET); //等待随机数就绪
	return RNG_GetRandomNumber();
}
//生成[min,max]范围的随机数
int RNG_GetRandomRange(int min,int max)
{
	return RNG_GetRandomNum()%(max-min+1)+min;
}

6.3 RNG.h

#ifndef _RNG__H_
#define _RNG__H_



u8 RNG_Init(void);

u32 RNG_GetRandomNum(void);

int RNG_GetRandomRange(int min,int max);

#endif

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值