news 2026/9/19 3:21:17

ESP32-S2/S3 USB Host 多媒体流驱动 usb_stream 使用指南:UVC 摄像头与 UAC 音频的读、写与控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ESP32-S2/S3 USB Host 多媒体流驱动 usb_stream 使用指南:UVC 摄像头与 UAC 音频的读、写与控制

ESP32-S2/S3 USB Host 多媒体流驱动 usb_stream 使用指南:UVC 摄像头与 UAC 音频的读、写与控制

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

导读

usb_stream是 ESP-IoT-Solution 仓库中基于 ESP32-S2/ESP32-S3 USB Host 能力的 UVC + UAC 主机驱动组件,用于从 USB 外设读取、写入和控制多媒体数据流。它同时支持一路 UVC 摄像头视频流、一路 UAC 麦克风输入流和一路 UAC 扬声器输出流。阅读本文后,你将掌握该组件的硬件选型要求、UVC/UAC 配置参数含义、完整的初始化与启动调用流程、流控(挂起/恢复、音量/静音)用法,以及 ESP32-S2 ECO0 芯片上的 SPI 屏幕抖动问题与软件规避方案。

组件概述与核心特性

usb_stream是一个位于 components/usb/usb_stream 的独立组件,通过 ESP32-S2/ESP32-S3 的 USB-OTG 外设以主机(Host)身份驱动外接 USB 设备。它面向三类多媒体设备:

  • UVC(USB Video Class)摄像头:通过 UVC Stream 接口获取 MJPEG 视频流,同时支持等时(Isochronous)和批量(Bulk)两种传输模式;
  • UAC(USB Audio Class)麦克风:通过 UAC Stream 接口接收音频采样数据(IN 流);
  • UAC 扬声器:通过 UAC Stream 接口发送音频数据(OUT 流),并可通过 UAC Control 接口控制音量、静音等特性。

从组件源码看,其能力还包括:

  1. 自动解析设备的配置描述符(Configuration Descriptor),按用户参数自动匹配接口、端点与格式;
  2. 支持 UVC/UAC 各路数据流分别挂起(suspend)与恢复(resume);
  3. 提供描述符打印、USB 枚举失败重试、任务优先级/核心/栈大小可配置(见 components/usb/usb_stream/Kconfig);
  4. 内部采用 FreeRTOS 任务 + Ringbuffer + URB 队列的流水线架构(见 usb_stream.c)。

注意:按 README.md 的说明,对于 ESP-IDF V5.3.3 及以上版本,如果启用 UVC,建议同时开启Component config → USB-OTG → Hardware FIFO size biasing中的Bias IN选项,以确保等时传输 FIFO 容量足够。

硬件与设备选型要求

开发板

任何带有 USB Host 口的 ESP32-S2 / ESP32-S3 开发板均可使用,但该 USB 口必须能够向外输出 5V 电压,因为绝大多数 USB 摄像头、USB 耳机、USB 声卡需要总线供电。

UVC 摄像头要求

  • 摄像头必须兼容USB 1.1 Full-Speed(全速)模式
  • 摄像头必须自带MJPEG硬件压缩输出(ESP32 侧不进行 JPEG 编码);
  • 用户可以通过uvc_streaming_config手动指定摄像头接口号、传输模式(等时/批量)和图像帧参数;
  • 等时传输模式:接口的最大包大小(Max Packet Size, MPS)应不超过 512 字节;图像数据流 USB 传输总带宽应小于4 Mbps(500 KB/s)
  • 批量传输模式:图像数据流 USB 传输总带宽应小于8.8 Mbps(1100 KB/s),批量模式可支持更高的带宽上限;
  • 其它特殊摄像头的兼容性要求,请参考示例程序的 README。

UAC 设备要求

  • 音频功能必须兼容UAC 1.0 协议(Audio Class 1.0,即全速等时音频);
  • 用户需要通过uac_streaming_config手动指定扬声器/麦克风的采样率、位宽等参数。

UVC 与 UAC 同时使用

  • UVC 和 UAC 功能可以单独启用:例如只配置 UAC 驱动一个 USB 耳机/音箱,或只配置 UVC 驱动一个 USB 摄像头;
  • 如需同时启用 UVC + UAC,当前驱动仅支持同时含有摄像头与音频接口的复合设备(Composite Device),不支持分别连接两个独立设备(一台摄像头 + 一台声卡)的组合。

快速接入与示例工程

通过组件管理器添加依赖

在任意 ESP-IDF 工程中使用组件管理器添加依赖,CMake 阶段会自动下载该组件:

idf.py add-dependency "espressif/usb_stream=*"

