语音对话

This commit is contained in:
admin
2026-02-25 11:16:30 +08:00
parent e9ac05592c
commit 9d060f9f40
5 changed files with 612 additions and 58 deletions

View File

@@ -22,6 +22,9 @@
#endif
static const char *TAG = "voice_audio";
static const uint32_t VOICE_CODEC_I2C_PROBE_TIMEOUT_MS = 50;
#define ES8311_CODEC_ALT_ADDR ((uint8_t)(ES8311_CODEC_DEFAULT_ADDR + 0x02))
#ifdef CONFIG_TQ_VOICE_CODEC_PA_PIN_REVERSED
#define VOICE_CODEC_PA_REVERSED true
@@ -56,6 +59,66 @@ static void fill_err(char *err, size_t err_len, const char *msg) {
}
}
static bool voice_audio_i2c_probe_addr(uint8_t addr_8bit) {
#ifdef VOICE_USE_IDF_I2C_MASTER
if (s_i2c_bus == NULL || addr_8bit == 0) {
return false;
}
uint16_t addr_7bit = (uint16_t)(addr_8bit >> 1);
return i2c_master_probe(s_i2c_bus, addr_7bit, (int)VOICE_CODEC_I2C_PROBE_TIMEOUT_MS) == ESP_OK;
#else
if (addr_8bit == 0) {
return false;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
if (cmd == NULL) {
return false;
}
i2c_master_start(cmd);
i2c_master_write_byte(cmd, addr_8bit, true);
i2c_master_stop(cmd);
esp_err_t err = i2c_master_cmd_begin(CONFIG_TQ_VOICE_I2C_PORT,
cmd,
pdMS_TO_TICKS(VOICE_CODEC_I2C_PROBE_TIMEOUT_MS));
i2c_cmd_link_delete(cmd);
return err == ESP_OK;
#endif
}
static uint8_t voice_audio_resolve_codec_addr(uint8_t preferred_addr) {
uint8_t candidates[3] = {preferred_addr, ES8311_CODEC_DEFAULT_ADDR, ES8311_CODEC_ALT_ADDR};
for (size_t i = 0; i < 3; ++i) {
uint8_t addr = candidates[i];
bool duplicate = false;
for (size_t j = 0; j < i; ++j) {
if (candidates[j] == addr) {
duplicate = true;
break;
}
}
if (duplicate) {
continue;
}
if (voice_audio_i2c_probe_addr(addr)) {
return addr;
}
}
ESP_LOGW(TAG,
"ES8311 not found on I2C(port=%d,sda=%d,scl=%d), tried addrs:0x%02x/0x%02x/0x%02x",
CONFIG_TQ_VOICE_I2C_PORT,
CONFIG_TQ_VOICE_I2C_SDA_PIN,
CONFIG_TQ_VOICE_I2C_SCL_PIN,
(unsigned)preferred_addr,
(unsigned)ES8311_CODEC_DEFAULT_ADDR,
(unsigned)ES8311_CODEC_ALT_ADDR);
return preferred_addr;
}
static esp_err_t voice_audio_init_i2c(void) {
#ifdef VOICE_USE_IDF_I2C_MASTER
if (s_i2c_bus != NULL) {
@@ -71,7 +134,15 @@ static esp_err_t voice_audio_init_i2c(void) {
.flags.enable_internal_pullup = true,
};
return i2c_new_master_bus(&bus_cfg, &s_i2c_bus);
esp_err_t err = i2c_new_master_bus(&bus_cfg, &s_i2c_bus);
if (err == ESP_OK) {
ESP_LOGI(TAG,
"voice i2c ready: port=%d sda=%d scl=%d",
CONFIG_TQ_VOICE_I2C_PORT,
CONFIG_TQ_VOICE_I2C_SDA_PIN,
CONFIG_TQ_VOICE_I2C_SCL_PIN);
}
return err;
#else
i2c_config_t i2c_cfg = {
.mode = I2C_MODE_MASTER,
@@ -83,7 +154,15 @@ static esp_err_t voice_audio_init_i2c(void) {
};
ESP_RETURN_ON_ERROR(i2c_param_config(CONFIG_TQ_VOICE_I2C_PORT, &i2c_cfg), TAG, "i2c_param_config failed");
return i2c_driver_install(CONFIG_TQ_VOICE_I2C_PORT, i2c_cfg.mode, 0, 0, 0);
esp_err_t err = i2c_driver_install(CONFIG_TQ_VOICE_I2C_PORT, i2c_cfg.mode, 0, 0, 0);
if (err == ESP_OK) {
ESP_LOGI(TAG,
"voice i2c ready: port=%d sda=%d scl=%d",
CONFIG_TQ_VOICE_I2C_PORT,
CONFIG_TQ_VOICE_I2C_SDA_PIN,
CONFIG_TQ_VOICE_I2C_SCL_PIN);
}
return err;
#endif
}
@@ -136,9 +215,27 @@ static esp_err_t voice_audio_build_codec_dev(void) {
return ESP_OK;
}
uint8_t codec_addr = voice_audio_resolve_codec_addr((uint8_t)CONFIG_TQ_VOICE_CODEC_ADDR);
if (codec_addr != (uint8_t)CONFIG_TQ_VOICE_CODEC_ADDR) {
ESP_LOGW(TAG,
"override ES8311 I2C addr 0x%02x -> 0x%02x",
(unsigned)CONFIG_TQ_VOICE_CODEC_ADDR,
(unsigned)codec_addr);
}
ESP_LOGI(TAG,
"voice codec cfg: i2c_port=%d addr=0x%02x i2s_port=%d mclk=%d bclk=%d ws=%d dout=%d din=%d",
CONFIG_TQ_VOICE_I2C_PORT,
(unsigned)codec_addr,
CONFIG_TQ_VOICE_I2S_PORT,
CONFIG_TQ_VOICE_I2S_MCLK_PIN,
CONFIG_TQ_VOICE_I2S_BCLK_PIN,
CONFIG_TQ_VOICE_I2S_WS_PIN,
CONFIG_TQ_VOICE_I2S_DOUT_PIN,
CONFIG_TQ_VOICE_I2S_DIN_PIN);
audio_codec_i2c_cfg_t i2c_cfg = {
.port = (uint8_t)CONFIG_TQ_VOICE_I2C_PORT,
.addr = (uint8_t)CONFIG_TQ_VOICE_CODEC_ADDR,
.addr = codec_addr,
#ifdef VOICE_USE_IDF_I2C_MASTER
.bus_handle = s_i2c_bus,
#endif
@@ -180,7 +277,8 @@ static esp_err_t voice_audio_build_codec_dev(void) {
s_codec_if = es8311_codec_new(&codec_cfg);
if (s_codec_if == NULL) {
return ESP_ERR_NO_MEM;
ESP_LOGE(TAG, "es8311_codec_new failed, check I2C wiring/pull-up/address");
return ESP_FAIL;
}
esp_codec_dev_cfg_t dev_cfg = {
@@ -230,7 +328,11 @@ esp_err_t voice_audio_open(const voice_audio_open_config_t *cfg, char *err, size
esp_err_t init_err = voice_audio_prepare(cfg);
if (init_err != ESP_OK) {
fill_err(err, err_len, "voice audio peripheral init failed");
if (init_err == ESP_FAIL) {
fill_err(err, err_len, "es8311 init failed, check i2c wiring/address");
} else {
fill_err(err, err_len, "voice audio peripheral init failed");
}
xSemaphoreGive(s_lock);
return init_err;
}