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
相关产品推荐
相关产品推荐

