谷动谷力

 找回密码
 立即注册
查看: 1704|回复: 0
打印 上一主题 下一主题
收起左侧

灵动微课堂 基于MM32F0163D7P的USB Audio Class(UAC)音频设备

[复制链接]
跳转到指定楼层
楼主
发表于 2023-8-2 20:19:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2024-4-17 11:47 编辑

灵动微课堂  基于MM32F0163D7P的USB Audio Class(UAC)音频设备


1 TinyUSB(UAC)音频简介

UAC是USB Audio Class的缩写,USB音频类,一个像USB这样的通用数据接口,可以有很多种实现数字音频数据传输的方式。不同的开发者可以根据自己的喜好和需求,定义任意的控制方式,传输模式,音频格式等等参数。
在上一节我们在MM32F0163D7P 平台上成功的移植了TinyUSB,基于这个平台,今天我们来实现一个 uac2_headset 音频设备,这个设备支持基础的录音和放音功能,如果要支持音量调节/静音功能,还需要再添加一个 HID 变成复合设备。

2 快速移植一个UAC+HID复合设备

按照前面两篇文章,我们可以快速的移植出一个基于TinyUSB的UAC+HID复合设备,主要的代码片段如下:
  1. /*------------- MAIN -------------*/
  2. int main(void)
  3. {
  4.   USB_DeviceClockInit();//board_init();

  5.   CONSOLE_Init(460800);  //enable printf debug

  6.   // init device stack on configured roothub port
  7.   tud_init(BOARD_TUD_RHPORT);

  8.   TU_LOG1("UAC Headset & HID running\r\n");   // CFG_TUSB_DEBUG for debugging #if CFG_TUSB_DEBUG
  9. // 0 : no debug
  10. // 1 : print error
  11. // 2 : print warning
  12. // 3 : print info

  13.   while (1)
  14.   {
  15.     tud_task(); // TinyUSB device task
  16.     audio_task();
  17.     hid_task();
  18.   }

  19.   return 0;
  20. }

  21. #define EPNUM_AUDIO_IN    0x01
  22. #define EPNUM_AUDIO_OUT   0x01

  23. #define EPNUM_HID   0x03


  24. uint8_t const desc_configuration[] =
  25. {
  26.     // Interface count, string index, total length, attribute, power in mA
  27.     TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),

  28.     // Interface number, string index, EP Out & EP In address, EP size
  29.     TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80),

  30.     // Interface number, string index, protocol, report descriptor len, EP Out & In address, size & polling interval
  31.     TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 6, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10),

  32. };

  33. //--------------------------------------------------------------------+
  34. // String Descriptors
  35. //--------------------------------------------------------------------+

  36. // array of pointer to string descriptors
  37. char const* string_desc_arr [] =
  38. {
  39.   (const char[]) { 0x09, 0x04 },  // 0: is supported language is English (0x0409)
  40.   "TinyUSB",                      // 1: Manufacturer
  41.   "TinyUSB headset",              // 2: Product
  42.   "000001",                       // 3: Serials, should use chip ID
  43.   "TinyUSB Speakers",             // 4: Audio Interface
  44.   "TinyUSB Microphone",           // 5: Audio Interface
  45.   "TinyUSB HID",                  // 6: HID Interface
  46. };
复制代码

图1 枚举过程
图2 枚举设备
工程文件树:
  1. TinyUSB_UAC_HID
  2.     │
  3.     ├─USER
  4.     │       main.c
  5.     │       usb_descriptors.c
  6.     │       usb_dcd_port.c
  7.     │  
  8.     └─TinyUSB

  9.             tusb.c
  10.             audio_device.c
  11.             tud_fifo.c
  12.             usbd.c
  13.             usb_control.c
  14.             hid_device.c
复制代码

3 耳机设备设置修改音量

在耳机属性里面可以操作修改音量大小,同时通过抓包工具可以抓到主机下发的SET CUR命令。
图3 设置音量

4 耳机设备设置修改采样频率和位深度

在耳机属性高级里面默认格式可以看到下拉框有两种格式,一个是2通道 16位48000Hz,另外一个是2通道 24位 48000Hz,播放声音下发ISOC包的时候根据这个选择传输。
图4 设置采样频率和位深度

通过设置,下位机可以在播放或者录音时处理不同的采样频率和位深度。样例中全局变量current_resolution是位深度,current_sample_rate是采样频率。

5 音频数据的收发处理

播放时ISOC下发的数据包缓存在spk_buf里面。
录用时麦克风的声音采样数据写入mic_buf,通过ISOC同步上传到电脑端。(例程是将播放的数据包处理后通过接口又返回电脑端,由
  1. tud_audio_write((uint8_t *)mic_buf, (uint16_t) (spk_data_size / 2))实现)
  2. //--------------------------------------------------------------------+
  3. // AUDIO Task
  4. //--------------------------------------------------------------------+

  5. void audio_task(void)
  6. {
  7.   // When new data arrived, copy data from speaker buffer, to microphone buffer
  8.   // and send it over
  9.   // Only support speaker & headphone both have the same resolution
  10.   // If one is 16bit another is 24bit be care of LOUD noise !
  11.   if (spk_data_size)
  12.   {
  13.     if (current_resolution == 16)         
  14.     {
  15.       int16_t *src = (int16_t*)spk_buf;
  16.       int16_t *limit = (int16_t*)spk_buf + spk_data_size / 2;
  17.       int16_t *dst = (int16_t*)mic_buf;
  18.       while (src < limit)
  19.       {
  20.         // Combine two channels into one
  21.         int32_t left = *src++;
  22.         int32_t right = *src++;
  23.         *dst++ = (int16_t) ((left >> 1) + (right >> 1));
  24.       }
  25.       memset(mic_buf,0xCC,sizeof(mic_buf));  //mm32 test code
  26.       tud_audio_write((uint8_t *)mic_buf, (uint16_t) (spk_data_size / 2));
  27.       spk_data_size = 0;
  28.     }
  29.     else if (current_resolution == 24)
  30.     {
  31.       int32_t *src = spk_buf;
  32.       int32_t *limit = spk_buf + spk_data_size / 4;
  33.       int32_t *dst = mic_buf;
  34.       while (src < limit)
  35.       {
  36.         // Combine two channels into one
  37.         int32_t left = *src++;
  38.         int32_t right = *src++;
  39.         *dst++ = (int32_t) ((uint32_t) ((left >> 1) + (right >> 1)) & 0xffffff00ul);
  40.       }
  41.       tud_audio_write((uint8_t *)mic_buf, (uint16_t) (spk_data_size / 2));
  42.       spk_data_size = 0;
  43.     }
  44.   }
  45. }
复制代码


6 功能验证测试

将uac2_headset 音频设备插入PC,在计算机管理->设备管理器->音频输入和输出里面出现耳机和麦克风两个TinyUSB headset设备证明枚举成功。
图5 设备管理器音频设备

电脑端播放音乐使用抓包工具抓到ISOC的数据包:

+14

最近谁赞过

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-27 23:10 , Processed in 0.085728 second(s), 41 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表