ESP32 I2S microphone level meter
An INMP441 I2S microphone on an ESP32, read with the ESP-IDF I2S driver: the sound level in dBFS and a bar on the serial monitor. Pick a tone, noise or voice and drag its level. The whole build, an ESP32 DevKit and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate Runs in your browser. Free, and no account needed.
The parts retail for about $11.50. On Mokxi they're free.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// INMP441 sound level meter on an ESP32.
//
// The INMP441 is a MEMS microphone with an I2S output: the ESP32 drives the
// bit clock (SCK) and the word select (WS), and the microphone answers with
// 24-bit samples on SD, most significant bit first. L/R to GND puts it in the
// left slot, so the driver reads ONLY_LEFT. Each sample arrives in a 32-bit
// slot, left-aligned, so shifting right by 8 gives the 24-bit value.
//
// Every 512 samples (32 ms at 16 kHz) the sketch prints the RMS level and
// the peak in dBFS, decibels below a full-scale 24-bit sine, and a bar of the
// level from -90 to 0 dBFS. The numbers are labeled for the Serial Plotter. The microphone sends zeros for its first 2^18
// clocks after power-up (about a quarter of a second of reading), as its data
// sheet says, so the first few lines read -inf.
//
// Wiring: VDD to 3V3, GND to GND, L/R to GND, SCK to GPIO 32, WS to GPIO 25,
// SD to GPIO 33.
#include <driver/i2s.h>
#include <math.h>
#define I2S_PORT I2S_NUM_0
#define I2S_SCK 32
#define I2S_WS 25
#define I2S_SD 33
const int kSampleRate = 16000;
const int kSamples = 512;
int32_t samples[kSamples];
void setup() {
Serial.begin(115200);
Serial.println("INMP441 level meter");
i2s_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),
.sample_rate = kSampleRate,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 256,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
i2s_pin_config_t pin_config = {
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = I2S_SD
};
if (i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL) != ESP_OK) {
Serial.println("i2s_driver_install failed");
while (true) delay(1000);
}
i2s_set_pin(I2S_PORT, &pin_config);
i2s_zero_dma_buffer(I2S_PORT);
}
void loop() {
size_t bytes_read = 0;
i2s_read(I2S_PORT, samples, sizeof(samples), &bytes_read, portMAX_DELAY);
int n = bytes_read / sizeof(int32_t);
if (n == 0) return;
// Integer work per sample; the floats come once a buffer.
int64_t sum = 0;
int64_t sumSquares = 0;
int32_t peak = 0;
for (int i = 0; i < n; i++) {
int32_t s = samples[i] >> 8; // the 24-bit sample
sum += s;
int32_t a = s < 0 ? -s : s;
if (a > peak) peak = a;
}
int32_t mean = (int32_t)(sum / n); // take out any DC offset
for (int i = 0; i < n; i++) {
int64_t d = (int64_t)((samples[i] >> 8) - mean);
sumSquares += d * d;
}
const float fullScale = 8388607.0f; // 2^23 - 1
float rms = sqrtf((float)sumSquares / n);
float level = 20.0f * log10f(rms / fullScale) + 3.01f; // dBFS, full-scale sine = 0
float peakDb = 20.0f * log10f(peak / fullScale);
Serial.print("level:");
Serial.print(level, 1);
Serial.print(" peak:");
Serial.print(peakDb, 1);
// The bar: one # for every 2.25 dB above -90 dBFS.
int bars = 0;
if (level > -90.0f) bars = (int)((level + 90.0f) / 2.25f); // not for -inf
if (bars > 40) bars = 40;
Serial.print(" |");
for (int i = 0; i < 40; i++) Serial.print(i < bars ? '#' : ' ');
Serial.println("|");
}
Parts list
2 parts, plus the jumper wires. They retail for about $11.50; on Mokxi they're free.
How it is wired
5 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- ESP32 DevKit V1 pin D32; I2S microphone, INMP441 pin SCK
- ESP32 DevKit V1 pin D33; I2S microphone, INMP441 pin SD
- ESP32 DevKit V1 pin D25; I2S microphone, INMP441 pin WS
- Ground: ESP32 DevKit V1 pin GND; I2S microphone, INMP441 pin LR; I2S microphone, INMP441 pin GND
- ESP32 DevKit V1 pin 3V3; I2S microphone, INMP441 pin VDD
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.