OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 115|回复: 0

《STM32H7R7开发指南 V1.1 》第六十九章 USB声卡(Slave)实验

[复制链接]

1359

主题

1375

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5805
金钱
5805
注册时间
2019-5-8
在线时间
1595 小时
发表于 昨天 09:33 | 显示全部楼层 |阅读模式
第六十九章 USB声卡(Slave)实验

1)实验平台:正点原子STM32H7R7开发板

2)章节摘自【正点原子】STM32H7R7开发指南 V1.1

3)购买链接: https://detail.tmall.com/item.htm?id=820823382459

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32h7rx.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32开发板技术交流群:756580169


2.jpg

3.png

上一章我们向大家介绍了如何利用STM32H7R7的USB接口来做一个USB读卡器,本章我们将利用STM32H7R7的USB来做一个声卡。本章分为如下几个部分:
69.1 USB声卡简介
69.2 硬件设计
69.3 软件设计
69.4 下载验证


69.1 USB声卡简介
USB声卡依赖于USB音频类(USB Audio Class),一个像USB通用的数据接口,可以实现数字音频的数据传输。
正点原子STM32H7R7开发板板载了一颗高性能CODEC芯片:ES8388,我们可以利用STM32H7R7的SAI接口,控制ES8388播放音乐,同样,如果结合STM32H7R7的USB功能,就可以实现一个USB声卡。
同上一章一样,我们直接移植官方的USB AUDIO例程,官方例程路径:8,STM32参考资料1,STM32CubeH7RS固件包 STM32Cube_FW_H7RS_V1.0.0Projects STM32H7S78-DKApplicationsUSB_Device Audio_Standalone,该例程采用USB同步传输来传输音频数据流并且支持某些控制命令(比如静音控制),例程仅支持USB FS模式(不支持HS),同时例程不需要特殊的驱动支持,大多数操作系统直接就可以识别。


69.2 硬件设计

1. 例程功能
本节实验功能简介:先将开发板通过USB_SLAVE连接电脑,开发板开机的时候先提示一些信息,然后开始USB配置,在配置成功之后就可以在电脑上发现多出一个声卡。我们在LCD液晶屏上显示USB的连接状态,如果连接成功,此时,我们可以通过耳机或开发板板载喇叭,可以听到来自电脑电脑的音频信号,还可以通过两个按键调节ES8388音量:按键KEY0可以增大音量,按键KEY2可以减少音量。LED0闪烁,提示程序运行。

2. 硬件资源
1)LED灯
       LED0 – PD14
       LED1 – PC0
2)独立按键
       KEY0 – PE9
       KEY1 – PE8
       KEY2 – PE7
       KEY_UP – PC13  (程序中的宏名:WK_UP)
3)串口1 (PB14/PB15连接在板载USB转串口芯片CH340上面)
4)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(包括MCU屏和RGB屏,都支持)
5)ES8388音频CODEC芯片,通过SAI驱动
6)SAI音频接口
7)USB_SLAVE接口(D-/D+连接在PM5/PM6上)
8)HyperRAM芯片


69.3 程序设计

69.3.1 程序解析
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。
本章,我们在实验48 音乐播放器实验的基础上修改,把不需要的文件从工程中移除,在Middlewares文件夹所在文件夹下新建一个USB的文件夹,同上一章一样,对照官方AUDIO例子,将相关文件拷贝到USB文件夹下。由于官方提供的USB_APP文件不太好用,我们正点原子团队直接编写了一套USB_APP代码,读者可以直接拷贝我们例程中的USB_APP文件夹,即:实验58 USB声卡(Slave)实验MiddlewaresUSBUSB_APP。
然后,我们在工程里面去掉一些不必要的代码,并添加USB相关代码,最终得到如图69.3.2.1所示的工程:


第六十九章 USB声卡1412.png
图69.3.2.1 USB声卡工程截图

1. USB驱动代码
可以看到,USB部分代码,同上一章的在结构上是一模一样的,只是.c文件稍微有些变化。同样,我们移植需要修改以下这几个文件中的代码。
usbd_conf.c代码,和上一章基本一样,可以用上一章的代码直接替换即可正常使用,但需要注意的是需要在usbd_conf.h中定义音频频率,代码如下。

  1. /* AUDIO Class Config */
  2. /* ST USB库目前只支持这一个采样率, 设置其他采样率无法正常工作 */
  3. #define USBD_AUDIO_FREQ                       48000U
