ESP32-S3模组上跑通ES8388(12)

news2024/12/26 21:45:26

接前一篇文章:ESP32-S3模组上跑通ES8388(11)

 

二、利用ESP-ADF操作ES8388

2. 详细解析

上一回解析了es8388_init函数中的第5段代码,本回继续往下解析。为了便于理解和回顾,再次贴出es8388_init函数源码,在components\audio_hal\driver\es8388\es8388.c中,如下:

​
/**
 * @return
 *     - (-1)  Error
 *     - (0)   Success
 */
esp_err_t es8388_init(audio_hal_codec_config_t *cfg)
{
    int res = 0;
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
    headphone_detect_init(get_headphone_detect_gpio());
#endif
 
    res = i2c_init(); // ESP32 in master mode
 
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04);  // 0x04 mute/0x00 unmute&ramp;DAC unmute and  disabled digital volume control soft ramp
    /* Chip Control and Power Management */
    res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50);
    res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00); //normal all and power up all
 
    // Disable the internal DLL to improve 8K sample rate
    res |= es_write_reg(ES8388_ADDR, 0x35, 0xA0);
    res |= es_write_reg(ES8388_ADDR, 0x37, 0xD0);
    res |= es_write_reg(ES8388_ADDR, 0x39, 0xD0);
 
    res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg->i2s_iface.mode); //CODEC IN I2S SLAVE MODE
 
    /* dac */
    res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0xC0);  //disable DAC and disable Lout/Rout/1/2
    res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x12);  //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
//    res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0);  //LPVrefBuf=0,Pdn_ana=0
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL1, 0x18);//1a 0x18:16bit iis , 0x00:24
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL2, 0x02);  //DACFsMode,SINGLE SPEED; DACFsRatio,256
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x00); // 0x00 audio on LIN1&RIN1,  0x09 LIN2&RIN2
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90); // only left DAC to left mixer enable 0db
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90); // only right DAC to right mixer enable 0db
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); // set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00); // vroi=0
 
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL24, 0x1E); // Set L1 R1 L2 R2 volume. 0x00: -30dB, 0x1E: 0dB, 0x21: 3dB
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL25, 0x1E);
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0);
    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0);
    // res |= es8388_set_adc_dac_volume(ES_MODULE_DAC, 0, 0);       // 0db
    int tmp = 0;
    if (AUDIO_HAL_DAC_OUTPUT_LINE2 == cfg->dac_output) {
        tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_ROUT1;
    } else if (AUDIO_HAL_DAC_OUTPUT_LINE1 == cfg->dac_output) {
        tmp = DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT2;
    } else {
        tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2;
    }
    res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, tmp);  //0x3c Enable DAC and Enable Lout/Rout/1/2
    /* adc */
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xFF);
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, 0xbb); // MIC Left and Right channel PGA gain
    tmp = 0;
    if (AUDIO_HAL_ADC_INPUT_LINE1 == cfg->adc_input) {
        tmp = ADC_INPUT_LINPUT1_RINPUT1;
    } else if (AUDIO_HAL_ADC_INPUT_LINE2 == cfg->adc_input) {
        tmp = ADC_INPUT_LINPUT2_RINPUT2;
    } else {
        tmp = ADC_INPUT_DIFFERENCE;
    }
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, tmp);  //0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input; DSSEL,use one DS Reg11; DSR, LINPUT1-RINPUT1
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL3, 0x02);
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, 0x0c); // 16 Bits length and I2S serial audio data format
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, 0x02);  //ADCFsMode,singel SPEED,RATIO=256
    //ALC for Microphone
    res |= es8388_set_adc_dac_volume(ES_MODULE_ADC, 0, 0);      // 0db
    res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x09);    // Power on ADC, enable LIN&RIN, power off MICBIAS, and set int1lp to low power mode
    
    /* es8388 PA gpio_config */
    gpio_config_t  io_conf;
    memset(&io_conf, 0, sizeof(io_conf));
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pin_bit_mask = BIT64(get_pa_enable_gpio());
    io_conf.pull_down_en = 0;
    io_conf.pull_up_en = 0;
    gpio_config(&io_conf);
    /* enable es8388 PA */
    es8388_pa_power(true);
 
    codec_dac_volume_config_t vol_cfg = ES8388_DAC_VOL_CFG_DEFAULT();
    dac_vol_handle = audio_codec_volume_init(&vol_cfg);
    ESP_LOGI(ES_TAG, "init,out:%02x, in:%02x", cfg->dac_output, cfg->adc_input);
    return res;
}

