M5Unified
Mic_Class.cpp
Go to the documentation of this file.
1 // Copyright (c) M5Stack. All rights reserved.
2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 
4 #include "Mic_Class.hpp"
5 
6 #include "../M5Unified.hpp"
7 
8 #if __has_include (<esp_idf_version.h>)
9  #include <esp_idf_version.h>
10  #if ESP_IDF_VERSION_MAJOR >= 4
11  #define NON_BREAK ;[[fallthrough]];
12  #endif
13 #endif
14 
15 #ifndef NON_BREAK
16 #define NON_BREAK ;
17 #endif
18 
19 #if __has_include(<sdkconfig.h>)
20 #include <sdkconfig.h>
21 #include <esp_log.h>
22 #include <math.h>
23 
24 #define __STDC_FORMAT_MACROS
25 #include <inttypes.h>
26 
27 namespace m5
28 {
29 #if defined ( ESP_PLATFORM )
30 #if defined (ESP_IDF_VERSION_VAL)
31  #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
32  #define COMM_FORMAT_I2S (I2S_COMM_FORMAT_STAND_I2S)
33  #define COMM_FORMAT_MSB (I2S_COMM_FORMAT_STAND_MSB)
34  #endif
35  #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 3)
36  #define SAMPLE_RATE_TYPE uint32_t
37  #endif
38  #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
39  #define MIC_CLASS_ADC_WIDTH_BITS ADC_WIDTH_BIT_12
40  #define MIC_CLASS_ADC_ATTEN_DB ADC_ATTEN_DB_11
41  #endif
42 #endif
43 
44 #ifndef COMM_FORMAT_I2S
45  #define COMM_FORMAT_I2S (I2S_COMM_FORMAT_I2S)
46  #define COMM_FORMAT_MSB (I2S_COMM_FORMAT_I2S_MSB)
47 #endif
48 
49 #ifndef SAMPLE_RATE_TYPE
50  #define SAMPLE_RATE_TYPE int
51 #endif
52 
53 #ifndef MIC_CLASS_ADC_WIDTH_BITS
54  #define MIC_CLASS_ADC_WIDTH_BITS ADC_WIDTH_12Bit
55  #define MIC_CLASS_ADC_ATTEN_DB ADC_ATTEN_11db
56 #endif
57 
58 
59  uint32_t Mic_Class::_calc_rec_rate(void) const
60  {
61  int rate = (_cfg.sample_rate * _cfg.over_sampling);
62  return rate;
63  }
64 
65  esp_err_t Mic_Class::_setup_i2s(void)
66  {
67  if (_cfg.pin_data_in < 0) { return ESP_FAIL; }
68 
69  SAMPLE_RATE_TYPE sample_rate = _calc_rec_rate();
70 /*
71  ESP-IDF ver4系にて I2S_MODE_ADC_BUILT_IN を使用するとサンプリングレートが正しく反映されない不具合があったため、特殊な対策を実装している。
72  ・指定するサンプリングレートの値を1/16にする
73  ・I2S_MODE_ADC_BUILT_INを使用せずに初期化を行う
74  ・最後にI2S0のレジスタを操作してADCモードを有効にする。
75 */
76  bool use_pdm = (_cfg.pin_bck < 0);
77  if (_cfg.use_adc) { sample_rate >>= 4; use_pdm = false;}
78 // ESP_LOGV("Mic","sampling rate:%" PRIu32 , sample_rate);
79  i2s_config_t i2s_config;
80  memset(&i2s_config, 0, sizeof(i2s_config_t));
81  i2s_config.mode = use_pdm
82  // ? (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM );
83  ? (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_RX | (0x1 << 6) ) // 0x1<<6 is I2S_MODE_PDM
84  : (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_RX );
85  i2s_config.sample_rate = sample_rate;
86  i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
87  i2s_config.channel_format = _cfg.stereo ? I2S_CHANNEL_FMT_RIGHT_LEFT : I2S_CHANNEL_FMT_ONLY_RIGHT;
88  i2s_config.communication_format = (i2s_comm_format_t)( COMM_FORMAT_I2S );
89  i2s_config.dma_buf_count = _cfg.dma_buf_count;
90  i2s_config.dma_buf_len = _cfg.dma_buf_len;
91 
92  i2s_pin_config_t pin_config;
93  memset(&pin_config, ~0u, sizeof(i2s_pin_config_t));
94 #if defined (ESP_IDF_VERSION_VAL)
95  #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 1)
96  pin_config.mck_io_num = _cfg.pin_mck;
97  #endif
98 #endif
99  pin_config.bck_io_num = _cfg.pin_bck;
100  pin_config.ws_io_num = _cfg.pin_ws;
101  pin_config.data_in_num = _cfg.pin_data_in;
102 
103  esp_err_t err;
104  if (ESP_OK != (err = i2s_driver_install(_cfg.i2s_port, &i2s_config, 0, nullptr)))
105  {
106  i2s_driver_uninstall(_cfg.i2s_port);
107  err = i2s_driver_install(_cfg.i2s_port, &i2s_config, 0, nullptr);
108  }
109  if (err != ESP_OK) { return err; }
110 
111 #if !defined (CONFIG_IDF_TARGET) || defined (CONFIG_IDF_TARGET_ESP32)
112  if (_cfg.use_adc)
113  {
114  if (((size_t)_cfg.pin_data_in) > 39) { return ESP_FAIL; }
115  static constexpr const uint8_t adc_table[] =
116  {
117  ADC2_CHANNEL_1 , // GPIO 0
118  255 ,
119  ADC2_CHANNEL_2 , // GPIO 2
120  255 ,
121  ADC2_CHANNEL_0 , // GPIO 4
122  255, 255, 255, 255, 255, 255, 255,
123  ADC2_CHANNEL_5 , // GPIO 12
124  ADC2_CHANNEL_4 , // GPIO 13
125  ADC2_CHANNEL_6 , // GPIO 14
126  ADC2_CHANNEL_3 , // GPIO 15
127  255, 255, 255, 255, 255, 255, 255, 255, 255,
128  ADC2_CHANNEL_8 , // GPIO 25
129  ADC2_CHANNEL_9 , // GPIO 26
130  ADC2_CHANNEL_7 , // GPIO 27
131  255, 255, 255, 255,
132  ADC1_CHANNEL_4 , // GPIO 32
133  ADC1_CHANNEL_5 , // GPIO 33
134  ADC1_CHANNEL_6 , // GPIO 34
135  ADC1_CHANNEL_7 , // GPIO 35
136  ADC1_CHANNEL_0 , // GPIO 36
137  ADC1_CHANNEL_1 , // GPIO 37
138  ADC1_CHANNEL_2 , // GPIO 38
139  ADC1_CHANNEL_3 , // GPIO 39
140  };
141  int adc_ch = adc_table[_cfg.pin_data_in];
142  if (adc_ch == 255) { return ESP_FAIL; }
143 
144  adc_unit_t unit = _cfg.pin_data_in >= 32 ? ADC_UNIT_1 : ADC_UNIT_2;
145  adc_set_data_width(unit, MIC_CLASS_ADC_WIDTH_BITS);
146  err = i2s_set_adc_mode(unit, (adc1_channel_t)adc_ch);
147  if (unit == ADC_UNIT_1)
148  {
149  adc1_config_channel_atten((adc1_channel_t)adc_ch, MIC_CLASS_ADC_ATTEN_DB);
150  }
151  else
152  {
153  adc2_config_channel_atten((adc2_channel_t)adc_ch, MIC_CLASS_ADC_ATTEN_DB);
154  }
155  if (_cfg.i2s_port == I2S_NUM_0)
156  {
157  I2S0.conf2.lcd_en = true;
158  I2S0.conf.rx_right_first = 0;
159  I2S0.conf.rx_msb_shift = 0;
160  I2S0.conf.rx_mono = 0;
161  I2S0.conf.rx_short_sync = 0;
162  I2S0.fifo_conf.rx_fifo_mod = true;
163  I2S0.conf_chan.rx_chan_mod = true;
164  }
165  }
166  else
167 #endif
168  {
169  err = i2s_set_pin(_cfg.i2s_port, &pin_config);
170  }
171 
172  return err;
173  }
174 
175  void Mic_Class::mic_task(void* args)
176  {
177  auto self = (Mic_Class*)args;
178  i2s_start(self->_cfg.i2s_port);
179 
180  int oversampling = self->_cfg.over_sampling;
181  if ( oversampling < 1) { oversampling = 1; }
182  else if (oversampling > 8) { oversampling = 8; }
183  oversampling <<= 1;
184  int32_t gain = self->_cfg.magnification;
185  const float f_gain = (float)gain / oversampling;
186  int32_t offset = 0;
187  size_t src_idx = ~0u;
188  size_t src_len = 0;
189  int32_t sum_value[4] = { 0,0 };
190  int32_t prev_value[2] = { 0, 0 };
191  const bool in_stereo = self->_cfg.stereo;
192  int32_t os_remain = oversampling;
193  const size_t dma_buf_len = self->_cfg.dma_buf_len;
194  int16_t* src_buf = (int16_t*)alloca(dma_buf_len * sizeof(int16_t));
195 
196  i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, portTICK_PERIOD_MS);
197  i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, portTICK_PERIOD_MS);
198 
199  while (self->_task_running)
200  {
201  bool rec_flip = self->_rec_flip;
202  recording_info_t* current_rec = &(self->_rec_info[!rec_flip]);
203  recording_info_t* next_rec = &(self->_rec_info[ rec_flip]);
204 
205  size_t dst_remain = current_rec->length;
206  if (dst_remain == 0)
207  {
208  rec_flip = !rec_flip;
209  self->_rec_flip = rec_flip;
210  xSemaphoreGive(self->_task_semaphore);
211  std::swap(current_rec, next_rec);
212  dst_remain = current_rec->length;
213  if (dst_remain == 0)
214  {
215  self->_is_recording = false;
216  ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
217  src_idx = ~0u;
218  src_len = 0;
219  sum_value[0] = 0;
220  sum_value[1] = 0;
221  continue;
222  }
223  }
224  self->_is_recording = true;
225 
226  for (;;)
227  {
228  if (src_idx >= src_len)
229  {
230  i2s_read(self->_cfg.i2s_port, src_buf, dma_buf_len, &src_len, 100 / portTICK_PERIOD_MS);
231  src_len >>= 1;
232  src_idx = 0;
233  }
234 
235  if (self->_cfg.use_adc)
236  {
237  do
238  {
239 #if defined (CONFIG_IDF_TARGET_ESP32)
240  sum_value[1 - (src_idx & 1)] += (src_buf[src_idx] & 0x0FFF) - 2048;
241 #else
242  sum_value[src_idx & 1] += (src_buf[src_idx] & 0x0FFF) - 2048;
243 #endif
244  ++src_idx;
245  } while (--os_remain && (src_idx < src_len));
246  }
247  else
248  {
249  do
250  {
251 #if defined (CONFIG_IDF_TARGET_ESP32)
252  sum_value[1 - (src_idx & 1)] += src_buf[src_idx];
253 #else
254  sum_value[src_idx & 1] += src_buf[src_idx];
255 #endif
256  ++src_idx;
257  } while (--os_remain && (src_idx < src_len));
258  }
259  if (os_remain) { continue; }
260  os_remain = oversampling;
261 
262  auto sv0 = sum_value[0];
263  auto sv1 = sum_value[1];
264  auto value_tmp = sv0 + sv1;
265  sum_value[0] += offset;
266  sum_value[1] += offset;
267  // Automatic zero level adjustment
268  offset = (32 + offset * 62 - value_tmp) >> 6;
269 
270  int32_t noise_filter = self->_cfg.noise_filter_level;
271  if (noise_filter)
272  {
273  for (int i = 0; i < 2; ++i)
274  {
275  int32_t v = (sum_value[i] * (256 - noise_filter) + prev_value[i] * noise_filter + 128) >> 8;
276  prev_value[i] = v;
277  sum_value[i] = v * f_gain;
278  }
279  }
280  else
281  {
282  for (int i = 0; i < 2; ++i)
283  {
284  sum_value[i] *= f_gain;
285  }
286  }
287 
288  int output_num = 2;
289 
290  if (in_stereo != current_rec->is_stereo)
291  {
292  if (in_stereo)
293  { // stereo -> mono convert.
294  sum_value[0] = (sum_value[0] + sum_value[1] + 1) >> 1;
295  output_num = 1;
296  }
297  else
298  { // mono -> stereo convert.
299  auto tmp = sum_value[1];
300  sum_value[3] = tmp;
301  sum_value[2] = tmp;
302  sum_value[1] = sum_value[0];
303  output_num = 4;
304  }
305  }
306  for (int i = 0; i < output_num; ++i)
307  {
308  auto value = sum_value[i];
309  if (current_rec->is_16bit)
310  {
311  if ( value < INT16_MIN+16) { value = INT16_MIN+16; }
312  else if (value > INT16_MAX-16) { value = INT16_MAX-16; }
313  auto dst = (int16_t*)(current_rec->data);
314  *dst++ = value;
315  current_rec->data = dst;
316  }
317  else
318  {
319  value = ((value + 128) >> 8) + 128;
320  if ( value < 0) { value = 0; }
321  else if (value > 255) { value = 255; }
322  auto dst = (uint8_t*)(current_rec->data);
323  *dst++ = value;
324  current_rec->data = dst;
325  }
326  }
327  sum_value[0] = 0;
328  sum_value[1] = 0;
329  dst_remain -= output_num;
330  if ((int32_t)dst_remain <= 0)
331  {
332  current_rec->length = 0;
333  break;
334  }
335  }
336  }
337  self->_is_recording = false;
338  i2s_stop(self->_cfg.i2s_port);
339 
340  self->_task_handle = nullptr;
341  vTaskDelete(nullptr);
342  }
343 
344  bool Mic_Class::begin(void)
345  {
346  if (_task_running)
347  {
348  auto rate = _calc_rec_rate();
349  if (_rec_sample_rate == rate)
350  {
351  return true;
352  }
353  do { vTaskDelay(1); } while (isRecording());
354  end();
355  _rec_sample_rate = rate;
356  }
357 
358  if (_task_semaphore == nullptr) { _task_semaphore = xSemaphoreCreateBinary(); }
359 
360  bool res = true;
362 
363  res = (ESP_OK == _setup_i2s()) && res;
364  if (res)
365  {
366  size_t stack_size = 1024 + (_cfg.dma_buf_len * sizeof(int16_t));
367  _task_running = true;
368 #if portNUM_PROCESSORS > 1
369  if (_cfg.task_pinned_core < portNUM_PROCESSORS)
370  {
371  xTaskCreatePinnedToCore(mic_task, "mic_task", stack_size, this, _cfg.task_priority, &_task_handle, _cfg.task_pinned_core);
372  }
373  else
374 #endif
375  {
376  xTaskCreate(mic_task, "mic_task", stack_size, this, _cfg.task_priority, &_task_handle);
377  }
378  }
379 
380  return res;
381  }
382 
383  void Mic_Class::end(void)
384  {
385  if (!_task_running) { return; }
386  _task_running = false;
387  if (_task_handle)
388  {
389  if (_task_handle) { xTaskNotifyGive(_task_handle); }
390  do { vTaskDelay(1); } while (_task_handle);
391  }
392 
394  i2s_driver_uninstall(_cfg.i2s_port);
395  }
396 
397  bool Mic_Class::_rec_raw(void* recdata, size_t array_len, bool flg_16bit, uint32_t sample_rate, bool flg_stereo)
398  {
399  recording_info_t info;
400  info.data = recdata;
401  info.length = array_len;
402  info.is_16bit = flg_16bit;
403  info.is_stereo = flg_stereo;
404 
405  _cfg.sample_rate = sample_rate;
406 
407  if (!begin()) { return false; }
408  if (array_len == 0) { return true; }
409  while (_rec_info[_rec_flip].length) { xSemaphoreTake(_task_semaphore, 1); }
410  _rec_info[_rec_flip] = info;
411  if (this->_task_handle)
412  {
413  xTaskNotifyGive(this->_task_handle);
414  }
415  return true;
416  }
417 #endif
418 }
419 #endif
int16_t value[3]
Definition: IMU_Base.hpp:0
int32_t prev_value[3]
Definition: IMU_Class.hpp:12
#define SAMPLE_RATE_TYPE
#define COMM_FORMAT_I2S
esp_err_t _setup_i2s(void)
bool begin(void)
size_t isRecording(void) const
Definition: Mic_Class.hpp:104
volatile bool _task_running
Definition: Mic_Class.hpp:174
recording_info_t _rec_info[2]
Definition: Mic_Class.hpp:159
static void mic_task(void *args)
uint32_t _rec_sample_rate
Definition: Mic_Class.hpp:169
volatile SemaphoreHandle_t _task_semaphore
Definition: Mic_Class.hpp:180
bool(* _cb_set_enabled)(void *args, bool enabled)
Definition: Mic_Class.hpp:171
void * _cb_set_enabled_args
Definition: Mic_Class.hpp:172
uint32_t _calc_rec_rate(void) const
void end(void)
volatile bool _rec_flip
Definition: Mic_Class.hpp:160
TaskHandle_t _task_handle
Definition: Mic_Class.hpp:179
mic_config_t _cfg
Definition: Mic_Class.hpp:168
bool _rec_raw(void *recdata, size_t array_len, bool flg_16bit, uint32_t sample_rate, bool stereo)
Definition: M5Unified.cpp:48
uint8_t task_priority
background task priority
Definition: Mic_Class.hpp:76
i2s_port_t i2s_port
I2S port.
Definition: Mic_Class.hpp:82
int pin_bck
i2s_bclk
Definition: Mic_Class.hpp:40
int pin_data_in
i2s_data_in (for mic)
Definition: Mic_Class.hpp:37
uint8_t over_sampling
Sampling times of obtain the average value.
Definition: Mic_Class.hpp:58
int pin_mck
i2s_mclk
Definition: Mic_Class.hpp:43
size_t dma_buf_count
for I2S dma_buf_count
Definition: Mic_Class.hpp:73
uint32_t sample_rate
input sampling rate (Hz)
Definition: Mic_Class.hpp:49
int pin_ws
i2s_ws (lrck)
Definition: Mic_Class.hpp:46
bool use_adc
use analog input mic ( need only pin_data_in )
Definition: Mic_Class.hpp:67
size_t dma_buf_len
for I2S dma_buf_len
Definition: Mic_Class.hpp:70
bool stereo
use stereo output
Definition: Mic_Class.hpp:52
uint8_t task_pinned_core
background task pinned core
Definition: Mic_Class.hpp:79