复制代码
usbd_desc.c/usbd_desc.h代码,同上一章不一样,上一章描述符是大容量存储设备,本章变成了USB声卡了,所以直接用ST官方USB Audio例程的就行。
usbd_audio.c代码,从ST官方USB Audio例程的AUDIO文件里直接复制过来。这个文件不需要做太多修改,这里我们就不做介绍了,详见本例程源码。
usbd_audio_if.h代码,需要添加声明用于更新音频的回调函数,代码如下。
void BSP_AUDIO_OUT_TransferComplete_CallBack(void);
usbd_audio_if.c代码,是我们重点要修改的,该文件是配合USB声卡的WM8994底层驱动相关代码,官方的板子,用的是WM8994,而我们用的是ES8388, 正点原子团队对该文件进行了重写,大家可直接从例程中复制,代码如下:

  1. /**
  2.   * @brief  Audio_Init
  3.   *         Initializes the AUDIO media low layer
  4.   * [url=home.php?mod=space&uid=271674]@param[/url]  None
  5.   * @retval Result of the operation: USBD_OK if all operations are OK else
  6. USBD_FAIL
  7.   */
  8. static int8_t Audio_Init(uint32_t  AudioFreq, uint32_t Volume, uint32_t options)
  9. {
  10.     UNUSED(options);
  11.    
  12.     es8388_adda_cfg(1, 0);
  13.     es8388_output_cfg(1, 1);
  14.     es8388_hpvol_set(Volume * 0.3);
  15.     es8388_spkvol_set(Volume * 0.3);
  16.     es8388_sai_cfg(0, 3);
  17. sai1_saia_init(SAI_MODEMASTER_TX, SAI_CLOCKSTROBING_RISINGEDGE,
  18. SAI_DATASIZE_16);
  19.     sai1_samplerate_set(AudioFreq);
  20.     sai1_tx_callback = audio_sai_dma_callback;
  21.    
  22.     return USBD_OK;
  23. }
  24. /**
  25.   * @brief  Audio_AudioCmd
  26.   *         AUDIO command handler
  27.   * @param  Buf: Buffer of data to be sent
  28.   * @param  size: Number of data to be sent (in bytes)
  29.   * @param  cmd: command opcode
  30.   * @retval Result of the operation: USBD_OK if all operations are OK
  31.   else USBD_FAIL
  32.   */
  33. static int8_t Audio_AudioCmd(uint8_t *pbuf, uint32_t size, uint8_t cmd)
  34. {
  35.     switch (cmd)
  36.     {
  37.         case AUDIO_CMD_START:
  38.         {
  39.             sai1_tx_dma_init(pbuf, 0, size, 1);
  40.             break;
  41.         }
  42.         case AUDIO_CMD_PLAY:
  43.         {
  44.             sai1_play_start();
  45.             break;
  46.         }
  47.         case AUDIO_CMD_STOP:
  48.         {
  49.             sai1_play_stop();
  50.             break;
  51.         }
  52.     }
  53.    
  54.     return USBD_OK;
  55. }

  56. /**
  57.   * @brief  Audio_VolumeCtl
  58.   * @param  vol: volume level (0..100)
  59.   * @retval Result of the operation: USBD_OK if all operations are OK else
  60. USBD_FAIL
  61.   */
  62. static int8_t Audio_VolumeCtl(uint8_t vol)
  63. {
  64.     es8388_hpvol_set(vol * 0.3);
  65.     es8388_spkvol_set(vol * 0.3);
  66.    
  67.     return USBD_OK;
  68. }

  69. /**
  70.   * @brief  Audio_MuteCtl
  71.   * @param  cmd: vmute command
  72.   * @retval Result of the operation: USBD_OK if all operations are OK else
  73. USBD_FAIL
  74.   */
  75. static int8_t Audio_MuteCtl(uint8_t cmd)
  76. {
  77.     if (cmd != 0)
  78.     {
  79.         es8388_output_cfg(0, 0);
  80.     }
  81.     else
  82.     {
  83.         es8388_output_cfg(1, 1);
  84.     }
  85.    
  86.     return USBD_OK;
  87. }

复制代码
本例程工作的时候,当USB连接成功,并完成识别以后,会先调用Audio_Init函数,设置音频接口相关参数,包括:ES8388的SAI配置、音量设置和SAI DMA发送完成中断回调函数等。
然后,当上电后首次有音乐输出的时候,会先调用Audio_AudioCmd函数,对SAI的DMA进行配置(使用单次模式,且单缓冲传输),然后启动SAI DMA传输,开始播放电脑的声音。然后,当DMA传输完成后,会自动停止DMA(单次模式),并通过audio_sai_dma_callback函数调用USBD_AUDIO_Sync函数,通知USB数据已经处理完成,等待USB传入新的数据包,经过处理如果有新的音频数据,则会调用Audio_AudioCmd函数,重启DMA传输,开启下一次数据DMA传送,然后DMA传输完成又会进入audio_sai_dma_callback函数,依次循环。
这样,就实现了USB传过来的音频数据,通过SAI DMA传输出去,最终通过ES8388输出给耳机或开发板板载喇叭,实现USB声卡功能。
USB AUDIO相关代码,就给大家介绍到这里,详细的介绍,请大家参考:UM1734(STM32Cube USB device library).pdf这个文档。


