一. 简介
本篇文章将介绍如何使用ESP32S3通过I2S发送WAV音频数据,驱动MAX98375A进行音频的播放。是EVE_V2项目开发的一部分工作。
二. MAX98375A介绍
芯片特性如下,可以在芯片手册上找到。
- 单电源工作(2.5V至5.5V)
- 3.2W输出功率:4Ω,5V
- 2.4mA静态电流
- 92%效率(RL = 8Ω,POUT = 1W)
- 25µVRMS输出噪声(AV = 15dB)
- 1kHz时,0.015% THD+N
- 无需MCLK
- 8kHz至96kHz采样速率
- 支持左声道、右声道以及(左声道/2 + 右声道/2)输出
外围驱动电路图图如下,用与I2S通讯的IO口有三个: BCLK,LRCLK,DIN。用于控制芯片的引脚有两个:
GAIN: 控制增益值,一般直接拉高即可,有特殊增益的话,可以查看下图,或者Database的 Table8。
SD_MODE: 根据电平值控制左右声道模式,其内部串联了一个100K的电阻,在外部调整上拉电阻的阻值调整模式,拉低可以使芯片Shutdown,不工作。
三. I2S协议
信号线:
- BCLK: 位时钟,SD信号的发送与采集和BCLK进行对齐,时钟速率 = 采样率 * 量化位宽 * 通道数。
- SD: 数据输入输出信号,麦克风对应输出DOUT,扬声器对应DIN,MSB模式输出。
- WS: 左右声道选择信号LRCLK,WS=0 ,表示当前的数据为左声道,WS=1,表示当前数据为右声道。
- MCLK: 主设置,可以不管。
针对MAX98375A的I2S时序图如下,LRCLK用于表示当前的数据的是左声道还是右声道数数据。
当然其中还有许多细节,这些就不需要我们管了,用FPGA做的话,就需要你非常清楚啦。
四. ESP32IDF I2S驱动
根据上面I2S的一点点介绍,可以知道I2S主要涉及到三个参数:采样率 * 量化位宽 * 通道数,所以配置的时候,也是配置这三个参数
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // 使用主模式并设置为发送数据
.sample_rate = 44100, // 设置采样率为44100Hz
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 设置每个采样点的位数为16位
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 只使用右声道
.communication_format = I2S_COMM_FORMAT_STAND_I2S, // I2S通信格式
.dma_buf_count = 8, // 设置DMA缓冲区数量为8
.dma_buf_len = 1024, // 每个DMA缓冲区的长度为1024字节
.intr_alloc_flags = ESP_INTR_FLAG_EDGE, // 分配中断标志
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
配置好,I2S的参数后,就要配置引脚了,方法如下
i2s_pin_config_t pin_config = {
.bck_io_num = MAX98375_BCLK_IO1, // BCLK引脚号
.ws_io_num = MAX98375_LRCLK_IO1, // LRCK引脚号
.data_out_num = MAX98375_DOUT_IO1, // DATA引脚号
.data_in_num = -1, // DATA_IN引脚号
};
i2s_set_pin(I2S_NUM_0, &pin_config);
这样I2S就配置好了,然后就调用下面的函数向I2S中发送数据就可以了。
i2s_write(I2S_NUM_0,buf,len,&sizes,1000);
五. WAV 文件解析
WAV文件的格式 和之前解析过的图片文件bmp类似,整个文件可以分为两大部分: 文件头 和 音频数据部分。我们需要从文件头中获取到I2S所涉及到的三个参数: :采样率 * 量化位宽 * 通道数,以及音频数据。
整个文件格式如下,文件头一共包括44个字节。从图中可以看到每一个部分的大小和偏移地址,以及存储模式是大端存储 还是 小端存储。
- NumChannels: 通道数,1为单通道,左通道或者右通道都可,2为双通道,即立体声。
- SampleRate: 采样率
- BitsPerSample: 音频数据
- data : 音频数据
在每次读取WAV文件的时候,需要根据提取到的信息更新I2S配置,即可。
在ESP32_IDF的例程中,给出了WAV文件格式的结构体
在每次发送完数据后,一定要stop I2S,负责喇叭会有异响,而且可能会发热严重。
FILE* fp = TFCard_Open("/sdcard/3.wav","rb");
struct WAV_File_Head wave_file_head;
uint8_t wav_hd[44];
TFCard_Read(fp,wav_hd,44);
wave_file_head.chunkId = *(uint32_t *)(wav_hd + 0);
wave_file_head.chunkSize = *(uint32_t *)(wav_hd + 4);
wave_file_head.format = *(uint32_t *)(wav_hd + 8);
wave_file_head.subchunk1Id = *(uint32_t *)(wav_hd + 12);
wave_file_head.subchunk1Size = *(uint32_t *)(wav_hd + 16);
wave_file_head.audioFormate = *(uint16_t *)(wav_hd + 20);
wave_file_head.numChannels = *(uint16_t *)(wav_hd + 22);
wave_file_head.sampleRate = *(uint32_t *)(wav_hd + 24);
wave_file_head.byteRatem = *(uint32_t *)(wav_hd + 28);
wave_file_head.blockAlign = *(uint16_t *)(wav_hd + 32);
wave_file_head.bitsPerSanple = *(uint32_t *)(wav_hd + 34);
wave_file_head.subchunk2Id = *(uint32_t *)(wav_hd + 36);
wave_file_head.subchunk2Size = *(uint32_t *)(wav_hd + 40);
i2s_start(I2S_NUM_0);
while( 1 ){
uint8_t data[1024];
uint32_t tt = TFCard_Read(fp,data,1024);
if( tt < 1024){
return;
}
MAX98375_I2S_Send_Buf(data,1024);
vTaskDelay(5);
}
vTaskDelay(pdMS_TO_TICKS(200)); //延时200ms
i2s_zero_dma_buffer(I2S_NUM_0);
i2s_stop(I2S_NUM_0);
六. 小结
本篇文章 介绍了 如何通过解析WAV文件,然后通过I2S 发送给MAX98375A进行音乐播放,介绍的比较简单,只介绍了比较重要的部分,以使用的目的介绍,没有过多的去说明细节;当用上了之后,再根据兴趣去研究相关的细节比较好。需要完整代码的可以在gzh ↓ 进行私聊
欢迎关注 微信公众号 FPGA之旅,qq群 649098696