从示例模板创建工程

组件注册表提供了三个官方示例(与本仓库 examples/usb/host 下的工程对应),可用以下命令从模板创建:

# USB 摄像头 + 麦克风 + 扬声器(USB Camera + Audio,含 Web 控制台) idf.py create-project-from-example "espressif/usb_stream=*:usb_camera_mic_spk" # USB 摄像头本地 LCD 显示 idf.py create-project-from-example "espressif/usb_stream=*:usb_camera_lcd_display" # USB 音频播放器 idf.py create-project-from-example "espressif/usb_stream=*:usb_audio_player"

示例下载到当前目录后,即可进入目录编译烧录。若执行create-project-from-example时报CMakeLists.txt not found in project directory错误,说明 idf-component-manager 版本过旧,请先在 ESP-IDF 环境中执行pip install -U idf-component-manager升级。

示例工程结构(以 usb_camera_mic_spk 为例)

仓库内的 examples/usb/host/usb_camera_mic_spk 是一个浏览器 Web 控制的 AV 演示工程,其main目录划分清晰:

  • main.c:应用入口;
  • app_usb_host.c/.h:初始化 USB Host,并通过fifo_settings_custom自定义 DWC 硬件 FIFO 分配(解决高采样率 UAC 端点 MPS 超限问题);
  • app_uvc_manager.c/.h:UVC 摄像头配置、分辨率选择与预览;
  • app_uac_manager.c/.h:UAC 麦克风/扬声器格式选择、静音、音量控制;
  • app_web.c/.happ_wifi.c/.h:SoftAP(默认 SSIDUSB-AV-DEMO)与 Web 控制台。

编译命令为:

idf.py set-target TARGET # esp32s2 / esp32s3 / esp32p4 等 idf.py -p PORT flash monitor

提示:在该示例的 README 中说明,若日志出现EP MPS exceeds supported limit(端点 MPS 超过当前 FIFO 配置上限导致ESP_ERR_NOT_SUPPORTED),需要针对目标设备调整fifo_settings_custom或选择较低带宽的 UAC 格式。

配置参数详解

UVC 配置结构 uvc_config_t

uvc_config_t uvc_config = { .frame_width = 320, // mjpeg 图像宽度像素,例如 320 .frame_height = 240, // mjpeg 图像高度像素,例如 240 .frame_interval = FPS2INTERVAL(15), // 帧间隔(100µs 单位),例如 15fps .xfer_buffer_size = 32 * 1024, // 单帧图像大小,需按实际测试确定,320*240 一般小于 35KB .xfer_buffer_a = pointer_buffer_a, // USB 传输内部缓冲区 A .xfer_buffer_b = pointer_buffer_b, // USB 传输内部缓冲区 B(双缓冲) .frame_buffer_size = 32 * 1024, // 单帧图像缓冲大小,需按实际测试确定 .frame_buffer = pointer_frame_buffer, // 图像帧缓冲 .frame_cb = &camera_frame_cb, // 摄像头回调,可在其中阻塞 .frame_cb_arg = NULL, // 摄像头回调参数 };

各字段含义与约束(依据 components/usb/usb_stream/include/usb_stream.h):

字段含义说明
frame_width/frame_height期望图像宽高(像素)可设为FRAME_RESOLUTION_ANY__UINT16_MAX__)匹配任意分辨率
frame_interval帧间隔(100ns 单位)用宏FPS2INTERVAL(fps)转换,如FPS2INTERVAL(15)表示 15fps;源码同时提供FRAME_INTERVAL_FPS_5/10/15/20/30等预设宏
xfer_buffer_size单块传输缓冲大小必须大于一帧图像大小;内部使用双缓冲(A/B)交替接收
xfer_buffer_a/b传输缓冲区指针建议使用MALLOC_CAP_DMA内存(参考测试代码heap_caps_malloc(..., MALLOC_CAP_DMA)
frame_buffer_size/frame_buffer帧缓冲大小与指针用于拼装完整 MJPEG 帧
frame_cb/frame_cb_arg帧回调与参数新帧就绪后触发,回调运行在独立任务上下文,允许阻塞(如解码、送显)
xfer_type(可选)传输模式UVC_XFER_ISOC(等时)或UVC_XFER_BULK(批量),多数摄像头为等时模式,批量模式带宽更高
format_index/frame_index(可选)格式索引 / 帧索引用于跳过描述符解析直接指定
interface/interface_alt(可选)流接口号 / 备用接口号备用接口用于选择 MPS,批量模式固定为 0
ep_addr/ep_mps(可选)端点地址 / 端点 MPS跳过描述符解析时手动指定
flags(可选)行为控制标志支持FLAG_UVC_SUSPEND_AFTER_START(启动后立即挂起 UVC)等

从 test_apps/main/test_usb_stream.c 可以看到,传输缓冲区按目标芯片区分大小:ESP32-S2 为 45KB、ESP32-S3 为 55KB,且要求xfer_buffer_size >= frame_buffer_size

UAC 配置结构 uac_config_t

uac_config_t uac_config = { .mic_bit_resolution = 16, // 麦克风采样位宽,bit .mic_samples_frequence = 16000, // 麦克风采样率,Hz .spk_bit_resolution = 16, // 扬声器采样位宽,bit .spk_samples_frequence = 16000, // 扬声器采样率,Hz .spk_buf_size = 16000, // 扬声器发送缓冲大小,需为 spk_ep_mps 的整数倍 .mic_buf_size = 0, // 麦克风接收缓冲大小,不使用为 0;否则需为 mic_min_bytes 的整数倍 .mic_cb = &mic_frame_cb, // 麦克风回调,禁止阻塞! .mic_cb_arg = NULL, // 麦克风回调参数 };

关键字段补充说明(同样以头文件为准):

  • spk_ch_num/mic_ch_num:扬声器/麦克风通道数,可设UAC_CH_ANY(0)匹配任意通道数;
  • mic_bit_resolution/spk_bit_resolution:位宽,可设UAC_BITS_ANY__UINT16_MAX__)匹配任意位宽;
  • mic_samples_frequence/spk_samples_frequence:采样率,可设UAC_FREQUENCY_ANY__UINT32_MAX__)匹配任意采样率;
  • spk_buf_size:扬声器发送 Ringbuffer 大小,必须为 spk 端点 MPS 的整数倍
  • mic_buf_size:麦克风接收缓冲大小,0 表示不使用(配合uac_mic_streaming_read轮询),否则需为mic_min_bytes的整数倍;
  • mic_cb:麦克风数据回调,一定不能阻塞,否则影响后续帧的接收;
  • 可选项(mic_interface/mic_ep_addr/mic_ep_mpsspk_interface/spk_ep_addr/spk_ep_mpsac_interfacemic_fu_id/spk_fu_id):手动指定接口、端点与特性单元(Feature Unit)ID,用于跳过描述符解析以加快启动速度。

