You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gu...@apache.org on 2021/11/26 18:23:29 UTC

[incubator-nuttx] branch master updated: risc-v/esp32c3: Refactor ADC calibration

This is an automated email from the ASF dual-hosted git repository.

gustavonihei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 66023da  risc-v/esp32c3: Refactor ADC calibration
66023da is described below

commit 66023da10c0de8a599d1db9eb3163646b6dfca0e
Author: Dong Heng <do...@espressif.com>
AuthorDate: Thu Oct 14 20:22:24 2021 +0800

    risc-v/esp32c3: Refactor ADC calibration
    
    Use calibration parameters from efuse rather than self-calibration.
---
 arch/risc-v/src/esp32c3/esp32c3_adc.c | 167 +++++++++++++++++++++++++++-------
 1 file changed, 136 insertions(+), 31 deletions(-)

diff --git a/arch/risc-v/src/esp32c3/esp32c3_adc.c b/arch/risc-v/src/esp32c3/esp32c3_adc.c
index 976a062..fa37438 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_adc.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_adc.c
@@ -38,6 +38,7 @@
 #include "esp32c3_adc.h"
 
 #include "hardware/esp32c3_system.h"
+#include "hardware/esp32c3_efuse.h"
 #include "hardware/esp32c3_saradc.h"
 #include "hardware/esp32c3_gpio_sigmap.h"
 #include "hardware/regi2c_ctrl.h"
@@ -63,6 +64,16 @@
 
 #define ADC_VAL_MASK            (0xfff)
 
+#define ADC_CAL_BASE_REG        EFUSE_RD_SYS_DATA_PART1_0_REG
+
+#define ADC_CAL_VER_OFF         (128)
+#define ADC_CAL_VER_LEN         (3)
+
+#define ADC_CAL_DATA_LEN        (10)
+#define ADC_CAL_DATA_COMP       (1000)
+
+#define ADC_CAL_VOL_LEN         (10)
+
 /* ADC input voltage attenuation, this affects measuring range */
 
 #define ADC_ATTEN_DB_0          (0)     /* Vmax = 800 mV  */
@@ -74,16 +85,32 @@
 
 #if defined(CONFIG_ESP32C3_ADC_VOL_750)
 #  define ADC_ATTEN_DEF         ADC_ATTEN_DB_0
-#  define ADC_VOL_VAL           (750)
+
+#  define ADC_CAL_DATA_OFF      (148)
+#  define ADC_CAL_VOL_OFF       (188)
+
+#  define ADC_CAL_VOL_DEF       (400)
 #elif defined(CONFIG_ESP32C3_ADC_VOL_1050)
 #  define ADC_ATTEN_DEF         ADC_ATTEN_DB_2_5
-#  define ADC_VOL_VAL           (1050)
+
+#  define ADC_CAL_DATA_OFF      (158)
+#  define ADC_CAL_VOL_OFF       (198)
+
+#  define ADC_CAL_VOL_DEF       (550)
 #elif defined(CONFIG_ESP32C3_ADC_VOL_1300)
 #  define ADC_ATTEN_DEF         ADC_ATTEN_DB_6
-#  define ADC_VOL_VAL           (1300)
+
+#  define ADC_CAL_DATA_OFF      (168)
+#  define ADC_CAL_VOL_OFF       (208)
+
+#  define ADC_CAL_VOL_DEF       (750)
 #elif defined(CONFIG_ESP32C3_ADC_VOL_2500)
 #  define ADC_ATTEN_DEF         ADC_ATTEN_DB_11
-#  define ADC_VOL_VAL           (2500)
+
+#  define ADC_CAL_DATA_OFF      (178)
+#  define ADC_CAL_VOL_OFF       (218)
+
+#  define ADC_CAL_VOL_DEF       (1370)
 #endif
 
 #define ADC_WORK_DELAY          (1)
@@ -214,6 +241,10 @@ static struct adc_dev_s g_adc1_chan4_dev =
 
 static bool g_calibrated;
 
+/* ADC calibration digital parameter */
+
+static uint16_t g_cal_digit;
+
 /* ADC clock reference */
 
 static uint32_t g_clk_ref;
