diff --git a/README.md b/README.md index 0b8c069..527aa5b 100644 --- a/README.md +++ b/README.md @@ -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 + 趋势图 | diff --git a/firmware/cyd_28r/VERSION.txt b/firmware/cyd_28r/VERSION.txt index 4d1fccf..dced4f4 100644 --- a/firmware/cyd_28r/VERSION.txt +++ b/firmware/cyd_28r/VERSION.txt @@ -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 diff --git a/firmware/cyd_28r/firmware.bin b/firmware/cyd_28r/firmware.bin index 46ef4fa..bb46c42 100644 Binary files a/firmware/cyd_28r/firmware.bin and b/firmware/cyd_28r/firmware.bin differ diff --git a/src/main.cpp b/src/main.cpp index 7ea3543..f573ba7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 @@ -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;