Explorar o código

Merge branch 'feature/temperature_intr' into 'master'

temperature sensor: Add high/low value threshold interrupt support

Closes IDF-5786

See merge request espressif/esp-idf!22331
C.S.M %!s(int64=2) %!d(string=hai) anos
pai
achega
679dae70cd
Modificáronse 26 ficheiros con 649 adicións e 66 borrados
  1. 8 0
      components/driver/Kconfig
  2. 88 1
      components/driver/temperature_sensor/include/driver/temperature_sensor.h
  3. 128 14
      components/driver/temperature_sensor/temperature_sensor.c
  4. 49 0
      components/driver/temperature_sensor/temperature_sensor_private.h
  5. 67 1
      components/driver/test_apps/temperature_sensor/main/test_temperature_sensor.c
  6. 11 3
      components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py
  7. 7 0
      components/driver/test_apps/temperature_sensor/sdkconfig.ci.iram_safe
  8. 12 4
      components/hal/esp32c6/include/hal/temperature_sensor_ll.h
  9. 12 4
      components/hal/esp32h2/include/hal/temperature_sensor_ll.h
  10. 8 0
      components/soc/esp32c6/include/soc/Kconfig.soc_caps.in
  11. 5 1
      components/soc/esp32c6/include/soc/soc_caps.h
  12. 8 0
      components/soc/esp32h2/include/soc/Kconfig.soc_caps.in
  13. 29 29
      components/soc/esp32h2/include/soc/apb_saradc_reg.h
  14. 5 2
      components/soc/esp32h2/include/soc/soc_caps.h
  15. 60 6
      docs/en/api-reference/peripherals/temp_sensor.rst
  16. 5 1
      examples/peripherals/.build-test-rules.yml
  17. 0 0
      examples/peripherals/temperature_sensor/temp_sensor/CMakeLists.txt
  18. 0 0
      examples/peripherals/temperature_sensor/temp_sensor/README.md
  19. 0 0
      examples/peripherals/temperature_sensor/temp_sensor/main/CMakeLists.txt
  20. 0 0
      examples/peripherals/temperature_sensor/temp_sensor/main/temp_sensor_main.c
  21. 0 0
      examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py
  22. 6 0
      examples/peripherals/temperature_sensor/temp_sensor_monitor/CMakeLists.txt
  23. 67 0
      examples/peripherals/temperature_sensor/temp_sensor_monitor/README.md
  24. 2 0
      examples/peripherals/temperature_sensor/temp_sensor_monitor/main/CMakeLists.txt
  25. 53 0
      examples/peripherals/temperature_sensor/temp_sensor_monitor/main/temp_sensor_monitor_main.c
  26. 19 0
      examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py

+ 8 - 0
components/driver/Kconfig

@@ -208,6 +208,14 @@ menu "Driver Configurations"
                 Wether to enable the debug log message for temperature sensor driver.
                 Note that, this option only controls the temperature sensor driver log, won't affect other drivers.
 
+        config TEMP_SENSOR_ISR_IRAM_SAFE
+            depends on SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+            bool "Temperature sensor ISR IRAM-Safe"
+            default n
+            help
+                Ensure the Temperature Sensor interrupt is IRAM-Safe by allowing the interrupt handler to be
+                executable when the cache is disabled (e.g. SPI Flash write).
+
     endmenu # TEMP_SENSOR Configuration
 
     menu "UART Configuration"

+ 88 - 1
components/driver/temperature_sensor/include/driver/temperature_sensor.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -7,6 +7,7 @@
 #pragma once
 
 #include <stdint.h>
+#include <stdbool.h>
 #include "esp_err.h"
 #include "hal/temperature_sensor_types.h"
 
@@ -94,6 +95,92 @@ esp_err_t temperature_sensor_disable(temperature_sensor_handle_t tsens);
  */
 esp_err_t temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, float *out_celsius);
 
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
+/**
+ * @brief Temperature sensor event data
+ */
+typedef struct {
+    int celsius_value; /**< Celsius value in interrupt callback. */
+} temperature_sensor_threshold_event_data_t;
+
+/**
+ * @brief Callback for temperature sensor threshold interrupt.
+ *
+ * @param[in] tsens The handle created by `temperature_sensor_install()`.
+ * @param[in] edata temperature sensor event data, fed by driver.
+ * @param[in] user_data User data, set in `temperature_sensor_register_callbacks()`.
+ * @return Whether a high priority task has been waken up by this function.
+ */
+typedef bool (*temperature_thres_cb_t)(temperature_sensor_handle_t tsens, const temperature_sensor_threshold_event_data_t *edata, void *user_data);
+
+/**
+ * @brief Group of temperature sensor callback functions, all of them will be run in ISR.
+ */
+typedef struct {
+    temperature_thres_cb_t on_threshold;  /**< Temperature value interrupt callback */
+} temperature_sensor_event_callbacks_t;
+
+/**
+ * @brief Config options for temperature value absolute interrupt.
+ */
+typedef struct {
+    float high_threshold;  /**< High threshold value(Celsius). Interrupt will be triggered if temperature value is higher than this value */
+    float low_threshold;   /**< Low threshold value(Celsius). Interrupt will be triggered if temperature value is lower than this value */
+} temperature_sensor_abs_threshold_config_t;
+
+/**
+ * @brief Set temperature sensor absolute mode automatic monitor.
+ *
+ * @param tsens The handle created by `temperature_sensor_install()`.
+ * @param abs_cfg Configuration of temperature sensor absolute mode interrupt, see `temperature_sensor_abs_threshold_config_t`.
+ * @note This function should not be called with `temperature_sensor_set_delta_threshold`.
+ *
+ * @return
+ *      - ESP_OK: Set absolute threshold successfully.
+ *      - ESP_ERR_INVALID_STATE: Set absolute threshold failed because of wrong state.
+ *      - ESP_ERR_INVALID_ARG: Set absolute threshold failed because of invalid argument.
+ */
+esp_err_t temperature_sensor_set_absolute_threshold(temperature_sensor_handle_t tsens, const temperature_sensor_abs_threshold_config_t *abs_cfg);
+
+/**
+ * @brief Config options for temperature value delta interrupt.
+ */
+typedef struct {
+    float increase_delta;   /**< Interrupt will be triggered if the temperature increment of two consecutive samplings if larger than `increase_delta` */
+    float decrease_delta;   /**< Interrupt will be triggered if the temperature decrement of two consecutive samplings if smaller than `decrease_delta` */
+} temperature_sensor_delta_threshold_config_t;
+
+/**
+ * @brief Set temperature sensor differential mode automatic monitor.
+ *
+ * @param tsens The handle created by `temperature_sensor_install()`.
+ * @param delta_cfg Configuration of temperature sensor delta mode interrupt, see `temperature_sensor_delta_threshold_config_t`.
+ * @note This function should not be called with `temperature_sensor_set_absolute_threshold`
+ *
+ * @return
+ *      - ESP_OK: Set differential value threshold successfully.
+ *      - ESP_ERR_INVALID_STATE: Set absolute threshold failed because of wrong state.
+ *      - ESP_ERR_INVALID_ARG: Set differential value threshold failed because of invalid argument.
+ */
+esp_err_t temperature_sensor_set_delta_threshold(temperature_sensor_handle_t tsens, const temperature_sensor_delta_threshold_config_t *delta_cfg);
+
+/**
+ * @brief Install temperature sensor interrupt callback. Temperature sensor interrupt will be enabled at same time
+ *
+ * @param tsens The handle created by `temperature_sensor_install()`.
+ * @param cbs Pointer to the group of temperature sensor interrupt callbacks.
+ * @param user_arg Callback argument.
+ *
+ * @return
+ *      - ESP_OK: Set event callbacks successfully
+ *      - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
+ *      - ESP_FAIL: Set event callbacks failed because of other error
+ */
+esp_err_t temperature_sensor_register_callbacks(temperature_sensor_handle_t tsens, const temperature_sensor_event_callbacks_t *cbs, void *user_arg);
+
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
 #ifdef __cplusplus
 }
 #endif