@@ -225,6 +256,48 @@ static sem_t g_sem_excl = SEM_INITIALIZER(1);
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: read_efuse
+ *
+ * Description:
+ *   Read Efuse data.
+ *
+ * Input Parameters:
+ *   addr   - register address
+ *   b_off  - bit offset
+ *   b_size - bit size
+ *
+ * Returned Value:
+ *  Efuse data.
+ *
+ ****************************************************************************/
+
+static uint32_t read_efuse(uint32_t addr, uint32_t b_off, uint32_t b_size)
+{
+  uint32_t data;
+  uint32_t regval;
+  uint32_t shift = 32 - b_size;
+  uint32_t mask = UINT32_MAX >> shift;
+  uint32_t res = b_off % 32;
+  uint32_t regaddr = addr + (b_off / 32 * 4);
+
+  regval = getreg32(regaddr);
+  data = regval >> res;
+  if (res <= shift)
+    {
+      data &= mask;
+    }
+  else
+    {
+      shift = 32 - res;
+
+      regval = getreg32(regaddr + 4);
+      data |= (regval & (mask >> shift)) << shift;
+    }
+
+  return data;
+}
+
+/****************************************************************************
  * Name: adc_enable_clk
  *
  * Description:
@@ -410,47 +483,74 @@ static void adc_calibrate(void)
   uint16_t adc_max = 0;
   uint16_t adc_min = UINT16_MAX;
   uint32_t adc_sum = 0;
+  uint32_t regval;
 
-  /* Enable Vdef */
+  regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VER_OFF, ADC_CAL_VER_LEN);
+  if (regval == 1)
+    {
+      ainfo("Calibrate based on efuse data\n");
 
-  rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                        I2C_ADC1_DEF, I2C_ADC1_DEF_MSB,
-                        I2C_ADC1_DEF_LSB, 1);
+      regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_DATA_OFF,
+                          ADC_CAL_DATA_LEN);
+      cali_val = regval + ADC_CAL_DATA_COMP;
+    }
+  else
+    {
+      ainfo("Calibrate based on GND voltage\n");
 
-  /* Start sampling */
+      /* Enable Vdef */
 
-  adc_samplecfg(ADC_CAL_CHANNEL);
+      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
+                            I2C_ADC1_DEF, I2C_ADC1_DEF_MSB,
+                            I2C_ADC1_DEF_LSB, 1);
 
-  /* Enable internal connect GND (for calibration). */
+      /* Start sampling */
 
-  rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                        I2C_ADC1_ENCAL_GND, I2C_ADC1_ENCAL_GND_MSB,
-                        I2C_ADC1_ENCAL_GND_LSB, 1);
+      adc_samplecfg(ADC_CAL_CHANNEL);
 
-  for (int i = 1; i < ADC_CAL_CNT_MAX ; i++)
-    {
-      adc_set_calibration(0);
-      adc = adc_read();
+      /* Enable internal connect GND (for calibration). */
 
-      adc_sum += adc;
-      adc_max  = MAX(adc, adc_max);
-      adc_min  = MIN(adc, adc_min);
-    }
+      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
+                            I2C_ADC1_ENCAL_GND, I2C_ADC1_ENCAL_GND_MSB,
+                            I2C_ADC1_ENCAL_GND_LSB, 1);
 
-  cali_val = (adc_sum - adc_max - adc_min) / (ADC_CAL_CNT_MAX - 2);
+      for (int i = 1; i < ADC_CAL_CNT_MAX ; i++)
+        {
+          adc_set_calibration(0);
+          adc = adc_read();
+
+          adc_sum += adc;
+          adc_max  = MAX(adc, adc_max);
+          adc_min  = MIN(adc, adc_min);
+        }
 
-  /* Disable internal connect GND (for calibration). */
+      cali_val = (adc_sum - adc_max - adc_min) / (ADC_CAL_CNT_MAX - 2);
 
-  rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
-                        I2C_ADC1_ENCAL_GND,
-                        I2C_ADC1_ENCAL_GND_MSB,
-                        I2C_ADC1_ENCAL_GND_LSB, 0);
+      /* Disable internal connect GND (for calibration). */
+
+      rom_i2c_writereg_mask(I2C_ADC, I2C_ADC_HOSTID,
+                            I2C_ADC1_ENCAL_GND,
+                            I2C_ADC1_ENCAL_GND_MSB,
+                            I2C_ADC1_ENCAL_GND_LSB, 0);
+    }
 
   ainfo("calibration value: %" PRIu16 "\n", cali_val);
 
   /* Set final calibration parameters */
 
   adc_set_calibration(cali_val);
+
+  /* Set calibration digital parameters */
+
+  regval = read_efuse(ADC_CAL_BASE_REG, ADC_CAL_VOL_OFF, ADC_CAL_VOL_LEN);
+  if (regval & BIT(ADC_CAL_VOL_LEN - 1))
+    {
+      g_cal_digit = 2000 - (regval & ~(BIT(ADC_CAL_VOL_LEN - 1)));
+    }
+  else
+    {
+      g_cal_digit = 2000 + regval;
+    }
 }
 
 /****************************************************************************
@@ -470,7 +570,8 @@ static void adc_calibrate(void)
 static void adc_read_work(struct adc_dev_s *dev)
 {
   int ret;
-  uint16_t adc;
+  uint32_t value;
+  int32_t adc;
   struct adc_chan_s *priv = (struct adc_chan_s *)dev->ad_priv;
 
   ret = sem_wait(&g_sem_excl);
@@ -481,12 +582,15 @@ static void adc_read_work(struct adc_dev_s *dev)
     }
 
   adc_samplecfg(priv->channel);
-  adc = adc_read();
+  value = adc_read();
+
+  adc = (int32_t)(value * (UINT16_MAX * ADC_CAL_VOL_DEF / g_cal_digit) /
+                  UINT16_MAX);
 
   priv->cb->au_receive(dev, priv->channel, adc);
 
   ainfo("channel: %" PRIu8 ", voltage: %" PRIu32 " mV\n", priv->channel,
-        (uint32_t)adc * ADC_VOL_VAL / ADC_CAL_VAL_MAX);
+        adc);
 
   sem_post(&g_sem_excl);
 }
@@ -579,6 +683,7 @@ static int adc_setup(struct adc_dev_s *dev)
 
   if (priv->ref > 0)
     {
+      priv->ref++;
       return OK;
     }