pdf-icon

Arduino Quick Start

2. Devices & Examples

5. Extensions

6. Applications

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 input mode configuration, 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.
cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
#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:

cpp
1 2 3 4 5 6 7 8 9 10 11 12
// 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.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.

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#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.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.

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#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.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.

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
#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