Fix INMP441 silent meter: stereo I2S slots and DC removal.

ESP32 left/right naming often mismatches L/R=GND, and DC bias made dB look stuck.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 21:00:29 +08:00
parent 59b85fb7dc
commit 8b2a2cbc0b
4 changed files with 69 additions and 17 deletions

View File

@@ -83,4 +83,5 @@ README.md
| 日期 | 说明 |
|------|------|
| 2026-10-27 | 修复无声贝变化:I2S 改立体声读槽(ESP32 L/R 与麦脚常反相)+ 去直流后再算 RMS |
| 2026-10-27 | 初版:INMP441 I2S 声贝仪表盘(WS22/SCK27/SD35),LVGL 圆弧 + peak/min/max + 趋势图 |

View File

@@ -1,5 +1,5 @@
name: CYD inmp441test (cyd_28r)
git: unknown
git: 59b85fb
date: 2026-10-27
board: ESP32-2432S028R (ILI9341)
inmp441: WS=GPIO22 SCK=GPIO27 SD=GPIO35
@@ -13,5 +13,5 @@ offsets:
sha256:
bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8
boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0
firmware.bin 0CA34A45377F5EDCAB501E510F97B28A9B7FCEB34D6C65F0B71691C784C41999
firmware.bin 81B26992192E72F77396E0B71782C145EFE106F996D9E432F1551F5182CC6710
partitions.bin 0A8B5720E7B77FF11F1462458C3A509DEE79224E5279898F26D6A2E3AE0517B7

Binary file not shown.

View File

@@ -3,7 +3,8 @@
* 2.8 (2432S028R): WS=22 SCK=27 SD=35, TFT_BL=21
* 3.5C (3248S035C): WS=22 SCK=21 SD=35, TFT_BL=27 — see ../CYD_PROJECT_GUIDE.md
*
* L/R -> GND(左声道);VDD -> 3.3V(勿接 5V)
* L/R -> GND(推荐);VDD -> 3.3V(勿接 5V)
* ESP32 I2S 声道命名常与 INMP441 反相:L/R=GND 时用 RIGHT 槽才有数据。
*/
#include <Arduino.h>
@@ -17,7 +18,7 @@
#define I2S_PORT I2S_NUM_0
#define SAMPLE_RATE 16000
#define SAMPLE_BITS 32
#define DMA_BUF_COUNT 4
#define DMA_BUF_COUNT 8
#define DMA_BUF_LEN 256
#define READ_SAMPLES 512
#define MIC_READ_MS 80
@@ -223,7 +224,9 @@ static bool mic_init(void) {
cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX);
cfg.sample_rate = SAMPLE_RATE;
cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT;
cfg.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
/* Stereo: ESP32 left/right vs INMP441 L/R pin are often inverted.
* L/R=GND usually lands in the RIGHT DMA slot on classic ESP32. */
cfg.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
cfg.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
cfg.dma_buf_count = DMA_BUF_COUNT;
@@ -247,31 +250,79 @@ static bool mic_init(void) {
return false;
}
i2s_zero_dma_buffer(I2S_PORT);
Serial.printf("I2S stereo RX WS=%d SCK=%d SD=%d\n",
I2S_WS_PIN, I2S_SCK_PIN, I2S_SD_PIN);
return true;
}
static bool mic_read_db(float *out_db, float *out_rms) {
size_t bytes_read = 0;
esp_err_t err = i2s_read(I2S_PORT, (void *)i2s_samples, sizeof(i2s_samples),
&bytes_read, pdMS_TO_TICKS(40));
&bytes_read, pdMS_TO_TICKS(50));
if (err != ESP_OK || bytes_read < sizeof(int32_t) * 32) {
return false;
}
int n = (int)(bytes_read / sizeof(int32_t));
double sum_sq = 0.0;
int used = 0;
for (int i = 0; i < n; i++) {
/* INMP441: 24-bit left-justified in 32-bit word */
int32_t s = i2s_samples[i] >> 8;
sum_sq += (double)s * (double)s;
used++;
}
if (used < 16) return false;
if (n < 32) return false;
/* Unpack 24-bit left-justified samples; stereo slots alternate. */
static int32_t unpacked[READ_SAMPLES];
for (int i = 0; i < n; i++) {
unpacked[i] = i2s_samples[i] >> 8;
}
/* Measure even/odd slots separately (ESP32 L/R naming vs mic L/R pin). */
double mean_even = 0.0, mean_odd = 0.0;
int n_even = 0, n_odd = 0;
for (int i = 0; i < n; i++) {
if ((i & 1) == 0) {
mean_even += unpacked[i];
n_even++;
} else {
mean_odd += unpacked[i];
n_odd++;
}
}
if (n_even < 8 || n_odd < 8) return false;
mean_even /= (double)n_even;
mean_odd /= (double)n_odd;
double sum_even = 0.0, sum_odd = 0.0;
int32_t peak_abs = 0;
for (int i = 0; i < n; i++) {
double v;
if ((i & 1) == 0) {
v = (double)unpacked[i] - mean_even;
sum_even += v * v;
} else {
v = (double)unpacked[i] - mean_odd;
sum_odd += v * v;
}
int32_t a = (int32_t)((v < 0) ? -v : v);
if (a > peak_abs) peak_abs = a;
}
double rms_even = sqrt(sum_even / (double)n_even);
double rms_odd = sqrt(sum_odd / (double)n_odd);
double rms = (rms_even > rms_odd) ? rms_even : rms_odd;
const char *slot = (rms_even >= rms_odd) ? "L/even" : "R/odd";
static uint8_t dbg = 0;
if (dbg < 10) {
dbg++;
Serial.printf(
"raw=%08lX/%08lX meanE=%.0f meanO=%.0f rmsE=%.0f rmsO=%.0f peak=%ld %s\n",
(unsigned long)(uint32_t)i2s_samples[0],
(unsigned long)(uint32_t)i2s_samples[1], mean_even, mean_odd, rms_even,
rms_odd, (long)peak_abs, slot);
}
double rms = sqrt(sum_sq / (double)used);
*out_rms = (float)rms;
if (rms < 1.0) rms = 1.0;
if (rms < 1.0) {
*out_db = 0.0f;
return true;
}
/* dBFS vs 24-bit full scale, then map to approximate SPL */
float dbfs = 20.0f * log10f((float)rms / 8388607.0f);
*out_db = dbfs + MIC_DB_OFFSET;