STM32CubeIDE Audio播放音频,DAC + TIM + DMA https://blog.csdn.net/sudaroot/article/details/106337717
STM32CubeIDE Audio播放音频,PWM + TIM https://blog.csdn.net/sudaroot/article/details/106373388
STM32CbueIDE Audio播放音频 WM8978 + I2S https://blog.csdn.net/sudaroot/article/details/106528371
STM32CubeIDE Audio播放音频 WM8978 + I2S + DMA双缓存模式 https://blog.csdn.net/sudaroot/article/details/106660351
STM32CubeIDE USB Audio声卡 WM8978 + I2S https://blog.csdn.net/sudaroot/article/details/106834893
只实现了USB播放音频功能,至于USB录音和控制音量等功能,找到了相关资料,但是个人没时间往下折腾。
官方程序X-CUBE-USB-AUDIO:https://www.st.com/zh/embedded-software/x-cube-usb-audio.html
文档《UM2195 User manual USB device audio streaming Expansion Package for STM32Cube》:https://www.stmcu.org.cn/document/detail/index/id-219223
本手册与补充STM32Cube™固件库的X-CUBE-USB-AUDIO扩展包相关联,它描述了X-CUBE-USB-AUDIO固件库以及使用方法。
文档和程序要相互配合着看。
..\STM32Cube\Repository\STM32Cube_FW_F4_V1.25.0\Projects\STM324xG_EVAL\Applications\USB_Device\AUDIO_Standalone
先看看readme.txt程序支持功能。
The device supports the following audio features: 设备支持以下音频功能:
- Pulse Coded Modulation (PCM) format -脉冲编码调制(PCM)格式
- sampling rate: 48KHz. -采样率:48KHz。
- Bit resolution: 16 -位分辨率:16
- Number of channels: 2 -频道数:2
- No volume control -无音量控制
- Mute/Unmute capability -静音/取消静音功能
- Asynchronous Endpoints -异步端点
注意:不支持音量控制。即电脑无法控制硬件音量,但是可以通过音频数据控制音量。
打开《STM32F4xx中文参考手册.pdf》755页。
由于我们使用MCK时钟输出,采样频率48KHz。故需要修改时钟树的分频。
先把PLLM VCO = 1MHz.
-USB_Device / App/usbd_desc.c 生成的初始化代码
-USB_Device / App/usbd_desc.h 生成的初始化代码头文件
-USB_Device / App/usbd_audio_if.c USBD音频接口
-USB_Device / App/usbd_audio_if.h USBD音频接口头文件
-USB_Device / App/usbd_desc.c USB设备AUDIO描述符
-USB_Device / App/usbd_desc.h USB设备AUDIO描述符头文件
-USB_Device / Target/usbd_conf.c常规低层驱动程序配置
-USB_Device / Target/ usbd_conf.h USB设备驱动程序配置文件
先打开usbd_audio.c, 看生成的底层驱动特性。
不支持音量控制!!!不支持音量控制!!!不支持音量控制!!!不支持音量控制!!!不支持音量控制!!!
现在需要做的是打开usbd_audio_if.c进行填充函数。
AUDIO_Init_FS, 插入PC会初始化
AUDIO_DeInit_FS, USB在挂起后重新连接PC会调用,再调用AUDIO_Init_FS
AUDIO_AudioCmd_FS, 播放控制函数。
AUDIO_VolumeCtl_FS, 音量控制,没用,底层不支持。
AUDIO_MuteCtl_FS, 静音。功能可用。
AUDIO_PeriodicTC_FS, 数据包接收完成回调。
AUDIO_GetState_FS, 获取状态。
还有两个外部函数,用于音频数据i2s半发送和发送完成后要求音频数据同步,即请求PC音频数据的。
void HalfTransfer_CallBack_FS(void)
void TransferComplete_CallBack_FS(void)
用到的只有粗体3个函数就行了,初始化我使用外部初始化WM8978,不在USB连接初始化硬件。其他函数功能自己玩。
WM8978的相关函数以前博客写了好多了。跳过。
新建一个audio_player.c,添加如下代码
#include "audio_player.h"
#include "wm8978.h"
#include "usbd_audio_if.h"
extern I2S_HandleTypeDef hi2s2;
extern DMA_HandleTypeDef hdma_spi2_tx;
void Audio_Player_Play(uint16_t* pBuffer, uint32_t Size)
{
if(Size > 0xFFFF) Size = 0xFFFF;
HAL_I2S_Transmit_DMA(&hi2s2, pBuffer, Size);
}
void Audio_Player_Pause(void)
{
HAL_I2S_DMAPause(&hi2s2);
}
void Audio_Player_Resume(void)
{
HAL_I2S_DMAResume(&hi2s2);
}
void Audio_Player_Stop(void)
{
HAL_I2S_DMAStop(&hi2s2);
}
void Audio_Player_VolumeCtl(uint8_t vol)
{
WM8978_VolumeCtl(vol);
}
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
HalfTransfer_CallBack_FS();
}
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
TransferComplete_CallBack_FS();
}
填充usbd_audio_if.c, AUDIO_CMD_START播放前的准备。 AUDIO_CMD_PLAY连续播放。
static int8_t AUDIO_AudioCmd_FS(uint8_t* pbuf, uint32_t size, uint8_t cmd)
{
/* USER CODE BEGIN 2 */
switch(cmd)
{
case AUDIO_CMD_START:
Audio_Player_Play((uint16_t*)pbuf, size);
break;
case AUDIO_CMD_PLAY:
Audio_Player_Play((uint16_t*)pbuf, size);
break;
}
return (USBD_OK);
/* USER CODE END 2 */
}
I2S发送完数据,hUsbDeviceFS.dev_state检测USB是否还连接。如果是USBD_STATE_CONFIGURED则是连接了PC。
如果不添加获取USB连接状态可能导致I2S一直在发送数据,原因就是USBD_AUDIO_Sync()即使在USB断开的情况下还是能
AUDIO_AudioCmd_FS()的AUDIO_CMD_PLAY触发,导致I2S DMA一直在发数据。
void TransferComplete_CallBack_FS(void)
{
if(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED)
{
USBD_AUDIO_Sync(&hUsbDeviceFS, AUDIO_OFFSET_FULL);
}
}
void HalfTransfer_CallBack_FS(void)
{
if(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED)
{
USBD_AUDIO_Sync(&hUsbDeviceFS, AUDIO_OFFSET_HALF);
}
}
主函数main
int main(void)
{
HAL_Init();
SystemClock_Config();
HAL_Delay(100);
MX_GPIO_Init();
MX_DMA_Init();
MX_I2C1_Init();
MX_I2S2_Init();
MX_USART1_UART_Init();
MX_USB_DEVICE_Init();
WM8978_Init();
printf("Sudaroot\r\n");
HAL_Delay(1000);
while (1)
{
}
}
对了,在初始化WM8978的时候,把音量开到最大。然后PC在调整音量的时候会调整音频PCM数据。故PC无法调整硬件WM8978的音量,但是通过调整发送过来的PCM数据也可以实现控制音量的效果。
源码:https://download.csdn.net/download/sudaroot/12532997
B站视频:https://www.bilibili.com/video/BV1xz411e7t5/
全篇完。
本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解方便记录成长笔记。 若有与大神大大见解有冲突,我坚信大神大大见解是对的,我的是错的。 若无法下载源码,可私聊私发。 感谢~!