1
0
mirror of https://github.com/esphome/esphome.git synced 2025-01-31 02:00:55 +00:00

[audio_adc] Add new `audio_adc` component (#8094)

This commit is contained in:
Keith Burzinski 2025-01-20 20:35:40 -06:00 committed by GitHub
parent c3d00b45f7
commit 576dbd6f0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 200 additions and 101 deletions

View File

@ -49,6 +49,7 @@ esphome/components/atc_mithermometer/* @ahpohl
esphome/components/atm90e26/* @danieltwagner
esphome/components/atm90e32/* @circuitsetup @descipher
esphome/components/audio/* @kahrendt
esphome/components/audio_adc/* @kbx81
esphome/components/audio_dac/* @kbx81
esphome/components/axs15231/* @clydebarrow
esphome/components/b_parasite/* @rbaron

View File

@ -0,0 +1,41 @@
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MIC_GAIN
from esphome.core import coroutine_with_priority
CODEOWNERS = ["@kbx81"]
IS_PLATFORM_COMPONENT = True
audio_adc_ns = cg.esphome_ns.namespace("audio_adc")
AudioAdc = audio_adc_ns.class_("AudioAdc")
SetMicGainAction = audio_adc_ns.class_("SetMicGainAction", automation.Action)
SET_MIC_GAIN_ACTION_SCHEMA = cv.maybe_simple_value(
{
cv.GenerateID(): cv.use_id(AudioAdc),
cv.Required(CONF_MIC_GAIN): cv.templatable(cv.decibel),
},
key=CONF_MIC_GAIN,
)
@automation.register_action(
"audio_adc.set_mic_gain", SetMicGainAction, SET_MIC_GAIN_ACTION_SCHEMA
)
async def audio_adc_set_mic_gain_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren)
template_ = await cg.templatable(config.get(CONF_MIC_GAIN), args, float)
cg.add(var.set_mic_gain(template_))
return var
@coroutine_with_priority(100.0)
async def to_code(config):
cg.add_define("USE_AUDIO_ADC")
cg.add_global(audio_adc_ns.using)

View File

@ -0,0 +1,17 @@
#pragma once
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace audio_adc {
class AudioAdc {
public:
virtual bool set_mic_gain(float mic_gain) = 0;
virtual float mic_gain() = 0;
};
} // namespace audio_adc
} // namespace esphome

View File

@ -0,0 +1,23 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "audio_adc.h"
namespace esphome {
namespace audio_adc {
template<typename... Ts> class SetMicGainAction : public Action<Ts...> {
public:
explicit SetMicGainAction(AudioAdc *audio_adc) : audio_adc_(audio_adc) {}
TEMPLATABLE_VALUE(float, mic_gain)
void play(Ts... x) override { this->audio_adc_->set_mic_gain(this->mic_gain_.value(x...)); }
protected:
AudioAdc *audio_adc_;
};
} // namespace audio_adc
} // namespace esphome

View File

@ -1,67 +0,0 @@
import esphome.codegen as cg
from esphome.components import i2c
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE
CODEOWNERS = ["@kahrendt"]
DEPENDENCIES = ["i2c"]
es7210_ns = cg.esphome_ns.namespace("es7210")
ES7210 = es7210_ns.class_("ES7210", cg.Component, i2c.I2CDevice)
es7210_bits_per_sample = es7210_ns.enum("ES7210BitsPerSample")
ES7210_BITS_PER_SAMPLE_ENUM = {
16: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_16,
24: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_24,
32: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_32,
}
es7210_mic_gain = es7210_ns.enum("ES7210MicGain")
ES7210_MIC_GAIN_ENUM = {
"0DB": es7210_mic_gain.ES7210_MIC_GAIN_0DB,
"3DB": es7210_mic_gain.ES7210_MIC_GAIN_3DB,
"6DB": es7210_mic_gain.ES7210_MIC_GAIN_6DB,
"9DB": es7210_mic_gain.ES7210_MIC_GAIN_9DB,
"12DB": es7210_mic_gain.ES7210_MIC_GAIN_12DB,
"15DB": es7210_mic_gain.ES7210_MIC_GAIN_15DB,
"18DB": es7210_mic_gain.ES7210_MIC_GAIN_18DB,
"21DB": es7210_mic_gain.ES7210_MIC_GAIN_21DB,
"24DB": es7210_mic_gain.ES7210_MIC_GAIN_24DB,
"27DB": es7210_mic_gain.ES7210_MIC_GAIN_27DB,
"30DB": es7210_mic_gain.ES7210_MIC_GAIN_30DB,
"33DB": es7210_mic_gain.ES7210_MIC_GAIN_33DB,
"34.5DB": es7210_mic_gain.ES7210_MIC_GAIN_34_5DB,
"36DB": es7210_mic_gain.ES7210_MIC_GAIN_36DB,
"37.5DB": es7210_mic_gain.ES7210_MIC_GAIN_37_5DB,
}
_validate_bits = cv.float_with_unit("bits", "bit")
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES7210),
cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All(
_validate_bits, cv.enum(ES7210_BITS_PER_SAMPLE_ENUM)
),
cv.Optional(CONF_MIC_GAIN, default="24DB"): cv.enum(
ES7210_MIC_GAIN_ENUM, upper=True
),
cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x40))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_mic_gain(config[CONF_MIC_GAIN]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))

View File

@ -0,0 +1,51 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.audio_adc import AudioAdc
import esphome.config_validation as cv
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_ID, CONF_MIC_GAIN, CONF_SAMPLE_RATE
CODEOWNERS = ["@kahrendt"]
DEPENDENCIES = ["i2c"]
es7210_ns = cg.esphome_ns.namespace("es7210")
ES7210 = es7210_ns.class_("ES7210", AudioAdc, cg.Component, i2c.I2CDevice)
es7210_bits_per_sample = es7210_ns.enum("ES7210BitsPerSample")
ES7210_BITS_PER_SAMPLE_ENUM = {
16: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_16,
24: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_24,
32: es7210_bits_per_sample.ES7210_BITS_PER_SAMPLE_32,
}
ES7210_MIC_GAINS = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 34.5, 36, 37.5]
_validate_bits = cv.float_with_unit("bits", "bit")
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(ES7210),
cv.Optional(CONF_BITS_PER_SAMPLE, default="16bit"): cv.All(
_validate_bits, cv.enum(ES7210_BITS_PER_SAMPLE_ENUM)
),
cv.Optional(CONF_MIC_GAIN, default="24db"): cv.All(
cv.decibel, cv.one_of(*ES7210_MIC_GAINS)
),
cv.Optional(CONF_SAMPLE_RATE, default=16000): cv.int_range(min=1),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x40))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
cg.add(var.set_bits_per_sample(config[CONF_BITS_PER_SAMPLE]))
cg.add(var.set_mic_gain(config[CONF_MIC_GAIN]))
cg.add(var.set_sample_rate(config[CONF_SAMPLE_RATE]))

View File

@ -25,12 +25,12 @@ static const size_t MCLK_DIV_FRE = 256;
}
void ES7210::dump_config() {
ESP_LOGCONFIG(TAG, "ES7210 ADC:");
ESP_LOGCONFIG(TAG, "ES7210 audio ADC:");
ESP_LOGCONFIG(TAG, " Bits Per Sample: %" PRIu8, this->bits_per_sample_);
ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_rate_);
if (this->is_failed()) {
ESP_LOGCONFIG(TAG, " Failed to initialize!");
ESP_LOGE(TAG, " Failed to initialize");
return;
}
}
@ -84,6 +84,16 @@ void ES7210::setup() {
// Enable device
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x71));
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x41));
this->setup_complete_ = true;
}
bool ES7210::set_mic_gain(float mic_gain) {
this->mic_gain_ = clamp<float>(mic_gain, ES7210_MIC_GAIN_MIN, ES7210_MIC_GAIN_MAX);
if (this->setup_complete_) {
return this->configure_mic_gain_();
}
return true;
}
bool ES7210::configure_sample_rate_() {
@ -122,9 +132,11 @@ bool ES7210::configure_sample_rate_() {
return true;
}
bool ES7210::configure_mic_gain_() {
for (int i = 0; i < 4; ++i) {
this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43 + i, 0x10, 0x00);
auto regv = this->es7210_gain_reg_value_(this->mic_gain_);
for (uint8_t i = 0; i < 4; ++i) {
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43 + i, 0x10, 0x00));
}
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0xff));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0xff));
@ -133,29 +145,44 @@ bool ES7210::configure_mic_gain_() {
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x0f, this->mic_gain_));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC1_GAIN_REG43, 0x0f, regv));
// Configure mic 2
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC12_POWER_REG4B, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x0f, this->mic_gain_));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC2_GAIN_REG44, 0x0f, regv));
// Configure mic 3
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x0f, this->mic_gain_));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC3_GAIN_REG45, 0x0f, regv));
// Configure mic 4
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_CLOCK_OFF_REG01, 0x0b, 0x00));
ES7210_ERROR_CHECK(this->write_byte(ES7210_MIC34_POWER_REG4C, 0x00));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x10, 0x10));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x0f, this->mic_gain_));
ES7210_ERROR_CHECK(this->es7210_update_reg_bit_(ES7210_MIC4_GAIN_REG46, 0x0f, regv));
return true;
}
uint8_t ES7210::es7210_gain_reg_value_(float mic_gain) {
// reg: 12 - 34.5dB, 13 - 36dB, 14 - 37.5dB
mic_gain += 0.5;
if (mic_gain <= 33.0) {
return (uint8_t) mic_gain / 3;
}
if (mic_gain < 36.0) {
return 12;
}
if (mic_gain < 37.0) {
return 13;
}
return 14;
}
bool ES7210::configure_i2s_format_() {
// Configure bits per sample
uint8_t reg_val = 0;

View File

@ -1,8 +1,11 @@
#pragma once
#include "esphome/components/audio_adc/audio_adc.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
#include "es7210_const.h"
namespace esphome {
namespace es7210 {
@ -14,25 +17,7 @@ enum ES7210BitsPerSample : uint8_t {
ES7210_BITS_PER_SAMPLE_32 = 32,
};
enum ES7210MicGain : uint8_t {
ES7210_MIC_GAIN_0DB = 0,
ES7210_MIC_GAIN_3DB,
ES7210_MIC_GAIN_6DB,
ES7210_MIC_GAIN_9DB,
ES7210_MIC_GAIN_12DB,
ES7210_MIC_GAIN_15DB,
ES7210_MIC_GAIN_18DB,
ES7210_MIC_GAIN_21DB,
ES7210_MIC_GAIN_24DB,
ES7210_MIC_GAIN_27DB,
ES7210_MIC_GAIN_30DB,
ES7210_MIC_GAIN_33DB,
ES7210_MIC_GAIN_34_5DB,
ES7210_MIC_GAIN_36DB,
ES7210_MIC_GAIN_37_5DB,
};
class ES7210 : public Component, public i2c::I2CDevice {
class ES7210 : public audio_adc::AudioAdc, public Component, public i2c::I2CDevice {
/* Class for configuring an ES7210 ADC for microphone input.
* Based on code from:
* - https://github.com/espressif/esp-bsp/ (accessed 20241219)
@ -44,9 +29,11 @@ class ES7210 : public Component, public i2c::I2CDevice {
void dump_config() override;
void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }
void set_mic_gain(ES7210MicGain mic_gain) { this->mic_gain_ = mic_gain; }
bool set_mic_gain(float mic_gain) override;
void set_sample_rate(uint32_t sample_rate) { this->sample_rate_ = sample_rate; }
float mic_gain() override { return this->mic_gain_; };
protected:
/// @brief Updates an I2C registry address by modifying the current state
/// @param reg_addr I2C register address
@ -55,14 +42,20 @@ class ES7210 : public Component, public i2c::I2CDevice {
/// @return True if successful, false otherwise
bool es7210_update_reg_bit_(uint8_t reg_addr, uint8_t update_bits, uint8_t data);
/// @brief Convert floating point mic gain value to register value
/// @param mic_gain Gain value to convert
/// @return Corresponding register value for specified gain
uint8_t es7210_gain_reg_value_(float mic_gain);
bool configure_i2s_format_();
bool configure_mic_gain_();
bool configure_sample_rate_();
bool setup_complete_{false};
bool enable_tdm_{false}; // TDM is unsupported in ESPHome as of version 2024.12
ES7210MicGain mic_gain_;
ES7210BitsPerSample bits_per_sample_;
uint32_t sample_rate_;
float mic_gain_{0};
ES7210BitsPerSample bits_per_sample_{ES7210_BITS_PER_SAMPLE_16};
uint32_t sample_rate_{0};
};
} // namespace es7210

View File

@ -1,6 +1,6 @@
#pragma once
#include "es7210.h"
#include <cinttypes>
namespace esphome {
namespace es7210 {
@ -42,7 +42,7 @@ static const uint8_t ES7210_MIC12_POWER_REG4B = 0x4B; /* MICBias & ADC & PGA Pow
static const uint8_t ES7210_MIC34_POWER_REG4C = 0x4C;
/*
* Clock coefficient structer
* Clock coefficient structure
*/
struct ES7210Coefficient {
uint32_t mclk; // mclk frequency
@ -122,5 +122,8 @@ static const ES7210Coefficient ES7210_COEFFICIENTS[] = {
{19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8},
};
static const float ES7210_MIC_GAIN_MIN = 0.0;
static const float ES7210_MIC_GAIN_MAX = 37.5;
} // namespace es7210
} // namespace esphome

View File

@ -1,6 +1,16 @@
esphome:
on_boot:
then:
- audio_adc.set_mic_gain: 0db
- audio_adc.set_mic_gain: !lambda 'return 4;'
i2c:
- id: i2c_aic3204
scl: ${scl_pin}
sda: ${sda_pin}
es7210:
audio_adc:
- platform: es7210
id: es7210_adc
bits_per_sample: 16bit
sample_rate: 16000