mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add more configuration for microphones - i2s/pdm/adc (#4775)
This commit is contained in:
		| @@ -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 ( |  | ||||||
|     VARIANT_ESP32, |  | ||||||
|     VARIANT_ESP32C3, |  | ||||||
|     VARIANT_ESP32H2, |  | ||||||
|     VARIANT_ESP32S2, |  | ||||||
|     VARIANT_ESP32S3, |  | ||||||
| ) |  | ||||||
|  |  | ||||||
|  | from . import ( | ||||||
|  |     ATTENUATION_MODES, | ||||||
|  |     ESP32_VARIANT_ADC1_PIN_TO_CHANNEL, | ||||||
|  |     validate_adc_pin, | ||||||
|  | ) | ||||||
|  |  | ||||||
| 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]) | ||||||
|  |  | ||||||
|  |     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_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, | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | #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_set_adc_mode(ADC_UNIT_1, this->adc_channel_); | ||||||
|  |     i2s_adc_enable(this->parent_->get_port()); | ||||||
|  |   } else { | ||||||
|  | #endif | ||||||
|  |     if (this->pdm_) | ||||||
|  |       config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM); | ||||||
|  |  | ||||||
|     i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); |     i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr); | ||||||
|  |  | ||||||
|     i2s_pin_config_t pin_config = this->parent_->get_pin_config(); |     i2s_pin_config_t pin_config = this->parent_->get_pin_config(); | ||||||
|     pin_config.data_in_num = this->din_pin_; |     pin_config.data_in_num = this->din_pin_; | ||||||
|  |  | ||||||
|     i2s_set_pin(this->parent_->get_port(), &pin_config); |     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: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user