ESP32/System/79. I2S audio
Your chip
Your language
System · 79 of 81

I2S audio

Digital audio in and out with no analog parts at all - a microphone that sends numbers, an amplifier that takes them. The chip generates all three clocks, and every bug is the same one - a buffer that ran dry.

/esp32/i2s-audio · arduino · S3

Three clocks and a buffer

16000 Hz, 16-bit, mono
256 kHz
Sample rate16 kHz
Bit depth16 bit
DMA buffer40 ms
Bit clock
256 kHz
Data rate
31 kB/s
Buffer RAM
1 kB
256 kHz bit clock, 31 kB/s, 1 kB of buffer. The chip generates all three clocks itself, so the microphone or the amplifier simply follows. The wiring gotcha is the channel-select pin on I2S microphones — tied high or low it decides left or right, and left floating you get silence on one side and blame the code.

The three wires, named

SignalAlso calledWhat it is
BCLKSCK, SCLKOne pulse per bit
WSLRCLK, LRCKWhich channel this sample belongs to
SDDIN, DOUTThe data itself

All three come from the ESP32 when it is the master, which is the usual arrangement. The microphone or amplifier just follows.

Parts that work

  • INMP441 or ICS-43434 — I2S microphones, 24-bit, three wires.
  • MAX98357A — I2S amplifier straight to a speaker, no DAC needed.
  • PCM5102 — I2S DAC to a line output, for headphones or a hi-fi.

The thing to design in from the start

Audio in its own FreeRTOS task, on core 1, with a DMA buffer of 40–80 ms. Everything else — Wi-Fi, the display, the SD card — then cannot interrupt the stream, and the clicks that people spend days chasing never appear.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

An INMP441 microphone into the ESP32. The samples arrive 24-bit inside a 32-bit slot, which is why the shift is there - without it every level looks 256 times too small.

i2s_mic.ino
#include <ESP_I2S.h>

I2SClass i2s;

void setup() {
  Serial.begin(115200);
  i2s.setPins(4, 5, -1, 6);            // BCLK, WS, DOUT, DIN
  i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_32BIT,
            I2S_SLOT_MODE_MONO);
}

void loop() {
  int32_t frame[256];
  size_t n = i2s.readBytes((char *)frame, sizeof(frame));

  long peak = 0;
  for (size_t i = 0; i < n / 4; i++) {
    long s = frame[i] >> 8;            // 24 bits in a 32-bit slot
    peak = max(peak, labs(s));
  }
  Serial.println(peak);
}

Give audio its own task, pinned to core 1. A loop that also serves a web page will empty the DMA queue eventually, and you hear it as a click.

When it does not work

Silence, or only one channel

The microphone's L/R pin is floating. Tie it high or low to choose a channel, and set the matching slot mode in the code.

The audio clicks and pops

The DMA buffer emptied. Something blocked - a flash write, a Wi-Fi reconnect, an SD card pausing. Increase the buffer and move audio into its own task.

Everything is extremely quiet

Missing the shift. 24-bit data in a 32-bit slot needs a right shift of 8 before it means anything.

A speaker connected directly does nothing

I2S is digital. It carries numbers, not power. You need an amplifier such as a MAX98357A, which takes I2S in and drives the speaker itself.

Where this goes next

Sound is a stream small enough to hold. The next page is one that is not.

Camera capture

Edit this page — content/esp32/i2s-audio.mdx

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse ESP32 on the forum