Skip to content

Commit 3ee954a

Browse files
committed
Add M5.In_I2C init
1 parent 7f7bec0 commit 3ee954a

8 files changed

Lines changed: 172 additions & 17 deletions

File tree

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,30 @@
66

77
**Module Audio** is an audio-interaction expansion module for M5Stack, built on the ES8388 audio codec solution. It offers dual 3.5 mm jacks (one TRS jack for microphone input only, one TRRS jack for both microphone input and headphone output) to fulfill various recording and stereo playback needs. An onboard STM32G030F6P6 microcontroller handles TRRS jack insertion detection and drives WS2812C RGB LEDs. Register configuration enables automatic switching between CTIA (American) and OMTP (International) wiring standards, ensuring compatibility with most headsets featuring integrated microphones. This module is ideal for smart voice, interactive art, educational entertainment, portable recording, and other audio applications.
88

9+
## I2C bus selection
10+
11+
Module Audio supports both the M5Unified internal I2C bus and the Arduino `Wire` bus. Call `M5.begin()` before using `M5.In_I2C`.
12+
13+
```cpp
14+
M5ModuleAudio audio;
15+
16+
M5.begin();
17+
audio.begin(M5.In_I2C);
18+
```
19+
20+
Existing `Wire` code remains supported:
21+
22+
```cpp
23+
M5ModuleAudio audio;
24+
25+
M5.begin();
26+
audio.begin(Wire);
27+
```
28+
929
## Related Link
1030

