From f49b192a5e14f7021670e43a8273d7e6ffafa2bc Mon Sep 17 00:00:00 2001 From: fuzhibo Date: Mon, 9 Sep 2019 20:56:46 +0800 Subject: [PATCH] refactor the adc driver --- components/driver/CMakeLists.txt | 3 +- components/driver/adc.c | 513 ++++++++ components/driver/include/driver/adc.h | 69 +- components/driver/rtc_module.c | 1027 +---------------- components/soc/CMakeLists.txt | 1 + components/soc/esp32/adc_periph.c | 25 + components/soc/esp32/include/hal/adc_ll.h | 622 ++++++++++ components/soc/esp32/include/soc/adc_caps.h | 25 + .../soc/esp32/include/soc/adc_channel.h | 2 +- components/soc/esp32/sources.cmake | 3 +- components/soc/esp32s2beta/adc_periph.c | 25 + .../soc/esp32s2beta/include/hal/adc_ll.h | 610 ++++++++++ .../soc/esp32s2beta/include/soc/adc_caps.h | 25 + .../soc/esp32s2beta/include/soc/sens_reg.h | 7 + components/soc/esp32s2beta/sources.cmake | 3 +- components/soc/include/hal/adc_hal.h | 207 ++++ components/soc/include/hal/adc_types.h | 37 + components/soc/include/soc/adc_periph.h | 17 + components/soc/src/hal/adc_hal.c | 83 ++ docs/Doxyfile | 1 + 20 files changed, 2236 insertions(+), 1069 deletions(-) create mode 100644 components/driver/adc.c create mode 100644 components/soc/esp32/adc_periph.c create mode 100644 components/soc/esp32/include/hal/adc_ll.h create mode 100644 components/soc/esp32/include/soc/adc_caps.h create mode 100644 components/soc/esp32s2beta/adc_periph.c create mode 100644 components/soc/esp32s2beta/include/hal/adc_ll.h create mode 100644 components/soc/esp32s2beta/include/soc/adc_caps.h create mode 100644 components/soc/include/hal/adc_hal.h create mode 100644 components/soc/include/hal/adc_types.h create mode 100644 components/soc/src/hal/adc_hal.c diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 4733d09d1a..d8aebd6d40 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -1,4 +1,5 @@ -set(srcs +set(srcs + "adc.c" "can.c" "dac.c" "gpio.c" diff --git a/components/driver/adc.c b/components/driver/adc.c new file mode 100644 index 0000000000..afb7cb86a2 --- /dev/null +++ b/components/driver/adc.c @@ -0,0 +1,513 @@ +// Copyright 2019 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. + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/xtensa_api.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "esp_log.h" +#include "soc/rtc.h" +#include "rtc_io.h" +#include "adc.h" +#include "dac.h" +#include "sys/lock.h" +#include "driver/gpio.h" +#include "adc1_i2s_private.h" + +#include "hal/adc_types.h" +#include "hal/adc_hal.h" + +#define ADC_MAX_MEAS_NUM_DEFAULT (255) +#define ADC_MEAS_NUM_LIM_DEFAULT (1) +#define SAR_ADC_CLK_DIV_DEFUALT (2) + +#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIG_FORMAT_12BIT) +#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_11) +#define DIG_ADC_BIT_WIDTH_DEFUALT (ADC_WIDTH_BIT_12) + +#define ADC_CHECK_RET(fun_ret) ({ \ + if (fun_ret != ESP_OK) { \ + ESP_LOGE(ADC_TAG,"%s:%d\n",__FUNCTION__,__LINE__); \ + return ESP_FAIL; \ + } \ +}) + +static const char *ADC_TAG = "ADC"; + +#define ADC_CHECK(a, str, ret_val) ({ \ + if (!(a)) { \ + ESP_LOGE(ADC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ + return (ret_val); \ + } \ +}) + +#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel]) + +#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG) + +extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. +#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock) +#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock) + +/* +In ADC2, there're two locks used for different cases: +1. lock shared with app and WIFI: + when wifi using the ADC2, we assume it will never stop, + so app checks the lock and returns immediately if failed. + +2. lock shared between tasks: + when several tasks sharing the ADC2, we want to guarantee + all the requests will be handled. + Since conversions are short (about 31us), app returns the lock very soon, + we use a spinlock to stand there waiting to do conversions one by one. + +adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock. +*/ +//prevent ADC2 being used by wifi and other tasks at the same time. +static _lock_t adc2_wifi_lock; +//prevent ADC2 being used by tasks (regardless of WIFI) +static 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; +/*--------------------------------------------------------------- + ADC Common +---------------------------------------------------------------*/ + +void adc_power_always_on(void) +{ + ADC_ENTER_CRITICAL(); + adc_hal_set_power_manage(ADC_POWER_SW_ON); + ADC_EXIT_CRITICAL(); +} + +void adc_power_on(void) +{ + ADC_ENTER_CRITICAL(); + /* The power FSM controlled mode saves more power, while the ADC noise may get increased. */ +#ifndef CONFIG_ADC_FORCE_XPD_FSM + /* Set the power always on to increase precision. */ + adc_hal_set_power_manage(ADC_POWER_SW_ON); +#else + /* Use the FSM to turn off the power while not used to save power. */ + if (adc_hal_get_power_manage() != ADC_POWER_BY_FSM) { + adc_hal_set_power_manage(ADC_POWER_SW_ON); + } +#endif + ADC_EXIT_CRITICAL(); +} + +void adc_power_off(void) +{ + ADC_ENTER_CRITICAL(); + adc_hal_set_power_manage(ADC_POWER_SW_OFF); + ADC_EXIT_CRITICAL(); +} + +esp_err_t adc_set_clk_div(uint8_t clk_div) +{ + ADC_ENTER_CRITICAL(); + adc_hal_set_clk_div(clk_div); + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src) +{ + ADC_CHECK(src < ADC_I2S_DATA_SRC_MAX, "ADC i2s data source error", ESP_ERR_INVALID_ARG); + ADC_ENTER_CRITICAL(); + adc_hal_dig_set_data_source(src); + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) +{ + gpio_num_t gpio_num = 0; + if (adc_unit & ADC_UNIT_1) { + ADC_CHANNEL_CHECK(ADC_NUM_1, channel); + gpio_num = ADC_GET_IO_NUM(ADC_NUM_1, channel); + + ADC_CHECK_RET(rtc_gpio_init(gpio_num)); + ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); + ADC_CHECK_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); + } + if (adc_unit & ADC_UNIT_2) { + ADC_CHANNEL_CHECK(ADC_NUM_2, channel); + gpio_num = ADC_GET_IO_NUM(ADC_NUM_2, channel); + ADC_CHECK_RET(rtc_gpio_init(gpio_num)); + ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); + ADC_CHECK_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); + } + return ESP_OK; +} + +esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en) +{ + ADC_ENTER_CRITICAL(); + if (adc_unit & ADC_UNIT_1) { + adc_hal_output_invert(ADC_NUM_1, inv_en); + } + if (adc_unit & ADC_UNIT_2) { + adc_hal_output_invert(ADC_NUM_1, inv_en); + } + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t bits) +{ + ADC_CHECK(bits < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG); + ADC_ENTER_CRITICAL(); + if (adc_unit & ADC_UNIT_1) { + adc_hal_rtc_set_output_format(ADC_NUM_1, bits); + } + if (adc_unit & ADC_UNIT_2) { + adc_hal_rtc_set_output_format(ADC_NUM_2, bits); + adc_hal_pwdet_set_cct(SOC_ADC_PWDET_CCT_DEFAULT); + } + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +/* this function should be called in the critical section. */ +static int adc_convert(adc_ll_num_t adc_n, int channel) +{ + return adc_hal_convert(adc_n, channel); +} + +/*------------------------------------------------------------------------------------- + * ADC I2S + *------------------------------------------------------------------------------------*/ +esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) +{ + if (adc_unit & ADC_UNIT_1) { + ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_NUM_1)), "ADC1 not support DMA for now.", ESP_ERR_INVALID_ARG); + ADC_CHANNEL_CHECK(ADC_NUM_1, channel); + } + if (adc_unit & ADC_UNIT_2) { + ADC_CHECK((SOC_ADC_SUPPORT_DMA_MODE(ADC_NUM_2)), "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG); + ADC_CHANNEL_CHECK(ADC_NUM_2, channel); + } + + adc_ll_pattern_table_t adc1_pattern[1]; + adc_ll_pattern_table_t adc2_pattern[1]; + adc_hal_dig_config_t dig_cfg = { + .conv_limit_en = ADC_MEAS_NUM_LIM_DEFAULT, + .conv_limit_num = ADC_MAX_MEAS_NUM_DEFAULT, + .clk_div = SAR_ADC_CLK_DIV_DEFUALT, + .format = DIG_ADC_OUTPUT_FORMAT_DEFUALT, + .conv_mode = (adc_ll_convert_mode_t)adc_unit, + }; + + if (adc_unit & ADC_UNIT_1) { + adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; + adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; + adc1_pattern[0].channel = channel; + dig_cfg.adc1_pattern_len = 1; + dig_cfg.adc1_pattern = adc1_pattern; + } + if (adc_unit & ADC_UNIT_2) { + adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT; + adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT; + adc2_pattern[0].channel = channel; + dig_cfg.adc2_pattern_len = 1; + dig_cfg.adc2_pattern = adc2_pattern; + } + + ADC_ENTER_CRITICAL(); + adc_hal_init(); + adc_hal_dig_controller_config(&dig_cfg); + ADC_EXIT_CRITICAL(); + + return ESP_OK; +} + +/*------------------------------------------------------------------------------------- + * ADC1 + *------------------------------------------------------------------------------------*/ +esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num) +{ + ADC_CHANNEL_CHECK(ADC_NUM_1, channel); + int io = ADC_GET_IO_NUM(ADC_NUM_1, channel); + if (io < 0) { + return ESP_ERR_INVALID_ARG; + } else { + *gpio_num = (gpio_num_t)io; + } + + return ESP_OK; +} + +esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) +{ + ADC_CHANNEL_CHECK(ADC_NUM_1, channel); + ADC_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG); + adc_gpio_init(ADC_UNIT_1, channel); + adc_hal_set_atten(ADC_NUM_1, channel, atten); + return ESP_OK; +} + +esp_err_t adc1_config_width(adc_bits_width_t width_bit) +{ + ADC_CHECK(width_bit < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG); + adc_hal_rtc_set_output_format(ADC_NUM_1, width_bit); + adc_hal_output_invert(ADC_NUM_1, true); + return ESP_OK; +} + +esp_err_t adc1_i2s_mode_acquire(void) +{ + /* Use locks to avoid digtal and RTC controller conflicts. + for adc1, block until acquire the lock. */ + _lock_acquire( &adc1_i2s_lock ); + ESP_LOGD( ADC_TAG, "i2s mode takes adc1 lock." ); + ADC_ENTER_CRITICAL(); + adc_hal_set_power_manage(ADC_POWER_SW_ON); + /* switch SARADC into DIG channel */ + adc_hal_set_controller(ADC_NUM_1, ADC_CTRL_DIG); + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t adc1_adc_mode_acquire(void) +{ + /* Use locks to avoid digtal and RTC controller conflicts. + for adc1, block until acquire the lock. */ + _lock_acquire( &adc1_i2s_lock ); + ADC_ENTER_CRITICAL(); + /* switch SARADC into RTC channel. */ + adc_hal_set_controller(ADC_NUM_1, ADC_CTRL_RTC); + ADC_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t adc1_lock_release(void) +{ + ADC_CHECK((uint32_t *)adc1_i2s_lock != NULL, "adc1 lock release called before acquire", ESP_ERR_INVALID_STATE ); + /* Use locks to avoid digtal and RTC controller conflicts. + for adc1, block until acquire the lock. */ + _lock_release( &adc1_i2s_lock ); + return ESP_OK; +} + +int adc1_get_raw(adc1_channel_t channel) +{ + uint16_t adc_value; + ADC_CHANNEL_CHECK(ADC_NUM_1, channel); + adc1_adc_mode_acquire(); + + adc_power_on(); + ADC_ENTER_CRITICAL(); + /* disable other peripherals. */ + adc_hal_hall_disable(); + /* currently the LNA is not open, close it by default. */ + adc_hal_amp_disable(); + /* set controller */ + adc_hal_set_controller(ADC_NUM_1, ADC_CTRL_RTC); + /* start conversion */ + adc_value = adc_convert(ADC_NUM_1, channel); + ADC_EXIT_CRITICAL(); + + adc1_lock_release(); + return adc_value; +} + +int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw() instead +{ + return adc1_get_raw(channel); +} + +void adc1_ulp_enable(void) +{ + adc_power_on(); + + ADC_ENTER_CRITICAL(); + adc_hal_set_controller(ADC_NUM_1, ADC_CTRL_ULP); + /* since most users do not need LNA and HALL with uLP, we disable them here + open them in the uLP if needed. */ + /* disable other peripherals. */ + adc_hal_hall_disable(); + adc_hal_amp_disable(); + ADC_EXIT_CRITICAL(); +} + +/*--------------------------------------------------------------- + ADC2 +---------------------------------------------------------------*/ +esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num) +{ + ADC_CHANNEL_CHECK(ADC_NUM_2, channel); + int io = ADC_GET_IO_NUM(ADC_NUM_2, channel); + if (io < 0) { + return ESP_ERR_INVALID_ARG; + } else { + *gpio_num = (gpio_num_t)io; + } + + return ESP_OK; +} + +esp_err_t adc2_wifi_acquire(void) +{ + /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */ + _lock_acquire( &adc2_wifi_lock ); + ESP_LOGD( ADC_TAG, "Wi-Fi takes adc2 lock." ); + return ESP_OK; +} + +esp_err_t adc2_wifi_release(void) +{ + ADC_CHECK((uint32_t *)adc2_wifi_lock != NULL, "wifi release called before acquire", ESP_ERR_INVALID_STATE ); + + _lock_release( &adc2_wifi_lock ); + ESP_LOGD( ADC_TAG, "Wi-Fi returns adc2 lock." ); + return ESP_OK; +} + +static esp_err_t adc2_pad_init(adc2_channel_t channel) +{ + gpio_num_t gpio_num = 0; + ADC_CHECK_RET(adc2_pad_get_io_num(channel, &gpio_num)); + ADC_CHECK_RET(rtc_gpio_init(gpio_num)); + ADC_CHECK_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); + ADC_CHECK_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); + return ESP_OK; +} + +esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) +{ + ADC_CHANNEL_CHECK(ADC_NUM_2, channel); + ADC_CHECK(atten <= ADC_ATTEN_11db, "ADC2 Atten Err", ESP_ERR_INVALID_ARG); + + adc2_pad_init(channel); + portENTER_CRITICAL( &adc2_spinlock ); + + //lazy initialization + //avoid collision with other tasks + if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) { + //try the lock, return if failed (wifi using). + portEXIT_CRITICAL( &adc2_spinlock ); + return ESP_ERR_TIMEOUT; + } + adc_hal_set_atten(ADC_NUM_2, channel, atten); + _lock_release( &adc2_wifi_lock ); + + portEXIT_CRITICAL( &adc2_spinlock ); + return ESP_OK; +} + +static inline void adc2_config_width(adc_bits_width_t width_bit) +{ + ADC_ENTER_CRITICAL(); + adc_hal_rtc_set_output_format(ADC_NUM_2, width_bit); + adc_hal_pwdet_set_cct(SOC_ADC_PWDET_CCT_DEFAULT); + adc_hal_output_invert(ADC_NUM_2, true); + ADC_EXIT_CRITICAL(); +} + +static inline void adc2_dac_disable( adc2_channel_t channel) +{ + if ( channel == ADC2_CHANNEL_8 ) { // the same as DAC channel 1 + dac_output_disable(DAC_CHANNEL_1); + } else if ( channel == ADC2_CHANNEL_9 ) { + dac_output_disable(DAC_CHANNEL_2); + } +} + +//registers in critical section with adc1: +//SENS_SAR_START_FORCE_REG, +esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out) +{ + uint16_t adc_value = 0; + ADC_CHECK(channel < ADC2_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); + + //in critical section with whole rtc module + adc_power_on(); + + //avoid collision with other tasks + portENTER_CRITICAL(&adc2_spinlock); + //lazy initialization + //try the lock, return if failed (wifi using). + if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) { + portEXIT_CRITICAL( &adc2_spinlock ); + return ESP_ERR_TIMEOUT; + } + + //disable other peripherals +#ifdef CONFIG_ADC_DISABLE_DAC + adc2_dac_disable(channel); +#endif + // set controller + // in critical section with whole rtc module + // because the PWDET use the same registers, place it here. + adc2_config_width(width_bit); + adc_hal_set_controller(ADC_NUM_2, ADC_CTRL_RTC); + //start converting + adc_value = adc_convert(ADC_NUM_2, channel); + _lock_release( &adc2_wifi_lock ); + portEXIT_CRITICAL(&adc2_spinlock); + + *raw_out = (int)adc_value; + return ESP_OK; +} + +esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) +{ + adc_power_always_on(); //Select power source of ADC + if (adc_hal_vref_output(gpio) != true) { + return ESP_ERR_INVALID_ARG; + } else { + //Configure RTC gpio + rtc_gpio_init(gpio); + rtc_gpio_set_direction(gpio, RTC_GPIO_MODE_DISABLED); + rtc_gpio_pullup_dis(gpio); + rtc_gpio_pulldown_dis(gpio); + return ESP_OK; + } +} + +/*--------------------------------------------------------------- + HALL SENSOR +---------------------------------------------------------------*/ + +static int hall_sensor_get_value(void) //hall sensor without LNA +{ + int hall_value; + + adc_power_on(); + + ADC_ENTER_CRITICAL(); + /* disable other peripherals. */ + adc_hal_amp_disable(); + adc_hal_hall_enable(); + // set controller + adc_hal_set_controller( ADC_NUM_1, ADC_CTRL_RTC ); + hall_value = adc_hal_hall_convert(); + ADC_EXIT_CRITICAL(); + + return hall_value; +} + +int hall_sensor_read(void) +{ + adc_gpio_init(ADC_NUM_1, ADC1_CHANNEL_0); + adc_gpio_init(ADC_NUM_1, ADC1_CHANNEL_3); + adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_0); + return hall_sensor_get_value(); +} diff --git a/components/driver/include/driver/adc.h b/components/driver/include/driver/adc.h index b0a6492602..17f73e4fa7 100644 --- a/components/driver/include/driver/adc.h +++ b/components/driver/include/driver/adc.h @@ -24,22 +24,7 @@ extern "C" { #include "esp_err.h" #include "driver/gpio.h" #include "soc/adc_periph.h" - -typedef enum { - ADC_ATTEN_DB_0 = 0, /*!= 0) { - SYSCON.saradc_fsm.rstb_wait = rst_wait; - } - // Internal FSM start wait time - if (start_wait >= 0) { - SYSCON.saradc_fsm.start_wait = start_wait; - } - // Internal FSM standby wait time - if (standby_wait >= 0) { - SYSCON.saradc_fsm.standby_wait = standby_wait; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - // Internal FSM reset wait time - if (rst_wait >= 0) { - SYSCON.saradc_fsm_wait.rstb_wait = rst_wait; - } - // Internal FSM start wait time - if (start_wait >= 0) { - SYSCON.saradc_fsm_wait.xpd_wait = start_wait; - } - // Internal FSM standby wait time - if (standby_wait >= 0) { - SYSCON.saradc_fsm_wait.standby_wait = standby_wait; - } -#endif - // Internal FSM standby sample cycle - if (sample_cycle >= 0) { - SYSCON.saradc_fsm.sample_cycle = sample_cycle; - } - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -static esp_err_t adc_set_data_format(adc_i2s_encode_t mode) -{ - portENTER_CRITICAL(&rtc_spinlock); - //data format: - //0: ADC_ENCODE_12BIT [15:12]-channel [11:0]-12 bits ADC data - //1: ADC_ENCODE_11BIT [15]-1 [14:11]-channel [10:0]-11 bits ADC data, the resolution should not be larger than 11 bits in this case. - SYSCON.saradc_ctrl.data_sar_sel = mode; - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -static esp_err_t adc_set_measure_limit(uint8_t meas_num, bool lim_en) -{ - portENTER_CRITICAL(&rtc_spinlock); - // Set max measure number - SYSCON.saradc_ctrl2.max_meas_num = meas_num; - // Enable max measure number limit - SYSCON.saradc_ctrl2.meas_num_limit = lim_en; - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -static esp_err_t adc_set_work_mode(adc_unit_t adc_unit) -{ - portENTER_CRITICAL(&rtc_spinlock); - if (adc_unit == ADC_UNIT_1) { - // saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc - SYSCON.saradc_ctrl.work_mode = 0; - //ENABLE ADC 0: ADC1 1: ADC2, only work for single SAR mode - SYSCON.saradc_ctrl.sar_sel = 0; - } else if (adc_unit == ADC_UNIT_2) { - // saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc - SYSCON.saradc_ctrl.work_mode = 0; - //ENABLE ADC1 0: SAR1 1: SAR2 only work for single SAR mode - SYSCON.saradc_ctrl.sar_sel = 1; - } else if (adc_unit == ADC_UNIT_BOTH) { - // saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc - SYSCON.saradc_ctrl.work_mode = 1; - } else if (adc_unit == ADC_UNIT_ALTER) { - // saradc mode sel : 0--single saradc; 1--double saradc; 2--alternative saradc - SYSCON.saradc_ctrl.work_mode = 2; - } - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -static esp_err_t adc_set_atten(adc_unit_t adc_unit, adc_channel_t channel, adc_atten_t atten) -{ - ADC_CHECK_UNIT(adc_unit); - if (adc_unit & ADC_UNIT_1) { - RTC_MODULE_CHECK((adc1_channel_t)channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); - } - RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG); - - portENTER_CRITICAL(&rtc_spinlock); - if (adc_unit & ADC_UNIT_1) { - //SAR1_atten - SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, SENS_SAR1_ATTEN_VAL_MASK, atten, (channel * 2)); - } - if (adc_unit & ADC_UNIT_2) { - //SAR2_atten - SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, SENS_SAR2_ATTEN_VAL_MASK, atten, (channel * 2)); - } - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -void adc_power_always_on(void) -{ - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; -#endif - portEXIT_CRITICAL(&rtc_spinlock); -} - -void adc_power_on(void) -{ - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - //The power FSM controlled mode saves more power, while the ADC noise may get increased. -#ifndef CONFIG_ADC_FORCE_XPD_FSM - //Set the power always on to increase precision. - SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; -#else - //Use the FSM to turn off the power while not used to save power. - 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; - } -#endif -#elif CONFIG_IDF_TARGET_ESP32S2BETA - //The power FSM controlled mode saves more power, while the ADC noise may get increased. -#ifndef CONFIG_ADC_FORCE_XPD_FSM - //Set the power always on to increase precision. - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; -#else - //Use the FSM to turn off the power while not used to save power. - if (SENS.sar_power_xpd_sar.force_xpd_sar & SENS_FORCE_XPD_SAR_SW_M) { - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; - } else { - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM; - } -#endif -#endif - portEXIT_CRITICAL(&rtc_spinlock); -} - -void adc_power_off(void) -{ - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - //Bit1 0:Fsm 1: SW mode - //Bit0 0:SW mode power down 1: SW mode power on - SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; -#endif - - portEXIT_CRITICAL(&rtc_spinlock); -} - -esp_err_t adc_set_clk_div(uint8_t clk_div) -{ - portENTER_CRITICAL(&rtc_spinlock); - // ADC clock divided from APB clk, 80 / 2 = 40Mhz, - SYSCON.saradc_ctrl.sar_clk_div = clk_div; - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src) -{ - RTC_MODULE_CHECK(src < ADC_I2S_DATA_SRC_MAX, "ADC i2s data source error", ESP_ERR_INVALID_ARG); - portENTER_CRITICAL(&rtc_spinlock); - // 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix - SYSCON.saradc_ctrl.data_to_i2s = src; - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) -{ - ADC_CHECK_UNIT(adc_unit); - gpio_num_t gpio_num = 0; - if (adc_unit & ADC_UNIT_1) { - RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG); - ADC1_CHECK_FUNCTION_RET(adc1_pad_get_io_num((adc1_channel_t) channel, &gpio_num)); - ADC1_CHECK_FUNCTION_RET(rtc_gpio_init(gpio_num)); - ADC1_CHECK_FUNCTION_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - ADC1_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); - } - return ESP_OK; -} - -esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en) -{ - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - if (adc_unit & ADC_UNIT_1) { - // Enable ADC data invert - SENS.sar_read_ctrl.sar1_data_inv = inv_en; - } - if (adc_unit & ADC_UNIT_2) { - // Enable ADC data invert - SENS.sar_read_ctrl2.sar2_data_inv = inv_en; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if (adc_unit & ADC_UNIT_1) { - // Enable ADC data invert - SENS.sar_reader1_ctrl.sar1_data_inv = inv_en; - } - if (adc_unit & ADC_UNIT_2) { - // Enable ADC data invert - SENS.sar_reader2_ctrl.sar2_data_inv = inv_en; - } -#endif - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t bits) -{ - ADC_CHECK_UNIT(adc_unit); - RTC_MODULE_CHECK(bits < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG); - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - if (adc_unit & ADC_UNIT_1) { - SENS.sar_start_force.sar1_bit_width = bits; - SENS.sar_read_ctrl.sar1_sample_bit = bits; - } - if (adc_unit & ADC_UNIT_2) { - SENS.sar_start_force.sar2_bit_width = bits; - SENS.sar_read_ctrl2.sar2_sample_bit = bits; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if (adc_unit & ADC_UNIT_1) { - SENS.sar_meas1_ctrl1.sar1_bit_width = bits; - SENS.sar_reader1_ctrl.sar1_sample_bit = bits; - } - if (adc_unit & ADC_UNIT_2) { - SENS.sar_meas2_ctrl1.sar2_bit_width = bits; - SENS.sar_reader2_ctrl.sar2_sample_bit = bits; - } -#endif - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -// this function should be called in the critical section -static void adc_set_controller(adc_unit_t unit, adc_controller_t ctrl ) -{ -#if CONFIG_IDF_TARGET_ESP32 - if ( unit == ADC_UNIT_1 ) { - switch( ctrl ) { - case ADC_CTRL_RTC: - SENS.sar_read_ctrl.sar1_dig_force = false; //RTC controller controls the ADC, not digital controller - SENS.sar_meas_start1.meas1_start_force = true; //RTC controller controls the ADC,not ulp coprocessor - SENS.sar_meas_start1.sar1_en_pad_force = true; //RTC controller controls the data port, not ulp coprocessor - SENS.sar_touch_ctrl1.xpd_hall_force = true; // RTC controller controls the hall sensor power,not ulp coprocessor - SENS.sar_touch_ctrl1.hall_phase_force = true; // RTC controller controls the hall sensor phase,not ulp coprocessor - break; - case ADC_CTRL_ULP: - SENS.sar_read_ctrl.sar1_dig_force = false; - SENS.sar_meas_start1.meas1_start_force = false; - SENS.sar_meas_start1.sar1_en_pad_force = false; - SENS.sar_touch_ctrl1.xpd_hall_force = false; - SENS.sar_touch_ctrl1.hall_phase_force = false; - break; - case ADC_CTRL_DIG: - SENS.sar_read_ctrl.sar1_dig_force = true; - SENS.sar_meas_start1.meas1_start_force = true; - SENS.sar_meas_start1.sar1_en_pad_force = true; - SENS.sar_touch_ctrl1.xpd_hall_force = true; - SENS.sar_touch_ctrl1.hall_phase_force = true; - break; - default: - ESP_LOGE(TAG, "adc1 selects invalid controller"); - break; - } - } else if ( unit == ADC_UNIT_2) { - switch( ctrl ) { - case ADC_CTRL_RTC: - SENS.sar_meas_start2.meas2_start_force = true; //RTC controller controls the ADC,not ulp coprocessor - SENS.sar_meas_start2.sar2_en_pad_force = true; //RTC controller controls the data port, not ulp coprocessor - SENS.sar_read_ctrl2.sar2_dig_force = false; //RTC controller controls the ADC, not digital controller - SENS.sar_read_ctrl2.sar2_pwdet_force = false; //RTC controller controls the ADC, not PWDET - SYSCON.saradc_ctrl.sar2_mux = true; //RTC controller controls the ADC, not PWDET - break; - case ADC_CTRL_ULP: - SENS.sar_meas_start2.meas2_start_force = false; - SENS.sar_meas_start2.sar2_en_pad_force = false; - SENS.sar_read_ctrl2.sar2_dig_force = false; - SENS.sar_read_ctrl2.sar2_pwdet_force = false; - SYSCON.saradc_ctrl.sar2_mux = true; - break; - case ADC_CTRL_DIG: - SENS.sar_meas_start2.meas2_start_force = true; - SENS.sar_meas_start2.sar2_en_pad_force = true; - SENS.sar_read_ctrl2.sar2_dig_force = true; - SENS.sar_read_ctrl2.sar2_pwdet_force = false; - SYSCON.saradc_ctrl.sar2_mux = true; - break; - case ADC2_CTRL_PWDET: - //currently only used by Wi-Fi - SENS.sar_meas_start2.meas2_start_force = true; - SENS.sar_meas_start2.sar2_en_pad_force = true; - SENS.sar_read_ctrl2.sar2_dig_force = false; - SENS.sar_read_ctrl2.sar2_pwdet_force = true; - SYSCON.saradc_ctrl.sar2_mux = false; - break; - default: - ESP_LOGE(TAG, "adc2 selects invalid controller"); - break; - } - } else { - ESP_LOGE(TAG, "invalid adc unit"); - assert(0); - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if ( unit == ADC_UNIT_1 ) { - switch( ctrl ) { - case ADC_CTRL_RTC: - SENS.sar_meas1_mux.sar1_dig_force = false; //RTC controller controls the ADC, not digital controller - SENS.sar_meas1_ctrl2.meas1_start_force = true; //RTC controller controls the ADC,not ulp coprocessor - SENS.sar_meas1_ctrl2.sar1_en_pad_force = true; //RTC controller controls the data port, not ulp coprocessor - SENS.sar_hall_ctrl.xpd_hall_force = true; // RTC controller controls the hall sensor power,not ulp coprocessor - SENS.sar_hall_ctrl.hall_phase_force = true; // RTC controller controls the hall sensor phase,not ulp coprocessor - break; - case ADC_CTRL_ULP: - SENS.sar_meas1_mux.sar1_dig_force = false; - SENS.sar_meas1_ctrl2.meas1_start_force = false; - SENS.sar_meas1_ctrl2.sar1_en_pad_force = false; - SENS.sar_hall_ctrl.xpd_hall_force = false; - SENS.sar_hall_ctrl.hall_phase_force = false; - break; - case ADC_CTRL_DIG: - SENS.sar_meas1_mux.sar1_dig_force = true; - SENS.sar_meas1_ctrl2.meas1_start_force = true; - SENS.sar_meas1_ctrl2.sar1_en_pad_force = true; - SENS.sar_hall_ctrl.xpd_hall_force = true; - SENS.sar_hall_ctrl.hall_phase_force = true; - break; - default: - ESP_LOGE(TAG, "adc1 selects invalid controller"); - break; - } - } else if ( unit == ADC_UNIT_2) { - switch( ctrl ) { - case ADC_CTRL_RTC: - SENS.sar_meas2_ctrl2.meas2_start_force = true; //RTC controller controls the ADC,not ulp coprocessor - SENS.sar_meas2_ctrl2.sar2_en_pad_force = true; //RTC controller controls the data port, not ulp coprocessor - break; - case ADC_CTRL_ULP: - SENS.sar_meas2_ctrl2.meas2_start_force = false; - SENS.sar_meas2_ctrl2.sar2_en_pad_force = false; - break; - case ADC_CTRL_DIG: - SENS.sar_meas2_ctrl2.meas2_start_force = true; - SENS.sar_meas2_ctrl2.sar2_en_pad_force = true; - break; - case ADC2_CTRL_PWDET: - //currently only used by Wi-Fi - SENS.sar_meas2_ctrl2.meas2_start_force = true; - SENS.sar_meas2_ctrl2.sar2_en_pad_force = true; - break; - default: - ESP_LOGE(TAG, "adc2 selects invalid controller"); - break; - } - } else { - ESP_LOGE(TAG, "invalid adc unit"); - assert(0); - } -#endif -} - -// this function should be called in the critical section -static int adc_convert( adc_unit_t unit, int channel) -{ - uint16_t adc_value = 0; -#if CONFIG_IDF_TARGET_ESP32 - if ( unit == ADC_UNIT_1 ) { - SENS.sar_meas_start1.sar1_en_pad = (1 << channel); //only one channel is selected. - while (SENS.sar_slave_addr1.meas_status != 0); - SENS.sar_meas_start1.meas1_start_sar = 0; - SENS.sar_meas_start1.meas1_start_sar = 1; - while (SENS.sar_meas_start1.meas1_done_sar == 0); - adc_value = SENS.sar_meas_start1.meas1_data_sar; - } else if ( unit == ADC_UNIT_2 ) { - SENS.sar_meas_start2.sar2_en_pad = (1 << channel); //only one channel is selected. - - SENS.sar_meas_start2.meas2_start_sar = 0; //start force 0 - SENS.sar_meas_start2.meas2_start_sar = 1; //start force 1 - while (SENS.sar_meas_start2.meas2_done_sar == 0) {}; //read done - adc_value = SENS.sar_meas_start2.meas2_data_sar; - } else { - ESP_LOGE(TAG, "invalid adc unit"); - return ESP_ERR_INVALID_ARG; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if ( unit == ADC_UNIT_1 ) { - SENS.sar_meas1_ctrl2.sar1_en_pad = (1 << channel); //only one channel is selected. - while (SENS.sar_slave_addr1.meas_status != 0); - SENS.sar_meas1_ctrl2.meas1_start_sar = 0; - SENS.sar_meas1_ctrl2.meas1_start_sar = 1; - while (SENS.sar_meas1_ctrl2.meas1_done_sar == 0); - adc_value = SENS.sar_meas1_ctrl2.meas1_data_sar; - } else if ( unit == ADC_UNIT_2 ) { - SENS.sar_meas2_ctrl2.sar2_en_pad = (1 << channel); //only one channel is selected. - - SENS.sar_meas2_ctrl2.meas2_start_sar = 0; //start force 0 - SENS.sar_meas2_ctrl2.meas2_start_sar = 1; //start force 1 - while (SENS.sar_meas2_ctrl2.meas2_done_sar == 0) {}; //read done - adc_value = SENS.sar_meas2_ctrl2.meas2_data_sar; - } else { - ESP_LOGE(TAG, "invalid adc unit"); - return ESP_ERR_INVALID_ARG; - } -#endif - return adc_value; -} - -/*------------------------------------------------------------------------------------- - * ADC I2S - *------------------------------------------------------------------------------------*/ -static esp_err_t adc_set_i2s_data_len(adc_unit_t adc_unit, int patt_len) -{ - ADC_CHECK_UNIT(adc_unit); - RTC_MODULE_CHECK((patt_len < ADC_PATT_LEN_MAX) && (patt_len > 0), "ADC pattern length error", ESP_ERR_INVALID_ARG); - portENTER_CRITICAL(&rtc_spinlock); - if(adc_unit & ADC_UNIT_1) { - SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1; - } - if(adc_unit & ADC_UNIT_2) { - SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1; - } - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -static esp_err_t adc_set_i2s_data_pattern(adc_unit_t adc_unit, int seq_num, adc_channel_t channel, adc_bits_width_t bits, adc_atten_t atten) -{ - ADC_CHECK_UNIT(adc_unit); - if (adc_unit & ADC_UNIT_1) { - RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG); - } - RTC_MODULE_CHECK(bits < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG); - RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG); - - portENTER_CRITICAL(&rtc_spinlock); - //Configure pattern table, each 8 bit defines one channel - //[7:4]-channel [3:2]-bit width [1:0]- attenuation - //BIT WIDTH: 3: 12BIT 2: 11BIT 1: 10BIT 0: 9BIT - //ATTEN: 3: ATTEN = 11dB 2: 6dB 1: 2.5dB 0: 0dB - uint8_t val = (channel << 4) | (bits << 2) | (atten << 0); - if (adc_unit & ADC_UNIT_1) { - SYSCON.saradc_sar1_patt_tab[seq_num / 4] &= (~(0xff << ((3 - (seq_num % 4)) * 8))); - SYSCON.saradc_sar1_patt_tab[seq_num / 4] |= (val << ((3 - (seq_num % 4)) * 8)); - } - if (adc_unit & ADC_UNIT_2) { - SYSCON.saradc_sar2_patt_tab[seq_num / 4] &= (~(0xff << ((3 - (seq_num % 4)) * 8))); - SYSCON.saradc_sar2_patt_tab[seq_num / 4] |= (val << ((3 - (seq_num % 4)) * 8)); - } - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) -{ - ADC_CHECK_UNIT(adc_unit); - if (adc_unit & ADC_UNIT_1) { - RTC_MODULE_CHECK((adc1_channel_t) channel < ADC1_CHANNEL_MAX, "ADC1 channel error", ESP_ERR_INVALID_ARG); - } - - uint8_t table_len = 1; - //POWER ON SAR - 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); - portENTER_CRITICAL(&rtc_spinlock); - if (adc_unit & ADC_UNIT_1) { - adc_set_controller( ADC_UNIT_1, ADC_CTRL_DIG ); - } - if (adc_unit & ADC_UNIT_2) { - adc_set_controller( ADC_UNIT_2, ADC_CTRL_DIG ); - } - portEXIT_CRITICAL(&rtc_spinlock); - adc_set_i2s_data_source(ADC_I2S_DATA_SRC_ADC); - adc_set_clk_div(SAR_ADC_CLK_DIV_DEFAULT); - // Set internal FSM wait time. - adc_set_fsm_time(ADC_FSM_RSTB_WAIT_DEFAULT, ADC_FSM_START_WAIT_DEFAULT, ADC_FSM_STANDBY_WAIT_DEFAULT, - ADC_FSM_TIME_KEEP); - adc_set_work_mode(adc_unit); - adc_set_data_format(ADC_ENCODE_12BIT); - adc_set_measure_limit(ADC_MAX_MEAS_NUM_DEFAULT, ADC_MEAS_NUM_LIM_DEFAULT); - //Invert The Level, Invert SAR ADC1 data - adc_set_data_inv(adc_unit, true); - return ESP_OK; - } - -/*------------------------------------------------------------------------------------- - * ADC1 - *------------------------------------------------------------------------------------*/ -esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num) -{ - RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC1 Channel Err", ESP_ERR_INVALID_ARG); - - switch (channel) { - case ADC1_CHANNEL_0: - *gpio_num = ADC1_CHANNEL_0_GPIO_NUM; - break; - case ADC1_CHANNEL_1: - *gpio_num = ADC1_CHANNEL_1_GPIO_NUM; - break; - case ADC1_CHANNEL_2: - *gpio_num = ADC1_CHANNEL_2_GPIO_NUM; - break; - case ADC1_CHANNEL_3: - *gpio_num = ADC1_CHANNEL_3_GPIO_NUM; - break; - case ADC1_CHANNEL_4: - *gpio_num = ADC1_CHANNEL_4_GPIO_NUM; - break; - case ADC1_CHANNEL_5: - *gpio_num = ADC1_CHANNEL_5_GPIO_NUM; - break; - case ADC1_CHANNEL_6: - *gpio_num = ADC1_CHANNEL_6_GPIO_NUM; - break; - case ADC1_CHANNEL_7: - *gpio_num = ADC1_CHANNEL_7_GPIO_NUM; - break; - default: - return ESP_ERR_INVALID_ARG; - } - - return ESP_OK; -} - -esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) -{ - RTC_MODULE_CHECK(channel < ADC1_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); - RTC_MODULE_CHECK(atten < ADC_ATTEN_MAX, "ADC Atten Err", ESP_ERR_INVALID_ARG); - adc_gpio_init(ADC_UNIT_1, channel); - adc_set_atten(ADC_UNIT_1, channel, atten); - return ESP_OK; -} - -esp_err_t adc1_config_width(adc_bits_width_t width_bit) -{ - RTC_MODULE_CHECK(width_bit < ADC_WIDTH_MAX, "ADC bit width error", ESP_ERR_INVALID_ARG); - adc_set_data_width(ADC_UNIT_1, width_bit); - adc_set_data_inv(ADC_UNIT_1, true); - return ESP_OK; -} - -static inline void adc1_fsm_disable(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - //channel is set in the convert function - SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; - //disable FSM, it's only used by the LNA. - SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0; - SENS.sar_meas_ctrl.amp_short_ref_fsm = 0; - SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0; - SENS.sar_meas_wait1.sar_amp_wait1 = 1; - SENS.sar_meas_wait1.sar_amp_wait2 = 1; - SENS.sar_meas_wait2.sar_amp_wait3 = 1; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - //channel is set in the convert function - SENS.sar_meas1_ctrl1.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; - //disable FSM, it's only used by the LNA. - SENS.sar_amp_ctrl3.amp_rst_fb_fsm = 0; - SENS.sar_amp_ctrl3.amp_short_ref_fsm = 0; - SENS.sar_amp_ctrl3.amp_short_ref_gnd_fsm = 0; - SENS.sar_amp_ctrl1.sar_amp_wait1 = 1; - SENS.sar_amp_ctrl1.sar_amp_wait2 = 1; - SENS.sar_amp_ctrl2.sar_amp_wait3 = 1; -#endif -} - -esp_err_t adc1_i2s_mode_acquire(void) -{ - //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); -#if CONFIG_IDF_TARGET_ESP32 - 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; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; - //switch SARADC into DIG channel - SENS.sar_meas1_mux.sar1_dig_force = 1; -#endif - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc1_adc_mode_acquire(void) -{ - //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 -#if CONFIG_IDF_TARGET_ESP32 - SENS.sar_read_ctrl.sar1_dig_force = 0; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - SENS.sar_meas1_mux.sar1_dig_force = 0; -#endif - portEXIT_CRITICAL(&rtc_spinlock); - return ESP_OK; -} - -esp_err_t adc1_lock_release(void) -{ - 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 ); - 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); - adc1_adc_mode_acquire(); - adc_power_on(); - - portENTER_CRITICAL(&rtc_spinlock); - //disable other peripherals - adc1_hall_enable(false); - adc1_fsm_disable(); //currently the LNA is not open, close it by default - //set controller - adc_set_controller( ADC_UNIT_1, ADC_CTRL_RTC ); - //start conversion - adc_value = adc_convert( ADC_UNIT_1, channel ); - portEXIT_CRITICAL(&rtc_spinlock); - adc1_lock_release(); - return adc_value; -} - -void adc1_ulp_enable(void) -{ - adc_power_on(); - - portENTER_CRITICAL(&rtc_spinlock); - adc_set_controller( ADC_UNIT_1, ADC_CTRL_ULP ); - // since most users do not need LNA and HALL with uLP, we disable them here - // open them in the uLP if needed. - adc1_fsm_disable(); - adc1_hall_enable(false); - portEXIT_CRITICAL(&rtc_spinlock); -} - -/*--------------------------------------------------------------- - ADC2 ----------------------------------------------------------------*/ -esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num) -{ - RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC2 Channel Err", ESP_ERR_INVALID_ARG); - - switch (channel) { - case ADC2_CHANNEL_0: - *gpio_num = ADC2_CHANNEL_0_GPIO_NUM; - break; - case ADC2_CHANNEL_1: - *gpio_num = ADC2_CHANNEL_1_GPIO_NUM; - break; - case ADC2_CHANNEL_2: - *gpio_num = ADC2_CHANNEL_2_GPIO_NUM; - break; - case ADC2_CHANNEL_3: - *gpio_num = ADC2_CHANNEL_3_GPIO_NUM; - break; - case ADC2_CHANNEL_4: - *gpio_num = ADC2_CHANNEL_4_GPIO_NUM; - break; - case ADC2_CHANNEL_5: - *gpio_num = ADC2_CHANNEL_5_GPIO_NUM; - break; - case ADC2_CHANNEL_6: - *gpio_num = ADC2_CHANNEL_6_GPIO_NUM; - break; - case ADC2_CHANNEL_7: - *gpio_num = ADC2_CHANNEL_7_GPIO_NUM; - break; - case ADC2_CHANNEL_8: - *gpio_num = ADC2_CHANNEL_8_GPIO_NUM; - break; - case ADC2_CHANNEL_9: - *gpio_num = ADC2_CHANNEL_9_GPIO_NUM; - break; - default: - return ESP_ERR_INVALID_ARG; - } - - return ESP_OK; -} - -esp_err_t adc2_wifi_acquire(void) -{ - //lazy initialization - //for wifi, block until acquire the lock - _lock_acquire( &adc2_wifi_lock ); - ESP_LOGD( RTC_MODULE_TAG, "Wi-Fi takes adc2 lock." ); - return ESP_OK; -} - -esp_err_t adc2_wifi_release(void) -{ - RTC_MODULE_CHECK((uint32_t*)adc2_wifi_lock != NULL, "wifi release called before acquire", ESP_ERR_INVALID_STATE ); - - _lock_release( &adc2_wifi_lock ); - ESP_LOGD( RTC_MODULE_TAG, "Wi-Fi returns adc2 lock." ); - return ESP_OK; -} - -static esp_err_t adc2_pad_init(adc2_channel_t channel) -{ - gpio_num_t gpio_num = 0; - ADC2_CHECK_FUNCTION_RET(adc2_pad_get_io_num(channel, &gpio_num)); - ADC2_CHECK_FUNCTION_RET(rtc_gpio_init(gpio_num)); - ADC1_CHECK_FUNCTION_RET(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED)); - ADC2_CHECK_FUNCTION_RET(gpio_set_pull_mode(gpio_num, GPIO_FLOATING)); - return ESP_OK; -} - -esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) -{ - RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC2 Channel Err", ESP_ERR_INVALID_ARG); - RTC_MODULE_CHECK(atten <= ADC_ATTEN_11db, "ADC2 Atten Err", ESP_ERR_INVALID_ARG); - - adc2_pad_init(channel); - portENTER_CRITICAL( &adc2_spinlock ); - - //lazy initialization - //avoid collision with other tasks - if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) { - //try the lock, return if failed (wifi using). - portEXIT_CRITICAL( &adc2_spinlock ); - return ESP_ERR_TIMEOUT; - } - SENS.sar_atten2 = ( SENS.sar_atten2 & ~(3<<(channel*2)) ) | ((atten&3) << (channel*2)); - _lock_release( &adc2_wifi_lock ); - - portEXIT_CRITICAL( &adc2_spinlock ); - return ESP_OK; -} - -static inline void adc2_config_width(adc_bits_width_t width_bit) -{ - portENTER_CRITICAL(&rtc_spinlock); -#if CONFIG_IDF_TARGET_ESP32 - //sar_start_force shared with ADC1 - SENS.sar_start_force.sar2_bit_width = width_bit; - //cct set to the same value with PHY - SENS.sar_start_force.sar2_pwdet_cct = 4; - portEXIT_CRITICAL(&rtc_spinlock); - - //Invert the adc value,the Output value is invert - SENS.sar_read_ctrl2.sar2_data_inv = 1; - //Set The adc sample width,invert adc value,must digital sar2_bit_width[1:0]=3 - SENS.sar_read_ctrl2.sar2_sample_bit = width_bit; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - //sar_start_force shared with ADC1 - SENS.sar_meas2_ctrl1.sar2_bit_width = width_bit; - //cct set to the same value with PHY - SENS.sar_meas2_mux.sar2_pwdet_cct = 4; - portEXIT_CRITICAL(&rtc_spinlock); - //Invert the adc value,the Output value is invert - SENS.sar_reader2_ctrl.sar2_data_inv = 1; - //Set The adc sample width,invert adc value,must digital sar2_bit_width[1:0]=3 - SENS.sar_reader2_ctrl.sar2_sample_bit = width_bit; -#endif -} - -static inline void adc2_dac_disable( adc2_channel_t channel) -{ -#if CONFIG_IDF_TARGET_ESP32 - if ( channel == ADC2_CHANNEL_8 ) { // the same as DAC channel 1 - dac_ll_power_down( DAC_CHANNEL_1 ); - } else if ( channel == ADC2_CHANNEL_9 ) { - dac_ll_power_down( DAC_CHANNEL_2 ); - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - if ( channel == ADC2_CHANNEL_6 ) { // the same as DAC channel 1 - dac_ll_power_down( DAC_CHANNEL_1 ); - } else if ( channel == ADC2_CHANNEL_7 ) { - dac_ll_power_down( DAC_CHANNEL_2 ); - } -#endif -} - -//registers in critical section with adc1: -//SENS_SAR_START_FORCE_REG, -esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int* raw_out) -{ - uint16_t adc_value = 0; - RTC_MODULE_CHECK(channel < ADC2_CHANNEL_MAX, "ADC Channel Err", ESP_ERR_INVALID_ARG); - - //in critical section with whole rtc module - adc_power_on(); - - //avoid collision with other tasks - portENTER_CRITICAL(&adc2_spinlock); - //lazy initialization - //try the lock, return if failed (wifi using). - if ( _lock_try_acquire( &adc2_wifi_lock ) == -1 ) { - portEXIT_CRITICAL( &adc2_spinlock ); - return ESP_ERR_TIMEOUT; - } - - //disable other peripherals -#ifdef CONFIG_ADC_DISABLE_DAC - adc2_dac_disable( channel ); -#endif - // set controller - // in critical section with whole rtc module - // because the PWDET use the same registers, place it here. - adc2_config_width( width_bit ); - adc_set_controller( ADC_UNIT_2, ADC_CTRL_RTC ); - //start converting - adc_value = adc_convert( ADC_UNIT_2, channel ); - _lock_release( &adc2_wifi_lock ); - portEXIT_CRITICAL(&adc2_spinlock); - - *raw_out = (int)adc_value; - return ESP_OK; -} - -esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) -{ -#if CONFIG_IDF_TARGET_ESP32 - int channel; - if(gpio == GPIO_NUM_25){ - channel = 8; //Channel 8 bit - }else if (gpio == GPIO_NUM_26){ - channel = 9; //Channel 9 bit - }else if (gpio == GPIO_NUM_27){ - channel = 7; //Channel 7 bit - }else{ - return ESP_ERR_INVALID_ARG; - } - - //Configure RTC gpio - rtc_gpio_init(gpio); - rtc_gpio_set_direction(gpio, RTC_GPIO_MODE_DISABLED); - 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) - RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels - //set ent - RTCCNTL.test_mux.ent_rtc = 1; - //set sar2_en_test - SENS.sar_start_force.sar2_en_test = 1; - //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) - SENS.sar_meas_start2.sar2_en_pad = 1< + +typedef enum { + ADC_DIG_FORMAT_12BIT, /*!< ADC to I2S data format, [15:12]-channel [11:0]-12 bits ADC data. + Note: In single convert mode. */ + ADC_DIG_FORMAT_11BIT, /*!< ADC to I2S data format, [15]-1 [14:11]-channel [10:0]-11 bits ADC data. + Note: In multi convert mode. */ + ADC_DIG_FORMAT_MAX, +} adc_ll_dig_output_format_t; + +typedef enum { + ADC_CONV_SINGLE_UNIT_1 = 1, /*!< SAR ADC 1*/ + ADC_CONV_SINGLE_UNIT_2 = 2, /*!< SAR ADC 2, not supported yet*/ + ADC_CONV_BOTH_UNIT = 3, /*!< SAR ADC 1 and 2, not supported yet */ + ADC_CONV_ALTER_UNIT = 7, /*!< SAR ADC 1 and 2 alternative mode, not supported yet */ + ADC_CONV_UNIT_MAX, +} adc_ll_convert_mode_t; + +typedef enum { + ADC_NUM_1 = 0, /*!< SAR ADC 1 */ + ADC_NUM_2 = 1, /*!< SAR ADC 2 */ + ADC_NUM_MAX, +} adc_ll_num_t; + +typedef struct { + union { + struct { + uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. + 0: input voltage * 1; + 1: input voltage * 1/1.34; + 2: input voltage * 1/2; + 3: input voltage * 1/3.6. */ + uint8_t bit_width: 2; /*!< ADC resolution. + 0: 9 bit; + 1: 10 bit; + 2: 11 bit; + 3: 12 bit. */ + uint8_t channel: 4; /*!< ADC channel index. */ + }; + uint8_t val; + }; +} adc_ll_pattern_table_t; + +typedef enum { + ADC_POWER_BY_FSM, /*!< ADC XPD controled by FSM. Used for polling mode */ + ADC_POWER_SW_ON, /*!< ADC XPD controled by SW. power on. Used for DMA mode */ + ADC_POWER_SW_OFF, /*!< ADC XPD controled by SW. power off. */ + ADC_POWER_MAX, /*!< For parameter check. */ +} adc_ll_power_t; + +typedef enum { + ADC_HALL_CTRL_ULP = 0x0,/*!< Hall sensor controled by ULP */ + ADC_HALL_CTRL_RTC = 0x1 /*!< Hall sensor controled by RTC */ +} adc_ll_hall_controller_t ; + +typedef enum { + ADC_CTRL_RTC = 0, + ADC_CTRL_ULP = 1, + ADC_CTRL_DIG = 2, + ADC2_CTRL_PWDET = 3, +} adc_ll_controller_t ; + +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ + +/** + * Set adc fsm interval parameter for digital controller. These values are fixed for same platforms. + * + * @param rst_wait cycles between DIG ADC controller reset ADC sensor and start ADC sensor. + * @param start_wait Delay time after open xpd. + * @param standby_wait Delay time to close xpd. + */ +static inline void adc_ll_dig_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait) +{ + // Internal FSM reset wait time + SYSCON.saradc_fsm.rstb_wait = rst_wait; + // Internal FSM start wait time + SYSCON.saradc_fsm.start_wait = start_wait; + // Internal FSM standby wait time + SYSCON.saradc_fsm.standby_wait = standby_wait; +} + +/** + * Set adc sample cycle for digital controller. + * + * @note Normally, please use default value. + * @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor. + * Range: 2 ~ 0xFF. + */ +static inline void adc_ll_dig_set_sample_cycle(uint32_t sample_cycle) +{ + SYSCON.saradc_fsm.sample_cycle = sample_cycle; +} + +/** + * Set adc output data format for digital controller. + * + * @param format Output data format. + */ +static inline void adc_ll_dig_set_output_format(adc_ll_dig_output_format_t format) +{ + SYSCON.saradc_ctrl.data_sar_sel = format; +} + +/** + * Set adc max conversion number for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param meas_num Max conversion number. Range: 0 ~ 255. + */ +static inline void adc_ll_dig_set_convert_limit_num(uint32_t meas_num) +{ + SYSCON.saradc_ctrl2.max_meas_num = meas_num; +} + +/** + * Enable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + */ +static inline void adc_ll_dig_convert_limit_enable(void) +{ + SYSCON.saradc_ctrl2.meas_num_limit = 1; +} + +/** + * Disable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + */ +static inline void adc_ll_dig_convert_limit_disable(void) +{ + SYSCON.saradc_ctrl2.meas_num_limit = 0; +} + +/** + * Set adc conversion mode for digital controller. + * + * @note ESP32 only support ADC1 single mode. + * + * @param mode Conversion mode select. + */ +static inline void adc_ll_dig_set_convert_mode(adc_ll_convert_mode_t mode) +{ + if (mode == ADC_CONV_SINGLE_UNIT_1) { + SYSCON.saradc_ctrl.work_mode = 0; + SYSCON.saradc_ctrl.sar_sel = 0; + } else if (mode == ADC_CONV_SINGLE_UNIT_2) { + SYSCON.saradc_ctrl.work_mode = 0; + SYSCON.saradc_ctrl.sar_sel = 1; + } else if (mode == ADC_CONV_BOTH_UNIT) { + SYSCON.saradc_ctrl.work_mode = 1; + } else if (mode == ADC_CONV_ALTER_UNIT) { + SYSCON.saradc_ctrl.work_mode = 2; + } +} + +/** + * Set I2S DMA data source for digital controller. + * + * @param src i2s data source. + */ +static inline void adc_ll_dig_set_data_source(adc_i2s_source_t src) +{ + /* 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix */ + SYSCON.saradc_ctrl.data_to_i2s = src; +} + +/** + * Set pattern table lenth for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. + * + * @prarm adc_n ADC unit. + * @param patt_len Items range: 1 ~ 16. + */ +static inline void adc_ll_set_pattern_table_len(adc_ll_num_t adc_n, uint32_t patt_len) +{ + if (adc_n == ADC_NUM_1) { + SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1; + } else { // adc_n == ADC_NUM_2 + SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1; + } +} + +/** + * Set pattern table lenth for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. + * + * @prarm adc_n ADC unit. + * @param pattern_index Items index. Range: 1 ~ 16. + * @param pattern Stored conversion rules. + */ +static inline void adc_ll_set_pattern_table(adc_ll_num_t adc_n, uint32_t pattern_index, adc_ll_pattern_table_t pattern) +{ + uint32_t tab; + uint8_t *arg; + if (adc_n == ADC_NUM_1) { + tab = SYSCON.saradc_sar1_patt_tab[pattern_index / 4]; + arg = (uint8_t *)&tab; + arg[pattern_index % 4] = pattern.val; + SYSCON.saradc_sar1_patt_tab[pattern_index / 4] = tab; + } else { // adc_n == ADC_NUM_2 + tab = SYSCON.saradc_sar2_patt_tab[pattern_index / 4]; + arg = (uint8_t *)&tab; + arg[pattern_index % 4] = pattern.val; + SYSCON.saradc_sar2_patt_tab[pattern_index / 4] = tab; + } +} + +/*--------------------------------------------------------------- + PWDET(Power detect) controller setting +---------------------------------------------------------------*/ +/** + * Set adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @prarm cct Range: 0 ~ 7. + */ +static inline void adc_ll_pwdet_set_cct(uint32_t cct) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + SENS.sar_start_force.sar2_pwdet_cct = cct; +} + +/** + * Get adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @return cct Range: 0 ~ 7. + */ +static inline uint32_t adc_ll_pwdet_get_cct(void) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + return SENS.sar_start_force.sar2_pwdet_cct; +} + +/*--------------------------------------------------------------- + RTC controller setting +---------------------------------------------------------------*/ +/** + * Set adc output data format for RTC controller. + * + * @prarm adc_n ADC unit. + * @prarm bits Output data bits width option. + */ +static inline void adc_ll_rtc_set_output_format(adc_ll_num_t adc_n, adc_bits_width_t bits) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_start_force.sar1_bit_width = bits; + SENS.sar_read_ctrl.sar1_sample_bit = bits; + } else { // adc_n == ADC_NUM_2 + SENS.sar_start_force.sar2_bit_width = bits; + SENS.sar_read_ctrl2.sar2_sample_bit = bits; + } +} + +/** + * Enable adc channel to start convert. + * + * @note Only one channel can be selected for once measurement. + * + * @prarm adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_meas_start1.sar1_en_pad = (1 << channel); //only one channel is selected. + } else { // adc_n == ADC_NUM_2 + SENS.sar_meas_start2.sar2_en_pad = (1 << channel); //only one channel is selected. + } +} + +/** + * Start conversion once by software for RTC controller. + * + * @note It may be block to wait conversion idle for ADC1. + * + * @prarm adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_ll_rtc_start_convert(adc_ll_num_t adc_n, int channel) +{ + if (adc_n == ADC_NUM_1) { + while (SENS.sar_slave_addr1.meas_status != 0); + SENS.sar_meas_start1.meas1_start_sar = 0; + SENS.sar_meas_start1.meas1_start_sar = 1; + } else { // adc_n == ADC_NUM_2 + SENS.sar_meas_start2.meas2_start_sar = 0; //start force 0 + SENS.sar_meas_start2.meas2_start_sar = 1; //start force 1 + } +} + +/** + * Check the conversion done flag for each ADCn for RTC controller. + * + * @prarm adc_n ADC unit. + * @return + * -true : The conversion process is finish. + * -false : The conversion process is not finish. + */ +static inline bool adc_ll_rtc_convert_is_done(adc_ll_num_t adc_n) +{ + bool ret = true; + if (adc_n == ADC_NUM_1) { + ret = (bool)SENS.sar_meas_start1.meas1_done_sar; + } else { // adc_n == ADC_NUM_2 + ret = (bool)SENS.sar_meas_start2.meas2_done_sar; + } + return ret; +} + +/** + * Get the converted value for each ADCn for RTC controller. + * + * @prarm adc_n ADC unit. + * @return + * - Converted value. + */ +static inline int adc_ll_rtc_get_convert_value(adc_ll_num_t adc_n) +{ + int ret_val = 0; + if (adc_n == ADC_NUM_1) { + ret_val = SENS.sar_meas_start1.meas1_data_sar; + } else { // adc_n == ADC_NUM_2 + ret_val = SENS.sar_meas_start2.meas2_data_sar; + } + return ret_val; +} + +/*--------------------------------------------------------------- + Common setting +---------------------------------------------------------------*/ +/** + * Set ADC module power management. + * + * @prarm manage Set ADC power status. + */ +static inline void adc_ll_set_power_manage(adc_ll_power_t manage) +{ + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_POWER_SW_ON) { + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; + } else if (manage == ADC_POWER_BY_FSM) { + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_POWER_SW_OFF) { + SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; + } +} + +/** + * Get ADC module power management. + * + * @return + * - ADC power status. + */ +static inline adc_ll_power_t adc_ll_get_power_manage(void) +{ + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + adc_ll_power_t manage; + if (SENS.sar_meas_wait2.force_xpd_sar == SENS_FORCE_XPD_SAR_PU) { + manage = ADC_POWER_SW_ON; + } else if (SENS.sar_meas_wait2.force_xpd_sar == SENS_FORCE_XPD_SAR_PD) { + manage = ADC_POWER_SW_OFF; + } else { + manage = ADC_POWER_BY_FSM; + } + return manage; +} + +/** + * ADC module clock division factor setting. ADC clock devided from APB clock. + * + * @prarm div Division factor. + */ +static inline void adc_ll_set_clk_div(uint32_t div) +{ + /* ADC clock devided from APB clk, e.g. 80 / 2 = 40Mhz, */ + SYSCON.saradc_ctrl.sar_clk_div = div; +} + +/** + * Set the attenuation of a particular channel on ADCn. + * + * @note For any given channel, this function must be called before the first time conversion. + * + * The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, + * usually 3.3V) requires setting >0dB signal attenuation for that ADC channel. + * + * When VDD_A is 3.3V: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V + * - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V + * - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below) + * + * @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured + * bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.) + * + * @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage. + * + * Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV + * - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV + * - 11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV + * + * For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges. + * + * @prarm adc_n ADC unit. + * @prarm channel ADCn channel number. + * @prarm atten The attenuation option. + */ +static inline void adc_ll_set_atten(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_atten1 = ( SENS.sar_atten1 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2)); + } else { // adc_n == ADC_NUM_2 + SENS.sar_atten2 = ( SENS.sar_atten2 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2)); + } +} + +/** + * ADC module output data invert or not. + * + * @prarm adc_n ADC unit. + */ +static inline void adc_ll_output_invert(adc_ll_num_t adc_n, bool inv_en) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_read_ctrl.sar1_data_inv = inv_en; // Enable / Disable ADC data invert + } else { // adc_n == ADC_NUM_2 + SENS.sar_read_ctrl2.sar2_data_inv = inv_en; // Enable / Disable ADC data invert + } +} + +/** + * Set ADC module controller. + * There are five SAR ADC controllers: + * Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes; + * Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep; + * the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2. + * + * @prarm adc_n ADC unit. + * @prarm ctrl ADC controller. + */ +static inline void adc_ll_set_controller(adc_ll_num_t adc_n, adc_ll_controller_t ctrl) +{ + if (adc_n == ADC_NUM_1) { + switch ( ctrl ) { + case ADC_CTRL_RTC: + SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + case ADC_CTRL_ULP: + SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas_start1.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start1.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_touch_ctrl1.xpd_hall_force = 0; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_touch_ctrl1.hall_phase_force = 0; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + case ADC_CTRL_DIG: + SENS.sar_read_ctrl.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + default: + break; + } + } else { // adc_n == ADC_NUM_2 + switch ( ctrl ) { + case ADC_CTRL_RTC: + SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control. + SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control. + break; + case ADC_CTRL_ULP: + SENS.sar_meas_start2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control. + SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control. + break; + case ADC_CTRL_DIG: + SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_read_ctrl2.sar2_dig_force = 1; // 1: Select digital control; 0: Select RTC control. + SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control. + SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control. + break; + case ADC2_CTRL_PWDET: // currently only used by Wi-Fi + SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_read_ctrl2.sar2_pwdet_force = 1; // 1: Select power detect control; 0: Select RTC control. + SYSCON.saradc_ctrl.sar2_mux = 0; // 1: Select digital control; 0: Select power detect control. + break; + default: + break; + } + } +} + +/** + * Close ADC AMP module if don't use it for power save. + */ +static inline void adc_ll_amp_disable(void) +{ + //channel is set in the convert function + SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; + //disable FSM, it's only used by the LNA. + SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0; + SENS.sar_meas_ctrl.amp_short_ref_fsm = 0; + SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0; + SENS.sar_meas_wait1.sar_amp_wait1 = 1; + SENS.sar_meas_wait1.sar_amp_wait2 = 1; + SENS.sar_meas_wait2.sar_amp_wait3 = 1; +} + +/*--------------------------------------------------------------- + Hall sensor setting +---------------------------------------------------------------*/ + +/** + * Enable hall sensor. + */ +static inline void adc_ll_hall_enable(void) +{ + RTCIO.hall_sens.xpd_hall = 1; +} + +/** + * Disable hall sensor. + */ +static inline void adc_ll_hall_disable(void) +{ + RTCIO.hall_sens.xpd_hall = 0; +} + +/** + * Reverse phase of hall sensor. + */ +static inline void adc_ll_hall_phase_enable(void) +{ + RTCIO.hall_sens.hall_phase = 1; +} + +/** + * Don't reverse phase of hall sensor. + */ +static inline void adc_ll_hall_phase_disable(void) +{ + RTCIO.hall_sens.hall_phase = 0; +} + +/** + * Set hall sensor controller. + * + * @param hall_ctrl Hall controller. + */ +static inline void adc_ll_set_hall_controller(adc_ll_hall_controller_t hall_ctrl) +{ + SENS.sar_touch_ctrl1.xpd_hall_force = hall_ctrl; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_touch_ctrl1.hall_phase_force = hall_ctrl; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. +} + +/** + * Output ADC2 reference voltage to gpio 25 or 26 or 27 + * + * This function utilizes the testing mux exclusive to ADC 2 to route the + * reference voltage one of ADC2's channels. Supported gpios are gpios + * 25, 26, and 27. This refernce voltage can be manually read from the pin + * and used in the esp_adc_cal component. + * + * @param[in] io GPIO number (gpios 25,26,27 supported) + * + * @return + * - true: v_ref successfully routed to selected gpio + * - false: Unsupported gpio + */ +static inline bool adc_ll_vref_output(int io) +{ + int channel; + if (io == 25) { + channel = 8; //Channel 8 bit + } else if (io == 26) { + channel = 9; //Channel 9 bit + } else if (io == 27) { + channel = 7; //Channel 7 bit + } else { + return false; + } + RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode + //set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2) + RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels + //set ent + RTCCNTL.test_mux.ent_rtc = 1; + //set sar2_en_test + SENS.sar_start_force.sar2_en_test = 1; + //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) + SENS.sar_meas_start2.sar2_en_pad = 1 << channel; + return true; +} diff --git a/components/soc/esp32/include/soc/adc_caps.h b/components/soc/esp32/include/soc/adc_caps.h new file mode 100644 index 0000000000..b4405d61da --- /dev/null +++ b/components/soc/esp32/include/soc/adc_caps.h @@ -0,0 +1,25 @@ +#pragma once + +#define SOC_ADC_PERIPH_NUM (2) +#define SOC_ADC_PATT_LEN_MAX (16) + +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 8: 10) +#define SOC_ADC_MAX_CHANNEL_NUM (10) + +#define SOC_ADC1_DATA_INVERT_DEFAULT (1) +#define SOC_ADC2_DATA_INVERT_DEFAULT (0) + +#define SOC_ADC_FSM_RSTB_WAIT_DEFAULT (8) +#define SOC_ADC_FSM_START_WAIT_DEFAULT (5) +#define SOC_ADC_FSM_STANDBY_WAIT_DEFAULT (100) +#define ADC_FSM_SAMPLE_CYCLE_DEFAULT (2) + +/** + * Check if adc support digital controller (DMA) mode. + * @value + * - 1 : support; + * - 0 : not support; + */ +#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) ((PERIPH_NUM==0)? 1: 0) + +#define SOC_ADC_PWDET_CCT_DEFAULT (4) \ No newline at end of file diff --git a/components/soc/esp32/include/soc/adc_channel.h b/components/soc/esp32/include/soc/adc_channel.h index e8835d35f8..fa6fdce6de 100644 --- a/components/soc/esp32/include/soc/adc_channel.h +++ b/components/soc/esp32/include/soc/adc_channel.h @@ -69,4 +69,4 @@ #define ADC2_GPIO26_CHANNEL ADC2_CHANNEL_9 #define ADC2_CHANNEL_9_GPIO_NUM 26 -#endif +#endif /* _SOC_ADC_CHANNEL_H_ */ diff --git a/components/soc/esp32/sources.cmake b/components/soc/esp32/sources.cmake index bb045fe176..efdf366f27 100644 --- a/components/soc/esp32/sources.cmake +++ b/components/soc/esp32/sources.cmake @@ -1,5 +1,6 @@ -set(SOC_SRCS "cpu_util.c" +set(SOC_SRCS "adc_periph.c" "dac_periph.c" + "cpu_util.c" "gpio_periph.c" "rtc_clk.c" "rtc_clk_init.c" diff --git a/components/soc/esp32s2beta/adc_periph.c b/components/soc/esp32s2beta/adc_periph.c new file mode 100644 index 0000000000..7c1314b6ff --- /dev/null +++ b/components/soc/esp32s2beta/adc_periph.c @@ -0,0 +1,25 @@ +// Copyright 2015-2019 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. + +#include "soc/adc_periph.h" + +/* Store IO number corresponding to the ADC channel number. */ +const int adc_channel_io_map[SOC_ADC_PERIPH_NUM][SOC_ADC_MAX_CHANNEL_NUM] = { + /* ADC1 */ + {ADC1_CHANNEL_0_GPIO_NUM, ADC1_CHANNEL_1_GPIO_NUM, ADC1_CHANNEL_2_GPIO_NUM, ADC1_CHANNEL_3_GPIO_NUM, ADC1_CHANNEL_4_GPIO_NUM, + ADC1_CHANNEL_5_GPIO_NUM, ADC1_CHANNEL_6_GPIO_NUM, ADC1_CHANNEL_7_GPIO_NUM, ADC1_CHANNEL_8_GPIO_NUM, ADC1_CHANNEL_9_GPIO_NUM}, + /* ADC2 */ + {ADC2_CHANNEL_0_GPIO_NUM, ADC2_CHANNEL_1_GPIO_NUM, ADC2_CHANNEL_2_GPIO_NUM, ADC2_CHANNEL_3_GPIO_NUM, ADC2_CHANNEL_4_GPIO_NUM, + ADC2_CHANNEL_5_GPIO_NUM, ADC2_CHANNEL_6_GPIO_NUM, ADC2_CHANNEL_7_GPIO_NUM, ADC2_CHANNEL_8_GPIO_NUM, ADC2_CHANNEL_9_GPIO_NUM} +}; diff --git a/components/soc/esp32s2beta/include/hal/adc_ll.h b/components/soc/esp32s2beta/include/hal/adc_ll.h new file mode 100644 index 0000000000..0dd4ce40d2 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/adc_ll.h @@ -0,0 +1,610 @@ +#pragma once + +#include "soc/adc_periph.h" +#include "hal/adc_types.h" +#include + +typedef enum { + ADC_DIG_FORMAT_12BIT, /*!< ADC to I2S data format, [15:12]-channel [11:0]-12 bits ADC data. + Note: In single convert mode. */ + ADC_DIG_FORMAT_11BIT, /*!< ADC to I2S data format, [15]-1 [14:11]-channel [10:0]-11 bits ADC data. + Note: In multi convert mode. */ + ADC_DIG_FORMAT_MAX, +} adc_ll_dig_output_format_t; + +typedef enum { + ADC_CONV_SINGLE_UNIT_1 = 1, /*!< SAR ADC 1*/ + ADC_CONV_SINGLE_UNIT_2 = 2, /*!< SAR ADC 2, not supported yet*/ + ADC_CONV_BOTH_UNIT = 3, /*!< SAR ADC 1 and 2, not supported yet */ + ADC_CONV_ALTER_UNIT = 7, /*!< SAR ADC 1 and 2 alternative mode, not supported yet */ + ADC_CONV_UNIT_MAX, +} adc_ll_convert_mode_t; + +typedef enum { + ADC_NUM_1 = 0, /*!< SAR ADC 1 */ + ADC_NUM_2 = 1, /*!< SAR ADC 2 */ + ADC_NUM_MAX, +} adc_ll_num_t; + +typedef struct { + union { + struct { + uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. + 0: input voltage * 1; + 1: input voltage * 1/1.34; + 2: input voltage * 1/2; + 3: input voltage * 1/3.6. */ + uint8_t bit_width: 2; /*!< ADC resolution. + 0: 9 bit; + 1: 10 bit; + 2: 11 bit; + 3: 12 bit. */ + uint8_t channel: 4; /*!< ADC channel index. */ + }; + uint8_t val; + }; +} adc_ll_pattern_table_t; + +typedef enum { + ADC_POWER_BY_FSM, /*!< ADC XPD controled by FSM. Used for polling mode */ + ADC_POWER_SW_ON, /*!< ADC XPD controled by SW. power on. Used for DMA mode */ + ADC_POWER_SW_OFF, /*!< ADC XPD controled by SW. power off. */ + ADC_POWER_MAX, /*!< For parameter check. */ +} adc_ll_power_t; + +typedef enum { + ADC_HALL_CTRL_ULP = 0x0,/*!< Hall sensor controled by ULP */ + ADC_HALL_CTRL_RTC = 0x1 /*!< Hall sensor controled by RTC */ +} adc_ll_hall_controller_t ; + +typedef enum { + ADC_CTRL_RTC = 0, + ADC_CTRL_ULP = 1, + ADC_CTRL_DIG = 2, + ADC2_CTRL_PWDET = 3, +} adc_ll_controller_t ; + +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ + +/** + * Set adc fsm interval parameter for digital controller. These values are fixed for same platforms. + * + * @param rst_wait cycles between DIG ADC controller reset ADC sensor and start ADC sensor. + * @param start_wait Delay time after open xpd. + * @param standby_wait Delay time to close xpd. + */ +static inline void adc_ll_dig_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait) +{ + // Internal FSM reset wait time + SYSCON.saradc_fsm_wait.rstb_wait = rst_wait; + // Internal FSM start wait time + SYSCON.saradc_fsm_wait.xpd_wait = start_wait; + // Internal FSM standby wait time + SYSCON.saradc_fsm_wait.standby_wait = standby_wait; +} + +/** + * Set adc sample cycle for digital controller. + * + * @note Normally, please use default value. + * @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor. + * Range: 2 ~ 0xFF. + */ +static inline void adc_ll_dig_set_sample_cycle(uint32_t sample_cycle) +{ + SYSCON.saradc_fsm.sample_cycle = sample_cycle; +} + +/** + * Set adc output data format for digital controller. + * + * @param format Output data format. + */ +static inline void adc_ll_dig_set_output_format(adc_ll_dig_output_format_t format) +{ + SYSCON.saradc_ctrl.data_sar_sel = format; +} + +/** + * Set adc max conversion number for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param meas_num Max conversion number. Range: 0 ~ 255. + */ +static inline void adc_ll_dig_set_convert_limit_num(uint32_t meas_num) +{ + SYSCON.saradc_ctrl2.max_meas_num = meas_num; +} + +/** + * Enable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + */ +static inline void adc_ll_dig_convert_limit_enable(void) +{ + SYSCON.saradc_ctrl2.meas_num_limit = 1; +} + +/** + * Disable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + */ +static inline void adc_ll_dig_convert_limit_disable(void) +{ + SYSCON.saradc_ctrl2.meas_num_limit = 0; +} + +/** + * Set adc conversion mode for digital controller. + * + * @note ESP32 only support ADC1 single mode. + * + * @param mode Conversion mode select. + */ +static inline void adc_ll_dig_set_convert_mode(adc_ll_convert_mode_t mode) +{ + if (mode == ADC_CONV_SINGLE_UNIT_1) { + SYSCON.saradc_ctrl.work_mode = 0; + SYSCON.saradc_ctrl.sar_sel = 0; + } else if (mode == ADC_CONV_SINGLE_UNIT_2) { + SYSCON.saradc_ctrl.work_mode = 0; + SYSCON.saradc_ctrl.sar_sel = 1; + } else if (mode == ADC_CONV_BOTH_UNIT) { + SYSCON.saradc_ctrl.work_mode = 1; + } else if (mode == ADC_CONV_ALTER_UNIT) { + SYSCON.saradc_ctrl.work_mode = 2; + } +} + +/** + * Set I2S DMA data source for digital controller. + * + * @param src i2s data source. + */ +static inline void adc_ll_dig_set_data_source(adc_i2s_source_t src) +{ + /* 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix */ + SYSCON.saradc_ctrl.data_to_i2s = src; +} + +/** + * Set pattern table lenth for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. + * + * @prarm adc_n ADC unit. + * @param patt_len Items range: 1 ~ 16. + */ +static inline void adc_ll_set_pattern_table_len(adc_ll_num_t adc_n, uint32_t patt_len) +{ + if (adc_n == ADC_NUM_1) { + SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1; + } else { // adc_n == ADC_NUM_2 + SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1; + } +} + +/** + * Set pattern table lenth for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. + * + * @prarm adc_n ADC unit. + * @param pattern_index Items index. Range: 1 ~ 16. + * @param pattern Stored conversion rules. + */ +static inline void adc_ll_set_pattern_table(adc_ll_num_t adc_n, uint32_t pattern_index, adc_ll_pattern_table_t pattern) +{ + uint32_t tab; + uint8_t *arg; + if (adc_n == ADC_NUM_1) { + tab = SYSCON.saradc_sar1_patt_tab[pattern_index / 4]; + arg = (uint8_t *)&tab; + arg[pattern_index % 4] = pattern.val; + SYSCON.saradc_sar1_patt_tab[pattern_index / 4] = tab; + } else { // adc_n == ADC_NUM_2 + tab = SYSCON.saradc_sar2_patt_tab[pattern_index / 4]; + arg = (uint8_t *)&tab; + arg[pattern_index % 4] = pattern.val; + SYSCON.saradc_sar2_patt_tab[pattern_index / 4] = tab; + } +} + +/*--------------------------------------------------------------- + PWDET(Power detect) controller setting +---------------------------------------------------------------*/ +/** + * Set adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @prarm cct Range: 0 ~ 7. + */ +static inline void adc_ll_pwdet_set_cct(uint32_t cct) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + SENS.sar_meas2_mux.sar2_pwdet_cct = cct; +} + +/** + * Get adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @return cct Range: 0 ~ 7. + */ +static inline uint32_t adc_ll_pwdet_get_cct(void) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + return SENS.sar_meas2_mux.sar2_pwdet_cct; +} + +/*--------------------------------------------------------------- + RTC controller setting +---------------------------------------------------------------*/ +/** + * Set adc output data format for RTC controller. + * + * @prarm adc_n ADC unit. + * @prarm bits Output data bits width option. + */ +static inline void adc_ll_rtc_set_output_format(adc_ll_num_t adc_n, adc_bits_width_t bits) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_meas1_ctrl1.sar1_bit_width = bits; + SENS.sar_reader1_ctrl.sar1_sample_bit = bits; + } else { // adc_n == ADC_NUM_2 + SENS.sar_meas2_ctrl1.sar2_bit_width = bits; + SENS.sar_reader2_ctrl.sar2_sample_bit = bits; + } +} + +/** + * Enable adc channel to start convert. + * + * @note Only one channel can be selected for once measurement. + * + * @prarm adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_meas1_ctrl2.sar1_en_pad = (1 << channel); //only one channel is selected. + } else { // adc_n == ADC_NUM_2 + SENS.sar_meas2_ctrl2.sar2_en_pad = (1 << channel); //only one channel is selected. + } +} + +/** + * Start conversion once by software for RTC controller. + * + * @note It may be block to wait conversion idle for ADC1. + * + * @prarm adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_ll_rtc_start_convert(adc_ll_num_t adc_n, int channel) +{ + if (adc_n == ADC_NUM_1) { + while (SENS.sar_slave_addr1.meas_status != 0); + SENS.sar_meas1_ctrl2.meas1_start_sar = 0; + SENS.sar_meas1_ctrl2.meas1_start_sar = 1; + } else { // adc_n == ADC_NUM_2 + SENS.sar_meas2_ctrl2.meas2_start_sar = 0; //start force 0 + SENS.sar_meas2_ctrl2.meas2_start_sar = 1; //start force 1 + } +} + +/** + * Check the conversion done flag for each ADCn for RTC controller. + * + * @prarm adc_n ADC unit. + * @return + * -true : The conversion process is finish. + * -false : The conversion process is not finish. + */ +static inline bool adc_ll_rtc_convert_is_done(adc_ll_num_t adc_n) +{ + bool ret = true; + if (adc_n == ADC_NUM_1) { + ret = (bool)SENS.sar_meas1_ctrl2.meas1_done_sar; + } else { // adc_n == ADC_NUM_2 + ret = (bool)SENS.sar_meas2_ctrl2.meas2_done_sar; + } + return ret; +} + +/** + * Get the converted value for each ADCn for RTC controller. + * + * @prarm adc_n ADC unit. + * @return + * - Converted value. + */ +static inline int adc_ll_rtc_get_convert_value(adc_ll_num_t adc_n) +{ + int ret_val = 0; + if (adc_n == ADC_NUM_1) { + ret_val = SENS.sar_meas1_ctrl2.meas1_data_sar; + } else { // adc_n == ADC_NUM_2 + ret_val = SENS.sar_meas2_ctrl2.meas2_data_sar; + } + return ret_val; +} + +/*--------------------------------------------------------------- + Common setting +---------------------------------------------------------------*/ +/** + * Set ADC module power management. + * + * @prarm manage Set ADC power status. + */ +static inline void adc_ll_set_power_manage(adc_ll_power_t manage) +{ + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_POWER_SW_ON) { + SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; + } else if (manage == ADC_POWER_BY_FSM) { + SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_POWER_SW_OFF) { + SENS.sar_power_xpd_sar.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; + } +} + +/** + * Get ADC module power management. + * + * @return + * - ADC power status. + */ +static inline adc_ll_power_t adc_ll_get_power_manage(void) +{ + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + adc_ll_power_t manage; + if (SENS.sar_power_xpd_sar.force_xpd_sar == SENS_FORCE_XPD_SAR_PU) { + manage = ADC_POWER_SW_ON; + } else if (SENS.sar_power_xpd_sar.force_xpd_sar == SENS_FORCE_XPD_SAR_PD) { + manage = ADC_POWER_SW_OFF; + } else { + manage = ADC_POWER_BY_FSM; + } + return manage; +} + +/** + * ADC module clock division factor setting. ADC clock devided from APB clock. + * + * @prarm div Division factor. + */ +static inline void adc_ll_set_clk_div(uint32_t div) +{ + /* ADC clock devided from APB clk, e.g. 80 / 2 = 40Mhz, */ + SYSCON.saradc_ctrl.sar_clk_div = div; +} + +/** + * Set the attenuation of a particular channel on ADCn. + * + * @note For any given channel, this function must be called before the first time conversion. + * + * The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, + * usually 3.3V) requires setting >0dB signal attenuation for that ADC channel. + * + * When VDD_A is 3.3V: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V + * - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V + * - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below) + * + * @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured + * bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.) + * + * @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage. + * + * Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV + * - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV + * - 11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV + * + * For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges. + * + * @prarm adc_n ADC unit. + * @prarm channel ADCn channel number. + * @prarm atten The attenuation option. + */ +static inline void adc_ll_set_atten(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_atten1 = ( SENS.sar_atten1 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2)); + } else { // adc_n == ADC_NUM_2 + SENS.sar_atten2 = ( SENS.sar_atten2 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2)); + } +} + +/** + * ADC module output data invert or not. + * + * @prarm adc_n ADC unit. + */ +static inline void adc_ll_output_invert(adc_ll_num_t adc_n, bool inv_en) +{ + if (adc_n == ADC_NUM_1) { + SENS.sar_reader1_ctrl.sar1_data_inv = inv_en; // Enable / Disable ADC data invert + } else { // adc_n == ADC_NUM_2 + SENS.sar_reader2_ctrl.sar2_data_inv = inv_en; // Enable / Disable ADC data invert + } +} + +/** + * Set ADC module controller. + * There are five SAR ADC controllers: + * Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes; + * Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep; + * the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2. + * + * @prarm adc_n ADC unit. + * @prarm ctrl ADC controller. + */ +static inline void adc_ll_set_controller(adc_ll_num_t adc_n, adc_ll_controller_t ctrl) +{ + if (adc_n == ADC_NUM_1) { + switch ( ctrl ) { + case ADC_CTRL_RTC: + SENS.sar_meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas1_ctrl2.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas1_ctrl2.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_hall_ctrl.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_hall_ctrl.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + case ADC_CTRL_ULP: + SENS.sar_meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas1_ctrl2.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas1_ctrl2.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_hall_ctrl.xpd_hall_force = 0; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_hall_ctrl.hall_phase_force = 0; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + case ADC_CTRL_DIG: + SENS.sar_meas1_mux.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control. + SENS.sar_meas1_ctrl2.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas1_ctrl2.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + SENS.sar_hall_ctrl.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_hall_ctrl.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. + break; + default: + break; + } + } else { // adc_n == ADC_NUM_2 + switch ( ctrl ) { + case ADC_CTRL_RTC: + SENS.sar_meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_CTRL_ULP: + SENS.sar_meas2_ctrl2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_CTRL_DIG: + SENS.sar_meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC2_CTRL_PWDET: // currently only used by Wi-Fi + SENS.sar_meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + default: + break; + } + } +} + +/** + * Close ADC AMP module if don't use it for power save. + */ +static inline void adc_ll_amp_disable(void) +{ + //channel is set in the convert function + SENS.sar_meas1_ctrl1.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; + //disable FSM, it's only used by the LNA. + SENS.sar_amp_ctrl3.amp_rst_fb_fsm = 0; + SENS.sar_amp_ctrl3.amp_short_ref_fsm = 0; + SENS.sar_amp_ctrl3.amp_short_ref_gnd_fsm = 0; + SENS.sar_amp_ctrl1.sar_amp_wait1 = 1; + SENS.sar_amp_ctrl1.sar_amp_wait2 = 1; + SENS.sar_amp_ctrl2.sar_amp_wait3 = 1; +} + +/*--------------------------------------------------------------- + Hall sensor setting +---------------------------------------------------------------*/ + +/** + * Enable hall sensor. + */ +static inline void adc_ll_hall_enable(void) +{ + SENS.sar_hall_ctrl.xpd_hall = 1; +} + +/** + * Disable hall sensor. + */ +static inline void adc_ll_hall_disable(void) +{ + SENS.sar_hall_ctrl.xpd_hall = 0; +} + +/** + * Reverse phase of hall sensor. + */ +static inline void adc_ll_hall_phase_enable(void) +{ + SENS.sar_hall_ctrl.hall_phase = 1; +} + +/** + * Don't reverse phase of hall sensor. + */ +static inline void adc_ll_hall_phase_disable(void) +{ + SENS.sar_hall_ctrl.hall_phase = 0; +} + +/** + * Set hall sensor controller. + * + * @param hall_ctrl Hall controller. + */ +static inline void adc_ll_set_hall_controller(adc_ll_hall_controller_t hall_ctrl) +{ + SENS.sar_hall_ctrl.xpd_hall_force = hall_ctrl; // 1: SW control HALL power; 0: ULP FSM control HALL power. + SENS.sar_hall_ctrl.hall_phase_force = hall_ctrl; // 1: SW control HALL phase; 0: ULP FSM control HALL phase. +} + +/** + * Output ADC2 reference voltage to gpio 25 or 26 or 27 + * + * This function utilizes the testing mux exclusive to ADC 2 to route the + * reference voltage one of ADC2's channels. Supported gpios are gpios + * 25, 26, and 27. This refernce voltage can be manually read from the pin + * and used in the esp_adc_cal component. + * + * @param[in] io GPIO number (gpios 25,26,27 supported) + * + * @return + * - true: v_ref successfully routed to selected gpio + * - false: Unsupported gpio + */ +static inline bool adc_ll_vref_output(int io) +{ + int channel; + if (io == 25) { + channel = 8; //Channel 8 bit + } else if (io == 26) { + channel = 9; //Channel 9 bit + } else if (io == 27) { + channel = 7; //Channel 7 bit + } else { + return false; + } + RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode + //set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2) + RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels + //set ent + RTCCNTL.test_mux.ent_rtc = 1; + //set sar2_en_test + SENS.sar_meas2_ctrl1.sar2_en_test = 1; + //set sar2 en force + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW + //set en_pad for channels 7,8,9 (bits 0x380) + SENS.sar_meas2_ctrl2.sar2_en_pad = 1 << channel; + return true; +} diff --git a/components/soc/esp32s2beta/include/soc/adc_caps.h b/components/soc/esp32s2beta/include/soc/adc_caps.h new file mode 100644 index 0000000000..ef2f1a3ef9 --- /dev/null +++ b/components/soc/esp32s2beta/include/soc/adc_caps.h @@ -0,0 +1,25 @@ +#pragma once + +#define SOC_ADC_PERIPH_NUM (2) +#define SOC_ADC_PATT_LEN_MAX (16) + +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10) +#define SOC_ADC_MAX_CHANNEL_NUM (10) + +#define SOC_ADC1_DATA_INVERT_DEFAULT (1) +#define SOC_ADC2_DATA_INVERT_DEFAULT (1) + +#define SOC_ADC_FSM_RSTB_WAIT_DEFAULT (8) +#define SOC_ADC_FSM_START_WAIT_DEFAULT (5) +#define SOC_ADC_FSM_STANDBY_WAIT_DEFAULT (100) +#define ADC_FSM_SAMPLE_CYCLE_DEFAULT (2) + +/** + * Check if adc support digital controller (DMA) mode. + * @value + * - 1 : support; + * - 0 : not support; + */ +#define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) ((PERIPH_NUM==0)? 1: 0) + +#define SOC_ADC_PWDET_CCT_DEFAULT (4) \ No newline at end of file diff --git a/components/soc/esp32s2beta/include/soc/sens_reg.h b/components/soc/esp32s2beta/include/soc/sens_reg.h index 6ca8c50d5e..d3cdf38830 100644 --- a/components/soc/esp32s2beta/include/soc/sens_reg.h +++ b/components/soc/esp32s2beta/include/soc/sens_reg.h @@ -96,6 +96,9 @@ extern "C" { #define SENS_FORCE_XPD_AMP_M ((SENS_FORCE_XPD_AMP_V)<<(SENS_FORCE_XPD_AMP_S)) #define SENS_FORCE_XPD_AMP_V 0x3 #define SENS_FORCE_XPD_AMP_S 24 +#define SENS_FORCE_XPD_AMP_FSM 0 // Use FSM to control power down +#define SENS_FORCE_XPD_AMP_PD 2 // Force power down +#define SENS_FORCE_XPD_AMP_PU 3 // Force power up /* SENS_SAR1_STOP : R/W ;bitpos:[2] ;default: 1'b0 ; */ /*description: stop SAR ADC1 conversion*/ #define SENS_SAR1_STOP (BIT(2)) @@ -452,6 +455,10 @@ extern "C" { #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 29 +#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 /* SENS_SAR1_DREF : R/W ;bitpos:[28:26] ;default: 3'd0 ; */ /*description: Adjust saradc1 offset*/ #define SENS_SAR1_DREF 0x00000007 diff --git a/components/soc/esp32s2beta/sources.cmake b/components/soc/esp32s2beta/sources.cmake index 509d342f41..c7a10af4bc 100644 --- a/components/soc/esp32s2beta/sources.cmake +++ b/components/soc/esp32s2beta/sources.cmake @@ -1,5 +1,6 @@ -set(SOC_SRCS "cpu_util.c" +set(SOC_SRCS "adc_periph.c" "dac_periph.c" + "cpu_util.c" "gpio_periph.c" "rtc_clk.c" "rtc_init.c" diff --git a/components/soc/include/hal/adc_hal.h b/components/soc/include/hal/adc_hal.h new file mode 100644 index 0000000000..87317b5623 --- /dev/null +++ b/components/soc/include/hal/adc_hal.h @@ -0,0 +1,207 @@ +#pragma once + +#include "hal/adc_types.h" +#include "hal/adc_ll.h" + +typedef struct { + bool conv_limit_en; + uint32_t conv_limit_num; + uint32_t clk_div; + uint32_t adc1_pattern_len; + uint32_t adc2_pattern_len; + adc_ll_pattern_table_t *adc1_pattern; + adc_ll_pattern_table_t *adc2_pattern; + adc_ll_convert_mode_t conv_mode; + adc_ll_dig_output_format_t format; +} adc_hal_dig_config_t; + +/*--------------------------------------------------------------- + Common setting +---------------------------------------------------------------*/ +/** + * ADC module initialization. + */ +void adc_hal_init(void); + +/** + * Set adc sample cycle for digital controller. + * + * @note Normally, please use default value. + * @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor. + * Range: 2 ~ 0xFF. + */ +#define adc_hal_dig_set_sample_cycle(sample_cycle) adc_ll_dig_set_sample_cycle(sample_cycle) + +/** + * Set ADC module power management. + * + * @prarm manage Set ADC power status. + */ +#define adc_hal_set_power_manage(manage) adc_ll_set_power_manage(manage) + +/** + * Get ADC module power management. + * + * @return + * - ADC power status. + */ +#define adc_hal_get_power_manage() adc_ll_get_power_manage() + +/** + * ADC module clock division factor setting. ADC clock devided from APB clock. + * + * @prarm div Division factor. + */ +#define adc_hal_set_clk_div(div) adc_ll_set_clk_div(div) + +/** + * ADC module output data invert or not. + * + * @prarm adc_n ADC unit. + */ +#define adc_hal_output_invert(adc_n, inv_en) adc_ll_output_invert(adc_n, inv_en) + +/** + * Set ADC module controller. + * There are five SAR ADC controllers: + * Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes; + * Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep; + * the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2. + * + * @prarm adc_n ADC unit. + * @prarm ctrl ADC controller. + */ +#define adc_hal_set_controller(adc_n, ctrl) adc_ll_set_controller(adc_n, ctrl) + +/** + * Set the attenuation of a particular channel on ADCn. + * + * @note For any given channel, this function must be called before the first time conversion. + * + * The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, + * usually 3.3V) requires setting >0dB signal attenuation for that ADC channel. + * + * When VDD_A is 3.3V: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V + * - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V + * - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below) + * + * @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured + * bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.) + * + * @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage. + * + * Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges: + * + * - 0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV + * - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV + * - 11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV + * + * For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges. + * + * @prarm adc_n ADC unit. + * @prarm channel ADCn channel number. + * @prarm atten The attenuation option. + */ +#define adc_hal_set_atten(adc_n, channel, atten) adc_ll_set_atten(adc_n, channel, atten) + +/** + * Close ADC AMP module if don't use it for power save. + */ +#define adc_hal_amp_disable() adc_ll_amp_disable() + +/*--------------------------------------------------------------- + PWDET(Power detect) controller setting +---------------------------------------------------------------*/ + +/** + * Set adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @prarm cct Range: 0 ~ 7. + */ +#define adc_hal_pwdet_set_cct(cct) adc_ll_pwdet_set_cct(cct) + +/** + * Get adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @return cct Range: 0 ~ 7. + */ +#define adc_hal_pwdet_get_cct() adc_ll_pwdet_get_cct() + +/*--------------------------------------------------------------- + RTC controller setting +---------------------------------------------------------------*/ + +/** + * Set adc output data format for RTC controller. + * + * @prarm adc_n ADC unit. + * @prarm bits Output data bits width option. + */ +#define adc_hal_rtc_set_output_format(adc_n, bits) adc_ll_rtc_set_output_format(adc_n, bits) + +/** + * Get the converted value for each ADCn for RTC controller. + * + * @note It may be block to wait conversion finish. + * @prarm adc_n ADC unit. + * @return + * - Converted value. + */ +int adc_hal_convert(adc_ll_num_t adc_n, int channel); + +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ +/** + * Setting the digital controller. + * + * @prarm adc_hal_dig_config_t cfg Pointer to digital controller paramter. + */ +void adc_hal_dig_controller_config(const adc_hal_dig_config_t *cfg); + +/** + * Set I2S DMA data source for digital controller. + * + * @param src i2s data source. + */ +#define adc_hal_dig_set_data_source(src) adc_ll_dig_set_data_source(src) + +/*--------------------------------------------------------------- + Hall sensor setting +---------------------------------------------------------------*/ + +/** + * Enable hall sensor. + */ +#define adc_hal_hall_enable() adc_ll_hall_enable() + +/** + * Disable hall sensor. + */ +#define adc_hal_hall_disable() adc_ll_hall_disable() + +/** + * Start hall convert and return the hall value. + * + * @return Hall value. + */ +int adc_hal_hall_convert(void); + +/** + * @brief Output ADC2 reference voltage to gpio + * + * This function utilizes the testing mux exclusive to ADC2 to route the + * reference voltage one of ADC2's channels. + * + * @param[in] io GPIO number + * @return + * - true: v_ref successfully routed to selected gpio + * - false: Unsupported gpio + */ +#define adc_hal_vref_output(io) adc_ll_vref_output(io) \ No newline at end of file diff --git a/components/soc/include/hal/adc_types.h b/components/soc/include/hal/adc_types.h new file mode 100644 index 0000000000..d651f00b4f --- /dev/null +++ b/components/soc/include/hal/adc_types.h @@ -0,0 +1,37 @@ +#pragma once + +typedef enum { + ADC_CHANNEL_0 = 0, /*!< ADC channel */ + ADC_CHANNEL_1, /*!< ADC channel */ + ADC_CHANNEL_2, /*!< ADC channel */ + ADC_CHANNEL_3, /*!< ADC channel */ + ADC_CHANNEL_4, /*!< ADC channel */ + ADC_CHANNEL_5, /*!< ADC channel */ + ADC_CHANNEL_6, /*!< ADC channel */ + ADC_CHANNEL_7, /*!< ADC channel */ + ADC_CHANNEL_8, /*!< ADC channel */ + ADC_CHANNEL_9, /*!< ADC channel */ + ADC_CHANNEL_MAX, +} adc_channel_t; + +typedef enum { + ADC_ATTEN_DB_0 = 0, /*!=0 : GPIO number index. + * - -1 : Not support. + */ +extern const int adc_channel_io_map[SOC_ADC_PERIPH_NUM][SOC_ADC_MAX_CHANNEL_NUM]; \ No newline at end of file diff --git a/components/soc/src/hal/adc_hal.c b/components/soc/src/hal/adc_hal.c new file mode 100644 index 0000000000..bd016668e7 --- /dev/null +++ b/components/soc/src/hal/adc_hal.c @@ -0,0 +1,83 @@ +// Copyright 2019 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. + +#include "hal/adc_hal.h" + +void adc_hal_init(void) +{ + adc_ll_set_power_manage(ADC_POWER_BY_FSM); + // Set internal FSM wait time, fixed value. + adc_ll_dig_set_fsm_time(SOC_ADC_FSM_RSTB_WAIT_DEFAULT, SOC_ADC_FSM_START_WAIT_DEFAULT, + SOC_ADC_FSM_STANDBY_WAIT_DEFAULT); + adc_ll_dig_set_sample_cycle(ADC_FSM_SAMPLE_CYCLE_DEFAULT); + adc_ll_output_invert(ADC_NUM_1, SOC_ADC1_DATA_INVERT_DEFAULT); + adc_ll_output_invert(ADC_NUM_2, SOC_ADC2_DATA_INVERT_DEFAULT); +} + +void adc_hal_dig_controller_config(const adc_hal_dig_config_t *cfg) +{ + /* If enable digtal controller, adc xpd should always on. */ + adc_ll_set_power_manage(ADC_POWER_SW_ON); + adc_ll_set_clk_div(cfg->clk_div); + /* Single channel mode or multi channel mode. */ + adc_ll_dig_set_convert_mode(cfg->conv_mode); + if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) { + adc_ll_set_controller(ADC_NUM_1, ADC_CTRL_DIG); + adc_ll_set_pattern_table_len(ADC_NUM_1, cfg->adc1_pattern_len); + for (int i = 0; i < cfg->adc1_pattern_len; i++) { + adc_ll_set_pattern_table(ADC_NUM_1, i, cfg->adc1_pattern[i]); + } + } + if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) { + adc_ll_set_controller(ADC_NUM_2, ADC_CTRL_DIG); + adc_ll_set_pattern_table_len(ADC_NUM_2, cfg->adc2_pattern_len); + for (int i = 0; i < cfg->adc2_pattern_len; i++) { + adc_ll_set_pattern_table(ADC_NUM_2, i, cfg->adc2_pattern[i]); + } + } + adc_ll_dig_set_output_format(cfg->format); + if (cfg->conv_limit_en) { + adc_ll_dig_set_convert_limit_num(cfg->conv_limit_num); + adc_ll_dig_convert_limit_enable(); + } else { + adc_ll_dig_convert_limit_disable(); + } + adc_ll_dig_set_data_source(ADC_I2S_DATA_SRC_ADC); +} + +int adc_hal_convert(adc_ll_num_t adc_n, int channel) +{ + adc_ll_rtc_enable_channel(adc_n, channel); + adc_ll_rtc_start_convert(adc_n, channel); + while (adc_ll_rtc_convert_is_done(adc_n) != true); + return adc_ll_rtc_get_convert_value(adc_n); +} + +int adc_hal_hall_convert(void) +{ + int Sens_Vp0; + int Sens_Vn0; + int Sens_Vp1; + int Sens_Vn1; + int hall_value; + // convert for 4 times with different phase and outputs + adc_ll_hall_phase_disable(); // hall phase + Sens_Vp0 = adc_hal_convert( ADC_NUM_1, ADC_CHANNEL_0 ); + Sens_Vn0 = adc_hal_convert( ADC_NUM_1, ADC_CHANNEL_3 ); + adc_ll_hall_phase_enable(); + Sens_Vp1 = adc_hal_convert( ADC_NUM_1, ADC_CHANNEL_0 ); + Sens_Vn1 = adc_hal_convert( ADC_NUM_1, ADC_CHANNEL_3 ); + hall_value = (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0); + return hall_value; +} \ No newline at end of file diff --git a/docs/Doxyfile b/docs/Doxyfile index 4b22164cac..4e8ddb9d8f 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -113,6 +113,7 @@ INPUT = \ ../../components/soc/include/hal/ledc_types.h \ ../../components/soc/include/hal/i2c_types.h \ ../../components/soc/include/hal/dac_types.h \ + ../../components/soc/include/hal/adc_types.h \ ../../components/soc/esp32/include/soc/adc_channel.h \ ../../components/soc/esp32/include/soc/dac_channel.h \ ../../components/soc/esp32/include/soc/touch_channel.h \