Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES8388 Final #2

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions usermods/audioreactive/audio_reactive.h
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,13 @@ class AudioReactive : public Usermod {
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin);
break;
#endif
case 6:
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break;

#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// ADC over I2S is only possible on "classic" ESP32
case 0:
Expand Down Expand Up @@ -2181,6 +2188,7 @@ class AudioReactive : public Usermod {
oappend(SET_F("addOption(dd,'.Legacy I2S PDM ☾',51);"));
#endif
#endif
oappend(SET_F("addOption(dd,'ES8388',6);"));

#ifdef SR_SQUELCH
oappend(SET_F("addInfo('AudioReactive:config:squelch',1,'<i>&#9100; ")); oappendi(SR_SQUELCH); oappend("</i>');"); // 0 is field type, 1 is actual field
Expand Down
100 changes: 100 additions & 0 deletions usermods/audioreactive/audio_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,106 @@ class ES7243 : public I2SSource {
int8_t pin_ES7243_SCL;
};

/* ES8388 Sound Modude
This is an I2S sound processing unit that requires ininitialization over
I2C before I2S data can be received.
*/
class ES8388Source : public I2SSource {
private:
// I2C initialization functions for ES8388
void _es8388I2cBegin() {
bool i2c_initialized = Wire.begin(pin_ES8388_SDA, pin_ES8388_SCL, 100000U);
if (i2c_initialized == false) {
ERRORSR_PRINTLN(F("AR: ES8388 failed to initialize I2C bus driver."));
}
}

void _es8388I2cWrite(uint8_t reg, uint8_t val) {
#ifndef ES8388_ADDR
Wire.beginTransmission(0x10);
#define ES8388_ADDR 0x10 // default address
#else
Wire.beginTransmission(ES8388_ADDR);
#endif
Wire.write((uint8_t)reg);
Wire.write((uint8_t)val);
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
if (i2cErr != 0) {
DEBUGSR_PRINTF("AR: ES8388 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, ES8388_ADDR, reg, val);
}
}

void _es8388InitAdc() {
// https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf Section 10.1
// https://docs.google.com/spreadsheets/d/1CN3MvhkcPVESuxKyx1xRYqfUit5hOdsG45St9BCUm-g/edit#gid=0 generally
// Sets ADC to around what AudioReactive expects, and loops line-in to line-out/headphone for monitoring.
_es8388I2cBegin();
_es8388I2cWrite(0x08,0x00); // I2S to slave
_es8388I2cWrite(0x02,0xf3); // Power down DEM and STM
_es8388I2cWrite(0x2b,0x80); // Set same LRCK
_es8388I2cWrite(0x00,0x05); // Set chip to Play & Record Mode
_es8388I2cWrite(0x0d,0x02); // Set MCLK/LRCK ratio to 256
_es8388I2cWrite(0x01,0x40); // Power up analog and lbias
_es8388I2cWrite(0x03,0x00); // Power up ADC, Analog Input, and Mic Bias
_es8388I2cWrite(0x0a,0x50); // Use Lin2/Rin2 for ADC input ("line-in")
_es8388I2cWrite(0x09,0x00); // Select Analog Input PGA Gain for ADC to 0dB (L+R)
_es8388I2cWrite(0x10,0b01000000); // Set ADC digital volume attenuation to -32dB (left)
_es8388I2cWrite(0x11,0b01000000); // Set ADC digital volume attenuation to -32dB (right)
_es8388I2cWrite(0x04,0x0c); // Turn on LOUT2 and ROUT2 power
_es8388I2cWrite(0x02,0b01000000); // Power up DEM and STM and undocumented bit for "turn on line-out amp"
_es8388I2cWrite(0x26,0x09); // Mixer - route LIN2/RIN2 to output
_es8388I2cWrite(0x27,0b01010000); // Mixer - route LIN to left mixer, 0dB gain
_es8388I2cWrite(0x2a,0b01010000); // Mixer - route RIN to right mixer, 0dB gain
_es8388I2cWrite(0x30,0b00011110); // LOUT2VOL - 0 = -45dB, 0b00011110 = +0dB
_es8388I2cWrite(0x31,0b00011110); // ROUT2VOL - 0 = -45dB, 0b00011110 = +0dB
}

public:
ES8388Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) :
I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) {
_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
};

void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {

// check that pins are valid
if ((sdaPin < 0) || (sclPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}

if ((i2sckPin < 0) || (mclkPin < 0)) {
ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
return;
}

// Reserve SDA and SCL pins of the I2C interface
PinManagerPinType es8388Pins[2] = { { sdaPin, true }, { sclPin, true } };
if (!pinManager.allocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C)) {
pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C);
ERRORSR_PRINTF("\nAR: Failed to allocate ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
return;
}

pin_ES8388_SDA = sdaPin;
pin_ES8388_SCL = sclPin;

// First route mclk, then configure ADC over I2C, then configure I2S
_es8388InitAdc();
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
}

void deinitialize() {
// Release SDA and SCL pins of the I2C interface
PinManagerPinType es8388Pins[2] = { { pin_ES8388_SDA, true }, { pin_ES8388_SCL, true } };
pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C);
I2SSource::deinitialize();
}

private:
int8_t pin_ES8388_SDA;
int8_t pin_ES8388_SCL;
};

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
#if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)
Expand Down