From 945d2e697c46ccfb06819bfa1df856e1bbb05049 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Fri, 8 Dec 2017 20:07:19 +0800 Subject: [PATCH] driver(i2s): fix broken i2s adc mode 1. Move i2s reset code from i2s_stop to i2s_start. 2. add RTC API to set sw mode for ADC 3. add description for adc_power_always_on() 4. add lock for i2s dma and RTC ADC functions. 5. add ADC read task in example reported from bbs: https://esp32.com/viewtopic.php?f=13&t=3490&p=17522#p17522 reported from github: https://github.com/espressif/esp-idf/issues/1333 Also update some deprecated APIs for ADC. --- components/driver/adc1_i2s_private.h | 73 +++++++++++++++++ components/driver/i2s.c | 62 +++++++++++---- components/driver/include/driver/adc.h | 3 +- components/driver/include/driver/i2s.h | 27 +++++++ components/driver/rtc_module.c | 79 ++++++++++++++++--- components/soc/esp32/include/soc/sens_reg.h | 1 + .../peripherals/i2s_adc_dac/main/app_main.c | 32 +++++++- 7 files changed, 245 insertions(+), 32 deletions(-) create mode 100644 components/driver/adc1_i2s_private.h diff --git a/components/driver/adc1_i2s_private.h b/components/driver/adc1_i2s_private.h new file mode 100644 index 00000000000..cc592ffe1d0 --- /dev/null +++ b/components/driver/adc1_i2s_private.h @@ -0,0 +1,73 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _DRIVER_ADC1_I2S_PRIVATE_H_ +#define _DRIVER_ADC1_I2S_PRIVATE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + + +/** + * @brief Force power on for SAR ADC. + * This function should be called for the scenario in which ADC are controlled by digital function like DMA. + * When the ADC power is always on, RTC FSM can still be functional. + * This is an internal API for I2S module to call to enable I2S-ADC function. + * Note that adc_power_off() can still power down ADC. + */ +void adc_power_always_on(); + +/** + * @brief For I2S dma to claim the usage of ADC1. + * + * Other tasks will be forbidden to use ADC1 between ``adc1_i2s_mode_acquire`` and ``adc1_i2s_release``. + * The I2S module may have to wait for a short time for the current conversion (if exist) to finish. + * + * @return + * - ESP_OK success + * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. + */ +esp_err_t adc1_i2s_mode_acquire(); + +/** + * @brief For ADC1 to claim the usage of ADC1. + * + * Other tasks will be forbidden to use ADC1 between ``adc1_adc_mode_acquire`` and ``adc1_i2s_release``. + * The ADC1 may have to wait for some time for the I2S read operation to finish. + * + * @return + * - ESP_OK success + * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. + */ +esp_err_t adc1_adc_mode_acquire(); + +/** + * @brief to let other tasks use the ADC1 when I2S is not work. + * + * Other tasks will be forbidden to use ADC1 between ``adc1_adc/i2s_mode_acquire`` and ``adc1_i2s_release``. + * Call this function to release the occupation of ADC1 + * + * @return always return ESP_OK. + */ +esp_err_t adc1_lock_release(); + +#ifdef __cplusplus +} +#endif + +#endif /*_DRIVER_ADC1_I2S_PRIVATE_H_*/ + diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 61bfbeb5d33..3794b23371c 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -31,6 +31,7 @@ #include "driver/i2s.h" #include "driver/rtc_io.h" #include "driver/dac.h" +#include "adc1_i2s_private.h" #include "esp_intr.h" #include "esp_err.h" @@ -84,12 +85,14 @@ typedef struct { int bits_per_sample; /*!< Bits per sample*/ i2s_mode_t mode; /*!< I2S Working mode*/ int use_apll; /*!< I2S use APLL clock */ + uint32_t sample_rate; /*!< I2S sample rate */ } i2s_obj_t; static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0}; static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1}; static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; - +static int _i2s_adc_unit = -1; +static int _i2s_adc_channel = -1; /** * @brief Pre define APLL parameters, save compute time * | bits_per_sample | rate | sdm0 | sdm1 | sdm2 | odir @@ -322,12 +325,11 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b return ESP_ERR_INVALID_ARG; } - if (p_i2s_obj[i2s_num] == NULL) { ESP_LOGE(I2S_TAG, "Not initialized yet"); return ESP_ERR_INVALID_ARG; } - + p_i2s_obj[i2s_num]->sample_rate = rate; double clkmdiv = (double)I2S_BASE_CLK / (rate * factor); if (clkmdiv > 256) { @@ -652,6 +654,18 @@ esp_err_t i2s_start(i2s_port_t i2s_num) I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); //start DMA link I2S_ENTER_CRITICAL(); + i2s_reset_fifo(i2s_num); + //reset dma + I2S[i2s_num]->lc_conf.in_rst = 1; + I2S[i2s_num]->lc_conf.in_rst = 0; + I2S[i2s_num]->lc_conf.out_rst = 1; + I2S[i2s_num]->lc_conf.out_rst = 0; + + I2S[i2s_num]->conf.tx_reset = 1; + I2S[i2s_num]->conf.tx_reset = 0; + I2S[i2s_num]->conf.rx_reset = 1; + I2S[i2s_num]->conf.rx_reset = 0; + esp_intr_disable(p_i2s_obj[i2s_num]->i2s_isr_handle); I2S[i2s_num]->int_clr.val = 0xFFFFFFFF; if (p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) { @@ -685,17 +699,6 @@ esp_err_t i2s_stop(i2s_port_t i2s_num) i2s_disable_rx_intr(i2s_num); } I2S[i2s_num]->int_clr.val = I2S[i2s_num]->int_st.val; //clear pending interrupt - i2s_reset_fifo(i2s_num); - //reset dma - I2S[i2s_num]->lc_conf.in_rst = 1; - I2S[i2s_num]->lc_conf.in_rst = 0; - I2S[i2s_num]->lc_conf.out_rst = 1; - I2S[i2s_num]->lc_conf.out_rst = 0; - - I2S[i2s_num]->conf.tx_reset = 1; - I2S[i2s_num]->conf.tx_reset = 0; - I2S[i2s_num]->conf.rx_reset = 1; - I2S[i2s_num]->conf.rx_reset = 0; I2S_EXIT_CRITICAL(); return ESP_OK; } @@ -722,10 +725,18 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) return ESP_OK; } +static esp_err_t _i2s_adc_mode_recover() +{ + I2S_CHECK(((_i2s_adc_unit != -1) && (_i2s_adc_channel != -1)), "i2s ADC recover error, not initialized...", ESP_ERR_INVALID_ARG); + return adc_i2s_mode_init(_i2s_adc_unit, _i2s_adc_channel); +} + esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel) { I2S_CHECK((adc_unit < ADC_UNIT_2), "i2s ADC unit error, only support ADC1 for now", ESP_ERR_INVALID_ARG); // For now, we only support SAR ADC1. + _i2s_adc_unit = adc_unit; + _i2s_adc_channel = adc_channel; return adc_i2s_mode_init(adc_unit, adc_channel); } @@ -864,7 +875,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co //initialize the specific ADC channel. //in the current stage, we only support ADC1 and single channel mode. //In default data mode, the ADC data is in 12-bit resolution mode. - adc_power_on(); + adc_power_always_on(); } // configure I2S data port interface. i2s_reset_fifo(i2s_num); @@ -1171,6 +1182,27 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by return ESP_OK; } +esp_err_t i2s_adc_enable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_i2s_mode_acquire(); + _i2s_adc_mode_recover(); + return i2s_set_clk(i2s_num, p_i2s_obj[i2s_num]->sample_rate, p_i2s_obj[i2s_num]->bits_per_sample, p_i2s_obj[i2s_num]->channel_num); +} + +esp_err_t i2s_adc_disable(i2s_port_t i2s_num) +{ + I2S_CHECK((i2s_num < I2S_NUM_MAX), "i2s_num error", ESP_ERR_INVALID_ARG); + I2S_CHECK((p_i2s_obj[i2s_num] != NULL), "Not initialized yet", ESP_ERR_INVALID_STATE); + I2S_CHECK((p_i2s_obj[i2s_num]->mode & I2S_MODE_ADC_BUILT_IN), "i2s built-in adc not enabled", ESP_ERR_INVALID_STATE); + + adc1_lock_release(); + return ESP_OK; +} + esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait) { char *data_ptr; diff --git a/components/driver/include/driver/adc.h b/components/driver/include/driver/adc.h index 9d26c539063..ccbe85014e1 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/include/driver/adc.h @@ -204,12 +204,13 @@ int adc1_get_voltage(adc1_channel_t channel) __attribute__((deprecated)); /** @endcond */ /** - * @brief Power on SAR ADC + * @brief Enable ADC power */ void adc_power_on(); /** * @brief Power off SAR ADC + * This function will force power down for ADC */ void adc_power_off(); diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 78fa80334f8..43e6ae5cbce 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -353,6 +353,8 @@ int i2s_read_bytes(i2s_port_t i2s_num, void *dest, size_t size, TickType_t ticks * * @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process, * to prevent the data getting corrupted. + * @note If the built-in ADC mode is enabled, we should call i2s_adc_start and i2s_adc_stop around the whole reading process, + * to prevent the data getting corrupted. * * @return * - ESP_OK Success @@ -485,6 +487,31 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b */ esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel); +/** + * @brief Start to use I2S built-in ADC mode + * @note This function would acquire the lock of ADC to prevent the data getting corrupted + * during the I2S peripheral is being used to do fully continuous ADC sampling. + * + * @param i2s_num i2s port index + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE driver state error + * - ESP_FAIL Internal driver error + */ +esp_err_t i2s_adc_enable(i2s_port_t i2s_num); + +/** + * @brief Stop to use I2S built-in ADC mode + * @param i2s_num i2s port index + * @note This function would release the lock of ADC so that other tasks can use ADC. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE driver state error + */ +esp_err_t i2s_adc_disable(i2s_port_t i2s_num); + #ifdef __cplusplus } #endif diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index a04282b8083..9a6b6faf1ef 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -34,6 +34,7 @@ #include "sys/lock.h" #include "driver/rtc_cntl.h" #include "driver/gpio.h" +#include "adc1_i2s_private.h" #ifndef NDEBUG // Enable built-in checks in queue.h in debug builds @@ -99,6 +100,9 @@ static _lock_t adc2_wifi_lock = NULL; //prevent ADC2 being used by tasks (regardless of WIFI) portMUX_TYPE adc2_spinlock = portMUX_INITIALIZER_UNLOCKED; +//prevent ADC1 being used by I2S dma and other tasks at the same time. +static _lock_t adc1_i2s_lock = NULL; + typedef struct { TimerHandle_t timer; uint32_t filtered_val[TOUCH_PAD_MAX]; @@ -108,12 +112,6 @@ typedef struct { } touch_pad_filter_t; static touch_pad_filter_t *s_touch_pad_filter = NULL; -typedef enum { - ADC_FORCE_FSM = 0x0, - ADC_FORCE_DISABLE = 0x2, - ADC_FORCE_ENABLE = 0x3, -} adc_force_mode_t; - //Reg,Mux,Fun,IE,Up,Down,Rtc_number const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = { {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, RTCIO_GPIO0_CHANNEL}, //0 @@ -1025,10 +1023,21 @@ static esp_err_t adc_set_atten(adc_unit_t adc_unit, adc_channel_t channel, adc_a return ESP_OK; } +void adc_power_always_on() +{ + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; + portEXIT_CRITICAL(&rtc_spinlock); +} + void adc_power_on() { portENTER_CRITICAL(&rtc_spinlock); - SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_FSM; + if (SENS.sar_meas_wait2.force_xpd_sar & SENS_FORCE_XPD_SAR_SW_M) { + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; + } else { + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM; + } portEXIT_CRITICAL(&rtc_spinlock); } @@ -1037,7 +1046,7 @@ void adc_power_off() portENTER_CRITICAL(&rtc_spinlock); //Bit1 0:Fsm 1: SW mode //Bit0 0:SW mode power down 1: SW mode power on - SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_DISABLE; + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; portEXIT_CRITICAL(&rtc_spinlock); } @@ -1161,7 +1170,7 @@ esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) uint8_t table_len = 1; //POWER ON SAR - adc_power_on(); + adc_power_always_on(); adc_gpio_init(adc_unit, channel); adc_set_i2s_data_len(adc_unit, table_len); adc_set_i2s_data_pattern(adc_unit, 0, channel, ADC_WIDTH_BIT_12, ADC_ATTEN_DB_11); @@ -1246,12 +1255,55 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit) return ESP_OK; } +esp_err_t adc1_i2s_mode_acquire() +{ + //lazy initialization + //for i2s, block until acquire the lock + _lock_acquire( &adc1_i2s_lock ); + ESP_LOGD( RTC_MODULE_TAG, "i2s mode takes adc1 lock." ); + portENTER_CRITICAL(&rtc_spinlock); + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; + //switch SARADC into DIG channel + SENS.sar_read_ctrl.sar1_dig_force = 1; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t adc1_adc_mode_acquire() +{ + //lazy initialization + //for adc1, block until acquire the lock + _lock_acquire( &adc1_i2s_lock ); + ESP_LOGD( RTC_MODULE_TAG, "adc mode takes adc1 lock." ); + portENTER_CRITICAL(&rtc_spinlock); + // for now the WiFi would use ADC2 and set xpd_sar force on. + // so we can not reset xpd_sar to fsm mode directly. + // We should handle this after the synchronization mechanism is established. + + //switch SARADC into RTC channel + SENS.sar_read_ctrl.sar1_dig_force = 0; + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t adc1_lock_release() +{ + RTC_MODULE_CHECK((uint32_t*)adc1_i2s_lock != NULL, "adc1 lock release called before acquire", ESP_ERR_INVALID_STATE ); + // for now the WiFi would use ADC2 and set xpd_sar force on. + // so we can not reset xpd_sar to fsm mode directly. + // We should handle this after the synchronization mechanism is established. + + _lock_release( &adc1_i2s_lock ); + ESP_LOGD( RTC_MODULE_TAG, "returns adc1 lock." ); + return ESP_OK; +} + int adc1_get_raw(adc1_channel_t channel) { uint16_t adc_value; RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); - - adc_power_on(); + adc1_adc_mode_acquire(); + adc_power_on(); portENTER_CRITICAL(&rtc_spinlock); //Adc Controler is Rtc module,not ulp coprocessor @@ -1274,6 +1326,7 @@ int adc1_get_raw(adc1_channel_t channel) while (SENS.sar_meas_start1.meas1_done_sar == 0); adc_value = SENS.sar_meas_start1.meas1_data_sar; portEXIT_CRITICAL(&rtc_spinlock); + adc1_lock_release(); return adc_value; } @@ -1467,6 +1520,8 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) rtc_gpio_input_disable(gpio); rtc_gpio_pullup_dis(gpio); rtc_gpio_pulldown_dis(gpio); + //force fsm + adc_power_always_on(); //Select power source of ADC RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode //set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2) @@ -1475,8 +1530,6 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) RTCCNTL.test_mux.ent_rtc = 1; //set sar2_en_test SENS.sar_start_force.sar2_en_test = 1; - //force fsm - SENS.sar_meas_wait2.force_xpd_sar = ADC_FORCE_ENABLE; //Select power source of ADC //set sar2 en force SENS.sar_meas_start2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW //set en_pad for channels 7,8,9 (bits 0x380) diff --git a/components/soc/esp32/include/soc/sens_reg.h b/components/soc/esp32/include/soc/sens_reg.h index adc9719056f..34834376e89 100644 --- a/components/soc/esp32/include/soc/sens_reg.h +++ b/components/soc/esp32/include/soc/sens_reg.h @@ -96,6 +96,7 @@ #define SENS_FORCE_XPD_SAR_M ((SENS_FORCE_XPD_SAR_V)<<(SENS_FORCE_XPD_SAR_S)) #define SENS_FORCE_XPD_SAR_V 0x3 #define SENS_FORCE_XPD_SAR_S 18 +#define SENS_FORCE_XPD_SAR_SW_M (BIT1) #define SENS_FORCE_XPD_SAR_FSM 0 // Use FSM to control power down #define SENS_FORCE_XPD_SAR_PD 2 // Force power down #define SENS_FORCE_XPD_SAR_PU 3 // Force power up diff --git a/examples/peripherals/i2s_adc_dac/main/app_main.c b/examples/peripherals/i2s_adc_dac/main/app_main.c index ee49eeaf36b..40798613f73 100755 --- a/examples/peripherals/i2s_adc_dac/main/app_main.c +++ b/examples/peripherals/i2s_adc_dac/main/app_main.c @@ -9,8 +9,11 @@ #include "driver/i2s.h" #include "driver/adc.h" #include "audio_example_file.h" +#include "esp_adc_cal.h" static const char* TAG = "ad/da"; +#define V_REF 1100 +#define ADC1_TEST_CHANNEL (ADC1_CHANNEL_7) #define PARTITION_NAME "storage" @@ -36,6 +39,10 @@ static const char* TAG = "ad/da"; #define EXAMPLE_I2S_FORMAT (I2S_CHANNEL_FMT_RIGHT_LEFT) //I2S channel number #define EXAMPLE_I2S_CHANNEL_NUM ((EXAMPLE_I2S_FORMAT < I2S_CHANNEL_FMT_ONLY_RIGHT) ? (2) : (1)) +//I2S built-in ADC unit +#define I2S_ADC_UNIT ADC_UNIT_1 +//I2S built-in ADC channel +#define I2S_ADC_CHANNEL ADC1_CHANNEL_0 //flash record size, for recording 5 seconds' data #define FLASH_RECORD_SIZE (EXAMPLE_I2S_CHANNEL_NUM * EXAMPLE_I2S_SAMPLE_RATE * EXAMPLE_I2S_SAMPLE_BITS / 8 * 5) @@ -45,6 +52,7 @@ static const char* TAG = "ad/da"; //flash read / write address #define FLASH_ADDR (0x200000) + /** * @brief I2S ADC/DAC mode init. */ @@ -66,7 +74,7 @@ void example_i2s_init() //init DAC pad i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); //init ADC pad - i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_0); + i2s_set_adc_mode(I2S_ADC_UNIT, I2S_ADC_CHANNEL); } /* @@ -193,10 +201,8 @@ void example_i2s_adc_dac(void*arg) ESP_LOGE(TAG, "Partition error: can't find partition name: %s\n", PARTITION_NAME); vTaskDelete(NULL); } - //1. Erase flash example_erase_flash(); - example_i2s_init(); int i2s_read_len = EXAMPLE_I2S_READ_LEN; int flash_wr_size = 0; size_t bytes_read, bytes_written; @@ -205,6 +211,7 @@ void example_i2s_adc_dac(void*arg) #if RECORD_IN_FLASH_EN char* i2s_read_buff = (char*) calloc(i2s_read_len, sizeof(char)); uint8_t* flash_write_buff = (uint8_t*) calloc(i2s_read_len, sizeof(char)); + i2s_adc_enable(EXAMPLE_I2S_NUM); while (flash_wr_size < FLASH_RECORD_SIZE) { //read data from I2S bus, in this case, from ADC. i2s_read(EXAMPLE_I2S_NUM, i2s_read_buff, i2s_read_len, &bytes_read, portMAX_DELAY); @@ -214,6 +221,7 @@ void example_i2s_adc_dac(void*arg) flash_wr_size += i2s_read_len; ets_printf("Sound recording %u%%\n", flash_wr_size * 100 / FLASH_RECORD_SIZE); } + i2s_adc_disable(EXAMPLE_I2S_NUM); free(i2s_read_buff); i2s_read_buff = NULL; free(flash_write_buff); @@ -257,10 +265,28 @@ void example_i2s_adc_dac(void*arg) vTaskDelete(NULL); } +void adc_read_task(void* arg) +{ + adc1_config_width(ADC_WIDTH_12Bit); + adc1_config_channel_atten(ADC1_TEST_CHANNEL, ADC_ATTEN_11db); + esp_adc_cal_characteristics_t characteristics; + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_11db, ADC_WIDTH_12Bit, ESP_ADC_CAL_VAL_DEFAULT_VREF, &characteristics); + + while(1) { + uint32_t voltage; + esp_err_t ret = esp_adc_cal_get_voltage(ADC1_TEST_CHANNEL, &characteristics, &voltage); + assert(ret==ESP_OK); + ESP_LOGI(TAG, "%d mV", voltage); + vTaskDelay(200 / portTICK_RATE_MS); + } +} + esp_err_t app_main() { + example_i2s_init(); esp_log_level_set("I2S", ESP_LOG_INFO); xTaskCreate(example_i2s_adc_dac, "example_i2s_adc_dac", 1024 * 2, NULL, 5, NULL); + xTaskCreate(adc_read_task, "ADC read task", 2048, NULL, 5, NULL); return ESP_OK; }