This commit is contained in:
2026-05-22 21:52:50 +03:00
commit be7c60e4dd
1854 changed files with 583428 additions and 0 deletions
@@ -0,0 +1,704 @@
/*
This is a very basic driver for the ES8388 based on the driver written by
me for NuttX. It is not complete and is missing master mode, mono mode, many
features and configuration options. You can use readReg and writeReg to
access the registers directly and configure missing features. Feel free to
contribute by adding missing features and improving the driver.
It is intended to be used only with arduino-esp32.
The default configuration can be found in the ES8388.h file.
This was only tested with the ESP32-LyraT board using 44100Hz 16-bit stereo
audio. It may not work with other configurations.
Created for arduino-esp32 on 20 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#include <cmath>
#include "ESP_I2S.h"
#include "Wire.h"
#include "ES8388.h"
/****************************************************************************
* Private Methods
****************************************************************************/
/*
Name: start
Description:
Unmute and start the ES8388 codec data transmission.
*/
void ES8388::start() {
uint8_t prev_regval = 0;
uint8_t regval = 0;
log_v("Starting ES8388 transmission...");
_running = true;
prev_regval = readReg(ES8388_DACCONTROL21);
if (_audio_mode == ES_MODULE_LINE) {
writeReg(ES8388_DACCONTROL16, ES8388_RMIXSEL_RIN2 | ES8388_LMIXSEL_LIN2);
writeReg(ES8388_DACCONTROL17, ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | ES8388_LI2LO_ENABLE | ES8388_LD2LO_DISABLE);
writeReg(ES8388_DACCONTROL20, ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | ES8388_RI2RO_ENABLE | ES8388_RD2RO_DISABLE);
writeReg(
ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | ES8388_LRCK_SEL_ADC | ES8388_SLRCK_SAME
);
} else {
writeReg(
ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | ES8388_LRCK_SEL_DAC | ES8388_SLRCK_SAME
);
}
regval = readReg(ES8388_DACCONTROL21);
if (regval != prev_regval) {
writeReg(
ES8388_CHIPPOWER, ES8388_DACVREF_PDN_PWRUP | ES8388_ADCVREF_PDN_PWRUP | ES8388_DACDLL_PDN_NORMAL | ES8388_ADCDLL_PDN_NORMAL | ES8388_DAC_STM_RST_RESET
| ES8388_ADC_STM_RST_RESET | ES8388_DAC_DIGPDN_RESET | ES8388_ADC_DIGPDN_RESET
);
writeReg(
ES8388_CHIPPOWER, ES8388_DACVREF_PDN_PWRUP | ES8388_ADCVREF_PDN_PWRUP | ES8388_DACDLL_PDN_NORMAL | ES8388_ADCDLL_PDN_NORMAL | ES8388_DAC_STM_RST_NORMAL
| ES8388_ADC_STM_RST_NORMAL | ES8388_DAC_DIGPDN_NORMAL | ES8388_ADC_DIGPDN_NORMAL
);
}
if (_audio_mode == ES_MODULE_LINE || _audio_mode == ES_MODULE_ADC_DAC || _audio_mode == ES_MODULE_ADC) {
writeReg(
ES8388_ADCPOWER, ES8388_INT1LP_NORMAL | ES8388_FLASHLP_NORMAL | ES8388_PDNADCBIASGEN_NORMAL | ES8388_PDNMICB_PWRON | ES8388_PDNADCR_PWRUP
| ES8388_PDNADCL_PWRUP | ES8388_PDNAINR_NORMAL | ES8388_PDNAINL_NORMAL
);
}
if (_audio_mode == ES_MODULE_LINE || _audio_mode == ES_MODULE_ADC_DAC || _audio_mode == ES_MODULE_DAC) {
writeReg(
ES8388_DACPOWER, ES8388_ROUT2_ENABLE | ES8388_LOUT2_ENABLE | ES8388_ROUT1_ENABLE | ES8388_LOUT1_ENABLE | ES8388_PDNDACR_PWRUP | ES8388_PDNDACL_PWRUP
);
}
setmute(_audio_mode, false);
log_v("ES8388 transmission started.");
}
/*
Name: reset
Description:
Reset the ES8388 codec to a known state depending on the audio mode.
*/
void ES8388::reset() {
uint8_t regconfig;
log_v("Resetting ES8388...");
log_d(
"Current configuration: _bpsamp=%d, _samprate=%d, _nchannels=%d, _audio_mode=%d, _dac_output=%d, _adc_input=%d, _mic_gain=%d", _bpsamp, _samprate,
_nchannels, _audio_mode, _dac_output, _adc_input, _mic_gain
);
writeReg(ES8388_DACCONTROL3, ES8388_DACMUTE_MUTED | ES8388_DACLER_NORMAL | ES8388_DACSOFTRAMP_DISABLE | ES8388_DACRAMPRATE_4LRCK);
writeReg(
ES8388_CONTROL2,
ES8388_PDNVREFBUF_NORMAL | ES8388_VREFLO_NORMAL | ES8388_PDNIBIASGEN_NORMAL | ES8388_PDNANA_NORMAL | ES8388_LPVREFBUF_LP | ES8388_LPVCMMOD_NORMAL | (1 << 6)
); /* Default value of undocumented bit */
writeReg(
ES8388_CHIPPOWER, ES8388_DACVREF_PDN_PWRUP | ES8388_ADCVREF_PDN_PWRUP | ES8388_DACDLL_PDN_NORMAL | ES8388_ADCDLL_PDN_NORMAL | ES8388_DAC_STM_RST_NORMAL
| ES8388_ADC_STM_RST_NORMAL | ES8388_DAC_DIGPDN_NORMAL | ES8388_ADC_DIGPDN_NORMAL
);
/* Disable the internal DLL to improve 8K sample rate */
writeReg(0x35, 0xa0);
writeReg(0x37, 0xd0);
writeReg(0x39, 0xd0);
writeReg(ES8388_MASTERMODE, ES8388_BCLKDIV(ES_MCLK_DIV_AUTO) | ES8388_BCLK_INV_NORMAL | ES8388_MCLKDIV2_NODIV | ES8388_MSC_SLAVE);
writeReg(
ES8388_DACPOWER, ES8388_ROUT2_DISABLE | ES8388_LOUT2_DISABLE | ES8388_ROUT1_DISABLE | ES8388_LOUT1_DISABLE | ES8388_PDNDACR_PWRDN | ES8388_PDNDACL_PWRDN
);
writeReg(
ES8388_CONTROL1, ES8388_VMIDSEL_500K | ES8388_ENREF_DISABLE | ES8388_SEQEN_DISABLE | ES8388_SAMEFS_SAME | ES8388_DACMCLK_ADCMCLK | ES8388_LRCM_ISOLATED
| ES8388_SCPRESET_NORMAL
);
setBitsPerSample(_bpsamp);
setSampleRate(_samprate);
writeReg(ES8388_DACCONTROL16, ES8388_RMIXSEL_RIN1 | ES8388_LMIXSEL_LIN1);
writeReg(ES8388_DACCONTROL17, ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | ES8388_LI2LO_DISABLE | ES8388_LD2LO_ENABLE);
writeReg(ES8388_DACCONTROL20, ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | ES8388_RI2RO_DISABLE | ES8388_RD2RO_ENABLE);
writeReg(
ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | ES8388_LRCK_SEL_DAC | ES8388_SLRCK_SAME
);
writeReg(ES8388_DACCONTROL23, ES8388_VROI_1_5K);
writeReg(ES8388_DACCONTROL24, ES8388_LOUT1VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL25, ES8388_ROUT1VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL26, ES8388_LOUT2VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL27, ES8388_ROUT2VOL(ES8388_DAC_CHVOL_DB(0)));
setmute(ES_MODULE_DAC, ES8388_DEFAULT_MUTE);
setvolume(ES_MODULE_DAC, ES8388_DEFAULT_VOL_OUT, ES8388_DEFAULT_BALANCE);
if (_dac_output == ES8388_DAC_OUTPUT_LINE2) {
regconfig = ES_DAC_CHANNEL_LOUT1 | ES_DAC_CHANNEL_ROUT1;
} else if (_dac_output == ES8388_DAC_OUTPUT_LINE1) {
regconfig = ES_DAC_CHANNEL_LOUT2 | ES_DAC_CHANNEL_ROUT2;
} else {
regconfig = ES_DAC_CHANNEL_LOUT1 | ES_DAC_CHANNEL_ROUT1 | ES_DAC_CHANNEL_LOUT2 | ES_DAC_CHANNEL_ROUT2;
}
writeReg(ES8388_DACPOWER, regconfig);
writeReg(
ES8388_ADCPOWER, ES8388_INT1LP_LP | ES8388_FLASHLP_LP | ES8388_PDNADCBIASGEN_LP | ES8388_PDNMICB_PWRDN | ES8388_PDNADCR_PWRDN | ES8388_PDNADCL_PWRDN
| ES8388_PDNAINR_PWRDN | ES8388_PDNAINL_PWRDN
);
setMicGain(24); /* +24 dB */
if (_adc_input == ES8388_ADC_INPUT_LINE1) {
regconfig = ES_ADC_CHANNEL_LINPUT1_RINPUT1;
} else if (_adc_input == ES8388_ADC_INPUT_LINE2) {
regconfig = ES_ADC_CHANNEL_LINPUT2_RINPUT2;
} else {
regconfig = ES_ADC_CHANNEL_DIFFERENCE;
}
writeReg(ES8388_ADCCONTROL2, regconfig);
writeReg(
ES8388_ADCCONTROL3, (1 << 1) | /* Default value of undocumented bit */
ES8388_TRI_NORMAL | ES8388_MONOMIX_STEREO | ES8388_DS_LINPUT1_RINPUT1
);
setBitsPerSample(_bpsamp);
setSampleRate(_samprate);
setmute(ES_MODULE_ADC, ES8388_DEFAULT_MUTE);
setvolume(ES_MODULE_ADC, ES8388_DEFAULT_VOL_IN, ES8388_DEFAULT_BALANCE);
writeReg(
ES8388_ADCPOWER, ES8388_INT1LP_LP | ES8388_FLASHLP_NORMAL | ES8388_PDNADCBIASGEN_NORMAL | ES8388_PDNMICB_PWRDN | ES8388_PDNADCR_PWRUP | ES8388_PDNADCL_PWRUP
| ES8388_PDNAINR_NORMAL | ES8388_PDNAINL_NORMAL
);
/* Stop sequence to avoid noise at boot */
stop();
log_v("ES8388 reset.");
}
/*
Name: stop
Description:
Mute and stop the ES8388 codec data transmission.
*/
void ES8388::stop() {
log_v("Stopping ES8388 transmission...");
_running = false;
if (_audio_mode == ES_MODULE_LINE) {
writeReg(
ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | ES8388_LRCK_SEL_DAC | ES8388_SLRCK_SAME
);
writeReg(ES8388_DACCONTROL16, ES8388_RMIXSEL_RIN1 | ES8388_LMIXSEL_LIN1);
writeReg(ES8388_DACCONTROL17, ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | ES8388_LI2LO_DISABLE | ES8388_LD2LO_ENABLE);
writeReg(ES8388_DACCONTROL20, ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | ES8388_RI2RO_DISABLE | ES8388_RD2RO_ENABLE);
goto stop_msg;
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(
ES8388_DACPOWER, ES8388_ROUT2_DISABLE | ES8388_LOUT2_DISABLE | ES8388_ROUT1_DISABLE | ES8388_LOUT1_DISABLE | ES8388_PDNDACR_PWRUP | ES8388_PDNDACL_PWRUP
);
}
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(
ES8388_ADCPOWER, ES8388_INT1LP_LP | ES8388_FLASHLP_LP | ES8388_PDNADCBIASGEN_LP | ES8388_PDNMICB_PWRDN | ES8388_PDNADCR_PWRDN | ES8388_PDNADCL_PWRDN
| ES8388_PDNAINR_PWRDN | ES8388_PDNAINL_PWRDN
);
}
if (_audio_mode == ES_MODULE_ADC_DAC) {
writeReg(
ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_PWRDN | ES8388_ADC_DLL_PWD_PWRDN | ES8388_MCLK_DIS_DISABLE | ES8388_OFFSET_DIS_DISABLE | ES8388_LRCK_SEL_DAC | ES8388_SLRCK_SAME
);
}
stop_msg:
setmute(_audio_mode, true);
log_v("ES8388 transmission stopped.");
}
/*
Name: setvolume
Description:
Set the volume of the ES8388 codec.
Input Parameters:
module - Module to set the volume for.
volume - Volume level {0..1000}.
balance - Balance level {0..1000}.
*/
void ES8388::setvolume(es_module_e module, uint16_t volume, uint16_t balance) {
uint16_t leftlvl;
int16_t dbleftlvl;
uint16_t rightlvl;
int16_t dbrightlvl;
log_d("Volume = %u, Balance = %u", volume, balance);
if (volume > 1000) {
log_w("Warning: Volume greater than 1000, setting to 1000.");
volume = 1000;
}
if (balance > 1000) {
log_w("Warning: Balance greater than 1000, setting to 1000.");
balance = 1000;
}
_balance = balance;
/* Calculate the left channel volume level {0..1000} */
if (_balance <= 500) {
leftlvl = volume;
} else if (_balance == 1000) {
leftlvl = 0;
} else {
leftlvl = ((((1000 - _balance) * 100) / 500) * volume) / 100;
}
/* Calculate the right channel volume level {0..1000} */
if (_balance >= 500) {
rightlvl = volume;
} else if (_balance == 0) {
rightlvl = 0;
} else {
rightlvl = (((_balance * 100) / 500) * volume) / 100;
}
/* Convert from (0..1000) to (-96..0) */
dbleftlvl = (int16_t)(leftlvl ? (20 * log10f((float)rightlvl / 1000)) : -96);
dbrightlvl = (int16_t)(rightlvl ? (20 * log10f((float)rightlvl / 1000)) : -96);
log_v("Volume: dbleftlvl = %d, dbrightlvl = %d", dbleftlvl, dbrightlvl);
/* Convert and truncate to 1 byte */
dbleftlvl = ((-dbleftlvl) << 1) & 0xff;
dbrightlvl = ((-dbrightlvl) << 1) & 0xff;
/* Set the volume */
if (module == ES_MODULE_DAC || module == ES_MODULE_ADC_DAC) {
writeReg(ES8388_DACCONTROL4, ES8388_LDACVOL(dbleftlvl));
writeReg(ES8388_DACCONTROL5, ES8388_RDACVOL(dbrightlvl));
_volume_out = volume;
}
if (module == ES_MODULE_ADC || module == ES_MODULE_ADC_DAC) {
writeReg(ES8388_ADCCONTROL8, ES8388_LADCVOL(dbleftlvl));
writeReg(ES8388_ADCCONTROL9, ES8388_RADCVOL(dbrightlvl));
_volume_in = volume;
}
}
/*
Name: setmute
Description:
Mute or unmute the selected ES8388 codec module.
Input Parameters:
module - Module to mute or unmute.
enable - Mute or unmute.
*/
void ES8388::setmute(es_module_e module, bool enable) {
uint8_t reg = 0;
log_d("module=%d, mute=%d", module, (int)enable);
_mute = enable;
if (module == ES_MODULE_DAC || module == ES_MODULE_ADC_DAC) {
reg = readReg(ES8388_DACCONTROL3) & (~ES8388_DACMUTE_BITMASK);
writeReg(ES8388_DACCONTROL3, reg | ES8388_DACMUTE(enable));
}
if (module == ES_MODULE_ADC || module == ES_MODULE_ADC_DAC) {
reg = readReg(ES8388_ADCCONTROL7) & (~ES8388_ADCMUTE_BITMASK);
writeReg(ES8388_ADCCONTROL7, reg | ES8388_ADCMUTE(enable));
}
}
/****************************************************************************
* Public Methods
****************************************************************************/
ES8388::~ES8388() {
end();
}
/*
Name: begin
Description:
Initialize the ES8388 codec. Requires the I2S and I2C buses to be initialized
before calling this function.
Input Parameters:
i2s - I2S bus instance.
i2c - I2C bus instance. Defaults to Wire.
addr - I2C address of the ES8388 codec. Defaults to 0x10.
Return:
true - Success.
false - Failure.
*/
bool ES8388::begin(I2SClass &i2s, TwoWire &i2c, uint8_t addr) {
log_v("Initializing ES8388...");
_i2c = &i2c;
_i2s = &i2s;
_addr = addr;
_fmt = ES8388_DEFAULT_FMT;
_mode = ES8388_DEFAULT_MODE;
_samprate = ES8388_DEFAULT_SAMPRATE;
_nchannels = ES8388_DEFAULT_NCHANNELS;
_bpsamp = ES8388_DEFAULT_BPSAMP;
_audio_mode = ES8388_DEFAULT_AUDIO_MODE;
_dac_output = ES8388_DEFAULT_DAC_OUTPUT;
_adc_input = ES8388_DEFAULT_ADC_INPUT;
_mic_gain = ES8388_DEFAULT_MIC_GAIN;
_running = false;
_lclk_div = ES_LCLK_DIV_256;
_word_length = ES_WORD_LENGTH_16BITS;
_i2c->beginTransmission(_addr);
if (_i2c->endTransmission() != 0) {
log_e("Device not found at address 0x%02x. Check if the I2C and I2S buses are initialized.", _addr);
return false;
}
reset();
log_v("ES8388 initialized.");
return true;
}
/*
Name: end
Description:
Stop the ES8388 codec and reset it to a known state.
*/
void ES8388::end() {
log_v("Ending ES8388...");
stop();
setmute(ES_MODULE_ADC_DAC, true);
_audio_mode = ES_MODULE_ADC_DAC;
reset();
log_v("ES8388 ended.");
}
/*
Name: readReg
Description:
Read a register from the ES8388 codec.
Input Parameters:
reg - Register address.
Return:
Register value.
*/
uint8_t ES8388::readReg(uint8_t reg) {
int data;
_i2c->beginTransmission(_addr);
if (_i2c->write(reg) == 0) {
log_e("Error writing register address 0x%02x.", reg);
return 0;
}
if (_i2c->endTransmission(false) != 0) {
log_e("Error ending transmission.");
return 0;
}
if (!_i2c->requestFrom(_addr, (uint8_t)1)) {
log_e("Error requesting data.");
return 0;
}
if ((data = _i2c->read()) < 0) {
log_e("Error reading data.");
return 0;
}
return (uint8_t)data;
}
/*
Name: writeReg
Description:
Write a register to the ES8388 codec.
Input Parameters:
reg - Register address.
data - Data to write.
*/
void ES8388::writeReg(uint8_t reg, uint8_t data) {
_i2c->beginTransmission(_addr);
if (_i2c->write(reg) == 0) {
log_e("Error writing register address 0x%02x.", reg);
return;
}
if (_i2c->write(data) == 0) {
log_e("Error writing data 0x%02x.", data);
return;
}
if (_i2c->endTransmission(true) != 0) {
log_e("Error ending transmission.");
return;
}
}
/*
Name: setMicGain
Description:
Set the microphone gain.
Input Parameters:
gain - Gain level in dB {0..24}.
*/
void ES8388::setMicGain(uint8_t gain) {
static const es_mic_gain_e gain_map[] = {
ES_MIC_GAIN_0DB, ES_MIC_GAIN_3DB, ES_MIC_GAIN_6DB, ES_MIC_GAIN_9DB, ES_MIC_GAIN_12DB,
ES_MIC_GAIN_15DB, ES_MIC_GAIN_18DB, ES_MIC_GAIN_21DB, ES_MIC_GAIN_24DB,
};
log_d("gain=%d", gain);
_mic_gain = gain_map[min(gain, (uint8_t)24) / 3];
writeReg(ES8388_ADCCONTROL1, ES8388_MICAMPR(_mic_gain) | ES8388_MICAMPL(_mic_gain));
log_v("Mic gain set to %d", _mic_gain);
}
/*
Name: setBitsPerSample
Description:
Set the number of bits per sample. This also configures the I2S bus.
Input Parameters:
bpsamp - Bits per sample {16, 24, 32}.
*/
void ES8388::setBitsPerSample(uint8_t bpsamp) {
/* ES8388 also supports 18 and 20 bits per sample, but the I2S bus does not */
switch (bpsamp) {
case 16: _word_length = ES_WORD_LENGTH_16BITS; break;
case 24: _word_length = ES_WORD_LENGTH_24BITS; break;
case 32: _word_length = ES_WORD_LENGTH_32BITS; break;
default: log_e("Data length not supported."); return;
}
_bpsamp = bpsamp;
_i2s->configureTX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
_i2s->configureRX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(ES8388_ADCCONTROL4, ES8388_ADCFORMAT(ES_I2S_NORMAL) | ES8388_ADCWL(_word_length) | ES8388_ADCLRP_NORM_2ND | ES8388_DATSEL_LL);
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(ES8388_DACCONTROL1, ES8388_DACFORMAT(ES_I2S_NORMAL) | ES8388_DACWL(_word_length) | ES8388_DACLRP_NORM_2ND | ES8388_DACLRSWAP_NORMAL);
}
log_v("Datawidth set to %u", _bpsamp);
}
/*
Name: setSampleRate
Description:
Set the sample rate. This also configures the I2S bus.
The divider depends on the sample rate and the MCLK frequency.
This needs to be re-implemented to properly support all cases.
ES8388 should also support 88100Hz and 96000Hz sample rates in
double speed mode but setting it makes the audio sound distorted.
Input Parameters:
rate - Sample rate {8000, 11025, 12000, 16000, 22050, 24000, 32000,
44100, 48000}.
*/
void ES8388::setSampleRate(uint32_t rate) {
/*
According to the datasheet, this should only matter for the master mode
but it seems to affect the slave mode as well.
*/
switch (rate) {
case 8000: _lclk_div = ES_LCLK_DIV_1536; break;
case 11025:
case 12000: _lclk_div = ES_LCLK_DIV_1024; break;
case 16000: _lclk_div = ES_LCLK_DIV_768; break;
case 22050:
case 24000: _lclk_div = ES_LCLK_DIV_512; break;
case 32000: _lclk_div = ES_LCLK_DIV_384; break;
case 44100:
case 48000: _lclk_div = ES_LCLK_DIV_256; break;
default: log_e("Sample rate not supported."); return;
}
_samprate = rate;
_i2s->configureTX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
_i2s->configureRX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(ES8388_ADCCONTROL5, ES8388_ADCFSRATIO(_lclk_div));
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC) {
writeReg(ES8388_DACCONTROL2, ES8388_DACFSRATIO(_lclk_div));
}
log_v("Sample rate set to %d in single speed mode", _samprate);
}
/*
Name: playWAV
Description:
Wrapper for the I2SClass::playWAV() method. This method starts the ES8388
codec before playing the WAV file and stops it after the WAV file has been
played.
Input Parameters:
data - Pointer to the WAV file data.
len - Length of the WAV file data.
*/
void ES8388::playWAV(uint8_t *data, size_t len) {
_audio_mode = ES_MODULE_DAC;
reset();
log_v("Playing WAV file...");
start();
_i2s->playWAV(data, len);
stop();
log_v("WAV file played.");
}
/*
Name: recordWAV
Description:
Wrapper for the I2SClass::recordWAV() method. This method starts the ES8388
codec before recording the WAV file and stops it after the WAV file has been
recorded.
Input Parameters:
rec_seconds - Length of the WAV file to record in seconds.
out_size - Pointer to the variable that will hold the size of the WAV file.
Return:
Pointer to the WAV file data.
*/
uint8_t *ES8388::recordWAV(size_t rec_seconds, size_t *out_size) {
uint8_t *data;
size_t size;
_audio_mode = ES_MODULE_ADC;
reset();
log_v("Recording WAV file...");
start();
data = _i2s->recordWAV(rec_seconds, &size);
stop();
log_v("WAV file recorded.");
*out_size = size;
return data;
}
void ES8388::setOutputVolume(uint16_t volume, uint16_t balance) {
setvolume(ES_MODULE_DAC, volume, balance);
}
void ES8388::setInputVolume(uint16_t volume, uint16_t balance) {
setvolume(ES_MODULE_ADC, volume, balance);
}
void ES8388::setOutputMute(bool enable) {
setmute(ES_MODULE_DAC, enable);
}
void ES8388::setInputMute(bool enable) {
setmute(ES_MODULE_ADC, enable);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,85 @@
/*
ESP32-LyraT I2S ES8388 loopback example
This simple example demonstrates using the I2S library in combination
with the ES8388 codec on the ESP32-LyraT board to record and play back
audio data.
Don't forget to enable the PSRAM in the Tools menu!
Created for arduino-esp32 on 20 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#include "ESP_I2S.h"
#include "Wire.h"
#include "ES8388.h"
/* Pin definitions */
/* I2C */
const uint8_t I2C_SCL = 23;
const uint8_t I2C_SDA = 18;
const uint32_t I2C_FREQ = 400000;
/* I2S */
const uint8_t I2S_MCLK = 0; /* Master clock */
const uint8_t I2S_SCK = 5; /* Audio data bit clock */
const uint8_t I2S_WS = 25; /* Audio data left and right clock */
const uint8_t I2S_SDOUT = 26; /* ESP32 audio data output (to speakers) */
const uint8_t I2S_SDIN = 35; /* ESP32 audio data input (from microphone) */
/* PA */
const uint8_t PA_ENABLE = 21; /* Power amplifier enable */
void setup() {
I2SClass i2s;
ES8388 codec;
uint8_t *wav_buffer;
size_t wav_size;
// Initialize the serial port
Serial.begin(115200);
pinMode(PA_ENABLE, OUTPUT);
digitalWrite(PA_ENABLE, HIGH);
Serial.println("Initializing I2C bus...");
// Initialize the I2C bus
Wire.begin(I2C_SDA, I2C_SCL, I2C_FREQ);
Serial.println("Initializing I2S bus...");
// Set up the pins used for audio input
i2s.setPins(I2S_SCK, I2S_WS, I2S_SDOUT, I2S_SDIN, I2S_MCLK);
// Initialize the I2S bus in standard mode
if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
Serial.println("Initializing ES8388...");
if (!codec.begin(i2s)) {
Serial.println("Failed to initialize ES8388!");
return;
}
Serial.println("Recording 10 seconds of audio data...");
// Record 10 seconds of audio data
wav_buffer = codec.recordWAV(10, &wav_size);
Serial.println("Recording complete. Playing audio data in 3 seconds.");
delay(3000);
// Play the audio data
Serial.println("Playing audio data...");
codec.playWAV(wav_buffer, wav_size);
Serial.println("Application complete.");
}
void loop() {}
@@ -0,0 +1,3 @@
requires:
- CONFIG_SOC_I2S_SUPPORTED=y
- CONFIG_SOC_I2C_SUPPORTED=y