arduino-audio-tools
AnalogAudioESP32V1.h
1 #pragma once
2 
3 #include "AudioConfig.h"
4 #if defined(ESP32) && defined(USE_ANALOG) && \
5  ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) || \
6  defined(DOXYGEN)
7 
8 #ifdef ARDUINO
9 # ifndef perimanClearPinBus
10 # define perimanClearPinBus(p) perimanSetPinBus(p, ESP32_BUS_TYPE_INIT, NULL)
11 # endif
12 #endif
13 
14 #include "AudioAnalog/AnalogAudioBase.h"
15 #include "AudioAnalog/AnalogConfigESP32V1.h"
16 #include "AudioTools/AudioStreams.h"
17 #include "AudioTools/AudioStreamsConverter.h"
18 
19 namespace audio_tools {
20 
29 public:
31  AnalogDriverESP32V1() = default;
32 
34  virtual ~AnalogDriverESP32V1() { end(); }
35 
38  TRACEI();
39  bool result = true;
40  this->cfg = cfg;
41 
42  switch (cfg.rx_tx_mode) {
43  case TX_MODE:
44  if (!setup_tx()) {
45  return false;
46  }
47  // convert to 16 bits
48  if (!converter.begin(cfg, 16)) {
49  LOGE("converter");
50  return false;
51  }
52  active_tx = true;
53  break;
54  case RX_MODE:
55  if (!setup_rx()) {
56  return false;
57  }
58  active_rx = true;
59  break;
60  default:
61  LOGE("mode");
62  return false;
63  }
64 
65  active = true;
66  return active;
67  }
68 
70  void end() override {
71  TRACEI();
72 #ifdef HAS_ESP32_DAC
73  if (active_tx) {
74  dac_continuous_del_channels(dac_handle);
75  }
76 #endif
77  if (active_rx) {
78  adc_continuous_stop(adc_handle);
79  // free up resources from ADC
80  adc_continuous_deinit(adc_handle);
81  // free up resources from calibration
82  if (cfg.adc_calibration_active) {
83 #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
84  adc_cali_delete_scheme_curve_fitting(adc_cali_handle);
85 #elif !defined(CONFIG_IDF_TARGET_ESP32H2)
86  adc_cali_delete_scheme_line_fitting(adc_cali_handle);
87 #endif
88  }
89  }
90 
91 #ifdef ARDUINO
92  // Set all used pins/channels to INIT state
93  for(int i = 0; i < cfg.channels; i++){
94  // convert channel to pin
95  adc_channel_t adc_channel = cfg.adc_channels[i];
96  int io_pin;
97  adc_continuous_channel_to_io(ADC_UNIT, adc_channel, &io_pin);
98  if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT){
99  if( !perimanClearPinBus(io_pin) ){
100  LOGE("perimanClearPinBus failed!");
101  return;
102  }
103  }
104  }
105 #endif
106 
107  converter.end();
108  active_tx = false;
109  active_rx = false;
110  active = false;
111  }
112 
113  // writes the data to the DAC
114  size_t write(const uint8_t *src, size_t size_bytes) override {
115  TRACED();
116  // convert any format to int16_t
117  return converter.write(src, size_bytes);
118  }
119 
120 // reads data from DMA buffer
121  size_t readBytes(uint8_t *dest, size_t size_bytes) override {
122  TRACED();
123  // in the future we might use the converter -> for the time beeing we only
124  // support 16 bits
125  return io.readBytes(dest, size_bytes);
126  }
127 
128  // is data in the ADC buffer?
129  int available() override { return active_rx ? DEFAULT_BUFFER_SIZE : 0; }
130 
131 protected:
132  adc_continuous_handle_t adc_handle = nullptr;
133  adc_cali_handle_t adc_cali_handle = nullptr;
134  AnalogConfigESP32V1 cfg;
135  bool active = false;
136  bool active_tx = false;
137  bool active_rx = false;
138  ConverterAutoCenter auto_center;
139 #ifdef HAS_ESP32_DAC
140  dac_continuous_handle_t dac_handle;
141 #endif
142 
144  class IO16Bit : public AudioStream {
145  public:
146  IO16Bit(AnalogDriverESP32V1 *driver) { self = driver; }
147 
148  // write int16_t data to the dac
149  size_t write(const uint8_t *src, size_t size_bytes) override {
150  TRACED();
151 #ifdef HAS_ESP32_DAC
152  size_t result = 0;
153 
154  // convert signed 16 bit to unsigned 8 bits
155  int16_t *data16 = (int16_t *)src;
156  uint8_t *data8 = (uint8_t *)src;
157  int samples = size_bytes / 2;
158  for (int j = 0; j < samples; j++) {
159  data8[j] = (32768u + data16[j]) >> 8;
160  }
161 
162  if (dac_continuous_write(self->dac_handle, data8, samples, &result,
163  self->cfg.timeout) != ESP_OK) {
164  result = 0;
165  }
166  return result * 2;
167 #else
168  return 0;
169 #endif
170  }
171 
172  // provides int16_t data from the adc
173  size_t readBytes(uint8_t *dest, size_t size_bytes) override {
174  TRACED();
175  size_t total_bytes = 0;
176  // allocate buffer for the requested bytes
177  int sample_count = size_bytes / sizeof(int16_t);
178  adc_digi_output_data_t result_data[sample_count];
179  memset(&result_data, 0, sizeof(result_data));
180  uint32_t result_cont;
181  if (adc_continuous_read(self->adc_handle, (uint8_t *)result_data,
182  sizeof(result_data), &result_cont,
183  self->cfg.timeout) == ESP_OK) {
184  // Result must fit into uint16_t !
185  uint16_t *result16 = (uint16_t *)dest;
186  uint16_t *end = (uint16_t *)(dest + size_bytes);
187  int result_count = result_cont / sizeof(adc_digi_output_data_t);
188  LOGD("adc_continuous_read -> %u bytes / %d samples", (unsigned) result_cont,
189  result_count);
190 
191  for (int i = 0; i < result_count; i++) {
192  adc_digi_output_data_t *p = &result_data[i];
193  uint16_t chan_num = AUDIO_ADC_GET_CHANNEL(p);
194  uint32_t data = AUDIO_ADC_GET_DATA(p);
195 
196  if (isValidADCChannel((adc_channel_t)chan_num)) {
197  LOGD("Idx: %d, channel: %d, data: %u", i, chan_num, (unsigned) data);
198 
199  assert(result16 < end); // make sure we dont write past the end
200  if (self->cfg.adc_calibration_active) {
201  // Provide result in millivolts
202  int data_milliVolts;
203  auto err = adc_cali_raw_to_voltage(self->adc_cali_handle, data,
204  &data_milliVolts);
205  if (err == ESP_OK) {
206  int result_full_range = data_milliVolts;
207  *result16 = result_full_range;
208  assert(result_full_range ==
209  (int)*result16); // check that we did not loose any bytes
210  result16++;
211  total_bytes += sizeof(uint16_t);
212  } else {
213  LOGE("adc_cali_raw_to_voltage: %d", err);
214  }
215  } else {
216  *result16 = data;
217  assert(
218  data ==
219  (uint32_t)*result16); // check that we did not loose any bytes
220  result16++;
221  total_bytes += sizeof(uint16_t);
222  }
223 
224  } else {
225  LOGD("invalid channel: %d, data: %u", chan_num, (unsigned) data);
226  }
227  }
228  // make sure that the center is at 0, so the result will be int16_t
229  if (self->cfg.is_auto_center_read) {
230  self->auto_center.convert(dest, total_bytes);
231  }
232 
233  } else {
234  LOGE("adc_continuous_read unsuccessful");
235  total_bytes = 0;
236  }
237  return total_bytes;
238  }
239 
240  protected:
241  AnalogDriverESP32V1 *self;
242 
243  bool isValidADCChannel(adc_channel_t channel) {
244  for (int j = 0; j < self->cfg.channels; j++) {
245  if (self->cfg.adc_channels[j] == channel) {
246  return true;
247  }
248  }
249  return false;
250  }
251 
252  } io{this};
253 
254  NumberFormatConverterStream converter{io};
255 
256 #ifdef HAS_ESP32_DAC
257  bool setup_tx() {
258  dac_continuous_config_t cont_cfg = {
259  .chan_mask =
260  cfg.channels == 1 ? cfg.dac_mono_channel : DAC_CHANNEL_MASK_ALL,
261  .desc_num = (uint32_t)cfg.buffer_count,
262  .buf_size = (size_t)cfg.buffer_size,
263  .freq_hz = (uint32_t)cfg.sample_rate,
264  .offset = 0,
265  .clk_src =
266  cfg.use_apll
267  ? DAC_DIGI_CLK_SRC_APLL
268  : DAC_DIGI_CLK_SRC_DEFAULT, // Using APLL as clock source to
269  // get a wider frequency range
270  .chan_mode = DAC_CHANNEL_MODE_ALTER,
271  };
272  // Allocate continuous channels
273  if (dac_continuous_new_channels(&cont_cfg, &dac_handle) != ESP_OK) {
274  LOGE("new_channels");
275  return false;
276  }
277  if (dac_continuous_enable(dac_handle) != ESP_OK) {
278  LOGE("enable");
279  return false;
280  }
281  return true;
282  }
283 
284 #else
285  bool setup_tx() {
286  LOGE("DAC not supported");
287  return false;
288  }
289 #endif
290 
291  bool setup_rx() {
292 
293  adc_channel_t adc_channel;
294  int io_pin;
295  esp_err_t err;
296 
297  if (!checkADCChannels())
298  return false;
299  if (!checkADCSampleRate())
300  return false;
301  if (!checkADCBitWidth())
302  return false;
303  if (!checkADCBitsPerSample())
304  return false;
305 
306  if(adc_handle != nullptr){
307  LOGE("adc unit %u continuous is already initialized. Please call end() first!", ADC_UNIT);
308  return false;
309  }
310 
311 #ifdef ARDUINO
312  // Set periman deinit callback
313  // TODO, currently handled in end() method
314 
315  // Set the pins/channels to INIT state
316  for(int i = 0; i < cfg.channels; i++){
317  // convert channel to pin
318  adc_channel = cfg.adc_channels[i];
319  adc_continuous_channel_to_io(ADC_UNIT, adc_channel, &io_pin);
320  if( !perimanClearPinBus(io_pin) ){
321  LOGE("perimanClearPinBus failed!");
322  return false;
323  }
324  }
325 #endif
326 
327  // Determine conv_frame_size which must be multiple of
328  // SOC_ADC_DIGI_DATA_BYTES_PER_CONV
329  uint32_t conv_frame_size =
330  (uint32_t)cfg.buffer_size * SOC_ADC_DIGI_RESULT_BYTES;
331  uint8_t calc_multiple_diff =
332  conv_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV;
333  if (calc_multiple_diff != 0) {
334  conv_frame_size = (conv_frame_size + calc_multiple_diff);
335  }
336 
337  //Conversion frame size buffer cant be bigger than 4092 bytes
338  if(conv_frame_size > 4092){
339  LOGE("buffer_size is too big. Please set lower buffer_size.");
340  return false;
341  } else {
342  LOGD("buffer_size %u, conv_frame_size: %u", cfg.buffer_size, (unsigned) conv_frame_size);
343  }
344 
345  adc_continuous_handle_cfg_t adc_config = {
346  .max_store_buf_size = (uint32_t)conv_frame_size * cfg.buffer_count,
347  .conv_frame_size = conv_frame_size,
348  };
349 
350  // Create adc_continuous handle
351  err = adc_continuous_new_handle(&adc_config, &adc_handle);
352  if (err != ESP_OK) {
353  LOGE("adc_continuous_new_handle failed with error: %d", err);
354  return false;
355  } else {
356  LOGD("adc_continuous_new_handle successful");
357  }
358 
359  adc_digi_pattern_config_t adc_pattern[cfg.channels] = {};
360  //dig_cfg.pattern_num = cfg.channels;
361  for (int i = 0; i < cfg.channels; i++) {
362  uint8_t ch = cfg.adc_channels[i] & 0x7;
363  adc_pattern[i].atten = cfg.adc_attenuation;
364  adc_pattern[i].channel = ch;
365  adc_pattern[i].unit = ADC_UNIT;
366  adc_pattern[i].bit_width = cfg.adc_bit_width;
367  }
368  //dig_cfg.adc_pattern = adc_pattern;
370  adc_continuous_config_t dig_cfg = {
371  .pattern_num = cfg.channels,
372  .adc_pattern = adc_pattern,
373  .sample_freq_hz = (uint32_t)cfg.sample_rate * cfg.channels,
374  .conv_mode = cfg.adc_conversion_mode,
375  .format = cfg.adc_output_type,
376  };
377 
378 
379  LOGI("dig_cfg.sample_freq_hz: %u", (unsigned)dig_cfg.sample_freq_hz);
380  LOGI("dig_cfg.conv_mode: %u", dig_cfg.conv_mode);
381  LOGI("dig_cfg.format: %u", dig_cfg.format);
382  for (int i = 0; i < cfg.channels; i++) {
383  LOGI("dig_cfg.adc_pattern[%d].atten: %u", i,
384  dig_cfg.adc_pattern[i].atten);
385  LOGI("dig_cfg.adc_pattern[%d].channel: %u", i,
386  dig_cfg.adc_pattern[i].channel);
387  LOGI("dig_cfg.adc_pattern[%d].unit: %u", i, dig_cfg.adc_pattern[i].unit);
388  LOGI("dig_cfg.adc_pattern[%d].bit_width: %u", i,
389  dig_cfg.adc_pattern[i].bit_width);
390  }
391 
392  // Initialize ADC
393  err = adc_continuous_config(adc_handle, &dig_cfg);
394  if (err != ESP_OK) {
395  LOGE("adc_continuous_config unsuccessful with error: %d", err);
396  return false;
397  }
398  LOGI("adc_continuous_config successful");
399 
400  // Set up optional calibration
401  if (!setupADCCalibration()) {
402  return false;
403  }
404 
405 #ifdef ARDUINO
406  // Attach the pins to the ADC unit
407  for(int i = 0; i < cfg.channels; i++){
408  adc_channel = cfg.adc_channels[i];
409  adc_continuous_channel_to_io(ADC_UNIT, adc_channel, &io_pin);
410  // perimanSetPinBus: uint8_t pin, peripheral_bus_type_t type, void * bus, int8_t bus_num, int8_t bus_channel
411  if( !perimanSetPinBus(io_pin, ESP32_BUS_TYPE_ADC_CONT, (void *)(ADC_UNIT+1), ADC_UNIT, adc_channel) ) {
412  LOGE("perimanSetPinBus to Continuous an ADC Unit %u failed!", ADC_UNIT);
413  return false;
414  }
415  }
416 #endif
417 
418  // Start ADC
419  err = adc_continuous_start(adc_handle);
420  if (err != ESP_OK) {
421  LOGE("adc_continuous_start unsuccessful with error: %d", err);
422  return false;
423  }
424 
425  // setup up optimal auto center which puts the avg at 0
426  auto_center.begin(cfg.channels, cfg.bits_per_sample, true);
427 
428  LOGI("adc_continuous_start successful");
429  return true;
430  }
431 
432  bool checkADCBitWidth() {
433  if ((cfg.adc_bit_width < SOC_ADC_DIGI_MIN_BITWIDTH) ||
434  (cfg.adc_bit_width > SOC_ADC_DIGI_MAX_BITWIDTH)) {
435  LOGE("adc bit width: %u cannot be set, range: %u to %u", cfg.adc_bit_width,
436  (unsigned)SOC_ADC_DIGI_MIN_BITWIDTH, (unsigned)SOC_ADC_DIGI_MAX_BITWIDTH);
437  return false;
438  }
439  LOGI("adc bit width: %u, range: %u to %u", cfg.adc_bit_width,
440  (unsigned)SOC_ADC_DIGI_MIN_BITWIDTH, (unsigned)SOC_ADC_DIGI_MAX_BITWIDTH);
441  return true;
442  }
443 
444  bool checkADCChannels() {
445  int io_pin;
446  adc_channel_t adc_channel;
447 
448  int max_channels = sizeof(cfg.adc_channels) / sizeof(adc_channel_t);
449  if (cfg.channels > max_channels) {
450  LOGE("number of channels: %d, max: %d", cfg.channels, max_channels);
451  return false;
452  }
453  LOGI("channels: %d, max: %d", cfg.channels, max_channels);
454 
455  // Lets make sure the adc channels are available
456  for(int i = 0; i < cfg.channels; i++){
457  adc_channel = cfg.adc_channels[i];
458  auto err = adc_continuous_channel_to_io(ADC_UNIT, adc_channel, &io_pin);
459  if(err != ESP_OK){
460  LOGE("ADC channel %u is not available on ADC unit %u", adc_channel, ADC_UNIT);
461  return false;
462  } else {
463  LOGI("ADC channel %u is on pin %u", adc_channel, io_pin);
464  }
465  }
466  return true;
467  }
468 
469  bool checkADCSampleRate() {
470  int sample_rate = cfg.sample_rate * cfg.channels;
471  if ((sample_rate < SOC_ADC_SAMPLE_FREQ_THRES_LOW) ||
472  (sample_rate > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)) {
473  LOGE("sample rate eff: %u can not be set, range: %u to %u",sample_rate,
474  SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH);
475  return false;
476  }
477  LOGI("sample rate eff: %u, range: %u to %u", sample_rate,
478  SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH);
479 
480  return true;
481  }
482 
483  bool checkADCBitsPerSample() {
484  int supported_bits = 16; // for the time beeing we support only 16 bits!
485 
486  // calculated default value if nothing is specified
487  if (cfg.bits_per_sample == 0) {
488  cfg.bits_per_sample = supported_bits;
489  LOGI("bits per sample set to: %d", cfg.bits_per_sample);
490  }
491 
492  // check bits_per_sample
493  if (cfg.bits_per_sample != supported_bits) {
494  LOGE("bits per sample: error. It should be: %d but is %d",
495  supported_bits, cfg.bits_per_sample);
496  return false;
497  }
498  LOGI("bits per sample: %d", cfg.bits_per_sample);
499  return true;
500  }
501 
502  bool setupADCCalibration() {
503  if (!cfg.adc_calibration_active)
504  return true;
505 
506  // Initialize ADC calibration handle
507  // Calibration is applied to an ADC unit (not per channel).
508 
509  // setup calibration only when requested
510  if (adc_cali_handle == NULL) {
511 #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
512  // curve fitting is preferred
513  adc_cali_curve_fitting_config_t cali_config;
514  cali_config.unit_id = ADC_UNIT;
515  cali_config.atten = (adc_atten_t)cfg.adc_attenuation;
516  cali_config.bitwidth = (adc_bitwidth_t)cfg.adc_bit_width;
517  auto err =
518  adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle);
519 #elif !defined(CONFIG_IDF_TARGET_ESP32H2)
520  // line fitting
521  adc_cali_line_fitting_config_t cali_config;
522  cali_config.unit_id = ADC_UNIT;
523  cali_config.atten = (adc_atten_t)cfg.adc_attenuation;
524  cali_config.bitwidth = (adc_bitwidth_t)cfg.adc_bit_width;
525  auto err =
526  adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle);
527 #endif
528  if (err != ESP_OK) {
529  LOGE("creating cali handle failed for ADC%d with atten %d and bitwidth "
530  "%d",
531  ADC_UNIT, cfg.adc_attenuation, cfg.adc_bit_width);
532  return false;
533  } else {
534  LOGI("created cali handle for ADC%d with atten %d and bitwidth %d",
535  ADC_UNIT, cfg.adc_attenuation, cfg.adc_bit_width);
536  }
537  }
538  return true;
539  }
540 
541 };
542 
544 using AnalogDriver = AnalogDriverESP32V1;
545 
546 } // namespace audio_tools
547 
548 #endif
ESP32 specific configuration for i2s input via adc using the adc_continuous API.
Definition: AnalogConfigESP32V1.h:57
adc_channel_t adc_channels[2]
ESP32: ADC_CHANNEL_6, ADC_CHANNEL_7; others ADC_CHANNEL_2, ADC_CHANNEL_3.
Definition: AnalogConfigESP32V1.h:81
Definition: AnalogAudioBase.h:13
conversion between int16_t and other formats
Definition: AnalogAudioESP32V1.h:144
AnalogAudioStream: A very fast DAC using DMA using the new dac_continuous API.
Definition: AnalogAudioESP32V1.h:28
virtual ~AnalogDriverESP32V1()
Destructor.
Definition: AnalogAudioESP32V1.h:34
bool setup_rx()
Definition: AnalogAudioESP32V1.h:291
void end() override
stops the I2S and uninstalls the driver
Definition: AnalogAudioESP32V1.h:70
bool begin(AnalogConfigESP32V1 cfg)
starts the DAC
Definition: AnalogAudioESP32V1.h:37
AnalogDriverESP32V1()=default
Default constructor.
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: AudioStreams.h:24
Converter which converts between bits_per_sample and 16 bits. The templated NumberFormatConverterStre...
Definition: AudioStreamsConverter.h:443
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AnalogAudio.h:10
AnalogDriverArduino AnalogDriver
AnalogAudioStream.
Definition: AnalogAudioArduino.h:258
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55