arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
AnalogDriverESP32V1.h
1#pragma once
2
3#include "AudioToolsConfig.h"
4
5#if defined(ESP32) && defined(USE_ANALOG) && \
6 ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) || 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 "AudioTools/CoreAudio/AudioAnalog/AnalogDriverBase.h"
15#include "AudioTools/CoreAudio/AudioAnalog/AnalogConfigESP32V1.h"
16#include "AudioTools/CoreAudio/AudioStreams.h"
17#include "AudioTools/CoreAudio/AudioStreamsConverter.h"
18
19namespace audio_tools {
20
29public:
32
35 end();
36 }
37
41 TRACEI();
42 bool result = true;
43 this->cfg = cfg;
44
45 switch (cfg.rx_tx_mode) {
46 case TX_MODE:
47 if (!setup_tx()) return false;
48 // convert to 16 bits
49 if (!converter.begin(cfg, 16)) {
50 LOGE("converter");
51 return false;
52 }
53 active_tx = true;
54 break;
55 case RX_MODE:
56 if (!setup_rx()) return false;
57 active_rx = true;
58 break;
59 default:
60 LOGE( "Unsupported MODE: %d", cfg.rx_tx_mode);
61 return false;
62 }
63
64 active = true;
65 return active;
66 }
67
70 void end() override {
71 TRACEI();
72 if (active_tx) {
73 cleanup_tx();
74 }
75 if (active_rx) {
76 cleanup_rx();
77 }
78
79 converter.end();
80
81 active_tx = false;
82 active_rx = false;
83 active = false;
84 }
85
86 // Writes the data to the Digital to Analog Converter
87 // ----------------------------------------------------------
88 size_t write(const uint8_t *src, size_t size_bytes) override {
89 // TRACED();
90 // convert any format to int16_t
91 return converter.write(src, size_bytes);
92 }
93
94 // Reads data from DMA buffer of the Analog to Digital Converter
95 // ----------------------------------------------------------
96 size_t readBytes(uint8_t *dest, size_t size_bytes) override {
97 // TRACED();
98 // Use the IO16Bit class for reading
99 return io.readBytes(dest, size_bytes);
100 }
101
102 // How much data will there be available after reading ADC buffer
103 // ----------------------------------------------------------
104 int available() override {
105 return active_rx ? (uint32_t)(cfg.buffer_size * sizeof(int16_t)) : 0;
106 }
107
108protected:
109
113 template<typename T>
114 class FIFO {
115 public:
116
117 FIFO() : size_(0), buffer_(nullptr), head_(0), tail_(0), count_(0) {}
118
119 FIFO(size_t size) : size_(size), buffer_(new T[size]), head_(0), tail_(0), count_(0) {}
120
121 ~FIFO() {
122 delete[] buffer_;
123 //LOGD("FIFO destroyed: size: %d, count: %d", size_, count_);
124 }
125
126 bool push(const T& value) {
127 if (count_ < size_) {
128 buffer_[tail_] = value;
129 //LOGD("FIFO push - Value: %d at location: %d", value, tail_);
130 tail_ = (tail_ + 1) % size_;
131 count_++;
132 //LOGD("FIFO push updated tail: %d, count: %d", tail_, count_);
133 return true;
134 }
135 //LOGD("FIFO push failed - count %d > size %d", value, count_, size_);
136 return false; // Buffer full
137 }
138
139 bool pop(T& value) {
140 if (count_ > 0) {
141 value = buffer_[head_];
142 //LOGD("FIFO pop - Value: %d at location: %d", value, head_);
143 head_ = (head_ + 1) % size_;
144 count_--;
145 //LOGD("FIFO pop updated head: %d, count: %d", head_, count_);
146 return true;
147 }
148 //LOGD("FIFO pop failed - count %d == 0", count_);
149 return false; // Buffer empty
150 }
151
152 size_t size() const {
153 return count_;
154 }
155
156 bool empty() const {
157 return count_ == 0;
158 }
159
160 bool full() const {
161 return count_ == size_;
162 }
163
164 void clear() {
165 head_ = 0;
166 tail_ = 0;
167 count_ = 0;
168 }
169
170 private:
171 size_t size_;
172 T* buffer_;
173 size_t head_;
174 size_t tail_;
175 size_t count_;
176 };
177
178 adc_continuous_handle_t adc_handle = nullptr;
179 adc_cali_handle_t adc_cali_handle = nullptr;
181 bool active = false;
182 bool active_tx = false;
183 bool active_rx = false;
184 ConverterAutoCenter auto_center;
185 #ifdef HAS_ESP32_DAC
186 dac_continuous_handle_t dac_handle = nullptr;
187 #endif
188
189 // create array of FIFO buffers, one for each channel
190 FIFO<ADC_DATA_TYPE>** fifo_buffers;
191
192 // 16Bit Audiostream for ESP32
193 // ----------------------------------------------------------
194 class IO16Bit : public AudioStream {
195 public:
196 IO16Bit(AnalogDriverESP32V1 *driver) { self = driver; }
197
198 // Write int16_t data to the Digital to Analog Converter
199 // ----------------------------------------------------------
200 size_t write(const uint8_t *src, size_t size_bytes) override {
201 // TRACED();
202 #ifdef HAS_ESP32_DAC
203 size_t result = 0;
204 // Convert signed 16-bit to unsigned 8-bit
205 int16_t *data16 = (int16_t *)src;
206 uint8_t *data8 = (uint8_t *)src;
207 int samples = size_bytes / 2;
208
209 // Process data in batches to reduce the number of conversions and writes
210 for (int j = 0; j < samples; j++) {
211 data8[j] = (32768u + data16[j]) >> 8;
212 }
213
214 if (dac_continuous_write(self->dac_handle, data8, samples, &result, self->cfg.timeout) != ESP_OK) {
215 result = 0;
216 }
217 return result * 2;
218 #else
219 return 0;
220 #endif
221 }
222
223 // Read int16_t data from Analog to Digital Converter
224 // ----------------------------------------------------------
225 // FYI
226 // typedef struct {
227 // union {
228 // struct {
229 // uint16_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
230 // uint16_t channel: 4; /*!<ADC channel index info. */
231 // } type1; /*!<ADC type1 */
232 // struct {
233 // uint16_t data: 11; /*!<ADC real output data info. Resolution: 11 bit. */
234 // uint16_t channel: 4; /*!<ADC channel index info. For ESP32-S2:
235 // If (channel < ADC_CHANNEL_MAX), The data is valid.
236 // If (channel > ADC_CHANNEL_MAX), The data is invalid. */
237 // uint16_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
238 // } type2; /*!<When the configured output format is 11bit.*/
239 // uint16_t val; /*!<Raw data value */
240 // };
241 // } adc_digi_output_data_t;
242
243 size_t readBytes(uint8_t *dest, size_t size_bytes) {
244 // TRACED();
245
246 size_t total_bytes = 0;
247 size_t bytes_provided = 0;
248 int min_samples_in_fifo_per_channel = 0;
249 int max_samples_in_fifo_per_channel = 0;
250 int samples_read =0;
251 int fifo_size = 0;
252 int idx = -1;
253 int samples_provided_per_channel = 0;
254 int data_milliVolts = 0;
255
256 int samples_requested = size_bytes / sizeof(int16_t);
257 int samples_requested_per_channel = samples_requested/self->cfg.channels;
258 // for the adc_continuous_read function
259 adc_digi_output_data_t* result_data = (adc_digi_output_data_t*)malloc(samples_requested * sizeof(adc_digi_output_data_t));
260 if (result_data == NULL) {
261 LOGE("Failed to allocate memory for result_data");
262 return 0; // Handle memory allocation failure
263 }
264 memset(result_data, 0, samples_requested * sizeof(adc_digi_output_data_t));
265 uint32_t bytes_read; // bytes from ADC buffer read
266
267 // for output buffer
268 uint16_t *result16 = (uint16_t *)dest; // pointer to the destination buffer
269 uint16_t *end = (uint16_t *)(dest + size_bytes); // pointer to the end of the destination buffer
270
271 // 1) read the requested bytes from the buffer
272 // LOGI("adc_continuous_read request:%d samples %d bytes requested", samples_requested, (uint32_t)(samples_requested * sizeof(adc_digi_output_data_t)));
273 if (adc_continuous_read(self->adc_handle, (uint8_t *)result_data, (uint32_t)(samples_requested * sizeof(adc_digi_output_data_t)), &bytes_read, (uint32_t)self->cfg.timeout) == ESP_OK) {
274 samples_read = bytes_read / sizeof(adc_digi_output_data_t);
275 LOGD("adc_continuous_read -> %u bytes / %d samples of %d bytes requested", (unsigned)bytes_read, samples_read, (int)(samples_requested * sizeof(adc_digi_output_data_t)));
276
277 // Parse and store data in FIFO buffers
278 for (int i = 0; i < samples_read; i++) {
279 adc_digi_output_data_t *p = &result_data[i];
280 ADC_CHANNEL_TYPE chan_num = AUDIO_ADC_GET_CHANNEL(p);
281 ADC_DATA_TYPE data = AUDIO_ADC_GET_DATA(p);
282
283 // Find the index of the channel in the configured channels
284 idx = -1;
285 for (int j = 0; j < self->cfg.channels; ++j) {
286 if (self->cfg.adc_channels[j] == chan_num) {
287 idx = j;
288 break;
289 }
290 }
291 // Push the data to the corresponding FIFO buffer
292 if (idx >= 0) {
293 if (self->fifo_buffers[idx]->push(data)) {
294 LOGD("Sample %d, FIFO %d, ch %u, d %u", i, idx, (unsigned)chan_num, (unsigned)data);
295 } else {
296 LOGE("Sample %d, FIFO buffer is full, ch %u, d %u", i, (unsigned)chan_num, (unsigned)data);
297 }
298 } else {
299 LOGE("Sample %d, ch %u not found in configuration, d: %u", i, (unsigned)chan_num, (unsigned)data);
300 for (int k = 0; k < self->cfg.channels; ++k) {
301 LOGE("Available config ch: %u", self->cfg.adc_channels[k]);
302 }
303 }
304
305 }
306
307 // Determine min number of samples from all FIFO buffers
308 min_samples_in_fifo_per_channel = self->fifo_buffers[0]->size();
309 for (int i = 1; i < self->cfg.channels; i++) {
310 fifo_size = self->fifo_buffers[i]->size();
311 if (fifo_size < min_samples_in_fifo_per_channel) {
312 min_samples_in_fifo_per_channel = fifo_size;
313 }
314 }
315
316 // 2) If necessary, top off the FIFO buffers to return the requested number of bytes
317 while (samples_requested_per_channel > min_samples_in_fifo_per_channel) {
318
319 // obtain two extra sets of data (2 because number of bytes requested from ADC buffer needs to be divisible by 4)
320 // LOGI("adc_continuous_read request:%d samples %d bytes requested", samples_requested, (uint32_t)(samples_requested * sizeof(adc_digi_output_data_t)));
321 if (adc_continuous_read(self->adc_handle, (uint8_t *)result_data, (uint32_t)(2*self->cfg.channels * sizeof(adc_digi_output_data_t)), &bytes_read, (uint32_t)self->cfg.timeout) != ESP_OK) {
322 LOGE("Top off, adc_continuous_read unsuccessful");
323 break;
324 }
325
326 // Parse the additional data
327 samples_read = bytes_read / sizeof(adc_digi_output_data_t);
328 LOGD("Top Off: Requested %d samples per Channel, Min samples in FIFO: %d, Read additional %d bytes / %d samples", samples_requested_per_channel, min_samples_in_fifo_per_channel, (unsigned)bytes_read, samples_read);
329
330 for (int i = 0; i < samples_read; i++) {
331 adc_digi_output_data_t *p = &result_data[i];
332 ADC_CHANNEL_TYPE chan_num = AUDIO_ADC_GET_CHANNEL(p);
333 ADC_DATA_TYPE data = AUDIO_ADC_GET_DATA(p);
334
335 // Find the index of the channel in the configured channels
336 idx = -1;
337 for (int j = 0; j < self->cfg.channels; ++j) {
338 if (self->cfg.adc_channels[j] == chan_num) {
339 idx = j;
340 break;
341 }
342 }
343 // Push the data to the corresponding FIFO buffer
344 if (idx >= 0) {
345 if (self->fifo_buffers[idx]->push(data)) {
346 LOGD("Top Off Sample %d, FIFO %d, ch %u, d %u", i, idx, (unsigned)chan_num, (unsigned)data);
347 } else {
348 LOGE("Top Off Sample %d, FIFO buffer is full, ch %u, d %u", i, (unsigned)chan_num, (unsigned)data);
349 }
350 } else {
351 LOGE("Top Off Sample %d, ch %u not found in configuration, d %u", i, (unsigned)chan_num, (unsigned)data);
352 for (int k = 0; k < self->cfg.channels; ++k) {
353 LOGE("Available config ch: %u", self->cfg.adc_channels[k]);
354 }
355 }
356 }
357
358 // Determine the updated minimal number of samples in FIFO buffers
359 min_samples_in_fifo_per_channel = self->fifo_buffers[0]->size();
360 max_samples_in_fifo_per_channel = self->fifo_buffers[0]->size();
361 for (int i = 1; i < self->cfg.channels; i++) {
362 fifo_size = self->fifo_buffers[i]->size();
363 if (fifo_size < min_samples_in_fifo_per_channel) {
364 min_samples_in_fifo_per_channel = fifo_size;
365 }
366 if (fifo_size > max_samples_in_fifo_per_channel) {
367 max_samples_in_fifo_per_channel = fifo_size;
368 }
369 }
370 LOGD("Min # of samples in FIFO: %d, Max # of samples in FIFO: %d", min_samples_in_fifo_per_channel, max_samples_in_fifo_per_channel);
371 }
372
373 // 3) Calibrate and copy data to the output buffer
374 if (samples_requested_per_channel <= min_samples_in_fifo_per_channel) {
375 LOGD("Going to copying %d samples of %d samples/channel to output buffer", samples_requested, samples_requested_per_channel);
376 samples_provided_per_channel = samples_requested_per_channel;
377 } else {
378 // This should not happen as we topped off the FIFO buffers in step 2)
379 LOGE("Only %d samples per channel available for output buffer", min_samples_in_fifo_per_channel);
380 samples_provided_per_channel = min_samples_in_fifo_per_channel;
381 }
382
383 for (int i = 0; i < samples_provided_per_channel; i++) {
384 for (int j = 0; j < self->cfg.channels; j++) {
385 ADC_DATA_TYPE data;
386 self->fifo_buffers[j]->pop(data);
387 if (result16 < end) {
388 if (self->cfg.adc_calibration_active) {
389 // Provide result in millivolts
390 auto err = adc_cali_raw_to_voltage(self->adc_cali_handle, (int)data, &data_milliVolts);
391 if (err == ESP_OK) {
392 *result16 = static_cast<int16_t>(data_milliVolts);
393 } else {
394 LOGE("adc_cali_raw_to_voltage error: %d", err);
395 *result16 = 0;
396 }
397 } else {
398 *result16 = data;
399 }
400 result16++;
401 } else {
402 LOGE("Buffer write overflow, skipping data");
403 }
404 }
405 }
406
407 bytes_provided = samples_provided_per_channel * self->cfg.channels * sizeof(int16_t);
408
409 // 4) Engage centering if enabled
410 if (self->cfg.is_auto_center_read) {
411 self->auto_center.convert(dest, bytes_provided);
412 }
413
414 } else {
415 LOGE("adc_continuous_read unsuccessful");
416 bytes_provided = 0;
417 }
418 free(result_data);
419 return bytes_provided;
420 }
421
422 protected:
423 AnalogDriverESP32V1 *self = nullptr;
424
425 } io{this};
426
427 NumberFormatConverterStream converter{io};
428
429 // Setup Digital to Analog
430 // ----------------------------------------------------------
431 #ifdef HAS_ESP32_DAC
432 bool setup_tx() {
433 dac_continuous_config_t cont_cfg = {
434 .chan_mask = cfg.channels == 1 ? cfg.dac_mono_channel : DAC_CHANNEL_MASK_ALL,
435 .desc_num = (uint32_t)cfg.buffer_count,
436 .buf_size = (size_t)cfg.buffer_size,
437 .freq_hz = (uint32_t)cfg.sample_rate,
438 .offset = 0,
439 .clk_src = cfg.use_apll ? DAC_DIGI_CLK_SRC_APLL : DAC_DIGI_CLK_SRC_DEFAULT, // Using APLL as clock source to get a wider frequency range
440 .chan_mode = cfg.channels == 1 ? DAC_CHANNEL_MODE_SIMUL : DAC_CHANNEL_MODE_ALTER,
441 };
442 // Allocate continuous channels
443 if (dac_continuous_new_channels(&cont_cfg, &dac_handle) != ESP_OK) {
444 LOGE("new_channels");
445 return false;
446 }
447 if (dac_continuous_enable(dac_handle) != ESP_OK) {
448 LOGE("enable");
449 return false;
450 }
451 return true;
452 }
453 #else
454 bool setup_tx() {
455 LOGE("DAC not supported");
456 return false;
457 }
458 #endif
459
460 // Setup Analog to Digital Converter
461 // ----------------------------------------------------------
462 bool setup_rx() {
463 adc_channel_t adc_channel;
464 int io_pin;
465 esp_err_t err;
466
467 // Check the configuration
468 if (!checkADCChannels()) return false;
469 if (!checkADCSampleRate()) return false;
470 if (!checkADCBitWidth()) return false;
471 if (!checkADCBitsPerSample()) return false;
472
473 if (adc_handle != nullptr) {
474 LOGE("adc unit %u continuous is already initialized. Please call end() first!", cfg.adc_unit);
475 return false;
476 }
477
478 #ifdef ARDUINO
479 // Set periman deinit callback
480 // TODO, currently handled in end() method
481
482 // Set the pins/channels to INIT state
483 for (int i = 0; i < cfg.channels; i++) {
484 adc_channel = cfg.adc_channels[i];
485 adc_continuous_channel_to_io(cfg.adc_unit, adc_channel, &io_pin);
486 if (!perimanClearPinBus(io_pin)) {
487 LOGE("perimanClearPinBus failed!");
488 return false;
489 }
490 }
491 #endif
492
493 // Determine conv_frame_size which must be multiple of SOC_ADC_DIGI_DATA_BYTES_PER_CONV
494 // Old Code
495 uint32_t conv_frame_size = (uint32_t)cfg.buffer_size * SOC_ADC_DIGI_RESULT_BYTES;
496 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
497 uint8_t calc_multiple = conv_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV;
498 if (calc_multiple != 0) {
499 conv_frame_size = (uint32_t) (conv_frame_size + calc_multiple);
500 }
501 #endif
502
503 // Proposed new Code
504 // uint32_t conv_frame_size = (uint32_t)cfg.buffer_size * SOC_ADC_DIGI_RESULT_BYTES;
505 // #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
506 // uint32_t conv_frame_size = (uint32_t)cfg.buffer_size * SOC_ADC_DIGI_DATA_BYTES_PER_CONV
507 // #endif
508
509 // Conversion frame size buffer can't be bigger than 4092 bytes
510 if (conv_frame_size > 4092) {
511 LOGE("buffer_size is too big. Please set lower buffer_size.");
512 return false;
513 } else {
514 LOGI("buffer_size: %u samples, conv_frame_size: %u bytes", cfg.buffer_size, (unsigned)conv_frame_size);
515 }
516
517 // Create adc_continuous handle
518 adc_continuous_handle_cfg_t adc_config;
519 adc_config.max_store_buf_size = (uint32_t)conv_frame_size * 2;
520 adc_config.conv_frame_size = (uint32_t) conv_frame_size;
521#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
522 adc_config.flags.flush_pool = true;
523#endif
524 err = adc_continuous_new_handle(&adc_config, &adc_handle);
525 if (err != ESP_OK) {
526 LOGE("adc_continuous_new_handle failed with error: %d", err);
527 return false;
528 } else {
529 LOGI("adc_continuous_new_handle successful");
530 }
531
532 // Configure the ADC patterns
533 adc_digi_pattern_config_t adc_pattern[cfg.channels] = {};
534 for (int i = 0; i < cfg.channels; i++) {
535 uint8_t ch = cfg.adc_channels[i];
536 adc_pattern[i].atten = (uint8_t) cfg.adc_attenuation;
537 adc_pattern[i].channel = (uint8_t)ch;
538 adc_pattern[i].unit = (uint8_t) cfg.adc_unit;
539 adc_pattern[i].bit_width = (uint8_t) cfg.adc_bit_width;
540 }
541
542 // Configure the ADC
543 adc_continuous_config_t dig_cfg = {
544 .pattern_num = (uint32_t) cfg.channels,
545 .adc_pattern = adc_pattern,
546 .sample_freq_hz = (uint32_t)cfg.sample_rate * cfg.channels,
547 .conv_mode = (adc_digi_convert_mode_t) cfg.adc_conversion_mode,
548 .format = (adc_digi_output_format_t) cfg.adc_output_type,
549 };
550
551 // Log the configuration
552 LOGI("dig_cfg.sample_freq_hz: %u", (unsigned)dig_cfg.sample_freq_hz);
553 LOGI("dig_cfg.conv_mode: %u (1: unit 1, 2: unit 2, 3: both)", dig_cfg.conv_mode);
554 LOGI("dig_cfg.format: %u (0 is type1: [12bit data, 4bit channel])", dig_cfg.format);
555 for (int i = 0; i < cfg.channels; i++) {
556 LOGI("dig_cfg.adc_pattern[%d].atten: %u", i, dig_cfg.adc_pattern[i].atten);
557 LOGI("dig_cfg.adc_pattern[%d].channel: %u", i, dig_cfg.adc_pattern[i].channel);
558 LOGI("dig_cfg.adc_pattern[%d].unit: %u", i, dig_cfg.adc_pattern[i].unit);
559 LOGI("dig_cfg.adc_pattern[%d].bit_width: %u", i, dig_cfg.adc_pattern[i].bit_width);
560 }
561
562 // Initialize ADC
563 err = adc_continuous_config(adc_handle, &dig_cfg);
564 if (err != ESP_OK) {
565 LOGE("adc_continuous_config unsuccessful with error: %d", err);
566 return false;
567 }
568 LOGI("adc_continuous_config successful");
569
570 // Set up optional calibration
571 if (!setupADCCalibration()) {
572 return false;
573 }
574
575 // Attach the pins to the ADC unit
576 #ifdef ARDUINO
577 for (int i = 0; i < cfg.channels; i++) {
578 adc_channel = cfg.adc_channels[i];
579 adc_continuous_channel_to_io(cfg.adc_unit, adc_channel, &io_pin);
580 // perimanSetPinBus: uint8_t pin, peripheral_bus_type_t type, void * bus, int8_t bus_num, int8_t bus_channel
581 if (!perimanSetPinBus(io_pin, ESP32_BUS_TYPE_ADC_CONT, (void *)(cfg.adc_unit + 1), cfg.adc_unit, adc_channel)) {
582 LOGE("perimanSetPinBus to Continuous an ADC Unit %u failed!", cfg.adc_unit);
583 return false;
584 }
585 }
586 #endif
587
588 // Start ADC
589 err = adc_continuous_start(adc_handle);
590 if (err != ESP_OK) {
591 LOGE("adc_continuous_start unsuccessful with error: %d", err);
592 return false;
593 }
594
595 // Setup up optimal auto center which puts the avg at 0
596 auto_center.begin(cfg.channels, cfg.bits_per_sample, true);
597
598 // Initialize the FIFO buffers
599 size_t fifo_size = (cfg.buffer_size / cfg.channels) + 8; // Add a few extra elements
600 fifo_buffers = new FIFO<ADC_DATA_TYPE>*[cfg.channels]; // Allocate an array of FIFO objects
601 for (int i = 0; i < cfg.channels; ++i) {
602 fifo_buffers[i] = new FIFO<ADC_DATA_TYPE>(fifo_size);
603 }
604 LOGI("%d FIFO buffers allocated of size %d", cfg.channels, fifo_size);
605
606 LOGI("Setup ADC successful");
607
608 return true;
609 }
610
612 bool cleanup_tx() {
613 bool ok = true;
614#ifdef HAS_ESP32_DAC
615 if (dac_handle==nullptr) return true;
616 if (dac_continuous_disable(dac_handle) != ESP_OK){
617 ok = false;
618 LOGE("dac_continuous_disable failed");
619 }
620 if (dac_continuous_del_channels(dac_handle) != ESP_OK){
621 ok = false;
622 LOGE("dac_continuous_del_channels failed");
623 }
624 dac_handle = nullptr;
625#endif
626 return ok;
627 }
628
629#ifdef ARDUINO
630 // dummy detach: w/o this it's failing
631 static bool adcDetachBus(void *bus) {
632 LOGD("===> adcDetachBus: %d", (int) bus);
633 return true;
634 }
635#endif
636
638 bool cleanup_rx() {
639 if (adc_handle==nullptr) return true;
640 adc_continuous_stop(adc_handle);
641 adc_continuous_deinit(adc_handle);
642 if (cfg.adc_calibration_active) {
643 #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
644 adc_cali_delete_scheme_curve_fitting(adc_cali_handle);
645 #elif !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)
646 adc_cali_delete_scheme_line_fitting(adc_cali_handle);
647 #endif
648 }
649
650 // Clean up the FIFO buffers
651 if (fifo_buffers != nullptr) {
652 for (int i = 0; i < cfg.channels; ++i) {
653 delete fifo_buffers[i];
654 }
655 delete[] fifo_buffers;
656 fifo_buffers = nullptr;
657 }
658
659#ifdef ARDUINO
660 // Set all used pins/channels to INIT state
661 perimanSetBusDeinit(ESP32_BUS_TYPE_ADC_CONT, adcDetachBus);
662 for (int i = 0; i < cfg.channels; i++) {
663 adc_channel_t adc_channel = cfg.adc_channels[i];
664 int io_pin;
665 adc_continuous_channel_to_io(cfg.adc_unit, adc_channel, &io_pin);
666 if (perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT) {
667 if (!perimanClearPinBus(io_pin)) {
668 LOGE("perimanClearPinBus failed!");
669 }
670 }
671 }
672#endif
673 adc_handle = nullptr;
674 return true; // Return true to indicate successful cleanup
675 }
676
679 if ((cfg.adc_bit_width < SOC_ADC_DIGI_MIN_BITWIDTH) ||
680 (cfg.adc_bit_width > SOC_ADC_DIGI_MAX_BITWIDTH)) {
681 LOGE("adc bit width: %u cannot be set, range: %u to %u", cfg.adc_bit_width,
682 (unsigned)SOC_ADC_DIGI_MIN_BITWIDTH, (unsigned)SOC_ADC_DIGI_MAX_BITWIDTH);
683 return false;
684 }
685 LOGI("adc bit width: %u, range: %u to %u", cfg.adc_bit_width,
686 (unsigned)SOC_ADC_DIGI_MIN_BITWIDTH, (unsigned)SOC_ADC_DIGI_MAX_BITWIDTH);
687 return true;
688 }
689
692 int io_pin;
693 adc_channel_t adc_channel;
694
695 int max_channels = sizeof(cfg.adc_channels) / sizeof(adc_channel_t);
696 if (cfg.channels > max_channels) {
697 LOGE("number of channels: %d, max: %d", cfg.channels, max_channels);
698 return false;
699 }
700 LOGI("channels: %d, max: %d", cfg.channels, max_channels);
701
702 // Lets make sure the adc channels are available
703 for (int i = 0; i < cfg.channels; i++) {
704 adc_channel = cfg.adc_channels[i];
705 auto err = adc_continuous_channel_to_io(cfg.adc_unit, adc_channel, &io_pin);
706 if (err != ESP_OK) {
707 LOGE("ADC channel %u is not available on ADC unit %u", adc_channel, cfg.adc_unit);
708 return false;
709 } else {
710 LOGI("ADC channel %u is on pin %u", adc_channel, io_pin);
711 }
712 }
713 return true;
714 }
715
718 int sample_rate = cfg.sample_rate * cfg.channels;
719 if ((sample_rate < SOC_ADC_SAMPLE_FREQ_THRES_LOW) ||
720 (sample_rate > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)) {
721 LOGE("sample rate eff: %u can not be set, range: %u to %u", sample_rate,
722 SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH);
723 return false;
724 }
725 LOGI("sample rate eff: %u, range: %u to %u", sample_rate,
726 SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH);
727
728 return true;
729 }
730
733 int supported_bits = 16; // for the time being we support only 16 bits!
734
735 // calculated default value if nothing is specified
736 if (cfg.bits_per_sample == 0) {
737 cfg.bits_per_sample = supported_bits;
738 LOGI("bits per sample set to: %d", cfg.bits_per_sample);
739 }
740
741 // check bits_per_sample
742 if (cfg.bits_per_sample != supported_bits) {
743 LOGE("bits per sample: error. It should be: %d but is %d",
744 supported_bits, cfg.bits_per_sample);
745 return false;
746 }
747 LOGI("bits per sample: %d", cfg.bits_per_sample);
748 return true;
749 }
750
753 if (!cfg.adc_calibration_active)
754 return true;
755
756 // Initialize ADC calibration handle
757 // Calibration is applied to an ADC unit (not per channel).
758
759 // setup calibration only when requested
760 esp_err_t err = ESP_OK;
761
762 if (adc_cali_handle == NULL) {
763 #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
764 // curve fitting is preferred
765 adc_cali_curve_fitting_config_t cali_config;
766 cali_config.unit_id = cfg.adc_unit;
767 cali_config.atten = (adc_atten_t)cfg.adc_attenuation;
768 cali_config.bitwidth = (adc_bitwidth_t)cfg.adc_bit_width;
769 err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle);
770 #elif !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4)
771 // line fitting is the alternative
772 adc_cali_line_fitting_config_t cali_config;
773 cali_config.unit_id = cfg.adc_unit;
774 cali_config.atten = (adc_atten_t)cfg.adc_attenuation;
775 cali_config.bitwidth = (adc_bitwidth_t)cfg.adc_bit_width;
776 err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle);
777 #endif
778 if (err != ESP_OK) {
779 LOGE("creating calibration handle failed for ADC%d with atten %d and bitwidth %d",
780 cfg.adc_unit, cfg.adc_attenuation, cfg.adc_bit_width);
781 return false;
782 } else {
783 LOGI("enabled calibration for ADC%d with atten %d and bitwidth %d",
784 cfg.adc_unit, cfg.adc_attenuation, cfg.adc_bit_width);
785 }
786 }
787 return true;
788 }
789
790};
791
794
795} // namespace audio_tools
796
797#endif
ESP32 specific configuration for i2s input via adc using the adc_continuous API.
Definition AnalogConfigESP32V1.h:102
Definition AnalogDriverBase.h:13
Custom FIFO class.
Definition AnalogDriverESP32V1.h:114
Definition AnalogDriverESP32V1.h:194
AnalogAudioStream: A very fast DAC using DMA using the new dac_continuous API.
Definition AnalogDriverESP32V1.h:28
bool checkADCBitWidth()
Definition AnalogDriverESP32V1.h:678
virtual ~AnalogDriverESP32V1()
Destructor.
Definition AnalogDriverESP32V1.h:34
bool checkADCChannels()
Definition AnalogDriverESP32V1.h:691
void end() override
Definition AnalogDriverESP32V1.h:70
bool cleanup_tx()
Cleanup dac.
Definition AnalogDriverESP32V1.h:612
bool cleanup_rx()
Cleanup Analog to Digital Converter.
Definition AnalogDriverESP32V1.h:638
bool begin(AnalogConfigESP32V1 cfg)
Definition AnalogDriverESP32V1.h:40
AnalogDriverESP32V1()
Default constructor.
Definition AnalogDriverESP32V1.h:31
bool setupADCCalibration()
Definition AnalogDriverESP32V1.h:752
bool checkADCSampleRate()
Definition AnalogDriverESP32V1.h:717
bool checkADCBitsPerSample()
Definition AnalogDriverESP32V1.h:732
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:119
Makes sure that the avg of the signal is set to 0.
Definition BaseConverter.h:185
Converter which converts between bits_per_sample and 16 bits. The templated NumberFormatConverterStre...
Definition AudioStreamsConverter.h:453
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
AnalogDriverArduino AnalogDriver
AnalogAudioStream.
Definition AnalogDriverArduino.h:48
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59