Skip to content

Commit e542bc9

Browse files
committed
Add test support and disable analog audio bypass
1 parent 3ee954a commit e542bc9

5 files changed

Lines changed: 242 additions & 34 deletions

File tree

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,45 @@ M5.begin();
2626
audio.begin(Wire);
2727
```
2828

29+
## Microphone routing
30+
31+
The LINE/MIC jack and the headset microphone share the ES8388 `LIN1` input. Keep the two STM32-controlled paths
32+
mutually exclusive.
33+
34+
Use the LINE/MIC jack:
35+
36+
```cpp
37+
audio.setHPMICStatus(AUDIO_MIC_CLOSE);
38+
audio.setMICStatus(AUDIO_MIC_OPEN);
39+
audio.setMicInputLine(ADC_INPUT_LINPUT1_RINPUT1);
40+
```
41+
42+
Use the microphone in a connected headset:
43+
44+
```cpp
45+
if (audio.getHPInsertStatus()) {
46+
audio.setMICStatus(AUDIO_MIC_CLOSE);
47+
audio.setHPMICStatus(AUDIO_MIC_OPEN);
48+
audio.setMicInputLine(ADC_INPUT_LINPUT1_RINPUT1);
49+
}
50+
```
51+
52+
Register `0x11` is reset to `AUDIO_MIC_CLOSE` at power-up. Headset insertion or removal does not change it.
53+
54+
## Device UID
55+
56+
Firmware `0xF1` exposes the STM32 96-bit UID in registers `0xE0` through `0xEB`:
57+
58+
```cpp
59+
uint8_t uid[DEVICE_UID_LENGTH];
60+
if (audio.getDeviceUID(uid)) {
61+
for (uint8_t value : uid) {
62+
Serial.printf("%02X", value);
63+
}
64+
Serial.println();
65+
}
66+
```
67+
2968
## Related Link
3069

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

src/M5Module_Audio.cpp

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ void M5ModuleAudio::setHPMode(audio_hpmode_t mode)
216216
writeBytes(_addr, reg, (uint8_t *)&mode, 1);
217217
}
218218

219+
void M5ModuleAudio::setHPMICStatus(audio_mic_t status)
220+
{
221+
uint8_t reg = HEADPHONE_MIC_STATUS;
222+
writeBytes(_addr, reg, (uint8_t *)&status, 1);
223+
}
224+
219225
void M5ModuleAudio::setRGBBrightness(uint8_t brightness)
220226
{
221227
if (brightness > 100) brightness = 100;
@@ -226,14 +232,35 @@ void M5ModuleAudio::setRGBBrightness(uint8_t brightness)
226232
void M5ModuleAudio::setRGBLED(uint8_t num, uint32_t color)
227233
{
228234
if (num > 2) num = 2;
229-
color = ((color & 0xFF) << 16) | (color & 0xFF00) | ((color >> 16) & 0xFF);
230-
uint8_t reg = RGB_LED + num * 3;
231-
writeBytes(_addr, reg, (uint8_t *)&color, 3);
235+
uint8_t rgb[3] = {
236+
static_cast<uint8_t>((color >> 16) & 0xFF),
237+
static_cast<uint8_t>((color >> 8) & 0xFF),
238+
static_cast<uint8_t>(color & 0xFF),
239+
};
240+
uint8_t reg = RGB_LED + num * sizeof(rgb);
241+
writeBytes(_addr, reg, rgb, sizeof(rgb));
242+
}
243+
244+
void M5ModuleAudio::setAllRGBLED(uint32_t color)
245+
{
246+
const uint8_t red = static_cast<uint8_t>((color >> 16) & 0xFF);
247+
const uint8_t green = static_cast<uint8_t>((color >> 8) & 0xFF);
248+
const uint8_t blue = static_cast<uint8_t>(color & 0xFF);
249+
uint8_t rgb[9];
250+
for (size_t index = 0; index < sizeof(rgb); index += 3) {
251+
rgb[index] = red;
252+
rgb[index + 1] = green;
253+
rgb[index + 2] = blue;
254+
}
255+
writeBytes(_addr, RGB_LED, rgb, sizeof(rgb));
232256
}
233257

234258
uint8_t M5ModuleAudio::setI2CAddress(uint8_t newAddr)
235259
{
236-
newAddr = constrain(newAddr, I2C_ADDR_MIN, I2C_ADDR_MAX);
260+
if (newAddr < I2C_ADDR_MIN || newAddr > I2C_ADDR_MAX || newAddr == ES8388_ADDR) {
261+
return _addr;
262+
}
263+
237264
uint8_t reg = I2C_ADDRESS;
238265
writeBytes(_addr, reg, (uint8_t *)&newAddr, 1);
239266
_addr = newAddr;
@@ -265,6 +292,14 @@ audio_hpmode_t M5ModuleAudio::getHPMode()
265292
return (audio_hpmode_t)data;
266293
}
267294

295+
audio_mic_t M5ModuleAudio::getHPMICStatus()
296+
{
297+
uint8_t data;
298+
uint8_t reg = HEADPHONE_MIC_STATUS;
299+
readBytes(_addr, reg, (uint8_t *)&data, 1);
300+
return (audio_mic_t)data;
301+
}
302+
268303
uint8_t M5ModuleAudio::getHPInsertStatus()
269304
{
270305
uint8_t data;
@@ -289,6 +324,26 @@ uint32_t M5ModuleAudio::getRGBLED(uint8_t num)
289324
return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
290325
}
291326

327+
bool M5ModuleAudio::getRGBLEDs(uint32_t colors[3])
328+
{
329+
if (colors == nullptr) {
330+
return false;
331+
}
332+
333+
uint8_t rgb[9] = {};
334+
if (!readBytes(_addr, RGB_LED, rgb, sizeof(rgb))) {
335+
colors[0] = colors[1] = colors[2] = 0;
336+
return false;
337+
}
338+
339+
for (size_t index = 0; index < 3; ++index) {
340+
const size_t offset = index * 3;
341+
colors[index] = (static_cast<uint32_t>(rgb[offset]) << 16) | (static_cast<uint32_t>(rgb[offset + 1]) << 8) |
342+
static_cast<uint32_t>(rgb[offset + 2]);
343+
}
344+
return true;
345+
}
346+
292347
uint8_t M5ModuleAudio::getFirmwareVersion()
293348
{
294349
uint8_t version;
@@ -305,6 +360,14 @@ uint8_t M5ModuleAudio::getI2CAddress()
305360
return I2CAddress;
306361
}
307362

363+
bool M5ModuleAudio::getDeviceUID(uint8_t uid[DEVICE_UID_LENGTH])
364+
{
365+
if (uid == nullptr) {
366+
return false;
367+
}
368+
return readBytes(_addr, DEVICE_UID, uid, DEVICE_UID_LENGTH);
369+
}
370+
308371
bool M5ModuleAudio::es8388_codec_init()
309372
{
310373
if (es8388 != nullptr) {
@@ -511,6 +574,20 @@ bool M5ModuleAudio::setMixSourceSelect(es_mixsel_t lmixsel, es_mixsel_t rmixsel)
511574
return true;
512575
}
513576

577+
bool M5ModuleAudio::setLineBypass(bool enabled)
578+
{
579+
if (es8388 == nullptr) {
580+
ESP_LOGI(TAG, "ES8388 codec is not initialized");
581+
return false;
582+
}
583+
584+
if (!es8388->setLineBypass(enabled)) {
585+
ESP_LOGI(TAG, "Failed to configure ES8388 line bypass");
586+
return false;
587+
}
588+
return true;
589+
}
590+
514591
bool M5ModuleAudio::setBitsSample(es_module_t mode, es_bits_length_t bits_len)
515592
{
516593
if (es8388 == nullptr) {
@@ -590,7 +667,7 @@ int M5ModuleAudio::getBufferSize(int duration, int sample_rate)
590667
#if USE_NEW_I2S_API
591668
sample_rate = I2S.txSampleRate();
592669
#else
593-
sample_rate = i2s_cfg.sample_rate;
670+
sample_rate = i2s_cfg.sample_rate;
594671
#endif
595672
}
596673
return duration * sample_rate * 2 * 2; // sample_rate * bytes_per_sample * channels
@@ -602,7 +679,7 @@ int M5ModuleAudio::getDuration(int size, int sample_rate)
602679
#if USE_NEW_I2S_API
603680
sample_rate = I2S.txSampleRate();
604681
#else
605-
sample_rate = i2s_cfg.sample_rate;
682+
sample_rate = i2s_cfg.sample_rate;
606683
#endif
607684
}
608685
return size / (sample_rate * 2 * 2); // sample_rate * bytes_per_sample * channels
@@ -638,7 +715,7 @@ bool M5ModuleAudio::record(FS &fs, const char *filename, int size)
638715
return false;
639716
}
640717
#else
641-
esp_err_t err = i2s_read(i2s_num, buffer, bytes_to_read, &bytes_read, portMAX_DELAY);
718+
esp_err_t err = i2s_read(i2s_num, buffer, bytes_to_read, &bytes_read, portMAX_DELAY);
642719
if (err != ESP_OK || bytes_read != bytes_to_read) {
643720
ESP_LOGI(TAG, "Recording failed during I2S read");
644721
file.close();
@@ -726,13 +803,13 @@ bool M5ModuleAudio::play(const uint8_t *buffer, int size)
726803
size_t bytes_written = 0;
727804
#if USE_NEW_I2S_API
728805
bytes_written = I2S.write(buffer, size);
729-
if (bytes_written < 0) {
806+
if (bytes_written != static_cast<size_t>(size)) {
730807
ESP_LOGI(TAG, "Playback failed");
731808
return false;
732809
}
733810
#else
734811
esp_err_t err = i2s_write(i2s_num, buffer, size, &bytes_written, portMAX_DELAY);
735-
if (err != ESP_OK) {
812+
if (err != ESP_OK || bytes_written != static_cast<size_t>(size)) {
736813
ESP_LOGI(TAG, "Playback failed");
737814
return false;
738815
}
@@ -774,25 +851,32 @@ void M5ModuleAudio::writeBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8
774851
#endif
775852
}
776853

777-
void M5ModuleAudio::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length)
854+
bool M5ModuleAudio::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_t length)
778855
{
856+
if (buffer == nullptr || length == 0) {
857+
return false;
858+
}
859+
779860
if (_m5_i2c != nullptr) {
780861
if (!_m5_i2c->readRegister(addr, reg, buffer, length, _i2c_speed)) {
781862
memset(buffer, 0, length);
863+
return false;
782864
}
783-
return;
865+
return true;
784866
}
785867

786868
if (_wire == nullptr) {
787869
memset(buffer, 0, length);
788-
return;
870+
return false;
789871
}
790872

791873
uint8_t index = 0;
792874
_wire->beginTransmission(addr);
793875
_wire->write(reg);
794-
_wire->endTransmission(false);
795-
_wire->requestFrom(addr, length);
876+
if (_wire->endTransmission(false) != 0 || _wire->requestFrom(addr, length) != length) {
877+
memset(buffer, 0, length);
878+
return false;
879+
}
796880
for (int i = 0; i < length; i++) {
797881
buffer[index++] = _wire->read();
798882
}
@@ -811,4 +895,5 @@ void M5ModuleAudio::readBytes(uint8_t addr, uint8_t reg, uint8_t *buffer, uint8_
811895
Serial.println("]");
812896
#else
813897
#endif
898+
return true;
814899
}

0 commit comments

Comments
 (0)