Skip to content

Fix Cardputer-Adv ES8311 mic by pinning IDF patch series to v5.4#97

Open
chilang wants to merge 1 commit into
m5stack:masterfrom
chilang:cardputer-adv-mic-fix-idf-v5.4
Open

Fix Cardputer-Adv ES8311 mic by pinning IDF patch series to v5.4#97
chilang wants to merge 1 commit into
m5stack:masterfrom
chilang:cardputer-adv-mic-fix-idf-v5.4

Conversation

@chilang
Copy link
Copy Markdown

@chilang chilang commented May 14, 2026

Summary

Building UIFlow against ESP-IDF v5.5.1 produces silent / constant samples (-8 / -1) on the Cardputer-Adv's ES8311 microphone. The same M5Unified sources built against ESP-IDF v5.4.2 work correctly. The regression lives in IDF v5.5.x's I²S driver / MCLK GPIO routing — not in M5Unified, not in the codec init, not in MicroPython bindings.

This PR switches IDF_PATH_PATCH_SERIES from 1005-idf_v5.5_freertos.patch to 1004-idf_v5.4_freertos.patch. Both patch files already ship in m5stack/patches/; this is a one-line selection change.

 IDF_PATH_PATCH_SERIES = \
-	1005-idf_v5.5_freertos.patch
+	1004-idf_v5.4_freertos.patch

The bug

On M5Stack Cardputer-Adv (ESP32-S3 + ES8311 I²S audio codec), microphone capture via M5.Mic.record() or M5.Mic.recordWavFile() returns constant samples:

  • -8 (16-bit signed, every sample identical) when the codec is in mic-ADC mode
  • -1 / 0xFFFFFFFF (line floating high) when the I²S RX bus has no data

The codec itself is healthy: I²C reads back all the expected ADC-chain register values after M5.Mic.begin() (0x01=0xBA, 0x0E=0x02, 0x14=0x10, 0x17=0xBF, 0x1C=0x6A). BCK and WS clocks toggle. But no audio data ever reaches the SoC.

Industry-wide, undiagnosed for months — see espressif/esp-idf#18621 for the upstream report and bisect.

Bisect — it's the IDF version

Built a standalone ESP-IDF project using stock M5Unified 0.2.10 and the documented Cardputer-Adv mic-init sequence. Same source, two IDF versions:

ESP-IDF version Mic result
v5.4.2 ✅ Works — min/max values track audio input
v5.5.1 ❌ Broken — stuck at -64 / -8 / -1

This rules out:

  • ES8311 codec hardware (works fine in M5Stack's stock Arduino "User Demo")
  • M5Unified Mic_Class.cpp (identical between tests)
  • arduino-esp32 board package (bypassed in the standalone test)
  • MicroPython bindings (native C++ test reproduces it)

The regression is in ESP-IDF v5.5.x's I²S driver / GPIO-matrix layer, almost certainly in MCLK pin routing. Without MCLK at 256×fs = 4.096 MHz, the ES8311 ADC PLL can't lock and outputs a DC-offset constant — matching every symptom observed across ~12 different test paths during investigation.

M5Stack's own ES8311 "User Demo" firmware on M5Burner uses the new i2s_channel_* API (i2s_new_channel, i2s_std_set_clock, i2s_check_set_mclk) and works on v5.5; the Arduino M5Unified library uses the legacy i2s_driver_install API and breaks. Suggests the legacy shim's MCLK handling regressed.

How to build

# Install ESP-IDF v5.4.2 alongside any existing IDF (e.g. v5.5.1):
git clone -b v5.4.2 --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf
~/esp/esp-idf/install.sh esp32s3

# Activate v5.4.2 environment:
source ~/esp/esp-idf/export.sh

# Install missing Python dep that v5.4.2's env doesn't carry by default:
python3 -m pip install future

# Build:
cd m5stack
make patch
make BOARD=M5STACK_CardputerADV

The build produces build-M5STACK_CardputerADV/uiflow-<hash>.bin (~6.3 MB, app + bootloader + partition table + nvs + fs-system).

The default packed binary excludes the fs-user partition by design. To ship a default /flash/ filesystem (apps, boot.py, main.py) in one flash, also write build-M5STACK_CardputerADV/fs-user.bin at offset 0x641000:

esptool.py --chip esp32s3 --port /dev/cu.usbmodemXXX --baud 1500000 write_flash \
    0x0 build-M5STACK_CardputerADV/uiflow-<hash>.bin \
    0x641000 build-M5STACK_CardputerADV/fs-user.bin

ESP32-S3 native USB-CDC doesn't auto-DTR/RTS into download mode. Manual: unplug, hold the G0 (BOOT) button, plug in, release G0.

What this fix is not

Verification

End-to-end test: built this branch, flashed to a Cardputer-Adv, ran a MicroPython app that calls M5.Mic.recordWavFile("/flash/last.wav", 16000, 6), uploaded the WAV to OpenAI Whisper via a Cloudflare Worker, got a correct transcription back. The full STT pipeline produces real audio data, not the -8 constant that v5.5.1 builds produce.

Reverting to upstream

make unpatch
git checkout m5stack/Makefile
make patch

Test plan

  • make patch applies cleanly against IDF v5.4.2
  • make BOARD=M5STACK_CardputerADV produces a working firmware image
  • M5.Mic.recordWavFile() captures real audio on Cardputer-Adv
  • End-to-end Whisper STT transcription verified
  • Reviewer: confirm other supported boards still build with the v5.4 patch series (only Cardputer-Adv tested)

Building UIFlow against ESP-IDF v5.5.1 produces silent / constant
samples (-8 / -1) on the Cardputer-Adv's ES8311 codec. Same M5Unified
sources built against v5.4.2 work correctly. The regression is in
IDF v5.5.x's I2S driver / MCLK pin routing, not in M5Unified or
the codec init.

Switch IDF_PATH_PATCH_SERIES from 1005-idf_v5.5_freertos.patch to
1004-idf_v5.4_freertos.patch. Both patches already ship in
m5stack/patches/; this is a one-line selection change.

See FIX.md for the full bisect, build instructions, and verification.
@chilang chilang force-pushed the cardputer-adv-mic-fix-idf-v5.4 branch from b37b723 to 4b1282d Compare May 14, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant