当前位置:首页 > 单片机 > 单片机
[导读]1 前言本文将基于STM32F4DISCOVERY板,介绍如何使用USB的CDC类进行开发,以及在开发过程中碰到发送64整数倍数据时会失败的问题分析及解决方案。2 硬件介绍在创建工程之前,我们首先即将使用的硬件进行必要的介绍。图

1 前言

本文将基于STM32F4DISCOVERY板,介绍如何使用USB的CDC类进行开发,以及在开发过程中碰到发送64整数倍数据时会失败的问题分析及解决方案。

2 硬件介绍

在创建工程之前,我们首先即将使用的硬件进行必要的介绍。


图1 USB电路


如上图所示,USB电路使用PA11,PA12,全速USB OTG,当然,这里只做device,英雌只需要看上图的下面部分。


图2 按键电路


如上图,本例中将使用到1个用户按键,PA0,按下时为1电平。
另外,晶振使用的是外部HSE 8M晶振。


3 创建CubeMx工程

打开CubeMX(V4.17.0),创建一个以STM32F407VGTx的工程,使用FS-USB,并使用PA0外部输入EXIT,如下图所示:


图3 pinout


使能外部HSE,使用外部8M HSE,其时钟树如下设置:


图4 时钟树


接下来是配置参数,这里只修改USB中断优先级为1,而PA0的外部中断优先级设置为4,如下:


图5 中断优先级设置


然后再中间件将USB class设置为Communicaiton Device Class,如下:


图6 USB Class设置


最后将工程的堆设为0.5K,栈设为1.5K :


图7 堆栈设置


最后生成一个 F407_CDC_Test的工程。


4 修改工程代码

我们对生成的工程不做任何修改,直接编译后烧进开发板后是可以被PC识别为虚拟串口的,如下图所示:


图8 PC识别为虚拟串口


