超级版主
 
- 积分
- 5805
- 金钱
- 5805
- 注册时间
- 2019-5-8
- 在线时间
- 1595 小时
|
|
第六十九章 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
上一章我们向大家介绍了如何利用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所示的工程:
图69.3.2.1 USB声卡工程截图
1. USB驱动代码
可以看到,USB部分代码,同上一章的在结构上是一模一样的,只是.c文件稍微有些变化。同样,我们移植需要修改以下这几个文件中的代码。
usbd_conf.c代码,和上一章基本一样,可以用上一章的代码直接替换即可正常使用,但需要注意的是需要在usbd_conf.h中定义音频频率,代码如下。
- /* AUDIO Class Config */
- /* ST USB库目前只支持这一个采样率, 设置其他采样率无法正常工作 */
- #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, 正点原子团队对该文件进行了重写,大家可直接从例程中复制,代码如下:
- /**
- * @brief Audio_Init
- * Initializes the AUDIO media low layer
- * [url=home.php?mod=space&uid=271674]@param[/url] None
- * @retval Result of the operation: USBD_OK if all operations are OK else
- USBD_FAIL
- */
- static int8_t Audio_Init(uint32_t AudioFreq, uint32_t Volume, uint32_t options)
- {
- UNUSED(options);
-
- es8388_adda_cfg(1, 0);
- es8388_output_cfg(1, 1);
- es8388_hpvol_set(Volume * 0.3);
- es8388_spkvol_set(Volume * 0.3);
- es8388_sai_cfg(0, 3);
- sai1_saia_init(SAI_MODEMASTER_TX, SAI_CLOCKSTROBING_RISINGEDGE,
- SAI_DATASIZE_16);
- sai1_samplerate_set(AudioFreq);
- sai1_tx_callback = audio_sai_dma_callback;
-
- return USBD_OK;
- }
- /**
- * @brief Audio_AudioCmd
- * AUDIO command handler
- * @param Buf: Buffer of data to be sent
- * @param size: Number of data to be sent (in bytes)
- * @param cmd: command opcode
- * @retval Result of the operation: USBD_OK if all operations are OK
- else USBD_FAIL
- */
- static int8_t Audio_AudioCmd(uint8_t *pbuf, uint32_t size, uint8_t cmd)
- {
- switch (cmd)
- {
- case AUDIO_CMD_START:
- {
- sai1_tx_dma_init(pbuf, 0, size, 1);
- break;
- }
- case AUDIO_CMD_PLAY:
- {
- sai1_play_start();
- break;
- }
- case AUDIO_CMD_STOP:
- {
- sai1_play_stop();
- break;
- }
- }
-
- return USBD_OK;
- }
- /**
- * @brief Audio_VolumeCtl
- * @param vol: volume level (0..100)
- * @retval Result of the operation: USBD_OK if all operations are OK else
- USBD_FAIL
- */
- static int8_t Audio_VolumeCtl(uint8_t vol)
- {
- es8388_hpvol_set(vol * 0.3);
- es8388_spkvol_set(vol * 0.3);
-
- return USBD_OK;
- }
- /**
- * @brief Audio_MuteCtl
- * @param cmd: vmute command
- * @retval Result of the operation: USBD_OK if all operations are OK else
- USBD_FAIL
- */
- static int8_t Audio_MuteCtl(uint8_t cmd)
- {
- if (cmd != 0)
- {
- es8388_output_cfg(0, 0);
- }
- else
- {
- es8388_output_cfg(1, 1);
- }
-
- return USBD_OK;
- }
复制代码 本例程工作的时候,当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的程序,具体如下:
- /* USBD句柄 */
- USBD_HandleTypeDef g_usbd_handle = {0};
- int main(void)
- {
- uint8_t t = 0;
- uint8_t key;
- uint8_t volume;
- uint8_t conn_sta;
-
- sys_mpu_config(); /* 配置MPU */
- sys_cache_enable(); /* 使能Cache */
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(300, 6, 2); /* 配置时钟,600MHz */
- delay_init(600); /* 初始化延时 */
- usart_init(115200); /* 初始化串口 */
- led_init(); /* 初始化LED */
- hyperram_init(); /* 初始化HyperRAM */
- lcd_init(); /* 初始化LCD */
- key_init(); /* 初始化按键 */
- es8388_init(); /* 初始化ES8388 */
- my_mem_init(SRAMIN); /* 初始化AXI-SRAM1~4内存池 */
- my_mem_init(SRAMEX); /* 初始化XSPI2 HyperRAM内存池 */
- my_mem_init(SRAM12); /* 初始化AHB-SRAM1~2内存池 */
- my_mem_init(SRAMDTCM); /* 初始化DTCM内存池 */
- my_mem_init(SRAMITCM); /* 初始化ITCM内存池 */
-
- lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
- lcd_show_string(30, 70, 200, 16, 16, "USB Audio Card TEST", RED);
- lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
- lcd_show_string(30, 110, 200, 16, 16, "KEY0: Vol+", RED);
- lcd_show_string(30, 130, 200, 16, 16, "KEY2: Vol-", RED);
-
- volume = AUDIO_DEFAULT_VOLUME;
- lcd_show_string(30, 150, 200, 16, 16, "Volume: ", RED);
- lcd_show_num(94, 150, AUDIO_DEFAULT_VOLUME, 3, 16, BLUE);
- lcd_show_string(30, 170, 200, 16, 16, "USB Disconnected", BLUE);
-
- USBD_Init(&g_usbd_handle, &AUDIO_Desc, DEVICE_FS);
- USBD_RegisterClass(&g_usbd_handle, USBD_AUDIO_CLASS);
- USBD_AUDIO_RegisterInterface(&g_usbd_handle, &USBD_AUDIO_fops);
- USBD_Start(&g_usbd_handle);
-
- while (1)
- {
- key = key_scan(1);
- if (key != NONE_PRES)
- {
- if (key == KEY0_PRES)
- {
- if (++volume > 100)
- {
- volume = 100;
- }
- }
- else if (key == KEY2_PRES)
- {
- if (volume != 0)
- {
- volume--;
- }
- }
- USBD_AUDIO_fops.VolumeCtl(volume);
- lcd_show_num(94, 150, volume, 3, 16, BLUE);
- }
-
- if (conn_sta != g_usb_conn_state)
- {
- conn_sta = g_usb_conn_state;
-
- if (g_usb_conn_state != 0)
- {
- lcd_show_string(30, 170, 200, 16, 16, "USB Connected ", BLUE);
- }
- else
- {
- lcd_show_string(30, 170, 200, 16, 16, "USB Disconnected",BLUE);
- }
- }
-
- if (++t == 20)
- {
- t = 0;
- LED0_TOGGLE();
- }
-
- delay_ms(10);
- }
- }
复制代码 此部分代码比较简单,同上一章一样定义了USBD_Device结构体,然后通过USBD_Init等函数初始化USB,不过本章实现的是USB声卡功能。
其他部分我们就不详细介绍了,软件设计部分就为大家介绍到这里。
69.4 下载验证
在代码编译成功之后,我们通过下载代码到STM32H7R7开发板上,在USB配置成功后(注意:USB数据线,要插在USB_SLAVE端口!不是USB_UART端口!另外,USB_HOST接口不要插任何外设!),LCD显示效果如图69.4.1所示:
图69.4.1 USB连接成功
此时,电脑提示发现新硬件,并自动完成驱动安装。
等USB配置成功后,LED1常亮,LED0闪烁,并且在设备管理器→声音、视频和游戏控制器里面看到多了设备,如图69.4.2所示:
图69.4.2 设备管理器找到STM32 USB声卡
然后,设置STM32 AUDIO Steaming in FS Mode为电脑的默认播放设备,则电脑的所有声音都被切换到开发板输出,将耳机插入STM32H7R7开发板的PHONE端口,即可听到来自电脑的声音,开发板板载喇叭也可以听到来自电脑的声音。通过按键KEY0/KEY2可以增大/减少音量,默认音量设置的是70,大家可以自己调节(范围:0~100)。 |
|