接下来是第6段代码:

    res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg->i2s_iface.mode); //CODEC IN I2S SLAVE MODE

ES8388_MASTERMODE

ES8388_MASTERMODE宏也在components\audio_hal\driver\es8388\es8388.h中定义,如下:

#define ES8388_MASTERMODE       0x08

其代表了ES8388的Master Mode Control寄存器。参见ES8388数据手册中的以下部分:

1e4756f2015a4ba49158c4d00c17670d.png

代码中将该寄存器的值设置为了cfg->i2s_iface.mode。那么这个cfg->i2s_iface.mode是什么值?在哪里被赋值的?

要弄清楚这些问题,就必须从es8388_init函数的参数audio_hal_codec_config_t *cfg以及调用它的地方传入的对应实参讲起。

先来看es8388_init函数是在哪里调用的。前文书讲过,es8388_init函数实际上对应的是audio_hal_func_t AUDIO_CODEC_ES8388_DEFAULT_HANDLE中的.audio_codec_initialize成员函数指针。再来回顾一下,在components\audio_hal\driver\es8388\es8388.c中,代码如下:

ad54d6243843483db93207066425d81d.png

也就是说,实际需要搜索ESP-ADF工程中调用audio_codec_initialize的地方。经过搜索,真正调用的地方只有一处,在components\audio_hal\audio_hal.c中audio_hal_init函数中,代码如下:

e576e6bd73b14fc0832c292aa408bfea.png

其实这里是个圈。本来就是沿着这条路径分析下来的,现在又回到了起点。不过这里并不是循环,只是由于之前没有关注,因此我们在此需要会看一下,弄清楚调用audio_hal_init函数时,传入的audio_hal_conf对应的实参是什么值。

再次在工程路径下搜索“audio_hal_init”,得到结果如下:

1cb0f4eadf69421e8cec9ad79836dd9f.png

这里,仍以ESP32-Lyrat V4_3开发板为例,看一下其调用audio_hal_init时传入的audio_hal_conf对应的值是多少。在components\audio_board\lyrat_v4_3\board.c中,代码如下:

audio_hal_handle_t audio_board_codec_init(void)
{
    audio_hal_codec_config_t audio_codec_cfg = AUDIO_CODEC_DEFAULT_CONFIG();
    audio_hal_handle_t codec_hal = audio_hal_init(&audio_codec_cfg, &AUDIO_CODEC_ES8388_DEFAULT_HANDLE);
    AUDIO_NULL_CHECK(TAG, codec_hal, return NULL);
    return codec_hal;
}

由代码可知,调用audio_hal_init函数时,传给其参数audio_hal_codec_config_t *audio_hal_conf的实参为&audio_codec_cfg,而audio_codec_cfg又是通过AUDIO_CODEC_DEFAULT_CONFIG()得到的。AUDIO_CODEC_DEFAULT_CONFIG()是一个宏函数,其定义在components\audio_board\lyrat_v4_3\board_def.h,代码如下:

#define AUDIO_CODEC_DEFAULT_CONFIG(){                   \
        .adc_input  = AUDIO_HAL_ADC_INPUT_LINE1,        \
        .dac_output = AUDIO_HAL_DAC_OUTPUT_ALL,         \
        .codec_mode = AUDIO_HAL_CODEC_MODE_BOTH,        \
        .i2s_iface = {                                  \
            .mode = AUDIO_HAL_MODE_SLAVE,               \
            .fmt = AUDIO_HAL_I2S_NORMAL,                \
            .samples = AUDIO_HAL_48K_SAMPLES,           \
            .bits = AUDIO_HAL_BIT_LENGTH_16BITS,        \
        },                                              \
};

由此就能知道cfg->i2s_iface.mode的值是什么了,是AUDIO_HAL_MODE_SLAVE。
AUDIO_HAL_MODE_SLAVE宏在components\audio_hal\include\audio_hal.h中定义,如下:

/**
 * @brief Select I2S interface operating mode i.e. master or slave for audio codec chip
 */