+ 128 - 14
components/driver/temperature_sensor/temperature_sensor.c

@@ -24,25 +24,18 @@
 #include "driver/temperature_sensor.h"
 #include "esp_efuse_rtc_calib.h"
 #include "esp_private/periph_ctrl.h"
+#include "temperature_sensor_private.h"
 #include "hal/temperature_sensor_ll.h"
 #include "soc/temperature_sensor_periph.h"
+#include "esp_memory_utils.h"
 
 static const char *TAG = "temperature_sensor";
 
-typedef enum {
-    TEMP_SENSOR_FSM_INIT,
-    TEMP_SENSOR_FSM_ENABLE,
-} temp_sensor_fsm_t;
-
 static float s_deltaT = NAN; // unused number
 
-typedef struct temperature_sensor_obj_t temperature_sensor_obj_t;
-
-struct temperature_sensor_obj_t {
-    const temperature_sensor_attribute_t *tsens_attribute;
-    temp_sensor_fsm_t  fsm;
-    temperature_sensor_clk_src_t clk_src;
-};
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+static int8_t s_temperature_regval_2_celsius(temperature_sensor_handle_t tsens, uint8_t regval);
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
 
 static temperature_sensor_attribute_t *s_tsens_attribute_copy;
 
@@ -53,7 +46,7 @@ static int inline accuracy_compare(const void *p1, const void *p2)
 
 static esp_err_t temperature_sensor_attribute_table_sort(void)
 {
-    s_tsens_attribute_copy = (temperature_sensor_attribute_t *)heap_caps_malloc(sizeof(temperature_sensor_attributes), MALLOC_CAP_DEFAULT);
+    s_tsens_attribute_copy = (temperature_sensor_attribute_t *)heap_caps_malloc(sizeof(temperature_sensor_attributes), TEMPERATURE_SENSOR_MEM_ALLOC_CAPS);
     ESP_RETURN_ON_FALSE(s_tsens_attribute_copy != NULL, ESP_ERR_NO_MEM, TAG, "No space for s_tsens_attribute_copy");
     for (int i = 0 ; i < TEMPERATURE_SENSOR_ATTR_RANGE_NUM; i++) {
         s_tsens_attribute_copy[i] = temperature_sensor_attributes[i];
@@ -75,6 +68,27 @@ static esp_err_t temperature_sensor_choose_best_range(temperature_sensor_handle_
     return ESP_OK;
 }
 
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+static void IRAM_ATTR temperature_sensor_isr(void *arg)
+{
+    temperature_sensor_ll_clear_intr();
+    bool cbs_yield = false;
+    temperature_sensor_handle_t tsens = (temperature_sensor_handle_t) arg;
+    temperature_sensor_threshold_event_data_t data = {
+        .celsius_value = s_temperature_regval_2_celsius(tsens, temperature_sensor_ll_get_raw_value()),
+    };
+    if (tsens->threshold_cbs) {
+        if (tsens->threshold_cbs(tsens, &data, tsens->cb_user_arg)) {
+            cbs_yield = true;
+        }
+    }
+
+    if (cbs_yield) {
+        portYIELD_FROM_ISR();
+    }
+}
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
 esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_config, temperature_sensor_handle_t *ret_tsens)
 {
 #if CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG
@@ -121,6 +135,13 @@ esp_err_t temperature_sensor_uninstall(temperature_sensor_handle_t tsens)
     s_tsens_attribute_copy = NULL;
     regi2c_saradc_disable();
 
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    temperature_sensor_ll_enable_intr(false);
+    if (tsens->temp_sensor_isr_handle) {
+        ESP_RETURN_ON_ERROR(esp_intr_free(tsens->temp_sensor_isr_handle), TAG, "uninstall interrupt service failed");
+    }
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
     periph_module_disable(PERIPH_TEMPSENSOR_MODULE);
     free(tsens);
     return ESP_OK;
@@ -137,6 +158,11 @@ esp_err_t temperature_sensor_enable(temperature_sensor_handle_t tsens)
     }
 #endif
 
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    temperature_sensor_ll_wakeup_enable(true);
+    temperature_sensor_ll_sample_enable(true);
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
     temperature_sensor_ll_clk_enable(true);
     temperature_sensor_ll_clk_sel(tsens->clk_src);
     temperature_sensor_ll_enable(true);
@@ -149,6 +175,11 @@ esp_err_t temperature_sensor_disable(temperature_sensor_handle_t tsens)
     ESP_RETURN_ON_FALSE(tsens, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
     ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "tsens not enabled yet");
 
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    temperature_sensor_ll_wakeup_enable(false);
+    temperature_sensor_ll_sample_enable(false);
+#endif
+
     temperature_sensor_ll_enable(false);
 #if SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
     if (tsens->clk_src == TEMPERATURE_SENSOR_CLK_SRC_RC_FAST) {
@@ -185,7 +216,7 @@ esp_err_t temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, floa
     ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "tsens not enabled yet");
 
     uint32_t tsens_out = temperature_sensor_ll_get_raw_value();
-    ESP_LOGV(TAG, "tsens_out %"PRIu32, tsens_out);
+    ESP_LOGD(TAG, "tsens_out %"PRIu32, tsens_out);
 
     *out_celsius = parse_temp_sensor_raw_value(tsens_out, tsens->tsens_attribute->offset);
     if (*out_celsius < tsens->tsens_attribute->range_min || *out_celsius > tsens->tsens_attribute->range_max) {
@@ -194,3 +225,86 @@ esp_err_t temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, floa
     }
     return ESP_OK;
 }