编程流程:配置 → 启动 → 回调 → 控制 → 停止

完整的使用流程如下(对应 usb_stream.h 的公开 API):

1. 配置驱动

  • 调用uvc_streaming_config(&uvc_config)配置 UVC 驱动(设备同时支持音频时);
  • 调用uac_streaming_config(&uac_config)配置 UAC 驱动。

普通使用场景只需指定上述"必选"参数,可选项置 0,驱动会从设备描述符中自动查找正确值;如需快速启动(Quick Start),则需手动指定全部参数以跳过获取与解析描述符的步骤。两个接口在数据流已运行时返回ESP_ERR_INVALID_STATE,参数非法返回ESP_ERR_INVALID_ARG

2. 启动数据流

esp_err_t usb_streaming_start(void);

调用后驱动会创建内部任务处理 USB 数据,并响应设备连接与协议协商。返回ESP_ERR_INVALID_STATE(未配置或已在运行)、ESP_FAIL(启动失败)或ESP_OK

可选地,可在启动前注册设备连接状态回调:

esp_err_t usb_streaming_state_register(state_callback_t cb, void *user_ptr);

回调在STREAM_CONNECTED/STREAM_DISCONNECTED时被调用(仅支持注册一个回调,后注册的覆盖先前的;需在启动前注册)。此外usb_streaming_connect_wait(timeout_ms)可阻塞等待设备连接。

3. 描述符匹配与回调触发

启动后,主机根据用户参数匹配已连接设备的描述符;设备不满足配置要求时,驱动会打印警告。匹配成功后,主机持续接收 IN 流(UVC 视频与 UAC 麦克风):

  • UVC 帧回调:每收到一帧完整 MJPEG 图像触发一次。回调运行在独立任务上下文(sample_proc),可以阻塞,例如在回调中执行 JPEG 解码或写入显示缓冲。测试代码中回调会打印frame_formatsequencewidthheightdata_bytes等信息;
  • UAC 麦克风回调:收到mic_min_bytes字节数据后触发,禁止阻塞,否则会影响下一帧接收;如需阻塞处理,应改用uac_mic_streaming_read轮询模式替代回调模式。

