pdf-icon

Arduino Quick Start

Module Audio Arduino Tutorial

1. Preparation

2. Initialization

Module Audio integrates an STM32 main controller to handle headset standard switching, LED control, headphone insertion detection (Channel 2 only), microphone enable, and other functions.

Interface Standard Selection
Since different headset wiring standards use different pin assignments, call device.setHPMode(AUDIO_HPMODE_NATIONAL); or device.setHPMode(AUDIO_HPMODE_AMERICAN); to switch between OMTP (AUDIO_HPMODE_NATIONAL) and CTIA (AUDIO_HPMODE_AMERICAN) for compatibility.
#include "M5Unified.h"
#include "audio_i2c.hpp"
#include "es8388.hpp"
#include "driver/i2s.h"

#define SYS_I2C_SDA_PIN  21
#define SYS_I2C_SCL_PIN  22
#define SYS_I2S_MCLK_PIN 0
#define SYS_I2S_SCLK_PIN 19
#define SYS_I2S_LRCK_PIN 27
#define SYS_I2S_DOUT_PIN 2
#define SYS_I2S_DIN_PIN  34
#define SYS_SPI_MISO_PIN 38
#define SYS_SPI_MOSI_PIN 23
#define SYS_SPI_CLK_PIN  18
#define SYS_SPI_CS_PIN   4

AudioI2c device;
ES8388 es8388(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);

void setup()
{
    M5.begin();
    Serial.begin(115200);
    device.begin(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);
    device.setHPMode(AUDIO_HPMODE_NATIONAL);
    // device.setHPMode(AUDIO_HPMODE_AMERICAN);
    device.setMICStatus(AUDIO_MIC_OPEN);
    device.setRGBBrightness(100);
    for (int i = 0; i <= 2; i++) {
        device.setRGBLED(i, 0x0000ff);
    }
}

void loop()
{
    bool isHPInsert = device.getHPInsertStatus();
    if (isHPInsert) {
        Serial.println("Headphone Inserted");
    } else {
        Serial.println("Headphone Removed");
    }
    delay(500);
}

3. Input Interface Configuration

Interface Usage
Module Audio provides two sets of 3.5 mm audio jacks (Channel 1 and Channel 2): Channel 1 is for 3.5 mm TRS microphone input only; Channel 2 supports 3.5 mm TRRS combined audio I/O, and is also compatible with TRS jacks.
  • TRS jack wiring: connect Channel 1 to MIC input and Channel 2 to audio output. Suitable for devices with separate mic and audio output (e.g., PC headsets).
  • TRRS jack wiring: connect Channel 2 for combined audio I/O. Suitable for wired headsets with built-in mics, and compatible with TRS devices.

After initialization, call the following APIs to select ADC/DAC channels and set volume/gain:

// Use input 1 for both channels
es8388.setADCInput(ADC_INPUT_LINPUT1_RINPUT1);

// Use input 2 for both channels
// es8388.setADCInput(ADC_INPUT_LINPUT2_RINPUT2);

es8388.setDACOutput(DAC_OUTPUT_OUT1);
es8388.setADCVolume(100);
es8388.setDACVolume(40);
es8388.setMicGain(MIC_GAIN_24DB);
es8388.setMixSourceSelect(MIXADC, MIXADC);
es8388.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
es8388.setSampleRate(SAMPLE_RATE_44K);

4. Recording & Playback

Using the TRS wiring method, configure Channel 1 for MIC input and Channel 2 for audio output to read MIC input data in real time and play it back.

#include "M5Unified.h"
#include "audio_i2c.hpp"
#include "es8388.hpp"
#include "driver/i2s.h"

AudioI2c device;
ES8388 es8388(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);

uint16_t rxbuf[256], txbuf[256];
size_t readsize = 0;

i2s_config_t i2s_config = {
    .mode                 = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
    .sample_rate          = 44100,
    .bits_per_sample      = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format       = I2S_CHANNEL_FMT_RIGHT_LEFT,
    .communication_format = I2S_COMM_FORMAT_STAND_I2S,
    .intr_alloc_flags     = 0,
    .dma_buf_count        = 8,
    .dma_buf_len          = 512,
    .use_apll             = false,
    .tx_desc_auto_clear   = true,
    .fixed_mclk           = 0
};

i2s_pin_config_t pin_config = {
    .mck_io_num   = SYS_I2S_MCLK_PIN,
    .bck_io_num   = SYS_I2S_SCLK_PIN,
    .ws_io_num    = SYS_I2S_LRCK_PIN,
    .data_out_num = SYS_I2S_DOUT_PIN,
    .data_in_num  = SYS_I2S_DIN_PIN,
};

