The Inter-Integrated Circuit Sound (I2S) is a synchronous serial communication protocol used to transmit digital audio data between devices.
I2S is a protocol designed to transmit digital audio data between devices (such as microphones, audio sensors, DACs (Digital-to-Analog Converters), ADCs (Analog-to-Digital Converters), and other audio peripherals).
Unlike other communication protocols, such as I2C or SPI, I2S is optimized for real-time audio data transmission.
The I2S protocol uses three main lines:
Serial Clock (SCK): This line provides the master clock that synchronizes the transmission of bits between devices.
Word Select (WS): Also known as the word clock line, it indicates when a new word data starts (for example, a new audio channel).
Data Line (SD): Carries the digital audio data itself.
Using I2S on ESP32
To use I2S on the ESP32, we first need to configure the I2S driver parameters using the libraries and functions provided by the Espressif SDK.
This includes setting up the clock, the audio data format, the number of channels, the data direction, among others.
#include "driver/i2s.h"
void configureI2S() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Master mode and transmission
.sample_rate = 44100, // Sample rate in Hz
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // Only right channel
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
}
Once the I2S driver is configured, we can transmit digital audio data. This involves properly packaging the audio data and sending it over the I2S bus.
void transmitAudioData(const uint8_t *data, size_t len) {
i2s_write_bytes(I2S_NUM_0, (const char *)data, len, portMAX_DELAY);
}
Code Example
Let’s see how an example of using I2S on ESP32 for real-time audio processing would look.
We can capture audio from a microphone, apply sound effects, and then play the processed audio through a speaker or headphones.
The final code will depend on the device, microphone, or speaker that we are using. But it generally looks something like this.
void processAudioData(const uint8_t *inputData, uint8_t *outputData, size_t len) {
// Apply audio processing effects to inputData and store the result in outputData
}
void audioProcessingTask(void *arg) {
uint8_t inputData[1024];
uint8_t outputData[1024];
while (1) {
// Capture audio data from the microphone using I2S
i2s_read_bytes(I2S_NUM_0, inputData, sizeof(inputData), portMAX_DELAY);
// Process the audio data
processAudioData(inputData, outputData, sizeof(inputData));
// Transmit the processed audio data through I2S
transmitAudioData(outputData, sizeof(outputData));
}
}
void app_main() {
configureI2S();
xTaskCreate(audioProcessingTask, "audio_task", 4096, NULL, 5, NULL);
}