5

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

 2 years ago
source link: http://yiiyee.cn/blog/2021/08/16/yie002%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a210-%e9%9a%8f%e6%9c%ba%e6%95%b0%e7%94%9f%e6%88%90%e5%99%a8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

在规划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位的随机数了。

20 total views, 2 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK