OpenEdv-开源电子网

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

《STM32F407 探索者开发指南》第六十四章 USB声卡(Slave)实验

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4667
金钱
4667
注册时间
2019-5-8
在线时间
1224 小时
发表于 2023-9-25 18:18:36 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-9-21 17:51 编辑

第六十四章 USB声卡(Slave)实验


1)实验平台:正点原子探索者STM32F407开发板

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


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

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

6)STM32技术交流QQ群:151941872

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

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



64.1 USB声卡简介
USB声卡依赖于USB音频类(USB Audio Class),一个像USB通用的数据接口,可以实现数字音频的数据传输。

正点原子探索者STM32F407开发板板载了一颗高性能CODEC芯片:ES8388,我们可以利用STM32F407的I2S接口,控制ES8388播放音乐,同样,如果结合STM32F407的USB功能,就可以实现一个USB声卡。

同上一章一样,我们直接移植官方的USB AUDIO例程,官方例程路径:8,STM32参考资料à1,STM32CubeF4固件包à STM32Cube_FW_F4_V1.26.0àProjectsà STM324xG_EVAL
àApplicationsàUSB_DeviceàAudio_Standalone,该例程采用USB同步传输来传输音频数据流并且支持某些控制命令(比如静音控制),例程仅支持USB FS模式(不支持HS),同时例程不需要特殊的驱动支持,大多数操作系统直接就可以识别。

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

2. 硬件资源
1)LED灯
LED0 – PF9
LED1 – PF10
2)独立按键
KEY0 – PE4
KEY1 – PE3
KEY2 – PE2
KEY_UP – PA0  (程序中的宏名:WK_UP)
3)串口1 (PA9/PA10连接在板载USB转串口芯片CH340上面)
4)正点原子 2.8/3.5/4.3/7寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
5)ES8388音频CODEC芯片,通过I2S驱动
6)I2S音频接口
7)USB_SLAVE接口(D-/D+连接在PA11/PA12上)
8)外部SRAM芯片,通过FSMC驱动

64.3 程序设计
62.3.1 程序流程图                           
QQ截图20230921175028.png
图64.3.1.1 USB声卡实验程序流程图

64.3.2 程序解析
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。

本章,我们在实验43 音乐播放器实验的基础上修改,把不需要的文件从工程中移除,在Middlewares文件夹所在文件夹下新建一个USB的文件夹,同上一章一样,对照官方AUDIO例子,将相关文件拷贝到USB文件夹下。

然后,我们在工程里面去掉一些不必要的代码,并添加USB相关代码,最终得到如图64.3.2.1所示的工程:   
image003.png
图64.3.2.1USB声卡工程截图

1. USB驱动代码
可以看到,USB部分代码,同上一章的在结构上是一模一样的,只是.c文件稍微有些变化。同样,我们移植需要修改的代码,就是USB_APP里面的这四个.c文件了。

usbd_conf.c代码,和上一章基本一样,可以用上一章的代码直接替换即可正常使用,但是需要在usbd_conf.h中定义音频频率,代码如图下。
  1. /* AUDIO Class Config */
  2. /* ST USB库目前只支持这一个采样率, 设置其他采样率无法正常工作 */
  3. #define USBD_AUDIO_FREQ                       48000
复制代码
usbd_desc.c/usbd_desc.h代码,同上一章不一样,上一章描述符是大容量存储设备,本章变成了USB声卡了,所以直接用ST官方USB Audio例程的就行。

usbd_audio_if代码,是USB声卡的接口文件,usbd_audio.c对外的所有接口函数,都在该.c文件里面,然后通过stm32f407_audio.c文件里面提供的相关函数,分别实现各个接口函数。该文件不需要做太多修改,这里我们就不做介绍了,详见本例程源码。

stm32f407_audio.c代码,是我们重点要修改的,该文件是配合USB声卡的CS43L22底层驱动相关代码,官方STM32F4xG的板子,用的是CS43L22,而我们用的是ES8388,需要修改代码,修改后代码如下:
  1. uint8_t g_volume = 0;    /* 当前音量 */
  2. /* USB数据输出状态,在usbd_audio.c里面定义 */
  3. extern uint8_t g_usbd_audio_dataout_en;
  4. /**
  5. *@brief        播放时,I2S DMA传输回调函数
  6. *@param        无
  7. *@retval       无
  8. */
  9. voidbsp_audio_i2s_dma_callback(void)
  10. {
  11.    BSP_AUDIO_OUT_TransferComplete_CallBack();    /* 执行回调函数,更新数据 */
  12. }
  13. /**
  14. *@brief   配置音频接口
  15. *@param   OutputDevice    :输出设备选择,未用到.
  16. *@param   Volume           :音量大小, 0~100
  17. *@param   AudioFreq       :音频采样率
  18. *@retval                    操作结果
  19. *  @arg                      0    , 成功
  20. *  @arg                      其他 , 错误代码
  21. */
  22. uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume,
  23.                                  uint32_t AudioFreq)
  24. {
  25.    es8388_i2s_cfg(0, 3);    /* 飞利浦标准,16位数据长度 */
  26.     /*飞利浦标准,主机发送,时钟低电平有效,16位扩展帧长度 */
  27.     i2s_init(I2S_STANDARD_PHILIPS, I2S_MODE_MASTER_TX, I2S_CPOL_LOW,
  28.               I2S_DATAFORMAT_16B_EXTENDED);
  29.    i2s_samplerate_set(AudioFreq);      /* 设置采样率 */
  30.    BSP_AUDIO_OUT_SetVolume(Volume);    /* 设置音量 */
  31.     /* 回调函数指 bsp_audio_i2s_dma_callback */
  32.    i2s_tx_callback = bsp_audio_i2s_dma_callback;
  33.    
  34.    printf("EVAL_AUDIO_Init:%d,%d\r\n", Volume, AudioFreq);
  35.    
  36.     return 0;
  37. }
  38. /**
  39. *@brief   开始播放音频数据
  40. *@param   pBuffer    : 音频数据流首地址指针
  41. *@param   Size         :数据流大小(单位:字节)
  42. *@retval                操作结果
  43. *  @arg                 0    , 成功
  44. *  @arg                 其他 , 错误代码
  45. */
  46. uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
  47. {
  48.    i2s_tx_dma_init((uint8_t*) pBuffer, 0, Size);    /* 配置I2S TX DMA */
  49.    I2S_TX_DMASx->CR &= ~(1 << 8);      /* 单次模式 */
  50.    I2S_TX_DMASx->CR &= ~(1 << 18);     /* 改成单缓冲模式 */
  51.    i2s_play_start();                      /* 开启DMA */
  52.    
  53.    printf("EVAL_AUDIO_Play:%x,%d\r\n", pBuffer, Size);
  54.    
  55.     return 0;
  56. }
  57. /**
  58. *@brief   切换音频数据流buffer,每次DMA中断完成会调用该函数
  59. *@param   pData   : 音频数据流缓存首地址
  60. *@param   Size    : 音频数据流大小(单位:harf word,也就是2个字节)
  61. *@retval            : 无
  62.   */
  63. voidBSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
  64. {
  65.     if (g_usbd_audio_dataout_en== 1)        /* USB有音频数据输出 */
  66.     {
  67.        g_usbd_audio_dataout_en = 0;         /* 清除标记位 */
  68.     }
  69.     else if (g_usbd_audio_dataout_en== 0)  /* 没有收到任何数据,全部填充0 */
  70.     {
  71.        my_mem_set(pData, 0, AUDIO_TOTAL_BUF_SIZE);
  72.        g_usbd_audio_dataout_en = 2;          /* 标记已经清零了buffer,停止数据输出 */
  73.     }
  74.     if (Size !=AUDIO_TOTAL_BUF_SIZE)
  75.     {   /* 想观察数据,可以printf,但是会有轻微的影响音质 */
  76.        // printf("chgbuf:%x,%d\r\n",pData, Size);
  77.     }
  78.    I2S_TX_DMASx->CR &= ~(1 << 0);           /* 关闭DMA传输 */
  79.     while (I2S_TX_DMASx->CR & 0X1);          /* 确保DMA可以被设置 */
  80.    I2S_TX_DMASx->NDTR = Size ;               /* 设置传输长度 */
  81.    I2S_TX_DMASx->CR |= 1 << 0;               /* 开启DMA传输 */
  82. }
  83. /**
  84. *@brief        停止播放
  85. *@retval      操作结果
  86. *  @arg        0    , 成功
  87. *  @arg        其他 , 错误代码
  88. */
  89. uint8_t BSP_AUDIO_OUT_Pause(void)
  90. {
  91.    printf("EVAL_AUDIO_Stop\r\n");
  92.     return 0;
  93. }
  94. /**
  95. *@brief   停止播放
  96. *@param   Option   : 未用到
  97. *@retval            操作结果
  98. *  @arg              0    , 成功
  99. *  @arg              其他 , 错误代码
  100. */
  101. uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
  102. {
  103.    printf("EVAL_AUDIO_Stop\r\n");
  104.     return 0;
  105. }
  106. /**
  107. *@brief   音量设置
  108. *@param   Volume:音量大小, 0~100
  109. *@retval           操作结果
  110. *  @arg             0    , 成功
  111. *  @arg             其他 , 错误代码
  112. */
  113. uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
  114. {
  115.    g_volume = Volume;
  116.    es8388_hpvol_set(g_volume * 0.3);
  117.    es8388_spkvol_set(g_volume * 0.3);
  118.     return 0;
  119. }
  120. /**
  121. *@brief   静音设置
  122. *@param   Cmd     : 0,不静音; 1,静音
  123. *@retval            操作结果
  124. *  @arg              0    , 成功
  125. *  @arg              其他 , 错误代码
  126. */
  127. uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
  128. {
  129.     if(Cmd)
  130.     {
  131.        es8388_output_cfg(0, 0);     /* 关闭输出 ,就是静音 */
  132.     }else
  133.     {
  134.        es8388_output_cfg(1, 1);     /* 打开输出 ,取消静音 */
  135.     }
  136.    
  137.    printf("BSP_AUDIO_OUT_SetMute:%d\r\n", Cmd);
  138.     return 0;
  139. }
复制代码
本例程工作的时候,当USB连接成功,并完成识别以后,会先调用BSP_AUDIO_OUT_Init函数,设置音频接口相关参数,包括:ES8388的I2C配置、I2S配置、音量设置和I2S DMA发送完成中断回调函数等。

然后,当上电后首次有音乐输出的时候,会先调用BSP_AUDIO_OUT_Play函数,对I2S的DMA进行配置(使用单次模式,且单缓冲传输),然后启动I2S DMA传输,开始播放电脑的声音。然后,当DMA传输完成后,会自动停止DMA(单次模式),并通过bsp_audio_i2s_dma_callback函数调用BSP_AUDIO_OUT_TransferComplete_CallBack回调函数,在回调函数里面,经过处理如果有新的音频数据,则会调用BSP_AUDIO_OUT_ChangeBuffer函数,重启DMA传输,开启下一次数据DMA传送,然后DMA传输完成又会进入bsp_audio_i2s_dma_callback函数,依次循环。

这样,就实现了USB传过来的音频数据,通过I2S DMA传输出去,最终通过ES8388输出给耳机或开发板板载喇叭,实现USB声卡功能。

USB AUDIO相关代码,就给大家介绍到这里,详细的介绍,请大家参考:UM1734(STM32CubeUSB device library).pdf这个文档。

2. main.c代码
下面是main.c的程序,具体如下:
  1. USBD_HandleTypeDefUSBD_Device;              /* USB Device处理结构体 */
  2. extern volatile uint8_t g_device_state;    /* USB连接 情况 */
  3. extern uint8_t g_volume;                      /* 音量(可通过按键设置) */
  4. int main(void)
  5. {
  6.     uint8_t key;
  7.     uint8_t t = 0;
  8.     uint8_t device_sta = 0xFF;
  9.    
  10.     HAL_Init();                             /* 初始化HAL库 */
  11.     sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
  12.     delay_init(168);                       /* 延时初始化 */
  13.     usart_init(115200);                   /* 串口初始化为115200 */
  14.     led_init();                             /* 初始化LED */
  15.     lcd_init();                             /* 初始化LCD */
  16.     key_init();                             /* 初始化按键 */
  17.     sram_init();                            /* 初始化外部SRAM */
  18.    
  19.     my_mem_init(SRAMIN);                  /* 初始化内部SRAM内存池 */
  20.     my_mem_init(SRAMEX);                  /* 初始化外部SRAM内存池 */
  21.     my_mem_init(SRAMCCM);                 /* 初始化CCM内存池 */
  22.    
  23.     lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  24.     lcd_show_string(30, 70, 200, 16, 16, "USB Sound Card TEST", RED);
  25.     lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  26.     lcd_show_string(30, 110, 200, 16, 16, "KEY2:Vol- KEY0:Vol+", RED);
  27.    
  28.     lcd_show_string(30, 140, 200, 16, 16, "VOLUME:", BLUE);         /* 提示音量 */
  29.     /* 显示音量值 */
  30.     lcd_show_xnum(30 + 56, 140, AUDIO_DEFAULT_VOLUME, 3, 16, 0x80, BLUE);
  31.     /* 提示正在建立连接 */
  32.     lcd_show_string(30, 180, 200, 16, 16, "USB Connecting...", RED);
  33.    
  34.     es8388_init();                /* ES8388初始化 */
  35.     es8388_adda_cfg(1, 0);       /* 开启DAC关闭ADC */
  36.     es8388_output_cfg(1, 1);    /* DAC选择通道输出 */
  37.     es8388_hpvol_set(25);        /* 设置耳机音量 */
  38.     es8388_spkvol_set(30);       /* 设置喇叭音量 */
  39.    
  40.     USBD_Init(&USBD_Device, &AUDIO_Desc, DEVICE_FS);    /* 初始化USB */
  41.     USBD_RegisterClass(&USBD_Device, USBD_AUDIO_CLASS); /* 添加类 */
  42.     /* 为MSC类添加回调函数 */
  43.     USBD_AUDIO_RegisterInterface(&USBD_Device, &USBD_AUDIO_fops);
  44.     USBD_Start(&USBD_Device);   /* 开启USB */
  45.    
  46.     delay_ms(1800);
  47.     while(1)
  48.     {
  49.         key = key_scan(1);                /* 支持连按 */
  50.         if (key)
  51.         {
  52.             if (key == KEY0_PRES)         /* KEY0按下,音量增加 */
  53.             {
  54.                 g_volume++;
  55.                 if (g_volume > 100)       /* 范围限定 */
  56.                 {
  57.                     g_volume = 100;
  58.                 }
  59.             }
  60.             else if (key == KEY2_PRES)   /* KEY2按下,音量减少 */
  61.             {
  62.                 if (g_volume)               /* 范围限定 */
  63.                 {
  64.                     g_volume--;
  65.                 }
  66.             }
  67.             es8388_hpvol_set(g_volume * 0.3);
  68.             es8388_spkvol_set(g_volume * 0.3);
  69.             /* 显示音量值 */
  70.             lcd_show_xnum(30 + 56, 140, g_volume, 3, 16, 0x80, BLUE);
  71.             delay_ms(20);
  72.         }
  73.         if (device_sta != g_device_state)   /* 状态改变了 */
  74.         {
  75.             if (g_device_state == 1)
  76.             {   /* 提示USB连接已经建立 */
  77.                 lcd_show_string(30, 180, 200, 16, 16, "USB Connected   ", RED);
  78.                 LED1(0);    /* LED1亮 */
  79.             }
  80.             else
  81.             {   /* 提示USB连接失败 */
  82.                 lcd_show_string(30, 180, 200, 16, 16, "USB DisConnected ", RED);
  83.                 LED1(1);    /* LED1灭 */
  84.             }
  85.             device_sta = g_device_state;
  86.         }
  87.         delay_ms(20);
  88.         t++;
  89.         if (t > 10)
  90.         {
  91.             t = 0;
  92.             LED0_TOGGLE();    /* 提示系统在运行 */
  93.         }
  94.     }
  95. }
复制代码
此部分代码比较简单,同上一章一样定义了USBD_Device结构体,然后通过USBD_Init等函数初始化USB,不过本章实现的是USB声卡功能。本章我们保留了原例程(实验43)的USMART部分,同样可以通过串口1设置ES8388相关参数。

其他部分我们就不详细介绍了,软件设计部分就为大家介绍到这里。

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

image005.png
图64.4.1 USB连接成功

此时,电脑提示发现新硬件,并自动完成驱动安装。

等USB配置成功后,LED1常亮,LED0闪烁,并且在设备管理器à声音、视频和游戏控制器里面看到多了设备,如图64.4.2所示:   
image007.png
图64.4.2 设备管理器找到STM32 USB声卡

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

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-23 07:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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