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

news2024/12/23 19:16:08

一. 简介

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

配置好,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个字节。从图中可以看到每一个部分的大小和偏移地址,以及存储模式是大端存储 还是 小端存储。

请添加图片描述

  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);

六. 小结

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1031379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

anaconda安装完成之后输入conda -V没有反应

anaconda安装完成后&#xff0c;conda没有反应 vim ~/.bashrc后面添加内容 # added by Anaconda3 5.3.0 installer # >>> conda init >>> # !! Contents within this block are managed by conda init !! __conda_setup"$(CONDA_REPORT_ERRORSfalse /u…

springboot实战(七)之jackson配置前后端交互下划线转驼峰对象序列化与反序列化

目录 环境&#xff1a; 1.驼峰转下划线配置 1.1单个字段命名转化使用JsonProperty注解 1.2单个类进行命名转化使用JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)注解 3.全局命名策略配置 2. 序列化以及反序列化 2.1序列化 2.2反序列化 3.自定义序列…

ImageJ查看图像灰度值矩阵及像素编号从0开始

ImageJ查看图像灰度值矩阵 imagej打开一幅图像 然后image —— transform——image to results&#xff0c;等一下就会出现灰度值矩阵 我读取的如下&#xff0c;可以看出&#xff0c;imagej对像素的编号是从0开始的&#xff0c;切记&#xff01;&#xff01;&#xff01;跟C/…

【论文笔记】Scene as Occupancy

原文链接&#xff1a;https://arxiv.org/abs/2306.02851 1. 引言 与传统的3D框物体表达相比&#xff0c;使用3D占用表达是几何感知的&#xff0c;因为3D框表达简化了物体的形状。此外&#xff0c;现有基于视觉的方法很少考虑时间信息&#xff1b;单阶段方法缺少从粗到细的细化…

Linux 线程(thread)

进程线程区别 创建线程 #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -功能&#xff1a;创建一个子线程&#xff0c;一般情况下main函数所在的线程称为主线程&#xff0c;…

科技资讯|Canalys发布全球可穿戴腕带设备报告,智能可穿戴增长将持续

市场调查机构 Canalys 近日发布报告&#xff0c;表示 2023 年第 2 季度全球可穿戴腕带设备出货量达 4400 万台&#xff0c;同比增长了 6%。 主要归功于其亲民的价格以及消费者对价位较高的替代品仍持谨慎态度&#xff0c;基础手环市场尽管与去年同期相比有所下降&#xff0c;…

JDBC连接mysql

文章目录 JDBC简介JDBC-MYSQL驱动下载JDBC使用通过结果集查询 PreparedStatement 预处理查询事务批处理连接池1.C3P02.德鲁伊 druid DBUtils工具 JDBC简介 JDBC(Java Data Connectivity,java数据库连接)是一种用于执行sql语句的JavaAPI&#xff0c;可以为多种关系数据库提供统…

极简式看图软件 Pixea Plus for Mac

Pixea Plus for Mac介绍 简单易用&#xff1a;Pixea的用户界面非常简洁直观&#xff0c;容易上手。 图片管理&#xff1a;Pixea允许用户创建个人或业务相册&#xff0c;并提供了图片搜索、排序、过滤等多种管理功能&#xff0c;方便用户组织和查找照片。 图片编辑&#xff1…

【Java 基础篇】Java网络编程:文件下载详解

文件下载是网络应用程序中的一个常见任务&#xff0c;允许用户从远程服务器获取文件。Java提供了丰富的网络编程库&#xff0c;使文件下载变得相对简单。本文将详细介绍如何使用Java进行文件下载&#xff0c;并提供一些相关内容的解释。 什么是文件下载 文件下载是指从一个网…

Django之初入门

一&#xff09;Django简介 1.简介 Django是一个开源的Python Web框架&#xff0c;它以简洁高效的方式帮助开发者构建复杂的Web应用程序。Django采用了MVC&#xff08;Model-View-Controller&#xff09;的架构模式&#xff0c;通过强大的工具和功能&#xff0c;提供了一套完整…

