STM32F4 USB 总结

2019-12-11 18:21发布

STM32F4  USBD_CDC总结
库版本号及各个文件介绍
(在文件中都有说明,仅仅翻译或加入自己理解)
版本号
  * @version V1.1.0
  * @date    19-March-2012
usb_bsp.c
usb硬件初始化(io口,高速全速设置、时钟、中断设置等)
usb_core.c
usb_otg,基本驱动功能,函数中都与寄存器直接打交道,对硬件进行操作
如:通过操作寄存器读写数据,读取硬件状态,模式等
usbd_core.c
设备基本功能,USBD_Init函数选择好枚举所需资料,通信所需类及接口。
该文件起承上启下作用,底层调用usb_core,上层完成对类接口的支持。
usbd_cdc_core.c
配置描述符枚举为CDC类设备,设置通信端点,提供了发送和接收数据时会调用的函数接口。
usb_dcd.c
外设接口,通信端点的打开关闭、发送、准备接收功能,设备的连接、断开功能
usb_dcd_int.c
外设中断服务处理,包括枚举及通信过程的中断,会根据类型调用相应的各层函数完成功能。
usbd_ioreq.c
控制端点接口
usbd_req.c
完成标准USB请求,第九章。
设备枚举所用,提供描述符、设置地址、配置等。
usbd_desc.c
定义设备描述符及字符串描述符
初始化
USBD_Init()
USB库的使用绝妙之处就在此处,从主程序中仅仅加入这个函数,然后后续就可以进行通信了,然而这个函数已经运筹帷幄,为所有做好布局了。
该函数仅仅是bsp初始化,对端点初始化、配置好中断;再就是指定描述符、类、用户的信息;然后等中断产生,由于早指定好了,自然会取到所需信息进行回复,或者调用所需函数进行发送接收。
入参一:USB_OTG_CORE_HANDLE *pdev,
总操作句柄,无论读写;只这一个全局结构体,囊括多如牛毛的寄存器、变量、函数、指针等均在内;不用再为满文件,满工程的全局变量而发愁。
入参二: USB_OTG_CORE_ID_TypeDef coreID,
全速还是高速。
入参三:USBD_DEVICE *pDevice,
指定设备描述符,字符串描述符;为后续枚举过程准备。   
入参四:USBD_Class_cb_TypeDef *class_cb,
                指定类回调函数结构,为后续通信铺垫。
USBD_Usr_cb_TypeDef *usr_cb
指定用户回调接口,比方说USB复位时,用户需要做什么呢,那么就会调用这里的函数,用户添加自己在usb复位时要做的动作即可。
描述符
(内容资料很多自己看,该描述符根据自己需要填写)
设备描述符
在usbd_desc.c中,枚举第一步就是要该描述符
配置描述符
在usbd_cdc_core.c中,usbd_cdc_CfgDesc该描述符包含所有的,包括配置描述符,接口描述符,端点描述符等。
            关于描述符,只需写好这两个就能枚举成功,且正常使用。
枚举大致中断过程
调用初始化函数后,然后等待中断
插入USB线(假设上位机驱动程序已安装好),会产生端点0中断,按默认地址通信。
中断查询设备描述符,由于早指定好了,所以会直接回复usbd_desc.c文件的USBD_DeviceDesc结构。
设置USB设备地址。
中断查询配置描述符,由于早指定好了,所以会直接回复usbd_cdc_core.c文件的usbd_cdc_CfgDesc结构。
由于USB通信主动权在主机,这样主机要什么我们就回复什么,由于早指定好了,在不知不觉中就完成了,期间可能出现,主机由于不知道描述符多长,那么第一次要前8个字节,然后再根据长度再获取一次全部要,通过监听通信,有时候出现来回几次要描述符,这都是正常的。
数据长度,及传输大致过程
端点最大长度,full模式为8、16、32、64,高速为512.
库里有个问题就是吧cdc数据包长度也设为64,那么每次通信最大为64了。
#define CDC_DATA_MAX_PACKET_SIZE       64 /* Endpoint IN & OUT Packet size */
#define CDC_DATA_OUT_PACKET_SIZE   CDC_DATA_MAX_PACKET_SIZE
我改掉了,就是用户不管底层每次传多少,不能限制我传输字节的数量,改为
   #define CDC_DATA_OUT_PACKET_SIZE   4096
           这样,我使用接收时,准备接收设置为:
  DCD_EP_PrepareRx(pdev, epnum,//CDC_OUT_EP1,
                   (uint8_t*)(USB_Rx_Buffer2),
                   CDC_DATA_OUT_PACKET_SIZE);
