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

Working proof of concept for ES8388 #1

Merged
merged 7 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions usermods/audioreactive/audio_reactive.h
Original file line number Diff line number Diff line change
Expand Up @@ -1484,9 +1484,9 @@ class AudioReactive : public Usermod {
#endif
case 6:
DEBUGSR_PRINTLN(F("AR: ES8388 Source"));
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE, sdaPin, sclPin);
audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE);
delay(100);
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
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)
Expand Down
131 changes: 88 additions & 43 deletions usermods/audioreactive/audio_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#else
#define SRate_t int
#endif
#include "ES8388.h"

//#include <driver/i2s_std.h>
//#include <driver/i2s_pdm.h>
Expand Down Expand Up @@ -490,75 +489,121 @@ 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:

void _es8388InitAdc() {
DEBUGSR_PRINTF("\nAR: _es8388InitAdc\n");

if (!es8388.init()) {
Serial.println("_es8388InitAdc init Fail\n");
return;
// 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."));
}
es8388.inputSelect(IN2); // IN2 Line-In
es8388.setInputGain(8);
es8388.outputSelect(OUT1); // OUT1 - Headphones
es8388.setOutputVolume(12);
es8388.mixerSourceSelect(MIXADC, MIXADC);
es8388.mixerSourceControl(DACOUT);
es8388.setALCmode(MUSIC);
es8388.analogBypass(true);
uint8_t *reg;
for (uint8_t i = 0; i < 53; i++) {
reg = es8388.readAllReg();
DEBUGSR_PRINTF("Reg-%02d = 0x%02x\r\n", i, reg[i]);
}

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);
}
}

public:
ES8388Source(int sampleRate, int blockSize, int sdaPin, int sclPin) :
I2SSource(sampleRate, blockSize) {
void _es8388InitAdc() {
// This is by no means 100% figured but it's working for line-in
// with a little too much noise for my liking...
// 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
_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(0x01,0x40); // Power up Analog and lbias ... These 5 (to here) need to be done in order
_es8388I2cWrite(0x03,0x00); // Power up ADC, Analog Input, and Mic Bias
_es8388I2cWrite(0x04,0x3C); // ** In guide, not in working example tho. **
_es8388I2cWrite(0x0a,0x50); // Use Lin2/Rin2 for ADC input
_es8388I2cWrite(0x09,0x00); // Select Analog Input PGA Gain for ADC to 0dB **
_es8388I2cWrite(0x0c,0x0c); // I2S format, 24-bit
_es8388I2cWrite(0x0d,0x02); // Set MCLK/LRCK ratio to 256
_es8388I2cWrite(0x10,0x00); // Set ADC digital volume attenuation to 0dB (left)
_es8388I2cWrite(0x11,0x00); // Set ADC digital volume attenuation to 0dB (right)
_es8388I2cWrite(0x17,0x18); // Set format for DAC (I2S, 24bit)
_es8388I2cWrite(0x18,0x02); // Set DAC MCLK/LRCK ratio to 256
_es8388I2cWrite(0x1a,0x00); // DAC Volume attenuation 0dB (left)
_es8388I2cWrite(0x1b,0x00); // DAC Volume attenuation 0dB (right)
_es8388I2cWrite(0x2e,0x00); // LOUT1 volume - 00 = -45dB
_es8388I2cWrite(0x2f,0x00); // ROUT1 volume - 00 = -45dB
_es8388I2cWrite(0x0C,0b00000001); // ADC digital format - I2S + Left Justified
_es8388I2cWrite(0x17,0b00000010); // DAC digital format - I2S + Left Justified
_es8388I2cWrite(0x02,0x00); // Power up DEM and STM
// end of guide init ^^^
_es8388I2cWrite(0x02,0b01000000); // Power. Guide says it's only 6 bits but that 1 means "turn on sometthing for line-out voltage"
_es8388I2cWrite(0x04,0x0c); // LOUT2 an ROUT2 powered
_es8388I2cWrite(0x30,0b00011110); // LOUT2VOL - 0 = -45dB, 0b00011110 = +0dB
_es8388I2cWrite(0x31,0b00011110); // ROUT2VOL - 0 = -45dB, 0b00011110 = +0dB
_es8388I2cWrite(0x26,0x09); // Mixer
_es8388I2cWrite(0x27,0x50); // Mixer
_es8388I2cWrite(0x2a,0x50); // Mixer
_es8388I2cWrite(0x03,0x00); // Power
}

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;
pin_ES8388_SDA = sdaPin;
pin_ES8388_SCL = sclPin;
DEBUGSR_PRINTF("\nAR: ES8388Source\n");
};

void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) {
DEBUGSR_PRINTF("\nAR: ES8388Source initialize called\n");
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 pins[2] = { { pin_ES8388_SDA, true }, { pin_ES8388_SCL, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
pinManager.deallocateMultiplePins(pins, 2, PinOwner::HW_I2C);
ERRORSR_PRINTF("\nAR: Failed to allocate ES8388 I2C pins: SDA=%d, SCL=%d\n", pin_ES8388_SDA, pin_ES8388_SCL);
PinManagerPinType es8388Pins[2] = { { sdaPin, true }, { sclPin, true } };
troyhacks marked this conversation as resolved.
Show resolved Hide resolved
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;
}

_es8388InitAdc();
// i2s
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
// WRITE_PERI_REG(PIN_CTRL, 0xFFF0);
// i2s_set_sample_rates(I2S_NUM_0, 22050);
pin_ES8388_SDA = sdaPin;
pin_ES8388_SCL = sclPin;

DEBUGSR_PRINTF("\nAR: ES8388Source calling I2SSource::initialize\n");
// 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
pinManager.deallocatePin(pin_ES8388_SDA, PinOwner::HW_I2C);
pinManager.deallocatePin(pin_ES8388_SCL, PinOwner::HW_I2C);
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;
ES8388 es8388 = ES8388(18, 23, 400000);
};



#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
#if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)
#warning this MCU does not support analog sound input
Expand Down