【F769IDISCOVERY评测】高速USB VCP和全速USB VCP 速度对比
本帖最后由 creep 于 2017-10-17 14:31 编辑STM32F769 Discovery (STM32官网)板载有一个USB OTG HS 接口和一个USB 高速PHY USB3320C-EZK,二者配合可以实现高速的虚拟串口和PC或者其他设备进行通信,下面我们就简单的看下高速的VCP的移植和通信速度,并和其他的板子上的全速VCP进行对比。
1、硬件
USB OTG HS 的外部PHY为USB3320C,和stm32769硬件接口如下,
USB3320C的时钟使用板载的24M晶振,并输出60MHZ的时钟给USB 高速模块,这个全速USB设备的48MHZ时钟有些区别。
移植的时候需要根据STM32F769 Discovery 的原理图确认具体是哪些引脚和USB3320C进行通信。
2、软件移植
ST官方提供了完善的USB库,移植非常简单,只需要根据具体的硬件设置要初始化的引脚即可,此处一定要注意必须根据原理图连接进行初始化化,不同的ST开发板的接法可能不同:
/* Configure USB HS GPIOs */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/* CLK */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* D0 */
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* D1 D2 D3 D4 D5 D6 D7 */
GPIO_InitStruct.Pin = GPIO_PIN_0| GPIO_PIN_1| GPIO_PIN_5 |\
GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* STP */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* NXT */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
/* DIR */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct)然后在编译器的预处理定义中选择高速外设:
最后在main函数中初始化USB即可:
int main(void)
{
uint8_t TestBuff;
uint16_t t;
/* Enable the CPU Cache */
CPU_CACHE_Enable();
HAL_Init();
/* Configure the system clock to 216 MHz */
SystemClock_Config();
USART1_Init();
for(t = 0;t < 512;t++)TestBuff = t;
/* Init Device Library */
USBD_Init(&USBD_Device, &VCP_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&USBD_Device, USBD_CDC_CLASS);
/* Add CDC Interface Class */
USBD_CDC_RegisterInterface(&USBD_Device, &USBD_CDC_fops);
/* Start Device Process */
USBD_Start(&USBD_Device);
/* Infinite loop */
while (1)
{
USB2PC(TestBuff,512);
}
}下载程序到板子后应该就可以在电脑设备管理器看到虚拟串口
如果是第一次使用VCP就要安装官方的驱动,有的电脑可能不是正版系统会导致安装驱动失败,解决办法可以参考这个帖子:
虚拟串口驱动安装失败的解决方法
基本上常见的串口驱动问题都可以解决,如果驱动安装成功后还提示设备有问题,可以尝试将代码的堆栈修改大一些试下。
3、数据传输
全速的USB VCP一次最多可以发送64个字节,高速的USB VCP 一次可以最多发送512个字节,如果一次发送整个数据包的数据,需要再发送一个数据个数为0的数据包,否则上位机可能没法接收数据。 USB发送数据主要是调用下面的函数:
//发送数据PC
uint8_t UsbSendData(uint8_t *pbuff,uint16_t buffsize)
{
uint16_t retry = 0;
USBD_HandleTypeDef *pdev = &USBD_Device;
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassData;
hcdc->TxBuffer = pbuff;
hcdc->TxLength = buffsize;
if(pdev->pClassData != NULL)
{
if(hcdc->TxState == 0)
{
/* Tx Transfer in progress */
hcdc->TxState = 1;
/* Transmit next packet */
USBD_LL_Transmit(pdev,
CDC_IN_EP,
hcdc->TxBuffer,
hcdc->TxLength);
}
else
{
return USBD_BUSY;
}
}
//等待发送结束
while(hcdc->TxState == 1)
{
retry++;
if(retry == 0xfff0)
{
return USBD_FAIL;
}
}
return USBD_OK;
} 根据上面USB发送数据包的要求,我们使用下面的函数来调用上面的函数来发送任意大小的数据,这个函数会自动在发送最大数据包后再发送一个空的数据包。USB_PACK_SIZE根据USB模式可能为64或者512
//可发送任意字节的数据到PC端
void USB2PC(uint8_t *str,uint16_t len)
{
uint16_t j = 0;
if(len < USB_PACK_SIZE)
{
UsbSendData(str,len);
}
else
{
for (j = 0;j < len/USB_PACK_SIZE;j++)
{
UsbSendData((str+USB_PACK_SIZE*j),USB_PACK_SIZE);
}
UsbSendData((str+USB_PACK_SIZE*j),len%USB_PACK_SIZE);
}
}为了测试发送的最大速度,我在main函数中循环调用发送函数一次发送512字节,发送内容为0X00-0XFF.
因为发送数据量比较大,有些串口助手可能会卡死,我使用SecureCRT 进行接收.接收数据如下,因为SecureCRT显示的ASCII,所以有些显示是乱码,但是数据是对的,
使用监控软件看到发送数据如下,可以每个数据包为512字节,每次发送的内容为0x00-0xFF.数据没有出错。
具体的发送速度如下,多次测试可以看到软件计算的结果有些不同
为了对比我们测试下STM32F746 Discovery上全速的USB发送速度,
int main(void)
{
uint8_t TestBuff;
uint16_t t;
CPU_CACHE_Enable();
HAL_Init();
SystemClock_Config();
LED_Init();
/* Init Device Library */
USBD_Init(&USBD_Device, &VCP_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&USBD_Device, USBD_CDC_CLASS);
/* Add CDC Interface Class */
USBD_CDC_RegisterInterface(&USBD_Device, &USBD_CDC_fops);
/* Start Device Process */
USBD_Start(&USBD_Device);
for(t = 0;t < 64;t++)TestBuff = t;
while(1)
{
USB2PC(TestBuff,64);
}
}
SecureCRT看到的数据
监控软件检测到的数据,数据包大小为64字节
检测到发送速度
全速USB的理论最大速度为12Mbps,高速USB的为480Mpbs,明显上面测的数据和理论的最大数度有些差距。不同的检测软件可能测试得到的数据不同,通过对比可以看到高速USB VCP和全速USB VCP还是有些速度提升的。测试代码使用keil5.20编译,代码没有进行任何优化。USB库是2016的比较新的版本。感兴趣的同学可以使用优化代码或者其他编译器编译代码试下是不是速度有所提升。
我在测试高速USB VCP的时候因为发送数据量较大,在我电脑上win10安装之后的首次蓝屏,赶紧拍照留念,微软迟早药丸。
测试代码;
参考文档
推荐阅读:
STM32 USB CDC虚拟多串口
好贴必须顶起 win10被你弄死机了:P:P 跟着大神学USB :)厉害 顶起,学习了。。。 你拿USB VCP虚拟串口的速度和全速/高速USB的速度对比,这。。。 moyanming2013 发表于 2016-12-3 20:57
你拿USB VCP虚拟串口的速度和全速/高速USB的速度对比,这。。。
大神,让您见笑了。:)
我就是顺便对比下。。。
给有需要的人或者想知道差别的同学一个基本的参考。 霹雳之火 发表于 2016-12-3 19:31
好贴必须顶起 win10被你弄死机了
微软大法好,升级了win10后,好多年的旧笔记本又满血复活了。:lol vcp速度上不去是因为你的usb没有做双缓冲,做一下就好了。不过开启stm32 IN端点的双缓冲时序还是蛮复杂的,并且官方没有任何参考历程 没有蓝屏不微软