0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何让CDC类USB设备批量接收64字节以上数据

茶话MCU 来源:茶话MCU 作者:茶话MCU 2022-10-31 10:54 次阅读

很多STM32开发者在实现CDC类虚拟串口与PC主机通信过程中,有时会遇到点麻烦而不得其解。那就是当主机端单次发送的数据不超过64字节时,接收正常。一旦发送数据量大于64字节时就接收失败,总是出现丢包现象,似乎只能接收64字节以内的数据。网上有人干脆建议主机每次发送不要超过64字节,当然,也有人提及要作分包处理但没具体实现代码可以参考。

2af41bee-572c-11ed-a3b6-dac502259ad0.png

作为CDC类的USB设备,到底能不能正确接收来自主机64字节以上的批量数据呢?

其实是可以的,只是当我们一次传输的数据大于当前端点所支持的最大包长时【这里端点使用BULK传输,一般最大包长默认设置为64字节】,USB模块会做分包传输,将一批数据传输分成多个处理[或称事务],即多个transaction来完成,每个Transaction里的数据包传输的最大数据量为64字节。

2b16214e-572c-11ed-a3b6-dac502259ad0.png

原理性的东西,这里不多啰嗦了,网上有成堆的介绍资料【当然,或许有点乱】。当我们弄清整个原理后,就可以自行组织接收处理代码了。下面我利用HAL库,基于STM32F429芯片演示实现过程,重点在接收处理代码。我使用STM32F429Discovery开发板,使用HSUSB模块并令其工作在FSMODE,这样我们就可以方便地使用片内USBFS PHY。

2b888d4c-572c-11ed-a3b6-dac502259ad0.png

我使用STM32CubeMx工具进行配置,生成基于STM32 HAL库的工程。使用ST提供的STM32CubeIDE进行编译调试。有关配置就不截图了。

另外,我还配置了1个按键并开启相应外部中断。每发生按键事件时,F429USB设备向PC主机发送一段打招呼的字符串,并通过串口助手显示出来。如下图所示:

2bcd1674-572c-11ed-a3b6-dac502259ad0.png

我在main.c文件里额外定义了下面几个变量:

2bfc75f4-572c-11ed-a3b6-dac502259ad0.png

其中,Flag_KeyPressed和Flag_DataReceived分别表示按键操作和收到从主机发过来的数据的情况。Rx_buffer【】数组用来存放接收来自主机的全部数据,这里的定义长度为512字节【你具体使用时按需设置】。下图是Main.c里的主循环代码截图:

2c18ee14-572c-11ed-a3b6-dac502259ad0.png

主循环里检查按键标志和收到数据的标志,如有按键发生,则向主机发送前面提到的打招呼的字符串;如有收到来自主机的数据,则向主机回送过去。

今天的重点是讨论USB设备如何从主机接收64字节以上的数据。基于现有HAL库,对于USB设备的接收,我们只需关注一个USB中断接收回调函数,那就是CDC_Receive_HS()函数。该函数在usbd_cdc_if.c文件里。我具体编写的函数代码如下面两幅截图所示。

2c40952c-572c-11ed-a3b6-dac502259ad0.png

2c7e56e6-572c-11ed-a3b6-dac502259ad0.png

代码很简单。 我在库代码的基础上增加了橙色方框内的代码。基本功能就是,先读取当前收到的数据长度【SinglePackLength】,分整包和非整包两种情况鉴别后再处理。若是接收的整包数据,继续等待接收下一包;若是非整包,视为此次传输结束,并设置收到标志Flag_DataReceived为非0值,然后在主循环里将收到的数据回送给主机。

其中,Max_Pack_Size是当前CDC类BULK传输端点的最大传输包长,这里为64字节。

Num_Rx_Data表示接收到数据个数,Num_Out_Pack表示接收到的数据包个数,Num_Packet跟Num_Out_Pack内容一样,不过,Num_Packet等于0还表示准备开始新一轮传输的接收。这里多定义Num_Out_Pack,一个重要目的是便于调试时查看结果。

基于上面的接收处理代码,我们来验证结果:

