Zum Inhalt

loudness_p4.tc

loudness_p4.tc — mic loudness/VU meter for the Waveshare ESP32-P4 10.1" board.

Source on GitHub

// loudness_p4.tc — mic loudness/VU meter for the Waveshare ESP32-P4 10.1" board.
//
// Drives the on-board ES7210 4-mic ADC DIRECTLY over I2C (no audio plugin needed),
// then opens an independent TinyC I2S RX channel for the samples. This is the
// "codec mic" case: the ES7210 is an I2S slave that needs MCLK = 256*fs from us,
// plus its ADC enabled over I2C.
//
// Board wiring (Waveshare ESP32-P4-WIFI6-Touch-LCD-X): I2S MCLK=13 BCLK=12 WS=10
// DIN=11 (DOUT=9 is the speaker). ES7210 @ I2C 0x40. 16 kHz, 16-bit, slave.
//
// Requires firmware ABI >= 7 (i2sMicBegin with MCLK).
// Console:  MIC  -> prints the current level.

#define MIC_MCLK   13
#define MIC_BCLK   12
#define MIC_WS     10
#define MIC_DIN    11
#define MIC_RATE   16000

#define ES_ADDR    0x40
#define ES_BUS     0          // I2C bus the ES7210 is on (set to 1 if not found on 0)

int micok = 0;
int level = 0;
int peak  = 0;

// ── ES7210 register helpers ──
void esw(int reg, int val) { i2cWrite8(ES_ADDR, reg, val, ES_BUS); }
int  esr(int reg)          { return i2cRead8(ES_ADDR, reg, ES_BUS); }
void esupd(int reg, int mask, int val) {
    int v = esr(reg);
    v = (v & (255 - mask)) | (mask & val);
    esw(reg, v);
}

// enable all 4 mics (mirrors es7210_mic_select(MIC_ALL))
void es_mic_all() {
    int i;
    for (i = 0; i < 4; i = i + 1) { esupd(0x43 + i, 0x10, 0x00); }
    esw(0x4B, 0xff); esw(0x4C, 0xff);
    esupd(0x01, 0x0b, 0x00); esw(0x4B, 0x00); esupd(0x43, 0x10, 0x10);  // MIC1
    esupd(0x01, 0x0b, 0x00); esw(0x4B, 0x00); esupd(0x44, 0x10, 0x10);  // MIC2
    esupd(0x01, 0x15, 0x00); esw(0x4C, 0x00); esupd(0x45, 0x10, 0x10);  // MIC3
    esupd(0x01, 0x15, 0x00); esw(0x4C, 0x00); esupd(0x46, 0x10, 0x10);  // MIC4
}

// full ES7210 init (SLAVE, 16 kHz, 16-bit, I2S normal). Mirrors pes7210_codec_init.
void es7210_init() {
    esw(0x00, 0xff);            // reset
    esw(0x00, 0x41);
    esw(0x01, 0x1f);            // clock off
    esw(0x09, 0x30);
    esw(0x0A, 0x30);
    esw(0x40, 0xC3);            // analog power
    esw(0x41, 0x70); esw(0x42, 0x70);   // mic bias
    esw(0x07, 0x20);            // OSR
    esw(0x02, 0xC1);            // main clock (256*fs)
    esw(0x07, 0x20);
    esw(0x04, 0x01); esw(0x05, 0x00);   // LRCK div (16 kHz)
    es_mic_all();
    int iface = esr(0x11) & 0x1f; esw(0x11, iface | 0x60);   // 16-bit
    iface = esr(0x11) & 0xfc;    esw(0x11, iface);           // I2S normal
    esw(0x12, 0x00);
    esupd(0x43, 0x0f, 14); esupd(0x44, 0x0f, 14);            // MIC1/2 = +37.5 dB
    esupd(0x45, 0x0f, 0);  esupd(0x46, 0x0f, 0);             // MIC3/4 = 0 dB
    int regv = esr(0x01); esw(0x01, regv);                  // start
    esw(0x06, 0x00);                                        // power up
    esw(0x47, 0x00); esw(0x48, 0x00); esw(0x49, 0x00); esw(0x4A, 0x00);
    es_mic_all();
}

int isqrt(int n) {
    if (n <= 0) { return 0; }
    int x = n; int y = (x + 1) / 2;
    while (y < x) { x = y; y = (x + n / x) / 2; }
    return x;
}
int pct_of(int rms) {
    int p = (isqrt(rms) * 100) / 181;
    if (p > 100) { p = 100; }
    return p;
}

void Every100ms() {
    if (!micok) { return; }
    int v = i2sMicLevel();
    if (v < 0) { return; }
    level = v;
    if (v > peak) { peak = v; } else { peak = (peak * 9) / 10; }
}

void Command(char cmd[]) {
    char resp[64];
    sprintf(resp, "rms=%d (%d%%) peak=%d", level, pct_of(level), pct_of(peak));
    responseCmnd(resp);
}

void WebUI() {
    char buf[256];
    int p = pct_of(level);
    int pk = pct_of(peak);
    sprintf(buf, "{s}Loudness{m}%d %% (rms %d){e}", p, level);
    webSend(buf);
    sprintf(buf, "{s}Level{m}<div style='position:relative;background:#222;width:170px;height:14px;border-radius:7px'><div style='background:#3ddc84;height:14px;width:%d%%;border-radius:7px'></div><div style='position:absolute;top:0;left:%d%%;width:2px;height:14px;background:#e66'></div></div>{e}", p, pk);
    webSend(buf);
}

int main() {
    es7210_init();                                  // bring up the ADC over I2C
    micok = (i2sMicBegin(MIC_MCLK, MIC_BCLK, MIC_WS, MIC_DIN, MIC_RATE) == 0);
    if (micok) { addLog("loudness_p4: ES7210 + mic RX started"); }
    else { addLog("loudness_p4: i2sMicBegin FAILED — check firmware ABI>=7"); }
    addCommand("MIC");
    return 0;
}