Kaynağa Gözat

adc: support adc self-calibration on esp32s3

Armando 4 yıl önce
ebeveyn
işleme
ddd0235783

+ 8 - 3
components/driver/adc_common.c

@@ -247,11 +247,16 @@ uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, a
     uint32_t init_code = 0;
     if (version == 1) {
         init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
-        s_adc_cali_param[adc_n][atten] = init_code;
     } else {
-        ESP_LOGW(ADC_TAG, "Calibration eFuse is not configured, skip calibration");
+        ESP_LOGV(ADC_TAG, "Calibration eFuse is not configured, use self-calibration for ICode");
+        adc_power_acquire();
+        RTC_ENTER_CRITICAL();
+        const bool internal_gnd = true;
+        init_code = adc_hal_self_calibration(adc_n, channel, atten, internal_gnd);
+        RTC_EXIT_CRITICAL();
+        adc_power_release();
     }
-
+    s_adc_cali_param[adc_n][atten] = init_code;
     return s_adc_cali_param[adc_n][atten];
 }
 #elif CONFIG_IDF_TARGET_ESP32S2

+ 8 - 0
components/esp_hw_support/port/esp32s3/private_include/regi2c_saradc.h

@@ -18,6 +18,14 @@
 #define I2C_SAR_ADC            0X69
 #define I2C_SAR_ADC_HOSTID     0
 
+#define ADC_SAR1_ENCAL_GND_ADDR 0x7
+#define ADC_SAR1_ENCAL_GND_ADDR_MSB 5
+#define ADC_SAR1_ENCAL_GND_ADDR_LSB 5
+
+#define ADC_SAR2_ENCAL_GND_ADDR 0x7
+#define ADC_SAR2_ENCAL_GND_ADDR_MSB 7
+#define ADC_SAR2_ENCAL_GND_ADDR_LSB 7
+
 #define ADC_SAR1_INITIAL_CODE_HIGH_ADDR 0x1
 #define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB 0x3
 #define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB 0x0

+ 6 - 3
components/hal/adc_hal.c

@@ -71,10 +71,14 @@ void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param)
     }
 }
 
-#if CONFIG_IDF_TARGET_ESP32S2
+#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
 static void cal_setup(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
 {
+#if CONFIG_IDF_TARGET_ESP32S2
     adc_hal_set_controller(adc_n, ADC_CTRL_RTC);    //Set controller
+#else
+    adc_hal_set_controller(adc_n, ADC_LL_CTRL_ARB);    //Set controller
+#endif
 
     /* Enable/disable internal connect GND (for calibration). */
     if (internal_gnd) {
@@ -134,7 +138,6 @@ static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel)
 #define ADC_HAL_CAL_TIMES        (10)
 #define ADC_HAL_CAL_OFFSET_RANGE (4096)
 
-#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
 uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd)
 {
     if (adc_n == ADC_NUM_2) {
@@ -190,9 +193,9 @@ uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc
                    : (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1;
 
     adc_ll_calibration_finish(adc_n);
+
     return ret;
 }
-#endif  //#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
 #endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
 
 #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2

+ 31 - 7
components/hal/esp32s3/include/hal/adc_ll.h

@@ -129,8 +129,12 @@ static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wa
  */
 static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle)
 {
-    //To be added including RTC_CNTR reg and functions
-    abort();
+    /* Should be called before writing I2C registers. */
+    SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU_M);
+    CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_SAR_M);
+    SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_SAR_CFG2_M);
+
+    REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle);
 }
 
 /**
@@ -720,16 +724,32 @@ static inline void adc_ll_calibration_init(adc_ll_num_t adc_n)
 /**
  * Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration.
  *
- * @note  Different ADC units and different attenuation options use different calibration data (initial data).
- *
  * @param adc_n ADC index number.
- * @param channel adc channel number.
+ * @param channel Not used
  * @param internal_gnd true:  Disconnect from the IO port and use the internal GND as the calibration voltage.
  *                     false: Use IO external voltage as calibration voltage.
  */
 static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t channel, bool internal_gnd)
 {
-    abort();
+    /* Should be called before writing I2C registers. */
+    SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU_M);
+    CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_SAR_M);
+    SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_SAR_CFG2_M);
+
+    /* Enable/disable internal connect GND (for calibration). */
+    if (adc_n == ADC_NUM_1) {
+        if (internal_gnd) {
+            REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1);
+        } else {
+            REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
+        }
+    } else {    //adc_n == ADC_NUM_2
+        if (internal_gnd) {
+            REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1);
+        } else {
+            REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0);
+        }
+    }
 }
 
 /**
@@ -739,7 +759,11 @@ static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t
  */
 static inline void adc_ll_calibration_finish(adc_ll_num_t adc_n)
 {
-    abort();
+    if (adc_n == ADC_NUM_1) {
+        REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
+    } else {    //adc_n == ADC_NUM_2
+        REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0);
+    }
 }
 
 /**

+ 2 - 2
examples/peripherals/adc/single_read/single_read/main/single_read.c

@@ -54,9 +54,9 @@ static bool adc_calibration_init(void)
 
     ret = esp_adc_cal_check_efuse(ADC_EXAMPLE_CALI_SCHEME);
     if (ret == ESP_ERR_NOT_SUPPORTED) {
-        ESP_LOGW(TAG, "Calibration scheme not supported, skip calibration");
+        ESP_LOGW(TAG, "Calibration scheme not supported, skip software calibration");
     } else if (ret == ESP_ERR_INVALID_VERSION) {
-        ESP_LOGW(TAG, "eFuse not burnt, skip calibration");
+        ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
     } else if (ret == ESP_OK) {
         cali_enable = true;
         esp_adc_cal_characterize(ADC_UNIT_1, ADC_EXAMPLE_ATTEN, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars);