ESPHome  2025.2.0
i2s_audio_microphone.cpp
Go to the documentation of this file.
1 #include "i2s_audio_microphone.h"
2 
3 #ifdef USE_ESP32
4 
5 #include <driver/i2s.h>
6 
7 #include "esphome/core/hal.h"
8 #include "esphome/core/log.h"
9 
10 namespace esphome {
11 namespace i2s_audio {
12 
13 static const size_t BUFFER_SIZE = 512;
14 
15 static const char *const TAG = "i2s_audio.microphone";
16 
18  ESP_LOGCONFIG(TAG, "Setting up I2S Audio Microphone...");
19 #if SOC_I2S_SUPPORTS_ADC
20  if (this->adc_) {
21  if (this->parent_->get_port() != I2S_NUM_0) {
22  ESP_LOGE(TAG, "Internal ADC only works on I2S0!");
23  this->mark_failed();
24  return;
25  }
26  } else
27 #endif
28  {
29  if (this->pdm_) {
30  if (this->parent_->get_port() != I2S_NUM_0) {
31  ESP_LOGE(TAG, "PDM only works on I2S0!");
32  this->mark_failed();
33  return;
34  }
35  }
36  }
37 }
38 
40  if (this->is_failed())
41  return;
42  if (this->state_ == microphone::STATE_RUNNING)
43  return; // Already running
45 }
47  if (!this->parent_->try_lock()) {
48  return; // Waiting for another i2s to return lock
49  }
50  i2s_driver_config_t config = {
51  .mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_RX),
52  .sample_rate = this->sample_rate_,
53  .bits_per_sample = this->bits_per_sample_,
54  .channel_format = this->channel_,
55  .communication_format = I2S_COMM_FORMAT_STAND_I2S,
56  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
57  .dma_buf_count = 4,
58  .dma_buf_len = 256,
59  .use_apll = this->use_apll_,
60  .tx_desc_auto_clear = false,
61  .fixed_mclk = 0,
62  .mclk_multiple = I2S_MCLK_MULTIPLE_256,
63  .bits_per_chan = this->bits_per_channel_,
64  };
65 
66  esp_err_t err;
67 
68 #if SOC_I2S_SUPPORTS_ADC
69  if (this->adc_) {
70  config.mode = (i2s_mode_t) (config.mode | I2S_MODE_ADC_BUILT_IN);
71  err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
72  if (err != ESP_OK) {
73  ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
74  this->status_set_error();
75  return;
76  }
77 
78  err = i2s_set_adc_mode(ADC_UNIT_1, this->adc_channel_);
79  if (err != ESP_OK) {
80  ESP_LOGW(TAG, "Error setting ADC mode: %s", esp_err_to_name(err));
81  this->status_set_error();
82  return;
83  }
84  err = i2s_adc_enable(this->parent_->get_port());
85  if (err != ESP_OK) {
86  ESP_LOGW(TAG, "Error enabling ADC: %s", esp_err_to_name(err));
87  this->status_set_error();
88  return;
89  }
90 
91  } else
92 #endif
93  {
94  if (this->pdm_)
95  config.mode = (i2s_mode_t) (config.mode | I2S_MODE_PDM);
96 
97  err = i2s_driver_install(this->parent_->get_port(), &config, 0, nullptr);
98  if (err != ESP_OK) {
99  ESP_LOGW(TAG, "Error installing I2S driver: %s", esp_err_to_name(err));
100  this->status_set_error();
101  return;
102  }
103 
104  i2s_pin_config_t pin_config = this->parent_->get_pin_config();
105  pin_config.data_in_num = this->din_pin_;
106 
107  err = i2s_set_pin(this->parent_->get_port(), &pin_config);
108  if (err != ESP_OK) {
109  ESP_LOGW(TAG, "Error setting I2S pin: %s", esp_err_to_name(err));
110  this->status_set_error();
111  return;
112  }
113  }
115  this->high_freq_.start();
116  this->status_clear_error();
117 }
118 
120  if (this->state_ == microphone::STATE_STOPPED || this->is_failed())
121  return;
122  if (this->state_ == microphone::STATE_STARTING) {
124  return;
125  }
127 }
128 
130  esp_err_t err;
131 #if SOC_I2S_SUPPORTS_ADC
132  if (this->adc_) {
133  err = i2s_adc_disable(this->parent_->get_port());
134  if (err != ESP_OK) {
135  ESP_LOGW(TAG, "Error disabling ADC: %s", esp_err_to_name(err));
136  this->status_set_error();
137  return;
138  }
139  }
140 #endif
141  err = i2s_stop(this->parent_->get_port());
142  if (err != ESP_OK) {
143  ESP_LOGW(TAG, "Error stopping I2S microphone: %s", esp_err_to_name(err));
144  this->status_set_error();
145  return;
146  }
147  err = i2s_driver_uninstall(this->parent_->get_port());
148  if (err != ESP_OK) {
149  ESP_LOGW(TAG, "Error uninstalling I2S driver: %s", esp_err_to_name(err));
150  this->status_set_error();
151  return;
152  }
153  this->parent_->unlock();
155  this->high_freq_.stop();
156  this->status_clear_error();
157 }
158 
159 size_t I2SAudioMicrophone::read(int16_t *buf, size_t len) {
160  size_t bytes_read = 0;
161  esp_err_t err = i2s_read(this->parent_->get_port(), buf, len, &bytes_read, (100 / portTICK_PERIOD_MS));
162  if (err != ESP_OK) {
163  ESP_LOGW(TAG, "Error reading from I2S microphone: %s", esp_err_to_name(err));
164  this->status_set_warning();
165  return 0;
166  }
167  if (bytes_read == 0) {
168  this->status_set_warning();
169  return 0;
170  }
171  this->status_clear_warning();
172  // ESP-IDF I2S implementation right-extends 8-bit data to 16 bits,
173  // and 24-bit data to 32 bits.
174  switch (this->bits_per_sample_) {
175  case I2S_BITS_PER_SAMPLE_8BIT:
176  case I2S_BITS_PER_SAMPLE_16BIT:
177  return bytes_read;
178  case I2S_BITS_PER_SAMPLE_24BIT:
179  case I2S_BITS_PER_SAMPLE_32BIT: {
180  size_t samples_read = bytes_read / sizeof(int32_t);
181  for (size_t i = 0; i < samples_read; i++) {
182  int32_t temp = reinterpret_cast<int32_t *>(buf)[i] >> 14;
183  buf[i] = clamp<int16_t>(temp, INT16_MIN, INT16_MAX);
184  }
185  return samples_read * sizeof(int16_t);
186  }
187  default:
188  ESP_LOGE(TAG, "Unsupported bits per sample: %d", this->bits_per_sample_);
189  return 0;
190  }
191 }
192 
194  std::vector<int16_t> samples;
195  samples.resize(BUFFER_SIZE);
196  size_t bytes_read = this->read(samples.data(), BUFFER_SIZE / sizeof(int16_t));
197  samples.resize(bytes_read / sizeof(int16_t));
198  this->data_callbacks_.call(samples);
199 }
200 
202  switch (this->state_) {
204  break;
206  this->start_();
207  break;
209  if (this->data_callbacks_.size() > 0) {
210  this->read_();
211  }
212  break;
214  this->stop_();
215  break;
216  }
217 }
218 
219 } // namespace i2s_audio
220 } // namespace esphome
221 
222 #endif // USE_ESP32
void status_set_warning(const char *message="unspecified")
Definition: component.cpp:151
bool is_failed() const
Definition: component.cpp:143
CallbackManager< void(const std::vector< int16_t > &)> data_callbacks_
Definition: microphone.h:34
void status_set_error(const char *message="unspecified")
Definition: component.cpp:159
i2s_channel_fmt_t channel_
Definition: i2s_audio.h:25
void start()
Start running the loop continuously.
Definition: helpers.cpp:674
void status_clear_warning()
Definition: component.cpp:166
void stop()
Stop running the loop continuously.
Definition: helpers.cpp:680
size_t read(int16_t *buf, size_t len) override
void status_clear_error()
Definition: component.cpp:172
i2s_bits_per_sample_t bits_per_sample_
Definition: i2s_audio.h:27
std::string size_t len
Definition: helpers.h:301
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
i2s_bits_per_chan_t bits_per_channel_
Definition: i2s_audio.h:28