STM32CbueIDE Audio播放音频 WM8978 + I2S

随言:

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​​​​​​​

 

仅想播放声音,一切从简。

步骤:了解wav音频格式,了解I2S协议,看手册配置WM8978,把数据通过I2S发给WM8978。

简化,暂不使用DMA发送数据,在网上都是双DMA缓存外部存储发送音频数据,容易绕晕。

不使用外部存储,使用芯片内部flash存储音频,音频数据加上程序不超过内部flash大小即可。

这既是我喜欢STM32CbueIDE这个软件的原因,能实时看到编译后的芯片资源剩余情况。

STM32CbueIDE Audio播放音频 WM8978 + I2S_第1张图片

 

 

WAV音频格式,自行百度。

 

I2S主要特性:下面内容摘自《STM32F4xx中文参考手册.pdf》

I2S 与 SPI 共用以下三个引脚:
● SD / DACDAT:串行数据(映射到 MOSI 引脚),用于发送或接收两个时分复用的数据通道上的数据(仅半双工模式)。
● WS / LRC:字选择(映射到 NSS 引脚),是主模式下的数据控制信号输出以及从模式下的数据控制信号输入。切换声道。
● CK / BCLK:串行时钟(映射到 SCK 引脚),是主模式下的串行时钟输出以及从模式下的串行时钟输入。
● I2S2ext_SD / I2S3ext_SD / ADCDAT:用于控制 I2S 全双工模式的附加引脚 (映射到 MISO 引脚)。
● MCK / MCLK:当 I2S 配置为主模式(并且 SPI_I2SPR 寄存器中的 MCKOE 位置 1)时,使用主时钟(单独映射)输出此附加时钟,该时钟输出频率 256 × FS,其中 FS 为音频信号采样频率。

 

注意STM32 对 24bit音频的相关操作。

 

STM32CbueIDE Audio播放音频 WM8978 + I2S_第2张图片

STM32CbueIDE Audio播放音频 WM8978 + I2S_第3张图片

STM32CbueIDE Audio播放音频 WM8978 + I2S_第4张图片

STM32CbueIDE Audio播放音频 WM8978 + I2S_第5张图片

 

 

WM8978主要特性:

WM8978手册:https://download.csdn.net/download/sudaroot/12497130

●I2S接口,支持最高192K,24bit音频播放
●DAC信噪比98dB;ADC信噪比90dB
●支持无电容耳机驱动(提供40mW@16Ω的输出能力)
●支持扬声器输出(提供0.9W@8Ω的驱动能力)
●支持立体声差分输入/麦克风输入
●支持左右声道音量独立调节
●支持3D效果,支持5路EQ调节

WM8978的控制通过I2S接口(即数字音频接口)同MCU进行音频数据传输(支持音频接收和发送)。

通过两线(MODE=0,即IIC接口)或三线(MODE=1)接口进行配置。

注意:

WM8978 的 寄存器只支持写操作不支持读操作。自己可以把寄存器值用数组存储下来。

WM8978 每个寄存器有0 ~ 8bit,共9bit控制。

STM32CbueIDE Audio播放音频 WM8978 + I2S_第6张图片

看下图I2C的时序,除了设备地址后,在发送寄存器地址的时候把要发送给该寄存器的数据的最高位(即bit8)一起发送。

即发送(reg_addr << 1) | ((data >> 8) & 0x01);

STM32CbueIDE Audio播放音频 WM8978 + I2S_第7张图片

由于WM8978只支持写操作,无读操作。故有唯一(写)地址 0x34 。

 

最简单的操作顺序:

1、芯片上电和关机操作顺序

STM32CbueIDE Audio播放音频 WM8978 + I2S_第8张图片

 

SPEAKER OUTPUTS (LOUT2 AND ROUT2) 后面还有内容,看手册54页吧。

STM32CbueIDE Audio播放音频 WM8978 + I2S_第9张图片