2. main.c代码
下面是main.c的程序,具体如下:

  1. /* USBD句柄 */
  2. USBD_HandleTypeDef g_usbd_handle = {0};

  3. int main(void)
  4. {
  5.     uint8_t t = 0;
  6.     uint8_t key;
  7.     uint8_t volume;
  8.     uint8_t conn_sta;
  9.    
  10.     sys_mpu_config();                   /* 配置MPU */
  11.     sys_cache_enable();                 /* 使能Cache */
  12.     HAL_Init();                         /* 初始化HAL库 */
  13.     sys_stm32_clock_init(300, 6, 2);    /* 配置时钟,600MHz */
  14.     delay_init(600);                    /* 初始化延时 */
  15.     usart_init(115200);                 /* 初始化串口 */
  16.     led_init();                         /* 初始化LED */
  17.     hyperram_init();                    /* 初始化HyperRAM */
  18.     lcd_init();                         /* 初始化LCD */
  19.     key_init();                         /* 初始化按键 */
  20.     es8388_init();                      /* 初始化ES8388 */
  21.     my_mem_init(SRAMIN);                /* 初始化AXI-SRAM1~4内存池 */
  22.     my_mem_init(SRAMEX);                /* 初始化XSPI2 HyperRAM内存池 */
  23.     my_mem_init(SRAM12);                /* 初始化AHB-SRAM1~2内存池 */
  24.     my_mem_init(SRAMDTCM);              /* 初始化DTCM内存池 */
  25.     my_mem_init(SRAMITCM);              /* 初始化ITCM内存池 */
  26.    
  27.     lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  28.     lcd_show_string(30, 70, 200, 16, 16, "USB Audio Card TEST", RED);
  29.     lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  30.     lcd_show_string(30, 110, 200, 16, 16, "KEY0: Vol+", RED);
  31.     lcd_show_string(30, 130, 200, 16, 16, "KEY2: Vol-", RED);
  32.    
  33.     volume = AUDIO_DEFAULT_VOLUME;
  34.     lcd_show_string(30, 150, 200, 16, 16, "Volume: ", RED);
  35.     lcd_show_num(94, 150, AUDIO_DEFAULT_VOLUME, 3, 16, BLUE);
  36.     lcd_show_string(30, 170, 200, 16, 16, "USB Disconnected", BLUE);
  37.    
  38.     USBD_Init(&g_usbd_handle, &AUDIO_Desc, DEVICE_FS);
  39.     USBD_RegisterClass(&g_usbd_handle, USBD_AUDIO_CLASS);
  40.     USBD_AUDIO_RegisterInterface(&g_usbd_handle, &USBD_AUDIO_fops);
  41.     USBD_Start(&g_usbd_handle);
  42.    
  43.     while (1)
  44.     {
  45.         key = key_scan(1);
  46.         if (key != NONE_PRES)
  47.         {
  48.             if (key == KEY0_PRES)
  49.             {
  50.                 if (++volume > 100)
  51.                 {
  52.                     volume = 100;
  53.                 }
  54.             }
  55.             else if (key == KEY2_PRES)
  56.             {
  57.                 if (volume != 0)
  58.                 {
  59.                     volume--;
  60.                 }
  61.             }
  62.             USBD_AUDIO_fops.VolumeCtl(volume);
  63.             lcd_show_num(94, 150, volume, 3, 16, BLUE);
  64.         }
  65.         
  66.         if (conn_sta != g_usb_conn_state)
  67.         {
  68.             conn_sta = g_usb_conn_state;
  69.             
  70.             if (g_usb_conn_state != 0)
  71.             {
  72.                 lcd_show_string(30, 170, 200, 16, 16, "USB Connected  ", BLUE);
  73.             }
  74.             else
  75.             {
  76.                 lcd_show_string(30, 170, 200, 16, 16, "USB Disconnected",BLUE);
  77.             }
  78.         }
  79.         
  80.         if (++t == 20)
  81.         {
  82.             t = 0;
  83.             LED0_TOGGLE();
  84.         }
  85.         
  86.         delay_ms(10);
  87.     }
  88. }
复制代码
此部分代码比较简单,同上一章一样定义了USBD_Device结构体,然后通过USBD_Init等函数初始化USB,不过本章实现的是USB声卡功能。
其他部分我们就不详细介绍了,软件设计部分就为大家介绍到这里。


69.4 下载验证
在代码编译成功之后,我们通过下载代码到STM32H7R7开发板上,在USB配置成功后(注意:USB数据线,要插在USB_SLAVE端口!不是USB_UART端口!另外,USB_HOST接口不要插任何外设!),LCD显示效果如图69.4.1所示:

第六十九章 USB声卡7810.png
图69.4.1 USB连接成功

此时,电脑提示发现新硬件,并自动完成驱动安装。
等USB配置成功后,LED1常亮,LED0闪烁,并且在设备管理器→声音、视频和游戏控制器里面看到多了设备,如图69.4.2所示:


第六十九章 USB声卡7917.png
图69.4.2 设备管理器找到STM32 USB声卡

然后,设置STM32 AUDIO Steaming in FS Mode为电脑的默认播放设备,则电脑的所有声音都被切换到开发板输出,将耳机插入STM32H7R7开发板的PHONE端口,即可听到来自电脑的声音,开发板板载喇叭也可以听到来自电脑的声音。通过按键KEY0/KEY2可以增大/减少音量,默认音量设置的是70,大家可以自己调节(范围:0~100)。
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-7-4 21:29

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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