Audio System + Drivers (#562)

This commit is contained in:
Shadowtrance
2026-07-14 16:34:29 +10:00
committed by GitHub
parent fa4a6e255c
commit 955416dac8
137 changed files with 8847 additions and 387 deletions
+1 -1
View File
@@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_ili9881c esp_lcd_st7123 esp_lcd_touch_st7123 GT911 PwmBacklight driver esp_driver_i2c vfs fatfs ina226-module sc2356-module
REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_ili9881c esp_lcd_st7123 esp_lcd_touch_st7123 GT911 PwmBacklight driver esp_driver_i2c vfs fatfs ina226-module
)
+8 -109
View File
@@ -140,57 +140,14 @@ static void initExpander1(::Device* io_expander1) {
gpio_descriptor_release(ip2326_charge_enable_pin);
}
static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = nullptr) {
// Init data from M5Unified:
// https://github.com/m5stack/M5Unified/blob/master/src/M5Unified.cpp
static constexpr uint8_t ES8388_I2C_ADDR = 0x10;
static constexpr uint8_t ENABLED_BULK_DATA[] = {
0, 0x80, // RESET/ CSM POWER ON
0, 0x00,
0, 0x00,
0, 0x0E,
1, 0x00,
2, 0x0A, // CHIP POWER: power up all
3, 0xFF, // ADC POWER: power down all
4, 0x3C, // DAC POWER: power up and LOUT1/ROUT1/LOUT2/ROUT2 enable
5, 0x00, // ChipLowPower1
6, 0x00, // ChipLowPower2
7, 0x7C, // VSEL
8, 0x00, // set I2S slave mode
// reg9-22 == adc
23, 0x18, // I2S format (16bit)
24, 0x00, // I2S MCLK ratio (128)
25, 0x20, // DAC unmute
26, 0x00, // LDACVOL 0x00~0xC0
27, 0x00, // RDACVOL 0x00~0xC0
28, 0x08, // enable digital click free power up and down
29, 0x00,
38, 0x00, // DAC CTRL16
39, 0xB8, // LEFT Ch MIX
42, 0xB8, // RIGHTCh MIX
43, 0x08, // ADC and DAC separate
45, 0x00, // 0x00=1.5k VREF analog output / 0x10=40kVREF analog output
46, 0x21,
47, 0x21,
48, 0x21,
49, 0x21
};
error_t error = i2c_controller_write_register_array(
i2c_controller,
ES8388_I2C_ADDR,
ENABLED_BULK_DATA,
sizeof(ENABLED_BULK_DATA),
pdMS_TO_TICKS(1000)
);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to enable ES8388: %s", error_to_string(error));
return error;
}
// Audio codec register programming is owned by the es8388-module/es7210-module drivers
// (registered as AUDIO_CODEC_TYPE devices, see m5stack,tab5.dts). This board still needs
// to drive the external speaker amplifier's enable line via io_expander0, which is board
// wiring glue rather than codec configuration, so it stays here.
static error_t enableSpeakerAmplifier(::Device* io_expander0) {
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
check(speaker_enable_pin, "Failed to acquire speaker enable pin");
error = gpio_descriptor_set_level(speaker_enable_pin, true);
error_t error = gpio_descriptor_set_level(speaker_enable_pin, true);
gpio_descriptor_release(speaker_enable_pin);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to enable amplifier: %s", error_to_string(error));
@@ -200,56 +157,6 @@ static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = null
return ERROR_NONE;
}
static error_t initMicrophone(::Device* i2c_controller) {
// ES7210 quad-channel microphone ADC at 0x40.
// Register sequence from M5Unified (M5Unified.cpp, _microphone_enabled_cb_tab5).
// Configures 4-slot TDM output at 48kHz/16-bit with MIC1+MIC2 active and MICBIAS enabled.
static constexpr uint8_t ES7210_I2C_ADDR = 0x40;
static constexpr uint8_t INIT_DATA[] = {
0x00, 0xFF, // RESET_CTL: full reset
0x00, 0x41, // RESET_CTL: release reset, keep CSM active
0x01, 0x1F, // CLK_ON_OFF: enable all clocks
0x06, 0x00, // DIGITAL_PDN: power up all digital blocks
0x07, 0x20, // ADC_OSR: OSR=256
0x08, 0x10, // MODE_CFG: I2S slave, TDM mode
0x09, 0x30, // TCT0_CHPINI: chopper init period
0x0A, 0x30, // TCT1_CHPINI
0x20, 0x0A, // ADC34_HPF2
0x21, 0x2A, // ADC34_HPF1
0x22, 0x0A, // ADC12_HPF2
0x23, 0x2A, // ADC12_HPF1
0x02, 0xC1, // CLK_CTRL: MCLK from I2S, PLL off
0x04, 0x01, // SDPOUT_CTL1: TDM output enable
0x05, 0x00, // SDPOUT_CTL0
0x11, 0x60, // DBIAS: adjust reference voltage for P4
0x40, 0x42, // ANALOG_SYS: enable analog supply
0x41, 0x70, // MICBIAS12: enable MICBIAS for MIC1+MIC2
0x42, 0x70, // MICBIAS34: enable MICBIAS for MIC3+MIC4
0x43, 0x1B, // MIC1_GAIN: +30 dB
0x44, 0x1B, // MIC2_GAIN: +30 dB
0x45, 0x00, // MIC3_GAIN: AEC ref, no gain
0x46, 0x00, // MIC4_GAIN: AEC ref, no gain
0x47, 0x00, // MIC1_LP
0x48, 0x00, // MIC2_LP
0x49, 0x00, // MIC3_LP
0x4A, 0x00, // MIC4_LP
0x4B, 0x00, // MIC12_PDN: power up MIC1+MIC2
0x4C, 0xFF, // MIC34_PDN: keep MIC3+MIC4 in power-down (AEC ref not needed)
0x01, 0x14, // CLK_ON_OFF: final clock config
};
error_t error = i2c_controller_write_register_array(
i2c_controller,
ES7210_I2C_ADDR,
INIT_DATA,
sizeof(INIT_DATA),
pdMS_TO_TICKS(1000)
);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to init ES7210: %s", error_to_string(error));
}
return error;
}
static esp_clock_output_mapping_handle_t camera_osc_handle = nullptr;
@@ -275,9 +182,6 @@ static void initCameraOsc() {
}
static bool initBoot() {
auto* i2c0 = device_find_by_name("i2c0");
check(i2c0, "i2c0 not found");
auto* io_expander0 = device_find_by_name("io_expander0");
check(io_expander0, "io_expander0 not found");
auto* io_expander1 = device_find_by_name("io_expander1");
@@ -287,14 +191,9 @@ static bool initBoot() {
initExpander0(io_expander0);
initExpander1(io_expander1);
error_t error = initSound(i2c0, io_expander0);
error_t error = enableSpeakerAmplifier(io_expander0);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to enable ES8388");
}
error = initMicrophone(i2c0);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to init ES7210");
LOG_E(TAG, "Failed to enable speaker amplifier");
}
return true;
+9 -6
View File
@@ -1,8 +1,11 @@
dependencies:
- Platforms/platform-esp32
- Drivers/pi4ioe5v6408-module
- Drivers/bmi270-module
- Drivers/ina226-module
- Drivers/rx8130ce-module
- Drivers/sc2356-module
- Platforms/platform-esp32
- Drivers/pi4ioe5v6408-module
- Drivers/bmi270-module
- Drivers/es7210-module
- Drivers/es8388-module
- Drivers/audio-stream-module
- Drivers/ina226-module
- Drivers/rx8130ce-module
- Drivers/sc2356-module
dts: m5stack,tab5.dts
+32 -11
View File
@@ -11,6 +11,8 @@
#include <tactility/bindings/esp32_usbhost.h>
#include <tactility/bindings/esp32_wifi.h>
#include <bindings/bmi270.h>
#include <bindings/es7210.h>
#include <bindings/es8388.h>
#include <bindings/ina226.h>
#include <bindings/pi4ioe5v6408.h>
#include <bindings/rx8130ce.h>
@@ -35,6 +37,17 @@
gpio-count = <57>;
};
// Declared before i2c0 so it starts before the es8388/es7210 codecs that reference it
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 27 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 29 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 26 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 28 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 30 GPIO_FLAG_NONE>;
};
i2c_internal: i2c0 {
compatible = "espressif,esp32-i2c-master";
port = <I2C_NUM_0>;
@@ -57,6 +70,25 @@
reg = <0x68>;
};
es8388 {
compatible = "everest,es8388";
reg = <0x10>;
i2s = <&i2s0>;
};
es7210 {
compatible = "everest,es7210";
reg = <0x40>;
i2s = <&i2s0>;
// Per schematic: MIC1/MIC2 are the two onboard capsules (U17/U16).
// MIC3 is not a microphone -- MIC3P is tapped from HPOUT_L (AEC_P) as an
// acoustic-echo-cancellation reference, MIC3N goes to AGND. MIC4 is the
// external headset-mic jack input (HPMIC), also not onboard. Select only
// the two real capsules; MIC3/MIC4 would otherwise show up as silent (or
// speaker-echoing) extra channels.
mic-mask = <3>;
};
rx8130ce {
compatible = "epson,rx8130ce";
reg = <0x32>;
@@ -107,17 +139,6 @@
on-chip-ldo-chan = <4>;
};
// ES8388 and ES7210
i2s0 {
compatible = "espressif,esp32-i2s";
port = <I2S_NUM_0>;
pin-bclk = <&gpio0 27 GPIO_FLAG_NONE>;
pin-ws = <&gpio0 29 GPIO_FLAG_NONE>;
pin-data-out = <&gpio0 26 GPIO_FLAG_NONE>;
pin-data-in = <&gpio0 28 GPIO_FLAG_NONE>;
pin-mclk = <&gpio0 30 GPIO_FLAG_NONE>;
};
usbhost0 {
compatible = "espressif,esp32-usbhost";
peripheral-map = <0>;