【极海APM32F407 Tiny Board】+3.枚举个UAC音频设备
[复制链接]
本文开始简单介绍一下,如何基于APM32F407 Tiny Board的OTG HS外设,在windows系统下进行一个UAC音频设备的枚举过程。
USB设备是一个很宽泛的概念,电脑、手机、PS5这些设备上最常见的就是USB接口了,可以接各种USB设备,但是具体划分下来,这些USB设备又分为HID、CDC、MSC、UAC、UVC等等,其中HID设备最常见的就是键盘、鼠标和手柄这些,CDC设备包括嵌入式开发中经常用到的USB转串口设备,MSC最常见的就是人手必备的U盘,UAC设备包括USB扬声器、USB耳机等,UVC设备则最常见的就是电脑通过USB接口外扩的USB摄像头。但是上面这几类并不是USB设备的所有种类,USB-IF(https://www.usb.org/defined-class-codes)网站列出了目前基本上所有的USB设备种类。
上面只展示了部分,具体可自行到USB-IF官网查看。对于USB耳机,现在也是越来越流行,前些年最为常见的就是3.5mm耳机,这种耳机属于模拟耳机,通过手机或PC上直接输出模拟(声音)信号给3.5mm耳机。而近些年,越来越多人追求更好的音质体验,USB耳机也越发流行,通过手机或PC端的USB接口输出数字信号(音频数据)到USB耳机上,经过耳机内自带的音频数据处理单元转换成模拟(声音)信号,客制化需求越来越多。
UAC设备,也有属于自己的小版本协议规范,包括UAC1.0,发布于1998年、UAC2.0,发布于2006年、UAC3.0,发布于2016年,目前最新的就是UAC3.0,后续只有一些关于此版本的修订补充。目前比较常用的应该是UAC1.0(根据我见到的,有哪些大佬见过UAC2.0设备的也可以讲讲,开开眼),UAC2.0在win10才开始支持,如果执意要开发UAC2.0设备,插到电脑上可能会出现各种兼容性问题,坑估计不少。本次先根据UAC1.0规范进行USB声卡枚举。
基础框架根据OTGD_HID_HS2官方例程,在此基础上进行更改。初步想法是,既然作为一个音频声卡设备,播放录音功能必然要有,同时也可以通过PC(Host)控制设备暂停播放等功能,设备也可以通过按键调低调高音量等,这个功能就需要HID参与。
在官方提供的USBD_Init函数基础上,重新更改为USBD_HS_Init函数,原有速度不变,依然为高速设备,描述符构建一个UAC描述符USBD_DESC_HS_UAC,涵盖了设备描述符、配置描述符、标准音频控制接口描述符、类特定音频控制接口头描述符、类特定音频控制输入终端描述符、类特定音频控制特性单元描述符、类特定音频控制输出终端描述符、标准音频流接口描述符、标准音频流同步音频数据端点描述符等等,这些描述符具体含义可以从UAC1.0规范文档中获得(文末为方便阅读,已将UAC1.0规范相关文档上传)。后面又构建了一个HID类的处理函数、一个UAC类的处理函数。
函数内部与官方函数基本无差异,只是增添了一个判断,用来判断当前处理的是HID类还是UAC类。对于USBD_HardwareInit中的内容,官方已将USB_OTG_HS相关寄存器配置好,初学者可不必过多关注,这个函数直接拿来用就好,只需要将自己需要实现的功能信息在USBD_HardwareInit之前赋值即可。
执行完USBD_HardwareInit之后,就开始枚举过程了,在OTG_HS1_IRQHandler中执行。
具体过程在USBD_SetupStage函数中进行,其中可通过recipient、reqType、request、reqWvalue、reqWLength、reqWIndex这些值来判断当前请求的类型,是标准请求还是类请求或者是厂商自定义请求等。
首先,根据recipient的值判断当前请求的接收者为设备、接口或端点,然后根据reqType判断当前的请求为标准请求、类请求或厂商自定义请求。当recipient的值对应为设备,reqType的值对应为标准请求,根据相应的请求通过USBD_StdDevReqHandler执行相应的回调函数,向Host返回相应的描述符或状态。
当recipient的值对应为接口,reqType的值对应为标准请求,根据相应的请求通过USBD_StdDevReqHandler执行相应的回调函数,向Host返回相应的描述符或状态;当reqType的值对应为类请求,通过usbInfo->classID判断当前为HID类请求还是UAC类请求,分别执行对应的回调函数,返回HID描述符、标准音频控制接口描述符、类特定音频控制接口头描述符、类特定音频控制输入终端描述符、类特定音频控制特性单元描述符、类特定音频控制输出终端描述符、标准音频流接口描述符、标准音频流同步音频数据端点描述符等。
分别构建一个hid和uac的c文件,用来处理HID类请求和UAC类请求,并返回对应的描述符。
处理UAC类请求的相关函数如图所示。枚举过程基本都在USBD_UAC_SetupHandler函数进行,后面涉及到音频播放会用到USBD_UAC_IsoOutIncompleteHandler和USBD_UAC_IsoInIncompleteHandler实现同步传输。
对于UAC类请求,USBD_UAC_SetupHandler函数里面更多的是关于静音、音量等等的一些设置,具体的其他延时、响度控制等可根据UAC1.0规范自行设置。
对于描述符部分,把相关描述符贴出来,过于繁多,不做过多解释,UAC1.0规范中已有详细解释。
此为设备描述符部分。
此为配置描述符,为UAC设备“是个什么样子”的核心。这个配置描述符对音频流数据采用PCM编码格式,使用UAC1.0规范。同时需要注意的是,一般情况下,端点描述符为固定7字节,但是在UAC和UVC设备中,端点描述符存在固定9字节的情况,网上对这个9字节解释非常少,最后还是通过UAC1.0规范中看到的,所以虽然全英,但是还是得啃。
最后,附上根据上面过程,实际抓取到的枚举过程的数据。
将开发板的USB口插到电脑上,此时在设备管理器应该会出现对应的音频设备。
对于VID和PID部分,均使用官方HID例程的,未做修改,与程序中所设一致。对于设备名称,也与程序中所设置一致。到此,已成功枚举出一个UAC声卡和UAC麦克风设备。
关于UAC设备中各种UAC类请求和音频控制描述符、音频流描述符,可以根据UAC1.0规范查到(已上传到文章底部),不做太多讲解,规范里面全英太多了(自己英语水平有限,翻译出来怕引人误解)。此外,文中可能部分注释未及时做修改,理解起来可能有偏差,仅供参考,后续会及时修改。
termt10.pdf
(44.23 KB, 下载次数: 3)
frmts10.pdf
(121.91 KB, 下载次数: 3)
audio10.pdf
(436.14 KB, 下载次数: 4)
|