+
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
+static uint8_t s_temperature_celsius_2_regval(temperature_sensor_handle_t tsens, int8_t celsius)
+{
+    return (uint8_t)((celsius + TEMPERATURE_SENSOR_LL_OFFSET_FACTOR + TEMPERATURE_SENSOR_LL_DAC_FACTOR * tsens->tsens_attribute->offset)/TEMPERATURE_SENSOR_LL_ADC_FACTOR);
+}
+
+IRAM_ATTR static int8_t s_temperature_regval_2_celsius(temperature_sensor_handle_t tsens, uint8_t regval)
+{
+    return TEMPERATURE_SENSOR_LL_ADC_FACTOR * regval - TEMPERATURE_SENSOR_LL_DAC_FACTOR * tsens->tsens_attribute->offset - TEMPERATURE_SENSOR_LL_OFFSET_FACTOR;
+}
+
+esp_err_t temperature_sensor_set_absolute_threshold(temperature_sensor_handle_t tsens, const temperature_sensor_abs_threshold_config_t *abs_cfg)
+{
+    esp_err_t ret = ESP_OK;
+    ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Temperature sensor has not been installed");
+    ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "temperature sensor is not in init state");
+    ESP_RETURN_ON_FALSE(abs_cfg, ESP_ERR_INVALID_ARG, TAG, "Invalid callback configuration");
+
+    temperature_sensor_ll_set_sample_rate(0xffff);
+    temperature_sensor_ll_wakeup_mode(TEMPERATURE_SENSOR_LL_WAKE_ABSOLUTE);
+    temperature_sensor_ll_set_th_high_val(s_temperature_celsius_2_regval(tsens, abs_cfg->high_threshold));
+    temperature_sensor_ll_set_th_low_val(s_temperature_celsius_2_regval(tsens, abs_cfg->low_threshold));
+
+    return ret;
+}
+
+esp_err_t temperature_sensor_set_delta_threshold(temperature_sensor_handle_t tsens, const temperature_sensor_delta_threshold_config_t *delta_cfg)
+{
+    esp_err_t ret = ESP_OK;
+    ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Temperature sensor has not been installed");
+    ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "temperature sensor is not in init state");
+    ESP_RETURN_ON_FALSE(delta_cfg, ESP_ERR_INVALID_ARG, TAG, "Invalid callback configuration");
+
+    temperature_sensor_ll_set_sample_rate(0xffff);
+    temperature_sensor_ll_wakeup_mode(TEMPERATURE_SENSOR_LL_WAKE_DELTA);
+    temperature_sensor_ll_set_th_high_val((uint8_t)(delta_cfg->increase_delta / TEMPERATURE_SENSOR_LL_ADC_FACTOR));
+    temperature_sensor_ll_set_th_low_val((uint8_t)(delta_cfg->decrease_delta / TEMPERATURE_SENSOR_LL_ADC_FACTOR));
+
+    return ret;
+}
+
+esp_err_t temperature_sensor_register_callbacks(temperature_sensor_handle_t tsens, const temperature_sensor_event_callbacks_t *cbs, void *user_arg)
+{
+    esp_err_t ret = ESP_OK;
+    ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Temperature sensor has not been installed");
+    ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "temperature sensor is not in init state");
+    ESP_RETURN_ON_FALSE(cbs, ESP_ERR_INVALID_ARG, TAG, "callback group pointer is invalid");
+
+#if CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE
+    if (cbs->on_threshold) {
+        ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_threshold), ESP_ERR_INVALID_ARG, TAG, "threshold callback not in IRAM");
+    }
+    if (user_arg) {
+        ESP_RETURN_ON_FALSE(esp_ptr_internal(user_arg), ESP_ERR_INVALID_ARG, TAG, "user argument not in internal RAM");
+    }
+#endif
+
+    int isr_flags = TEMPERATURE_SENSOR_INTR_ALLOC_FLAGS;
+#if SOC_ADC_TEMPERATURE_SHARE_INTR
+    isr_flags |= ESP_INTR_FLAG_SHARED;
+#endif
+
+    // lazy install interrupt service.
+    if (!tsens->temp_sensor_isr_handle) {
+        ret = esp_intr_alloc_intrstatus(ETS_APB_ADC_INTR_SOURCE, isr_flags,
+                                    (uint32_t)temperature_sensor_ll_get_intr_status(),
+                                    TEMPERATURE_SENSOR_LL_INTR_MASK, temperature_sensor_isr, tsens, &tsens->temp_sensor_isr_handle);
+    }
+
+    if (cbs->on_threshold != NULL) {
+        temperature_sensor_ll_enable_intr(true);
+        temperature_sensor_ll_clear_intr();
+        tsens->threshold_cbs = cbs->on_threshold;
+        tsens->cb_user_arg = user_arg;
+    } else {
+        temperature_sensor_ll_enable_intr(false);
+    }
+    return ret;
+}
+
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT

+ 49 - 0
components/driver/temperature_sensor/temperature_sensor_private.h

@@ -0,0 +1,49 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include "soc/temperature_sensor_periph.h"
+#include "hal/temperature_sensor_types.h"
+#include "driver/temperature_sensor.h"
+#include "esp_intr_alloc.h"
+#include "sdkconfig.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    TEMP_SENSOR_FSM_INIT,
+    TEMP_SENSOR_FSM_ENABLE,
+} temp_sensor_fsm_t;
+
+#if CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE
+#define TEMPERATURE_SENSOR_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
+#define TEMPERATURE_SENSOR_MEM_ALLOC_CAPS      (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
+#else
+#define TEMPERATURE_SENSOR_INTR_ALLOC_FLAGS    (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
+#define TEMPERATURE_SENSOR_MEM_ALLOC_CAPS      (MALLOC_CAP_DEFAULT)
+#endif
+
+typedef struct temperature_sensor_obj_t temperature_sensor_obj_t;
+
+struct temperature_sensor_obj_t {
+    const temperature_sensor_attribute_t *tsens_attribute;
+    temp_sensor_fsm_t  fsm;
+    temperature_sensor_clk_src_t clk_src;
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    intr_handle_t temp_sensor_isr_handle;
+    temperature_thres_cb_t threshold_cbs;
+    void *cb_user_arg;
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+};
+
+
+#ifdef __cplusplus
+}
+#endif

+ 67 - 1
components/driver/test_apps/temperature_sensor/main/test_temperature_sensor.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -8,6 +8,11 @@
 #include "esp_log.h"
 #include "unity.h"
 #include "driver/temperature_sensor.h"
+#include "esp_attr.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "soc/soc_caps.h"
+#include "unity_test_utils_cache.h"
 
 TEST_CASE("Temperature_sensor_driver_workflow_test", "[temperature_sensor]")
 {
@@ -79,3 +84,64 @@ TEST_CASE("Double Start-Stop test", "[temperature_sensor]")
     TEST_ESP_OK(temperature_sensor_disable(temp_handle));
     TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
 }
+
+#if SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
+IRAM_ATTR static bool temp_sensor_cbs_test(temperature_sensor_handle_t tsens, const temperature_sensor_threshold_event_data_t *edata, void *user_data)
+{
+    uint8_t *times = (uint8_t*)user_data;
+    ESP_DRAM_LOGI("tsens", "Temperature value is higher or lower than threshold, restart...\n\n");
+    (*times)++;
+    return false;
+}
+
+#if CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE
+static void IRAM_ATTR test_delay_post_cache_disable(void *args)
+{
+    esp_rom_delay_us(1000);
+}
+#endif
+
+TEST_CASE("Temperature sensor callback test", "[temperature_sensor]")
+{
+    printf("Initializing Temperature sensor\n");
+    float tsens_out;
+    temperature_sensor_config_t temp_sensor = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 50);
+    temperature_sensor_handle_t temp_handle = NULL;
+    TEST_ESP_OK(temperature_sensor_install(&temp_sensor, &temp_handle));
+
+    temperature_sensor_event_callbacks_t cbs = {
+        .on_threshold = temp_sensor_cbs_test,
+    };
+
+    temperature_sensor_abs_threshold_config_t threshold_cfg = {
+        .high_threshold = 50,
+        .low_threshold = -10,
+    };
+    uint8_t temperature_alarm = 0;
+    uint8_t cnt = 10;
+    TEST_ESP_OK(temperature_sensor_set_absolute_threshold(temp_handle, &threshold_cfg));
+    temperature_sensor_register_callbacks(temp_handle, &cbs, &temperature_alarm);
+
+    TEST_ESP_OK(temperature_sensor_enable(temp_handle));
+#if CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE
+    printf("disable flash cache and check if we can still get temperature intr\r\n");
+    for (int i = 0; i < 100; i++) {
+        unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL);
+    }
+#endif
+    while (cnt--) {
+        ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
+        printf("Temperature out celsius %f°C\n", tsens_out);
+        vTaskDelay(pdMS_TO_TICKS(1000));
+    }
+
+    TEST_ESP_OK(temperature_sensor_disable(temp_handle));
+    TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
+    printf("temperature alarm is %d\n", temperature_alarm);
+    // Note that on CI runner there is no way to heat the board to trigger such an interrupt.
+    // But locally test should be notice that alarm must be larger than 0.
+    TEST_ASSERT_GREATER_OR_EQUAL(0, temperature_alarm);
+}
+
+#endif // SOC_TEMPERATURE_SENSOR_INTR_SUPPORT

