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

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

 

二、利用ESP-ADF操作ES8388

2. 详细解析

上一回继续解析到了ESP-ADF的audio_hal层的第1个也是最为关键的函数 —— audio_hal_init()中的第5段代码,也就是mutex_lock函数与mutex_unlock函数之间的临界区代码。再来回顾一下:


audio_hal_handle_t audio_hal_init(audio_hal_codec_config_t *audio_hal_conf, audio_hal_func_t *audio_hal_func)
{
    esp_err_t ret = 0;
    ……
    mutex_lock(audio_hal->audio_hal_lock);
    ret = audio_hal->audio_codec_initialize(audio_hal_conf);
    if (ret == ESP_FAIL) {
        audio_free(audio_hal);
        if (audio_hal_func->handle) {
            return audio_hal_func->handle;
        } else {
            ESP_LOGE(TAG, "codec init failed!");
            return NULL;
        }
    }
    ret |= audio_hal->audio_codec_config_iface(audio_hal_conf->codec_mode, &audio_hal_conf->i2s_iface);
    if ((audio_hal_conf->codec_mode == AUDIO_HAL_CODEC_MODE_DECODE) || (audio_hal_conf->codec_mode == AUDIO_HAL_CODEC_MODE_BOTH)) {
        ret |= audio_hal->audio_codec_set_volume(AUDIO_HAL_VOL_DEFAULT);
    }
    AUDIO_RET_ON_FALSE(TAG, ret, return NULL, "audio_hal_init failed");
    audio_hal->handle = audio_hal;
    audio_hal_func->handle = audio_hal;
    mutex_unlock(audio_hal->audio_hal_lock);
    ……
}

其中的第1段代码:

    ret = audio_hal->audio_codec_initialize(audio_hal_conf);
    if (ret == ESP_FAIL) {
        audio_free(audio_hal);
        if (audio_hal_func->handle) {
            return audio_hal_func->handle;
        } else {
            ESP_LOGE(TAG, "codec init failed!");
            return NULL;
        }
    }

实际上是调用了es8388_init函数。

上一回解析了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;
}

接下来是es8388_init函数的第3段代码,片段如下:

    res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04);  // 0x04 mute/0x00 unmute&ramp;DAC unmute and  disabled digital volume control soft ramp

注意,由此段开始,正式进入到ES8388的相关寄存器的设置了。但在此之前,先讲一下es_write_reg函数。

es_write_reg函数在components\audio_hal\driver\es8388\es8388.c中,代码如下:

static esp_err_t es_write_reg(uint8_t slave_addr, uint8_t reg_add, uint8_t data)
{
    return i2c_bus_write_bytes(i2c_handle, slave_addr, &reg_add, sizeof(reg_add), &data, sizeof(data));
}

i2c_bus_write_bytes函数也是在components\esp_peripherals\driver\i2c_bus\i2c_bus.c中,代码如下:

esp_err_t i2c_bus_write_bytes(i2c_bus_handle_t bus, int addr, uint8_t *reg, int regLen, uint8_t *data, int datalen)
{
    I2C_BUS_CHECK(bus != NULL, "Handle error", ESP_FAIL);
    i2c_bus_t *p_bus = (i2c_bus_t *) bus;
    I2C_BUS_CHECK(p_bus->i2c_port < I2C_NUM_MAX, "I2C port error", ESP_FAIL);
    I2C_BUS_CHECK(data != NULL, "Not initialized input data pointer", ESP_FAIL);
    esp_err_t ret = ESP_OK;
    mutex_lock(p_bus->bus_lock);
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    ret |= i2c_master_start(cmd);
    ret |= i2c_master_write_byte(cmd, addr, 1);
    ret |= i2c_master_write(cmd, reg, regLen, I2C_ACK_CHECK_EN);
    ret |= i2c_master_write(cmd, data, datalen, I2C_ACK_CHECK_EN);
    ret |= i2c_master_stop(cmd);
    ret |= i2c_master_cmd_begin(p_bus->i2c_port, cmd, 1000 / portTICK_RATE_MS);
    i2c_cmd_link_delete(cmd);
    mutex_unlock(p_bus->bus_lock);
    I2C_BUS_CHECK(ret == 0, "I2C Bus WriteReg Error", ESP_FAIL);
    return ret;
}

