Arduino library 路 Communication

ESP32 I2S: digital audio in from a microphone and out to an amplifier

I2S is the three-wire serial bus for digital audio: a bit clock (BCLK), a word select line (WS, also called LRCLK) that says left or right channel, and a data line. The ESP32 has I2S hardware that can sit on almost any GPIO, which is how projects read an INMP441 MEMS microphone or drive a MAX98357A class D amplifier straight into a speaker with no DAC in between.

Built in on Mokxi: #include <ESP_I2S.h> and it builds, with nothing to install. Free, and no account needed.

What I2S (ESP32 core and ESP-IDF) does

Arduino-ESP32 3.x provides I2SClass in ESP_I2S.h: set the pins, then begin() with the mode, sample rate, bit width and mono or stereo. Older core 2.x sketches use the I2S object from I2S.h, and many tutorials call the ESP-IDF driver in driver/i2s.h directly; the three are different APIs for the same peripheral, so copy code from a tutorial that matches your core version.

The usual surprise is the sample format. An INMP441 sends 24 bits left-justified in a 32-bit slot, and only on the channel its L/R pin selects, so a sketch reading 16-bit stereo gets silence or noise until the width and slot match the microphone.

Library Manager nameI2S (ESP32 core and ESP-IDF)
AuthorEspressif
Include#include <ESP_I2S.h>
#include <I2S.h>
#include <driver/i2s.h>
#include <driver/i2s_std.h>
BoardsESP32-C3, ESP32-C6, Seeed XIAO ESP32-C3, ESP32-C3 SuperMini, Seeed XIAO ESP32-C6, ESP32 DevKit, ESP32-DevKitC V4, LOLIN32 Lite, Wemos D1 R32, Cheap Yellow Display, TTGO T-Display, ESP32-S3-DevKitC-1, Seeed XIAO ESP32-S3, Arduino Nano ESP32
In the simulatorRuns, with a gap the note below names.
Parts it drivesI2S microphone, INMP441, I2S amplifier, MAX98357A

Install it

It builds on ESP32-C3, ESP32-C6, Seeed XIAO ESP32-C3, ESP32-C3 SuperMini, Seeed XIAO ESP32-C6, ESP32 DevKit, ESP32-DevKitC V4, LOLIN32 Lite, Wemos D1 R32, Cheap Yellow Display, TTGO T-Display, ESP32-S3-DevKitC-1, Seeed XIAO ESP32-S3, Arduino Nano ESP32.

In Mokxi it is built in: #include <ESP_I2S.h> and the sketch compiles, with no download, no zip and no Library Manager.

On a real board it comes with the board package (Espressif), so the Arduino IDE has it as soon as the board is installed: there is nothing to add from the Library Manager.

ESP32-C3 路 ESP32-C6 路 Seeed XIAO ESP32-C3 路 ESP32-C3 SuperMini 路 Seeed XIAO ESP32-C6 路 ESP32 DevKit 路 ESP32-DevKitC V4 路 LOLIN32 Lite 路 Wemos D1 R32 路 Cheap Yellow Display 路 TTGO T-Display 路 ESP32-S3-DevKitC-1 路 Seeed XIAO ESP32-S3 路 Arduino Nano ESP32

The calls you will use

In the order a sketch meets them.

I2SClass i2s

The I2S port object from ESP_I2S.h, one per peripheral you use.

i2s.setPins(26, 25, 22)

Sets BCLK, WS and the data out pin; a fourth argument is data in, for a microphone. Call it before begin().

i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)

Starts standard (Philips) I2S at 16 kHz with 16-bit samples in stereo. Returns false if the settings or pins are rejected.

i2s.write((uint8_t *)samples, sizeof(samples))

Sends a buffer of samples to the amplifier and returns how many bytes went out. Interleave left and right in stereo.

i2s.readBytes((char *)buffer, sizeof(buffer))

Reads samples from the microphone into a buffer and returns the number of bytes read.

