diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 72a12ef862b..e458b509221 100644 --- a/components/driver/Kconfig +++ b/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" diff --git a/components/driver/temperature_sensor/include/driver/temperature_sensor.h b/components/driver/temperature_sensor/include/driver/temperature_sensor.h index 743a2fdc1a3..ef05f3f0685 100644 --- a/components/driver/temperature_sensor/include/driver/temperature_sensor.h +++ b/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 +#include #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 diff --git a/components/driver/temperature_sensor/temperature_sensor.c b/components/driver/temperature_sensor/temperature_sensor.c index 44a199f0359..d7f170ce620 100644 --- a/components/driver/temperature_sensor/temperature_sensor.c +++ b/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 diff --git a/components/driver/temperature_sensor/temperature_sensor_private.h b/components/driver/temperature_sensor/temperature_sensor_private.h new file mode 100644 index 00000000000..e4e97cf14af --- /dev/null +++ b/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 +#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 diff --git a/components/driver/test_apps/temperature_sensor/main/test_temperature_sensor.c b/components/driver/test_apps/temperature_sensor/main/test_temperature_sensor.c index 94d39698453..8bcffd0e3d6 100644 --- a/components/driver/test_apps/temperature_sensor/main/test_temperature_sensor.c +++ b/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 diff --git a/components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py b/components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py index de1fe3c844b..3a97ba4ca34 100644 --- a/components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py +++ b/components/driver/test_apps/temperature_sensor/pytest_temperature_sensor.py @@ -16,6 +16,14 @@ '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() diff --git a/components/driver/test_apps/temperature_sensor/sdkconfig.ci.iram_safe b/components/driver/test_apps/temperature_sensor/sdkconfig.ci.iram_safe new file mode 100644 index 00000000000..57952c81a93 --- /dev/null +++ b/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 diff --git a/components/hal/esp32c6/include/hal/temperature_sensor_ll.h b/components/hal/esp32c6/include/hal/temperature_sensor_ll.h index b245b2faca4..a0198f1a7f6 100644 --- a/components/hal/esp32c6/include/hal/temperature_sensor_ll.h +++ b/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; } /** diff --git a/components/hal/esp32h2/include/hal/temperature_sensor_ll.h b/components/hal/esp32h2/include/hal/temperature_sensor_ll.h index 67188bca54a..38f68871023 100644 --- a/components/hal/esp32h2/include/hal/temperature_sensor_ll.h +++ b/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; } /** diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 8459b1fd3f0..7efd0ddf40a 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 81c84d64c31..4359860b90f 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/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 */ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 7d14a7b24b6..bb615232b18 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/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 diff --git a/components/soc/esp32h2/include/soc/apb_saradc_reg.h b/components/soc/esp32h2/include/soc/apb_saradc_reg.h index 2a55f48436d..933120275b3 100644 --- a/components/soc/esp32h2/include/soc/apb_saradc_reg.h +++ b/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 */ diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 8bb35fa96b5..a7963d16ef6 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/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 */ diff --git a/docs/en/api-reference/peripherals/temp_sensor.rst b/docs/en/api-reference/peripherals/temp_sensor.rst index 9fbf66e8c59..43a2d3d5102 100644 --- a/docs/en/api-reference/peripherals/temp_sensor.rst +++ b/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 ---------------------------------- diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index e50f99c9932..2bd8c93cb49 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/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 diff --git a/examples/peripherals/temp_sensor/CMakeLists.txt b/examples/peripherals/temperature_sensor/temp_sensor/CMakeLists.txt similarity index 100% rename from examples/peripherals/temp_sensor/CMakeLists.txt rename to examples/peripherals/temperature_sensor/temp_sensor/CMakeLists.txt diff --git a/examples/peripherals/temp_sensor/README.md b/examples/peripherals/temperature_sensor/temp_sensor/README.md similarity index 100% rename from examples/peripherals/temp_sensor/README.md rename to examples/peripherals/temperature_sensor/temp_sensor/README.md diff --git a/examples/peripherals/temp_sensor/main/CMakeLists.txt b/examples/peripherals/temperature_sensor/temp_sensor/main/CMakeLists.txt similarity index 100% rename from examples/peripherals/temp_sensor/main/CMakeLists.txt rename to examples/peripherals/temperature_sensor/temp_sensor/main/CMakeLists.txt diff --git a/examples/peripherals/temp_sensor/main/temp_sensor_main.c b/examples/peripherals/temperature_sensor/temp_sensor/main/temp_sensor_main.c similarity index 100% rename from examples/peripherals/temp_sensor/main/temp_sensor_main.c rename to examples/peripherals/temperature_sensor/temp_sensor/main/temp_sensor_main.c diff --git a/examples/peripherals/temp_sensor/pytest_temp_sensor_example.py b/examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py similarity index 100% rename from examples/peripherals/temp_sensor/pytest_temp_sensor_example.py rename to examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/CMakeLists.txt b/examples/peripherals/temperature_sensor/temp_sensor_monitor/CMakeLists.txt new file mode 100644 index 00000000000..44aa59aaff4 --- /dev/null +++ b/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) diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/README.md b/examples/peripherals/temperature_sensor/temp_sensor_monitor/README.md new file mode 100644 index 00000000000..865ec13c24f --- /dev/null +++ b/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 `. + +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. diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/main/CMakeLists.txt b/examples/peripherals/temperature_sensor/temp_sensor_monitor/main/CMakeLists.txt new file mode 100644 index 00000000000..d0a8e291057 --- /dev/null +++ b/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 ".") diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/main/temp_sensor_monitor_main.c b/examples/peripherals/temperature_sensor/temp_sensor_monitor/main/temp_sensor_monitor_main.c new file mode 100644 index 00000000000..34e5dfbf2e2 --- /dev/null +++ b/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)); + } +} diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py b/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py new file mode 100644 index 00000000000..7ac06afa0e4 --- /dev/null +++ b/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