ES8311 support added for the ESP32-P4 EV board with mic.

This commit is contained in:
Troy
2024-10-02 09:15:46 -04:00
parent 63ff7205d6
commit 283a7284b4
2 changed files with 115 additions and 1 deletions

View File

@@ -2022,7 +2022,16 @@ class AudioReactive : public Usermod {
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
if (i2c_scl >= 0) sclPin = -1;
case 9:
DEBUGSR_PRINTLN(F("AR: ES8311 Source (Mic)"));
audioSource = new ES8311Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f);
//useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour
delay(100);
// WLEDMM align global pins
if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined)
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
if (i2c_scl >= 0) sclPin = -1;
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break;
@@ -2934,6 +2943,11 @@ class AudioReactive : public Usermod {
#else
oappend(SET_F("addOption(dd,'AC101 ☾',8);"));
#endif
#if SR_DMTYPE==9
oappend(SET_F("addOption(dd,'ES8311 ☾ (⎌)',9);"));
#else
oappend(SET_F("addOption(dd,'ES8311 ☾',9);"));
#endif
#ifdef SR_SQUELCH
oappend(SET_F("addInfo(ux+':config:squelch',1,'<i>&#9100; ")); oappendi(SR_SQUELCH); oappend("</i>');"); // 0 is field type, 1 is actual field
#endif

View File

@@ -640,6 +640,106 @@ class ES8388Source : public I2SSource {
};
/* ES8311 Sound Module
This is an I2S sound processing unit that requires initialization over
I2C before I2S data can be received.
*/
class ES8311Source : public I2SSource {
private:
// I2C initialization functions for es8311
void _es8311I2cBegin() {
Wire.setClock(100000);
}
void _es8311I2cWrite(uint8_t reg, uint8_t val) {
#ifndef ES8311_ADDR
#define ES8311_ADDR 0x18 // default address is... foggy
#endif
Wire.beginTransmission(ES8311_ADDR);
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: ES8311 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, ES8311_ADDR, reg, val);
}
}
void _es8311InitAdc() {
//
// Currently only tested with the ESP32-P4 EV board with the onboard mic.
// Datasheet with I2C commands: https://dl.xkwy2018.com/downloads/RK3588/01_Official%20Release/04_Product%20Line%20Branch_NVR/02_Key%20Device%20Specifications/ES8311%20DS.pdf
//
_es8311I2cBegin();
_es8311I2cWrite(0x00, 0b00011111); // RESET, default value
_es8311I2cWrite(0x45, 0b00000000); // GP, default value
_es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00110000 trying 0b00111010 (MCLK enable?)
_es8311I2cWrite(0x02, 0b00000000); // 22050hz calculated
_es8311I2cWrite(0x05, 0b00000000); // 22050hz calculated
_es8311I2cWrite(0x03, 0b00010000); // 22050hz calculated
_es8311I2cWrite(0x04, 0b00010000); // 22050hz calculated
_es8311I2cWrite(0x07, 0b00000000); // 22050hz calculated
_es8311I2cWrite(0x08, 0b11111111); // 22050hz calculated
_es8311I2cWrite(0x06, 0b11100011); // 22050hz calculated
_es8311I2cWrite(0x16, 0b00100000); // ADC was 0b00000011 trying 0b00100100 now
_es8311I2cWrite(0x0B, 0b00000000); // SYSTEM at default
_es8311I2cWrite(0x0C, 0b00100000); // SYSTEM was 0b00001111 trying 0b00100000
_es8311I2cWrite(0x10, 0b00010011); // SYSTEM was 0b00011111 trying 0b00010011
_es8311I2cWrite(0x11, 0b01111100); // SYSTEM was 0b01111111 trying 0b01111100
_es8311I2cWrite(0x00, 0b11000000); // *** RESET (again - seems important?)
_es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00111111 trying 0b00111010 (again??)
_es8311I2cWrite(0x14, 0b00010000); // *** SYSTEM was 0b00011010 trying 0b00010000 (or 0b01111010) (PGA gain)
_es8311I2cWrite(0x12, 0b00000000); // SYSTEM - DAC, likely don't care
_es8311I2cWrite(0x13, 0b00010000); // SYSTEM - output, likely don't cate
_es8311I2cWrite(0x09, 0b00001000); // SDP IN (likely don't care) was 0b00001100 (16-bit) - changed to 0b00001000 (I2S 32-bit)
_es8311I2cWrite(0x0A, 0b00001000); // *** SDP OUT, was 0b00001100 trying 0b00001000 (I2S 32-bit)
_es8311I2cWrite(0x0E, 0b00000010); // *** SYSTEM was 0b00000010 trying 0b00011010 (seems best so far!) (or 0b00000010)
_es8311I2cWrite(0x0F, 0b01000100); // SYSTEM was 0b01000100
_es8311I2cWrite(0x15, 0b00000000); // ADC soft ramp (disabled)
_es8311I2cWrite(0x1B, 0b00000101); // ADC soft-mute was 0b00000101
_es8311I2cWrite(0x1C, 0b01100101); // ADC EQ and offset freeze was 0b01100101 (bad at 0b00101100)
_es8311I2cWrite(0x17, 0b10111111); // ADC volume was 0b11111111 trying ADC volume 0b10111111 = 0db (maxgain) 0x16
_es8311I2cWrite(0x44, 0b00000000); // 0b10000000 - loopback test. on: 0x88; off: 0x00; mic--" speak
}
public:
ES8311Source(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 i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
DEBUGSR_PRINTLN("es8311Source:: initialize();");
// if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too
// ERRORSR_PRINTF("\nAR: invalid I2S es8311 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
// return;
// }
// BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here.
// Workaround: Set I2C pins here, which will also set them globally.
// Bug also exists in ES7243.
if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined"
ERRORSR_PRINTF("\nAR: invalid es8311 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return;
}
if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins
ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
return;
}
// First route mclk, then configure ADC over I2C, then configure I2S
_es8311InitAdc();
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
}
void deinitialize() {
I2SSource::deinitialize();
}
};
class WM8978Source : public I2SSource {
private:
// I2C initialization functions for WM8978