int32_t buffer[64];
size_t n = i2s.readBytes((char *)buffer, sizeof(buffer));
for (size_t i = 0; i < n / 4; i++) Serial.println(buffer[i] >> 8);

i2s.end()

Stops the port and frees its pins.

Example: ESP32 I2S sine player

On the ESP32 DevKit V1. It runs in the browser exactly as printed.

sketch.ino 路 ESP32 DevKit V1
// MAX98357A 440 Hz tone on an ESP32.
//
// The MAX98357A is an I2S amplifier: it takes the bit clock (BCLK), the word
// select (LRC) and the samples (DIN) and drives a speaker directly. With SD
// left open it plays the average of the left and right channels; GAIN left
// open is 9 dB.
//
// This sketch uses ESP_I2S.h, the I2S library of Arduino-ESP32 3.x. In
// setup() it fills a table with one cycle of a sine; loop() keeps writing the
// next block of samples, the same value to the left and the right slot, so
// the speaker hears a steady 440 Hz. At 16 kHz, 440 Hz is 36.36 samples a
// cycle, so the table is read with a 16.16 fixed-point phase rather than a
// whole number of samples, and no float is touched per sample.
//
// Wiring: VIN to 5V (VIN on the DevKit), GND to GND, BCLK to GPIO 26,
// LRC to GPIO 25, DIN to GPIO 22, a speaker across SPK+ and SPK-.

#include <ESP_I2S.h>
#include <math.h>

#define I2S_BCLK 26
#define I2S_LRC 25
#define I2S_DIN 22

const uint32_t kSampleRate = 16000;
const uint32_t kFrequency = 440;
const int kTable = 256;
const int16_t kAmplitude = 8000;  // about a quarter of full scale

I2SClass i2s;
int16_t sine[kTable];
int16_t block[2 * 128];  // 128 stereo frames: left, right, left, right ...
uint32_t phase = 0;
// Table steps a sample, in 16.16 fixed point: 440 * 256 / 16000.
const uint32_t kStep = (uint32_t)(((uint64_t)kFrequency * kTable << 16) / kSampleRate);

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < kTable; i++) {
    sine[i] = (int16_t)(kAmplitude * sinf(2.0f * (float)M_PI * i / kTable));
  }
  i2s.setPins(I2S_BCLK, I2S_LRC, I2S_DIN);
  if (!i2s.begin(I2S_MODE_STD, kSampleRate, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)) {
    Serial.println("Failed to initialize I2S!");
    while (true) delay(1000);
  }
  Serial.println("Playing 440 Hz");
}

void loop() {
  for (int i = 0; i < 128; i++) {
    int16_t s = sine[(phase >> 16) & (kTable - 1)];
    block[2 * i] = s;      // left
    block[2 * i + 1] = s;  // right
    phase += kStep;
  }
  i2s.write((uint8_t *)block, sizeof(block));
}

Open it in the editor, wired and ready to run 路 ESP32 I2S sine player: the project page

Common errors and how to fix them

The microphone reads all zeros

Check that the INMP441鈥檚 L/R pin and the slot you read agree (L/R to GND is the left channel), that the data pin is set as the input in setPins(), and that you read 32-bit samples. A 16-bit read of a 32-bit slot often lands on the empty bits.

The speaker plays loud static instead of the tone

The sample rate, bit width or byte order in the buffer does not match what begin() was told. For 16-bit stereo, write int16_t pairs, left then right, and pass the same rate you computed the wave for.

'I2SClass' does not name a type

ESP_I2S.h and I2SClass are Arduino-ESP32 3.x. On core 2.x use the I2S.h object or the ESP-IDF driver/i2s.h calls, or update the ESP32 core in the Boards Manager.

Projects that use I2S (ESP32 core and ESP-IDF)

Built-in projects that include it. Each page has the full sketch and opens in the editor, already wired.

Try I2S (ESP32 core and ESP-IDF) without installing anything

Open the example, change the sketch, and keep your version in a free account.