回调中的实际数据结构(见头文件):mic_frame_t携带datadata_bytesbit_resolutionsamples_frequence;UVC 回调帧包含frame_format(MJPEG 等)、sequencewidthheightdata_bytes

4. 发送扬声器数据(OUT 流)

esp_err_t uac_spk_streaming_write(void *data, size_t data_bytes, size_t timeout_ms);

用户将音频数据写入内部 Ringbuffer,主机在 USB 空闲时取出数据发送 OUT 流。Ringbuffer 满时返回ESP_ERR_TIMEOUT

5. 流控与音频控制

esp_err_t usb_streaming_control(usb_stream_t stream, stream_ctrl_t ctrl_type, void *ctrl_value);
  • streamSTREAM_UVCSTREAM_UAC_SPKSTREAM_UAC_MIC
  • ctrl_typeCTRL_SUSPEND/CTRL_RESUME(挂起/恢复,ctrl_value为 NULL)、CTRL_UAC_MUTE(静音,ctrl_value为 false/true)、CTRL_UAC_VOLUME(音量,ctrl_value为 0~100);
  • 若当前设备不支持该控制类型,返回ESP_ERR_NOT_SUPPORTED

音量/静音通过 UAC Control 接口的特性单元(Feature Unit)实现,源码中定义了UAC_FU_MUTE_CONTROLUAC_FU_VOLUME_CONTROL等控制选择子,并将音量范围映射到 0~100(见 usb_stream.c 中的UAC_SPK_VOLUME_MAX/MIN/STEP)。

在测试用例 test_usb_stream.c 的状态回调中可以看到典型组合用法:设备连接后先查询分辨率列表,再依次恢复 UVC/扬声器/麦克风流,然后设置扬声器和麦克风的静音与音量(CTRL_UAC_VOLUME传 30)。

6. 动态调整参数

  • uvc_frame_size_list_get/uac_frame_size_list_get:查询当前已连接设备的支持分辨率/音频格式列表(传 NULL 仅获取列表大小);
  • uvc_frame_size_reset(width, height, interval)/uac_frame_size_reset(stream, ch_num, bit_resolution, samples_frequence):在挂起状态下修改参数,恢复后生效。

7. 停止数据流

esp_err_t usb_streaming_stop(void);

停止后内部任务被删除,USB 资源(URB、管道、事件队列等)被完全释放,返回ESP_ERR_TIMEOUT表示停止等待超时。

Kconfig 可调参数

组件提供丰富的 menuconfig 选项(Component config → USB Stream,见 Kconfig),常用项如下:

配置项默认值说明
CTRL_TRANSFER_DATA_MAX_BYTES1024控制传输最大数据长度(64~2048 字节)
USB_STREAM_QUICK_STARTn快速启动模式,跳过描述符解析
UVC_PRINT_DESC/UVC_PRINT_DESC_VERBOSEy / n枚举时打印描述符信息 / 详细模式
USB_PROC_TASK_PRIORITY/CORE/STACK_SIZE5 / 按芯片 / 3072USB 处理任务优先级(1~25)、核与栈大小
USB_WAITING_AFTER_CONN_MS50设备连接后的枚举延时(ms)
USB_CTRL_XFER_TIMEOUT_MS1000控制传输超时(ms)
USB_ENUM_FAILED_RETRY/COUNT/DELAY_MSy / 10 / 200枚举失败重试开关、次数与间隔
SAMPLE_PROC_TASK_PRIORITY/CORE/STACK_SIZE2 / 0 / 3072UVC 帧处理任务配置(CORE 为 -1 时不绑定核)
UVC_CHECK_HEADER_EOFy校验 payload 头 EOF 位,确认整帧接收完成
UVC_DROP_NO_EOF_FRAME/UVC_DROP_OVERFLOW_FRAMEn / y丢弃无 EOF 帧 / 溢出帧
NUM_BULK_STREAM_URBS/NUM_BULK_BYTES_PER_URB2 / 2048批量模式 URB 数量与单次传输字节数
NUM_ISOC_UVC_URBS/NUM_PACKETS_PER_URB3 / 4等时模式 UVC URB 数量与每 URB 包数
NUM_ISOC_SPK_URBS/NUM_ISOC_MIC_URBS3 / 3扬声器/麦克风等时 URB 数量
UAC_MIC_CB_MIN_MS_DEFAULT16麦克风回调最小间隔(ms,1~32)
UAC_SPK_ST_MAX_MS_DEFAULT16扬声器单次最大发送时长(ms,1~32)
UAC_MIC_PACKET_COMPENSATIONn麦克风丢包时补数据
UAC_SPK_PACKET_COMPENSATION/CONTINUOUS/TIMEOUT_MS/SIZE_MSy / y / 80 / 10扬声器缓冲空时补零策略、持续补零、超时与补零时长