这一步就是前文书提到的ESP-IDF中I2C操作流程的“3.3 运行I2C通信”。详情参见:ESP32学习笔记(17)——I2C接口使用 - 简书

d41e57135544451aac16fdd92fd6b65a.png

7bb1e3821d9847b099d6c183ba8509ec.png

本回就到这里,下一回正式开始(结合代码和手册)讲解ES8388的相关寄存器设置。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

bind实验

服务端 查看域名 [rootclient yum.repos.d]# hostname client 设置域名 [rootclient yum.repos.d]# hostnamectl set-hostname dns1.openlab.edu [rootclient yum.repos.d]# cd [rootclient ~]# hostname dns1.openlab.edu 安装bind包 [rootclient ~]# yum install bind -y…

【LeetCode每日一题】——717.1比特与2比特字符

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 数组 二【题目难度】 简单 三【题目编号】 717.1比特与2比特字符 四【题目描述】 有两种特…

Linux学习笔记11 系统启动初始化,服务和进程管理(下)

前文 前文介绍了系统启动初始化程序&#xff0c;介绍了systemd的基础知识。这里主要看一下我们systemd的单元管理和常用的命令以及示例。 Linux学习笔记10 系统启动初始化&#xff0c;服务和进程管理&#xff08;上&#xff09;-CSDN博客 systemd单元管理 启动服务 这很常…

pnpm安装electron出现postinstall$ node install.js报错

pnpm install --registryhttp://registry.npm.taobao.org安装依赖包的时候出现了postinstall$ node install.js报错 找到install.js 找到downloadArtifact方法&#xff0c;添加如下代码 mirrorOptions:{mirror:"http://npmmirror.com/mirrors/electron/"}http://n…

程序执行堆栈执行模拟

所有的文件都是在硬盘&#xff08;磁盘&#xff09;上&#xff0c;调用时先调用javac指令的jdk编译成.class然后被java指令的jre送到内存中&#xff0c;java在内存中有自己的一片区域叫JVM&#xff0c;编译进来的文件首先进入方法区。 staitc的属性就是在进入内存的时候开辟了一…

windows平台使用C#创建系统服务

使用 C# 在 Windows 平台创建和管理系统服务 在 Windows 平台上&#xff0c;系统服务&#xff08;Windows Service&#xff09;是一种运行在后台、无需用户交互的应用程序。系统服务广泛应用于长期任务处理、网络监听、后台调度等场景。本文将详细介绍如何使用 C# 创建一个 Win…

JVM_总结详解

1、CPU和内存的交互 了解jvm内存模型前&#xff0c;了解下cpu和计算机内存的交互情况。【因为Java虚拟机内存模型定义的访问操作与计算机十分相似】 有篇很棒的文章&#xff0c;从cpu讲到内存模型:[什么是java内存模型&#xff1f;] 在计算机中&#xff0c;cpu和内存的交互最…

TLinux 3.1 (Centos 8)修改网卡设备名

原网卡设备名&#xff1a;ifcfg-enp17s 新网卡设备名&#xff1a;ifcfg-eth0 1. 修改接口配置文件名 rename /etc/sysconfig/network-scripts/ifcfg-enp17s /etc/sysconfig/network-scripts/ifcfg-eth0 2. 修改接口配置文件 vi /etc/sysconfig/network-scripts/ifcfg-eth…

ElasticSearch7.x入门教程之全文搜索(七)

文章目录 前言一、多条件查询&#xff1a;bool query二、更加精准查询&#xff1a;dis_max query总结 前言 这里再接着上一篇文章继续记录。非常感谢江南一点雨松哥的文章。 欢迎大家去查看&#xff0c;地址&#xff1a;http://www.javaboy.org 一、多条件查询&#xff1a;boo…

基于springboot 的体质测试数据分析及可视化设计LWPPT

技术可行性&#xff1a;技术背景 本企业网站在Windows操作系统中进行开发&#xff0c;并且目前PC机的性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的&#xff0c;也是当下广泛应用的技术之一。 系统的开发环境和配置都是可以自行安装的&#x…

oracle小技巧-解决特殊密码字符而导致的exp错误

在使用oracle数据库的时候&#xff0c;我们经常会利用exp工具对某些表进行导出。但有些时候&#xff0c;因我们用户密码为安全性设有特殊字符&#xff0c;导致exp导出时候报&#xff1a;“EXP-00056和ORA-12154”&#xff0c;今天我们就分享下如何通过设置符号隔离的小技巧解决…

【ArcGIS Pro实操第11期】经纬度数据转化成平面坐标数据

经纬度数据转化成平面坐标数据 数据准备ArcGIS操作步骤-投影转换为 Sinusoidal1 投影2 计算几何Python 示例 另&#xff1a;Sinusoidal (World) 和 Sinusoidal (Sphere) 的主要区别参考 数据准备 数据投影&#xff1a; 目标投影&#xff1a;与MODIS数据相同&#xff08;Sinu…

病理组学分析系列教程1:使用Python-histolab进行病理图像预处理,tiles切片自动生成

首先&#xff0c;先上参考资料链接&#xff1a; 了解数字病理影像图片WSI如何切割-使用histolab 视频详细讲解使用histolab进行病理图像切分 详细介绍数字病理图像的存储格式及格式转换工具介绍 一、病理图像预处理 相信很多朋友对于WSI这种巨大的病理图像的预处理都觉得束…

kubernetes——part3-2 集群声明式文件YAML

一、YAML介绍 YAML 的意思是&#xff1a;仍是一种标记语言&#xff0c;但为了强调这种语言以数据做为中心&#xff0c;而不是以标记语言为重点。是一个可读性高&#xff0c;用来表达数据序列的格式。 二、基本语法 1.低版本缩进时不允许使用Tab键&#xff0c;只允许使用空格…

使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限&#xff0c;校验过用户的用户名和密码后&#xff0c;会向用户响应一段经过加密的token&#xff0c;在这段token中可能储存了数据权限等&#xff0c;在后期的访问中&#xff0c;需要携带这段token&#xff0c;后台解析这段token才…

什么是换电系统?驱动新能源汽车发展的“能源驿站”

随着新能源汽车保有量上升&#xff0c;新能源汽车充换电设施需求量同步增加。由于我国土地、电力资源相对紧张&#xff0c;随着车辆保有量继续增加&#xff0c;换电模式有望成为对充电模式的良好补充&#xff0c;具备广阔的中长期发展前景。蔚来是换电领域的先行者&#xff0c;…

Power BI - Connect to SharePoint online list with Image column

1.简单介绍 当前SharePoint online list有modern和classic两种模式&#xff0c;现在使用modern模式的比较多。list中有Image类型的列&#xff0c;Power BI如何连接到SharePoint list并显示image呢 note, SharePoint list中的Image列&#xff0c;Lookup列&#xff0c;People列…

[在线实验]-Redis Docker镜像的下载与部署

镜像下载 dockerredis镜像资源-CSDN文库 加载镜像 使用以下命令从redis.tar文件中加载Docker镜像 docker load --input redis.tar 创建映射目录 为了确保Redis的数据能够持久化&#xff0c;我们需要创建一个本地目录来存储这些数据 mkdir -p datasource/docker/redis 运…

redis学习(016 实战:黑马点评:分布式锁:Redisson)

黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目 总时长 42:48:00 共175P 此文章包含第64p-第p68的内容 文章目录 分布式锁的优化Redission操作编写代码 Redission可以实现可重入锁的原理lua脚本编写可重入锁获取…

SystemUI 下拉框 Build 版本信息去掉

需求及场景 去掉SystemUI 下拉框 Build 版本信息 如下图所示&#xff1a;去掉 12 &#xff08;SP1A.201812.016) 了解 去掉之前我们先了解它是个什么东西:其实就是一个Build RTM 信息显示 Android_12_build_SP1A.210812.016 修改文件 /frameworks/base/packages/Syste…