diff --git a/examples/tests/adc/read/read.ino b/examples/tests/adc/read/read.ino index ce555f108a..0cf10f99d0 100644 --- a/examples/tests/adc/read/read.ino +++ b/examples/tests/adc/read/read.ino @@ -1,7 +1,7 @@ #include "AudioTools.h" #include "AudioTools.h" -AudioInfo info(44100, 1, 16); +AudioInfo info(44100, 2, 16); AnalogAudioStream adc; MeasuringStream out(10, &Serial); StreamCopy copier(out, adc); @@ -11,7 +11,10 @@ void setup(void) { Serial.begin(115200); AudioLogger::instance().begin(Serial, AudioLogger::Info); - LOGI("Supported samples rates: %d - %d", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH) +#ifdef ESP32 + LOGI("Supported samples rates: %d - %d", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); + LOGI("Supported bit width: %d - %d", SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); +#endif auto cfg = adc.defaultConfig(RX_MODE); cfg.copyFrom(info); diff --git a/src/AudioAnalog/AnalogAudioESP32V1.h b/src/AudioAnalog/AnalogAudioESP32V1.h index ed35e87d7a..38cc1df408 100644 --- a/src/AudioAnalog/AnalogAudioESP32V1.h +++ b/src/AudioAnalog/AnalogAudioESP32V1.h @@ -1,24 +1,26 @@ #pragma once #include "AudioConfig.h" -#if defined(ESP32) && defined(USE_ANALOG) && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) || defined(DOXYGEN) +#if defined(ESP32) && defined(USE_ANALOG) && \ + ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) || \ + defined(DOXYGEN) #include "AudioAnalog/AnalogAudioBase.h" #include "AudioTools/AudioStreams.h" #include "AudioTools/AudioStreamsConverter.h" namespace audio_tools { -#define GET_UNIT(x) ((x>>3) & 0x1) - +#define GET_UNIT(x) ((x >> 3) & 0x1) /** - * @brief AnalogAudioStream: A very fast DAC using DMA using the new dac_continuous API + * @brief AnalogAudioStream: A very fast DAC using DMA using the new + * dac_continuous API * @ingroup platform * @author Phil Schatzmann * @copyright GPLv3 */ class AnalogDriverESP32V1 : public AnalogDriverBase { - public: +public: /// Default constructor AnalogDriverESP32V1() = default; @@ -31,29 +33,29 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { bool result = true; this->cfg = cfg; - switch(cfg.rx_tx_mode){ - case TX_MODE: - if (!setup_tx()){ - return false; - } - active_tx = true; - break; - case RX_MODE: - if (!setup_rx()){ - return false; - } - active_rx = true; - break; - default: - LOGE("mode"); + switch (cfg.rx_tx_mode) { + case TX_MODE: + if (!setup_tx()) { return false; - } - - // convert to 16 bits - if (!converter.begin(cfg, 16)){ - LOGE("converter"); + } + // convert to 16 bits + if (!converter.begin(cfg, 16)) { + LOGE("converter"); + return false; + } + active_tx = true; + break; + case RX_MODE: + if (!setup_rx()) { + return false; + } + active_rx = true; + break; + default: + LOGE("mode"); return false; } + active = true; return active; } @@ -62,7 +64,7 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { void end() override { TRACEI(); #ifdef HAS_ESP32_DAC - if (active_tx) { + if (active_tx) { dac_continuous_del_channels(dac_handle); } #endif @@ -84,18 +86,22 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { size_t readBytes(uint8_t *dest, size_t size_bytes) override { TRACED(); - return io.readBytes(dest, size_bytes); - } + uint32_t result = 0; + size_t samples = size_bytes / 2; - int available() override { - return active_rx ? DEFAULT_BUFFER_SIZE : 0; - } - - void setTimeout(int value){ - timeout = value; + if (adc_continuous_read(adc_handle, dest, samples, &result, timeout) == + ESP_OK) { + // convert unsigned to signed ? + } else { + result = 0; + } + return result * 2; } + int available() override { return active_rx ? DEFAULT_BUFFER_SIZE : 0; } + + void setTimeout(int value) { timeout = value; } - protected: +protected: #ifdef HAS_ESP32_DAC dac_continuous_handle_t dac_handle; #endif @@ -108,51 +114,33 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { /// writes the int16_t data to the DAC class IO16Bit : public AudioStream { - public: - IO16Bit(AnalogDriverESP32V1 *driver){ - self = driver; - } - size_t write(const uint8_t *src, size_t size_bytes) override { - TRACED(); + public: + IO16Bit(AnalogDriverESP32V1 *driver) { self = driver; } + size_t write(const uint8_t *src, size_t size_bytes) override { + TRACED(); #ifdef HAS_ESP32_DAC - size_t result = 0; - - // convert signed 16 bit to unsigned 8 bits - int16_t* data16 = (int16_t*)src; - uint8_t* data8 = (uint8_t*)src; - int samples = size_bytes / 2; - for (int j=0; j < samples; j++){ - data8[j] = (32768u + data16[j]) >> 8; - } + size_t result = 0; + + // convert signed 16 bit to unsigned 8 bits + int16_t *data16 = (int16_t *)src; + uint8_t *data8 = (uint8_t *)src; + int samples = size_bytes / 2; + for (int j = 0; j < samples; j++) { + data8[j] = (32768u + data16[j]) >> 8; + } - if (dac_continuous_write(self->dac_handle, data8, samples, &result, - self->timeout) != ESP_OK) { - result = 0; - } - return result * 2; + if (dac_continuous_write(self->dac_handle, data8, samples, &result, + self->timeout) != ESP_OK) { + result = 0; + } + return result * 2; #else - return 0; + return 0; #endif - } + } - size_t readBytes(uint8_t *dest, size_t size_bytes) override { - TRACED(); - uint32_t result = 0; - size_t samples = size_bytes / 2; - - if(adc_continuous_read(self->adc_handle, dest, samples, &result, self->timeout)== ESP_OK) { - // convert unsigned 8 bits to signed 16 bits; - int16_t* data16 = (int16_t*)dest; - for (int j = result-1; j>=0; j--){ - data16[j] = (static_cast(dest[8]) - 128) * 256; - } - } else { - result = 0; - } - return result * 2; - } - protected: - AnalogDriverESP32V1 *self; + protected: + AnalogDriverESP32V1 *self; } io{this}; @@ -160,22 +148,22 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { #ifdef HAS_ESP32_DAC - bool setup_tx(){ + bool setup_tx() { dac_continuous_config_t cont_cfg = { .chan_mask = cfg.channels == 1 ? cfg.dac_mono_channel : DAC_CHANNEL_MASK_ALL, .desc_num = (uint32_t)cfg.buffer_count, - .buf_size = (size_t) cfg.buffer_size, + .buf_size = (size_t)cfg.buffer_size, .freq_hz = (uint32_t)cfg.sample_rate, .offset = 0, .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 + : DAC_DIGI_CLK_SRC_DEFAULT, // Using APLL as clock source to + // get a wider frequency range .chan_mode = DAC_CHANNEL_MODE_ALTER, }; - // Allocate continuous channels + // Allocate continuous channels if (dac_continuous_new_channels(&cont_cfg, &dac_handle) != ESP_OK) { LOGE("new_channels"); return false; @@ -186,62 +174,59 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { } return true; } - - #else - bool setup_tx(){ + +#else + bool setup_tx() { LOGE("DAC not supported"); return false; } - #endif +#endif - bool setup_rx(){ - int max_channels = sizeof(cfg.adc_channels)/sizeof(adc_channel_t); - if (cfg.channels > max_channels ){ + bool setup_rx() { + int max_channels = sizeof(cfg.adc_channels) / sizeof(adc_channel_t); + if (cfg.channels > max_channels) { LOGE("channels: %d, max: %d", cfg.channels, max_channels); return false; } else { LOGI("channels: %d, max: %d", cfg.channels, max_channels); - } adc_continuous_handle_cfg_t adc_config = { .max_store_buf_size = (uint32_t)cfg.buffer_size * cfg.buffer_count, - .conv_frame_size = (uint32_t)cfg.buffer_size / SOC_ADC_DIGI_DATA_BYTES_PER_CONV * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, + .conv_frame_size = (uint32_t)cfg.buffer_size / + SOC_ADC_DIGI_DATA_BYTES_PER_CONV * + SOC_ADC_DIGI_DATA_BYTES_PER_CONV, }; esp_err_t err = adc_continuous_new_handle(&adc_config, &adc_handle); - if (err != ESP_OK){ + if (err != ESP_OK) { LOGE("adc_continuous_new_handle failed with error: %d", err); return false; } else { LOGI("adc_continuous_new_handle successful"); } - if ((cfg.sample_rate < SOC_ADC_SAMPLE_FREQ_THRES_LOW) || (cfg.sample_rate > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)){ - LOGE("sample rate: %u can not be set, range: %u to %u", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); + if ((cfg.sample_rate < SOC_ADC_SAMPLE_FREQ_THRES_LOW) || + (cfg.sample_rate > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)) { + LOGE("sample rate: %u can not be set, range: %u to %u", + SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); return false; } else { - LOGI("sample rate: %u, range: %u to %u",cfg.sample_rate, SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); + LOGI("sample rate: %u, range: %u to %u", cfg.sample_rate, + SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); } - if ((cfg.adc_bit_width < SOC_ADC_DIGI_MIN_BITWIDTH) || (cfg.adc_bit_width > SOC_ADC_DIGI_MAX_BITWIDTH)){ - LOGE("adc bit width: %u cannot be set, range: %u to %u", SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); + if ((cfg.adc_bit_width < SOC_ADC_DIGI_MIN_BITWIDTH) || + (cfg.adc_bit_width > SOC_ADC_DIGI_MAX_BITWIDTH)) { + LOGE("adc bit width: %u cannot be set, range: %u to %u", + SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); return false; } else { - LOGI("adc bit width: %u, range: %u to %u", cfg.adc_bit_width, SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); + LOGI("adc bit width: %u, range: %u to %u", cfg.adc_bit_width, + SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); } - // adjust bits per sample based on adc bit width setting (multiple of 8) - if (cfg.adc_bit_width <= 8) { - cfg.bits_per_sample = 8; - } else if (cfg.adc_bit_width <= 16) { - cfg.bits_per_sample = 16; - } else if(cfg.adc_bit_width <= 24) { - cfg.bits_per_sample = 24; - } else if(cfg.adc_bit_width <= 32) { - cfg.bits_per_sample = 32; - } else { - cfg.bits_per_sample = 16; + if (!checkBitsPerSample()) { + return false; } - LOGI("bits per sample: %d", cfg.bits_per_sample); adc_continuous_config_t dig_cfg = { .sample_freq_hz = cfg.sample_rate, @@ -251,12 +236,12 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { adc_digi_pattern_config_t adc_pattern[cfg.channels] = {0}; dig_cfg.pattern_num = cfg.channels; for (int i = 0; i < cfg.channels; i++) { - uint8_t unit = GET_UNIT(cfg.adc_channels[i]); - uint8_t ch = cfg.adc_channels[i] & 0x7; - adc_pattern[i].atten = cfg.adc_attenuation; - adc_pattern[i].channel = ch; - adc_pattern[i].unit = unit; - adc_pattern[i].bit_width = cfg.adc_bit_width; + uint8_t unit = GET_UNIT(cfg.adc_channels[i]); + uint8_t ch = cfg.adc_channels[i] & 0x7; + adc_pattern[i].atten = cfg.adc_attenuation; + adc_pattern[i].channel = ch; + adc_pattern[i].unit = unit; + adc_pattern[i].bit_width = cfg.adc_bit_width; } dig_cfg.adc_pattern = adc_pattern; @@ -264,21 +249,24 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { LOGI("dig_cfg.conv_mode: %u", dig_cfg.conv_mode); LOGI("dig_cfg.format: %u", dig_cfg.format); for (int i = 0; i < cfg.channels; i++) { - LOGI("dig_cfg.adc_pattern[%d].atten: %u", i, dig_cfg.adc_pattern[i].atten); - LOGI("dig_cfg.adc_pattern[%d].channel: %u", i, dig_cfg.adc_pattern[i].channel); - LOGI("dig_cfg.adc_pattern[%d].unit: %u", i, dig_cfg.adc_pattern[i].unit); - LOGI("dig_cfg.adc_pattern[%d].bit_width: %u", i, dig_cfg.adc_pattern[i].bit_width); - } + LOGI("dig_cfg.adc_pattern[%d].atten: %u", i, + dig_cfg.adc_pattern[i].atten); + LOGI("dig_cfg.adc_pattern[%d].channel: %u", i, + dig_cfg.adc_pattern[i].channel); + LOGI("dig_cfg.adc_pattern[%d].unit: %u", i, dig_cfg.adc_pattern[i].unit); + LOGI("dig_cfg.adc_pattern[%d].bit_width: %u", i, + dig_cfg.adc_pattern[i].bit_width); + } err = adc_continuous_config(adc_handle, &dig_cfg); - if (err != ESP_OK){ + if (err != ESP_OK) { LOGE("adc_continuous_config unsuccessful with error: %d", err); return false; } LOGI("adc_continuous_config successful"); err = adc_continuous_start(adc_handle); - if(err != ESP_OK){ + if (err != ESP_OK) { LOGE("adc_continuous_start unsuccessful with error: %d", err); return false; } @@ -287,11 +275,65 @@ class AnalogDriverESP32V1 : public AnalogDriverBase { return true; } + // this is maybe a little bit too much since currently any supported + // adc_bit_width leads to int16_t data + bool checkBitsPerSample() { + // adjust bits per sample based on adc bit width setting (multiple of 8) + LOGI("cfg.bits_per_sample: %d", cfg.bits_per_sample); + if (cfg.bits_per_sample == 0) { + if (cfg.adc_bit_width <= 8) { + cfg.bits_per_sample = 8; + } else if (cfg.adc_bit_width <= 16) { + cfg.bits_per_sample = 16; + } else if (cfg.adc_bit_width <= 24) { + cfg.bits_per_sample = 24; + } else if (cfg.adc_bit_width <= 32) { + cfg.bits_per_sample = 32; + } else { + cfg.bits_per_sample = 16; + } + LOGI("bits per sample: %d", cfg.bits_per_sample); + return true; + } + + // check bits per sample with requested adc_bit_width + switch (cfg.bits_per_sample) { + case 8: + if (cfg.adc_bit_width > 8) { + LOGE("bits_per_sample %d not valid for adc_bit_width %d", + cfg.bits_per_sample, cfg.adc_bit_width); + return false; + } + break; + case 16: + if (cfg.adc_bit_width <= 8 || cfg.adc_bit_width > 16) { + LOGE("bits_per_sample %d not valid for adc_bit_width %d", + cfg.bits_per_sample, cfg.adc_bit_width); + return false; + } + break; + case 24: + if (cfg.adc_bit_width <= 16 || cfg.adc_bit_width > 24) { + LOGE("bits_per_sample %d not valid for adc_bit_width %d", + cfg.bits_per_sample, cfg.adc_bit_width); + return false; + } + break; + case 32: + if (cfg.adc_bit_width <= 24 || cfg.adc_bit_width >= 32) { + LOGE("bits_per_sample %d not valid for adc_bit_width %d", + cfg.bits_per_sample, cfg.adc_bit_width); + return false; + } + break; + } + return true; + } }; /// @brief AnalogAudioStream using AnalogDriver = AnalogDriverESP32V1; -} // namespace +} // namespace audio_tools #endif diff --git a/src/AudioAnalog/AnalogConfigESP32V1.h b/src/AudioAnalog/AnalogConfigESP32V1.h index ea312a8e99..4d35be59a9 100644 --- a/src/AudioAnalog/AnalogConfigESP32V1.h +++ b/src/AudioAnalog/AnalogConfigESP32V1.h @@ -59,8 +59,6 @@ class AnalogConfigESP32V1 : public AudioInfo { uint32_t sample_rate = SOC_ADC_SAMPLE_FREQ_THRES_LOW; /// ESP32: ADC_CHANNEL_6, ADC_CHANNEL_7; others ADC_CHANNEL_2, ADC_CHANNEL_3 adc_channel_t adc_channels[2] = ADC_CHANNELS; - uint32_t channels = 2; - int bits_per_sample = 16; #ifdef HAS_ESP32_DAC /// ESP32: DAC_CHANNEL_MASK_CH0 or DAC_CHANNEL_MASK_CH1