已知问题与规避方案:ESP32-S2 ECO0 SPI 屏幕抖动

在最早版本的 ESP32-S2(ECO0)芯片上,USB 传输可能污染 SPI 数据,导致 SPI 屏幕与 USB 摄像头同时工作时出现画面抖动。ESP32-S2 新版本(>=ECO1)以及 ESP32-S3 均不存在该 Bug。

软件规避方案如下(修改 IDF 内部文件,属于芯片级 workaround):

  1. components/hal/esp32s2/include/hal/spi_ll.h中新增查询发送 FIFO 计数函数:
static inline uint32_t spi_ll_tx_get_fifo_cnt(spi_dev_t *hw) { return hw->dma_out_status.out_fifo_cnt; }
  1. 修改spi_new_trans实现,在真正 kick off 传输前,等待数据确实已写入发送 FIFO,再启动传输:
// 该函数用于发送新事务,运行在 ISR 或任务中。 // 配置事务相关的寄存器和 DMA(或非 DMA 的 FIFO)使用的链表。 static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_t *trans_buf) { //................... spi_hal_setup_trans(hal, hal_dev, &hal_trans); spi_hal_prepare_data(hal, hal_dev, &hal_trans); //Call pre-transmission callback, if any if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans); #if 1 //USB Bug workaround while (trans->length && spi_ll_tx_get_fifo_cnt(SPI_LL_GET_HW(host->id)) == 0) { __asm__ __volatile__("nop"); __asm__ __volatile__("nop"); __asm__ __volatile__("nop"); } #endif //Kick off transfer spi_hal_user_start(hal); }

其原理是:在 USB 污染发生时,发送 FIFO 计数可能短暂为 0,此时忙等几个 NOP 周期让 FIFO 数据稳定后再启动 DMA 传输,从而避免 SPI 数据被 USB 传输干扰。

总结

usb_stream为 ESP32-S2/ESP32-S3 提供了一套完整的多媒体 USB Host 解决方案:一条 UVC 摄像头流 + 一条 UAC 麦克风流 + 一条 UAC 扬声器流可同时工作,支持等时/批量传输、描述符自动解析、分路挂起/恢复、音量与静音控制,并有配套的 Web 控制台示例、LCD 显示示例与音频播放示例。开发者只需配置uvc_config_t/uac_config_t结构体,按"配置 → 启动 → 回调处理 → 控制 → 停止"的流程调用 API,即可快速接入 USB 摄像头与音频设备;若使用早期 ESP32-S2 ECO0 芯片并配合 SPI 屏幕,可参考上文给出的软件规避补丁。

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 3:20:27

基于MATLAB的平行与垂直泊车路径规划仿真实现

泊车路线规划这个方向,我前前后后折腾了不少版本。最早是在MATLAB里跑通了一个平行泊车的圆弧规划,后来又补上了垂直泊车工况,两个程序放在一起,配合一份简单的参考说明,整个流程算是完整了。这次就把项目里的核心思路…

作者头像 李华
网站建设 2026/9/19 3:18:53

研发项目管理工具与模板:从选型到落地的最佳实践

简介:这份PPT课件以研发项目管理工具与模板为主题,面向研发项目经理、项目骨干以及企业研发管理推进者。内容从项目管理概述切入,系统讲解团队建设、需求管理、计划制定、质量管理和计划控制等关键环节,并引入研发管理成熟度模型&…

作者头像 李华
网站建设 2026/9/19 3:17:42

开放式蓝牙耳机怎么选?6款热门型号横评与避坑指南

关于开放式蓝牙耳机的选购,我最近被问到的频率实在太高了。从“跑步戴哪种不掉”到“上班戴哪种能听见同事说话”,几乎每个来问的朋友都带着一堆纠结。这类耳机确实是个特殊品类,它不像入耳式那样核心拼降噪,也不像头戴式那样拼音…

作者头像 李华
网站建设 2026/9/19 3:14:41

CSS圆锥渐变实现流光边框动画:conic-gradient与@property实战指南

前几天接了一个视觉稿,卡片四周要带一圈会流动的彩色渐变边框,设计师原话是“就一个流光描边,一下午能上吧”。我盯着那个匀速转圈的亮斑看了几秒,第一反应是交给 Canvas 或者 Lottie,但冷静下来之后意识到&#xff0c…

作者头像 李华
网站建设 2026/9/19 3:14:25

大华DH-EVS7064S-R网络视频存储服务器部署与RAID/iSCSI配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华