typedef enum {
    AUDIO_HAL_MODE_SLAVE = 0x00,   /*!< set slave mode */
    AUDIO_HAL_MODE_MASTER = 0x01,  /*!< set master mode */
} audio_hal_iface_mode_t;

这就可以回到代码中了:

    res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg->i2s_iface.mode); //CODEC IN I2S SLAVE MODE

ES8388_MASTERMODE

ES8388_MASTERMODE宏也在components\audio_hal\driver\es8388\es8388.h中定义,如下:

#define ES8388_MASTERMODE       0x08

其代表了ES8388的Master Mode Control寄存器。参见ES8388数据手册中的以下部分:

1e4756f2015a4ba49158c4d00c17670d.png

代码中将该寄存器的值设置为了0x00,也就是0b00000000,意义如下:

  • MSC(bit 7)

0:slave serial port mode。从串行端口模式。

  • MCLKDIV2(bit 6)

0:MCLK not divide (default)。MCLK不分频(默认)。

  • BCLK_INV(bit 5)

0:normal (default)。正常(默认)。

  • BCLKDIV(bit 4:0)

0b00000:master mode BCLK generated automatically based on the clock table (default)。根据时钟表自动生成主模式BCLK(默认)。

 

至此,es8388_init函数中的第6段代码就解析完了,下一回继续解析该函数后续内容。

 

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

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

相关文章

对于相对速度的重新理解 - 15

换一个视角看待能量可能一切都更为清晰&#xff0c;从&#xff0c; 可以意识到&#xff0c;最终质量 指的是 的数量。这个数量就是 我们可以去除电性振动和磁性振动的影响&#xff0c;把这两种振动的影响归结在 里面&#xff0c;这就像是&#xff0c;有一百万个某种物体&#x…

记一次腾讯云海外服务器http能正常访问https访问拒绝问题处理过程

最近双十一, 购了一台腾讯云的海外服务器&#xff0c; 开通后就是一堆的服务器软件安装数据上传和配置&#xff0c;没想到&#xff0c;等待配置完成后才发现https无法正常访问&#xff0c;于是开启了自查。 1. 检查nginx软件的ssl配置 nginx http https配置参考 server {l…

Java 单元测试模拟框架-Mockito 的介绍

Mockito 是什么 Mockito 是一个用于单元测试的模拟框架&#xff0c;基于它可以使用简洁易用的API编写出色的测试。 Mockito 允许开发人员创建和管理模拟对象&#xff08;mock objects&#xff09;&#xff0c;以便在测试过程中替换那些不容易构造或获取的对象。 Mockito的基本…

分享一款 Vue 图片编辑插件 (推荐)

&#x1f4a5;本篇文章给大家分享一款强大到没朋友的Vue图片编辑插件&#xff0c;可以对图片进行旋转、缩放、裁剪、涂鸦、标注、添加文本等&#xff0c;快来试试并收藏吧&#xff01;&#x1f495; 这是一款对图片进行旋转、缩放、裁剪、涂鸦、标注、添加文本在线处理的图片处…

在基于控制器的 API 和最小 API 之间进行选择

文章目录 ASP.NET Core 支持两种创建 API 的方法&#xff1a;基于控制器的方法和最小 API。 API 项目中的控制器是派生自 ControllerBase 的类。 最小 API 在 Lambda 或方法中使用逻辑处理程序定义终结点。 本文解释了这两种方法之间的差异。 最小 API 的设计默认隐藏了主机类…

【UVM】phase机制

Phase的种类 funcion phase 不消耗仿真时间 八种&#xff08;图中白色背景&#xff09; task phase 消耗仿真时间 一种&#xff08;图中灰色背景&#xff09;&#xff0c;run_phase又可以细分为十二种 Phase的功能 bulid_phase&#xff1a;uvm_component类的实例化&…

《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》

《装甲车内气体检测“神器”:上海松柏 K-5S 电化学传感器模组详解》 一、引言二、K-5S 电化学传感器模组概述&#xff08;一&#xff09;产品简介&#xff08;二&#xff09;产品特点&#xff08;三&#xff09;产品适用场景 三、电化学传感器原理及优点&#xff08;一&#xf…

【Linux课程学习】:文件第二弹---理解一切皆文件,缓存区

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux课程学习 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 Linux学习笔记&#xff1a; https://blog.csdn.net/d…

