• ESP32-IDF使用I2S驱动MAX98375--解析WAV文件


    一. 简介

    本篇文章将介绍如何使用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协议

    信号线:

    1. BCLK: 位时钟,SD信号的发送与采集和BCLK进行对齐,时钟速率 = 采样率 * 量化位宽 * 通道数
    2. SD: 数据输入输出信号,麦克风对应输出DOUT,扬声器对应DIN,MSB模式输出。
    3. WS: 左右声道选择信号LRCLK,WS=0 ,表示当前的数据为左声道,WS=1,表示当前数据为右声道。
    4. 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    配置好,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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这样I2S就配置好了,然后就调用下面的函数向I2S中发送数据就可以了。

    i2s_write(I2S_NUM_0,buf,len,&sizes,1000);
    
    • 1

    五. WAV 文件解析

    WAV文件的格式 和之前解析过的图片文件bmp类似,整个文件可以分为两大部分: 文件头 和 音频数据部分。我们需要从文件头中获取到I2S所涉及到的三个参数: :采样率 * 量化位宽 * 通道数,以及音频数据

    整个文件格式如下,文件头一共包括44个字节。从图中可以看到每一个部分的大小和偏移地址,以及存储模式是大端存储 还是 小端存储。

    请添加图片描述

    1. NumChannels: 通道数,1为单通道,左通道或者右通道都可,2为双通道,即立体声。
    2. SampleRate: 采样率
    3. BitsPerSample: 音频数据
    4. 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    六. 小结

    本篇文章 介绍了 如何通过解析WAV文件,然后通过I2S 发送给MAX98375A进行音乐播放,介绍的比较简单,只介绍了比较重要的部分,以使用的目的介绍,没有过多的去说明细节;当用上了之后,再根据兴趣去研究相关的细节比较好。需要完整代码的可以在gzh ↓ 进行私聊

    欢迎关注 微信公众号 FPGA之旅,qq群 649098696

  • 相关阅读:
    前端食堂技术周刊第 47 期:Docusaurus 2.0 、7 月登陆网络平台的新内容 、Nuxt.js 团队的轮子库
    基于springboot实现“漫画之家”系统项目【项目源码+论文说明】
    Eclipse搭建struts2框架
    5、JS-BOM和DOM
    微服务学习(六):实现SSH通信
    精彩,Excel成为编程语言,国产重量级选手再也坐不住了
    Monaco Editor教程(十三):在指定位置插入或替换文本
    Tornado框架路由系统介绍及(IOloop.current().start())启动源码分析
    软考高项考试历程回顾
    如何有效提升你的论证写作能力?
  • 原文地址:https://blog.csdn.net/weixin_44678052/article/details/133169873