当然,这里的前提是必须在PC机上安装了ST发布的虚拟串口驱动(STSW-STM32102下载地址 :http://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-utilities/stsw-stm32102.html)。


(注意:这里所说的虚拟串口主要是指其可以被当做串口来用,但其速度跟串口所设置的波特率完全没有关系,用户不要被名字所迷惑,虽然使用起来跟串口没有区别,但其本质还是USB,在初始化设置波特率不会对USB的通讯速率产生任何影响,本文档所描述的是全速USB,因此,其最大速率就固定为12M/S,这个是由全速USB外设标准48M输入时钟所决定的)

此时是没有任何具体功能的,为了更好的看到通讯的数据,我们将使用串口通讯工具来进行测试,这里我们使用的串口工具是: sscom32.

4.1 验证接收功能

我们将使用PC串口工具SSCOM32通过USB向MCU发送数据,为了能在PC端能看到MCU是否能接收到数据,我们在MCU端修改代码,让MCU一旦接收到来自PC端的数据后,立马返回一模一样的数据,因此需要在生成的源码文件usbd_cdc_if.c文件中找到到函数:CDC_Receive_FS(),添加处理函数,如下:

staticint8_tCDC_Receive_FS(uint8_t*Buf,uint32_t*Len){/*USERCODEBEGIN6*/HanldeReceiveData(Buf,*Len);USBD_CDC_SetRxBuffer(&hUsbDeviceFS,&Buf[0]);USBD_CDC_ReceivePacket(&hUsbDeviceFS);return(USBD_OK);/*USERCODEEND6*/}/*USERCODEBEGINPRIVATE_FUNCTIONS_IMPLEMENTATION*/staticvoidHanldeReceiveData(uint8_t*Buf,uint32_tLen){CDC_Transmit_FS(Buf,Len);}/*USERCODEENDPRIVATE_FUNCTIONS_IMPLEMENTATION*/12345678910111213141516171234567891011121314151617

编译后烧进板子进行验证:


图9%20MCU接收返回相同数据


如上如所示,串口工具能够收到来自MCU的返回数据,与发送数据完全一样,这说明,MCU已经接收到了PC端发送的数据,另外,PC端也能接收到MCU端发送的数据。


4.2%20验证发送功能

接下来我们来通过按键响应来主动向PC端发送数据,我们在按键回调函数内添加代码如下:

/*USERCODEBEGIN0*/staticuint8_tSendData[256]={0};voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){uint16_ti;for(i=0;i

即用户按下按键,MCU则向PC端发送一次数据,这里发送的是63个字节,内容为0~62,测试后PC端的串口工具完全能收到MCU端发送的63个字节,如下图所示:


图10 PC端收到63个字节


但是当我们将代码修改为发送64个字节后 :


/*USERCODEBEGIN0*/staticuint8_tSendData[256]={0};voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){uint16_ti;for(i=0;i

修改后进行验证,发现PC端串口工具不能接收到数据,,这里代码基本完全没有变化,只是发送长度之前为63,这里为64,结果却不相同,很明显,USB CDC协议栈哪里出了问题。

我们先使用USB分析仪对发送64个字节时进行USB总线监控:


图11 USB数据监控


如上图,我们发现,当发送64个字节时,由于正好是最大包长(64),按USB标准来看,应该多发一次空的transaction,但是这里,仅仅只发了一次transaction,这也就是为什么串口没有接收到数据的原因(MCU端的USB实际上是已经发送了64个字节,但由于缺少一个transaction,因此PC端的驱动会认为数据格式不完整,而放弃所有已经接收到的数据,从而使上层看起来没有接收到任何内容)。


图12 USB2.0标准对于最大包长整数倍的要求


因此,接下来的工作就是找到USB协议栈中的相应处理环节,然后将缺少的那个空的transaction补上即可。


4.3 USB CDC协议栈修改4.3.1 USB数据发送流程分析

在对USB CDC协议栈进行修改之前,我们先来梳理下USB发送的流程。
发送USB数据大概过程如下:
1> 填写DIEPTSIZ寄存器的发送包数(pakage count)和传输大小(transfer size)。
2> 使能发送断点的发送空中断(DIEPEMPMSK,利用发送空中断TXFE来将发送数据填充到DFIFO)。
3> 使能中断。
4> 后续就是中断的事了。
后续将会有3次中断:
1> USB_OTG_DIEPINT_TXFE中断:在此中断处理中,程序将发送缓冲的数据分包填充到DFIFO(不能超过最大包长,只有最后一包数据才有可能小于最大包长)。
2> USB_OTG_DIEPINT_TXFE中断: 还是TXFE中断,上次TXFE填充的发送数据全部发送完了后,最终还是会继续触发TXFE中断,也就是这次中断,在这次FXFE中断中禁止FXFE。也就是说,后续不会再有TXFE中断,除非再次使能。
3> USB_OTG_DIEPINT_XFRC中断:传输完成中断,表示到这次中断为止,传输完成。在这个中断中将回调HAL_PCD_DataInStageCallback()函数,就相当于发送中断一样。
这就是USB数据发送的流程,这里需要注意地是,对于端点0和非端点0来说,在具体流程实现上还是稍微有所差异的。究其原因,主要是端点0和非端点0的DIEPTSIZ寄存器的包大小和传输大小位宽是不一样的。如下图:


图13 端点0的DIEPTSIZ寄存器



图14 端点1~3的DIEPTSIZ寄存器


对比上图,端点0的DIEPTSIZ寄存器的XFRSIZ位宽为7,最大值为127,也就是说最多一次只能传输127个字节,按最大包长64字节来算,就是是最多两包数据。如果需要发送超过127个字节时,又该如何做呢?查看USB协议栈内核代码,发现每次端点0发送数据时,在发送代码中固定每次最多可以传输64字节,然后在传输完成中断处理时,再将剩下的数据接着传输(usb core),当然,每次传输最多也是64个字节,就这样,直到发送完所有数据为止。为什么每次传输最大设置为64?不是XFRSIZ位宽为7,理论上可以为127吗?我的理解是,这样也是可以的,只要包长控制在64个字节内就可以了,至于每次传输多少字节,只要XFRSIZ位宽够用,你可以设置127个字节范围内任何数据均可。代码中设置为64,主要为了图方便。


但是,对于非端点0,XFRSIZ位宽为19位,524288个字节,足够传输所有实际数据了,因此,在发送代码中,并没有限定传输数据的长度,在TXFE中断中也能将所有待发送的字节填入DFIFO。但是,当发送的数据刚好是64的整数倍时,按USB标准,应该继续发送一次空字节,以表示数据全部发送完毕。

4.3.2 代码修改

对比端点0的处理,发现端点0在传输完成中断(XFRC)中,有对这种情况的判断,一旦检测到这种情况,则会发送一次空传输。如下:
usb_core.c文件中的USBD_LL_DataInStage()函数 :

USBD_StatusTypeDefUSBD_LL_DataInStage(USBD_HandleTypeDef*pdev,uint8_tepnum,uint8_t*pdata){USBD_EndpointTypeDef*pep;if(epnum==0){pep=&pdev->ep_in[0];if(pdev->ep0_state==USBD_EP0_DATA_IN){if(pep->rem_length>pep->maxpacket){pep->rem_length-=pep->maxpacket;//继续发送剩余数据USBD_CtlContinueSendData(pdev,pdata,pep->rem_length);/*Prepareendpointforprematureendoftransfer*/USBD_LL_PrepareReceive(pdev,0,NULL,0);}else{/*lastpacketisMPSmultiple,sosendZLPpacket*/if((pep->total_length%pep->maxpacket==0)&&(pep->total_length>=pep->maxpacket)&&(pep->total_lengthep0_data_len)){//再多发送一次空数据USBD_CtlContinueSendData(pdev,NULL,0);pdev->ep0_data_len=0;/*Prepareendpointforprematureendoftransfer*/USBD_LL_PrepareReceive(pdev,0,NULL,0);}else{if((pdev->pClass->EP0_TxSent!=NULL)&&(pdev->dev_state==USBD_STATE_CONFIGURED)){pdev->pClass->EP0_TxSent(pdev);}USBD_CtlReceiveStatus(pdev);}}}if(pdev->dev_test_mode==1){USBD_RunTestMode(pdev);pdev->dev_test_mode=0;}}elseif((pdev->pClass->DataIn!=NULL)&&(pdev->dev_state==USBD_STATE_CONFIGURED)){pdev->pClass->DataIn(pdev,epnum);//非0端点回调CDC类的DataIn()函数处理}returnUSBD_OK;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364651234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2024年4月17日,中国 – 服务多重电子应用领域、全球排名前列的半导体公司意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM)将在2024年4月25日欧洲证券交易所开盘前公布202...

关键字: 半导体 数据

数据占满我们的电子设备已成常态,为了满足广大用户的需求,NAS应运而生。然而,对于许多普通用户来说,NAS设备的设置和使用却常常令人望而却步。不过,铁威马TOS 6的出现,不仅功能强大,而且操作简便,即使是初次接触NAS...

关键字: 数据 电子设备 NAS

机器学习作为人工智能领域的重要组成部分,其过程涉及到多个核心环节。本文将详细阐述机器学习的四个主要步骤:数据准备、模型选择、模型训练与评估,以及模型部署与应用,以揭示机器学习从数据到应用的完整流程。

关键字: 数据 人工智能 机器学习

机器学习算法是人工智能领域中的核心技术之一,它通过对大量数据进行学习,自动发现数据中的规律和模式,从而实现对新数据的预测、分类、聚类等任务。本文将深入探讨机器学习算法的基本过程,包括数据准备、模型选择、训练与评估等关键步...

关键字: 数据 人工智能 机器学习

该系列产品有助于嵌入式设计人员在更广泛的系统中轻松实现USB功能

关键字: 单片机 嵌入式设计 USB

在这篇文章中,小编将对usb的相关内容和情况加以介绍以帮助大家增进对它的了解程度,和小编一起来阅读以下内容吧。

关键字: USB USB隔离诊断

随着人工智能(AI)技术的迅速发展,人们对于通用人工智能(AGI,即Artificial General Intelligence)的期待也日益高涨。通用人工智能指的是具备像人类一样全面智能的计算机系统,能够执行各种复杂...

关键字: 人工智能 计算机 数据

今天,小编将在这篇文章中为大家带来Type-C接口的有关报道,通过阅读这篇文章,大家可以对Type-C接口具备清晰的认识,主要内容如下。

关键字: Type-C USB

一直以来,Type-C接口都是大家的关注焦点之一。因此针对大家的兴趣点所在,小编将为大家带来Type-C接口的相关介绍,详细内容请看下文。

关键字: Type-C USB

随着科技的飞速发展和智能手机的普及,USB调试模式已成为许多科技爱好者和开发者不可或缺的工具。通过USB调试模式,用户可以连接手机与电脑,实现数据传输、应用安装、系统调试等多种功能。本文将深入探讨USB调试模式的打开方法...

关键字: USB 智能手机
关闭
关闭