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