等接到4096或上位机发送一帧完成后才产生一次中断,而不是接收64字节就产生一次中断;这样收到一帧就是上位机发送的完整帧,就可以给应用层处理了
对于IN事物,可以直接调用
   DCD_EP_Tx (pdev,epnum,   (uint8_t*)USB_Tx_Buffer2,    USB_tx-len);
   发送任意长度数据。

使用者需要关心或修改的地方
STM32最恶心的地方就是很多硬BUG。
首先就是STM32F439声称可以达到180M,但180M情况下不能分配出USB工作所需的48M 时钟,智能配置为168M,开始没注意,USB运行不稳定。
USB_OTG全速接口有问题,勘误手册里写的很明白,如果不看,就被坑,我就被坑了,手册给出的解决方法是,用高速接口的全速模式代替全速接口,也就是说画pcb前我们就应该知道,所以我现在板子还飞线呢!!!
而高速接口你要看明白,不能直接用的,要外边接片子才能用,有没有让他给骗的,说这个片子有高速接口就这么画上了。
对于这个库的使用,需要修改地方
主程序调用USBD_Init函数
修改设备描述符
修改配置描述符
看看中断服务程序定义没
如果需要修改用户回调函数
收数据在usbd_cdc_DataOut中,这是中断,可以给应用程序提示受到数据。
发数据任何地方调用DCD_EP_Tx。如果定时发研究下usbd_cdc_SOF,这个每1毫秒执行一次,你可以随便干什么,当定时器的话不太准;如果连续发可以研究下usbd_cdc_DataIn,这是发送完成进的中断。无要求的话只用DCD_EP_Tx一般也没问题,也就发出去了。
不要怀疑每1毫秒中断一次的USB_SOF会影响我们的效率,每次中断假设1000个时钟周期,那么就是1M时钟周期每秒,我们主频是168M,怕什么。
发送数据时,最好主机已经准备接收了,如果没准备好,就会出现返回nak,那么单片机会不停的发送,这会影响效率,所以上位机要知道你让单片机发数据,那你就要尽快准备好(我试验是这样,但我自己觉得这样不太合理)。
由于IN事务是由上位机主动的,但单片机又没有上位机IN事务的中断,只有发送缓冲区空中断,也就是说这次发送要建立在上次传输完成缓冲区空基础上,那么第一帧单片机是怎么发的呢?是猜的上位机要数据的时间? 现在处理方法是,上位机用OUT事务告诉我,让单片机发送什么数据,然后单片机才开始发送,更像串口通信那样(这也是我觉得不够完美的地方,不知道是理解错了)
如果设备为从设备,且有自己的电源,那么USB插入电脑时,会枚举成功,但USB线拔下时,没有特殊中断,只有一个suspend中断,但不能作为拔出依据,别的情况也会产生这个中断,我的板卡拔下再次插入不进行枚举,然后屏蔽掉这段程序,就OK了,暂时这么解决了。DCD_HandleUSBSuspend_ISR();屏蔽掉睡眠和关时钟的程序。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
10条回答
ronic
1楼-- · 2019-12-12 11:35
lz提到的单片机不停发送的事情我也碰到,如果PC没有接收,单片机就挂住了。大概是在不停的发送。这个很郁闷,理论上搞个超时机制,不至于死在那里。另外我在打开0x82 endpoint的时候,发现PC主机只能发数据给stm32f4,但是无法读,也在测试。。。中
wdluo
2楼-- · 2019-12-12 17:31
ronic 发表于 2015-9-13 17:56
lz提到的单片机不停发送的事情我也碰到,如果PC没有接收,单片机就挂住了。大概是在不停的发送。这个很郁闷 ...

要解决单片机一直发数据的问题,可以考虑在PC端开启一个线程一直读数据,然后单片机就可以一直发送数据了
lyl520719
3楼-- · 2019-12-12 22:07
"USB"爱你不容易。
nianhua_m
4楼-- · 2019-12-13 01:06
 精彩回答 2  元偷偷看……

一周热门 更多>