You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

STM32F743 USB麦克风传输异常问题排查求助

问题排查与解决方案

核心现象梳理

  • 基于无品牌STM32F743开发板,将USB音频扬声器示例改为麦克风输入,使用虚拟测试数据
  • 描述符替换后,USB Device Viewer识别正常
  • Wireshark捕获到URB_ISOCHRONOUS请求,但所有数据包长度为0
  • USBD_AUDIO_SOF()USBD_AUDIO_DataIn()未触发(UART调试无输出)
  • 首次调用USBD_LL_Transmit()返回USBD_OK,已禁用D-Cache和MPU,调整缓冲区内存分配无效

排查步骤与修复建议

1. 检查音频类同步端点描述符

确认IN方向同步端点的描述符配置无错误:

  • 端点方向必须设为IN(麦克风是设备向主机发送数据)
  • wMaxPacketSize需明确设置为96字节,若启用高带宽模式,需同步配置bIntervalwMaxPacketSize的高字节字段
  • 确保音频类AS InterfaceStreaming Interface描述符中,端点地址关联正确,无笔误

2. 验证回调函数注册逻辑

检查USBD_AUDIO_HandleTypeDef结构体中的回调指针是否正确绑定,避免被默认扬声器配置覆盖:

USBD_AUDIO_HandleTypeDef haudio = {
  .Init = { ... },
  .pClassData = ...,
  .SOFCallback = USBD_AUDIO_SOF,  // 确认此处未置空或被错误覆盖
  .DataInCallback = USBD_AUDIO_DataIn,  // 确认回调绑定有效
};

若使用CubeMX生成代码,需检查USBD_AUDIO_Init()函数中是否正确初始化了这些回调。

3. 调整同步传输启动逻辑

同步传输需在接口激活后循环触发,单次USBD_LL_Transmit()仅发送一次数据包:

  • USBD_AUDIO_SetInterface()回调中,当主机将音频流接口设为ACTIVE状态时,启动首次传输
  • USBD_AUDIO_DataIn()回调中,完成当前传输后立即启动下一次传输,维持数据流
    示例代码:
uint8_t USBD_AUDIO_SetInterface(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
  USBD_AUDIO_HandleTypeDef *haudio = (USBD_AUDIO_HandleTypeDef*)pdev->pClassData;
  if (haudio->state == AUDIO_STATE_ACTIVE) {
    // 启动首次同步传输
    USBD_LL_Transmit(pdev, AUDIO_IN_EP, haudio->buffer, 96);
  }
  return USBD_OK;
}

4. 确认缓冲区内存属性

即便禁用D-Cache,仍需确保缓冲区位于USB DMA可访问的非缓存内存区域

  • 使用__attribute__((section(".RAM_D2_DMA")))标记缓冲区,或直接分配在CubeMX配置的DMA专用内存区
  • 禁止使用栈内存作为USB传输缓冲区,必须用全局或静态内存
    示例:
static uint8_t audio_tx_buffer[96] __attribute__((section(".RAM_D2_DMA")));

5. 检查USB中断配置

确认USB OTG的关键中断已启用:

  • 在CubeMX中开启USB OTG全局中断、SOF中断、IN端点中断
  • 检查HAL_PCD_IRQHandler()函数是否正确处理SOF和IN端点完成事件,无中断屏蔽情况

6. 验证音频格式匹配性

确保主机请求的音频格式(采样率、位深、通道数)与设备端配置一致:

  • USBD_AUDIO_SetFormat()回调中打印主机请求参数,确认与96字节数据包对应的格式匹配(例如48kHz、16位单声道:48000*2/1000=96字节/帧)
  • 格式不匹配会导致主机不发送有效SOF请求,设备端无法触发回调

关键适配代码片段

/* SOF回调,用于调试确认触发状态 */
void USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev)
{
  printf("SOF Triggered!\r\n");
}

/* 数据发送完成回调,循环启动下一次传输 */
uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
  // 填充虚拟测试数据
  static uint8_t test_val = 0;
  for (int i=0; i<96; i++) {
    audio_tx_buffer[i] = test_val++;
  }
  // 启动下一次传输
  USBD_LL_Transmit(pdev, AUDIO_IN_EP, audio_tx_buffer, 96);
  printf("DataIn Triggered!\r\n");
  return USBD_OK;
}

内容的提问来源于stack exchange,提问作者Abrikos Kokos

火山引擎 最新活动