【STM32F769Discovery开发板试用】USB-HS HID收发简单测评
<p> STM32的大部分评估板和第三方开发板都带有USB接口,USB接口配置为Device模式的话就可以跟电脑进行通信了,一般Device模式又分为HID/CDC/DFU/MS/Audio等协议,其中HID为人体学输入设备,CDC为虚拟串口设备,DFU为固件升级设备,MS为大容量存储设备,Audio为音频通信设备,HID适用于简单/低速的透传通信或是虚拟为鼠标键盘等人体学输入设备,可以自定义每个透传字段的长度,特征值等,不需要对数据包中的逐个字节进行解析;CDC适用于高速/大流量的透传通信,可以以winusb形式与电脑进行通信,不可以自定义透传字段特征值,只能从一帧数据包中逐个字节进行解析;DFU只适用于主控代码升级;MS只适用于将主控虚拟为U盘等存储设备;Audio只适用于将主控虚拟为声卡设备。在数据透传应用上,HID协议与CDC协议极其相似。<br /> 官方给出的搭建HID代码例程的步骤非常简单,只需要使用CubeMX并配置发送字段即可完成,一步步开始吧,不过USB通信是需要固定48MHz时钟的,对于官方的评估板或者时钟设计参考官方评估板的第三方开发板,一般尽量使用CubeMX的板级初始化功能(即Access to Board Selector):</p>
<p></p>
<p>不使用芯片级初始化功能(Access to MCU Selector)意义在于,可以正确初始化USB时钟,避免不必要的麻烦。进入CubeMX引脚配置界面,将不必要的外设如ETH I2S SAI QSPI FMC LTDC等全部剔除,并设置USBHS(高速接口)为Device模式,外挂PHY,SOF不启用:</p>
<p></p>
<p>为什么是外挂PHY呢,很简单,看原理图和板子的芯片布局就知道了:</p>
<p></p>
<p>板子F769主控的USBHS接口是通过一块USB3320 USB-PHY芯片引出物理层microUSB接口的。</p>
<p>然后是对于USB Device第三方外设的配置,设置模式为Custom HID:</p>
<p></p>
<p>最后确认USB时钟频率为48MHz即可生成工程:</p>
<p></p>
<p>工程生成后,按照ST官方给出USBHID文档的指引,需要替换usbd_custom_hid_if.c文件下的CUSTOM_HID_ReportDesc_HS枚举数组:</p>
<pre>
<code>#define REPORT_INPUT_LEN 64
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_HS __ALIGN_END =
{
0x06,0xA0,0xFF,//用法页(FFA0h, vendor defined)
0x09, 0x01,//用法(vendor defined)
0xA1, 0x01,//集合(Application)
0x09, 0x02 ,//用法(vendor defined)
0xA1, 0x00,//集合(Physical)
0x06,0xA1,0xFF,//用法页(vendor defined)
//输入报告
0x09, 0x03 ,//用法(vendor defined)
0x09, 0x04,//用法(vendor defined)
0x15, 0x80,//逻辑最小值(0x80 or -128)
0x25, 0x7F,//逻辑最大值(0x7F or 127)
0x35, 0x00,//物理最小值(0)
0x45, 0xFF,//物理最大值(255)
0x75, 0x08,//报告长度Report size (8位)
0x95, REPORT_INPUT_LEN,
//报告数值
0x81, 0x02,
//输入(data, variable, absolute)
//输出报告
0x09, 0x05,
//用法(vendor defined)
0x09, 0x06,
//用法(vendor defined)
0x15, 0x80,
//逻辑最小值(0x80 or -128)
0x25, 0x7F,
//逻辑最大值(0x7F or 127)
0x35, 0x00,
//物理最小值(0)
0x45, 0xFF,
//物理最大值(255)
0x75, 0x08,
//报告长度(8位)
0x95, 0x40,
//报告数值(64 fields)
0x91, 0x02,
//输出(data, variable, absolute)
0xC0,
//集合结束(Physical)
0xC0
//集合结束(Application)
};</code></pre>
<p>这个数组会被初始化函数集USBD_CustomHID_fops_HS调用:</p>
<pre>
<code>USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_HS =
{
CUSTOM_HID_ReportDesc_HS,
CUSTOM_HID_Init_HS,
CUSTOM_HID_DeInit_HS,
CUSTOM_HID_OutEvent_HS
};</code></pre>
<p>然后修改usbd_conf.h的USBD_CUSTOM_HID_REPORT_DESC_SIZE,这里填52,即刚刚那个数组的长度:</p>
<p></p>
<p>添加回调函数,这步必不可少:</p>
<pre>
<code>void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_IncTick();
}</code></pre>
<p>上述代码修改完毕之后就可以用USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS,buf,sizeof(buf));函数进行USBHID发送,每次调用函数发送的单位是64字节,固定的:</p>
<p></p>
<p>当然为了便于系统和HID软件识别,需要修改VID PID 设备名等参数:</p>
<pre>
<code>#define USBD_VID 1155
#define USBD_PID_HS 22352
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "STMicroelectronics"
#define USBD_PRODUCT_STRING_HS "donatello1996 STM32F769 USBHID Device"
#define USBD_CONFIGURATION_STRING_HS "Custom HID Config"
#define USBD_INTERFACE_STRING_HS "Custom HID Interface"</code></pre>
<p></p>
<p>最后使用示波器抓取发送函数耗时:<br />
</p>
<pre>
<code> while(1)
{
GPIOJ->BSRR |= 0x00000002;
USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS,buf,sizeof(buf));
GPIOJ->BSRR |= 0x00020000;
USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS,buf,sizeof(buf));
}</code></pre>
<p></p>
<p>可以看出,即使是HID这种低速模式,发送间隔居然也缩小到不可思议的500ns,也就是1us可以发送128个字节,那么1s就可以发送128MB,在多数项目中绝对够用了,如果是使用高速的CDC模式则更快,1s发送几百MB不在话下。</p>
<p>上传工程文件</p>
<p>扯了,你这么用示波器抓只是判断 USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS,buf,sizeof(buf)); 这个调用的间隔时间。</p>
<p>USB HS的接口 ULPI 的时钟才60MHz, 不可能有超过60MB/s的收发速度。</p>
cruelfox 发表于 2020-8-4 17:49
扯了,你这么用示波器抓只是判断 USBD_CUSTOM_HID_SendReport(&hUsbDeviceHS,buf,sizeof(buf)); 这 ...
<p>时钟60MHz跟可以发送的数据量速率128MB/s有什么关系呢?60MHz只不过是USB时钟电平的频率,一秒钟内时钟可以翻转60M次,只要在时钟翻转一次电平的时候CPU往USBHS缓冲区送入一次64字节的数据包就代表发送成功了,接收端能否正常,准确无误接收这些数据包跟发送端有啥关系呢?</p>
donatello1996 发表于 2020-8-4 18:13
时钟60MHz跟可以发送的数据量速率128MB/s有什么关系呢?60MHz只不过是USB时钟电平的频率,一秒钟内时钟可 ...
<p>你那只是函数返回而已,数据并没有发送出去。</p>
<p>HID报文是Interrupt Transfer类型的,只有主机polling的时候才可以把数据发出去。</p>
<p>这不是SPI... 就算是480Mbps的SPI,也最大才60MB/s的传输量。</p>
cruelfox 发表于 2020-8-4 21:28
你那只是函数返回而已,数据并没有发送出去。
HID报文是Interrupt Transfer类型的,只有主机polling的 ...
<p>数据有没有成功发送出去,需要电脑上位机那边接收并做计数,不是STM32这边需要关心的问题,先不说polling到底间隔多长,反正成功发送多少数据量肯定跟60MHz的时钟没有半毛钱关系。</p>
<div class='shownolgin' data-isdigest='no'>donatello1996 发表于 2020-8-5 09:58
数据有没有成功发送出去,需要电脑上位机那边接收并做计数,不是STM32这边需要关心的问题,先不说polling ...
<p>是的,你认为的“发送成功”跟这没关系,USB模块存在不存在都没有关系。只要函数没有卡在那里就是成功。</p>
</div><script>showreplylogin();</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <div class='shownolgin' data-isdigest='no'><p>单从USB2.0的参数看,最大480Mbps即使不考虑协议最大速率不会超过60MB/S</p>
<p>你再去看USB3320的数据手册最大60MHz的时钟,它与STM32的总线宽度也只有1byte,所以它能和STM32的最大通信速率也不会超过60MH</p>
<p> </p>
<p></p>
<p> </p>
<p></p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>littleshrimp 发表于 2020-8-6 17:37
单从USB2.0的参数看,最大480Mbps即使不考虑协议最大速率不会超过60MB/S
你再去看USB3320的数据手册最大 ...
<p>有图有真相,令人信服,点赞!既然官方手册都说了不超过60MB/s的话,那就肯定不会超过,但具体应该是多少数值我得写个上位机验证一下,这点是必须要实事求是的。我跟楼上那位争论的重点在于,不应该把USB时钟和每秒发送数据量混在一起讨论,我认为这是两个完全不同的概念,发送数据量是跟USB时钟有很小的关联,但绝对不是简单的1对1关系,F769主控的USB控制器从USB时钟源获取工作时钟,在规定的周期内从缓冲区把一帧数据发出,那么一秒发送的数据量具体有多少,跟一帧数据大小和占用时钟周期有关系,这是一个二元关系,不是简单的1对1关系</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>donatello1996 发表于 2020-8-6 18:38
有图有真相,令人信服,点赞!既然官方手册都说了不超过60MB/s的话,那就肯定不会超过,但具体应该是多少 ...
<p>USBD_CUSTOM_HID_SendReport函数有返回值</p>
<p>你试一下,判断返回值为USBD_OK时再操作GPIO</p>
<p>测量一下波形看看间隔是多少</p>
<p></p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'><p>深挖的有点意思。</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>littleshrimp 发表于 2020-8-6 19:54
USBD_CUSTOM_HID_SendReport函数有返回值
你试一下,判断返回值为USBD_OK时再操作GPIO
测量一下波 ...
<p>好的,这周我有空试试,我也想知道F769的USBHID性能如何</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>freebsder 发表于 2020-8-6 22:02
深挖的有点意思。
<p>道长见笑了</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'><p>博主对stm32的USB相关内容还是不是很了解啊</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>donatello1996 发表于 2020-8-6 18:38
有图有真相,令人信服,点赞!既然官方手册都说了不超过60MB/s的话,那就肯定不会超过,但具体应该是多少 ...
<p>发送的数据量和时钟频率是有很大关系的,时钟频率就决定了你IO口的翻转频率</p>
</div><script>showreplylogin();</script> <div class='shownolgin' data-isdigest='no'>donatello1996 发表于 2020-8-4 18:13
时钟60MHz跟可以发送的数据量速率128MB/s有什么关系呢?60MHz只不过是USB时钟电平的频率,一秒钟内时钟可 ...
<p>那你要怎么做到时钟翻转一次的时候写入64字节的数据呢,stm32的数据总线有64字节这么大的位宽吗</p>
<p> </p>
</div><script>showreplylogin();</script>
页:
[1]