当前位置: 首页 > article >正文

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的相关寄存器设置。

 


http://www.kler.cn/a/417584.html

相关文章:

  • MongoDB 查询文档
  • HTTP和HTTPS协议详解
  • 理解 C 与 C++ 中的 const 常量与数组大小的关系
  • pytorch实现门控循环单元 (GRU)
  • 【漫话机器学习系列】070.汉明损失(Hamming Loss)
  • 实时波形与频谱分析———傅立叶变换
  • android studio Terminal控制台命令打包 apk
  • 0.shell 脚本执行方式
  • 零基础Python学习
  • centos7.6升级cmake+编译pcm工具
  • Mybatis:CRUD数据操作之单个条件(动态SQL)
  • FreeRTOS 软件定时器
  • Selenium 自动化测试demo
  • 【K230 CanMV】图像识别-摄像头获取图像 Sensor 函数全解析
  • 开源法律、政策和实践
  • ArcGIS栅格影像裁剪工具
  • R安装rgdal报错 解决办法
  • Android 引入 proto 项目及使用方法
  • 网络安全相关证书资料
  • linux环境下,导出conda和pip的安装包和对应版本
  • solana java 转账交易示例
  • 前端用原生js下载File对象文件,多用于上传附件时,提交之前进行点击预览,或打开本地已经选择待上传的附件列表
  • DDR3保姆级使用教程:ZYNQ 7010
  • 【嵌入式——QT】QT制作安装包
  • 什么是换电系统?驱动新能源汽车发展的“能源驿站”
  • 构造函数与析构函数错题汇总