From 0a119eac4f1fbd1b94c1a11333019864d93863df Mon Sep 17 00:00:00 2001 From: pelgraine <140762863+pelgraine@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:10:28 +1000 Subject: [PATCH] initial audio playback working success - fixed pin 41 guard dac issue for pro variant by guarding with has es8311 audio --- examples/companion_radio/main.cpp | 84 +++++- examples/companion_radio/ui-new/Alarmscreen.h | 4 + .../ui-new/Audiobookplayerscreen.h | 4 + examples/companion_radio/ui-new/ES8311.h | 272 ++++++++++++++++++ .../ui-new/Voicemessagescreen.h | 4 + variants/lilygo_tdeck_max/platformio.ini | 6 + variants/lilygo_tdeck_max/variant.h | 22 +- 7 files changed, 376 insertions(+), 20 deletions(-) create mode 100644 examples/companion_radio/ui-new/ES8311.h diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 6b376b0d..119e75b5 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -90,6 +90,9 @@ #ifdef MECK_AUDIO_VARIANT #include "VoiceMessageScreen.h" #include "BundledSounds.h" + #ifdef HAS_ES8311_AUDIO + #include "ES8311.h" // MAX: native ES8311 codec init (Arduino Wire) + #endif #endif #if defined(MECK_AUDIO_VARIANT) || defined(HAS_4G_MODEM) #include "NotifSounds.h" @@ -1850,6 +1853,22 @@ void setup() { board.begin(); MESH_DEBUG_PRINTLN("setup() - board.begin() done"); + // Initialize touch input (CST328) HERE, immediately after board.begin(), + // while the I2C bus is freshly initialised and quiet -- mirroring LilyGo's + // working example, which calls touch.begin() first thing. Running it later + // (after display/radio/filesystem init) left the bus in a state where the + // CST328 firmware-info read failed. + #if defined(LilyGo_TDeck_Pro) && defined(HAS_TOUCHSCREEN) + #if defined(LilyGo_TDeck_Pro_Max) + board.touchReset(); // fresh XL9555 reset immediately before driver init + #endif + if (touchInput.begin(CST328_PIN_INT)) { + MESH_DEBUG_PRINTLN("setup() - Touch input initialized"); + } else { + MESH_DEBUG_PRINTLN("setup() - Touch input FAILED"); + } + #endif + #ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; MESH_DEBUG_PRINTLN("setup() - about to call display.begin()"); @@ -2283,14 +2302,8 @@ void setup() { initKeyboard(); #endif - // Initialize touch input (CST328 on T-Deck Pro) - #if defined(LilyGo_TDeck_Pro) && defined(HAS_TOUCHSCREEN) - if (touchInput.begin(CST328_PIN_INT)) { - MESH_DEBUG_PRINTLN("setup() - Touch input initialized"); - } else { - MESH_DEBUG_PRINTLN("setup() - Touch input FAILED"); - } - #endif + // Touch input (CST328) is initialised earlier, right after board.begin(), + // on a freshly-initialised quiet I2C bus (see setup() near board.begin()). // Initialize GT911 touch (T5S3 E-Paper Pro) // Wire is already initialized by T5S3Board::begin(). The 4-arg begin() re-calls @@ -2824,7 +2837,9 @@ void loop() { audio->setVolume(0); audio->stopSong(); delay(50); - // digitalWrite(41, LOW); +#ifndef HAS_ES8311_AUDIO + digitalWrite(41, LOW); +#endif notifTonePlaying = false; notifFadingOut = false; notifMuted = false; @@ -2868,8 +2883,36 @@ void loop() { // Stop any stale playback before touching DAC audio->stopSong(); - // Configure I2S pins first (before DAC power) - bool ok = audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, 0); + // MAX: route audio to the ES8311 codec and enable the speaker amp. + // NOTE: the codec REGISTER init is deferred until AFTER the I2S clocks + // are actually running (after connecttoFS + the silence-fill loop). The + // ES8311 appears to need live BCLK/LRCK to lock its clock tree; init'd + // on a clockless bus it configures correctly (readback confirms) but + // produces no output. Routing/amp are safe to set here. + #ifdef HAS_ES8311_AUDIO + board.selectAudioES8311(); // XL9555 AUDIO_SEL low -> ES8311 + board.amplifierEnable(); // XL9555 AMPLIFIER high -> NS4150B on + // DIAG: read back the two routing pins to confirm they took effect + // (AUDIO_SEL should be LOW=0 for ES8311, AMPLIFIER should be HIGH=1). + Serial.printf("NotifTone: routing AUDIO_SEL=%d (want 0) AMP=%d (want 1)\n", + board.xl9555_digitalRead(XL_PIN_AUDIO_SEL) ? 1 : 0, + board.xl9555_digitalRead(XL_PIN_AMPLIFIER) ? 1 : 0); + #endif + + // Configure I2S pins. Mirroring Ripple, the ES8311 is driven WITH MCLK + // (use_mclk=true), so MCLK must be generated on BOARD_I2S_MCLK. Use the + // 5-arg setPinout: the 4th arg is DIN (data-in, unused -> no change), the + // 5th is MCK. The earlier 4-arg call mistakenly passed MCLK as the 4th + // (DIN) arg, so MCLK was never generated -- this passes it as MCK. + #ifdef HAS_ES8311_AUDIO + bool ok = audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, + I2S_PIN_NO_CHANGE, BOARD_I2S_MCLK); + Serial.printf("NotifTone: setPinout(BCLK=%d LRC=%d DOUT=%d MCK=%d) -> %s\n", + BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, BOARD_I2S_MCLK, + ok ? "ok" : "FAILED"); + #else + bool ok = audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT, 0); + #endif if (!ok) ok = audio->setPinout(BOARD_I2S_BCLK, BOARD_I2S_LRC, BOARD_I2S_DOUT); // Start playback at volume 0 (silence into DAC during power-on) @@ -2877,9 +2920,11 @@ void loop() { audio->connecttoFS(SD, file); // Enable DAC amplifier and let it stabilise with silence flowing - // pinMode(41, OUTPUT); - // digitalWrite(41, HIGH); - // delay(80); +#ifndef HAS_ES8311_AUDIO + pinMode(41, OUTPUT); + digitalWrite(41, HIGH); + delay(80); +#endif // Fill audio buffer with silence at volume 0 (prevents power-on pop) for (int i = 0; i < 30; i++) { @@ -2887,6 +2932,17 @@ void loop() { delay(2); } + // I2S clocks are now running (connecttoFS started the channel and the + // loop above has pushed samples). NOW bring up the ES8311 over I2C, so + // it can lock to the live BCLK/LRCK. Done once per boot. + #ifdef HAS_ES8311_AUDIO + static bool es8311_ready = false; + if (!es8311_ready) { + es8311_ready = es8311_init_44100_16bit(); + Serial.printf("NotifTone: ES8311 init (post-I2S) %s\n", es8311_ready ? "OK" : "FAILED"); + } + #endif + // Ramp volume up to max audio->setVolume(21); notifTonePlaying = true; diff --git a/examples/companion_radio/ui-new/Alarmscreen.h b/examples/companion_radio/ui-new/Alarmscreen.h index 03e4dc9e..68cc6998 100644 --- a/examples/companion_radio/ui-new/Alarmscreen.h +++ b/examples/companion_radio/ui-new/Alarmscreen.h @@ -264,13 +264,17 @@ private: // ---- DAC power (same pattern as AudiobookPlayerScreen) ---- void enableDAC() { +#ifndef HAS_ES8311_AUDIO pinMode(41, OUTPUT); digitalWrite(41, HIGH); delay(50); +#endif } void disableDAC() { +#ifndef HAS_ES8311_AUDIO digitalWrite(41, LOW); +#endif } // ---- Audio control for alarm ringing ---- diff --git a/examples/companion_radio/ui-new/Audiobookplayerscreen.h b/examples/companion_radio/ui-new/Audiobookplayerscreen.h index 7fe2d05b..e355c8ae 100644 --- a/examples/companion_radio/ui-new/Audiobookplayerscreen.h +++ b/examples/companion_radio/ui-new/Audiobookplayerscreen.h @@ -219,17 +219,21 @@ private: // On the audio variant, this pin supplies power to the DAC circuit. // TDeckBoard::begin() sets it LOW ("disable modem") which starves the DAC. void enableDAC() { +#ifndef HAS_ES8311_AUDIO pinMode(41, OUTPUT); digitalWrite(41, HIGH); if (!_dacPowered) { delay(50); } _dacPowered = true; +#endif } void disableDAC() { +#ifndef HAS_ES8311_AUDIO digitalWrite(41, LOW); _dacPowered = false; +#endif } // Restore an M4B file that was temporarily renamed to .m4a for playback. diff --git a/examples/companion_radio/ui-new/ES8311.h b/examples/companion_radio/ui-new/ES8311.h new file mode 100644 index 00000000..3c580221 --- /dev/null +++ b/examples/companion_radio/ui-new/ES8311.h @@ -0,0 +1,272 @@ +#pragma once + +// ============================================================================= +// ES8311.h -- Minimal self-contained ES8311 codec init for T-Deck Pro MAX +// +// The MAX uses an ES8311 I2C-configured audio codec (the Pro V1.1 used a +// PCM5102A "dumb" DAC that needed no config). The ES8311 will not produce +// sound until its registers are configured over I2C. This driver does exactly +// that, over Arduino Wire, with no esp_codec_dev / Cpp_Bus_Driver framework. +// +// The register sequence and clock-coefficient table are taken from, and +// cross-verified between, Espressif's esp_codec_dev es8311.c and LilyGo's P4 +// Cpp_Bus_Driver Es8311 -- both agree on every clock register, so the sequence +// here is not reverse-engineered. +// +// Configuration (fixed for Stage 1): +// - ES8311 in SLAVE mode (ESP32 I2S is master: drives MCLK/BCLK/LRCK) +// - use_mclk = TRUE: a real MCLK is driven on BOARD_I2S_MCLK (GPIO38) by the +// I2S peripheral (APLL on, auto-derived 256 * fs). This mirrors the working +// Ripple firmware, which drives the ES8311 with MCLK on this exact platform. +// - 44100 Hz, 16-bit, DAC (playback) only; MCLK = 256 * sample_rate +// - Register sequence transcribed from the proven esp_codec_dev es8311.c +// (es8311_open + es8311_set_bits_per_sample + es8311_config_sample + +// es8311_start) for the use_mclk == true path +// +// Routing/amplifier (XL9555: AUDIO_SEL low, AMPLIFIER high) is handled by the +// board class (board.selectAudioES8311(); board.amplifierEnable()), NOT here. +// +// I2C: the ES8311 is at 0x18 on the shared Wire bus (SDA13/SCL14), already +// initialised by board.begin(). This driver only uses Wire, never re-inits it. +// +// Guard: HAS_ES8311_AUDIO +// ============================================================================= + +#ifdef HAS_ES8311_AUDIO + +#ifndef MECK_ES8311_H +#define MECK_ES8311_H + +#include +#include +#include "variant.h" + +// ES8311 register addresses (subset used here) +#define ES8311_REG00_RESET 0x00 +#define ES8311_REG01_CLK_MANAGER 0x01 +#define ES8311_REG02_CLK_MANAGER 0x02 +#define ES8311_REG03_CLK_MANAGER 0x03 +#define ES8311_REG04_CLK_MANAGER 0x04 +#define ES8311_REG05_CLK_MANAGER 0x05 +#define ES8311_REG06_CLK_MANAGER 0x06 +#define ES8311_REG07_CLK_MANAGER 0x07 +#define ES8311_REG08_CLK_MANAGER 0x08 +#define ES8311_REG09_SDPIN 0x09 +#define ES8311_REG0A_SDPOUT 0x0A +#define ES8311_REG0B_SYSTEM 0x0B +#define ES8311_REG0C_SYSTEM 0x0C +#define ES8311_REG0D_SYSTEM 0x0D +#define ES8311_REG0E_SYSTEM 0x0E +#define ES8311_REG10_SYSTEM 0x10 +#define ES8311_REG11_SYSTEM 0x11 +#define ES8311_REG12_SYSTEM 0x12 +#define ES8311_REG13_SYSTEM 0x13 +#define ES8311_REG14_SYSTEM 0x14 +#define ES8311_REG15_ADC 0x15 +#define ES8311_REG16_ADC 0x16 +#define ES8311_REG17_ADC 0x17 +#define ES8311_REG1B_ADC 0x1B +#define ES8311_REG1C_ADC 0x1C +#define ES8311_REG31_DAC 0x31 +#define ES8311_REG32_DAC 0x32 +#define ES8311_REG37_DAC 0x37 +#define ES8311_REG44_GPIO 0x44 +#define ES8311_REG45_GP 0x45 +#define ES8311_REGFD_CHIPID1 0xFD + +#ifndef I2C_ADDR_ES8311 +#define I2C_ADDR_ES8311 0x18 +#endif + +// --- low-level I2C register access over Wire --- + +static inline bool es8311_write(uint8_t reg, uint8_t val) { + Wire.beginTransmission((uint8_t)I2C_ADDR_ES8311); + Wire.write(reg); + Wire.write(val); + return Wire.endTransmission() == 0; +} + +static inline uint8_t es8311_read(uint8_t reg) { + Wire.beginTransmission((uint8_t)I2C_ADDR_ES8311); + Wire.write(reg); + if (Wire.endTransmission(false) != 0) return 0; + if (Wire.requestFrom((uint8_t)I2C_ADDR_ES8311, (uint8_t)1) != 1) return 0; + return Wire.read(); +} + +// Initialise the ES8311 for 44100 Hz, 16-bit, slave mode, MCLK = 256 * fs. +// Returns true if the chip ID read back as 0x83 (ES8311 reports ID 0x8311 +// across REGFD/REGFE; REGFD high byte is 0x83). +static inline bool es8311_init_44100_16bit() { + // Chip presence / ID check (REGFD should read 0x83 on ES8311) + uint8_t id = es8311_read(ES8311_REGFD_CHIPID1); + Serial.printf("[ES8311] chip ID REGFD = 0x%02X (expect 0x83)\n", id); + + // ---- open(): base register setup (from esp_codec_dev es8311_open) ---- + // GPIO REG44 written twice: ES8311 first I2C write can be unreliable. + es8311_write(ES8311_REG44_GPIO, 0x08); + es8311_write(ES8311_REG44_GPIO, 0x08); + + es8311_write(ES8311_REG01_CLK_MANAGER, 0x30); + es8311_write(ES8311_REG02_CLK_MANAGER, 0x00); + es8311_write(ES8311_REG03_CLK_MANAGER, 0x10); + es8311_write(ES8311_REG16_ADC, 0x24); + es8311_write(ES8311_REG04_CLK_MANAGER, 0x10); + es8311_write(ES8311_REG05_CLK_MANAGER, 0x00); + es8311_write(ES8311_REG0B_SYSTEM, 0x00); + es8311_write(ES8311_REG0C_SYSTEM, 0x00); + es8311_write(ES8311_REG10_SYSTEM, 0x1F); + es8311_write(ES8311_REG11_SYSTEM, 0x7F); + es8311_write(ES8311_REG00_RESET, 0x80); // CSM power up + + // Slave mode: REG00 bit6 = 0. (read-modify-write) + { + uint8_t regv = es8311_read(ES8311_REG00_RESET); + regv &= 0xBF; // slave + es8311_write(ES8311_REG00_RESET, regv); + } + + // Clock source for internal MCLK (REG01), transcribed from the proven + // esp_codec_dev es8311.c es8311_open() for use_mclk == true: + // regv = 0x3F; use_mclk true -> regv &= 0x7F; invert_mclk false -> regv &= ~0x40 + // => REG01 = 0x3F + // The codec uses the externally supplied MCLK (driven on GPIO38 via APLL), + // mirroring the working Ripple firmware on this platform. + { + uint8_t regv = 0x3F; + regv &= 0x7F; // use_mclk = true + regv &= ~0x40; // mclk not inverted + es8311_write(ES8311_REG01_CLK_MANAGER, regv); + } + + // SCLK not inverted (REG06) + { + uint8_t regv = es8311_read(ES8311_REG06_CLK_MANAGER); + regv &= ~0x20; + es8311_write(ES8311_REG06_CLK_MANAGER, regv); + } + + es8311_write(ES8311_REG13_SYSTEM, 0x10); + es8311_write(ES8311_REG1B_ADC, 0x0A); + es8311_write(ES8311_REG1C_ADC, 0x6A); + // no_dac_ref == false: set internal reference signal (ADCL + DACR) -> REG44 = 0x58. + // (es8311.c writes 0x58 here for DAC playback; the earlier 0x08 writes were the + // I2C-noise-immunity double-write.) + es8311_write(ES8311_REG44_GPIO, 0x58); + + // ---- config_sample(): clock dividers, transcribed from es8311_config_sample ---- + // For use_mclk == true the driver looks up the coeff row by + // (sample_rate * mclk_div, sample_rate) with mclk_div = 256 default, i.e. the + // {11289600, 44100} row: pre_div=1, pre_multi=1, adc_div=1, dac_div=1, + // fs_mode=0, lrck_h=0x00, lrck_l=0xff, bclk_div=0x04, adc_osr=0x10, dac_osr=0x10. + // pre_multi == 1 -> datmp = 0 (the use_mclk==false datmp=3 override does NOT + // apply here). So REG02 = (pre_div-1)<<5 | 0<<3 = 0x00. + { + const uint8_t pre_div = 1, pre_multi_enc = 0; // datmp=0 (pre_multi=1, use_mclk=true) + const uint8_t adc_div = 1, dac_div = 1, fs_mode = 0; + const uint8_t lrck_h = 0x00, lrck_l = 0xFF, bclk_div = 0x04; + const uint8_t adc_osr = 0x10, dac_osr = 0x10; + + uint8_t regv = es8311_read(ES8311_REG02_CLK_MANAGER); + regv &= 0x07; + regv |= (pre_div - 1) << 5; + regv |= pre_multi_enc << 3; + es8311_write(ES8311_REG02_CLK_MANAGER, regv); + + regv = (fs_mode << 6) | adc_osr; + es8311_write(ES8311_REG03_CLK_MANAGER, regv); + + es8311_write(ES8311_REG04_CLK_MANAGER, dac_osr); + + regv = ((adc_div - 1) << 4) | (dac_div - 1); + es8311_write(ES8311_REG05_CLK_MANAGER, regv); + + regv = es8311_read(ES8311_REG06_CLK_MANAGER); + regv &= 0xE0; + if (bclk_div < 19) regv |= (bclk_div - 1); + else regv |= bclk_div; + es8311_write(ES8311_REG06_CLK_MANAGER, regv); + + regv = es8311_read(ES8311_REG07_CLK_MANAGER); + regv &= 0xC0; + regv |= lrck_h; + es8311_write(ES8311_REG07_CLK_MANAGER, regv); + + es8311_write(ES8311_REG08_CLK_MANAGER, lrck_l); + } + + // ---- format + bits per sample: 16-bit, I2S (REG09 DAC SDP) ---- + // 16-bit -> SDP word length field = 0x0C in bits [4:2]; I2S format = 0x00. + { + uint8_t dac_iface = es8311_read(ES8311_REG09_SDPIN); + dac_iface &= 0xE3; // clear word-length field bits [4:2] only + dac_iface |= (0x03 << 2); // 0x0C = 16-bit (bits [4:2] = 011) + es8311_write(ES8311_REG09_SDPIN, dac_iface); + } + + // ---- start(): power up DAC path (from es8311_start, DAC mode) ---- + { + uint8_t regv = 0x80; // CSM on + regv &= 0xBF; // slave + es8311_write(ES8311_REG00_RESET, regv); + + // REG01 clock source (from es8311_start): regv=0x3F; use_mclk true -> &=0x7F; + // invert_mclk false -> &=~0x40 => 0x3F. Re-applied here exactly as the proven + // start sequence does, so it stays consistent with the open() write. + { + uint8_t r01 = 0x3F; + r01 &= 0x7F; // use_mclk = true + r01 &= ~0x40; // not inverted + es8311_write(ES8311_REG01_CLK_MANAGER, r01); + } + + // DAC interface power on (REG09 bit6 = 0) + uint8_t dac_iface = es8311_read(ES8311_REG09_SDPIN); + dac_iface &= ~(1 << 6); + es8311_write(ES8311_REG09_SDPIN, dac_iface); + + es8311_write(ES8311_REG17_ADC, 0xBF); + es8311_write(ES8311_REG0E_SYSTEM, 0x02); + es8311_write(ES8311_REG12_SYSTEM, 0x00); // enable DAC + es8311_write(ES8311_REG14_SYSTEM, 0x1A); + es8311_write(ES8311_REG0D_SYSTEM, 0x01); + es8311_write(ES8311_REG15_ADC, 0x40); + es8311_write(ES8311_REG37_DAC, 0x08); + es8311_write(ES8311_REG45_GP, 0x00); + } + + // Unmute DAC and set a sane default volume. + es8311_write(ES8311_REG31_DAC, 0x00); // unmute + es8311_write(ES8311_REG32_DAC, 0xBF); // ~0 dB (191 = 0 dB) + + // DIAG: read back key registers to confirm the power-up/format writes landed. + // REG00 (CSM/reset), REG01 (clock src), REG02 (clk div), REG09 (SDP/DAC iface), + // REG0D (power up/down), REG12 (DAC enable), REG31 (DAC mute), REG32 (DAC vol). + Serial.printf("[ES8311] readback R00=%02X R01=%02X R02=%02X R09=%02X R0D=%02X R12=%02X R31=%02X R32=%02X\n", + es8311_read(ES8311_REG00_RESET), + es8311_read(ES8311_REG01_CLK_MANAGER), + es8311_read(ES8311_REG02_CLK_MANAGER), + es8311_read(ES8311_REG09_SDPIN), + es8311_read(ES8311_REG0D_SYSTEM), + es8311_read(ES8311_REG12_SYSTEM), + es8311_read(ES8311_REG31_DAC), + es8311_read(ES8311_REG32_DAC)); + + return id == 0x83; +} + +// DAC volume, 0..255 (0 = mute-ish, 191 = 0 dB, 255 = +32 dB). +static inline void es8311_set_dac_volume(uint8_t vol) { + es8311_write(ES8311_REG32_DAC, vol); +} + +// Hard mute / unmute the DAC. +static inline void es8311_set_mute(bool mute) { + uint8_t regv = es8311_read(ES8311_REG31_DAC); + regv &= 0x9F; + es8311_write(ES8311_REG31_DAC, mute ? (regv | 0x60) : regv); +} + +#endif // MECK_ES8311_H +#endif // HAS_ES8311_AUDIO \ No newline at end of file diff --git a/examples/companion_radio/ui-new/Voicemessagescreen.h b/examples/companion_radio/ui-new/Voicemessagescreen.h index 41a96ad2..ed68e848 100644 --- a/examples/companion_radio/ui-new/Voicemessagescreen.h +++ b/examples/companion_radio/ui-new/Voicemessagescreen.h @@ -218,15 +218,19 @@ private: // DAC power control (same as AudiobookPlayerScreen) void enableDAC() { +#ifndef HAS_ES8311_AUDIO pinMode(41, OUTPUT); digitalWrite(41, HIGH); if (!_dacPowered) delay(50); _dacPowered = true; +#endif } void disableDAC() { +#ifndef HAS_ES8311_AUDIO digitalWrite(41, LOW); _dacPowered = false; +#endif } // --------------------------------------------------------------------------- diff --git a/variants/lilygo_tdeck_max/platformio.ini b/variants/lilygo_tdeck_max/platformio.ini index 1c5049e4..fea698d7 100644 --- a/variants/lilygo_tdeck_max/platformio.ini +++ b/variants/lilygo_tdeck_max/platformio.ini @@ -133,6 +133,10 @@ build_flags = -D CST328_PIN_RST=-1 -D ARDUINO_LOOP_STACK_SIZE=32768 -D HAS_MECK_FONTS + ; Audio: ES8311 I2C codec (MAX). Enables the audio variant code paths and + ; the native ES8311 init. 4G modem stays disabled until audio is solid. + -D MECK_AUDIO_VARIANT=1 + -D HAS_ES8311_AUDIO=1 build_src_filter = ${esp32_base.build_src_filter} ; Include MAX variant (target.cpp + TDeckProMaxBoard.cpp) +<../variants/lilygo_tdeck_max> @@ -143,6 +147,8 @@ lib_deps = zinggjm/GxEPD2@^1.5.9 adafruit/Adafruit GFX Library@^1.11.0 bitbank2/PNGdec@^1.0.1 + lewisxhe/SensorLib@^0.2.0 + https://github.com/sh123/esp32_codec2_arduino.git WebServer DNSServer Update diff --git a/variants/lilygo_tdeck_max/variant.h b/variants/lilygo_tdeck_max/variant.h index 9f952af5..ff0dc89b 100644 --- a/variants/lilygo_tdeck_max/variant.h +++ b/variants/lilygo_tdeck_max/variant.h @@ -195,26 +195,36 @@ // MCLK = IO38 (master clock — ES8311 needs this, PCM5102A didn't) // SCLK = IO39 (bit clock, aka BCLK) // LRCK = IO18 (word select, aka LRC/WS) -// DSDIN = IO17 (DAC serial data in — ESP32 sends audio TO codec) -// ASDOUT= IO40 (ADC serial data out — codec sends mic audio TO ESP32) +// DSDIN = IO40 (DAC serial data in — ESP32 sends audio TO codec) +// ASDOUT= IO17 (ADC serial data out — codec sends mic audio TO ESP32) // ----------------------------------------------------------------------------- #define HAS_ES8311_AUDIO 1 #define BOARD_ES8311_MCLK 38 #define BOARD_ES8311_SCLK 39 #define BOARD_ES8311_LRCK 18 -#define BOARD_ES8311_DSDIN 17 // ESP32 → ES8311 (speaker/headphone output) -#define BOARD_ES8311_ASDOUT 40 // ES8311 → ESP32 (microphone input) +#define BOARD_ES8311_DSDIN 40 // ESP32 → ES8311 (speaker/headphone output) +#define BOARD_ES8311_ASDOUT 17 // ES8311 → ESP32 (microphone input) // Compatibility aliases for ESP32-audioI2S library (setPinout expects BCLK, LRC, DOUT) #define BOARD_I2S_BCLK BOARD_ES8311_SCLK // IO39 #define BOARD_I2S_LRC BOARD_ES8311_LRCK // IO18 -#define BOARD_I2S_DOUT BOARD_ES8311_DSDIN // IO17 +#define BOARD_I2S_DOUT BOARD_ES8311_DSDIN // IO40 #define BOARD_I2S_MCLK BOARD_ES8311_MCLK // IO38 (ESP32-audioI2S may need setMCLK) // Microphone — ES8311 built-in ADC (replaces separate PDM mic on V1.1) // Mic data comes through I2S ASDOUT pin, not a separate PDM interface. -#define BOARD_MIC_I2S_DIN BOARD_ES8311_ASDOUT // IO40 +#define BOARD_MIC_I2S_DIN BOARD_ES8311_ASDOUT // IO17 + +// The Pro V1.1 had a discrete PDM microphone on BOARD_MIC_CLOCK/BOARD_MIC_DATA. +// The MAX has no PDM mic; audio capture is via the ES8311 ADC over the shared +// I2S bus. VoiceMessageScreen::initMic() (PDM path) is therefore not usable on +// MAX as-is. These are defined as -1 so the audio-variant code compiles; voice +// message RECORDING is non-functional on MAX until an ES8311-ADC capture path +// is written. -1 makes any accidental PDM init fail safely rather than driving +// the codec's real I2S pins. +#define BOARD_MIC_CLOCK -1 +#define BOARD_MIC_DATA -1 // ----------------------------------------------------------------------------- // Sensors