本章将学习 ESP32-S3 的硬件随机数发生器。使用 BOOT 按键来获取硬件随机数,并且将获取到的随机数值显示在 LCD 上面。同时,使用 LED 指示程序运行状态。
        本章分为如下几个小节:
31.1 随机数发生器简介
31.2 硬件设计
31.3 程序设计
31.4 下载验证
31.1 随机数发生器简介

        ESP32-S3 内置的硬件随机数发生器(RNG)是一个基于物理过程生成真随机数的模块,它利用芯片内部固有的噪声源(如​​热噪声​​和​​时钟抖动​​)来产生​​不可预测​​的随机数,非常适合用于加密、安全认证和各类需要高随机性的应用场景。
      RNG 工作原理与特性:

  • 噪声源​​:主要依赖​​两种物理熵源​​:

​​        模数转换器 (ADC) 热噪声​​:当 SARADC 或高速 ADC 工作时,其内部晶体管的热噪声会产生微小的电压波动,经采样后形成随机比特流。
​​        RC_FAST_CLK 时钟抖动​​:对内部 20MHz RC 快速时钟进行采样,利用其固有的频率漂移和抖动(电路亚稳态)作为随机性来源。
这些熵源产生的比特流通过异或 (XOR) 等逻辑混合后,存入 RNG_DATA_REG寄存器供读取。

  • 输出数据​​:每次读取会返回一个 ​​32 位​​的无符号随机数 (uint32_t)。
  • 性能与质量​​:生成的随机数在其范围内​​分布均匀​​。为确保熵值最大,建议在使用 RNG 时至少使能一路 ADC 作为种子源。

        真随机数发生器(TRNG)​ VS 伪随机数发生器 (PRNG)​:

特性维度​

​真随机数发生器 (TRNG)​

​伪随机数发生器 (PRNG)​

​​随机性来源​​

​物理现象​​(热噪声、量子效应等)

​确定性算法​​(数学公式)

​​可预测性​​

​完全不可预测​​,即使知道所有生成细节也无法推测结果

​可预测​​,知道算法和种子即可重现整个序列

​​周期性​​

​无周期​​,理论上永不重复

​有周期​​,序列长度取决于算法和种子长度

​​速度​​

相对较慢,受物理过程限制

非常快,依赖算法计算速度

​​主要应用​​

​高安全场景​​:加密密钥生成、数字签名、安全令牌

​一般随机需求​​:模拟仿真、游戏、随机抽样

​​硬件依赖​​

通常需要​​专用硬件​​或利用物理熵源

纯软件即可实现

表31.1.1 真随机数发生器(TRNG)​ 和 伪随机数发生器 (PRNG)​比较

31.1.1 RNG 功能描述

        下面先来了解噪声源,EDP32- S3 的随机数发生器噪声源如图 31.1.1.1 所示:

图 31.1.1.1 ESP32-S3 随机数发生器噪声源

        系统可以从随机数发生器的寄存器 RNG_DATA_REG 中读取随机数,每个读到的 32 位随机数都是真随机数,噪声源为系统中的热噪声和异步时钟。具体来说,这些热噪声可以来自SARADC或高速 ADC或两者兼有。当芯片的 SARADC 或高速 ADC工作时,就会产生比特流,并 通 过 异 或(XOR)逻辑运算作为随机数种子进入随机数生成器 。当为数字内核使能RC_FAST_CLK 时钟时,随机数发生器也会对 RC_FAST_CLK(20MHz)进行采样,作为随机数种子。RC_FAST_CLK 是一种异步时钟源,由于存在电路亚稳态,因此可以提高随机数发生器的墒值。然而,为了保证随机数发生器可以获得最大熵值,仍建议在使用随机数发生器时至少使能一路 ADC 作为随机数种子。

31.1.2 RNG 随机数寄存器

        RND 随机数寄存器描述如下所示:

名称 描述 地址 访问
RNG_DATA_REG 随机数数据 0x0110 只读

表 31.1.2.1 RNG 寄存器列表

图 31.1.2.1 RNG_CR 寄存器

        需要注意:这里的地址都是相对于随机数发生器基地址的地址偏移量。

31.2 硬件设计

31.2.1 例程功能

        本实验使用 ESP32-S3 自带的硬件随机数生成器(RNG),获取随机数,并显示在 LCD 屏幕上。按 BOOT 按键可以获取一次随机数。同时程序自动获取 0~9 范围内的随机数,显示在屏幕上。 LED 闪烁用于提示程序正在运行。

31.2.2 硬件资源

        1. LED
                LED - IO1
        2.独立按键
                BOOT - IO0
        3. XL9555
                IIC_SDA-IO41
                IIC_SCL-IO42
        4. SPILCD
                CS-IO21
                SCK-IO12
                SDA-IO11
                DC-IO40(在 P5 端口,使用跳线帽将 IO_SET 和 LCD_DC 相连)
                PWR- IO1_3(XL9555)
                RST- IO1_2(XL9555)
        5. RNG(硬件随机数生成器)

31.2.3 原理图

        RNG 属于 ESP32-S3 内部资源,通过软件设置。本实验通过配合按键获取随机数和通过 LCD 显示。

31.3 程序设计

31.3.1 程序流程图
        本实验的程序流程图:

图 31.3.1.1 随机数实验程序流程图

31.3.2 RNG 函数解析

        ESP-IDF 提供了一套 API 来配置 RNG。要使用此功能,需要导入必要的头文件:

#include "esp_random.h"

        接下来介绍一些常用的 ESP32-S3 中的 RNG 函数,这些函数的描述及其作用如下:
(1)得到随机数
        该函数用于获取一个 32 位的硬件随机数,其函数原型如下:

uint32_t esp_random(void);

        该函数的无形参。

该函数的返回值描述,如下表所示:

返回值 描述
result ^ REG_READ(WDEV_RND_REG) 0 和 UINT32_MAX 之间的随机值

表 31.3.2.1 函数 esp_random ()返回值描述

31.3.3 RNG 驱动解析

        在 IDF 版 21_rng 例程中,在 21_rng\components\BSP 路径下新增了一个 RNG 文件夹,分别用于存放 rng.c、 rng.h 这两个文件。其中, rng.h 文件负责声明 RNG 相关的函数和变量,而rng.c 文件则实现了 RNG 的驱动代码。

(1)rng.h 文件

uint32_t rng_get_random_num(void);          /* 得到随机数 */
int rng_get_random_range(int min, int max); /* 得到某个范围内的随机数 */

(2)rng.c 文件

/**
 * @brief       得到随机数
 * @param       无
 * @retval      获取到的随机数(32bit)
 */
uint32_t rng_get_random_num(void)
{
    uint32_t randomnum;
    
    randomnum = esp_random();
    
    return randomnum;
}

/**
 * @brief       得到某个范围内的随机数
 * @param       min,max: 最小,最大值.
 * @retval      得到的随机数(rval),满足:min<=rval<=max
 */
int rng_get_random_range(int min, int max)
{ 
    uint32_t randomnum;
    
    randomnum = esp_random();
    
    return randomnum % (max - min + 1) + min;
}

31.3.4 CMakeLists.txt 文件

        打开本实验 BSP 下的 CMakeLists.txt 文件,其内容如下所示:

set(src_dirs
            IIC
            KEY
            LCD
            LED
            RNG
            SPI
            XL9555)

set(include_dirs
            IIC
            KEY
            LCD
            LED
            RNG
            SPI
            XL9555)

set(requires
            driver)

idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)

31.3.5 实验应用代码

        打开 main/main.c 文件,该文件定义了工程入口函数,名为 app_main。该函数代码如下。

i2c_obj_t i2c0_master;

/**
 * @brief       程序入口
 * @param       无
 * @retval      无
 */
void app_main(void)
{
    uint8_t key;
    uint32_t random;
    uint8_t t = 0;
    esp_err_t ret;
    
    ret = nvs_flash_init();                                         /* 初始化NVS */

    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }

    led_init();                                                     /* 初始化LED */
    i2c0_master = iic_init(I2C_NUM_0);                              /* 初始化IIC0 */
    spi2_init();                                                    /* 初始化SPI2 */
    xl9555_init(i2c0_master);                                       /* 初始化XL9555 */
    lcd_init();                                                     /* 初始化LCD */
    key_init();                                                     /* 初始化按键 */
    
    lcd_show_string(30, 50, 200, 16, 16, "ESP32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "RNG TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    
    lcd_show_string(30, 110, 200, 16, 16, "RNG Ready!   ", RED);
    lcd_show_string(30, 130, 200, 16, 16, "BOOT:Get Random Num", RED);
    lcd_show_string(30, 150, 200, 16, 16, "Random Num:", RED);
    lcd_show_string(30, 180, 200, 16, 16, "Random Num[0-9]:", RED);

    while(1)
    {
        key = key_scan(0);
        
        if (key == BOOT)                                            /* 获取随机数并显示至LCD */
        {
            random = rng_get_random_num();
            lcd_show_num(30 + 8 * 11, 150, random, 10, 16, BLUE);
        }
        
        if ((t % 20) == 0)                                          /* 获取0~9间的随机数并显示至LCD */
        {
            LED_TOGGLE();                                           /* 每200ms,翻转一次LED */
            random = rng_get_random_range(0, 9);                    /* 取[0,9]区间的随机数 */
            lcd_show_num(30 + 8 * 16, 180, random, 1, 16, BLUE);    /* 显示随机数 */
        }

        vTaskDelay(10);
        t++;
    }
}

31.4 下载验证

        将程序下载到开发板后,可以看到 LED 不停的闪烁,提示程序已经在运行了。然后按下 BOOT,就可以在屏幕上看到获取到的随机数。同时,就算不按 BOOT,程序也会自动的获取 0~9 区间的随机数显示在 LCD 上面。实验结果如图 31.4.1 所示:

图 31.4.1 获取随机数成功

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