void setup()
{
    M5.begin();
    Serial.begin(115200);
    device.begin(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);
    device.setHPMode(AUDIO_HPMODE_NATIONAL);
    device.setMICStatus(AUDIO_MIC_OPEN);
    device.setRGBBrightness(100);
    // Initialize ES8388
    if (!es8388.init()) Serial.println("Init Fail");
    es8388.setADCInput(ADC_INPUT_LINPUT1_RINPUT1);
    es8388.setMicGain(MIC_GAIN_24DB);
    es8388.setADCVolume(100);
    es8388.setDACVolume(40);
    es8388.setDACOutput(DAC_OUTPUT_OUT1);
    es8388.setMixSourceSelect(MIXADC, MIXADC);
    es8388.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
    es8388.setSampleRate(SAMPLE_RATE_44K);

    // Install I2S driver
    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config);
}

void loop()
{
    i2s_read(I2S_NUM_0, &rxbuf[0], 256 * 2, &readsize, portMAX_DELAY);
    for (int i = 0; i < 256; i++) {
        txbuf[i] = rxbuf[i];
    }
    i2s_write(I2S_NUM_0, &txbuf[0], 256 * 2, &readsize, portMAX_DELAY);
}

5. Playing MicroSD WAV

Configure Channel 2 for audio output, load a WAV file from the MicroSD card, and play it. Ensure the WAV file is copied to the MicroSD card and the card is inserted into the host device.

#include "M5Unified.h"
#include "audio_i2c.hpp"
#include "es8388.hpp"
#include "driver/i2s.h"
#include <SPI.h>
#include <SD.h>

AudioI2c device;
ES8388 es8388(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);

void i2s_write_task(void *arg);

i2s_config_t i2s_config = { /* same as above */ };
i2s_pin_config_t pin_config = { /* same as above */ };

void setup()
{
    M5.begin();
    Serial.begin(115200);
    device.begin(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);
    device.setHPMode(AUDIO_HPMODE_NATIONAL);
    device.setMICStatus(AUDIO_MIC_OPEN);
    device.setRGBBrightness(100);
    // Initialize ES8388
    if (!es8388.init()) Serial.println("Init Fail");
    es8388.setADCVolume(100);
    es8388.setDACVolume(80);
    es8388.setDACOutput(DAC_OUTPUT_OUT1);
    es8388.setMixSourceSelect(MIXADC, MIXADC);
    es8388.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
    es8388.setSampleRate(SAMPLE_RATE_44K);

    i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
    i2s_set_pin(I2S_NUM_0, &pin_config);

    if (SD.begin(SYS_SPI_CS_PIN)) {
        Serial.println("SD card initialized successfully");
    } else {
        Serial.println("Failed to initialize SD card. Retrying...");
    }

    xTaskCreate(i2s_write_task, "i2s_write_task", 1024 * 8, NULL, 6, NULL);
}

void loop() { }

void i2s_write_task(void *arg)
{
    File file = SD.open("/hello.wav", FILE_READ);
    if (!file) {
        Serial.println("Failed to open WAV file for reading");
        vTaskDelete(NULL);
    }

    file.seek(44); // Skip WAV header

    uint8_t buf[1024];
    size_t bytesRead, bytesWritten;

    while (true) {
        if (file.available() == 0) {
            file.seek(44);
        }
        bytesRead = file.read(buf, sizeof(buf));
        if (bytesRead > 0) {
            esp_err_t res = i2s_write(I2S_NUM_0, buf, bytesRead, &bytesWritten, portMAX_DELAY);
            if (res != ESP_OK) {
                Serial.printf("I2S write error: %d\n", res);
            }
        } else {
            break;
        }
    }
    file.close();
    vTaskDelete(NULL);
}

6. RGB LED Control

Module Audio integrates three programmable RGB LEDs on its side. Refer to the example below for control.

#include "M5Unified.h"
#include "audio_i2c.hpp"

#define SYS_I2C_SDA_PIN 21
#define SYS_I2C_SCL_PIN 22

AudioI2c device;

void setup()
{
    M5.begin();
    Serial.begin(115200);
    while (!device.begin(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN)) {
        delay(1000);
    }
    device.setRGBBrightness(100);
}

void loop()
{
    for (int i = 0; i <= 2; i++) {
        device.setRGBLED(i, 0xff0000);
    }
    delay(1000);
    for (int i = 0; i <= 2; i++) {
        device.setRGBLED(i, 0x00ff00);
    }
    delay(1000);
    for (int i = 0; i <= 2; i++) {
        device.setRGBLED(i, 0x0000ff);
    }
    delay(1000);
}
On This Page