From daceb3516d4159b2b733b4facb1ebc4f4339eb14 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Mon, 27 Jun 2022 18:55:46 +0800 Subject: [PATCH] temperature sensor: Add support on ESP32-S3, Closes https://github.com/espressif/esp-idf/issues/8086 --- components/driver/CMakeLists.txt | 1 + components/driver/esp32c3/rtc_tempsensor.c | 1 + components/driver/esp32h2/rtc_tempsensor.c | 1 + components/driver/esp32s2/rtc_tempsensor.c | 1 + components/driver/esp32s3/rtc_tempsensor.c | 168 ++++++++++++++++++ .../efuse/esp32s3/esp_efuse_rtc_calib.c | 16 ++ components/soc/esp32s3/include/soc/soc_caps.h | 1 + docs/doxygen/Doxyfile_esp32s3 | 1 + .../api-reference/peripherals/temp_sensor.rst | 6 - examples/peripherals/temp_sensor/README.md | 4 +- .../temp_sensor/main/temp_sensor_main.c | 2 +- 11 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 components/driver/esp32s3/rtc_tempsensor.c diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index fb8e693d1d..1b572810e9 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -67,6 +67,7 @@ if(${target} STREQUAL "esp32s3") "spi_slave_hd.c" "touch_sensor_common.c" "esp32s3/touch_sensor.c" + "esp32s3/rtc_tempsensor.c" ) endif() diff --git a/components/driver/esp32c3/rtc_tempsensor.c b/components/driver/esp32c3/rtc_tempsensor.c index d77b75e902..82b1cb4b20 100644 --- a/components/driver/esp32c3/rtc_tempsensor.c +++ b/components/driver/esp32c3/rtc_tempsensor.c @@ -111,6 +111,7 @@ esp_err_t temp_sensor_stop(void) { APB_SARADC.apb_tsens_ctrl.tsens_pu = 0; APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 0; + tsens_hw_state = TSENS_HW_STATE_CONFIGURED; return ESP_OK; } diff --git a/components/driver/esp32h2/rtc_tempsensor.c b/components/driver/esp32h2/rtc_tempsensor.c index e447ebaa99..a45d86025d 100644 --- a/components/driver/esp32h2/rtc_tempsensor.c +++ b/components/driver/esp32h2/rtc_tempsensor.c @@ -111,6 +111,7 @@ esp_err_t temp_sensor_stop(void) { APB_SARADC.apb_tsens_ctrl.tsens_pu = 0; APB_SARADC.apb_tsens_ctrl2.tsens_clk_sel = 0; + tsens_hw_state = TSENS_HW_STATE_CONFIGURED; return ESP_OK; } diff --git a/components/driver/esp32s2/rtc_tempsensor.c b/components/driver/esp32s2/rtc_tempsensor.c index 7e74817904..0b4f0ac6f9 100644 --- a/components/driver/esp32s2/rtc_tempsensor.c +++ b/components/driver/esp32s2/rtc_tempsensor.c @@ -129,6 +129,7 @@ esp_err_t temp_sensor_stop(void) vSemaphoreDelete(rtc_tsens_mux); rtc_tsens_mux = NULL; } + tsens_hw_state = TSENS_HW_STATE_CONFIGURED; return ESP_OK; } diff --git a/components/driver/esp32s3/rtc_tempsensor.c b/components/driver/esp32s3/rtc_tempsensor.c new file mode 100644 index 0000000000..af456ec24a --- /dev/null +++ b/components/driver/esp32s3/rtc_tempsensor.c @@ -0,0 +1,168 @@ +/* + * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "esp_types.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "esp_check.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/rtc_io_reg.h" +#include "soc/rtc_io_struct.h" +#include "soc/sens_reg.h" +#include "soc/sens_struct.h" +#include "driver/temp_sensor.h" +#include "regi2c_ctrl.h" +#include "esp_log.h" +#include "esp_efuse_rtc_calib.h" + +static const char *TAG = "tsens"; + +#define TSENS_XPD_WAIT_DEFAULT 0xFF /* Set wait cycle time(8MHz) from power up to reset enable. */ +#define TSENS_ADC_FACTOR (0.4386) +#define TSENS_DAC_FACTOR (27.88) +#define TSENS_SYS_OFFSET (20.52) + +typedef struct { + int index; + int offset; + int set_val; + int range_min; + int range_max; + int error_max; +} tsens_dac_offset_t; + +static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = { + /* DAC Offset reg_val min max error */ + {TSENS_DAC_L0, -2, 5, 50, 125, 3}, + {TSENS_DAC_L1, -1, 7, 20, 100, 2}, + {TSENS_DAC_L2, 0, 15, -10, 80, 1}, + {TSENS_DAC_L3, 1, 11, -30, 50, 2}, + {TSENS_DAC_L4, 2, 10, -40, 20, 3}, +}; + +typedef enum { + TSENS_HW_STATE_UNCONFIGURED, + TSENS_HW_STATE_CONFIGURED, + TSENS_HW_STATE_STARTED, +} tsens_hw_state_t; + +static tsens_hw_state_t tsens_hw_state = TSENS_HW_STATE_UNCONFIGURED; + +static float s_deltaT = NAN; // Unused number + +esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens) +{ + esp_err_t err = ESP_OK; + if (tsens_hw_state == TSENS_HW_STATE_STARTED) { + ESP_LOGE(TAG, "Do not configure the temp sensor when it's running!"); + err = ESP_ERR_INVALID_STATE; + } + 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, I2C_SARADC_TSENS_DAC, dac_offset[tsens.dac_offset].set_val); + SENS.sar_tctrl.tsens_clk_div = tsens.clk_div; + SENS.sar_tctrl.tsens_power_up_force = 1; + SENS.sar_tctrl.tsens_power_up = 1; + SENS.sar_tctrl2.tsens_xpd_force = 1; + ESP_LOGI(TAG, "Config temperature range [%d°C ~ %d°C], error < %d°C", + dac_offset[tsens.dac_offset].range_min, + dac_offset[tsens.dac_offset].range_max, + dac_offset[tsens.dac_offset].error_max); + tsens_hw_state = TSENS_HW_STATE_CONFIGURED; + return err; +} + +esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens) +{ + ESP_RETURN_ON_FALSE(tsens != NULL, ESP_ERR_INVALID_ARG, TAG, "no tsens specified"); + CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_SAR_M); + SET_PERI_REG_MASK(ANA_CONFIG2_REG, ANA_SAR_CFG2_M); + tsens->dac_offset = REGI2C_READ_MASK(I2C_SAR_ADC, I2C_SARADC_TSENS_DAC); + for (int i = TSENS_DAC_L0; i < TSENS_DAC_MAX; i++) { + if ((int)tsens->dac_offset == dac_offset[i].set_val) { + tsens->dac_offset = dac_offset[i].index; + break; + } + } + tsens->clk_div = SENS.sar_tctrl.tsens_clk_div; + return ESP_OK; +} + +esp_err_t temp_sensor_start(void) +{ + esp_err_t err = ESP_OK; + if (tsens_hw_state != TSENS_HW_STATE_CONFIGURED) { + ESP_LOGE(TAG, "Temperature sensor is already running or not be configured"); + err = ESP_ERR_INVALID_STATE; + } + SENS.sar_tctrl.tsens_dump_out = 0; + SENS.sar_tctrl.tsens_power_up = 1; + SENS.sar_peri_clk_gate_conf.tsens_clk_en = 1; + tsens_hw_state = TSENS_HW_STATE_STARTED; + return err; +} + +esp_err_t temp_sensor_stop(void) +{ + SENS.sar_tctrl.tsens_power_up = 0; + tsens_hw_state = TSENS_HW_STATE_CONFIGURED; + return ESP_OK; +} + +esp_err_t temp_sensor_read_raw(uint32_t *tsens_out) +{ + ESP_RETURN_ON_FALSE(tsens_out != NULL, ESP_ERR_INVALID_ARG, TAG, "no tsens_out specified"); + SENS.sar_tctrl.tsens_dump_out = 1; + while (!SENS.sar_tctrl.tsens_ready); + *tsens_out = SENS.sar_tctrl.tsens_out; + SENS.sar_tctrl.tsens_dump_out = 0; + return ESP_OK; +} + +static void read_delta_t_from_efuse(void) +{ + uint32_t version = esp_efuse_rtc_calib_get_ver(); + if (version == 1) { + // fetch calibration value for temp sensor from eFuse + s_deltaT = esp_efuse_rtc_calib_get_cal_temp(version); + } else { + // no value to fetch, use 0. + s_deltaT = 0; + } + ESP_LOGD(TAG, "s_deltaT = %f", s_deltaT); +} + +static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const int dac_offset) +{ + if (isnan(s_deltaT)) { //suggests that the value is not initialized + read_delta_t_from_efuse(); + } + float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac_offset - TSENS_SYS_OFFSET) - s_deltaT; + return result; +} + +esp_err_t temp_sensor_read_celsius(float *celsius) +{ + ESP_RETURN_ON_FALSE(celsius != NULL, ESP_ERR_INVALID_ARG, TAG, "celsius points to nothing"); + temp_sensor_config_t tsens; + uint32_t tsens_out = 0; + esp_err_t ret = temp_sensor_get_config(&tsens); + if (ret == ESP_OK) { + ret = temp_sensor_read_raw(&tsens_out); + ESP_RETURN_ON_FALSE(ret == ESP_OK, ret, TAG, "failed to read raw data"); + const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset]; + *celsius = parse_temp_sensor_raw_value(tsens_out, dac->offset); + if (*celsius < dac->range_min || *celsius > dac->range_max) { + ESP_LOGW(TAG, "Exceeding the temperature range!"); + ret = ESP_ERR_INVALID_STATE; + } + } + return ret; +} diff --git a/components/efuse/esp32s3/esp_efuse_rtc_calib.c b/components/efuse/esp32s3/esp_efuse_rtc_calib.c index 272549986b..ec5f76814c 100644 --- a/components/efuse/esp32s3/esp_efuse_rtc_calib.c +++ b/components/efuse/esp32s3/esp_efuse_rtc_calib.c @@ -96,3 +96,19 @@ esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, in return ESP_OK; } + +float esp_efuse_rtc_calib_get_cal_temp(int version) +{ + assert(version == 1); + const esp_efuse_desc_t** cal_temp_efuse; + cal_temp_efuse = ESP_EFUSE_TEMP_CALIB; + int cal_temp_size = esp_efuse_get_field_size(cal_temp_efuse); + assert(cal_temp_size == 9); + + uint32_t cal_temp = 0; + esp_err_t err = esp_efuse_read_field_blob(cal_temp_efuse, &cal_temp, cal_temp_size); + assert(err == ESP_OK); + (void)err; + // BIT(8) stands for sign: 1: negtive, 0: positive + return ((cal_temp & BIT(8)) != 0)? -(uint8_t)cal_temp: (uint8_t)cal_temp; +} diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 1ce8343b12..6234e5c058 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -39,6 +39,7 @@ #define SOC_FLASH_ENCRYPTION_XTS_AES_256 1 #define SOC_PSRAM_DMA_CAPABLE 1 #define SOC_XT_WDT_SUPPORTED 1 +#define SOC_TEMP_SENSOR_SUPPORTED 1 /*-------------------------- SOC CAPS ----------------------------------------*/ #define SOC_APPCPU_HAS_CLOCK_GATING_BUG (1) diff --git a/docs/doxygen/Doxyfile_esp32s3 b/docs/doxygen/Doxyfile_esp32s3 index 2b3ea49869..ac3cfe67c6 100644 --- a/docs/doxygen/Doxyfile_esp32s3 +++ b/docs/doxygen/Doxyfile_esp32s3 @@ -8,6 +8,7 @@ INPUT += \ $(PROJECT_PATH)/components/driver/include/driver/pcnt.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/touch_sensor_channel.h \ $(PROJECT_PATH)/components/driver/$(IDF_TARGET)/include/driver/touch_sensor.h \ + $(PROJECT_PATH)/components/driver/esp32s2/include/driver/temp_sensor.h \ $(PROJECT_PATH)/components/ulp/include/esp32s3/ulp_riscv.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_host.h \ diff --git a/docs/en/api-reference/peripherals/temp_sensor.rst b/docs/en/api-reference/peripherals/temp_sensor.rst index 31ab51f324..a9e9fcb1be 100644 --- a/docs/en/api-reference/peripherals/temp_sensor.rst +++ b/docs/en/api-reference/peripherals/temp_sensor.rst @@ -1,12 +1,6 @@ Temperature Sensor =================== -.. only:: esp32s3 - - .. warning:: - - This feature is not supported in v4.4 - Overview -------- diff --git a/examples/peripherals/temp_sensor/README.md b/examples/peripherals/temp_sensor/README.md index 611c2dc700..64aae9b6ce 100644 --- a/examples/peripherals/temp_sensor/README.md +++ b/examples/peripherals/temp_sensor/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-S2 | ESP32-C3 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-C3 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | # Temperature Sensor Example diff --git a/examples/peripherals/temp_sensor/main/temp_sensor_main.c b/examples/peripherals/temp_sensor/main/temp_sensor_main.c index 2605899d22..b946c798c3 100644 --- a/examples/peripherals/temp_sensor/main/temp_sensor_main.c +++ b/examples/peripherals/temp_sensor/main/temp_sensor_main.c @@ -14,7 +14,7 @@ /* Note: ESP32 don't support temperature sensor */ -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 #include "driver/temp_sensor.h" static const char *TAG = "TempSensor";