mirror of
https://github.com/esphome/esphome.git
synced 2024-11-14 02:58:11 +01:00
Add more configuration for microphones - i2s/pdm/adc (#4775)
This commit is contained in:
parent
b19c7d462b
commit
39a650ee54
6 changed files with 245 additions and 129 deletions
|
@ -1 +1,118 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import pins
|
||||||
|
from esphome.const import CONF_INPUT
|
||||||
|
|
||||||
|
from esphome.core import CORE
|
||||||
|
from esphome.components.esp32 import get_esp32_variant
|
||||||
|
from esphome.components.esp32.const import (
|
||||||
|
VARIANT_ESP32,
|
||||||
|
VARIANT_ESP32C3,
|
||||||
|
VARIANT_ESP32H2,
|
||||||
|
VARIANT_ESP32S2,
|
||||||
|
VARIANT_ESP32S3,
|
||||||
|
)
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
|
|
||||||
|
ATTENUATION_MODES = {
|
||||||
|
"0db": cg.global_ns.ADC_ATTEN_DB_0,
|
||||||
|
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
|
||||||
|
"6db": cg.global_ns.ADC_ATTEN_DB_6,
|
||||||
|
"11db": cg.global_ns.ADC_ATTEN_DB_11,
|
||||||
|
"auto": "auto",
|
||||||
|
}
|
||||||
|
|
||||||
|
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
||||||
|
|
||||||
|
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
|
||||||
|
# pin to adc1 channel mapping
|
||||||
|
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||||
|
VARIANT_ESP32: {
|
||||||
|
36: adc1_channel_t.ADC1_CHANNEL_0,
|
||||||
|
37: adc1_channel_t.ADC1_CHANNEL_1,
|
||||||
|
38: adc1_channel_t.ADC1_CHANNEL_2,
|
||||||
|
39: adc1_channel_t.ADC1_CHANNEL_3,
|
||||||
|
32: adc1_channel_t.ADC1_CHANNEL_4,
|
||||||
|
33: adc1_channel_t.ADC1_CHANNEL_5,
|
||||||
|
34: adc1_channel_t.ADC1_CHANNEL_6,
|
||||||
|
35: adc1_channel_t.ADC1_CHANNEL_7,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32S2: {
|
||||||
|
1: adc1_channel_t.ADC1_CHANNEL_0,
|
||||||
|
2: adc1_channel_t.ADC1_CHANNEL_1,
|
||||||
|
3: adc1_channel_t.ADC1_CHANNEL_2,
|
||||||
|
4: adc1_channel_t.ADC1_CHANNEL_3,
|
||||||
|
5: adc1_channel_t.ADC1_CHANNEL_4,
|
||||||
|
6: adc1_channel_t.ADC1_CHANNEL_5,
|
||||||
|
7: adc1_channel_t.ADC1_CHANNEL_6,
|
||||||
|
8: adc1_channel_t.ADC1_CHANNEL_7,
|
||||||
|
9: adc1_channel_t.ADC1_CHANNEL_8,
|
||||||
|
10: adc1_channel_t.ADC1_CHANNEL_9,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32S3: {
|
||||||
|
1: adc1_channel_t.ADC1_CHANNEL_0,
|
||||||
|
2: adc1_channel_t.ADC1_CHANNEL_1,
|
||||||
|
3: adc1_channel_t.ADC1_CHANNEL_2,
|
||||||
|
4: adc1_channel_t.ADC1_CHANNEL_3,
|
||||||
|
5: adc1_channel_t.ADC1_CHANNEL_4,
|
||||||
|
6: adc1_channel_t.ADC1_CHANNEL_5,
|
||||||
|
7: adc1_channel_t.ADC1_CHANNEL_6,
|
||||||
|
8: adc1_channel_t.ADC1_CHANNEL_7,
|
||||||
|
9: adc1_channel_t.ADC1_CHANNEL_8,
|
||||||
|
10: adc1_channel_t.ADC1_CHANNEL_9,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32C3: {
|
||||||
|
0: adc1_channel_t.ADC1_CHANNEL_0,
|
||||||
|
1: adc1_channel_t.ADC1_CHANNEL_1,
|
||||||
|
2: adc1_channel_t.ADC1_CHANNEL_2,
|
||||||
|
3: adc1_channel_t.ADC1_CHANNEL_3,
|
||||||
|
4: adc1_channel_t.ADC1_CHANNEL_4,
|
||||||
|
},
|
||||||
|
VARIANT_ESP32H2: {
|
||||||
|
0: adc1_channel_t.ADC1_CHANNEL_0,
|
||||||
|
1: adc1_channel_t.ADC1_CHANNEL_1,
|
||||||
|
2: adc1_channel_t.ADC1_CHANNEL_2,
|
||||||
|
3: adc1_channel_t.ADC1_CHANNEL_3,
|
||||||
|
4: adc1_channel_t.ADC1_CHANNEL_4,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_adc_pin(value):
|
||||||
|
if str(value).upper() == "VCC":
|
||||||
|
return cv.only_on_esp8266("VCC")
|
||||||
|
|
||||||
|
if str(value).upper() == "TEMPERATURE":
|
||||||
|
return cv.only_on_rp2040("TEMPERATURE")
|
||||||
|
|
||||||
|
if CORE.is_esp32:
|
||||||
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
|
variant = get_esp32_variant()
|
||||||
|
if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL:
|
||||||
|
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
|
||||||
|
|
||||||
|
if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]:
|
||||||
|
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
|
||||||
|
return pins.internal_gpio_input_pin_schema(value)
|
||||||
|
|
||||||
|
if CORE.is_esp8266:
|
||||||
|
from esphome.components.esp8266.gpio import CONF_ANALOG
|
||||||
|
|
||||||
|
value = pins.internal_gpio_pin_number({CONF_ANALOG: True, CONF_INPUT: True})(
|
||||||
|
value
|
||||||
|
)
|
||||||
|
|
||||||
|
if value != 17: # A0
|
||||||
|
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.")
|
||||||
|
return pins.gpio_pin_schema(
|
||||||
|
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
||||||
|
)(value)
|
||||||
|
|
||||||
|
if CORE.is_rp2040:
|
||||||
|
value = pins.internal_gpio_input_pin_number(value)
|
||||||
|
if value not in (26, 27, 28, 29):
|
||||||
|
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
|
||||||
|
return pins.internal_gpio_input_pin_schema(value)
|
||||||
|
|
||||||
|
raise NotImplementedError
|
||||||
|
|
|
@ -1,133 +1,27 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome import pins
|
|
||||||
from esphome.components import sensor, voltage_sampler
|
from esphome.components import sensor, voltage_sampler
|
||||||
|
from esphome.components.esp32 import get_esp32_variant
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ATTENUATION,
|
CONF_ATTENUATION,
|
||||||
CONF_RAW,
|
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_INPUT,
|
|
||||||
CONF_NUMBER,
|
CONF_NUMBER,
|
||||||
CONF_PIN,
|
CONF_PIN,
|
||||||
|
CONF_RAW,
|
||||||
DEVICE_CLASS_VOLTAGE,
|
DEVICE_CLASS_VOLTAGE,
|
||||||
STATE_CLASS_MEASUREMENT,
|
STATE_CLASS_MEASUREMENT,
|
||||||
UNIT_VOLT,
|
UNIT_VOLT,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
from esphome.components.esp32 import get_esp32_variant
|
|
||||||
from esphome.components.esp32.const import (
|
from . import (
|
||||||
VARIANT_ESP32,
|
ATTENUATION_MODES,
|
||||||
VARIANT_ESP32C3,
|
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
|
||||||
VARIANT_ESP32H2,
|
validate_adc_pin,
|
||||||
VARIANT_ESP32S2,
|
|
||||||
VARIANT_ESP32S3,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
AUTO_LOAD = ["voltage_sampler"]
|
AUTO_LOAD = ["voltage_sampler"]
|
||||||
|
|
||||||
ATTENUATION_MODES = {
|
|
||||||
"0db": cg.global_ns.ADC_ATTEN_DB_0,
|
|
||||||
"2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
|
|
||||||
"6db": cg.global_ns.ADC_ATTEN_DB_6,
|
|
||||||
"11db": cg.global_ns.ADC_ATTEN_DB_11,
|
|
||||||
"auto": "auto",
|
|
||||||
}
|
|
||||||
|
|
||||||
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
|
||||||
|
|
||||||
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
|
|
||||||
# pin to adc1 channel mapping
|
|
||||||
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
|
||||||
VARIANT_ESP32: {
|
|
||||||
36: adc1_channel_t.ADC1_CHANNEL_0,
|
|
||||||
37: adc1_channel_t.ADC1_CHANNEL_1,
|
|
||||||
38: adc1_channel_t.ADC1_CHANNEL_2,
|
|
||||||
39: adc1_channel_t.ADC1_CHANNEL_3,
|
|
||||||
32: adc1_channel_t.ADC1_CHANNEL_4,
|
|
||||||
33: adc1_channel_t.ADC1_CHANNEL_5,
|
|
||||||
34: adc1_channel_t.ADC1_CHANNEL_6,
|
|
||||||
35: adc1_channel_t.ADC1_CHANNEL_7,
|
|
||||||
},
|
|
||||||
VARIANT_ESP32S2: {
|
|
||||||
1: adc1_channel_t.ADC1_CHANNEL_0,
|
|
||||||
2: adc1_channel_t.ADC1_CHANNEL_1,
|
|
||||||
3: adc1_channel_t.ADC1_CHANNEL_2,
|
|
||||||
4: adc1_channel_t.ADC1_CHANNEL_3,
|
|
||||||
5: adc1_channel_t.ADC1_CHANNEL_4,
|
|
||||||
6: adc1_channel_t.ADC1_CHANNEL_5,
|
|
||||||
7: adc1_channel_t.ADC1_CHANNEL_6,
|
|
||||||
8: adc1_channel_t.ADC1_CHANNEL_7,
|
|
||||||
9: adc1_channel_t.ADC1_CHANNEL_8,
|
|
||||||
10: adc1_channel_t.ADC1_CHANNEL_9,
|
|
||||||
},
|
|
||||||
VARIANT_ESP32S3: {
|
|
||||||
1: adc1_channel_t.ADC1_CHANNEL_0,
|
|
||||||
2: adc1_channel_t.ADC1_CHANNEL_1,
|
|
||||||
3: adc1_channel_t.ADC1_CHANNEL_2,
|
|
||||||
4: adc1_channel_t.ADC1_CHANNEL_3,
|
|
||||||
5: adc1_channel_t.ADC1_CHANNEL_4,
|
|
||||||
6: adc1_channel_t.ADC1_CHANNEL_5,
|
|
||||||
7: adc1_channel_t.ADC1_CHANNEL_6,
|
|
||||||
8: adc1_channel_t.ADC1_CHANNEL_7,
|
|
||||||
9: adc1_channel_t.ADC1_CHANNEL_8,
|
|
||||||
10: adc1_channel_t.ADC1_CHANNEL_9,
|
|
||||||
},
|
|
||||||
VARIANT_ESP32C3: {
|
|
||||||
0: adc1_channel_t.ADC1_CHANNEL_0,
|
|
||||||
1: adc1_channel_t.ADC1_CHANNEL_1,
|
|
||||||
2: adc1_channel_t.ADC1_CHANNEL_2,
|
|
||||||
3: adc1_channel_t.ADC1_CHANNEL_3,
|
|
||||||
4: adc1_channel_t.ADC1_CHANNEL_4,
|
|
||||||
},
|
|
||||||
VARIANT_ESP32H2: {
|
|
||||||
0: adc1_channel_t.ADC1_CHANNEL_0,
|
|
||||||
1: adc1_channel_t.ADC1_CHANNEL_1,
|
|
||||||
2: adc1_channel_t.ADC1_CHANNEL_2,
|
|
||||||
3: adc1_channel_t.ADC1_CHANNEL_3,
|
|
||||||
4: adc1_channel_t.ADC1_CHANNEL_4,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def validate_adc_pin(value):
|
|
||||||
if str(value).upper() == "VCC":
|
|
||||||
return cv.only_on_esp8266("VCC")
|
|
||||||
|
|
||||||
if str(value).upper() == "TEMPERATURE":
|
|
||||||
return cv.only_on_rp2040("TEMPERATURE")
|
|
||||||
|
|
||||||
if CORE.is_esp32:
|
|
||||||
value = pins.internal_gpio_input_pin_number(value)
|
|
||||||
variant = get_esp32_variant()
|
|
||||||
if variant not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL:
|
|
||||||
raise cv.Invalid(f"This ESP32 variant ({variant}) is not supported")
|
|
||||||
|
|
||||||
if value not in ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant]:
|
|
||||||
raise cv.Invalid(f"{variant} doesn't support ADC on this pin")
|
|
||||||
return pins.internal_gpio_input_pin_schema(value)
|
|
||||||
|
|
||||||
if CORE.is_esp8266:
|
|
||||||
from esphome.components.esp8266.gpio import CONF_ANALOG
|
|
||||||
|
|
||||||
value = pins.internal_gpio_pin_number({CONF_ANALOG: True, CONF_INPUT: True})(
|
|
||||||
value
|
|
||||||
)
|
|
||||||
|
|
||||||
if value != 17: # A0
|
|
||||||
raise cv.Invalid("ESP8266: Only pin A0 (GPIO17) supports ADC.")
|
|
||||||
return pins.gpio_pin_schema(
|
|
||||||
{CONF_ANALOG: True, CONF_INPUT: True}, internal=True
|
|
||||||
)(value)
|
|
||||||
|
|
||||||
if CORE.is_rp2040:
|
|
||||||
value = pins.internal_gpio_input_pin_number(value)
|
|
||||||
if value not in (26, 27, 28, 29):
|
|
||||||
raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
|
|
||||||
return pins.internal_gpio_input_pin_schema(value)
|
|
||||||
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
def validate_config(config):
|
def validate_config(config):
|
||||||
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
|
if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
|
||||||
|
|
|
@ -2,8 +2,9 @@ import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
|
|
||||||
from esphome import pins
|
from esphome import pins
|
||||||
from esphome.const import CONF_ID
|
from esphome.const import CONF_ID, CONF_NUMBER
|
||||||
from esphome.components import microphone
|
from esphome.components import microphone, esp32
|
||||||
|
from esphome.components.adc import ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, validate_adc_pin
|
||||||
|
|
||||||
from .. import (
|
from .. import (
|
||||||
i2s_audio_ns,
|
i2s_audio_ns,
|
||||||
|
@ -16,18 +17,59 @@ from .. import (
|
||||||
CODEOWNERS = ["@jesserockz"]
|
CODEOWNERS = ["@jesserockz"]
|
||||||
DEPENDENCIES = ["i2s_audio"]
|
DEPENDENCIES = ["i2s_audio"]
|
||||||
|
|
||||||
|
CONF_ADC_PIN = "adc_pin"
|
||||||
|
CONF_ADC_TYPE = "adc_type"
|
||||||
|
CONF_PDM = "pdm"
|
||||||
|
|
||||||
I2SAudioMicrophone = i2s_audio_ns.class_(
|
I2SAudioMicrophone = i2s_audio_ns.class_(
|
||||||
"I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component
|
"I2SAudioMicrophone", I2SAudioIn, microphone.Microphone, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = microphone.MICROPHONE_SCHEMA.extend(
|
INTERNAL_ADC_VARIANTS = [esp32.const.VARIANT_ESP32]
|
||||||
|
PDM_VARIANTS = [esp32.const.VARIANT_ESP32, esp32.const.VARIANT_ESP32S3]
|
||||||
|
|
||||||
|
|
||||||
|
def validate_esp32_variant(config):
|
||||||
|
variant = esp32.get_esp32_variant()
|
||||||
|
if config[CONF_ADC_TYPE] == "external":
|
||||||
|
if config[CONF_PDM]:
|
||||||
|
if variant not in PDM_VARIANTS:
|
||||||
|
raise cv.Invalid(f"{variant} does not support PDM")
|
||||||
|
return config
|
||||||
|
if config[CONF_ADC_TYPE] == "internal":
|
||||||
|
if variant not in INTERNAL_ADC_VARIANTS:
|
||||||
|
raise cv.Invalid(f"{variant} does not have an internal ADC")
|
||||||
|
return config
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
BASE_SCHEMA = microphone.MICROPHONE_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(I2SAudioMicrophone),
|
cv.GenerateID(): cv.declare_id(I2SAudioMicrophone),
|
||||||
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
|
cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent),
|
||||||
cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number,
|
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
cv.typed_schema(
|
||||||
|
{
|
||||||
|
"internal": BASE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ADC_PIN): validate_adc_pin,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
"external": BASE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_I2S_DIN_PIN): pins.internal_gpio_input_pin_number,
|
||||||
|
cv.Required(CONF_PDM): cv.boolean,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
},
|
||||||
|
key=CONF_ADC_TYPE,
|
||||||
|
),
|
||||||
|
validate_esp32_variant,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
@ -35,6 +77,13 @@ async def to_code(config):
|
||||||
|
|
||||||
await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
|
await cg.register_parented(var, config[CONF_I2S_AUDIO_ID])
|
||||||
|
|
||||||
cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN]))
|
if config[CONF_ADC_TYPE] == "internal":
|
||||||
|
variant = esp32.get_esp32_variant()
|
||||||
|
pin_num = config[CONF_ADC_PIN][CONF_NUMBER]
|
||||||
|
channel = ESP32_VARIANT_ADC1_PIN_TO_CHANNEL[variant][pin_num]
|
||||||
|
cg.add(var.set_adc_channel(channel))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_din_pin(config[CONF_I2S_DIN_PIN]))
|
||||||
|
cg.add(var.set_pdm(config[CONF_PDM]))
|
||||||
|
|
||||||
await microphone.register_microphone(var, config)
|
await microphone.register_microphone(var, config)
|
||||||
|
|
|
@ -17,15 +17,36 @@ static const char *const TAG = "i2s_audio.microphone";
|
||||||
void I2SAudioMicrophone::setup() {
|
void I2SAudioMicrophone::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone...");
|
ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone...");
|
||||||
this->buffer_.resize(BUFFER_SIZE);
|
this->buffer_.resize(BUFFER_SIZE);
|
||||||
|
|
||||||
|
#if SOC_I2S_SUPPORTS_ADC
|
||||||
|
if (this->adc_) {
|
||||||
|
if (this->parent_->get_port() != I2S_NUM_0) {
|
||||||
|
ESP_LOGE(TAG, "Internal ADC only works on I2S0!");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (this->pdm_) {
|
||||||
|
if (this->parent_->get_port() != I2S_NUM_0) {
|
||||||
|
ESP_LOGE(TAG, "PDM only works on I2S0!");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2SAudioMicrophone::start() { this->state_ = microphone::STATE_STARTING; }
|
void I2SAudioMicrophone::start() {
|
||||||
|
if (this->is_failed())
|
||||||
|
return;
|
||||||
|
this->state_ = microphone::STATE_STARTING;
|
||||||
|
}
|
||||||
void I2SAudioMicrophone::start_() {
|
void I2SAudioMicrophone::start_() {
|
||||||
if (!this->parent_->try_lock()) {
|
if (!this->parent_->try_lock()) {
|
||||||
return; // Waiting for another i2s to return lock
|
return; // Waiting for another i2s to return lock
|
||||||
}
|
}
|
||||||
i2s_driver_config_t config = {
|
i2s_driver_config_t config = {
|
||||||
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
|
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX),
|
||||||
.sample_rate = 16000,
|
.sample_rate = 16000,
|
||||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||||
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
|
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
|
||||||
|
@ -40,18 +61,33 @@ void I2SAudioMicrophone::start_() {
|
||||||
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
|
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
#if SOC_I2S_SUPPORTS_ADC
|
||||||
|
if (this->adc_) {
|
||||||
|
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN);
|
||||||
|
i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
||||||
|
|
||||||
i2s_pin_config_t pin_config = this->parent_->get_pin_config();
|
i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_);
|
||||||
pin_config.data_in_num = this->din_pin_;
|
i2s_adc_enable(this->parent_->get_port());
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
if (this->pdm_)
|
||||||
|
config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM);
|
||||||
|
|
||||||
i2s_set_pin(this->parent_->get_port(), &pin_config);
|
i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
|
||||||
|
|
||||||
|
i2s_pin_config_t pin_config = this->parent_->get_pin_config();
|
||||||
|
pin_config.data_in_num = this->din_pin_;
|
||||||
|
|
||||||
|
i2s_set_pin(this->parent_->get_port(), &pin_config);
|
||||||
|
#if SOC_I2S_SUPPORTS_ADC
|
||||||
|
}
|
||||||
|
#endif
|
||||||
this->state_ = microphone::STATE_RUNNING;
|
this->state_ = microphone::STATE_RUNNING;
|
||||||
this->high_freq_.start();
|
this->high_freq_.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2SAudioMicrophone::stop() {
|
void I2SAudioMicrophone::stop() {
|
||||||
if (this->state_ == microphone::STATE_STOPPED)
|
if (this->state_ == microphone::STATE_STOPPED || this->is_failed())
|
||||||
return;
|
return;
|
||||||
this->state_ = microphone::STATE_STOPPING;
|
this->state_ = microphone::STATE_STOPPING;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,27 @@ class I2SAudioMicrophone : public I2SAudioIn, public microphone::Microphone, pub
|
||||||
|
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
void set_din_pin(uint8_t pin) { this->din_pin_ = pin; }
|
void set_din_pin(int8_t pin) { this->din_pin_ = pin; }
|
||||||
|
void set_pdm(bool pdm) { this->pdm_ = pdm; }
|
||||||
|
|
||||||
|
#if SOC_I2S_SUPPORTS_ADC
|
||||||
|
void set_adc_channel(adc1_channel_t channel) {
|
||||||
|
this->adc_channel_ = channel;
|
||||||
|
this->adc_ = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void start_();
|
void start_();
|
||||||
void stop_();
|
void stop_();
|
||||||
void read_();
|
void read_();
|
||||||
|
|
||||||
uint8_t din_pin_{0};
|
int8_t din_pin_{I2S_PIN_NO_CHANGE};
|
||||||
|
#if SOC_I2S_SUPPORTS_ADC
|
||||||
|
adc1_channel_t adc_channel_{ADC1_CHANNEL_MAX};
|
||||||
|
bool adc_{false};
|
||||||
|
#endif
|
||||||
|
bool pdm_{false};
|
||||||
std::vector<uint8_t> buffer_;
|
std::vector<uint8_t> buffer_;
|
||||||
|
|
||||||
HighFrequencyLoopRequester high_freq_;
|
HighFrequencyLoopRequester high_freq_;
|
||||||
|
|
|
@ -700,8 +700,15 @@ prometheus:
|
||||||
|
|
||||||
microphone:
|
microphone:
|
||||||
- platform: i2s_audio
|
- platform: i2s_audio
|
||||||
id: mic_id
|
id: mic_id_adc
|
||||||
|
adc_pin: GPIO35
|
||||||
|
adc_type: internal
|
||||||
|
|
||||||
|
- platform: i2s_audio
|
||||||
|
id: mic_id_external
|
||||||
i2s_din_pin: GPIO23
|
i2s_din_pin: GPIO23
|
||||||
|
adc_type: external
|
||||||
|
pdm: false
|
||||||
|
|
||||||
speaker:
|
speaker:
|
||||||
- platform: i2s_audio
|
- platform: i2s_audio
|
||||||
|
@ -712,7 +719,7 @@ speaker:
|
||||||
|
|
||||||
|
|
||||||
voice_assistant:
|
voice_assistant:
|
||||||
microphone: mic_id
|
microphone: mic_id_external
|
||||||
on_start:
|
on_start:
|
||||||
- logger.log: "Voice assistant started"
|
- logger.log: "Voice assistant started"
|
||||||
on_stt_end:
|
on_stt_end:
|
||||||
|
|
Loading…
Reference in a new issue