STM32CbueIDE Audio播放音频 WM8978 + I2S_第10张图片

实际按照上电顺序操作,再R4选择I2S(FMT)和数据格式(WL),R6选择外部MCK时钟CLKSEL = 0,再调整一下左右声道音量,就能出声音了。

如果喜欢输出音质好一下R10寄存器设置一下 DACOSR128 = 1;

还有R43寄存器ROUT2信号路径还具有可选的反相器。用于该反相的放大器可用于以-15dB-> + 6dB的可调增益范围混入AUXR信号。这样就可以将“蜂鸣”信号仅应用于扬声器输出,而不会影响HP或线路输出。

 

 

硬件图:某原子STM32F407ZG + WM8978

STM32CbueIDE Audio播放音频 WM8978 + I2S_第11张图片

 

 

STM32CubeIDE

配置I2C控制WM8978寄存器。

STM32CbueIDE Audio播放音频 WM8978 + I2S_第12张图片

 

I2S协议。使用的音频是双声道8KHz 16bit音频。

STM32CbueIDE Audio播放音频 WM8978 + I2S_第13张图片

生成代码。

 

WM8978控制代码,其中datas.h里面是音频数据。

#include 
#include 
#include 
#include "datas.h"

#define	WM8978_ADDRESS				0x1A
#define	WM8978_WIRTE_ADDRESS		(WM8978_ADDRESS << 1 | 0)
#define	BUFFER_SIZE					2048

HAL_StatusTypeDef WM8978_Register_Wirter(uint8_t reg_addr, uint16_t data)
{
	uint8_t pData[10] = {0};

	pData[0] = (reg_addr << 1) | ((data >> 8) & 0x01);
	pData[1] = data & 0xFF;
	return HAL_I2C_Master_Transmit(&hi2c1, WM8978_WIRTE_ADDRESS, pData, 2, 1000);
}

void WM8978_Init(void)
{
	WM8978_Register_Wirter(0, 0);		// 软复位
	WM8978_Register_Wirter(1, 0x0F);	// 模拟放大器使能, 使能输出输入缓存区
	WM8978_Register_Wirter(3, 0x7F);	// 使能左右声道和L\ROUT2
	WM8978_Register_Wirter(4, 0x10);	// I2S 16bit
	WM8978_Register_Wirter(6,0);		// MCU提供时钟
	WM8978_Register_Wirter(10, 0x08);	// 输出音质最好
	WM8978_Register_Wirter(43, 0x10);	// ROUT2反相
	WM8978_Register_Wirter(54,30);		// 设置LOUT2左声道音量
	WM8978_Register_Wirter(55,30|(1<<8));	// 设置ROUT2右声道音量, 更新左右声道音量
}

void WM8978_Palyer(void)
{
	uint32_t DataLength = 0;
	uint8_t* DataAddress = NULL;
	uint16_t* TempAddress = NULL;

	DataLength = sizeof(data) - 0x2c;
	DataAddress = (unsigned char *)(data + 0x2c);
	TempAddress = (uint16_t*)DataAddress;

	while(1)
	{
		HAL_I2S_Transmit(&hi2s2, TempAddress, BUFFER_SIZE / 2, 1000);
		DataLength -= BUFFER_SIZE;
		TempAddress += (BUFFER_SIZE / 2);
		if(DataLength < BUFFER_SIZE) break;
	}
}

 

主函数:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CRC_Init();
  MX_I2C1_Init();
  MX_I2S2_Init();
  MX_USART1_UART_Init();
  printf("Sudaroot\r\n");

  WM8978_Init();
  WM8978_Palyer();

  while (1)
  {

  }
}

 

源码:https://download.csdn.net/download/sudaroot/12497400

 

本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解方便记录成长笔记。 若有与大神大大见解有冲突,我坚信大神大大见解是对的,我的是错的。 感谢~!

你可能感兴趣的:(STM32)