+ 11 - 3
components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py

@@ -16,6 +16,14 @@ from pytest_embedded import Dut
     'release',
 ], indirect=True)
 def test_temperature_sensor_driver(dut: Dut) -> None:
-    dut.expect('Press ENTER to see the list of tests')
-    dut.write('*')
-    dut.expect_unity_test_output(timeout=120)
+    dut.run_all_single_board_cases()
+
+
+@pytest.mark.esp32c6
+@pytest.mark.esp32h2
+@pytest.mark.generic
+@pytest.mark.parametrize('config', [
+    'iram_safe',
+], indirect=True)
+def test_temperature_sensor_cbs(dut: Dut) -> None:
+    dut.run_all_single_board_cases()

+ 7 - 0
components/driver/test_apps/temperature_sensor/sdkconfig.ci.iram_safe

@@ -0,0 +1,7 @@
+CONFIG_COMPILER_DUMP_RTL_FILES=y
+CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE=y
+CONFIG_COMPILER_OPTIMIZATION_NONE=y
+# silent the error check, as the error string are stored in rodata, causing RTL check failure
+CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
+# place non-ISR FreeRTOS functions in Flash
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y

+ 12 - 4
components/hal/esp32c6/include/hal/temperature_sensor_ll.h

@@ -19,6 +19,7 @@
 #include "hal/regi2c_ctrl.h"
 #include "soc/regi2c_saradc.h"
 #include "soc/apb_saradc_struct.h"
+#include "soc/apb_saradc_reg.h"
 #include "soc/soc.h"
 #include "soc/soc_caps.h"
 #include "soc/pcr_struct.h"
