Skip to content

Commit a6842cc

Browse files
committed
Module-Audio
1 parent d91938a commit a6842cc

16 files changed

+2619
-38
lines changed

README.md

+5-38
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,15 @@
1-
# Product Name
1+
# Module-Audio
22

33
## Overview
44

5-
### SKU:xxx
5+
### SKU:M144
66

7-
Description of the product
7+
**Module Audio** is an M5Stack expansion module designed for audio interaction, based on the ES8388 audio codec solution, supporting dual ADC inputs and dual DAC outputs; and is equipped with an STM32G030F6P6 microcontroller to enable GPIO software control for the microphone, detect headphone insertion/removal on the TRRS jack, and drive WS2812C RGB lighting effects. It uses an FSUSB42MUX dual SPDT analog switch to automatically switch between CTIA (American standard) and OMTP (Chinese standard) wiring standards, making it compatible with mainstream headsets with microphones. The module is plug-and-play via the M5-BUS interface and seamlessly stacks with the M5Stack Core host. It is equipped with a 3.5 mm jack dedicated solely to microphone input, as well as a TRRS combo jack that supports both headphone playback and microphone input. This product is suitable for intelligent voice applications, interactive art, educational entertainment, portable recording, and various other audio use cases.
88

99
## Related Link
1010

11-
- [Document & Datasheet](https://docs.m5stack.com/en/unit/product_Link)
12-
13-
## Required Libraries:
14-
15-
- [Adafruit_BMP280_Library](https://github.com/adafruit/Required_Libraries_Link)
16-
17-
## License
18-
19-
- [Product Name- MIT](LICENSE)
20-
21-
## Remaining steps(Editorial Staff Look,After following the steps, remember to delete all the content below)
22-
23-
1. Change [clang format check path](./.github/workflows/clang-format-check.yml#L9-L15).
24-
2. Add License content to [LICENSE](/LICENSE).
25-
3. Change link on line 78 of [bug-report.yml](./.github/ISSUE_TEMPLATE/bug-report.yml#L78).
26-
27-
```cpp
28-
Example
29-
# M5Unit-ENV
30-
31-
## Overview
32-
33-
### SKU:U001 & U001-B & U001-C
34-
35-
Contains M5Stack-**UNIT ENV** series related case programs.ENV is an environmental sensor with integrated SHT30 and QMP6988 internally to detect temperature, humidity, and atmospheric pressure data.
36-
37-
## Related Link
38-
39-
- [Document & Datasheet](https://docs.m5stack.com/en/unit/envIII)
40-
41-
## Required Libraries:
42-
43-
- [Adafruit_BMP280_Library](https://github.com/adafruit/Adafruit_BMP280_Library)
11+
- [Document & Datasheet](https://docs.m5stack.com/en/module/Module-Audio)
4412

4513
## License
4614

47-
- [M5Unit-ENV - MIT](LICENSE)
48-
```
15+
- [MIT](https://github.com/m5stack/Module-Audio/blob/main/LICENSE)

examples/M5core/i2sloopback.ino

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* @Hardwares: M5Core Basic v2.7+ Module Audio
7+
* @Dependent Library:
8+
* M5Unified@^0.2.5: https://github.com/m5stack/M5Unified
9+
* Module Audio:
10+
*/
11+
12+
#include "M5Unified.h"
13+
#include "audio_i2c.hpp"
14+
#include "es8388.hpp"
15+
#include "driver/i2s.h"
16+
AudioI2c device;
17+
18+
#define SYS_I2C_SDA_PIN 21
19+
#define SYS_I2C_SCL_PIN 22
20+
#define SYS_I2S_MCLK_PIN 0
21+
#define SYS_I2S_SCLK_PIN 13
22+
#define SYS_I2S_LRCK_PIN 12
23+
#define SYS_I2S_DOUT_PIN 15
24+
#define SYS_I2S_DIN_PIN 34
25+
#define SYS_SPI_MISO_PIN 19
26+
#define SYS_SPI_MOSI_PIN 23
27+
#define SYS_SPI_CLK_PIN 18
28+
#define SYS_SPI_CS_PIN 4
29+
30+
ES8388 es8388(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);
31+
32+
uint16_t rxbuf[256], txbuf[256];
33+
size_t readsize = 0;
34+
byte error, address;
35+
const uint32_t color[] = {0xFF0000, 0xFF0000, 0xFF0000, 0x00FF00, 0xFFFF00, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF};
36+
i2s_config_t i2s_config = {.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
37+
.sample_rate = 44100,
38+
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
39+
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
40+
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
41+
.intr_alloc_flags = 0,
42+
.dma_buf_count = 8,
43+
.dma_buf_len = 512,
44+
.use_apll = false,
45+
.tx_desc_auto_clear = true,
46+
.fixed_mclk = 0};
47+
48+
i2s_pin_config_t pin_config = {
49+
.mck_io_num = SYS_I2S_MCLK_PIN,
50+
.bck_io_num = SYS_I2S_SCLK_PIN,
51+
.ws_io_num = SYS_I2S_LRCK_PIN,
52+
.data_out_num = SYS_I2S_DOUT_PIN,
53+
.data_in_num = SYS_I2S_DIN_PIN,
54+
};
55+
56+
void setup()
57+
{
58+
M5.begin();
59+
Serial.begin(115200);
60+
for (int address = 1; address < 127; address++) {
61+
Wire.beginTransmission(address);
62+
error = Wire.endTransmission();
63+
if (error == 0) {
64+
Serial.print("Found I2C device at address 0x");
65+
Serial.print(address, HEX);
66+
Serial.print(" \n");
67+
} else if (error == 4) {
68+
Serial.print("Unknown error at address 0x");
69+
Serial.println(address, HEX);
70+
}
71+
}
72+
device.begin(&Wire, SYS_I2C_SCL_PIN, SYS_I2C_SCL_PIN);
73+
device.setHPMode(AUDIO_HPMODE_NATIONAL);
74+
device.setMICStatus(AUDIO_MIC_OPEN);
75+
device.setRGBBrightness(100);
76+
Serial.printf("getHPMode:%d\n", device.getHPMode());
77+
Serial.printf("getMICStatus:%d\n", device.getMICStatus());
78+
for (int i = 0; i <= 2; i++) {
79+
device.setRGBLED(i, color[i + 3]);
80+
// Output the hexadecimal value of the current color
81+
Serial.printf("Set RGB to %06X\n", (unsigned int)color[i + 3]);
82+
Serial.printf("get RGB to %06X\n", device.getRGBLED(i));
83+
}
84+
Serial.println("Read Reg ES8388 : ");
85+
if (!es8388.init()) Serial.println("Init Fail");
86+
es8388.setADCInput(ADC_INPUT_LINPUT1_RINPUT1);
87+
es8388.setMicGain(MIC_GAIN_24DB);
88+
es8388.setADCVolume(100);
89+
// The volume output should not exceed 40, otherwise there will be noise or current sounds
90+
es8388.setDACVolume(40);
91+
es8388.setDACOutput(DAC_OUTPUT_OUT1);
92+
es8388.setMixSourceSelect(MIXADC, MIXADC);
93+
es8388.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
94+
es8388.setSampleRate(SAMPLE_RATE_44K);
95+
uint8_t *reg;
96+
for (uint8_t i = 0; i < 53; i++) {
97+
reg = es8388.readAllReg();
98+
Serial.printf("Reg-%02d = 0x%02x\r\n", i, reg[i]);
99+
}
100+
// i2s
101+
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
102+
WRITE_PERI_REG(PIN_CTRL, 0xFFF0);
103+
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
104+
i2s_set_pin(I2S_NUM_0, &pin_config);
105+
}
106+
107+
void loop()
108+
{
109+
i2s_read(I2S_NUM_0, &rxbuf[0], 256 * 2, &readsize, 1000);
110+
for (int i = 0; i < 256; i++) {
111+
// direct transfer too txbuff
112+
txbuf[i] = rxbuf[i];
113+
// txbuf[i] = 0; //mute
114+
}
115+
// play received buffer
116+
i2s_write(I2S_NUM_0, &txbuf[0], 256 * 2, &readsize, 1000);
117+
}

examples/M5core/player_sd.ino

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* @Hardwares: M5Core Basic v2.7+ Module Audio
7+
* @Dependent Library:
8+
* M5Unified@^0.2.5: https://github.com/m5stack/M5Unified
9+
* Module Audio:
10+
*/
11+
12+
#include "M5Unified.h"
13+
#include "audio_i2c.hpp"
14+
#include "es8388.hpp"
15+
#include "driver/i2s.h"
16+
#include <SPI.h>
17+
#include <SD.h>
18+
AudioI2c device;
19+
20+
#define SYS_I2C_SDA_PIN 21
21+
#define SYS_I2C_SCL_PIN 22
22+
#define SYS_I2S_MCLK_PIN 0
23+
#define SYS_I2S_SCLK_PIN 13
24+
#define SYS_I2S_LRCK_PIN 12
25+
#define SYS_I2S_DOUT_PIN 15
26+
#define SYS_I2S_DIN_PIN 34
27+
#define SYS_SPI_MISO_PIN 19
28+
#define SYS_SPI_MOSI_PIN 23
29+
#define SYS_SPI_CLK_PIN 18
30+
#define SYS_SPI_CS_PIN 4
31+
32+
ES8388 es8388(&Wire, SYS_I2C_SDA_PIN, SYS_I2C_SCL_PIN);
33+
void i2s_write_task(void *arg);
34+
uint16_t rxbuf[256], txbuf[256];
35+
size_t readsize = 0;
36+
byte error, address;
37+
const uint32_t color[] = {0xFF0000, 0xFF0000, 0xFF0000, 0x00FF00, 0xFFFF00, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF};
38+
i2s_config_t i2s_config = {.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX),
39+
.sample_rate = 44100,
40+
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
41+
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
42+
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
43+
.intr_alloc_flags = 0,
44+
.dma_buf_count = 8,
45+
.dma_buf_len = 512,
46+
.use_apll = false,
47+
.tx_desc_auto_clear = true,
48+
.fixed_mclk = 0};
49+
50+
i2s_pin_config_t pin_config = {
51+
.mck_io_num = SYS_I2S_MCLK_PIN,
52+
.bck_io_num = SYS_I2S_SCLK_PIN,
53+
.ws_io_num = SYS_I2S_LRCK_PIN,
54+
.data_out_num = SYS_I2S_DOUT_PIN,
55+
.data_in_num = SYS_I2S_DIN_PIN,
56+
};
57+
58+
void setup()
59+
{
60+
M5.begin();
61+
Serial.begin(115200);
62+
for (int address = 1; address < 127; address++) {
63+
Wire.beginTransmission(address);
64+
error = Wire.endTransmission();
65+
if (error == 0) {
66+
Serial.print("Found I2C device at address 0x");
67+
Serial.print(address, HEX);
68+
Serial.print(" \n");
69+
} else if (error == 4) {
70+
Serial.print("Unknown error at address 0x");
71+
Serial.println(address, HEX);
72+
}
73+
}
74+
device.begin(&Wire, SYS_I2C_SCL_PIN, SYS_I2C_SCL_PIN);
75+
device.setHPMode(AUDIO_HPMODE_NATIONAL);
76+
device.setMICStatus(AUDIO_MIC_OPEN);
77+
device.setRGBBrightness(100);
78+
Serial.printf("getHPMode:%d\n", device.getHPMode());
79+
Serial.printf("getMICStatus:%d\n", device.getMICStatus());
80+
for (int i = 0; i <= 2; i++) {
81+
device.setRGBLED(i, color[i + 3]);
82+
// Output the hexadecimal value of the current color
83+
Serial.printf("Set RGB to %06X\n", (unsigned int)color[i + 3]);
84+
Serial.printf("get RGB to %06X\n", device.getRGBLED(i));
85+
}
86+
Serial.println("Read Reg ES8388 : ");
87+
if (!es8388.init()) Serial.println("Init Fail");
88+
es8388.setADCVolume(100);
89+
es8388.setDACVolume(80);
90+
es8388.setDACOutput(DAC_OUTPUT_OUT1);
91+
es8388.setMixSourceSelect(MIXADC, MIXADC);
92+
es8388.setBitsSample(ES_MODULE_ADC, BIT_LENGTH_16BITS);
93+
es8388.setSampleRate(SAMPLE_RATE_44K);
94+
uint8_t *reg;
95+
for (uint8_t i = 0; i < 53; i++) {
96+
reg = es8388.readAllReg();
97+
Serial.printf("Reg-%02d = 0x%02x\r\n", i, reg[i]);
98+
}
99+
// i2s
100+
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
101+
WRITE_PERI_REG(PIN_CTRL, 0xFFF0);
102+
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
103+
i2s_set_pin(I2S_NUM_0, &pin_config);
104+
if (SD.begin(SYS_SPI_CS_PIN)) {
105+
Serial.println("SD card initialized successfully");
106+
107+
} else {
108+
Serial.println("Failed to initialize SD card. Retrying...");
109+
}
110+
xTaskCreate(i2s_write_task, "i2s_write_task", 1024 * 8, NULL, 6, NULL);
111+
}
112+
113+
void loop()
114+
{
115+
}
116+
117+
void i2s_write_task(void *arg)
118+
{
119+
// Open the WAV file
120+
// Replace with the path of your WAV file
121+
File file = SD.open("/hello.wav", "r");
122+
if (!file) {
123+
Serial.println("Failed to open WAV file for reading");
124+
vTaskDelete(NULL);
125+
}
126+
127+
// Obtain the file size and print
128+
size_t fileSize = file.size();
129+
Serial.printf("File size: %d bytes\n", fileSize);
130+
131+
// Skip the WAV file header (44 bytes)
132+
file.seek(44);
133+
134+
uint8_t txbuf[1024];
135+
136+
while (1) {
137+
// Check whether the end of the file has been reached
138+
if (file.available() == 0) {
139+
// Go back to the beginning of the file in order to replay it
140+
file.seek(44);
141+
}
142+
143+
// Read data
144+
size_t bytesRead = file.read(txbuf, sizeof(txbuf));
145+
146+
// If data is read
147+
if (bytesRead > 0) {
148+
size_t bytesWritten = 0;
149+
esp_err_t result = i2s_write(I2S_NUM_0, txbuf, bytesRead, &bytesWritten, portMAX_DELAY);
150+
// Check the writing result
151+
if (result != ESP_OK) {
152+
Serial.printf("I2S write error: %d\n", result);
153+
}
154+
} else {
155+
// If there is no more data, exit the loop
156+
break;
157+
}
158+
}
159+
160+
// Close the file
161+
file.close();
162+
vTaskDelete(NULL);
163+
}

0 commit comments

Comments
 (0)