2cdbacb0-572c-11ed-a3b6-dac502259ad0.png

借助PC端的串口助手向STM32F429 USB设备发送了5个字符,我们通过STM32CubeIDE调试环境可以清晰地从上图看到设备收到的数据个数为5,数据包个数为1。显然没问题。那个Rx_buffer数组是我用来存放接收数据的,若在调试窗口打开,数据较多列表显示会很长,这里就没打开了。事实上接收的数据内容也是没问题的。

下图是借助PC端的串口助手向STM32F429 USB设备发送了305个字符的接收情况:

2cfe83b6-572c-11ed-a3b6-dac502259ad0.png

显然,对于305个字符,PC主机端要分成5包才能发送完毕,即4整包【每包64字节】再加1个非完整包。所以USB设备接收结果也正好是5包,即上图中Num_Out_pack的数据,接收到的数据量为305,即上图中Num_Rx_Data的数据。同样,结果OK。

下图是PC端刚好发送一个完整包64字节数据的USB设备接收情况,也一切正常。

2d42e57e-572c-11ed-a3b6-dac502259ad0.png

也就是说,使用我上面编写的接收处理代码,对主机发送的数据的个数不再局限于64字节以内了。当然,具体应用时我们还可以根据主机端单次传输数据的大小情况及提取数据的方式适当调整这里的Rx_buffer[]数组大小。【注:上面测试时我临时关闭了设备端的数据回送功能,是为了避免截图里的数据混乱,让人分不清原数据和回显数据】

有人可能在上面的接收代码里看到了一个变量Wait_Rx_Dly。刚开始,代码里是没有这个变量的。后来我在测试主机发送64字节整包数据时,发现了一个小问题【最终到底算不算问题,或许要视具体应用场景而定,我这里稍作了点处理】。

问题是这样的:

主机每发送1包64字节数据时,设备端接收没有问题,但只要主机端每次发送64字节完整数据包过来,不论相隔时间多久,设备端依然接收,且总在前次结果上累加,除非主机端发一个非64字节数据包过来,设备接收就总是视为同一次传输。比方像下面截图所示:

2d76b58e-572c-11ed-a3b6-dac502259ad0.png

上图就是PC主机端借助串口助手分四次且每次发送64字节数据时USB设备的接收情况。从图上不难看出,4次数据都汇集在一起了,关键还没完,还在等待后续数据过来。我是希望一次传输做一次处理,于是我让设备每收到一个完整数据包,就重新给定一个延时,比方3~5ms,用变量Wait_Rx_Dly来记录延时值,在某毫秒定时中断里对该变量做减1操作。若延时到了还没有收到数据或延时过程中收到非完整包则视为本次传输结束,然后去处理刚才收到的数据。

2d9c6158-572c-11ed-a3b6-dac502259ad0.png

我顺便使用了HAL库里自带的systick中断函数来做这个延时管理。当接收处理代码加上这个延时管理后,就不会出现不同传输批次的数据挤在一块了。问题得以解决。

另外,我上面分享的接收处理代码也有很好的通用性,并不局限于Bulk传输。我们知道,不同传输类型的端点的最大包长往往并不一样,如果使用上面的参考代码,我们只需调整那个最大包长参数【Max_Pack_Size】,并适当调整Rx_buffer[]数组的大小就可以使用了。数据个数、传输包个数这些变量都可以保留使用。

那段接收处理代码很简单,看懂了都可以自行组织编写。顺便说下,我使用的STM32F4系列的Cube库版本为STM32F4xx HALV1.8.1。好,今天的话题就分享到这里,希望帮到有需要的人。祝君好运!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • usb
    usb
    +关注

    关注

    59

    文章

    7438

    浏览量

    258267
  • STM32
    +关注

    关注

    2240

    文章

    10675

    浏览量

    348866
  • CDC
    CDC
    +关注

    关注

    0

    文章

    55

    浏览量

    17685

原文标题:如何让CDC类USB设备批量接收64字节以上数据

