Skip to content

Commit 67e7829

Browse files
authored
Merge pull request #168 from troyhacks/ES8311-Support
ES8311 Support
2 parents 9359684 + 283a728 commit 67e7829

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

usermods/audioreactive/audio_reactive.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2056,7 +2056,16 @@ class AudioReactive : public Usermod {
20562056
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
20572057
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
20582058
if (i2c_scl >= 0) sclPin = -1;
2059-
2059+
case 9:
2060+
DEBUGSR_PRINTLN(F("AR: ES8311 Source (Mic)"));
2061+
audioSource = new ES8311Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f);
2062+
//useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour
2063+
delay(100);
2064+
// WLEDMM align global pins
2065+
if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined)
2066+
if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin;
2067+
if (i2c_sda >= 0) sdaPin = -1; // -1 = use global
2068+
if (i2c_scl >= 0) sclPin = -1;
20602069
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
20612070
break;
20622071

@@ -3002,6 +3011,11 @@ class AudioReactive : public Usermod {
30023011
#else
30033012
oappend(SET_F("addOption(dd,'AC101 ☾',8);"));
30043013
#endif
3014+
#if SR_DMTYPE==9
3015+
oappend(SET_F("addOption(dd,'ES8311 ☾ (⎌)',9);"));
3016+
#else
3017+
oappend(SET_F("addOption(dd,'ES8311 ☾',9);"));
3018+
#endif
30053019
#ifdef SR_SQUELCH
30063020
oappend(SET_F("addInfo(ux+':config:squelch',1,'<i>&#9100; ")); oappendi(SR_SQUELCH); oappend("</i>');"); // 0 is field type, 1 is actual field
30073021
#endif

usermods/audioreactive/audio_source.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,106 @@ class ES8388Source : public I2SSource {
651651

652652
};
653653

654+
/* ES8311 Sound Module
655+
This is an I2S sound processing unit that requires initialization over
656+
I2C before I2S data can be received.
657+
*/
658+
class ES8311Source : public I2SSource {
659+
private:
660+
// I2C initialization functions for es8311
661+
void _es8311I2cBegin() {
662+
Wire.setClock(100000);
663+
}
664+
665+
void _es8311I2cWrite(uint8_t reg, uint8_t val) {
666+
#ifndef ES8311_ADDR
667+
#define ES8311_ADDR 0x18 // default address is... foggy
668+
#endif
669+
Wire.beginTransmission(ES8311_ADDR);
670+
Wire.write((uint8_t)reg);
671+
Wire.write((uint8_t)val);
672+
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
673+
if (i2cErr != 0) {
674+
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);
675+
}
676+
}
677+
678+
void _es8311InitAdc() {
679+
//
680+
// Currently only tested with the ESP32-P4 EV board with the onboard mic.
681+
// 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
682+
//
683+
_es8311I2cBegin();
684+
_es8311I2cWrite(0x00, 0b00011111); // RESET, default value
685+
_es8311I2cWrite(0x45, 0b00000000); // GP, default value
686+
_es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00110000 trying 0b00111010 (MCLK enable?)
687+
688+
_es8311I2cWrite(0x02, 0b00000000); // 22050hz calculated
689+
_es8311I2cWrite(0x05, 0b00000000); // 22050hz calculated
690+
_es8311I2cWrite(0x03, 0b00010000); // 22050hz calculated
691+
_es8311I2cWrite(0x04, 0b00010000); // 22050hz calculated
692+
_es8311I2cWrite(0x07, 0b00000000); // 22050hz calculated
693+
_es8311I2cWrite(0x08, 0b11111111); // 22050hz calculated
694+
_es8311I2cWrite(0x06, 0b11100011); // 22050hz calculated
695+
696+
_es8311I2cWrite(0x16, 0b00100000); // ADC was 0b00000011 trying 0b00100100 now
697+
_es8311I2cWrite(0x0B, 0b00000000); // SYSTEM at default
698+
_es8311I2cWrite(0x0C, 0b00100000); // SYSTEM was 0b00001111 trying 0b00100000
699+
_es8311I2cWrite(0x10, 0b00010011); // SYSTEM was 0b00011111 trying 0b00010011
700+
_es8311I2cWrite(0x11, 0b01111100); // SYSTEM was 0b01111111 trying 0b01111100
701+
_es8311I2cWrite(0x00, 0b11000000); // *** RESET (again - seems important?)
702+
_es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00111111 trying 0b00111010 (again??)
703+
_es8311I2cWrite(0x14, 0b00010000); // *** SYSTEM was 0b00011010 trying 0b00010000 (or 0b01111010) (PGA gain)
704+
_es8311I2cWrite(0x12, 0b00000000); // SYSTEM - DAC, likely don't care
705+
_es8311I2cWrite(0x13, 0b00010000); // SYSTEM - output, likely don't cate
706+
_es8311I2cWrite(0x09, 0b00001000); // SDP IN (likely don't care) was 0b00001100 (16-bit) - changed to 0b00001000 (I2S 32-bit)
707+
_es8311I2cWrite(0x0A, 0b00001000); // *** SDP OUT, was 0b00001100 trying 0b00001000 (I2S 32-bit)
708+
_es8311I2cWrite(0x0E, 0b00000010); // *** SYSTEM was 0b00000010 trying 0b00011010 (seems best so far!) (or 0b00000010)
709+
_es8311I2cWrite(0x0F, 0b01000100); // SYSTEM was 0b01000100
710+
_es8311I2cWrite(0x15, 0b00000000); // ADC soft ramp (disabled)
711+
_es8311I2cWrite(0x1B, 0b00000101); // ADC soft-mute was 0b00000101
712+
_es8311I2cWrite(0x1C, 0b01100101); // ADC EQ and offset freeze was 0b01100101 (bad at 0b00101100)
713+
_es8311I2cWrite(0x17, 0b10111111); // ADC volume was 0b11111111 trying ADC volume 0b10111111 = 0db (maxgain) 0x16
714+
_es8311I2cWrite(0x44, 0b00000000); // 0b10000000 - loopback test. on: 0x88; off: 0x00; mic--" speak
715+
716+
}
717+
718+
public:
719+
ES8311Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) :
720+
I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) {
721+
_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
722+
};
723+
724+
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
725+
DEBUGSR_PRINTLN("es8311Source:: initialize();");
726+
727+
// if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too
728+
// ERRORSR_PRINTF("\nAR: invalid I2S es8311 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
729+
// return;
730+
// }
731+
// BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here.
732+
// Workaround: Set I2C pins here, which will also set them globally.
733+
// Bug also exists in ES7243.
734+
if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined"
735+
ERRORSR_PRINTF("\nAR: invalid es8311 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
736+
return;
737+
}
738+
if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins
739+
ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl);
740+
return;
741+
}
742+
743+
// First route mclk, then configure ADC over I2C, then configure I2S
744+
_es8311InitAdc();
745+
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
746+
}
747+
748+
void deinitialize() {
749+
I2SSource::deinitialize();
750+
}
751+
752+
};
753+
654754
class WM8978Source : public I2SSource {
655755
private:
656756
// I2C initialization functions for WM8978

0 commit comments

Comments
 (0)