WilmerSit 2024-08-09 16:13 采纳率: 0%
浏览 234
已结题

CDC_Transmit_FS发送问题

芯片: stm32f429zgt6
stm32cube: 1.14.1

使用cube自动生成usb_otg_fs代码

img

未作任何修改,仅将接收函数与发送函数加以应用,下载到板子能收也能发,但是有个问题,上位机通过串口读取数据,多次来回会出现板子发送不出数据但是能正常接收,断点调试也显示ok, 但是上位机未显示数据(上位机没问题,通过多个第三方串口发送也是如此),再次发送后,板子会将上次的数据返回,并没有返回此次应该返回的数据,待下次发送才返回(或者多次未返回,后续一次性返回多个数据,但存在丢失部分),如此出现交错帧,错过几次之后就再也无法发出数据,但接收依然正常,收取与发送均不超过64字节,如果由单片机主动单方向一直发送也不会有问题。

主函数轮询读取环形队列接收的数据,并解析,通过发送函数返回数据

//发送函数
static int usb_send(int32_t inode, const void *pbuf, int32_t length, int32_t offset)
{
    if (USB_INODE != inode)
        return -1;
    memcpy(s_tx_buf_temp, pbuf, length);
    CDC_Transmit_FS(s_tx_buf_temp, length);
    return 0;
}
//接收函数,丢到环形队列,由外部函数解析对应帧
int8_t CDC_Receive_FS(uint8_t *Buf, uint32_t *Len)
{
    uint32_t wr_index = 0;
    static uint32_t rd_index = 0;

    memcpy(&s_rx_buf_temp[rd_index], Buf, *Len);
    
    wr_index = rd_index + *Len;
    
    if (wr_index == rd_index)
    {
        return -1;
    }
    else if (wr_index > rd_index)
    {
        ring_fifo_put(&s_rxfifo, &s_rx_buf_temp[rd_index], wr_index - rd_index);
    }
    else
    {
        ring_fifo_put(&s_rxfifo, &s_rx_buf_temp[rd_index], USB_RX_SIZE - rd_index);
        ring_fifo_put(&s_rxfifo, s_rx_buf_temp, wr_index);
    }
    rd_index = wr_index % USB_RX_SIZE;  // 更新 rd_index,确保在环形缓冲区内循环

    /* USER CODE BEGIN 6 */
    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);
    return (USBD_OK);
    /* USER CODE END 6 */
}
  • 写回答

1条回答 默认 最新

  • 清水白石008 2024-08-12 06:03
    关注
    🕒上午好,题主!目前:🟢[在线]
    📢参考GPT-4o mini 模型、由清水白石008整理提供!
    📣今日金句:人必須相信自己,這是成功的秘訣。
    

    在使用 STM32F429ZGT6 和 USB OTG FS 进行 USB CDC 通信时,您遇到的问题是上位机无法接收到数据,且出现了数据交错和丢失的现象。根据您提供的代码和描述,以下是一些可能的原因和解决方案:

    1. 确保 USB 传输的正确性

    • USB 传输缓冲区:确保在发送数据时,USB 传输缓冲区没有被覆盖。CDC_Transmit_FS 函数是异步的,可能在数据发送完成之前就返回了。确保在发送新数据之前,前一个数据包已经完全发送。

    • 检查返回值CDC_Transmit_FS 函数的返回值可以用来判断数据是否成功发送。您可以在发送函数中添加对返回值的检查:

      uint8_t result = CDC_Transmit_FS(s_tx_buf_temp, length);
      if (result != USBD_OK) {
          // 处理发送失败的情况
      }
      

    2. 确保环形缓冲区的正确性

    • 环形缓冲区的读写指针:在接收函数中,确保读写指针的更新是正确的。您在接收函数中使用了 rd_indexwr_index,请确保它们的更新逻辑没有问题。

    • 环形缓冲区溢出:检查环形缓冲区是否有溢出情况。您可以在写入数据之前检查缓冲区的剩余空间,确保不会覆盖未读的数据。

    3. 处理接收数据的逻辑

    • 解析数据的时机:确保在接收到数据后,及时解析并处理数据。如果处理数据的逻辑较慢,可能会导致接收缓冲区溢出。

    • 避免阻塞:在解析数据时,避免长时间阻塞。可以考虑使用定时器或中断来处理数据解析,以确保接收数据的及时性。

    4. USB CDC 相关设置

    • USB CDC 配置:确保 USB CDC 的配置正确,包括波特率、数据位、停止位等设置。与上位机的配置必须一致。

    • USB 设备状态:在调试时,检查 USB 设备的状态,确保设备处于正确的工作状态。可以使用 USB 监控工具(如 USBlyzer 或 Wireshark)来监控 USB 数据流。

    5. 调试和日志

    • 添加调试信息:在发送和接收函数中添加调试信息,记录发送和接收的数据长度、内容等,以便于分析问题。

    • 使用逻辑分析仪:如果可能,使用逻辑分析仪监控 USB 数据线,查看实际发送和接收的数据,帮助定位问题。

    6. 代码示例调整

    以下是对您发送和接收函数的简单调整示例:

    // 发送函数
    static int usb_send(int32_t inode, const void *pbuf, int32_t length, int32_t offset)
    {
        if (USB_INODE != inode)
            return -1;
    
        // 确保长度不超过缓冲区大小
        if (length > sizeof(s_tx_buf_temp)) {
            return -1; // 错误处理
        }
    
        memcpy(s_tx_buf_temp, pbuf, length);
        uint8_t result = CDC_Transmit_FS(s_tx_buf_temp, length);
        return (result == USBD_OK) ? 0 : -1; // 返回发送结果
    }
    
    // 接收函数
    int8_t CDC_Receive_FS(uint8_t *Buf, uint32_t *Len)
    {
        uint32_t wr_index = 0;
        static uint32_t rd_index = 0;
    
        memcpy(&s_rx_buf_temp[rd_index], Buf, *Len);
        wr_index = rd_index + *Len;
    
        // 检查环形缓冲区溢出
        if (wr_index >= USB_RX_SIZE) {
            return -1; // 溢出处理
        }
    
        ring_fifo_put(&s_rxfifo, &s_rx_buf_temp[rd_index], *Len);
        rd_index = wr_index % USB_RX_SIZE; // 更新读指针
    
        // 重新设置接收缓冲区
        USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
        USBD_CDC_ReceivePacket(&hUsbDeviceFS);
        return USBD_OK;
    }
    

    总结

    通过以上步骤和建议,您应该能够定位并解决 STM32 USB CDC 通信中出现的问题。确保发送和接收的逻辑清晰,避免缓冲区溢出和数据交错。如果问题仍然存在,建议逐步调试并记录数据流,以便更好地理解问题的根源。希望这些信息能帮助您解决问题!

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月16日
  • 创建了问题 8月9日