面霸儿 2024-03-12 11:59 采纳率: 0%
浏览 34
已结题

STM32L4 USBD CDC-MSC组合设备类CDC_Transmit_FS发送问题

STM32USB库调用CDC_TransmitFS这个函数,只能在CDC_ReceiveFS回环中发送,在main中发送数据,cdc->TxState 这个标志一直是1,所以只成功调用了USBD_CDC_SetTxBuffer,但USBD_CDC_TransmitPacket、USBD_CDC_DataIn以及后续的CDC_TransmitCplt都无法调用。

看论坛有两个解决办法:1.放到和usb同优先级的中断里调用CDC_TransmitFS进行发送。只调用成功了2.`发送之前调用这个函数EP0_RxReady。 但两种方法都会导致程序卡死。

CDC_Receive_FS与CDC_Transmit_FS均在usbd_cdc_if.c中实现,CDC_Receive_FS中调用CDC_Transmit_FS则可以正常回环收发消息。

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);
  CDC_Transmit_FS(Buf, *Len);   /* +++lakun:将收到的数据在发回去 */
  return (USBD_OK);
  /* USER CODE END 6 */
}

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
}

  • 写回答

20条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-03-12 11:59
    关注
    获得0.60元问题酬金

    引自免费微信小程序:皆我百晓生

    针对STM32L4 USBD CDC-MSC组合设备类中CDC_Transmit_FS发送问题,你遇到的情况是无法在主循环(main)中成功调用该函数进行数据发送。从描述看,cdc->TxState标志一直为1,导致无法进入正确的传输状态并调用相关传输完成的回调函数。

    首先,我们需要理解CDC_Transmit_FS的工作原理和流程。当需要发送数据时,它首先检查当前传输状态(TxState),如果正在传输则返回BUSY状态。接着,设置待发送的数据缓冲区,并通过USBD_CDC_TransmitPacket触发USB数据包的发送。

    根据你的描述,尝试在与USB中断同优先级的任务或中断中调用CDC_Transmit_FS以及在发送前调用EP0_RxReady都会导致程序卡死,这可能是因为没有正确处理并发访问和同步问题。

    解决方案建议:

    1. 同步Tx状态:
      • 在调用CDC_Transmit_FS之前,确保TxState确实为空闲状态。可以在调用前添加一个等待机制,例如使用互斥量或者标志位来同步对TxState的访问。
    // 假设txSem是一个互斥量
    osSemaphoreWait(txSem, osWaitForever); // 等待获取互斥量,确保不与其他任务冲突
    if (hcdc->TxState == 0) {
        USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
        result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
        hcdc->TxState = 1; // 设置为传输状态
    }
    osSemaphoreRelease(txSem); // 释放互斥量
    
    // 在CDC_TransmitCplt回调函数中恢复TxState
    void CDC_TransmitCplt(void) {
        hcdc->TxState = 0;
        // 其他必要的处理...
    }
    
    1. 事件驱动方式:
      • 可以创建一个队列用于存放待发送的数据,然后在CDC_Receive_FS或其他USB中断服务例程中检查这个队列,并调用CDC_Transmit_FS发送数据。
    static uint8_t txQueue[QUEUE_SIZE][BUFFER_SIZE];
    static uint16_t txQueueHead, txQueueTail;
    
    // 添加数据到队列
    void EnqueueTxData(uint8_t* Buf, uint16_t Len) {
        memcpy(txQueue[txQueueTail], Buf, Len);
        txQueueTail = (txQueueTail + 1) % QUEUE_SIZE;
        // 如果队列为空,则触发发送
        if (txQueueHead == txQueueTail) {
            CDC_TransmitFromQueue();
        }
    }
    
    // 从队列中取出数据并发送
    void CDC_TransmitFromQueue() {
        if (txQueueHead != txQueueTail) {
            uint8_t* Buf = txQueue[txQueueHead];
            uint16_t Len = BUFFER_SIZE;
            CDC_Transmit_FS(Buf, Len);
            txQueueHead = (txQueueHead + 1) % QUEUE_SIZE;
        }
    }
    
    // 在CDC_Receive_FS或其他适当位置调用EnqueueTxData
    CDC_Receive_FS(...) {
        ...
        EnqueueTxData(Buf, *Len);
        ...
    }
    

    以上代码仅为示例,实际应用时请根据项目的具体RTOS环境和需求进行调整。此外,请确保已正确初始化USB堆栈,并且CDC相关的回调函数如USBD_CDC_DataInCDC_TransmitCplt等已被正确注册和实现。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 3月20日
  • 创建了问题 3月12日

悬赏问题

  • ¥50 C++使用TWAIN协议如何实现A3幅面扫描仪扫描A4横向
  • ¥15 如何在sql server里完成筛选
  • ¥15 请问为什么我配置IPsec后PC1 ping不通 PC2,抓包出来数据包也并没有被加密
  • ¥200 求博主教我搞定neo4j简易问答系统,有偿
  • ¥15 nginx的使用与作用
  • ¥100 关于#VijeoCitect#的问题,如何解决?(标签-ar|关键词-数据类型)
  • ¥15 一个矿井排水监控系统的plc梯形图,求各程序段都是什么意思
  • ¥50 安卓10如何在没有root权限的情况下设置开机自动启动指定app?
  • ¥15 ats2837 spi2从机的代码
  • ¥200 wsl2 vllm qwen1.5部署问题