汽车控制软件下载移动管家手机控车一键启动app

移动管家手机控制汽车系统是一款实现车辆远程智能控制的应用程序‌。通过下载并安装特定的APP&#xff0c;用户可以轻松实现以下功能&#xff1a;‌远程启动与熄火‌&#xff1a;无论身处何地&#xff0c;只要有网络&#xff0c;即可远程启动或熄火车辆&#xff0c;提前预冷或预…

匿名发帖/匿名论坛功能设计与实现(编辑发帖部分)

前言 还是之前的音乐系统&#xff0c;首页一直是没想好写些什么&#xff0c;想写一个基于数据分析筛选的歌曲推荐功能&#xff0c;但是目前技术选型没太有考究等以后再实现吧&#xff0c;昨天突然想到可以把首页设计成前40%页面是歌曲推荐后面接下来就是一段匿名论坛功能&…

微信小程序 城市点击后跳转 并首页显示被点击城市

在微信小程序中&#xff0c;渲染出城市列表后&#xff0c;如何点击城市&#xff0c;就跳转回到首页&#xff0c;并在首页显示所点击的城市呢&#xff1f; 目录 一、定义点击城市的事件 二、首页的处理 首页&#xff1a;点击成都市会跳转到城市列表 城市列表&#xff1a;点击…

DOM,事件监听和VUE入门

四个事件、 JS模块化 VUE入门 Ajax VUE总结

Python学习笔记(5)Python的创建型设计模式

创建型设计模式&#xff08;Creational Design Patterns&#xff09;&#xff0c;主要关注对象的创建机制。这类模式可以使得系统更加独立于如何创建、组合和表示其对象。通过将这些职责分离出来&#xff0c;创建型设计模式有助于提高代码的灵活性和复用性。 本书的范例代码已经…

云备份实战项目

文章目录 前言一、整体项目简介二、服务端环境及功能简介三、 客户端环境及功能简介四、服务端文件管理类的实现1. 获取文件大小&#xff0c;最后一次修改时间&#xff0c;最后一次访问时间&#xff0c;文件名称&#xff0c;以及文件内容的读写等功能2. 判断文件是否存在&#…

Java有关数组的相关问题

Java中的栈和堆的含义 栈 存储局部变量&#xff1a;栈主要用于存储方法中的局部变量&#xff0c;包括基本数据类型&#xff08;int、double、boolean等&#xff09;和对象的引用&#xff08;不包含对象本身&#xff09;。 遵循后进先出原则&#xff1a;当一个方法被调用时&…

使用Dify与BGE-M3搭建RAG(检索增强生成)应用-改进一,使用工作流代替Agnet

文章目录 前言Agent vs 工作流编写工作流 前言 在上一篇中&#xff0c;我们实现了一个基本的基于Dify的RAG的示范。 使用Dify与BGE-M3搭建RAG&#xff08;检索增强生成&#xff09;应用 这个效果确实很差。 我们一起来看看&#xff0c;该怎么改进。 今天我们就尝试一下&…

Python语法基础(四)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 高阶函数之map 高阶函数就是说&#xff0c;A函数作为B函数的参数&#xff0c;B函数就是高阶函数 map&#xff1a;映射 map(func,iterable) 这个是map的基本语法&#xff0c;…

Python毕业设计选题:基于django+vue的智慧社区可视化平台的设计与实现+spider

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 管理员登录 管理员功能界面 养老机构管理 业主管理 社区安防管理 社区设施管理 车位…

Ubuntu环境中RocketMQ安装教程

参考教程 https://blog.csdn.net/weixin_56219549/article/details/126143231 1、安装JDK&#xff0c;并配置环境变量&#xff08;略&#xff09; 2、下载RocketMQ安装包 RocketMQ下载地址&#xff0c;选择二进制包下载 unzip rocketmq-all-5.0.0-ALPHA-bin-release.zip 使…

【SSM】mybatis的增删改查

目录 代理Dao方式的增删改查 1. 创建项目 $$1. 在sql.xml里增加日志代码以及user的mapper资源。 $$ 2. 在usermapper里引入接口。 $$3. 在测试类中引入以下代码&#xff0c;并修改其中名字。 $$ 4. 实例对象User.java里属性要与表中列严格对应。 2. 查询 1>. 查询所有 …