I2S Sound Level Meter
ESP32 DevKit (WROOM-32)·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic + PCB
An INMP441 MEMS microphone streams 16-bit audio into the ESP32 over I2S (SCK GPIO32, WS GPIO25, SD GPIO33). Every 100 ms the sketch reads a 256-sample block with the ESP-IDF i2s_read() driver, computes the RMS level, converts it to dBFS and lights a proportional 5-LED VU bar (2 green, 2 yellow, 1 red) while printing a matching serial bar graph. The simulator feeds the mic a synthetic ambient tone whose loudness slowly rises and falls, so the VU bar sweeps up and down just like a real room. Bundled Lab bench, schematic and routed PCB included.
sketch.ino
// I2S Sound Level Meter — INMP441 MEMS microphone + 5-LED VU bar
//
// The INMP441 streams 16-bit audio over I2S. Every 100 ms the sketch reads a
// block of samples, computes the RMS level, converts it to a dB-style value
// and lights a proportional bar of LEDs (2 green, 2 yellow, 1 red).
#include <driver/i2s.h>
#define I2S_SCK 32 // BCLK — serial clock
#define I2S_WS 25 // LRCLK — word select
#define I2S_SD 33 // DOUT from the microphone
#define SAMPLE_RATE 16000
#define BLOCK_SIZE 256
const int ledPins[5] = {23, 22, 21, 19, 18}; // VU bar, quiet -> loud
int16_t samples[BLOCK_SIZE];
void setup() {
Serial.begin(115200);
for (int i = 0; i < 5; i++) {
pinMode(ledPins[i], OUTPUT);
digitalWrite(ledPins[i], LOW);
}
i2s_config_t cfg;
cfg.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX);
cfg.sample_rate = SAMPLE_RATE;
cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
cfg.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
cfg.communication_format = I2S_COMM_FORMAT_STAND_I2S;
cfg.intr_alloc_flags = 0;
cfg.dma_buf_count = 4;
cfg.dma_buf_len = BLOCK_SIZE;
i2s_driver_install(I2S_NUM_0, &cfg, 0, NULL);
i2s_pin_config_t pins;
pins.mck_io_num = I2S_PIN_NO_CHANGE;
pins.bck_io_num = I2S_SCK;
pins.ws_io_num = I2S_WS;
pins.data_out_num = I2S_PIN_NO_CHANGE;
pins.data_in_num = I2S_SD;
i2s_set_pin(I2S_NUM_0, &pins);
Serial.println("I2S sound level meter ready");
}
void loop() {
size_t bytesRead = 0;
i2s_read(I2S_NUM_0, samples, BLOCK_SIZE * 2, &bytesRead, 100);
int n = bytesRead / 2;
if (n == 0) { delay(10); return; }
// RMS level of the block
float sumSq = 0;
for (int i = 0; i < n; i++) {
float s = samples[i];
sumSq += s * s;
}
float rms = sqrt(sumSq / n);
// Rough dBFS (0 dB = full-scale 32768) mapped onto a 0-5 LED bar
float db = 20.0 * log10(rms / 32768.0 + 0.0000001);
float thresholds[5] = {-24.0, -21.5, -19.5, -17.5, -16.0};
int bar = 0;
for (int i = 0; i < 5; i++) {
if (db >= thresholds[i]) bar = i + 1;
}
for (int i = 0; i < 5; i++) {
digitalWrite(ledPins[i], i < bar ? HIGH : LOW);
}
Serial.print("RMS ");
Serial.print(rms, 0);
Serial.print(" ");
Serial.print(db, 1);
Serial.print(" dBFS [");
for (int i = 0; i < 5; i++) Serial.print(i < bar ? "#" : ".");
Serial.println("]");
delay(100);
}Built with FluxBench.AI — the AI workbench for embedded projects.