From 8d922847af20ab51503f0199081029ea4047859e Mon Sep 17 00:00:00 2001 From: fuzhibo Date: Wed, 3 Jun 2020 17:38:10 +0800 Subject: [PATCH] driver(adc): esp32s2 support API adc2_vref_to_gpio --- components/driver/adc_common.c | 33 ++++++++++ components/driver/esp32/adc.c | 16 ----- components/driver/esp32/include/driver/adc.h | 16 ----- components/driver/include/driver/adc_common.h | 34 ++++++++++ components/soc/include/hal/adc_hal.h | 14 ++++ .../soc/src/esp32/include/hal/adc_hal.h | 13 ---- components/soc/src/esp32/include/hal/adc_ll.h | 62 ++++++++--------- .../soc/src/esp32s2/include/hal/adc_ll.h | 66 +++++++++++++++++++ docs/en/api-reference/peripherals/adc.rst | 4 +- 9 files changed, 180 insertions(+), 78 deletions(-) diff --git a/components/driver/adc_common.c b/components/driver/adc_common.c index a6246315b..e11c5d5af 100644 --- a/components/driver/adc_common.c +++ b/components/driver/adc_common.c @@ -535,3 +535,36 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * return ESP_OK; } +esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) +{ + return adc_vref_to_gpio(ADC_UNIT_2, gpio); +} + +esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) +{ +#ifdef CONFIG_IDF_TARGET_ESP32 + if (adc_unit & ADC_UNIT_1) return ESP_ERR_INVALID_ARG; +#endif + adc2_channel_t ch = ADC2_CHANNEL_MAX; + /* Check if the GPIO supported. */ + for (int i = 0; i < ADC2_CHANNEL_MAX; i++) { + if (gpio == ADC_GET_IO_NUM(ADC_NUM_2, i)) { + ch = i; + break; + } + } + if (ch == ADC2_CHANNEL_MAX) return ESP_ERR_INVALID_ARG; + + ADC_ENTER_CRITICAL(); + adc_hal_set_power_manage(ADC_POWER_SW_ON); + if (adc_unit & ADC_UNIT_1) { + adc_hal_vref_output(ADC_NUM_1, ch, true); + } else if (adc_unit & ADC_UNIT_2) { + adc_hal_vref_output(ADC_NUM_2, ch, true); + } + ADC_EXIT_CRITICAL(); + + //Configure RTC gpio, Only ADC2's channels IO are supported to output reference voltage. + adc_gpio_init(ADC_UNIT_2, ch); + return ESP_OK; +} \ No newline at end of file diff --git a/components/driver/esp32/adc.c b/components/driver/esp32/adc.c index 80aee81b9..6e124f4b1 100644 --- a/components/driver/esp32/adc.c +++ b/components/driver/esp32/adc.c @@ -133,22 +133,6 @@ esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel) RTC controller setting ---------------------------------------------------------------*/ -esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) -{ - ADC_ENTER_CRITICAL(); - adc_hal_set_power_manage(ADC_POWER_SW_ON); - ADC_EXIT_CRITICAL(); - if (adc_hal_vref_output(gpio) != true) { - 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); - return ESP_OK; -} - /*--------------------------------------------------------------- HALL SENSOR ---------------------------------------------------------------*/ diff --git a/components/driver/esp32/include/driver/adc.h b/components/driver/esp32/include/driver/adc.h index 4f07a6b51..2ee228b32 100644 --- a/components/driver/esp32/include/driver/adc.h +++ b/components/driver/esp32/include/driver/adc.h @@ -46,22 +46,6 @@ esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel); RTC controller setting ---------------------------------------------------------------*/ -/** - * @brief 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] gpio GPIO number (GPIOs 25, 26 and 27 are supported) - * - * @return - * - ESP_OK: v_ref successfully routed to selected GPIO - * - ESP_ERR_INVALID_ARG: Unsupported GPIO - */ -esp_err_t adc2_vref_to_gpio(gpio_num_t gpio); - /** * @brief Read Hall Sensor * diff --git a/components/driver/include/driver/adc_common.h b/components/driver/include/driver/adc_common.h index 9f896a55d..2c426b71d 100644 --- a/components/driver/include/driver/adc_common.h +++ b/components/driver/include/driver/adc_common.h @@ -312,6 +312,40 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten); */ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out); +/** + * @brief Output ADC1 or ADC2's reference voltage to ``adc2_channe_t``'s IO. + * + * This function routes the internal reference voltage of ADCn to one of + * ADC2's channels. This reference voltage can then be manually measured + * for calibration purposes. + * + * @note ESP32 only supports output of ADC2's internal reference voltage. + * @param[in] adc_unit ADC unit index + * @param[in] gpio GPIO number (Only ADC2's channels IO are supported) + * + * @return + * - ESP_OK: v_ref successfully routed to selected GPIO + * - ESP_ERR_INVALID_ARG: Unsupported GPIO + */ +esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio); + +/** + * @brief Output ADC2 reference voltage to ``adc2_channe_t``'s IO. + * + * This function routes the internal reference voltage of ADCn to one of + * ADC2's channels. This reference voltage can then be manually measured + * for calibration purposes. + * + * @deprecated Use ``adc_vref_to_gpio`` instead. + * + * @param[in] gpio GPIO number (ADC2's channels are supported) + * + * @return + * - ESP_OK: v_ref successfully routed to selected GPIO + * - ESP_ERR_INVALID_ARG: Unsupported GPIO + */ +esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) __attribute__((deprecated)); + #ifdef __cplusplus } #endif diff --git a/components/soc/include/hal/adc_hal.h b/components/soc/include/hal/adc_hal.h index 621b23d13..e497149e6 100644 --- a/components/soc/include/hal/adc_hal.h +++ b/components/soc/include/hal/adc_hal.h @@ -168,6 +168,20 @@ int adc_hal_convert(adc_ll_num_t adc_n, int channel, int *value); */ #define adc_hal_rtc_output_invert(adc_n, inv_en) adc_ll_rtc_output_invert(adc_n, inv_en) +/** + * Enable/disable the output of ADCn's internal reference voltage to one of ADC2's channels. + * + * This function routes the internal reference voltage of ADCn to one of + * ADC2's channels. This reference voltage can then be manually measured + * for calibration purposes. + * + * @note ESP32 only supports output of ADC2's internal reference voltage. + * @param[in] adc ADC unit select + * @param[in] channel ADC2 channel number + * @param[in] en Enable/disable the reference voltage output + */ +#define adc_hal_vref_output(adc, channel, en) adc_ll_vref_output(adc, channel, en) + /*--------------------------------------------------------------- Digital controller setting ---------------------------------------------------------------*/ diff --git a/components/soc/src/esp32/include/hal/adc_hal.h b/components/soc/src/esp32/include/hal/adc_hal.h index 091c51d25..1bd84bd21 100644 --- a/components/soc/src/esp32/include/hal/adc_hal.h +++ b/components/soc/src/esp32/include/hal/adc_hal.h @@ -100,19 +100,6 @@ void adc_hal_digi_deinit(void); */ 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) - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/components/soc/src/esp32/include/hal/adc_ll.h b/components/soc/src/esp32/include/hal/adc_ll.h index 6e15d8821..a472ae667 100644 --- a/components/soc/src/esp32/include/hal/adc_ll.h +++ b/components/soc/src/esp32/include/hal/adc_ll.h @@ -673,43 +673,43 @@ static inline void adc_ll_set_hall_controller(adc_ll_hall_controller_t hall_ctrl } /** - * Output ADC2 reference voltage to gpio 25 or 26 or 27 + * Output ADC internal reference voltage to channels, only available for ADC2 on ESP32. * - * 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. + * This function routes the internal reference voltage of ADCn to one of + * ADC2's channels. This reference voltage can then be manually measured + * for calibration purposes. * - * @param[in] io GPIO number (gpios 25,26,27 supported) - * - * @return - * - true: v_ref successfully routed to selected gpio - * - false: Unsupported gpio + * @param[in] adc ADC unit select + * @param[in] channel ADC2 channel number + * @param[in] en Enable/disable the reference voltage output */ -static inline bool adc_ll_vref_output(int io) +static inline void adc_ll_vref_output(adc_ll_num_t adc, adc_channel_t channel, bool en) { - 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 + if (adc != ADC_NUM_2) return; + + if (en) { + 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; } else { - return false; + RTCCNTL.test_mux.dtest_rtc = 0; //Config test mux to route v_ref to ADC2 Channels + //set ent + RTCCNTL.test_mux.ent_rtc = 0; + //set sar2_en_test + SENS.sar_start_force.sar2_en_test = 0; + //set sar2 en force + SENS.sar_meas_start2.sar2_en_pad_force = 0; //Pad bitmap controlled by SW + //set en_pad for channels 7,8,9 (bits 0x380) + SENS.sar_meas_start2.sar2_en_pad = 0; } - 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; } #ifdef __cplusplus diff --git a/components/soc/src/esp32s2/include/hal/adc_ll.h b/components/soc/src/esp32s2/include/hal/adc_ll.h index 3eaadfb8c..13949394b 100644 --- a/components/soc/src/esp32s2/include/hal/adc_ll.h +++ b/components/soc/src/esp32s2/include/hal/adc_ll.h @@ -110,6 +110,19 @@ typedef enum { #define ADC_LL_SAR1_SAMPLE_CYCLE_ADDR 0x2 #define ADC_LL_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2 #define ADC_LL_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0 + +#define ADC_LL_SARADC_DTEST_RTC_ADDR 0x7 +#define ADC_LL_SARADC_DTEST_RTC_ADDR_MSB 1 +#define ADC_LL_SARADC_DTEST_RTC_ADDR_LSB 0 + +#define ADC_LL_SARADC_ENT_TSENS_ADDR 0x7 +#define ADC_LL_SARADC_ENT_TSENS_ADDR_MSB 2 +#define ADC_LL_SARADC_ENT_TSENS_ADDR_LSB 2 + +#define ADC_LL_SARADC_ENT_RTC_ADDR 0x7 +#define ADC_LL_SARADC_ENT_RTC_ADDR_MSB 3 +#define ADC_LL_SARADC_ENT_RTC_ADDR_LSB 3 + /* ADC calibration defines end. */ /*--------------------------------------------------------------- @@ -1248,6 +1261,59 @@ static inline void adc_ll_set_calibration_param(adc_ll_num_t adc_n, uint32_t par } /* Temp code end. */ +/** + * Output ADCn inter reference voltage to ADC2 channels. + * + * This function routes the internal reference voltage of ADCn to one of + * ADC2's channels. This reference voltage can then be manually measured + * for calibration purposes. + * + * @param[in] adc ADC unit select + * @param[in] channel ADC2 channel number + * @param[in] en Enable/disable the reference voltage output + */ +static inline void adc_ll_vref_output(adc_ll_num_t adc, adc_channel_t channel, bool en) +{ + /* Should be called before writing I2C registers. */ + void phy_get_romfunc_addr(void); + phy_get_romfunc_addr(); + SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PU_M); + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, BIT(18)); + SET_PERI_REG_MASK(ADC_LL_ANA_CONFIG2_REG, BIT(16)); + + if (en) { + if (adc == ADC_NUM_1) { + /* Config test mux to route v_ref to ADC1 Channels */ + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_DTEST_RTC_ADDR, 1); + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_TSENS_ADDR, 0); + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_RTC_ADDR, 1); + } else { + /* Config test mux to route v_ref to ADC2 Channels */ + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_DTEST_RTC_ADDR, 0); + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_TSENS_ADDR, 1); + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_RTC_ADDR, 0); + } + //in sleep force to use rtc to control ADC + SENS.sar_meas2_mux.sar2_rtc_force = 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 ADC2 channels (bits 0x380) + SENS.sar_meas2_ctrl2.sar2_en_pad = 1 << channel; + } else { + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_TSENS_ADDR, 0); + I2C_WRITEREG_MASK_RTC(ADC_LL_I2C_ADC, ADC_LL_SARADC_ENT_RTC_ADDR, 0); + SENS.sar_meas2_mux.sar2_rtc_force = 0; + //set sar2_en_test + SENS.sar_meas2_ctrl1.sar2_en_test = 0; + //set sar2 en force + SENS.sar_meas2_ctrl2.sar2_en_pad_force = 0; //Pad bitmap controlled by SW + //set en_pad for ADC2 channels (bits 0x380) + SENS.sar_meas2_ctrl2.sar2_en_pad = 0; + } +} + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/adc.rst b/docs/en/api-reference/peripherals/adc.rst index 12b19b93d..ca5a29ddf 100644 --- a/docs/en/api-reference/peripherals/adc.rst +++ b/docs/en/api-reference/peripherals/adc.rst @@ -53,7 +53,7 @@ Then it is possible to read ADC conversion result with :cpp:func:`adc1_get_raw` This API provides convenient way to configure ADC1 for reading from :doc:`ULP <../../api-guides/ulp>`. To do so, call function :cpp:func:`adc1_ulp_enable` and then set precision and attenuation as discussed above. -There is another specific function :cpp:func:`adc2_vref_to_gpio` used to route internal reference voltage to a GPIO pin. It comes handy to calibrate ADC reading and this is discussed in section :ref:`adc-api-adc-calibration`. +There is another specific function :cpp:func:`adc_vref_to_gpio` used to route internal reference voltage to a GPIO pin. It comes handy to calibrate ADC reading and this is discussed in section :ref:`adc-api-adc-calibration`. .. todo:: @@ -228,7 +228,7 @@ Routing ADC reference voltage to GPIO, so it can be manually measured (for **Def ... - esp_err_t status = adc2_vref_to_gpio(GPIO_NUM_25); + esp_err_t status = adc_vref_to_gpio(ADC_UNIT_1, GPIO_NUM_25); if (status == ESP_OK) { printf("v_ref routed to GPIO\n"); } else {