最新版本 在线生成SSL证书源码 后台对接ssl证书api接口

SSL证书是保证网络安全的基本保障之一。向您介绍我们的在线生成SSL证书系统&#xff0c; 支持在线生成SSL证书系统&#xff0c;用户登录可在线申请SSL&#xff0c;后台对接ssl证书api接口。

金融行业如何利用软文营销进行品牌维护

金融行业作为强监管行业&#xff0c;与人民财产息息相关&#xff0c;因此塑造可靠的品牌形象是金融行业必须面对的课题&#xff0c;而金融行业的特性决定了它在品牌传播与建设上会受到一定的限制&#xff0c;因此金融行业想要进行品牌维护的话&#xff0c;软文营销就是非常不错…

频频刷屏朋友圈,白酒如何越来越年轻化?来聊聊白酒企业数字化

最近&#xff0c;某白酒品牌频频吸引大众眼球&#xff0c;白酒与咖啡、巧克力等联名衍生品一经推出便掀起热潮。某商品由于太过火爆&#xff0c;甚至一度售罄下架。 不得不说&#xff0c;我国拥有超大规模内需市场&#xff0c;消费潜力巨大。 当前&#xff0c;创新消费场景加…

vue 路由中 vite 与webpack 动态 导入的方法汇总

vite 动态导入路由&#xff1a; router/index.js文件 //vite 下面寻找 views 文件夹下面所有的page.js文件 let pageList import.meta.glob(../views/**/page.json, {eager: true,import: default, }); //所有的文件 const modules import.meta.glob(../views/**/**.vue);/…

el-select 下拉框全选、多选的几种方式组件

组件一、基础多选 适用性较广的基础多选&#xff0c;用 Tag 展示已选项 <template><el-select v-model"value1" multiple placeholder"请选择"><el-optionv-for"item in options":key"item.value":label"item.la…

linux下特定usb设备的权限设置

文章目录 背景查找资料解决方案 背景 目前我在Ubuntu下使用一个USB热成像摄像头&#xff0c;通过调用它的sdk进行图像的采集以及获取对应像素点的温度。假设我现在的测试程序名称为MyApp。 当我用下面的命令运行时&#xff0c;程序是正常运行且能从热成像仪采集图像 sudo ./M…

上新!100%国产物料认证,米尔入门级国产核心板全志T113-i方案

自米尔国产全志T113系列的核心板发布以来&#xff0c;这款高性价比、低成本、入门级、高性能的国产核心板咨询不断&#xff0c;配套的开发板已经成交量数百套&#xff0c;深受工程师们的青睐&#xff0c;为了集齐T113全系列的产品&#xff0c;这次米尔发布了基于全志T113-i处理…

Spring学习笔记2 Spring的入门程序

Spring学习笔记1 启示录_biubiubiu0706的博客-CSDN博客 Spring官网地址:https://spring.io 进入github往下拉 用maven引入spring-context依赖 写spring的第一个程序 引入下面依赖,好比引入Spring的基本依赖 <dependency><groupId>org.springframework</groupId&…

DA5 网站用户没有补全的信息

目录 1.题目描述 2.输入描述 3.输出描述 4.题目分析 5.通过代码 1.题目描述 现有一个Nowcoder.csv文件&#xff0c;它记录了牛客网的部分用户数据&#xff0c;包含如下字段&#xff08;字段与字段之间以逗号间隔&#xff09;&#xff1a; Nowcoder_ID&#xff1a;用户ID …

应用在苹果应用商店该如何进行优化

众所周知&#xff0c;ASO最大化的提高应用程序在商店中的可见性&#xff0c;其目标是获得更多的下载量&#xff0c;同时它也与下载的转化率有关。 1、根据应用阶段追求不同的目标。 它可以是有机增长或转化率的提高&#xff0c;获得更多安装并降低用户获取成本&#xff0c;增加…