@@ -34,6 +35,13 @@ extern "C" {
 #define TEMPERATURE_SENSOR_LL_DAC_FACTOR     (27.88)
 #define TEMPERATURE_SENSOR_LL_OFFSET_FACTOR  (20.52)
 
+#define TEMPERATURE_SENSOR_LL_INTR_MASK      APB_SARADC_APB_SARADC_TSENS_INT_ST
+
+typedef enum {
+    TEMPERATURE_SENSOR_LL_WAKE_ABSOLUTE = 0,
+    TEMPERATURE_SENSOR_LL_WAKE_DELTA = 1,
+} temperature_sensor_ll_wakeup_mode_t;
+
 /**
  * @brief Enable the temperature sensor power.
  *
@@ -90,6 +98,7 @@ static inline void temperature_sensor_ll_set_range(uint32_t range)
  *
  * @return uint32_t raw_value
  */
+__attribute__((always_inline))
 static inline uint32_t temperature_sensor_ll_get_raw_value(void)
 {
     return APB_SARADC.saradc_apb_tsens_ctrl.saradc_tsens_out;
@@ -187,6 +196,7 @@ static inline void temperature_sensor_ll_enable_intr(bool enable)
 /**
  * @brief Clear temperature sensor interrupt
  */
+__attribute__((always_inline))
 static inline void temperature_sensor_ll_clear_intr(void)
 {
     APB_SARADC.saradc_int_clr.saradc_apb_saradc_tsens_int_clr = 1;
@@ -194,12 +204,10 @@ static inline void temperature_sensor_ll_clear_intr(void)
 
 /**
  * @brief Get temperature sensor interrupt status.
- *
- * @param[out] int_status interrupt status.
  */
-static inline void temperature_sensor_ll_get_intr_status(uint8_t *int_status)
+static inline volatile void *temperature_sensor_ll_get_intr_status(void)
 {
-    *int_status = APB_SARADC.saradc_int_st.saradc_apb_saradc_tsens_int_st;
+    return &APB_SARADC.saradc_int_st;
 }
 
 /**

+ 12 - 4
components/hal/esp32h2/include/hal/temperature_sensor_ll.h

@@ -19,6 +19,7 @@
 #include "hal/regi2c_ctrl.h"
 #include "soc/regi2c_saradc.h"
 #include "soc/apb_saradc_struct.h"
+#include "soc/apb_saradc_reg.h"
 #include "soc/soc.h"
 #include "soc/soc_caps.h"
 #include "soc/pcr_struct.h"
@@ -34,6 +35,13 @@ extern "C" {
 #define TEMPERATURE_SENSOR_LL_DAC_FACTOR     (27.88)
 #define TEMPERATURE_SENSOR_LL_OFFSET_FACTOR  (20.52)
 
+#define TEMPERATURE_SENSOR_LL_INTR_MASK      APB_SARADC_APB_SARADC_TSENS_INT_ST
+
+typedef enum {
+    TEMPERATURE_SENSOR_LL_WAKE_ABSOLUTE = 0,
+    TEMPERATURE_SENSOR_LL_WAKE_DELTA = 1,
+} temperature_sensor_ll_wakeup_mode_t;
+
 /**
  * @brief Enable the temperature sensor power.
  *
@@ -90,6 +98,7 @@ static inline void temperature_sensor_ll_set_range(uint32_t range)
  *
  * @return uint32_t raw_value
  */
+__attribute__((always_inline))
 static inline uint32_t temperature_sensor_ll_get_raw_value(void)
 {
     return APB_SARADC.saradc_apb_tsens_ctrl.saradc_tsens_out;
@@ -187,6 +196,7 @@ static inline void temperature_sensor_ll_enable_intr(bool enable)
 /**
  * @brief Clear temperature sensor interrupt
  */
+__attribute__((always_inline))
 static inline void temperature_sensor_ll_clear_intr(void)
 {
     APB_SARADC.saradc_int_clr.saradc_apb_saradc_tsens_int_clr = 1;
@@ -194,12 +204,10 @@ static inline void temperature_sensor_ll_clear_intr(void)
 
 /**
  * @brief Get temperature sensor interrupt status.
- *
- * @param[out] int_status interrupt status.
  */
-static inline void temperature_sensor_ll_get_intr_status(uint8_t *int_status)
+static inline volatile void *temperature_sensor_ll_get_intr_status(void)
 {
-    *int_status = APB_SARADC.saradc_int_st.saradc_apb_saradc_tsens_int_st;
+    return &APB_SARADC.saradc_int_st;
 }
 
 /**

+ 8 - 0
components/soc/esp32c6/include/soc/Kconfig.soc_caps.in

@@ -271,6 +271,10 @@ config SOC_ADC_CALIBRATION_V1_SUPPORTED
     bool
     default n
 
+config SOC_ADC_TEMPERATURE_SHARE_INTR
+    bool
+    default y
+
 config SOC_APB_BACKUP_DMA
     bool
     default n
@@ -1099,6 +1103,10 @@ config SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL
     bool
     default y
 
+config SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    bool
+    default y
+
 config SOC_WIFI_HW_TSF
     bool
     default y

+ 5 - 1
components/soc/esp32c6/include/soc/soc_caps.h

@@ -113,6 +113,9 @@
 /*!< Calibration */
 #define SOC_ADC_CALIBRATION_V1_SUPPORTED        (0) /*!< support HW offset calibration version 1*/
 
+/*!< Interrupt */
+#define SOC_ADC_TEMPERATURE_SHARE_INTR          (1)
+
 // ESP32C6-TODO: Copy from esp32c6, need check
 /*-------------------------- APB BACKUP DMA CAPS -------------------------------*/
 #define SOC_APB_BACKUP_DMA              (0)
@@ -460,7 +463,8 @@
 
 /*-------------------------- Temperature Sensor CAPS -------------------------------------*/
 #define SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC                (1)
-#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL                (1)
+#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL                   (1)
+#define SOC_TEMPERATURE_SENSOR_INTR_SUPPORT                   (1)
 
 /*------------------------------------ WI-FI CAPS ------------------------------------*/
 #define SOC_WIFI_HW_TSF                 (1)    /*!< Support hardware TSF */

+ 8 - 0
components/soc/esp32h2/include/soc/Kconfig.soc_caps.in

@@ -239,6 +239,10 @@ config SOC_ADC_CALIBRATION_V1_SUPPORTED
     bool
     default n
 
+config SOC_ADC_TEMPERATURE_SHARE_INTR
+    bool
+    default y
+
 config SOC_APB_BACKUP_DMA
     bool
     default n
@@ -1039,6 +1043,10 @@ config SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL
     bool
     default y
 
+config SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+    bool
+    default y
+
 config SOC_BLE_SUPPORTED
     bool
     default y

+ 29 - 29
components/soc/esp32h2/include/soc/apb_saradc_reg.h

@@ -1,5 +1,5 @@
 /**
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  *
  *  SPDX-License-Identifier: Apache-2.0
  */
@@ -14,7 +14,7 @@ extern "C" {
 /** APB_SARADC_CTRL_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_CTRL_REG (DR_REG_APB_BASE + 0x0)
+#define APB_SARADC_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x0)
 /** APB_SARADC_SARADC_START_FORCE : R/W; bitpos: [0]; default: 0;
  *  select software enable saradc sample
  */
@@ -82,7 +82,7 @@ extern "C" {
 /** APB_SARADC_CTRL2_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_CTRL2_REG (DR_REG_APB_BASE + 0x4)
+#define APB_SARADC_CTRL2_REG (DR_REG_APB_SARADC_BASE + 0x4)
 /** APB_SARADC_SARADC_MEAS_NUM_LIMIT : R/W; bitpos: [0]; default: 0;
  *  enable max meas num
  */
@@ -129,7 +129,7 @@ extern "C" {
 /** APB_SARADC_FILTER_CTRL1_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_FILTER_CTRL1_REG (DR_REG_APB_BASE + 0x8)
+#define APB_SARADC_FILTER_CTRL1_REG (DR_REG_APB_SARADC_BASE + 0x8)
 /** APB_SARADC_APB_SARADC_FILTER_FACTOR1 : R/W; bitpos: [28:26]; default: 0;
  *  Factor of saradc filter1
  */
@@ -148,7 +148,7 @@ extern "C" {
 /** APB_SARADC_FSM_WAIT_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_FSM_WAIT_REG (DR_REG_APB_BASE + 0xc)
+#define APB_SARADC_FSM_WAIT_REG (DR_REG_APB_SARADC_BASE + 0xc)
 /** APB_SARADC_SARADC_XPD_WAIT : R/W; bitpos: [7:0]; default: 8;
  *  saradc_xpd_wait
  */
@@ -174,7 +174,7 @@ extern "C" {
 /** APB_SARADC_SAR1_STATUS_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR1_STATUS_REG (DR_REG_APB_BASE + 0x10)
+#define APB_SARADC_SAR1_STATUS_REG (DR_REG_APB_SARADC_BASE + 0x10)
 /** APB_SARADC_SARADC_SAR1_STATUS : RO; bitpos: [31:0]; default: 536870912;
  *  saradc1 status about data and channel
  */
@@ -186,7 +186,7 @@ extern "C" {
 /** APB_SARADC_SAR2_STATUS_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR2_STATUS_REG (DR_REG_APB_BASE + 0x14)
+#define APB_SARADC_SAR2_STATUS_REG (DR_REG_APB_SARADC_BASE + 0x14)
 /** APB_SARADC_SARADC_SAR2_STATUS : RO; bitpos: [31:0]; default: 536870912;
  *  saradc2 status about data and channel
  */
@@ -198,7 +198,7 @@ extern "C" {
 /** APB_SARADC_SAR_PATT_TAB1_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR_PATT_TAB1_REG (DR_REG_APB_BASE + 0x18)
+#define APB_SARADC_SAR_PATT_TAB1_REG (DR_REG_APB_SARADC_BASE + 0x18)
 /** APB_SARADC_SARADC_SAR_PATT_TAB1 : R/W; bitpos: [23:0]; default: 16777215;
  *  item 0 ~ 3 for pattern table 1 (each item one byte)
  */
@@ -210,7 +210,7 @@ extern "C" {
 /** APB_SARADC_SAR_PATT_TAB2_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR_PATT_TAB2_REG (DR_REG_APB_BASE + 0x1c)
+#define APB_SARADC_SAR_PATT_TAB2_REG (DR_REG_APB_SARADC_BASE + 0x1c)
 /** APB_SARADC_SARADC_SAR_PATT_TAB2 : R/W; bitpos: [23:0]; default: 16777215;
  *  Item 4 ~ 7 for pattern table 1 (each item one byte)
  */
@@ -222,7 +222,7 @@ extern "C" {
 /** APB_SARADC_ONETIME_SAMPLE_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_ONETIME_SAMPLE_REG (DR_REG_APB_BASE + 0x20)
+#define APB_SARADC_ONETIME_SAMPLE_REG (DR_REG_APB_SARADC_BASE + 0x20)
 /** APB_SARADC_SARADC_ONETIME_ATTEN : R/W; bitpos: [24:23]; default: 0;
  *  configure onetime atten
  */
@@ -262,7 +262,7 @@ extern "C" {
 /** APB_SARADC_ARB_CTRL_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_ARB_CTRL_REG (DR_REG_APB_BASE + 0x24)
+#define APB_SARADC_ARB_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x24)
 /** APB_SARADC_ADC_ARB_APB_FORCE : R/W; bitpos: [2]; default: 0;
  *  adc2 arbiter force to enableapb controller
  */
@@ -323,7 +323,7 @@ extern "C" {
 /** APB_SARADC_FILTER_CTRL0_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_FILTER_CTRL0_REG (DR_REG_APB_BASE + 0x28)
+#define APB_SARADC_FILTER_CTRL0_REG (DR_REG_APB_SARADC_BASE + 0x28)
 /** APB_SARADC_APB_SARADC_FILTER_CHANNEL1 : R/W; bitpos: [21:18]; default: 13;
  *  configure filter1 to adc channel
  */
@@ -349,7 +349,7 @@ extern "C" {
 /** APB_SARADC_SAR1DATA_STATUS_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR1DATA_STATUS_REG (DR_REG_APB_BASE + 0x2c)
+#define APB_SARADC_SAR1DATA_STATUS_REG (DR_REG_APB_SARADC_BASE + 0x2c)
 /** APB_SARADC_APB_SARADC1_DATA : RO; bitpos: [16:0]; default: 0;
  *  saradc1 data
  */
@@ -361,7 +361,7 @@ extern "C" {
 /** APB_SARADC_SAR2DATA_STATUS_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_SAR2DATA_STATUS_REG (DR_REG_APB_BASE + 0x30)
+#define APB_SARADC_SAR2DATA_STATUS_REG (DR_REG_APB_SARADC_BASE + 0x30)
 /** APB_SARADC_APB_SARADC2_DATA : RO; bitpos: [16:0]; default: 0;
  *  saradc2 data
  */
@@ -373,7 +373,7 @@ extern "C" {
 /** APB_SARADC_THRES0_CTRL_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_THRES0_CTRL_REG (DR_REG_APB_BASE + 0x34)
+#define APB_SARADC_THRES0_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x34)
 /** APB_SARADC_APB_SARADC_THRES0_CHANNEL : R/W; bitpos: [3:0]; default: 13;
  *  configure thres0 to adc channel
  */
@@ -399,7 +399,7 @@ extern "C" {
 /** APB_SARADC_THRES1_CTRL_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_THRES1_CTRL_REG (DR_REG_APB_BASE + 0x38)
+#define APB_SARADC_THRES1_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x38)
 /** APB_SARADC_APB_SARADC_THRES1_CHANNEL : R/W; bitpos: [3:0]; default: 13;
  *  configure thres1 to adc channel
  */
@@ -425,7 +425,7 @@ extern "C" {
 /** APB_SARADC_THRES_CTRL_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_THRES_CTRL_REG (DR_REG_APB_BASE + 0x3c)
+#define APB_SARADC_THRES_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x3c)
 /** APB_SARADC_APB_SARADC_THRES_ALL_EN : R/W; bitpos: [27]; default: 0;
  *  enable thres to all channel
  */
@@ -451,7 +451,7 @@ extern "C" {
 /** APB_SARADC_INT_ENA_REG register
  *  digital saradc int register
  */
-#define APB_SARADC_INT_ENA_REG (DR_REG_APB_BASE + 0x40)
+#define APB_SARADC_INT_ENA_REG (DR_REG_APB_SARADC_BASE + 0x40)
 /** APB_SARADC_APB_SARADC_TSENS_INT_ENA : R/W; bitpos: [25]; default: 0;
  *  tsens low  interrupt enable
  */
@@ -505,7 +505,7 @@ extern "C" {
 /** APB_SARADC_INT_RAW_REG register
  *  digital saradc int register
  */
-#define APB_SARADC_INT_RAW_REG (DR_REG_APB_BASE + 0x44)
+#define APB_SARADC_INT_RAW_REG (DR_REG_APB_SARADC_BASE + 0x44)
 /** APB_SARADC_APB_SARADC_TSENS_INT_RAW : R/WTC/SS; bitpos: [25]; default: 0;
  *  saradc tsens  interrupt raw
  */
@@ -559,7 +559,7 @@ extern "C" {
 /** APB_SARADC_INT_ST_REG register
  *  digital saradc int register
  */
-#define APB_SARADC_INT_ST_REG (DR_REG_APB_BASE + 0x48)
+#define APB_SARADC_INT_ST_REG (DR_REG_APB_SARADC_BASE + 0x48)
 /** APB_SARADC_APB_SARADC_TSENS_INT_ST : RO; bitpos: [25]; default: 0;
  *  saradc tsens  interrupt state
  */
@@ -613,7 +613,7 @@ extern "C" {
 /** APB_SARADC_INT_CLR_REG register
  *  digital saradc int register
  */
-#define APB_SARADC_INT_CLR_REG (DR_REG_APB_BASE + 0x4c)
+#define APB_SARADC_INT_CLR_REG (DR_REG_APB_SARADC_BASE + 0x4c)
 /** APB_SARADC_APB_SARADC_TSENS_INT_CLR : WT; bitpos: [25]; default: 0;
  *  saradc tsens  interrupt clear
  */
@@ -667,7 +667,7 @@ extern "C" {
 /** APB_SARADC_DMA_CONF_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_DMA_CONF_REG (DR_REG_APB_BASE + 0x50)
+#define APB_SARADC_DMA_CONF_REG (DR_REG_APB_SARADC_BASE + 0x50)
 /** APB_SARADC_APB_ADC_EOF_NUM : R/W; bitpos: [15:0]; default: 255;
  *  the dma_in_suc_eof gen when sample cnt = spi_eof_num
  */
@@ -693,7 +693,7 @@ extern "C" {
 /** APB_SARADC_CLKM_CONF_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_CLKM_CONF_REG (DR_REG_APB_BASE + 0x54)
+#define APB_SARADC_CLKM_CONF_REG (DR_REG_APB_SARADC_BASE + 0x54)
 /** APB_SARADC_CLKM_DIV_NUM : R/W; bitpos: [7:0]; default: 4;
  *  Integral I2S clock divider value
  */
@@ -733,7 +733,7 @@ extern "C" {
 /** APB_SARADC_APB_TSENS_CTRL_REG register
  *  digital tsens configure register
  */
-#define APB_SARADC_APB_TSENS_CTRL_REG (DR_REG_APB_BASE + 0x58)
+#define APB_SARADC_APB_TSENS_CTRL_REG (DR_REG_APB_SARADC_BASE + 0x58)
 /** APB_SARADC_TSENS_OUT : RO; bitpos: [7:0]; default: 128;
  *  temperature sensor data out
  */
@@ -766,7 +766,7 @@ extern "C" {
 /** APB_SARADC_TSENS_CTRL2_REG register
  *  digital tsens configure register
  */
-#define APB_SARADC_TSENS_CTRL2_REG (DR_REG_APB_BASE + 0x5c)
+#define APB_SARADC_TSENS_CTRL2_REG (DR_REG_APB_SARADC_BASE + 0x5c)
 /** APB_SARADC_TSENS_XPD_WAIT : R/W; bitpos: [11:0]; default: 2;
  *  the time that power up tsens need wait
  */
@@ -799,7 +799,7 @@ extern "C" {
 /** APB_SARADC_CALI_REG register
  *  digital saradc configure register
  */
-#define APB_SARADC_CALI_REG (DR_REG_APB_BASE + 0x60)
+#define APB_SARADC_CALI_REG (DR_REG_APB_SARADC_BASE + 0x60)
 /** APB_SARADC_APB_SARADC_CALI_CFG : R/W; bitpos: [16:0]; default: 32768;
  *  saradc cali factor
  */
@@ -811,7 +811,7 @@ extern "C" {
 /** APB_TSENS_WAKE_REG register
  *  digital tsens configure register
  */
-#define APB_TSENS_WAKE_REG (DR_REG_APB_BASE + 0x64)
+#define APB_TSENS_WAKE_REG (DR_REG_APB_SARADC_BASE + 0x64)
 /** APB_SARADC_WAKEUP_TH_LOW : R/W; bitpos: [7:0]; default: 0;
  *  reg_wakeup_th_low
  */
@@ -851,7 +851,7 @@ extern "C" {
 /** APB_TSENS_SAMPLE_REG register
  *  digital tsens configure register
  */
-#define APB_TSENS_SAMPLE_REG (DR_REG_APB_BASE + 0x68)
+#define APB_TSENS_SAMPLE_REG (DR_REG_APB_SARADC_BASE + 0x68)
 /** APB_SARADC_TSENS_SAMPLE_RATE : R/W; bitpos: [15:0]; default: 20;
  *  HW sample rate
  */
@@ -870,7 +870,7 @@ extern "C" {
 /** APB_SARADC_CTRL_DATE_REG register
  *  version
  */
-#define APB_SARADC_CTRL_DATE_REG (DR_REG_APB_BASE + 0x3fc)
+#define APB_SARADC_CTRL_DATE_REG (DR_REG_APB_SARADC_BASE + 0x3fc)
 /** APB_SARADC_DATE : R/W; bitpos: [31:0]; default: 35676736;
  *  version
  */

+ 5 - 2
components/soc/esp32h2/include/soc/soc_caps.h

@@ -109,6 +109,9 @@
 /*!< Calibration */
 #define SOC_ADC_CALIBRATION_V1_SUPPORTED        (0) /*!< support HW offset calibration version 1*/
 
+/*!< Interrupt */
+#define SOC_ADC_TEMPERATURE_SHARE_INTR          (1)
+
 // ESP32H2-TODO: Copy from esp32c6, need check
 /*-------------------------- APB BACKUP DMA CAPS -------------------------------*/
 #define SOC_APB_BACKUP_DMA              (0)
@@ -453,10 +456,10 @@
 
 #define SOC_CLK_LP_FAST_SUPPORT_LP_PLL           (1)      /*!< Support LP_PLL clock as the LP_FAST clock source */
 
-// TODO: IDF-6229 (Copy from esp32c6, need check)
 /*-------------------------- Temperature Sensor CAPS -------------------------------------*/
 #define SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC                (1)
-#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL                (1)
+#define SOC_TEMPERATURE_SENSOR_SUPPORT_XTAL                   (1)
+#define SOC_TEMPERATURE_SENSOR_INTR_SUPPORT                   (1)
 
 /*---------------------------------- Bluetooth CAPS ----------------------------------*/
 #define SOC_BLE_SUPPORTED               (1)    /*!< Support Bluetooth Low Energy hardware */

+ 60 - 6
docs/en/api-reference/peripherals/temp_sensor.rst

@@ -29,11 +29,15 @@ Due to restrictions of hardware, the sensor has predefined measurement ranges wi
 Functional Overview
 -------------------
 
--  `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to get a temperature sensor handle and how to recycle the resources when temperature sensor finishes working.
--  `Enable and Disable Temperature Sensor <#enable-and-disable-temperature-sensor>`__ - covers how to enable and disable the temperature sensor.
--  `Get Temperature Value <#get-temperature-value>`__ - covers how to get the real-time temperature value.
--  `Power Management <#power-management>`__ - covers how temperature sensor is affected when changing power mode (i.e. light sleep).
--  `Thread Safety <#thread-safety>`__ - covers how to make the driver to be thread safe.
+.. list::
+
+    -  `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to get a temperature sensor handle and how to recycle the resources when temperature sensor finishes working.
+    -  `Enable and Disable Temperature Sensor <#enable-and-disable-temperature-sensor>`__ - covers how to enable and disable the temperature sensor.
+    -  `Get Temperature Value <#get-temperature-value>`__ - covers how to get the real-time temperature value.
+    :SOC_TEMPERATURE_SENSOR_INTR_SUPPORT: - `Temperature Threshold Interrupt <#install-temperature-threshold-callback>`__ - describes how to register a temperature threshold callback.
+    -  `Power Management <#power-management>`__ - covers how temperature sensor is affected when changing power mode (i.e. light sleep).
+    :SOC_TEMPERATURE_SENSOR_INTR_SUPPORT: - `IRAM Safe <#iram-safe>`__ - describes tips on how to make the temperature sensor interrupt work better along with a disabled cache.
+    -  `Thread Safety <#thread-safety>`__ - covers how to make the driver to be thread safe.
 
 Resource Allocation
 ^^^^^^^^^^^^^^^^^^^
@@ -89,11 +93,58 @@ After the temperature sensor is enabled by :cpp:func:`temperature_sensor_enable`
     // Disable the temperature sensor if it's not needed and save the power
     ESP_ERROR_CHECK(temperature_sensor_disable(temp_handle));
 
+.. only:: SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
+    Install Temperature Threshold Callback
+    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+    {IDF_TARGET_NAME} supports automatically triggering to monitor the temperature value continuously. When temperature value reaches a given threshold, an interrupt will happen. Thus users can install their own interrupt callback functions to do what they want. (e.g. alarm, restart, etc.). Following information indicates how to prepare a threshold callback.
+
+    -  :cpp:member:`temperature_sensor_event_callbacks_t::on_threshold`. As this function is called within the ISR context, you must ensure that the function does not attempt to block (e.g., by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function, etc.). The function prototype is declared in :cpp:type:`temperature_thres_cb_t`.
+
+    You can save your own context to :cpp:func:`temperature_sensor_register_callbacks` as well, via the parameter ``user_arg``. The user data will be directly passed to the callback function.
+
+    .. code:: c
+
+        IRAM_ATTR static bool temp_sensor_monitor_cbs(temperature_sensor_handle_t tsens, const temperature_sensor_threshold_event_data_t *edata, void *user_data)
+        {
+            ESP_DRAM_LOGI("tsens", "Temperature value is higher or lower than threshold, value is %d\n...\n\n", edata->celsius_value);
+            return false;
+        }
+
+        // Callback configurations
+        temperature_sensor_abs_threshold_config_t threshold_cfg = {
+            .high_threshold = 50,
+            .low_threshold = -10,
+        };
+        // Set absolute value monitor threshold.
+        temperature_sensor_set_absolute_threshold(temp_sensor, &threshold_cfg);
+        // Register interrupt callback
+        temperature_sensor_event_callbacks_t cbs = {
+            .on_threshold = temp_sensor_monitor_cbs,
+        };
+        // Install temperature callback.
+        temperature_sensor_register_callbacks(temp_sensor, &cbs, NULL);
+
 Power Management
 ^^^^^^^^^^^^^^^^
 
 When power management is enabled (i.e. ``CONFIG_PM_ENABLE`` is on), temperature sensor will still keep working because it uses XTAL clock (on ESP32-C3) or RTC clock (on ESP32-S2/S3).
 
+.. only:: SOC_TEMPERATURE_SENSOR_INTR_SUPPORT
+
+    IRAM Safe
+    ^^^^^^^^^
+
+    By default, the temperature sensor interrupt will be deferred when the Cache is disabled for reasons like writing/erasing Flash. Thus the event callback functions will not get executed in time, which is not expected in a real-time application.
+
+    There's a Kconfig option :ref:`CONFIG_TEMP_SENSOR_ISR_IRAM_SAFE` that will:
+
+    1. Enable the interrupt being serviced even when cache is disabled.
+    2. Place all functions that used by the ISR into IRAM.
+
+    This will allow the interrupt to run while the cache is disabled but will come at the cost of increased IRAM consumption.
+
 Thread Safety
 ^^^^^^^^^^^^^
 
@@ -112,7 +163,10 @@ Unexpected Behaviors
 Application Example
 -------------------
 
-* Temperature sensor reading example: :example:`peripherals/temp_sensor`.
+.. list::
+
+    * Temperature sensor reading example: :example:`peripherals/temperature_sensor/temp_sensor`.
+    :SOC_TEMPERATURE_SENSOR_INTR_SUPPORT: * Temperature sensor value monitor example: :example:`peripherals/temperature_sensor/temp_sensor`.
 
 API Reference
 ----------------------------------

+ 5 - 1
examples/peripherals/.build-test-rules.yml

@@ -210,10 +210,14 @@ examples/peripherals/spi_slave_hd/segment_mode/seg_slave:
       temporary: true
       reason: not supported
 
-examples/peripherals/temp_sensor:
+examples/peripherals/temperature_sensor/temp_sensor:
   disable:
     - if: SOC_TEMP_SENSOR_SUPPORTED != 1
 
+examples/peripherals/temperature_sensor/temp_sensor_monitor:
+  disable:
+    - if: SOC_TEMPERATURE_SENSOR_INTR_SUPPORT != 1
+
 examples/peripherals/timer_group:
   disable:
     - if: SOC_GPTIMER_SUPPORTED != 1

+ 0 - 0
examples/peripherals/temp_sensor/CMakeLists.txt → examples/peripherals/temperature_sensor/temp_sensor/CMakeLists.txt


+ 0 - 0
examples/peripherals/temp_sensor/README.md → examples/peripherals/temperature_sensor/temp_sensor/README.md


+ 0 - 0
examples/peripherals/temp_sensor/main/CMakeLists.txt → examples/peripherals/temperature_sensor/temp_sensor/main/CMakeLists.txt


+ 0 - 0
examples/peripherals/temp_sensor/main/temp_sensor_main.c → examples/peripherals/temperature_sensor/temp_sensor/main/temp_sensor_main.c


+ 0 - 0
examples/peripherals/temp_sensor/pytest_temp_sensor_example.py → examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py


+ 6 - 0
examples/peripherals/temperature_sensor/temp_sensor_monitor/CMakeLists.txt

@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(temp_sensor_monitor)

+ 67 - 0
examples/peripherals/temperature_sensor/temp_sensor_monitor/README.md

@@ -0,0 +1,67 @@
+| Supported Targets | ESP32-C6 | ESP32-H2 |
+| ----------------- | -------- | -------- |
+
+# Temperature Sensor Interrupt Example
+
+(Refer to README.md file in path peripherals/temperature_sensor/temp_sensor to get some basic information about temperature sensor)
+
+The ESP32-C6/H2 supports automatically monitor the temperature value continuously and gives interrupt when reaches specific value, which means user can register their callback functions when interrupt happens.
+
+The interrupt happens in two ways.
+
+* Absolute mode, which means when temperature reaches to a specific value, then interrupt triggered.
+* Delta mode, which means the change between two consecutive samplings is larger/smaller than the settings.
+
+## How to use example
+
+Before project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
+
+If you want to see clearer what interrupt did. You may need a heat gun or other heaters, when temperature reaches specific value you can see interrupt message.
+
+### Hardware Required
+
+* A development board with a supported target listed in the above table.
+* A USB cable for power supply and programming
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+```
+I (312) example: Install temperature sensor, expected temp ranger range: 10~50 ℃
+I (322) temperature_sensor: Range [-10°C ~ 80°C], error < 1°C
+I (332) example: Enable temperature sensor
+I (332) example: Read temperature
+I (342) example: Temperature value 20.27 ℃
+I (1342) example: Temperature value 20.71 ℃
+I (2342) example: Temperature value 22.46 ℃
+I (3342) example: Temperature value 26.85 ℃
+I (4342) example: Temperature value 29.92 ℃
+I (5342) example: Temperature value 33.87 ℃
+I (6342) example: Temperature value 41.76 ℃
+I (7342) example: Temperature value 48.78 ℃
+I tsens: Temperature value is higher or lower than threshold, value is 50
+...
+
+
+I tsens: Temperature value is higher or lower than threshold, value is 50
+...
+
+
+I tsens: Temperature value is higher or lower than threshold, value is 51
+...
+
+
+```
+
+## Troubleshooting
+
+For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

+ 2 - 0
examples/peripherals/temperature_sensor/temp_sensor_monitor/main/CMakeLists.txt

@@ -0,0 +1,2 @@
+idf_component_register(SRCS "temp_sensor_monitor_main.c"
+                       INCLUDE_DIRS ".")

+ 53 - 0
examples/peripherals/temperature_sensor/temp_sensor_monitor/main/temp_sensor_monitor_main.c

@@ -0,0 +1,53 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_log.h"
+#include "driver/temperature_sensor.h"
+#include "esp_attr.h"
+
+static const char *TAG = "example";
+
+IRAM_ATTR static bool temp_sensor_monitor_cbs(temperature_sensor_handle_t tsens, const temperature_sensor_threshold_event_data_t *edata, void *user_data)
+{
+    ESP_DRAM_LOGI("tsens", "Temperature value is higher or lower than threshold, value is %d\n...\n\n", edata->celsius_value);
+    return false;
+}
+
+void app_main(void)
+{
+    ESP_LOGI(TAG, "Install temperature sensor, expected temp ranger range: 10~50 ℃");
+    temperature_sensor_handle_t temp_sensor = NULL;
+    temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 50);
+    ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor_config, &temp_sensor));
+
+
+    temperature_sensor_event_callbacks_t cbs = {
+        .on_threshold = temp_sensor_monitor_cbs,
+    };
+
+    temperature_sensor_abs_threshold_config_t threshold_cfg = {
+        .high_threshold = 50,
+        .low_threshold = -10,
+    };
+    ESP_ERROR_CHECK(temperature_sensor_set_absolute_threshold(temp_sensor, &threshold_cfg));
+
+    ESP_ERROR_CHECK(temperature_sensor_register_callbacks(temp_sensor, &cbs, NULL));
+
+    ESP_LOGI(TAG, "Enable temperature sensor");
+    ESP_ERROR_CHECK(temperature_sensor_enable(temp_sensor));
+
+    ESP_LOGI(TAG, "Read temperature");
+    int cnt = 20;
+    float tsens_value;
+
+    while (cnt--) {
+        ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_sensor, &tsens_value));
+        ESP_LOGI(TAG, "Temperature value %.02f ℃", tsens_value);
+        vTaskDelay(pdMS_TO_TICKS(1000));
+    }
+}

+ 19 - 0
examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py

@@ -0,0 +1,19 @@
+# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded.dut import Dut
+
+
+@pytest.mark.esp32c6
+@pytest.mark.esp32h2
+@pytest.mark.generic
+def test_temp_sensor_monitor_example(dut: Dut) -> None:
+    dut.expect_exact('Install temperature sensor')
+    dut.expect_exact('Enable temperature sensor')
+    dut.expect_exact('Read temperature')
+    temp_value = dut.expect(r'Temperature value (\d+\.\d+) .*', timeout=5)
+    # Because the example test only run in the normal temperature environment. So this assert range is meaningful
+    assert 0 < float(temp_value.group(1).decode('utf8')) < 50
+    temp_value = dut.expect(r'Temperature value (\d+\.\d+) .*', timeout=5)
+    assert 0 < float(temp_value.group(1).decode('utf8')) < 50