STM32 USB CDC 长包接收

Posted

技术标签:

【中文标题】STM32 USB CDC 长包接收【英文标题】:STM32 USB CDC Long packet receive 【发布时间】:2020-12-25 00:16:57 【问题描述】:

我需要将数据从 PC 发送到我的 STM32F3,所以我决定在 uC 中使用内置 USB。 但现在我有一个问题——我想一次向 stm32 发送大量数据——我的意思是 200-500 字节。

当我从 PC 发送带有少于 64 个图表的 minicom 数据包时 - 一切都很好 - 回调 CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) 发生一次 - 它启用 UsbRxFlag,只是为了通知正在运行的程序有数据可用。

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)

  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  if( (Buf[0] == 'A') & (Buf[1] == 'T') )
      GPIOB->BSRR = (uint32_t)RX_Led_Pin;
      UsbRxFlag = 1;
  

  return (USBD_OK);
  /* USER CODE END 6 */

但是当我尝试向 uC 发送更多数据(只是来自 minicom 的长文本)时,会发生一些奇怪的事情 - 有时 uC 根本没有反应 - 有时它没有考虑某些数据。

如何处理通过 USB-CDC 向 STM32F3 发送超过 64 字节的数据?

【问题讨论】:

旁白:(Buf[0] == 'A') & (Buf[1] == 'T') 通常写成(Buf[0] == 'A') && (Buf[1] == 'T'),但在这里并没有真正的功能差异。 &&&. 【参考方案1】:

全速 USB 通信的最大数据包长度为 64 字节。因此数据将以 64 字节的块传输,需要在另一端重新组装。

USB CDC 基于批量传输端点并实现数据流(也称为管道),而不是消息流。它基本上是一个字节流。因此,如果您发送 200 个字节,不要指望 200 个字节在哪里结束。此类信息不会被传输。

您的代码看起来有点可疑:

Reinstate Monica 指出,您可能指的是“&&”而不是“&”。 除非您更改缓冲区,否则USBD_CDC_SetRxBuffer 只需要在初始化时调用一次。 调用CDC_Receive_FS时,已经收到了一个数据包。 Buf 将指向您使用 USBD_CDC_SetRxBuffer 指定的缓冲区。 Len 提供数据包的长度。所以你要做的第一件事就是处理接收到的数据。处理完数据并且可以再次重用缓冲区后,您将调用USBD_CDC_ReceivePacket 以指示您已准备好接收下一个数据包。所以将USBD_CDC_SetRxBuffer 移动到另一个函数(除非你想使用多个缓冲区)并将USBD_CDC_ReceivePacket 移动到CDC_Receive_FS 的末尾。

函数调用的错误顺序可能会导致接收到的数据在您仍在处理时被覆盖。

但最大的问题可能是,如果您发送的是单件,那么您可能希望整个数据以单件的形式接收,或者它至少包含一段结束的指示。事实并非如此。您必须自己实现。

如果您使用的是文本协议,则可以缓冲所有传入数据,直到检测到换行为止。那你就知道你有一个完整的命令,可以执行了。

【讨论】:

您好 Codo,感谢您的回复。 USBD_CDC_SetRxBuffer 的代码是由 CubeMX 生成器生成的。我是否正确理解 - USBD_CDC_ReceivePacket(&hUsbDeviceFS) 是一个在程序准备好接收新数据包时应该调用的函数?告诉我,如果我可以使用 Len 显示接收到多少数据,为什么我必须使用换行符? 批量端点实现数据流,而不是基于消息或数据包的协议。在发送端,数据包可以以发送者认为最佳的任何方式组合或拆分。事实上,Windows、Linux 和 macOS 都会合并数据,超过 64 字节就得拆分。例如。如果您连续发送 10 次 10 个字节,则前 10 个字节可能会立即发送,而其余的会被合并,然后分成 64 个字节的块和另一个 26 个字节的块。【参考方案2】:

以下是用于读取任意数量字节的通用实现:https://github.com/philrawlings/bluepill-usb-cdc-test。

完整代码有点太长,无法在此处发布,但这实质上修改了usb_cdc_if.c 以创建一个循环缓冲区并公开其他功能(CDC_GetRxBufferBytesAvailable_FS()CDC_ReadRxBuffer_FS()CDC_FlushRxBuffer_FS()),这些功能可以从@ 使用987654326@。主页上显示的 readme.md 文本描述了所需的所有代码更改。

正如@Codo 所提到的,您需要在源数据中添加终止字符,或者在开头包含一个“长度”值(它本身是一个固定的字节数),然后指示有多少字节是在数据负载中。

【讨论】:

以上是关于STM32 USB CDC 长包接收的主要内容,如果未能解决你的问题,请参考以下文章

STM32 USB CDC Rx 中断

为啥 USB CDC 在接收数据时会挂起?

STM32F0 USB CDC_Init_FS() 和 CDC_Receive_FS() 使用 CubeMX

STM32F4:使用 FatFs 和 USB 的 SD 卡失败

stm32 usb数据接收与数据发送程序流程分析

ESP32 usb to STM32 USB cdc 模式 - USB to USB