文章出处:【微信号:stmcu832,微信公众号:茶话MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    H743zit6使用SPIDMA模式接收数据异常怎么解决?

    字节数据,用usb虚拟串口返回上位机(上位机显示一列20个字节)。此时无论接收多少次全为零,但波形是正确的。 调试模式下能接收到部分正确的
    发表于 03-15 06:01

    做STM32f103 USB双缓存的时候,发送4K数据里面前64字节是0,为什么?

    做STM32f103 USB 双缓存的时候, 采取ENP3的TXaddr1和TXaddr0的双缓存ping-pong发送机制,每次上位机接收完4K数据, 4K数据
    发表于 04-28 07:07

    在进行USB CDC开发时,无法发送64整数倍的数据

    ,就是是最多两包数据。如果需要发送超过127个字节时,又该如何做呢?查看USB协议栈内核代码,发现每次端点0发送数据时,在发送代码中固定每次最多可以传输
    发表于 03-28 13:30

    如何将配置端点缓冲区的大小配置为64字节

    你好,我在CyPress CY7C68013A高速控制器上工作。如何将配置端点缓冲区的大小配置为64字节(如全速),用于批量传输。我的主机还支持USB 2高速,但由于项目的典型性质,我
    发表于 05-09 16:07

    USBUART_PutData()不适用于64字节

    你好!我正在测试USB CDC示例项目,不能让它发送64字节数据,虽然这等于最大数据包大小,应
    发表于 06-21 11:37

    如何解决传输64字节字符串时USB UART出现的问题

    应该发送64字节数据包后发送10数据包长度。在PC的司机会知道该字符串只有在收到这个零长度数据包的接收
    发表于 07-18 14:57

    如何使用Encore II的64字节控制传输字节

    我在EnCORE 2中的USB组件控制端点大小只有8字节。在我的应用程序中,我需要传输64字节。如何做到这一点?控制端点是一个双向端点,它使用相同的缓冲器(UBSI接口
    发表于 08-13 09:38

    USB CDC吞吐量问题

    我从论坛上阅读CDC的所有内容中得知,我的申请应该只是学术性的,并且迟疑不决。我的实时要求是在250毫秒内传输115200字节(吞吐量460800字节/秒)。从PIC32到PC。客户需要他们的PC
    发表于 10-14 15:52

    USB CDC数据损坏:传输的32被接收为0

    是:.(!{发送4096字节数据到微告诉微写数据到闪存}数据被精确地写入闪存,因此我知道我的闪存可以,但是看起来发送值32(0x20)被接收
    发表于 10-21 14:14

    大于64字节传输的USB HID—描述符中要更改什么?

    ,如果需要的话,它将把一个事务分成多个64字节数据包。用这个?我仍然在Microchip应用程序库的版本2.9的USB堆栈上。谢谢。
    发表于 05-06 13:21

    CH573USB模拟串口的过程中,64字节数据无法发送至上位机怎么处理?

    CH573USB模拟串口,从上位机发送64字节长度的数据给CH573,然后CH573重新发送64字节
    发表于 07-01 07:25

    为什么我在512字节数据缓冲区传输数据却得到1536字节

    我正在使用 STM32L4R5ZI-P 开发板。我已将 USB 配置为仅具有 CDC 设备,其中 APP_TX_DATA_SIZE 为 2048,USBD_MAX_STR_DESC
    发表于 12-19 07:13

    为什么无法从PC接收超过64字节数据

    我正在全速模式下使用经过修改的 CDC USB 设备,但我无法从 PC 接收64 字节
    发表于 01-16 07:22

    rt1052的usb属于高速usb,hid设备最大不是可以支持到1024字节

    数据一包的大小才8个字节,后面我自己改成64字节,测试收发是可以的,但是我试着改成128字节,最终收发就有问题了 。rt1052的
    发表于 04-17 07:41

    H743zit6使用SPIDMA模式接收数据异常怎么解决?

    字节数据,用usb虚拟串口返回上位机(上位机显示一列20个字节)。此时无论接收多少次全为零,但波形是正确的。 调试模式下能接收到部分正确的
    发表于 08-05 07:52