1131
- [Document & Datasheet](https://docs.m5stack.com/en/module/Module-Audio)
1232

1333
## License
1434

15-
- [MIT](https://github.com/m5stack/Module-Audio/blob/main/LICENSE)
35+
- [MIT](https://github.com/m5stack/Module-Audio/blob/main/LICENSE)

examples/i2sloopback/i2sloopback.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void setup()
2525
cfg.serial_baudrate = 115200;
2626
M5.begin(cfg);
2727

28-
if (!device.begin(Wire)) {
28+
if (!device.begin(M5.In_I2C)) {
2929
while (1) {
3030
Serial.println("Module Audio not found");
3131
delay(1000);

examples/player_sd/player_sd.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void setup()
2626
cfg.serial_baudrate = 115200;
2727
M5.begin(cfg);
2828

29-
if (!device.begin(Wire)) {
29+
if (!device.begin(M5.In_I2C)) {
3030
while (1) {
3131
Serial.println("Module Audio not found");
3232
delay(1000);

examples/player_spiffs/player_spiffs.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void setup()
2121
cfg.serial_baudrate = 115200;
2222
M5.begin(cfg);
2323

24-
if (!device.begin(Wire)) {
24+
if (!device.begin(M5.In_I2C)) {
2525
while (1) {
2626
Serial.println("Module Audio not found");
2727
delay(1000);

src/M5Module_Audio.cpp

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,20 @@ uint32_t sample_rate_to_hz(es_sample_rate_t rate)
3535
} // namespace
3636

3737
#if USE_NEW_I2S_API
38-
M5ModuleAudio::M5ModuleAudio() : _wire(nullptr), _sda(0), _scl(0), _addr(I2C_ADDR), es8388(nullptr)
38+
M5ModuleAudio::M5ModuleAudio()
39+
: _wire(nullptr), _m5_i2c(nullptr), _i2c_speed(400000), _sda(0), _scl(0), _addr(I2C_ADDR), es8388(nullptr)
3940
{
4041
}
4142
#else
4243
M5ModuleAudio::M5ModuleAudio(i2s_port_t i2s_num)
43-
: _wire(nullptr), _sda(0), _scl(0), _addr(I2C_ADDR), es8388(nullptr), i2s_num(i2s_num)
44+
: _wire(nullptr),
45+
_m5_i2c(nullptr),
46+
_i2c_speed(400000),
47+
_sda(0),
48+
_scl(0),
49+
_addr(I2C_ADDR),
50+
es8388(nullptr),
51+
i2s_num(i2s_num)
4452
{
4553
}
4654
#endif
@@ -72,10 +80,29 @@ bool M5ModuleAudio::begin(TwoWire &wire, uint8_t addr)
7280
return begin(wire, sda, scl, addr, 400000, 44100, mck, di, ws, do_, bck);
7381
}
7482

83+
bool M5ModuleAudio::begin(m5::I2C_Class &i2c, uint8_t addr, uint32_t speed)
84+
{
85+
#if defined(CONFIG_IDF_TARGET_ESP32S3)
86+
uint8_t bck = M5.getPin(m5::pin_name_t::mbus_pin24); // SCLK
87+
uint8_t mck = M5.getPin(m5::pin_name_t::mbus_pin22); // MCLK
88+
#else
89+
uint8_t bck = M5.getPin(m5::pin_name_t::mbus_pin22); // SCLK
90+
uint8_t mck = M5.getPin(m5::pin_name_t::mbus_pin24); // MCLK
91+
#endif
92+
uint8_t di = M5.getPin(m5::pin_name_t::mbus_pin26);
93+
uint8_t ws = M5.getPin(m5::pin_name_t::mbus_pin21); // LRCK
94+
uint8_t do_ = M5.getPin(m5::pin_name_t::mbus_pin23);
95+
printf("I2C port: %d, SDA: %d, SCL: %d\n", i2c.getPort(), i2c.getSDA(), i2c.getSCL());
96+
printf("I2S MCK: %d, DI: %d, WS: %d, DO: %d, BCK: %d\n", mck, di, ws, do_, bck);
97+
return begin(i2c, addr, speed, 44100, mck, di, ws, do_, bck);
98+
}
99+
75100
bool M5ModuleAudio::begin(TwoWire &wire, uint8_t sda, uint8_t scl, uint8_t addr, uint32_t speed)
76101
{
77102
_i2s_initialized = false;
78103
_wire = &wire;
104+
_m5_i2c = nullptr;
105+
_i2c_speed = speed;
79106
_sda = sda;
80107
_scl = scl;
81108
_addr = addr;
@@ -101,10 +128,12 @@ bool M5ModuleAudio::begin(TwoWire &wire, uint8_t sda, uint8_t scl, uint8_t addr,
101128
bool M5ModuleAudio::begin(TwoWire &wire, uint8_t sda, uint8_t scl, uint8_t addr, uint32_t speed, int sample_rate,
102129
int i2s_mck, int i2s_di, int i2s_ws, int i2s_do, int i2s_bck)
103130
{
104-
_wire = &wire;
105-
_sda = sda;
106-
_scl = scl;
107-
_addr = addr;
131+
_wire = &wire;
132+
_m5_i2c = nullptr;
133+
_i2c_speed = speed;
134+
_sda = sda;
135+
_scl = scl;
136+
_addr = addr;
108137

109138
// Store IO pins
110139
_i2s_mck = i2s_mck;
@@ -141,6 +170,40 @@ bool M5ModuleAudio::begin(TwoWire &wire, uint8_t sda, uint8_t scl, uint8_t addr,
141170
return true;
142171
}
143172

173+
bool M5ModuleAudio::begin(m5::I2C_Class &i2c, uint8_t addr, uint32_t speed, int sample_rate, int i2s_mck, int i2s_di,
174+
int i2s_ws, int i2s_do, int i2s_bck)
175+
{
176+
_wire = nullptr;
177+
_m5_i2c = &i2c;
178+
_i2c_speed = speed;
179+
_sda = i2c.getSDA();
180+
_scl = i2c.getSCL();
181+
_addr = addr;
182+
183+
_i2s_mck = i2s_mck;
184+
_i2s_bck = i2s_bck;
185+
_i2s_ws = i2s_ws;
186+
_i2s_do = i2s_do;
187+
_i2s_di = i2s_di;
188+
189+
if (!i2c.isEnabled() || !i2c.scanID(addr, speed)) {
190+
ESP_LOGI(TAG, "Module Audio controller not found on M5Unified I2C bus");
191+
return false;
192+
}
193+
194+
if (!i2s_driver_init(sample_rate)) {
195+
ESP_LOGI(TAG, "I2S driver initialization failed");
196+
return false;
197+
}
198+
199+
if (!es8388_codec_init()) {
200+
ESP_LOGI(TAG, "ES8388 codec initialization failed");
201+
return false;
202+
}
203+
204+
return setMicGain(MIC_GAIN_0DB);
205+
}
206+
144207
void M5ModuleAudio::setMICStatus(audio_mic_t status)
145208
{
146209
uint8_t reg = MICROPHONE_STATUS;
@@ -249,7 +312,11 @@ bool M5ModuleAudio::es8388_codec_init()
249312
es8388 = nullptr;
250313
}
251314

252-
es8388 = new ES8388(_wire, _sda, _scl);
315+
if (_m5_i2c != nullptr) {
316+
es8388 = new ES8388(_m5_i2c, _i2c_speed);
317+
} else {
318+
es8388 = new ES8388(_wire, _sda, _scl, _i2c_speed);
319+
}
253320
if (!es8388->init()) {
254321
ESP_LOGI(TAG, "Failed to initialize ES8388 codec");
255322
return false;
@@ -675,6 +742,15 @@ bool M5ModuleAudio::play(const uint8_t *buffer, int size)
675742

676743
void M5ModuleAudio::writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length)
677744
{
745+
if (_m5_i2c != nullptr) {
746+
_m5_i2c->writeRegister(addr, reg, buffer, length, _i2c_speed);
747+
return;
748+
}
749+
750+
if (_wire == nullptr) {
751+
return;
752+
}
753+
678754
_wire->beginTransmission(addr);
679755
_wire->write(reg);
680756
for (int i = 0; i < length; i++) {
@@ -700,6 +776,18 @@ void M5ModuleAudio::writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8
700776

701777
void M5ModuleAudio::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length)
702778
{
779+
if (_m5_i2c != nullptr) {
780+
if (!_m5_i2c->readRegister(addr, reg, buffer, length, _i2c_speed)) {
781+
memset(buffer, 0, length);
782+
}
783+
return;
784+
}
785+
786+
if (_wire == nullptr) {
787+
memset(buffer, 0, length);
788+
return;
789+
}
790+
703791
uint8_t index = 0;
704792
_wire->beginTransmission(addr);
705793
_wire->write(reg);

src/M5Module_Audio.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ class M5ModuleAudio {
102102

103103
bool begin(TwoWire& wire, uint8_t addr = I2C_ADDR);
104104

105+
/**
106+
* @brief Initializes Module Audio using an M5Unified I2C bus and automatic board pin mapping.
107+
* @param i2c M5Unified I2C bus (for example, M5.In_I2C).
108+
* @param addr Module Audio controller I2C address.
109+
* @param speed I2C clock speed in Hz.
110+
* @return bool True if I2C, I2S, and ES8388 initialization succeeded.
111+
*/
112+
bool begin(m5::I2C_Class& i2c, uint8_t addr = I2C_ADDR, uint32_t speed = 400000);
113+
114+
/**
115+
* @brief Initializes Module Audio using an M5Unified I2C bus and explicit I2S pins.
116+
*/
117+
bool begin(m5::I2C_Class& i2c, uint8_t addr, uint32_t speed, int sample_rate, int i2s_mck, int i2s_di, int i2s_ws,
118+
int i2s_do, int i2s_bck);
119+
105120
/**
106121
* @brief Set microphone/LINE input status
107122
* @param status Audio input state (AUDIO_MIC_CLOSE/AUDIO_MIC_OPEN)
@@ -352,6 +367,8 @@ class M5ModuleAudio {
352367

353368
private:
354369
TwoWire* _wire;
370+
m5::I2C_Class* _m5_i2c;
371+
uint32_t _i2c_speed;
355372
uint8_t _sda, _scl;
356373
uint8_t _addr;
357374

src/es8388.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,28 @@
55
*/
66

77
#include "es8388.hpp"
8+
#include <M5Unified.h>
89

910
ES8388::ES8388(TwoWire* wire, uint8_t sda, uint8_t scl, uint32_t speed)
11+
: _wire(wire), _m5_i2c(nullptr), _scl(scl), _sda(sda), _speed(speed)
1012
{
11-
_wire = wire;
12-
_sda = sda;
13-
_scl = scl;
14-
_speed = speed;
1513
_wire->begin(_sda, _scl, _speed);
1614
}
1715

16+
ES8388::ES8388(m5::I2C_Class* i2c, uint32_t speed) : _wire(nullptr), _m5_i2c(i2c), _scl(-1), _sda(-1), _speed(speed)
17+
{
18+
}
19+
1820
bool ES8388::writeBytes(uint8_t reg, uint8_t data)
1921
{
22+
if (_m5_i2c != nullptr) {
23+
return _m5_i2c->writeRegister8(ES8388_ADDR, reg, data, _speed);
24+
}
25+
26+
if (_wire == nullptr) {
27+
return false;
28+
}
29+
2030
_wire->beginTransmission(ES8388_ADDR);
2131
_wire->write(reg);
2232
_wire->write(data);
@@ -35,6 +45,14 @@ bool ES8388::writeBytes(uint8_t reg, uint8_t data)
3545

3646
bool ES8388::readBytes(uint8_t reg, uint8_t& data)
3747
{
48+
if (_m5_i2c != nullptr) {
49+
return _m5_i2c->readRegister(ES8388_ADDR, reg, &data, 1, _speed);
50+
}
51+
52+
if (_wire == nullptr) {
53+
return false;
54+
}
55+
3856
bool ret = false;
3957
_wire->beginTransmission(ES8388_ADDR);
4058
_wire->write(reg);
@@ -312,4 +330,4 @@ bool ES8388::setSampleRate(es_sample_rate_t rate)
312330
res &= writeBytes(ES8388_ADCCONTROL5, adcFsRatio & 0x1F);
313331
res &= writeBytes(ES8388_DACCONTROL2, dacFsRatio & 0x1F);
314332
return res;
315-
}
333+
}

src/es8388.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include <Arduino.h>
1111
#include <Wire.h>
1212

13+
namespace m5 {
14+
class I2C_Class;
15+
}
16+
1317
// #define ES8388_DEBUG Serial // This macro definition can be annotated without sending and receiving data prints
1418
// Define the serial port you want to use, e.g., Serial1 or Serial2
1519
#if defined ES8388_DEBUG
@@ -392,6 +396,13 @@ class ES8388 {
392396
*/
393397
ES8388(TwoWire* wire, uint8_t sda = -1, uint8_t scl = -1, uint32_t speed = 400000L);
394398

399+
/**
400+
* @brief Constructs ES8388 codec controller using an M5Unified I2C bus
401+
* @param i2c M5Unified I2C bus pointer (for example, &M5.In_I2C)
402+
* @param speed I2C clock speed in Hz (default 400kHz)
403+
*/
404+
ES8388(m5::I2C_Class* i2c, uint32_t speed = 400000L);
405+
395406
/**
396407
* @brief Reads all codec registers into a buffer
397408
* @return Pointer to 53-byte array containing register values (0x00-0x34)
@@ -487,6 +498,7 @@ class ES8388 {
487498

488499
private:
489500
TwoWire* _wire;
501+
m5::I2C_Class* _m5_i2c;
490502
uint8_t _scl;
491503
uint8_t _sda;
492504
uint32_t _speed;
@@ -510,4 +522,4 @@ class ES8388 {
510522
bool readBytes(uint8_t reg, uint8_t& data);
511523
};
512524

513-
#endif
525+
#endif

0 commit comments

Comments
 (0)