You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F429ZIT6 USB CDC发送后TxState持续Busy问题求助

STM32F429 USB CDC TxState持续Busy问题排查与解决

核心问题定位

运行5-10分钟后TxState始终处于Busy状态,说明USB CDC的发送完成回调未被正确触发,或者回调中未完成TxState的重置,导致后续发送请求无法被处理。以下是针对性的排查和修复步骤:

1. 确保CDC发送完成回调正确实现

STM32 USBD CDC框架中,发送完成后会触发CDC_TransmitCplt_HS回调,必须在该函数中重置TxState,否则TxState会一直保持Busy状态。

添加或完善以下回调函数:

static int8_t CDC_TransmitCplt_HS(uint8_t *Buf, uint32_t *Len)
{
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceHS.pClassData;
  
  // 重置发送状态为空闲
  hcdc->TxState = 0;
  
  return USBD_OK;
}

同时,需要在USBD_CDC接口结构体中注册该回调,确保框架能正确调用:

USBD_CDC_ItfTypeDef USBD_Interface_fops_HS = {
  CDC_Init_HS,
  CDC_DeInit_HS,
  CDC_Control_HS,  
  CDC_Receive_HS,
  CDC_TransmitCplt_HS  // 必须添加这一行
};

2. 检查USB中断优先级配置

如果USB的TX完成中断被其他高优先级中断长期抢占,会导致发送完成回调无法及时执行,TxState无法重置。在CubeIDE中:

  • 进入Pinout & Configuration -> NVIC
  • 确保OTG_HS_IRQn的中断优先级不低于其他频繁触发的中断(比如定时器、UART等),建议配置抢占优先级为2-3,子优先级为0(根据系统实际中断情况调整)
  • 确保OTG_HS_IRQHandler函数正确实现:
void OTG_HS_IRQHandler(void)
{
  HAL_PCD_IRQHandler(&hpcd_USB_OTG_HS);
}

3. 验证发送缓冲区的有效性

发送数据时,CDC_Transmit_HS传入的Buf必须在整个发送过程中保持有效(直到发送完成回调触发)。如果Buf是临时栈变量或者被提前释放/覆盖,会导致USB传输出错,TxState卡住。

  • 确保发送心跳的缓冲区是全局变量或者静态变量:
// 全局或静态的心跳回复缓冲区
static uint8_t heart_beat_reply[14] = {0x01, 0x02, ...}; // 根据协议填充实际内容

// 在主函数中回复心跳时使用该缓冲区
CDC_Transmit_HS(heart_beat_reply, 14);

4. 完善发送错误的状态重置逻辑

在USBD_CDC_TransmitPacket返回错误时,强制重置TxState,避免单次发送失败导致状态永久卡住。修改CDC_Transmit_HS函数:

uint8_t CDC_Transmit_HS(uint8_t* Buf, uint16_t Len) {
  uint8_t result = USBD_OK;
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceHS.pClassData;
  
  if (hcdc->TxState != 0)
  {
    ZF_LOGE("Tx failed, resource busy\n\r"); 
    return USBD_BUSY;
  }
  
  USBD_CDC_SetTxBuffer(&hUsbDeviceHS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceHS);  
  
  // 发送失败时强制重置TxState,避免异常状态
  if (result != USBD_OK) {
    hcdc->TxState = 0;
    ZF_LOGE("TX failed, reset TxState\n\r");
  }
  
  ZF_LOGD("TX Message Result:%d\n\r", result);  
  return result;
}

5. 检查环形缓冲区的溢出保护

虽然接收功能正常,但长期运行下环形缓冲区若无溢出保护,可能导致内存 corruption,间接影响发送逻辑。确保ring_push函数有溢出判断:

// 修改ring_push函数,添加溢出处理
int ring_push(RingBuffer *buf, uint8_t *data) {
  if ((buf->head + 1) % buf->size == buf->tail) {
    // 缓冲区溢出,记录告警日志
    ZF_LOGE("RX Ring Buffer overflow\n\r");
    return -1;
  }
  buf->buffer[buf->head] = *data;
  buf->head = (buf->head + 1) % buf->size;
  return 0;
}

内容的提问来源于stack exchange,提问作者Roger Sacchelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:55:14