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

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

二、利用ESP-ADF操作ES8388

2. 详细解析

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

cpp 复制代码
​
/**
 * @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段代码:

cpp 复制代码
    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中定义,如下:

cpp 复制代码
#define ES8388_MASTERMODE       0x08

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

代码中将该寄存器的值设置为了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中,代码如下:

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

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

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

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

cpp 复制代码
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,代码如下:

cpp 复制代码
#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中定义,如下:

cpp 复制代码
/**
 * @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;

这就可以回到代码中了:

cpp 复制代码
    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中定义,如下:

cpp 复制代码
#define ES8388_MASTERMODE       0x08

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

代码中将该寄存器的值设置为了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段代码就解析完了,下一回继续解析该函数后续内容。

相关推荐
启明云端wireless-tag19 天前
ESP32-S3设备智能化升级,物联网无线AI语音交互,让生活更加便捷和有趣
物联网·乐鑫·esp32-s3·无线方案·ai语音交互
蓝天居士1 个月前
ES8388 —— 带耳机放大器的低功耗立体声音频编解码器(4)
嵌入式·音频·es8388
启明智显1 个月前
AI笔筒操作说明及应用场景
人工智能·嵌入式硬件·嵌入式·ai大模型·启明智显·esp32-s3
启明云端wireless-tag2 个月前
乐鑫ESP32-S3无线方案,AI大模型中控屏智能升级,提升智能家居用户体验
物联网·智能家居·乐鑫·esp32-s3·中控屏
零意@2 个月前
rk3588调试es8388语音编解码IC小结
linux·rk3588·音频编解码·es8388·声卡
启明云端wireless-tag3 个月前
设备智能语音交互控制,乐鑫ESP32-S3智能AI方案,助力产品个性化交互
人工智能·物联网·交互·乐鑫·esp32-s3·wifi模组
咖喱年糕4 个月前
【VSCode】安装 【ESP-IDF】插件及【ESP32-S3】新建工程和工程配置
json·cmake·esp32-s3·esp-idf·project·串口下载
柔贝特三哥4 个月前
19集 两款ESP32开发板如何选择?-《MCU嵌入式AI开发笔记》
人工智能·笔记·单片机·esp32·esp32-s3·esp32-c3·mcu嵌入式ai开发
启明智显6 个月前
【启明智显方案分享】ESP32-S3与GPT AI融合的智能问答嵌入式设备应用解决方案
人工智能·gpt·启明智显·esp32-s3·智慧屏