请保留-> 【原文: 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所示。
由于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所示。
由于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所示。
至此,就完成了随机数生成器的开发。
目前设计的生成器中,返回的是16位的随机数。一般的随机数,是使用32位的,比如STM32F4就提供了32位的随机数发生部件。稍微修改下本篇的程序,比如调整校正数为32位的,就能提供32位的随机数了。
1,459 total views, 1 views today