YIE002开发探索10-随机数生成器

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】
(代码仓库地址:https://gitee.com/luobing4365/yie002-explorer
具体参考博客:YIE002开发探索-Gitee代码仓库说明)

在规划YIE002开发板的时候,其中有一个目标是,实现类似ChaosKey一样的,可以在UEFI下访问的随机数生成器。

ChaosKey是一个硬件真随机数生成器,通过USB进行通信。其主页为:https://altusmetrum.org/ChaosKey/。

STM32F2和STM32F4系列的芯片,提供了芯片内部的随机数生成器。而YIE002开发板上使用的STM32F103C8T6,并没有提供。因此,必须使用其他办法来实现目标。

1 随机数生成器构建

上一篇中,已经打通了USB HID的双向通信通道,数据可以很方便地发送给上位机了。所需要的,是产生随机数的源。

在YIE002开发板上,有些引脚是悬空的,其中的PB1可用作ADC通道9进行采样,如图1所示。

图1 YIE002的单片机引脚图

由于PB1是悬空状态,所采集的ADC数据是不确定的。可以利用此机制,来构造随机数生成器。不过,由于ADC的量程有限,因此添加一个16位的全局变量random_add。程序运行期间,每次进入main()函数的while循环,此全局变量都增1。

将采集到的ADC值(12位)与radom_add相加,得到一个16位的随机数,通过USB HID的通道返回给上位机,就完成了随机数生成器的构建过程了。

2 YIE002-STM32的随机数生成器编程

随机数生成器分为两部分:ADC采样和USB HID通道构建。

我们可以直接使用上一篇HID双向通信的代码,在其上进行修改。不过,由于采用STM32 Cube MX编程,在自动生成代码的时候,所有非“USER CODE BEGIN”和“USER CODE END”内编写的代码,都会消失。

比如上一篇直接修改了usbd_customhid.c内的函数,这块的代码在自动生成代码的时候,不会保存下来。

2.1 随机数生成器的Cube MX图形配置

主要的工作是在上一篇代码的基础上,打开对ADC的支持。如图2所示。

图2 打开ADC

由于YIE002开发板上的PB1是悬空的,因此选择它使用ADC采样,作为随机数发生器的数据源。ADC可以使用轮询、中断、DMA等方式进行采样,简单起见,我们准备使用轮询的方式来运作。

其余的配置保持之前的状态就可以了,然后选择GENERATE CODE生成代码。

2.2 编写应用代码

由于自动生成的代码把编写的USB相关的内容覆盖了(主要是报表描述符、SetReport和GetReport类命令的处理),因此,需要编写的代码包括ADC采样和USB代码的重编写。

1)ADC采样

为了调整随机数的输出,增加了随机数调整用的变量,在主函数main()中定义变量如下:

uint16_t ADC_Value = 0;
uint16_t random_add = 0;  //用来生成随机数校正用的数值

同时定义一个全局变量,保存生成的随机数:

//通过ADC生成随机数
uint16_t random_value=0x1376;

在main()的while循环中,添加如下代码,对PB1进行ADC采样,获得随机值:

while (1)
{
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	//robin 20210815 adc
	random_add++;
	HAL_ADC_Start(&hadc1);  //启动ADC转换
	HAL_ADC_PollForConversion(&hadc1,100); //等待转换完成,超时时间为100ms
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1),HAL_ADC_STATE_REG_EOC))//判断转换完成标志位是否设置
	{
		ADC_Value = HAL_ADC_GetValue(&hadc1);  //读取ADC转换数据,转换为12位
		random_value = ADC_Value + random_add;
	}
//…后略

通过以上代码,就得到了需要生成的随机数。

2)添加USB通信代码

按照上一篇博客的内容,添加报表描述符,修改传输数据包等。

针对三种传输方式,需要修改的内容如下。

读写文件的方式,需要修改main()函数中发送数据的部分,内容如下:

if(USBdataFlag == 1)
{
	USBdataFlag=0;
	USBRxBuff[0] = (uint8_t)random_value;
	USBRxBuff[1] = (uint8_t)(random_value>>8);
	USBRxBuff[2] = 0x11;	
	USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS,USBRxBuff,USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
}

Input Report&Output Report的方式,以及Feature Report方式,需要修改类命令SET_REPORT和GET_REPORT的处理。

在usbd_customhid.c中,修改函数USBD_CUSTOM_HID_Setup(),内容如下:

extern uint8_t USBdataFlag;
extern uint8_t USBRxBuff[16];
extern uint8_t Report_InOut_Flag; //Robin: Input报告和Output报告标志
extern uint8_t Report_Feature_Flag;//Robin: Feature报告标志
static uint8_t  USBD_CUSTOM_HID_Setup(USBD_HandleTypeDef *pdev,
                                      USBD_SetupReqTypedef *req){
//……前略
case CUSTOM_HID_REQ_SET_REPORT:
	//robin add for in/out/feature report
	//类命令的wValue高字节,1-Input Report; 2-Output Report; 3-Feature Report
	if(((req->wValue)&0xff00) == 0x0200)
		Report_InOut_Flag=1;
	else if(((req->wValue)&0xff00) == 0x0300)
		Report_Feature_Flag=1;

    hhid->IsReportAvailable = 1U;
    USBD_CtlPrepareRx(pdev, hhid->Report_buf, req->wLength);
 break;
				
case CUSTOM_HID_REQ_GET_REPORT: //robin 20210815
	if(((req->wValue)&0xff00) == 0x0100)
	{
		Report_InOut_Flag=0;
		for(uint8_t i=0;i<USBD_CUSTOMHID_OUTREPORT_BUF_SIZE;i++)
			USBRxBuff[i] = hhid->Report_buf[i];
		USBRxBuff[0] = (uint8_t)random_value;
		USBRxBuff[1] = (uint8_t)(random_value>>8);
		USBRxBuff[2] = 0x22;
	}
	else if(((req->wValue)&0xff00) == 0x0300)
	{
		Report_Feature_Flag=0;
		for(uint8_t i=0;i<USBD_CUSTOMHID_OUTREPORT_BUF_SIZE;i++)
			USBRxBuff[i] = hhid->Report_buf[i];
		USBRxBuff[0] = (uint8_t)random_value;
		USBRxBuff[1] = (uint8_t)(random_value>>8);
		USBRxBuff[2] = 0x33;
	}
	USBD_CtlSendData (pdev, (uint8_t *)&USBRxBuff, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE); // to pc	
break;
//……后略
}

不管哪种方式,都是通过前两个字节,将随机数传送给上位机。因此,在上位机发送任何16字节数据之后,都能在返回的16字节中,取出前两个字节的随机数。

2.3 测试

将代码编译后,下载到开发板上。配合UEFI开发探索74篇附带的测试工具UsbHID,可以观察到随机数获取的过程。如图3所示。

图3 测试随机数生成器

至此,就完成了随机数生成器的开发。

目前设计的生成器中,返回的是16位的随机数。一般的随机数,是使用32位的,比如STM32F4就提供了32位的随机数发生部件。稍微修改下本篇的程序,比如调整校正数为32位的,就能提供32位的随机数了。

1,459 total views, 1 views today

发表评论

电子邮件地址不会被公开。