diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index 109a1a692..619a631dc 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -23,7 +23,7 @@ #include "soc/timer_periph.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" -#include "hal/timer_ll.h" +#include "hal/wdt_hal.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/libc_stubs.h" #elif CONFIG_IDF_TARGET_ESP32S2 @@ -133,14 +133,16 @@ void esp_gcov_dump(void) esp_cpu_stall(other_core); #endif while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) { - // to avoid complains that task watchdog got triggered for other tasks - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_set_protect(&TIMERG0, true); - // to avoid reboot on INT_WDT - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_feed(&TIMERG1); - timer_ll_wdt_set_protect(&TIMERG1, true); + wdt_hal_context_t twdt = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_context_t iwdt = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + //Feed the Task Watchdog (TG0) to prevent it from timing out + wdt_hal_write_protect_disable(&twdt); + wdt_hal_feed(&twdt); + wdt_hal_write_protect_enable(&twdt); + //Likewise, feed the Interrupt Watchdog (TG1) to prevent a reboot + wdt_hal_write_protect_disable(&iwdt); + wdt_hal_feed(&iwdt); + wdt_hal_write_protect_enable(&iwdt); } esp_dbg_stub_gcov_dump_do(); diff --git a/components/bootloader/subproject/main/ld/esp32/bootloader.ld b/components/bootloader/subproject/main/ld/esp32/bootloader.ld index b6c5f8987..853c8c9b5 100644 --- a/components/bootloader/subproject/main/ld/esp32/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32/bootloader.ld @@ -52,7 +52,7 @@ SECTIONS *libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*) *libmicro-ecc.a:*.*(.literal .text .literal.* .text.*) *libspi_flash.a:*.*(.literal .text .literal.* .text.*) - *libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*) + *libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*) *libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*) *libefuse.a:*.*(.literal .text .literal.* .text.*) *(.fini.literal) diff --git a/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld b/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld index 1cced512c..79b256881 100644 --- a/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld @@ -38,7 +38,7 @@ SECTIONS *libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*) *libmicro-ecc.a:*.*(.literal .text .literal.* .text.*) *libspi_flash.a:*.*(.literal .text .literal.* .text.*) - *libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*) + *libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*) *libefuse.a:*.*(.literal .text .literal.* .text.*) *(.fini.literal) *(.fini) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 9cf02b02b..7b250bb3b 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -22,11 +22,9 @@ #include "bootloader_clock.h" #include "bootloader_common.h" #include "esp_flash_encrypt.h" -#include "hal/timer_ll.h" #include "soc/cpu.h" #include "soc/rtc.h" -#include "soc/rtc_wdt.h" - +#include "hal/wdt_hal.h" static const char *TAG = "boot"; @@ -61,21 +59,34 @@ esp_err_t bootloader_check_bootloader_validity(void) void bootloader_config_wdt(void) { + /* + * At this point, the flashboot protection of RWDT and MWDT0 will have been + * automatically enabled. We can disable flashboot protection as it's not + * needed anymore. If configured to do so, we also initialize the RWDT to + * protect the remainder of the bootloader process. + */ + //Disable RWDT flashboot protection. + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, false); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + #ifdef CONFIG_BOOTLOADER_WDT_ENABLE + //Initialize and start RWDT to protect the for bootloader if configured to do so ESP_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS); - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC); - rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS); - rtc_wdt_enable(); - rtc_wdt_protect_on(); -#else /* disable watch dog */ - rtc_wdt_disable(); + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_flashboot_en(&TIMERG0, false); + + //Disable MWDT0 flashboot protection. But only after we've enabled the RWDT first so that there's not gap in WDT protection. + wdt_hal_context_t wdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt_ctx); + wdt_hal_set_flashboot_en(&wdt_ctx, false); + wdt_hal_write_protect_enable(&wdt_ctx); } void bootloader_enable_random(void) diff --git a/components/bootloader_support/src/esp32/flash_encrypt.c b/components/bootloader_support/src/esp32/flash_encrypt.c index 2d900fe00..322414adc 100644 --- a/components/bootloader_support/src/esp32/flash_encrypt.c +++ b/components/bootloader_support/src/esp32/flash_encrypt.c @@ -22,7 +22,7 @@ #include "esp_efuse.h" #include "esp_log.h" #include "esp32/rom/secure_boot.h" -#include "soc/rtc_wdt.h" +#include "hal/wdt_hal.h" #include "esp32/rom/cache.h" #include "esp32/rom/spi_flash.h" /* TODO: Remove this */ @@ -345,8 +345,11 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length) return ESP_FAIL; } + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) { - rtc_wdt_feed(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); uint32_t sec_start = i + src_addr; err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false); if (err != ESP_OK) { diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index 51d524d32..7798db0cc 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -20,15 +20,13 @@ else() "dport_access.c" "esp_himem.c" "hw_random.c" - "int_wdt.c" "intr_alloc.c" "pm_esp32.c" "pm_trace.c" "sleep_modes.c" "spiram.c" "spiram_psram.c" - "system_api_esp32.c" - "task_wdt.c") + "system_api_esp32.c") set(include_dirs "include") diff --git a/components/esp32/clk.c b/components/esp32/clk.c index 9ac244a9e..304861a10 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -27,9 +27,9 @@ #include "soc/soc.h" #include "soc/dport_reg.h" #include "soc/rtc.h" -#include "soc/rtc_wdt.h" #include "soc/rtc_periph.h" #include "soc/i2s_periph.h" +#include "hal/wdt_hal.h" #include "driver/periph_ctrl.h" #include "xtensa/core-macros.h" #include "bootloader_clock.h" @@ -98,10 +98,13 @@ void esp_clk_init(void) // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). // This prevents excessive delay before resetting in case the supply voltage is drawdown. // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). - rtc_wdt_protect_off(); - rtc_wdt_feed(); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1600); - rtc_wdt_protect_on(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif #if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) @@ -116,10 +119,11 @@ void esp_clk_init(void) #ifdef CONFIG_BOOTLOADER_WDT_ENABLE // After changing a frequency WDT timeout needs to be set for new frequency. - rtc_wdt_protect_off(); - rtc_wdt_feed(); - rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS); - rtc_wdt_protect_on(); + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif rtc_cpu_freq_config_t old_config, new_config; diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 801b37107..69070e1b5 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -28,9 +28,10 @@ #include "soc/dport_reg.h" #include "soc/gpio_periph.h" #include "soc/timer_periph.h" -#include "soc/rtc_wdt.h" #include "soc/efuse_periph.h" +#include "hal/wdt_hal.h" + #include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" @@ -146,7 +147,10 @@ void IRAM_ATTR call_start_cpu0(void) #endif ) { #ifndef CONFIG_BOOTLOADER_WDT_ENABLE - rtc_wdt_disable(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif } @@ -553,7 +557,10 @@ static void main_task(void* args) // Now that the application is about to start, disable boot watchdog #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - rtc_wdt_disable(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif #ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c deleted file mode 100644 index 9b20dbb21..000000000 --- a/components/esp32/int_wdt.c +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - - -#include "sdkconfig.h" -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include -#include "esp_err.h" -#include "esp_intr_alloc.h" -#include "esp_attr.h" -#include "esp_freertos_hooks.h" -#include "soc/timer_periph.h" -#include "driver/timer.h" -#include "driver/periph_ctrl.h" -#include "esp_int_wdt.h" -#include "hal/timer_ll.h" - -#if CONFIG_ESP_INT_WDT - -#define TG1_WDT_TICK_US 500 -#define WDT_INT_NUM 24 - - -//Take care: the tick hook can also be called before esp_int_wdt_init() is called. -#if CONFIG_ESP_INT_WDT_CHECK_CPU1 -//Not static; the ISR assembly checks this. -bool int_wdt_app_cpu_ticked=false; - -static void IRAM_ATTR tick_hook(void) { - if (xPortGetCoreID()!=0) { - int_wdt_app_cpu_ticked=true; - } else { - //Only feed wdt if app cpu also ticked. - if (int_wdt_app_cpu_ticked) { - timer_ll_wdt_set_protect(&TIMERG1, false); - //Set timeout before interrupt - timer_ll_wdt_set_timeout(&TIMERG1, 0, - CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); - //Set timeout before reset - timer_ll_wdt_set_timeout(&TIMERG1, 1, - 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); - timer_ll_wdt_feed(&TIMERG1); - timer_ll_wdt_set_protect(&TIMERG1, true); - int_wdt_app_cpu_ticked=false; - } - } -} -#else -static void IRAM_ATTR tick_hook(void) { - if (xPortGetCoreID()!=0) return; - timer_ll_wdt_set_protect(&TIMERG1, false); - //Set timeout before interrupt - timer_ll_wdt_set_timeout(&TIMERG1, 0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); - //Set timeout before reset - timer_ll_wdt_set_timeout(&TIMERG1, 1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US); - timer_ll_wdt_feed(&TIMERG1); - timer_ll_wdt_set_protect(&TIMERG1, true); -} -#endif - - -void esp_int_wdt_init(void) { - periph_module_enable(PERIPH_TIMG1_MODULE); - //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets - //it to their actual value. - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_init(&TIMERG1); - timer_ll_wdt_set_tick(&TIMERG1, TG1_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG1_WDT_TICK_US - //1st stage timeout: interrupt - timer_ll_wdt_set_timeout_behavior(&TIMERG1, 0, TIMER_WDT_INT); - timer_ll_wdt_set_timeout(&TIMERG1, 0, 5*1000*1000/TG1_WDT_TICK_US); - //2nd stage timeout: reset system - timer_ll_wdt_set_timeout_behavior(&TIMERG1, 1, TIMER_WDT_RESET_SYSTEM); - timer_ll_wdt_set_timeout(&TIMERG1, 1, 5*1000*1000/TG1_WDT_TICK_US); - timer_ll_wdt_set_enable(&TIMERG1, true); - timer_ll_wdt_feed(&TIMERG1); - timer_ll_wdt_set_protect(&TIMERG1, true); - - timer_ll_wdt_clear_intr_status(&TIMERG1); - timer_ll_wdt_enable_intr(&TIMERG1); -} - -void esp_int_wdt_cpu_init(void) -{ - esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID()); - ESP_INTR_DISABLE(WDT_INT_NUM); - intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); - //We do not register a handler for the interrupt because it is interrupt level 4 which - //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for - //this interrupt. - ESP_INTR_ENABLE(WDT_INT_NUM); -} - - - -#endif diff --git a/components/esp32/sleep_modes.c b/components/esp32/sleep_modes.c index 175a217b4..e986199fe 100644 --- a/components/esp32/sleep_modes.c +++ b/components/esp32/sleep_modes.c @@ -29,8 +29,8 @@ #include "soc/rtc.h" #include "soc/spi_periph.h" #include "soc/dport_reg.h" -#include "soc/rtc_wdt.h" #include "soc/soc_memory_layout.h" +#include "hal/wdt_hal.h" #include "driver/rtc_io.h" #include "driver/uart.h" #include "freertos/FreeRTOS.h" @@ -315,16 +315,15 @@ esp_err_t esp_light_sleep_start(void) rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails - bool wdt_was_enabled = rtc_wdt_is_on(); // If WDT was enabled in the user code, then do not change it here. + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + bool wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here. if (!wdt_was_enabled) { - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1000); - rtc_wdt_enable(); - rtc_wdt_protect_on(); + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); } // Enter sleep, then wait for flash to be ready on wakeup @@ -354,7 +353,9 @@ esp_err_t esp_light_sleep_start(void) esp_timer_private_unlock(); DPORT_STALL_OTHER_CPU_END(); if (!wdt_was_enabled) { - rtc_wdt_disable(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); } portEXIT_CRITICAL(&light_sleep_lock); return err; diff --git a/components/esp32/system_api_esp32.c b/components/esp32/system_api_esp32.c index 504da1dda..b93c222ce 100644 --- a/components/esp32/system_api_esp32.c +++ b/components/esp32/system_api_esp32.c @@ -30,8 +30,7 @@ #include "soc/timer_periph.h" #include "soc/cpu.h" #include "soc/rtc.h" -#include "soc/rtc_wdt.h" -#include "hal/timer_ll.h" +#include "hal/wdt_hal.h" #include "freertos/xtensa_api.h" #if CONFIG_IDF_TARGET_ESP32 @@ -51,14 +50,14 @@ void IRAM_ATTR esp_restart_noos(void) xt_ints_off(0xFFFFFFFF); // Enable RTC watchdog for 1 second - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC); - rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1000); - rtc_wdt_flashboot_mode_enable(); + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); // Reset and stall the other CPU. // CPU must be reset before stalling, in case it was running a s32c1i @@ -72,14 +71,17 @@ void IRAM_ATTR esp_restart_noos(void) // Other core is now stalled, can access DPORT registers directly esp_dport_access_int_abort(); + //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context // Disable TG0/TG1 watchdogs - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_set_enable(&TIMERG0, false); - timer_ll_wdt_set_protect(&TIMERG0, true); + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_set_enable(&TIMERG1, false); - timer_ll_wdt_set_protect(&TIMERG1, true); + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); // Flush any data left in UART FIFOs uart_tx_wait_idle(0); diff --git a/components/esp32s2/CMakeLists.txt b/components/esp32s2/CMakeLists.txt index f1cf31f4b..0401ca4e5 100644 --- a/components/esp32s2/CMakeLists.txt +++ b/components/esp32s2/CMakeLists.txt @@ -17,15 +17,13 @@ else() "crosscore_int.c" "dport_access.c" "hw_random.c" - "int_wdt.c" "intr_alloc.c" "pm_esp32s2.c" "pm_trace.c" "sleep_modes.c" "spiram.c" "spiram_psram.c" - "system_api_esp32s2.c" - "task_wdt.c") + "system_api_esp32s2.c") set(include_dirs "include") diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 270d69b35..f698eb29d 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -28,9 +28,9 @@ #include "soc/dport_access.h" #include "soc/soc.h" #include "soc/rtc.h" -#include "soc/rtc_wdt.h" #include "soc/rtc_periph.h" #include "soc/i2s_reg.h" +#include "hal/wdt_hal.h" #include "driver/periph_ctrl.h" #include "xtensa/core-macros.h" #include "bootloader_clock.h" @@ -85,10 +85,13 @@ void esp_clk_init(void) // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). // This prevents excessive delay before resetting in case the supply voltage is drawdown. // (If frequency is changed from 90kHz to 32kHz then WDT timeout will increased to 1.6sec * 90/32 = 4.5 sec). - rtc_wdt_protect_off(); - rtc_wdt_feed(); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1600); - rtc_wdt_protect_on(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif #if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS) @@ -103,10 +106,11 @@ void esp_clk_init(void) #ifdef CONFIG_BOOTLOADER_WDT_ENABLE // After changing a frequency WDT timeout needs to be set for new frequency. - rtc_wdt_protect_off(); - rtc_wdt_feed(); - rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS); - rtc_wdt_protect_on(); + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif rtc_cpu_freq_config_t old_config, new_config; diff --git a/components/esp32s2/cpu_start.c b/components/esp32s2/cpu_start.c index 262c8e5ff..09f5fc00b 100644 --- a/components/esp32s2/cpu_start.c +++ b/components/esp32s2/cpu_start.c @@ -34,7 +34,7 @@ #include "soc/rtc_cntl_reg.h" #include "soc/timer_group_reg.h" #include "soc/periph_defs.h" -#include "soc/rtc_wdt.h" +#include "hal/wdt_hal.h" #include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" @@ -122,7 +122,10 @@ void IRAM_ATTR call_start_cpu0(void) // from panic handler we can be reset by RWDT or TG0WDT if (rst_reas == RTCWDT_SYS_RESET || rst_reas == TG0WDT_SYS_RESET) { #ifndef CONFIG_BOOTLOADER_WDT_ENABLE - rtc_wdt_disable(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif } @@ -397,7 +400,10 @@ static void main_task(void *args) // Now that the application is about to start, disable boot watchdog #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - rtc_wdt_disable(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif #ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE diff --git a/components/esp32s2/int_wdt.c b/components/esp32s2/int_wdt.c deleted file mode 100644 index bd46f3702..000000000 --- a/components/esp32s2/int_wdt.c +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - - -#include "sdkconfig.h" -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include -#include "esp_err.h" -#include "esp_intr_alloc.h" -#include "esp_attr.h" -#include "esp_freertos_hooks.h" -#include "soc/timer_group_struct.h" -#include "soc/timer_group_reg.h" -#include "driver/timer.h" -#include "driver/periph_ctrl.h" -#include "esp_int_wdt.h" - -#if CONFIG_ESP_INT_WDT - - -#define WDT_INT_NUM 24 - - -//Take care: the tick hook can also be called before esp_int_wdt_init() is called. - -static void IRAM_ATTR tick_hook(void) -{ - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; -} - -void esp_int_wdt_init(void) -{ - periph_module_enable(PERIPH_TIMG1_MODULE); - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG1.wdt_config0.level_int_en=1; - TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS - //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets - //it to their actual value. - TIMERG1.wdt_config2=10000; - TIMERG1.wdt_config3=10000; - TIMERG1.wdt_config0.en=1; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; - TIMERG1.int_clr.wdt=1; - timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M); -} - -void esp_int_wdt_cpu_init(void) -{ - esp_register_freertos_tick_hook_for_cpu(tick_hook, 0); - ESP_INTR_DISABLE(WDT_INT_NUM); - intr_matrix_set(0, ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); - //We do not register a handler for the interrupt because it is interrupt level 4 which - //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for - //this interrupt. - ESP_INTR_ENABLE(WDT_INT_NUM); -} - - - -#endif // CONFIG_ESP_INT_WDT diff --git a/components/esp32s2/sleep_modes.c b/components/esp32s2/sleep_modes.c index 17d831f06..b209646b4 100644 --- a/components/esp32s2/sleep_modes.c +++ b/components/esp32s2/sleep_modes.c @@ -31,9 +31,9 @@ #include "soc/spi_periph.h" #include "soc/dport_reg.h" #include "soc/extmem_reg.h" -#include "soc/rtc_wdt.h" #include "soc/soc_memory_layout.h" #include "soc/uart_caps.h" +#include "hal/wdt_hal.h" #include "driver/rtc_io.h" #include "driver/uart.h" #include "freertos/FreeRTOS.h" @@ -301,16 +301,15 @@ esp_err_t esp_light_sleep_start(void) rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config(); // Safety net: enable WDT in case exit from light sleep fails - bool wdt_was_enabled = rtc_wdt_is_on(); // If WDT was enabled in the user code, then do not change it here. + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + bool wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here. if (!wdt_was_enabled) { - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1000); - rtc_wdt_enable(); - rtc_wdt_protect_on(); + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); } // Enter sleep, then wait for flash to be ready on wakeup @@ -340,7 +339,9 @@ esp_err_t esp_light_sleep_start(void) esp_timer_private_unlock(); DPORT_STALL_OTHER_CPU_END(); if (!wdt_was_enabled) { - rtc_wdt_disable(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); } portEXIT_CRITICAL(&light_sleep_lock); return err; diff --git a/components/esp32s2/system_api_esp32s2.c b/components/esp32s2/system_api_esp32s2.c index e4c17b978..332aa52f6 100644 --- a/components/esp32s2/system_api_esp32s2.c +++ b/components/esp32s2/system_api_esp32s2.c @@ -25,11 +25,10 @@ #include "soc/gpio_reg.h" #include "soc/rtc_cntl_reg.h" #include "soc/timer_group_reg.h" -#include "soc/timer_group_struct.h" #include "soc/cpu.h" #include "soc/rtc.h" -#include "soc/rtc_wdt.h" #include "soc/syscon_reg.h" +#include "hal/wdt_hal.h" #include "freertos/xtensa_api.h" /* "inner" restart function for after RTOS, interrupts & anything else on this @@ -42,27 +41,33 @@ void IRAM_ATTR esp_restart_noos(void) xt_ints_off(0xFFFFFFFF); // Enable RTC watchdog for 1 second - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC); - rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns); - rtc_wdt_set_time(RTC_WDT_STAGE0, 1000); - rtc_wdt_flashboot_mode_enable(); + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); // Reset and stall the other CPU. // CPU must be reset before stalling, in case it was running a s32c1i // instruction. This would cause memory pool to be locked by arbiter // to the stalled CPU, preventing current CPU from accessing this pool. const uint32_t core_id = xPortGetCoreID(); + + //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context // Disable TG0/TG1 watchdogs - TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_config0.en = 0; - TIMERG0.wdt_wprotect = 0; - TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config0.en = 0; - TIMERG1.wdt_wprotect = 0; + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); // Flush any data left in UART FIFOs uart_tx_wait_idle(0); diff --git a/components/esp32s2/task_wdt.c b/components/esp32s2/task_wdt.c deleted file mode 100644 index de5dd1b86..000000000 --- a/components/esp32s2/task_wdt.c +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include -#include "esp_err.h" -#include "esp_intr_alloc.h" -#include "esp_attr.h" -#include "esp_freertos_hooks.h" -#include "soc/timer_periph.h" -#include "esp_log.h" -#include "driver/timer.h" -#include "driver/periph_ctrl.h" -#include "esp_task_wdt.h" -#include "esp_private/system_internal.h" - -static const char *TAG = "task_wdt"; - -//Assertion macro where, if 'cond' is false, will exit the critical section and return 'ret' -#define ASSERT_EXIT_CRIT_RETURN(cond, ret) ({ \ - if(!(cond)){ \ - portEXIT_CRITICAL(&twdt_spinlock); \ - return ret; \ - } \ -}) - -//Empty define used in ASSERT_EXIT_CRIT_RETURN macro when returning in void -#define VOID_RETURN - -//Structure used for each subscribed task -typedef struct twdt_task_t twdt_task_t; -struct twdt_task_t { - TaskHandle_t task_handle; - bool has_reset; - twdt_task_t *next; -}; - -//Structure used to hold run time configuration of the TWDT -typedef struct twdt_config_t twdt_config_t; -struct twdt_config_t { - twdt_task_t *list; //Linked list of subscribed tasks - uint32_t timeout; //Timeout period of TWDT - bool panic; //Flag to trigger panic when TWDT times out - intr_handle_t intr_handle; -}; - -static twdt_config_t *twdt_config = NULL; -static portMUX_TYPE twdt_spinlock = portMUX_INITIALIZER_UNLOCKED; - -/* - * Idle hook callback for Idle Tasks to reset the TWDT. This callback will only - * be registered to the Idle Hook of a particular core when the corresponding - * Idle Task subscribes to the TWDT. - */ -static bool idle_hook_cb(void) -{ - esp_task_wdt_reset(); - return true; -} - -/* - * Internal function that looks for the target task in the TWDT task list. - * Returns the list item if found and returns null if not found. Also checks if - * all the other tasks have reset. Should be called within critical. - */ -static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) -{ - twdt_task_t *target = NULL; - *all_reset = true; - for(twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ - if(task->task_handle == handle){ - target = task; //Get pointer to target task list member - }else{ - if(task->has_reset == false){ //If a task has yet to reset - *all_reset = false; - } - } - } - return target; -} - -/* - * Resets the hardware timer and has_reset flags of each task on the list. - * Called within critical - */ -static void reset_hw_timer(void) -{ - //All tasks have reset; time to reset the hardware timer. - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; - //Clear all has_reset flags in list - for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ - task->has_reset=false; - } -} - -/* - * This function is called by task_wdt_isr function (ISR for when TWDT times out). - * It can be redefined in user code to handle twdt events. - * Note: It has the same limitations as the interrupt function. - * Do not use ESP_LOGI functions inside. - */ -void __attribute__((weak)) esp_task_wdt_isr_user_handler(void) -{ - -} - -/* - * ISR for when TWDT times out. Checks for which tasks have not reset. Also - * triggers panic if configured to do so - */ -static void task_wdt_isr(void *arg) -{ - portENTER_CRITICAL_ISR(&twdt_spinlock); - twdt_task_t *twdttask; - const char *cpu; - //Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset) - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; - //Acknowledge interrupt - TIMERG0.int_clr.wdt=1; - //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty - //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case, - //something bad already happened and reporting this is considered more important - //than the badness caused by a spinlock here. - - //Return immediately if no tasks have been added to task list - ASSERT_EXIT_CRIT_RETURN((twdt_config->list != NULL), VOID_RETURN); - - //Watchdog got triggered because at least one task did not reset in time. - ESP_EARLY_LOGE(TAG, "Task watchdog got triggered. The following tasks did not reset the watchdog in time:"); - for (twdttask=twdt_config->list; twdttask!=NULL; twdttask=twdttask->next) { - if (!twdttask->has_reset) { - cpu=xTaskGetAffinity(twdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1"); - if (xTaskGetAffinity(twdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1"); - ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetTaskName(twdttask->task_handle), cpu); - } - } - ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:")); - for (int x=0; xpanic){ //Trigger Panic if configured to do so - ESP_EARLY_LOGE(TAG, "Aborting."); - portEXIT_CRITICAL_ISR(&twdt_spinlock); - esp_reset_reason_set_hint(ESP_RST_TASK_WDT); - abort(); - } - - portEXIT_CRITICAL_ISR(&twdt_spinlock); -} - -/* - * Initializes the TWDT by allocating memory for the config data - * structure, obtaining the idle task handles/registering idle hooks, and - * setting the hardware timer registers. If reconfiguring, it will just modify - * wdt_config and reset the hardware timer. - */ -esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) -{ - portENTER_CRITICAL(&twdt_spinlock); - if(twdt_config == NULL){ //TWDT not initialized yet - //Allocate memory for wdt_config - twdt_config = calloc(1, sizeof(twdt_config_t)); - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NO_MEM); - - twdt_config->list = NULL; - twdt_config->timeout = timeout; - twdt_config->panic = panic; - - //Register Interrupt and ISR - ESP_ERROR_CHECK(esp_intr_alloc(ETS_TG0_WDT_LEVEL_INTR_SOURCE, 0, task_wdt_isr, NULL, &twdt_config->intr_handle)); - - //Configure hardware timer - periph_module_enable(PERIPH_TIMG0_MODULE); - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS - TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS - TIMERG0.wdt_config0.level_int_en=1; - TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt - TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system - TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; //Enable write protection - - }else{ //twdt_config previously initialized - //Reconfigure task wdt - twdt_config->panic = panic; - twdt_config->timeout = timeout; - - //Reconfigure hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt - TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset - TIMERG0.wdt_config0.en=1; //Renable timer - TIMERG0.wdt_feed=1; //Reset timer - TIMERG0.wdt_wprotect=0; //Enable write protection - } - portEXIT_CRITICAL(&twdt_spinlock); - return ESP_OK; -} - -esp_err_t esp_task_wdt_deinit(void) -{ - portENTER_CRITICAL(&twdt_spinlock); - //TWDT must already be initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND); - //Task list must be empty - ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE); - - //Disable hardware timer - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection - TIMERG0.wdt_config0.en=0; //Disable timer - TIMERG0.wdt_wprotect=0; //Enable write protection - - ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt - free(twdt_config); //Free twdt_config - twdt_config = NULL; - portEXIT_CRITICAL(&twdt_spinlock); - return ESP_OK; -} - -esp_err_t esp_task_wdt_add(TaskHandle_t handle) -{ - portENTER_CRITICAL(&twdt_spinlock); - //TWDT must already be initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); - - twdt_task_t *target_task; - bool all_reset; - if (handle == NULL){ //Get handle of current task if none is provided - handle = xTaskGetCurrentTaskHandle(); - } - //Check if tasks exists in task list, and if all other tasks have reset - target_task = find_task_in_twdt_list(handle, &all_reset); - //task cannot be already subscribed - ASSERT_EXIT_CRIT_RETURN((target_task == NULL), ESP_ERR_INVALID_ARG); - - //Add target task to TWDT task list - target_task = calloc(1,sizeof(twdt_task_t)); - ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NO_MEM); - target_task->task_handle = handle; - target_task->has_reset = true; - target_task->next = NULL; - if (twdt_config->list == NULL) { //Adding to empty list - twdt_config->list = target_task; - } else { //Adding to tail of list - twdt_task_t *task; - for (task = twdt_config->list; task->next != NULL; task = task->next){ - ; //point task to current tail of TWDT task list - } - task->next = target_task; - } - - //If idle task, register the idle hook callback to appropriate core - for(int i = 0; i < portNUM_PROCESSORS; i++){ - if(handle == xTaskGetIdleTaskHandleForCPU(i)){ - ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_hook_cb, i)); - break; - } - } - - if(all_reset){ //Reset hardware timer if all other tasks in list have reset in - reset_hw_timer(); - } - - portEXIT_CRITICAL(&twdt_spinlock); //Nested critical if Legacy - return ESP_OK; -} - -esp_err_t esp_task_wdt_reset(void) -{ - portENTER_CRITICAL(&twdt_spinlock); - //TWDT must already be initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); - - TaskHandle_t handle = xTaskGetCurrentTaskHandle(); - twdt_task_t *target_task; - bool all_reset; - - //Check if task exists in task list, and if all other tasks have reset - target_task = find_task_in_twdt_list(handle, &all_reset); - //Return error if trying to reset task that is not on the task list - ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_NOT_FOUND); - - target_task->has_reset = true; //Reset the task if it's on the task list - if(all_reset){ //Reset if all other tasks in list have reset in - reset_hw_timer(); - } - - portEXIT_CRITICAL(&twdt_spinlock); - return ESP_OK; -} - -esp_err_t esp_task_wdt_delete(TaskHandle_t handle) -{ - if(handle == NULL){ - handle = xTaskGetCurrentTaskHandle(); - } - portENTER_CRITICAL(&twdt_spinlock); - //Return error if twdt has not been initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_NOT_FOUND); - - twdt_task_t *target_task; - bool all_reset; - target_task = find_task_in_twdt_list(handle, &all_reset); - //Task doesn't exist on list. Return error - ASSERT_EXIT_CRIT_RETURN((target_task != NULL), ESP_ERR_INVALID_ARG); - - if(target_task == twdt_config->list){ //target_task is head of list. Delete - twdt_config->list = target_task->next; - free(target_task); - }else{ //target_task not head of list. Delete - twdt_task_t *prev; - for (prev = twdt_config->list; prev->next != target_task; prev = prev->next){ - ; //point prev to task preceding target_task - } - prev->next = target_task->next; - free(target_task); - } - - //If idle task, deregister idle hook callback form appropriate core - for(int i = 0; i < portNUM_PROCESSORS; i++){ - if(handle == xTaskGetIdleTaskHandleForCPU(i)){ - esp_deregister_freertos_idle_hook_for_cpu(idle_hook_cb, i); - break; - } - } - - if(all_reset){ //Reset hardware timer if all remaining tasks have reset - reset_hw_timer(); - } - - portEXIT_CRITICAL(&twdt_spinlock); - return ESP_OK; -} - -esp_err_t esp_task_wdt_status(TaskHandle_t handle) -{ - if(handle == NULL){ - handle = xTaskGetCurrentTaskHandle(); - } - - portENTER_CRITICAL(&twdt_spinlock); - //Return if TWDT is not initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), ESP_ERR_INVALID_STATE); - - twdt_task_t *task; - for(task = twdt_config->list; task!=NULL; task=task->next){ - //Return ESP_OK if task is found - ASSERT_EXIT_CRIT_RETURN((task->task_handle != handle), ESP_OK); - } - - //Task could not be found - portEXIT_CRITICAL(&twdt_spinlock); - return ESP_ERR_NOT_FOUND; -} - -void esp_task_wdt_feed(void) -{ - portENTER_CRITICAL(&twdt_spinlock); - //Return immediately if TWDT has not been initialized - ASSERT_EXIT_CRIT_RETURN((twdt_config != NULL), VOID_RETURN); - - //Check if task is on list - TaskHandle_t handle = xTaskGetCurrentTaskHandle(); - bool all_reset; - twdt_task_t *target_task = find_task_in_twdt_list(handle, &all_reset); - - //reset the task if it's on the list, then return - if(target_task != NULL){ - target_task->has_reset = true; - if(all_reset){ - reset_hw_timer(); //Reset hardware timer if all other tasks have reset - } - portEXIT_CRITICAL(&twdt_spinlock); - return; - } - - //Add task if it's has not on list - target_task = calloc(1, sizeof(twdt_task_t)); - ASSERT_EXIT_CRIT_RETURN((target_task != NULL), VOID_RETURN); //If calloc failed - target_task->task_handle = handle; - target_task->has_reset = true; - target_task->next = NULL; - - if (twdt_config->list == NULL) { //Adding to empty list - twdt_config->list = target_task; - } else { //Adding to tail of list - twdt_task_t *task; - for (task = twdt_config->list; task->next != NULL; task = task->next){ - ; //point task to current tail of wdt task list - } - task->next = target_task; - } - - portEXIT_CRITICAL(&twdt_spinlock); -} - - diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index a5f37842d..c0d16dc73 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -13,7 +13,9 @@ else() "src/freertos_hooks.c" "src/mac_addr.c" "src/pm_locks.c" - "src/stack_check.c") + "src/stack_check.c" + "src/task_wdt.c" + "src/int_wdt.c") # IPC framework is not applicable if freertos unicore config is selected if(NOT CONFIG_FREERTOS_UNICORE) diff --git a/components/esp_common/include/esp_private/system_internal.h b/components/esp_common/include/esp_private/system_internal.h index 8ecef8da9..9b60b2ffe 100644 --- a/components/esp_common/include/esp_private/system_internal.h +++ b/components/esp_common/include/esp_private/system_internal.h @@ -20,7 +20,10 @@ extern "C" { #include "esp_system.h" -#define TG0_WDT_TICK_US 500 +#define MWDT0_TICK_PRESCALER 40000 +#define MWDT0_TICKS_PER_US 500 +#define MWDT1_TICK_PRESCALER 40000 +#define MWDT1_TICKS_PER_US 500 /** * @brief Internal function to restart PRO and APP CPUs. diff --git a/components/esp_common/src/int_wdt.c b/components/esp_common/src/int_wdt.c new file mode 100644 index 000000000..2e205192f --- /dev/null +++ b/components/esp_common/src/int_wdt.c @@ -0,0 +1,113 @@ +// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "esp_err.h" +#include "esp_intr_alloc.h" +#include "esp_attr.h" +#include "esp_freertos_hooks.h" +#include "soc/timer_periph.h" +#include "driver/timer.h" +#include "driver/periph_ctrl.h" +#include "esp_int_wdt.h" +#include "esp_private/system_internal.h" +#include "hal/timer_types.h" +#include "hal/wdt_hal.h" + +#if CONFIG_ESP_INT_WDT + +#define WDT_INT_NUM 24 + +#define IWDT_INSTANCE WDT_MWDT1 +#define IWDT_PRESCALER MWDT1_TICK_PRESCALER //Tick period of 500us if WDT source clock is 80MHz +#define IWDT_TICKS_PER_US MWDT1_TICKS_PER_US +#define IWDT_INITIAL_TIMEOUT_S 5 +static wdt_hal_context_t iwdt_context; + +//Take care: the tick hook can also be called before esp_int_wdt_init() is called. +#if CONFIG_ESP_INT_WDT_CHECK_CPU1 +//Not static; the ISR assembly checks this. +bool int_wdt_app_cpu_ticked = false; + +static void IRAM_ATTR tick_hook(void) { + if (xPortGetCoreID()!=0) { + int_wdt_app_cpu_ticked = true; + } else { + //Only feed wdt if app cpu also ticked. + if (int_wdt_app_cpu_ticked) { + //Todo: Check if there's a way to avoid reconfiguring the stages on each feed. + wdt_hal_write_protect_disable(&iwdt_context); + //Reconfigure stage timeouts + wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt + wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset + wdt_hal_feed(&iwdt_context); + wdt_hal_write_protect_enable(&iwdt_context); + int_wdt_app_cpu_ticked = false; + } + } +} +#else +static void IRAM_ATTR tick_hook(void) { +#if CONFIG_IDF_TARGET_ESP32 + if (xPortGetCoreID()!=0) { + return; + } +#endif + //Todo: Check if there's a way to avoid reconfiguring the stages on each feed. + wdt_hal_write_protect_disable(&iwdt_context); + //Reconfigure stage timeouts + wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt + wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset + wdt_hal_feed(&iwdt_context); + wdt_hal_write_protect_enable(&iwdt_context); +} +#endif + + +void esp_int_wdt_init(void) { + periph_module_enable(PERIPH_TIMG1_MODULE); + //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets + //it to their actual value. + wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true); + wdt_hal_write_protect_disable(&iwdt_context); + //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets + //it to their actual value. + //1st stage timeout: interrupt + wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); + //2nd stage timeout: reset system + wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); + //Enable WDT + wdt_hal_enable(&iwdt_context); + wdt_hal_write_protect_enable(&iwdt_context); +} + +void esp_int_wdt_cpu_init(void) +{ + esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID()); + ESP_INTR_DISABLE(WDT_INT_NUM); + intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); + //We do not register a handler for the interrupt because it is interrupt level 4 which + //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for + //this interrupt. + ESP_INTR_ENABLE(WDT_INT_NUM); +} + +#endif diff --git a/components/esp32/task_wdt.c b/components/esp_common/src/task_wdt.c similarity index 85% rename from components/esp32/task_wdt.c rename to components/esp_common/src/task_wdt.c index c12926ec3..7b4b9a817 100644 --- a/components/esp32/task_wdt.c +++ b/components/esp_common/src/task_wdt.c @@ -33,7 +33,8 @@ #include "driver/periph_ctrl.h" #include "esp_task_wdt.h" #include "esp_private/system_internal.h" -#include "hal/timer_ll.h" +#include "hal/timer_types.h" +#include "hal/wdt_hal.h" static const char *TAG = "task_wdt"; @@ -49,6 +50,12 @@ static const char *TAG = "task_wdt"; //Empty define used in ASSERT_EXIT_CRIT_RETURN macro when returning in void #define VOID_RETURN +//HAL related variables and constants +#define TWDT_INSTANCE WDT_MWDT0 +#define TWDT_TICKS_PER_US MWDT0_TICKS_PER_US +#define TWDT_PRESCALER MWDT0_TICK_PRESCALER //Tick period of 500us if WDT source clock is 80MHz +static wdt_hal_context_t twdt_context; + //Structure used for each subscribed task typedef struct twdt_task_t twdt_task_t; struct twdt_task_t { @@ -108,9 +115,9 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset) static void reset_hw_timer(void) { //All tasks have reset; time to reset the hardware timer. - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_set_protect(&TIMERG0, true); + wdt_hal_write_protect_disable(&twdt_context); + wdt_hal_feed(&twdt_context); + wdt_hal_write_protect_enable(&twdt_context); //Clear all has_reset flags in list for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){ task->has_reset=false; @@ -138,11 +145,10 @@ static void task_wdt_isr(void *arg) twdt_task_t *twdttask; const char *cpu; //Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset) - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_set_protect(&TIMERG0, true); - //Acknowledge interrupt - timer_ll_wdt_clear_intr_status(&TIMERG0); + wdt_hal_write_protect_disable(&twdt_context); + wdt_hal_handle_intr(&twdt_context); //Feeds WDT and clears acknowledges interrupt + wdt_hal_write_protect_enable(&twdt_context); + //We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case, //something bad already happened and reporting this is considered more important @@ -199,33 +205,27 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic) //Configure hardware timer periph_module_enable(PERIPH_TIMG0_MODULE); - timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection - timer_ll_wdt_init(&TIMERG0); - timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US - //1st stage timeout: interrupt - timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT); - timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); - //2nd stage timeout: reset system - timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM); - timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); - timer_ll_wdt_set_enable(&TIMERG0, true); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection + wdt_hal_init(&twdt_context, TWDT_INSTANCE, TWDT_PRESCALER, true); + wdt_hal_write_protect_disable(&twdt_context); + //Configure 1st stage timeout and behavior + wdt_hal_config_stage(&twdt_context, WDT_STAGE0, twdt_config->timeout * 1000000 / TWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); + //Configure 2nd stage timeout and behavior + wdt_hal_config_stage(&twdt_context, WDT_STAGE1, 2*twdt_config->timeout * 1000000 / TWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); + //Enable the WDT + wdt_hal_enable(&twdt_context); + wdt_hal_write_protect_enable(&twdt_context); } else { //twdt_config previously initialized //Reconfigure task wdt twdt_config->panic = panic; twdt_config->timeout = timeout; //Reconfigure hardware timer - timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection - timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer - //Set timeout before interrupt - timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); - //Set timeout before reset - timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US); - timer_ll_wdt_set_enable(&TIMERG0, true); //Renable timer - timer_ll_wdt_feed(&TIMERG0); //Reset timer - timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection + wdt_hal_write_protect_disable(&twdt_context); + wdt_hal_disable(&twdt_context); + wdt_hal_config_stage(&twdt_context, WDT_STAGE0, twdt_config->timeout*1000*1000/TWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); + wdt_hal_config_stage(&twdt_context, WDT_STAGE1, 2*twdt_config->timeout*1000*1000/TWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_enable(&twdt_context); + wdt_hal_write_protect_enable(&twdt_context); } portEXIT_CRITICAL(&twdt_spinlock); return ESP_OK; @@ -240,9 +240,7 @@ esp_err_t esp_task_wdt_deinit(void) ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE); //Disable hardware timer - timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection - timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer - timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection + wdt_hal_deinit(&twdt_context); ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt free(twdt_config); //Free twdt_config diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index 655da68e9..628a15389 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -30,10 +30,12 @@ #include "esp_core_dump.h" -#include "soc/rtc_wdt.h" #include "soc/cpu.h" +#include "soc/rtc.h" #include "hal/timer_hal.h" #include "hal/cpu_hal.h" +#include "hal/wdt_types.h" +#include "hal/wdt_hal.h" #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT #include @@ -54,6 +56,10 @@ bool g_panic_abort = false; static char *s_panic_abort_details = NULL; +static wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; +static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; +static wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 : &UART1 }; @@ -112,21 +118,18 @@ void panic_print_dec(int d) */ static void reconfigure_all_wdts(void) { - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_init(&TIMERG0); - timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US - //1st stage timeout: reset system - timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM); - //1 second before reset - timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US); - timer_ll_wdt_set_enable(&TIMERG0, true); - timer_ll_wdt_set_protect(&TIMERG0, true); + //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context + //Reconfigure TWDT (Timer Group 0) + wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT0_TICK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_config_stage(&wdt0_context, 0, 1000*1000/MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset + wdt_hal_enable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); - //Disable wdt 1 - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_set_enable(&TIMERG1, false); - timer_ll_wdt_set_protect(&TIMERG1, true); + //Disable IWDT (Timer Group 1) + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); } /* @@ -134,13 +137,16 @@ static void reconfigure_all_wdts(void) */ static inline void disable_all_wdts(void) { - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_set_enable(&TIMERG0, false); - timer_ll_wdt_set_protect(&TIMERG0, true); + //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context + //Task WDT is the Main Watchdog Timer of Timer Group 0 + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_set_enable(&TIMERG1, false); - timer_ll_wdt_set_protect(&TIMERG1, true); + //Interupt WDT is the Main Watchdog Timer of Timer Group 1 + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); } static void print_abort_details(const void *f) @@ -224,17 +230,16 @@ void esp_panic_handler(panic_info_t *info) } // start panic WDT to restart system if we hang in this handler - if (!rtc_wdt_is_on()) { - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); + if (!wdt_hal_is_enabled(&rtc_wdt_ctx)) { + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(7000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data. // @ 115200 UART speed it will take more than 6 sec to print them out. - rtc_wdt_set_time(RTC_WDT_STAGE0, 7000); - rtc_wdt_enable(); - rtc_wdt_protect_on(); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + } //Feed the watchdogs, so they will give us time to print out debug info @@ -264,7 +269,9 @@ void esp_panic_handler(panic_info_t *info) #if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB disable_all_wdts(); - rtc_wdt_disable(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); panic_print_str("Entering gdb stub now.\r\n"); esp_gdbstub_panic_handler((XtExcFrame*) info->frame); #else @@ -285,7 +292,9 @@ void esp_panic_handler(panic_info_t *info) reconfigure_all_wdts(); } #endif /* CONFIG_ESP32_ENABLE_COREDUMP */ - rtc_wdt_disable(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index 7fe4f8bcd..13cc09d3c 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -30,7 +30,9 @@ #include "hal/soc_hal.h" #include "hal/cpu_hal.h" -#include "hal/timer_hal.h" +#include "hal/wdt_types.h" +#include "hal/wdt_hal.h" + #include "sdkconfig.h" @@ -50,6 +52,8 @@ extern void esp_panic_handler(panic_info_t*); +static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + static XtExcFrame* xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL}; /* @@ -480,7 +484,9 @@ static void panic_handler(XtExcFrame *frame, bool pseudo_excause) if (esp_cpu_in_ocd_debug_mode()) { if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) { - timer_ll_wdt_clear_intr_status(&TIMERG1); + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_handle_intr(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); } } diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index eb67fa974..46f3b7ff4 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -29,6 +29,7 @@ idf_component_register(SRCS "src/cpu_util.c" "src/hal/spi_flash_hal_iram.c" "src/hal/mpu_hal.c" "src/hal/soc_hal.c" + "src/hal/wdt_hal_iram.c" "src/compare_set.c" PRIV_REQUIRES ${target} LDFRAGMENTS linker.lf) diff --git a/components/soc/include/hal/timer_types.h b/components/soc/include/hal/timer_types.h index 09e0fcc24..c7bf64831 100644 --- a/components/soc/include/hal/timer_types.h +++ b/components/soc/include/hal/timer_types.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include "soc/timer_group_caps.h" +#include "esp_attr.h" /** * @brief Selects a Timer-Group out of 2 available groups @@ -70,17 +71,6 @@ typedef enum { } timer_intr_t; FLAG_ATTR(timer_intr_t) -/** - * @brief Behavior of the watchdog if a stage times out. - */ -//this is compatible with the value of esp32. -typedef enum { - TIMER_WDT_OFF = 0, /*!< The stage is turned off*/ - TIMER_WDT_INT = 1, /*!< The stage will trigger an interrupt*/ - TIMER_WDT_RESET_CPU = 2, /*!< The stage will reset the CPU*/ - TIMER_WDT_RESET_SYSTEM = 3, /*!< The stage will reset the whole system*/ -} timer_wdt_behavior_t; - /** * @brief Decides whether to enable alarm mode */ diff --git a/components/soc/include/hal/wdt_hal.h b/components/soc/include/hal/wdt_hal.h new file mode 100644 index 000000000..0d0f650d5 --- /dev/null +++ b/components/soc/include/hal/wdt_hal.h @@ -0,0 +1,180 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "soc/timer_group_caps.h" +#include "hal/wdt_types.h" +#include "hal/mwdt_ll.h" +#include "hal/rwdt_ll.h" + +/** + * Context that should be maintained by both the driver and the HAL + */ +typedef struct { + wdt_inst_t inst; /**< Which WDT instance this HAL context is using (i.e. MWDT0, MWDT1, RWDT)*/ + union { + timg_dev_t *mwdt_dev; /**< Starting address of the MWDT */ + rtc_cntl_dev_t *rwdt_dev; /**< Starting address of the RWDT*/ + }; +} wdt_hal_context_t; + +/* ---------------------------- Init and Config ----------------------------- */ + +/** + * @brief Initialize one of the WDTs associated HAL context + * + * This function initializes one of the WDTs (MWDT0, MWDT1, or RWDT) hardware by + * doing the following: + * - Disables the WDT and all of its stages + * - Sets some registers with default values + * - Sets the WDTs source clock prescaler (not applicable to RWDT) + * - Optionally enables the level interrupt + * + * The HAL context is initialized by storing the type (i.e. MWDT or RWDT) of + * this WDT instance, and a pointer to the associated registers. + * + * @param hal Context of HAL layer + * @param wdt_inst Which WDT instance to initialize (MWDT0, MWDT1, or RWDT) + * @param prescaler MWDT source clock prescaler. Unused for RWDT + * @param enable_intr True to enable level interrupt. False to disable + * + * @note Although the WDTs on the ESP32 have an edge interrupt, this HAL does + * not utilize it and will always disables it. + * @note RWDT does not have a prescaler. Its tick rate is equal to the + * frequency of its source clock (RTC slow clock). + */ +void wdt_hal_init(wdt_hal_context_t *hal, wdt_inst_t wdt_inst, uint32_t prescaler, bool enable_intr); + +/** + * @brief Deinitialize a WDT and its HAL context + * + * This function deinitializes a WDT by feeding then disabling it. The WDT's + * interrupt is also cleared and disabled. The HAL context is cleared. + * + * @param hal Context of HAL layer + */ +void wdt_hal_deinit(wdt_hal_context_t *hal); + +/** + * @brief Configure a particular stage of a WDT + * + * @param hal Context of HAL layer + * @param stage Stage to configure (0 to 3) + * @param timeout Number of WDT ticks for the stage to time out + * @param behavior What action to take when the stage times out. Note that only + * the RWDT supports the RTC reset action. + * + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior); + +/* -------------------------------- Runtime --------------------------------- */ + +/** + * @brief Disable write protection of the WDT registers + * + * @param hal Context of HAL layer + */ +void wdt_hal_write_protect_disable(wdt_hal_context_t *hal); + +/** + * @brief Enable write protection of the WDT registers + * + * @param hal Context of HAL layer + */ +void wdt_hal_write_protect_enable(wdt_hal_context_t *hal); + +/** + * @brief Enable the WDT + * + * The WDT will start counting when enabled. This function also feeds the WDT + * before enabling it. + * + * @param hal Context of HAL layer + * + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_enable(wdt_hal_context_t *hal); + +/** + * @brief Disable the WDT + * + * @param hal Context of HAL layer + * + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_disable(wdt_hal_context_t *hal); + +/** + * @brief Handle WDT interrupt + * + * Clears the interrupt status bit and feeds the WDT + * + * @param hal Context of HAL layer + * + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_handle_intr(wdt_hal_context_t *hal); + +/** + * @brief Feed the WDT + * + * Feeding the WDT will reset the internal count and current stage. + * + * @param hal Context of HAL layer + * + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_feed(wdt_hal_context_t *hal); + +/** + * @brief Enable/Disable the WDT flash boot mode + * + * @param hal Context of HAL layer + * @param enable True to enable flash boot mode, false to disable. + * + * @note Flash boot mode can trigger a time out even if the WDT is disabled. + * @note This function can only be called when the WDT is unlocked. Call + * wdt_hal_write_protect_disable() first. + */ +void wdt_hal_set_flashboot_en(wdt_hal_context_t *hal, bool enable); + +/** + * @brief Check if the WDT is enabled + * + * @param hal Context of HAL layer + * @return True if enabled, false otherwise + */ +bool wdt_hal_is_enabled(wdt_hal_context_t *hal); + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/hal/wdt_types.h b/components/soc/include/hal/wdt_types.h new file mode 100644 index 000000000..afc0dc498 --- /dev/null +++ b/components/soc/include/hal/wdt_types.h @@ -0,0 +1,71 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + WDT_RWDT = 0, /*!< RTC Watchdog Timer (RWDT) */ + WDT_MWDT0, /*!< Main System Watchdog Timer (MWDT) of Timer Group 0 */ + WDT_MWDT1, /*!< Main System Watchdog Timer (MWDT) of Timer Group 1 */ +} wdt_inst_t; + +/** + * @brief Stages of a Watchdog Timer. A WDT has 4 stages. + */ +typedef enum { + WDT_STAGE0 = 0, /*!< Stage 0 */ + WDT_STAGE1 = 1, /*!< Stage 1 */ + WDT_STAGE2 = 2, /*!< Stage 2 */ + WDT_STAGE3 = 3 /*!< Stage 3 */ +} wdt_stage_t; + +/** + * @brief Behavior of the WDT stage if it times out + * + * @note These enum values should be compatible with the corresponding register + * field values. + */ +typedef enum { + WDT_STAGE_ACTION_OFF = 0, /*!< Disabled. This stage will have no effects on the system. */ + WDT_STAGE_ACTION_INT = 1, /*!< Trigger an interrupt when the stage expires. */ + WDT_STAGE_ACTION_RESET_CPU = 2, /*!< Reset a CPU core when the stage expires. */ + WDT_STAGE_ACTION_RESET_SYSTEM = 3, /*!< Reset the main system when the stage expires. This includes the CPU and all peripherals. The RTC is an exception and will not be reset. */ + WDT_STAGE_ACTION_RESET_RTC = 4, /*!< Reset the main system and the RTC when the stage expires. ONLY AVAILABLE FOR RWDT */ +} wdt_stage_action_t; + +/** + * @brief Length of CPU or System Reset signals + * + * @note These enum values should be compatible with the corresponding register + * field values. + */ +typedef enum { + WDT_RESET_SIG_LENGTH_100ns = 0, /*!< 100 ns */ + WDT_RESET_SIG_LENGTH_200ns = 1, /*!< 200 ns */ + WDT_RESET_SIG_LENGTH_300ns = 2, /*!< 300 ns */ + WDT_RESET_SIG_LENGTH_400ns = 3, /*!< 400 ns */ + WDT_RESET_SIG_LENGTH_500ns = 4, /*!< 500 ns */ + WDT_RESET_SIG_LENGTH_800ns = 5, /*!< 800 ns */ + WDT_RESET_SIG_LENGTH_1_6us = 6, /*!< 1.6 us */ + WDT_RESET_SIG_LENGTH_3_2us = 7 /*!< 3.2 us */ +} wdt_reset_sig_length_t; + + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/soc/rtc_wdt.h b/components/soc/include/soc/rtc_wdt.h deleted file mode 100644 index 0ed2c9a7b..000000000 --- a/components/soc/include/soc/rtc_wdt.h +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* Recommendation of using API RTC_WDT. -1) Setting and enabling rtc_wdt: -@code - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); //RTC_WDT_STAGE_ACTION_RESET_SYSTEM or RTC_WDT_STAGE_ACTION_RESET_RTC - rtc_wdt_set_time(RTC_WDT_STAGE0, 7000); // timeout rtd_wdt 7000ms. - rtc_wdt_enable(); - rtc_wdt_protect_on(); - @endcode - -* If you use this option RTC_WDT_STAGE_ACTION_RESET_SYSTEM then after reset you can see these messages. -They can help to understand where the CPUs were when the WDT was triggered. - W (30) boot: PRO CPU has been reset by WDT. - W (30) boot: WDT reset info: PRO CPU PC=0x400xxxxx - ... function where it happened - - W (31) boot: WDT reset info: APP CPU PC=0x400xxxxx - ... function where it happened - -* If you use this option RTC_WDT_STAGE_ACTION_RESET_RTC then you will see message (rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)) -without description where were CPUs when it happened. - -2) Reset counter of rtc_wdt: -@code - rtc_wdt_feed(); -@endcode - -3) Disable rtc_wdt: -@code - rtc_wdt_disable(); -@endcode - */ - -#pragma once -#include -#include -#include "soc/rtc_periph.h" -#include "esp_err.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/// List of stage of rtc watchdog. WDT has 4 stage. -typedef enum { - RTC_WDT_STAGE0 = 0, /*!< Stage 0 */ - RTC_WDT_STAGE1 = 1, /*!< Stage 1 */ - RTC_WDT_STAGE2 = 2, /*!< Stage 2 */ - RTC_WDT_STAGE3 = 3 /*!< Stage 3 */ -} rtc_wdt_stage_t; - -/// List of action. When the time of stage expires this action will be triggered. -typedef enum { - RTC_WDT_STAGE_ACTION_OFF = RTC_WDT_STG_SEL_OFF, /*!< Disabled. This stage will have no effects on the system. */ - RTC_WDT_STAGE_ACTION_INTERRUPT = RTC_WDT_STG_SEL_INT, /*!< Trigger an interrupt. When the stage expires an interrupt is triggered. */ - RTC_WDT_STAGE_ACTION_RESET_CPU = RTC_WDT_STG_SEL_RESET_CPU, /*!< Reset a CPU core. */ - RTC_WDT_STAGE_ACTION_RESET_SYSTEM = RTC_WDT_STG_SEL_RESET_SYSTEM, /*!< Reset the main system includes the CPU and all peripherals. The RTC is an exception to this, and it will not be reset. */ - RTC_WDT_STAGE_ACTION_RESET_RTC = RTC_WDT_STG_SEL_RESET_RTC /*!< Reset the main system and the RTC. */ -} rtc_wdt_stage_action_t; - -/// Type of reset signal -typedef enum { - RTC_WDT_SYS_RESET_SIG = 0, /*!< System reset signal length selection */ - RTC_WDT_CPU_RESET_SIG = 1 /*!< CPU reset signal length selection */ -} rtc_wdt_reset_sig_t; - -/// Length of reset signal -typedef enum { - RTC_WDT_LENGTH_100ns = 0, /*!< 100 ns */ - RTC_WDT_LENGTH_200ns = 1, /*!< 200 ns */ - RTC_WDT_LENGTH_300ns = 2, /*!< 300 ns */ - RTC_WDT_LENGTH_400ns = 3, /*!< 400 ns */ - RTC_WDT_LENGTH_500ns = 4, /*!< 500 ns */ - RTC_WDT_LENGTH_800ns = 5, /*!< 800 ns */ - RTC_WDT_LENGTH_1_6us = 6, /*!< 1.6 us */ - RTC_WDT_LENGTH_3_2us = 7 /*!< 3.2 us */ -} rtc_wdt_length_sig_t; - -/** - * @brief Get status of protect of rtc_wdt. - * - * @return - * - True if the protect of RTC_WDT is set - */ -bool rtc_wdt_get_protect_status(void); - -/** - * @brief Set protect of rtc_wdt. - */ -void rtc_wdt_protect_on(void); - -/** - * @brief Reset protect of rtc_wdt. - */ -void rtc_wdt_protect_off(void); - -/** - * @brief Enable rtc_wdt. - */ -void rtc_wdt_enable(void); - -/** - * @brief Enable the flash boot protection procedure for WDT. - * - * Do not recommend to use it in the app. - * This function was added to be compatibility with the old bootloaders. - * This mode is disabled in bootloader or using rtc_wdt_disable() function. - */ -void rtc_wdt_flashboot_mode_enable(void); - -/** - * @brief Disable rtc_wdt. - */ -void rtc_wdt_disable(void); - -/** - * @brief Reset counter rtc_wdt. - * - * It returns to stage 0 and its expiry counter restarts from 0. - */ -void rtc_wdt_feed(void); - -/** - * @brief Set time for required stage. - * - * @param[in] stage Stage of rtc_wdt. - * @param[in] timeout_ms Timeout for this stage. - * - * @return - * - ESP_OK In case of success - * - ESP_ERR_INVALID_ARG If stage has invalid value - */ -esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms); - -/** - * @brief Get the timeout set for the required stage. - * - * @param[in] stage Stage of rtc_wdt. - * @param[out] timeout_ms Timeout set for this stage. (not elapsed time). - * - * @return - * - ESP_OK In case of success - * - ESP_ERR_INVALID_ARG If stage has invalid value - */ -esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms); - -/** - * @brief Set an action for required stage. - * - * @param[in] stage Stage of rtc_wdt. - * @param[in] stage_sel Action for this stage. When the time of stage expires this action will be triggered. - * - * @return - * - ESP_OK In case of success - * - ESP_ERR_INVALID_ARG If stage or stage_sel have invalid value - */ -esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel); - -/** - * @brief Set a length of reset signal. - * - * @param[in] reset_src Type of reset signal. - * @param[in] reset_signal_length A length of reset signal. - * - * @return - * - ESP_OK In case of success - * - ESP_ERR_INVALID_ARG If reset_src or reset_signal_length have invalid value - */ -esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length); - -/** - * @brief Return true if rtc_wdt is enabled. - * - * @return - * - True rtc_wdt is enabled - */ -bool rtc_wdt_is_on(void); - -#ifdef __cplusplus -} -#endif diff --git a/components/soc/linker.lf b/components/soc/linker.lf index df2191e32..8dd9e25cd 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -23,3 +23,4 @@ entries: lldesc (noflash_text) cpu_hal (noflash) soc_hal (noflash) + wdt_hal_iram (noflash) diff --git a/components/soc/soc/esp32/include/soc/rtc_cntl_reg.h b/components/soc/soc/esp32/include/soc/rtc_cntl_reg.h index 090b3f707..4869736c8 100644 --- a/components/soc/soc/esp32/include/soc/rtc_cntl_reg.h +++ b/components/soc/soc/esp32/include/soc/rtc_cntl_reg.h @@ -17,6 +17,15 @@ /* The value that needs to be written to RTC_CNTL_WDT_WKEY to write-enable the wdt registers */ #define RTC_CNTL_WDT_WKEY_VALUE 0x50D83AA1 +/* Possible values for RTC_CNTL_WDT_CPU_RESET_LENGTH and RTC_CNTL_WDT_SYS_RESET_LENGTH */ +#define RTC_WDT_RESET_LENGTH_100_NS 0 +#define RTC_WDT_RESET_LENGTH_200_NS 1 +#define RTC_WDT_RESET_LENGTH_300_NS 2 +#define RTC_WDT_RESET_LENGTH_400_NS 3 +#define RTC_WDT_RESET_LENGTH_500_NS 4 +#define RTC_WDT_RESET_LENGTH_800_NS 5 +#define RTC_WDT_RESET_LENGTH_1600_NS 6 +#define RTC_WDT_RESET_LENGTH_3200_NS 7 #include "soc.h" #define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0) diff --git a/components/soc/soc/esp32/include/soc/rtc_cntl_struct.h b/components/soc/soc/esp32/include/soc/rtc_cntl_struct.h index b7d2e8bd0..4a8fc7d46 100644 --- a/components/soc/soc/esp32/include/soc/rtc_cntl_struct.h +++ b/components/soc/soc/esp32/include/soc/rtc_cntl_struct.h @@ -447,8 +447,8 @@ typedef volatile struct rtc_cntl_dev_s { uint32_t flashboot_mod_en: 1; /*enable WDT in flash boot*/ uint32_t sys_reset_length: 3; /*system reset counter length*/ uint32_t cpu_reset_length: 3; /*CPU reset counter length*/ - uint32_t level_int_en: 1; /*N/A*/ - uint32_t edge_int_en: 1; /*N/A*/ + uint32_t level_int_en: 1; /*When set, level type interrupt generation is enabled*/ + uint32_t edge_int_en: 1; /*When set, edge type interrupt generation is enabled*/ uint32_t stg3: 3; /*1: interrupt stage en 2: CPU reset stage en 3: system reset stage en 4: RTC reset stage en*/ uint32_t stg2: 3; /*1: interrupt stage en 2: CPU reset stage en 3: system reset stage en 4: RTC reset stage en*/ uint32_t stg1: 3; /*1: interrupt stage en 2: CPU reset stage en 3: system reset stage en 4: RTC reset stage en*/ diff --git a/components/soc/soc/esp32/include/soc/timer_group_caps.h b/components/soc/soc/esp32/include/soc/timer_group_caps.h index e15269aae..67dbe54ff 100644 --- a/components/soc/soc/esp32/include/soc/timer_group_caps.h +++ b/components/soc/soc/esp32/include/soc/timer_group_caps.h @@ -13,3 +13,8 @@ // limitations under the License. #pragma once + +#include "soc/soc.h" + +//APB Frequency +#define WDT_SOURCE_CLK_FREQ_MHZ (APB_CLK_FREQ / 1000000) diff --git a/components/soc/soc/esp32/include/soc/timer_group_reg.h b/components/soc/soc/esp32/include/soc/timer_group_reg.h index 2db2a7e3f..9201ff063 100644 --- a/components/soc/soc/esp32/include/soc/timer_group_reg.h +++ b/components/soc/soc/esp32/include/soc/timer_group_reg.h @@ -24,6 +24,15 @@ #define TIMG_WDT_STG_SEL_RESET_CPU 2 #define TIMG_WDT_STG_SEL_RESET_SYSTEM 3 +/* Possible values for TIMG_WDT_CPU_RESET_LENGTH and TIMG_WDT_SYS_RESET_LENGTH */ +#define TIMG_WDT_RESET_LENGTH_100_NS 0 +#define TIMG_WDT_RESET_LENGTH_200_NS 1 +#define TIMG_WDT_RESET_LENGTH_300_NS 2 +#define TIMG_WDT_RESET_LENGTH_400_NS 3 +#define TIMG_WDT_RESET_LENGTH_500_NS 4 +#define TIMG_WDT_RESET_LENGTH_800_NS 5 +#define TIMG_WDT_RESET_LENGTH_1600_NS 6 +#define TIMG_WDT_RESET_LENGTH_3200_NS 7 #define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000) #define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000) diff --git a/components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h b/components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h index ac336c8b2..de61f173e 100644 --- a/components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h +++ b/components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h @@ -17,6 +17,16 @@ /* The value that needs to be written to RTC_CNTL_WDT_WKEY to write-enable the wdt registers */ #define RTC_CNTL_WDT_WKEY_VALUE 0x50D83AA1 +/* Possible values for RTC_CNTL_WDT_CPU_RESET_LENGTH and RTC_CNTL_WDT_SYS_RESET_LENGTH */ +#define RTC_WDT_RESET_LENGTH_100_NS 0 +#define RTC_WDT_RESET_LENGTH_200_NS 1 +#define RTC_WDT_RESET_LENGTH_300_NS 2 +#define RTC_WDT_RESET_LENGTH_400_NS 3 +#define RTC_WDT_RESET_LENGTH_500_NS 4 +#define RTC_WDT_RESET_LENGTH_800_NS 5 +#define RTC_WDT_RESET_LENGTH_1600_NS 6 +#define RTC_WDT_RESET_LENGTH_3200_NS 7 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h b/components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h index 3e10ea66a..5083161d7 100644 --- a/components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h +++ b/components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h @@ -20,6 +20,8 @@ extern "C" { #endif +#include + typedef volatile struct { union { struct { diff --git a/components/soc/soc/esp32s2/include/soc/timer_group_caps.h b/components/soc/soc/esp32s2/include/soc/timer_group_caps.h index 8e4451349..7c10dee29 100644 --- a/components/soc/soc/esp32s2/include/soc/timer_group_caps.h +++ b/components/soc/soc/esp32s2/include/soc/timer_group_caps.h @@ -14,4 +14,8 @@ #pragma once +#include "soc/soc.h" + #define TIMER_GROUP_SUPPORTS_XTAL_CLOCK +//APB Frequency +#define WDT_SOURCE_CLK_FREQ_MHZ (APB_CLK_FREQ / 1000000) diff --git a/components/soc/soc/esp32s2/include/soc/timer_group_reg.h b/components/soc/soc/esp32s2/include/soc/timer_group_reg.h index 1f016a96f..3bf68c16b 100644 --- a/components/soc/soc/esp32s2/include/soc/timer_group_reg.h +++ b/components/soc/soc/esp32s2/include/soc/timer_group_reg.h @@ -29,6 +29,16 @@ extern "C" { #define TIMG_WDT_STG_SEL_RESET_CPU 2 #define TIMG_WDT_STG_SEL_RESET_SYSTEM 3 +/* Possible values for TIMG_WDT_CPU_RESET_LENGTH and TIMG_WDT_SYS_RESET_LENGTH */ +#define TIMG_WDT_RESET_LENGTH_100_NS 0 +#define TIMG_WDT_RESET_LENGTH_200_NS 1 +#define TIMG_WDT_RESET_LENGTH_300_NS 2 +#define TIMG_WDT_RESET_LENGTH_400_NS 3 +#define TIMG_WDT_RESET_LENGTH_500_NS 4 +#define TIMG_WDT_RESET_LENGTH_800_NS 5 +#define TIMG_WDT_RESET_LENGTH_1600_NS 6 +#define TIMG_WDT_RESET_LENGTH_3200_NS 7 + #define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000) /* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */ /*description: */ diff --git a/components/soc/soc/esp32s2/include/soc/timer_group_struct.h b/components/soc/soc/esp32s2/include/soc/timer_group_struct.h index 0f16144d2..55d6befea 100644 --- a/components/soc/soc/esp32s2/include/soc/timer_group_struct.h +++ b/components/soc/soc/esp32s2/include/soc/timer_group_struct.h @@ -13,6 +13,9 @@ // limitations under the License. #ifndef _SOC_TIMG_STRUCT_H_ #define _SOC_TIMG_STRUCT_H_ + +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/components/soc/soc/include/soc/rtc_cntl_periph.h b/components/soc/soc/include/soc/rtc_cntl_periph.h new file mode 100644 index 000000000..60e3d3216 --- /dev/null +++ b/components/soc/soc/include/soc/rtc_cntl_periph.h @@ -0,0 +1,18 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "soc/rtc_cntl_reg.h" +#include "soc/rtc_cntl_struct.h" diff --git a/components/soc/src/esp32/CMakeLists.txt b/components/soc/src/esp32/CMakeLists.txt index fd81a73f2..dfefca39e 100644 --- a/components/soc/src/esp32/CMakeLists.txt +++ b/components/soc/src/esp32/CMakeLists.txt @@ -5,7 +5,6 @@ set(srcs "brownout_hal.c" "rtc_pm.c" "rtc_sleep.c" "rtc_time.c" - "rtc_wdt.c" "soc_memory_layout.c" "touch_sensor_hal.c") diff --git a/components/soc/src/esp32/include/hal/mwdt_ll.h b/components/soc/src/esp32/include/hal/mwdt_ll.h new file mode 100644 index 000000000..9a981c685 --- /dev/null +++ b/components/soc/src/esp32/include/hal/mwdt_ll.h @@ -0,0 +1,262 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "soc/timer_periph.h" +#include "hal/wdt_types.h" +#include "esp_attr.h" + +//Type check wdt_stage_action_t +_Static_assert(WDT_STAGE_ACTION_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +//Type check wdt_reset_sig_length_t +_Static_assert(WDT_RESET_SIG_LENGTH_100ns == TIMG_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_200ns == TIMG_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_300ns == TIMG_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_400ns == TIMG_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_500ns == TIMG_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_800ns == TIMG_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == TIMG_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == TIMG_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); + +/** + * @brief Enable the MWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw) +{ + hw->wdt_config0.en = 1; +} + +/** + * @brief Disable the MWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw) +{ + hw->wdt_config0.en = 0; +} + +/** + * Check if the MWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if the MWDT is enabled, false otherwise + */ +FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) +{ + return (hw->wdt_config0.en) ? true : false; +} + +/** + * @brief Configure a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout + * @param behavior What action to take when the stage times out + */ +FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = behavior; + hw->wdt_config2 = timeout; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = behavior; + hw->wdt_config3 = timeout; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = behavior; + hw->wdt_config4 = timeout; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = behavior; + hw->wdt_config5 = timeout; + break; + default: + break; + } +} + +/** + * @brief Disable a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + break; + } +} + +/** + * @brief Enable or disable MWDT edge interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable edge interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable) +{ + hw->wdt_config0.edge_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable or disable MWDT level interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable level interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable) +{ + hw->wdt_config0.level_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.cpu_reset_length = length; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.sys_reset_length = length; +} + +/** + * @brief Enable/Disable the MWDT flashboot mode. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0; +} + +/** + * @brief Set the clock prescaler of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param prescaler Prescaler value between 1 to 65535 + */ +FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler) +{ + hw->wdt_config1.clk_prescale = prescaler; +} + +/** + * @brief Feed the MWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw) +{ + hw->wdt_feed = 1; +} + +/** + * @brief Enable write protection of the MWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw) +{ + hw->wdt_wprotect = 0; +} + +/** + * @brief Disable write protection of the MWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) +{ + hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE; +} + +/** + * @brief Clear the MWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) +{ + hw->int_clr_timers.wdt = 1; +} + +/** + * @brief Set the interrupt enable bit for the MWDT interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param enable Whether to enable the MWDT interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable) +{ + hw->int_ena.wdt = (enable) ? 1 : 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/src/esp32/include/hal/rwdt_ll.h b/components/soc/src/esp32/include/hal/rwdt_ll.h new file mode 100644 index 000000000..c1d2d6060 --- /dev/null +++ b/components/soc/src/esp32/include/hal/rwdt_ll.h @@ -0,0 +1,297 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "hal/wdt_types.h" +#include "soc/rtc_cntl_periph.h" +#include "esp_attr.h" + +//Type check wdt_stage_action_t +_Static_assert(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +//Type check wdt_reset_sig_length_t +_Static_assert(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); + + +/** + * @brief Enable the RWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw) +{ + hw->wdt_config0.en = 1; +} + +/** + * @brief Disable the RWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw) +{ + hw->wdt_config0.en = 0; +} + +/** + * @brief Check if the RWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if RTC WDT is enabled + */ +FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw) +{ + return (hw->wdt_config0.en) ? true : false; +} + +/** + * @brief Configure a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout + * @param behavior What action to take when the stage times out + */ +FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = behavior; + hw->wdt_config1 = timeout_ticks; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = behavior; + hw->wdt_config2 = timeout_ticks; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = behavior; + hw->wdt_config3 = timeout_ticks; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = behavior; + hw->wdt_config4 = timeout_ticks; + break; + default: + abort(); + } +} + +/** + * @brief Disable a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + abort(); + } +} + +/** + * @brief Enable or disable RWDT edge interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable edge interrupt + */ +FORCE_INLINE_ATTR void rwdt_ll_set_edge_intr(rtc_cntl_dev_t *hw, bool enable) +{ + hw->wdt_config0.edge_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable or disable RWDT level interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable level interrupt + */ +FORCE_INLINE_ATTR void rwdt_ll_set_level_intr(rtc_cntl_dev_t *hw, bool enable) +{ + hw->wdt_config0.level_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.cpu_reset_length = length; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.sys_reset_length = length; +} + +/** + * @brief Enable/Disable the RWDT flashboot mode. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU0 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU1 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the RWDT pause during sleep functionality + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0; +} + +/** + * @brief Feed the RWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw) +{ + hw->wdt_feed.feed = 1; +} + +/** + * @brief Enable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw) +{ + hw->wdt_wprotect = 0; +} + +/** + * @brief Disable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw) +{ + hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE; +} + +/** + * @brief Enable the RWDT interrupt. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT interrupt, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable) +{ + hw->int_ena.rtc_wdt = (enable) ? 1 : 0; +} + +/** + * @brief Check if the RWDT interrupt has been triggered + * + * @param hw Start address of the peripheral registers. + * @return True if the RWDT interrupt was triggered + */ +FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw) +{ + return (hw->int_st.rtc_wdt) ? true : false; +} + +/** + * @brief Clear the RWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw) +{ + hw->int_clr.rtc_wdt = 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/src/esp32/include/hal/timer_ll.h b/components/soc/src/esp32/include/hal/timer_ll.h index c6cff70f4..34679c6d7 100644 --- a/components/soc/src/esp32/include/hal/timer_ll.h +++ b/components/soc/src/esp32/include/hal/timer_ll.h @@ -381,157 +381,6 @@ static inline void timer_ll_get_intr_status_reg(timg_dev_t *hw, uint32_t *intr_s *intr_status_reg = (uint32_t)&(hw->int_st_timers.val); } -/* WDT operations */ - -/** - * @brief Unlock/lock the WDT register in case of mis-operations. - * - * @param hw Beginning address of the peripheral registers. - * @param protect true to lock, false to unlock before operations. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect) -{ - hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE); -} - -/** - * @brief Initialize WDT. - * - * @param hw Beginning address of the peripheral registers. - * - * @note Call `timer_ll_wdt_set_protect` first - */ -FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw) -{ - hw->wdt_config0.sys_reset_length=7; //3.2uS - hw->wdt_config0.cpu_reset_length=7; //3.2uS - //currently only level interrupt is supported - hw->wdt_config0.level_int_en = 1; - hw->wdt_config0.edge_int_en = 0; -} - -/** - * @brief Set the WDT tick time. - * - * @param hw Beginning address of the peripheral registers. - * @param tick_time_us Tick time. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us) -{ - hw->wdt_config1.clk_prescale=80*tick_time_us; -} - -/** - * @brief Feed the WDT. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw) -{ - hw->wdt_feed = 1; -} - -/** - * @brief Set the WDT timeout. - * - * @param hw Beginning address of the peripheral registers. - * @param stage Stage number of WDT. - * @param timeout_Tick tick threshold of timeout. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick) -{ - switch (stage) { - case 0: - hw->wdt_config2=timeout_tick; - break; - case 1: - hw->wdt_config3=timeout_tick; - break; - case 2: - hw->wdt_config4=timeout_tick; - break; - case 3: - hw->wdt_config5=timeout_tick; - break; - default: - abort(); - } -} - -_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); - -/** - * @brief Set the WDT timeout behavior. - * - * @param hw Beginning address of the peripheral registers. - * @param stage Stage number of WDT. - * @param behavior Behavior of WDT, please see enum timer_wdt_behavior_t. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior) -{ - switch (stage) { - case 0: - hw->wdt_config0.stg0 = behavior; - break; - case 1: - hw->wdt_config0.stg1 = behavior; - break; - case 2: - hw->wdt_config0.stg2 = behavior; - break; - case 3: - hw->wdt_config0.stg3 = behavior; - break; - default: - abort(); - } -} - -/** - * @brief Enable/Disable the WDT enable. - * - * @param hw Beginning address of the peripheral registers. - * @param enable True to enable WDT, false to disable WDT. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable) -{ - hw->wdt_config0.en = enable; -} - -/** - * @brief Enable/Disable the WDT flashboot mode. - * - * @param hw Beginning address of the peripheral registers. - * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable) -{ - hw->wdt_config0.flashboot_mod_en = enable; -} - -/** - * @brief Clear the WDT interrupt status. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_clear_intr_status(timg_dev_t* hw) -{ - hw->int_clr_timers.wdt = 1; -} - -/** - * @brief Enable the WDT interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_enable_intr(timg_dev_t* hw) -{ - hw->int_ena.wdt = 1; -} - #ifdef __cplusplus } #endif diff --git a/components/soc/src/esp32/rtc_wdt.c b/components/soc/src/esp32/rtc_wdt.c deleted file mode 100644 index facf8d444..000000000 --- a/components/soc/src/esp32/rtc_wdt.c +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "soc/rtc_wdt.h" -#include "soc/rtc.h" - - -bool rtc_wdt_get_protect_status(void) -{ - return READ_PERI_REG(RTC_CNTL_WDTWPROTECT_REG) != RTC_CNTL_WDT_WKEY_VALUE; -} - -void rtc_wdt_protect_off(void) -{ - WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); -} - -void rtc_wdt_protect_on(void) -{ - WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); -} - - -void rtc_wdt_enable(void) -{ - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP); -} - -void rtc_wdt_flashboot_mode_enable(void) -{ - REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); -} - -void rtc_wdt_disable(void) -{ - bool protect = rtc_wdt_get_protect_status(); - if (protect) { - rtc_wdt_protect_off(); - } - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE2, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE3, RTC_WDT_STAGE_ACTION_OFF); - REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); - REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN); - if (protect) { - rtc_wdt_protect_on(); - } -} - -void rtc_wdt_feed(void) -{ - bool protect = rtc_wdt_get_protect_status(); - if (protect) { - rtc_wdt_protect_off(); - } - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - if (protect) { - rtc_wdt_protect_on(); - } -} - -esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms) -{ - if (stage > 3) { - return ESP_ERR_INVALID_ARG; - } - uint32_t timeout = (uint32_t) ((uint64_t) rtc_clk_slow_freq_get_hz() * timeout_ms / 1000); - if (stage == RTC_WDT_STAGE0) { - WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, timeout); - } else if (stage == RTC_WDT_STAGE1) { - WRITE_PERI_REG(RTC_CNTL_WDTCONFIG2_REG, timeout); - } else if (stage == RTC_WDT_STAGE2) { - WRITE_PERI_REG(RTC_CNTL_WDTCONFIG3_REG, timeout); - } else { - WRITE_PERI_REG(RTC_CNTL_WDTCONFIG4_REG, timeout); - } - - return ESP_OK; -} - -esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms) -{ - if (stage > 3) { - return ESP_ERR_INVALID_ARG; - } - uint32_t time_tick; - if (stage == RTC_WDT_STAGE0) { - time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG1_REG); - } else if (stage == RTC_WDT_STAGE1) { - time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG2_REG); - } else if (stage == RTC_WDT_STAGE2) { - time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG3_REG); - } else { - time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG4_REG); - } - - *timeout_ms = time_tick * 1000 / rtc_clk_slow_freq_get_hz(); - - return ESP_OK; -} - -esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel) -{ - if (stage > 3 || stage_sel > 4) { - return ESP_ERR_INVALID_ARG; - } - if (stage == RTC_WDT_STAGE0) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, stage_sel); - } else if (stage == RTC_WDT_STAGE1) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG1, stage_sel); - } else if (stage == RTC_WDT_STAGE2) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG2, stage_sel); - } else { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG3, stage_sel); - } - - return ESP_OK; -} - -esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length) -{ - if (reset_src > 1 || reset_signal_length > 7) { - return ESP_ERR_INVALID_ARG; - } - if (reset_src == 0) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, reset_signal_length); - } else { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, reset_signal_length); - } - - return ESP_OK; -} - -bool rtc_wdt_is_on(void) -{ - return (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN) != 0) || (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN) != 0); -} diff --git a/components/soc/src/esp32s2/CMakeLists.txt b/components/soc/src/esp32s2/CMakeLists.txt index 765ef7776..0321c6ec0 100644 --- a/components/soc/src/esp32s2/CMakeLists.txt +++ b/components/soc/src/esp32s2/CMakeLists.txt @@ -5,7 +5,6 @@ set(srcs "brownout_hal.c" "rtc_pm.c" "rtc_sleep.c" "rtc_time.c" - "rtc_wdt.c" "soc_memory_layout.c" "touch_sensor_hal.c" "usb_hal.c") diff --git a/components/soc/src/esp32s2/include/hal/mwdt_ll.h b/components/soc/src/esp32s2/include/hal/mwdt_ll.h new file mode 100644 index 000000000..f909678b3 --- /dev/null +++ b/components/soc/src/esp32s2/include/hal/mwdt_ll.h @@ -0,0 +1,264 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "soc/timer_periph.h" +#include "hal/wdt_types.h" +#include "esp_attr.h" + +//Type check wdt_stage_action_t +_Static_assert(WDT_STAGE_ACTION_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +//Type check wdt_reset_sig_length_t +_Static_assert(WDT_RESET_SIG_LENGTH_100ns == TIMG_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_200ns == TIMG_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_300ns == TIMG_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_400ns == TIMG_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_500ns == TIMG_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_800ns == TIMG_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == TIMG_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == TIMG_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); + +/** + * @brief Enable the MWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw) +{ + hw->wdt_config0.en = 1; +} + +/** + * @brief Disable the MWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw) +{ + hw->wdt_config0.en = 0; +} + +/** + * Check if the MWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if the MWDT is enabled, false otherwise + */ +FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw) +{ + return (hw->wdt_config0.en) ? true : false; +} + +/** + * @brief Configure a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout + * @param behavior What action to take when the stage times out + */ +FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = behavior; + hw->wdt_config2 = timeout; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = behavior; + hw->wdt_config3 = timeout; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = behavior; + hw->wdt_config4 = timeout; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = behavior; + hw->wdt_config5 = timeout; + break; + default: + break; + } +} + +/** + * @brief Disable a particular stage of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + break; + } +} + +/** + * @brief Enable or disable MWDT edge interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable edge interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable) +{ + hw->wdt_config0.edge_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable or disable MWDT level interrupt + * + * @param hw Start address of the peripheral registers. + * @param enable Whether to enable level interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable) +{ + hw->wdt_config0.level_int_en = (enable) ? 1 : 0; +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.cpu_reset_length = length; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.sys_reset_length = length; +} + +/** + * @brief Enable/Disable the MWDT flashboot mode. + * + * @param hw Beginning address of the peripheral registers. + * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0; +} + +/** + * @brief Set the clock prescaler of the MWDT + * + * @param hw Start address of the peripheral registers. + * @param prescaler Prescaler value between 1 to 65535 + */ +FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler) +{ + hw->wdt_config1.clk_prescale = prescaler; +} + +/** + * @brief Feed the MWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw) +{ + hw->wdt_feed = 1; +} + +/** + * @brief Enable write protection of the MWDT registers + * + * Locking the MWDT will prevent any of the MWDT's registers from being modified + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw) +{ + hw->wdt_wprotect = 0; +} + +/** + * @brief Disable write protection of the MWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw) +{ + hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE; +} + +/** + * @brief Clear the MWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw) +{ + hw->int_clr.wdt = 1; +} + +/** + * @brief Set the interrupt enable bit for the MWDT interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param enable Whether to enable the MWDT interrupt + */ +FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable) +{ + hw->int_ena.wdt = (enable) ? 1 : 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/src/esp32s2/include/hal/rwdt_ll.h b/components/soc/src/esp32s2/include/hal/rwdt_ll.h new file mode 100644 index 000000000..d9645ddc7 --- /dev/null +++ b/components/soc/src/esp32s2/include/hal/rwdt_ll.h @@ -0,0 +1,311 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for Timer Group register operations. +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "hal/wdt_types.h" +#include "soc/rtc_cntl_periph.h" +#include "soc/efuse_reg.h" +#include "esp_attr.h" + +//Type check wdt_stage_action_t +_Static_assert(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +_Static_assert(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t"); +//Type check wdt_reset_sig_length_t +_Static_assert(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); +_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t"); + +/** + * @brief Enable the RWDT + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw) +{ + hw->wdt_config0.en = 1; +} + +/** + * @brief Disable the RWDT + * + * @param hw Start address of the peripheral registers. + * @note This function does not disable the flashboot mode. Therefore, given that + * the MWDT is disabled using this function, a timeout can still occur + * if the flashboot mode is simultaneously enabled. + */ +FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw) +{ + hw->wdt_config0.en = 0; +} + +/** + * @brief Check if the RWDT is enabled + * + * @param hw Start address of the peripheral registers. + * @return True if RTC WDT is enabled + */ +FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw) +{ + return (hw->wdt_config0.en) ? true : false; +} + +/** + * @brief Configure a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to configure + * @param timeout Number of timer ticks for the stage to timeout (see note). + * @param behavior What action to take when the stage times out + * + * @note The value of of RWDT stage 0 timeout register is special, in + * that an implicit multiplier is applied to that value to produce + * and effective timeout tick value. The multiplier is dependent + * on an EFuse value. Therefore, when configuring stage 0, the valid + * values for the timeout argument are: + * - If Efuse value is 0, any even number between [2,2*UINT32_MAX] + * - If Efuse value is 1, any multiple of 4 between [4,4*UINT32_MAX] + * - If Efuse value is 2, any multiple of 8 between [8,8*UINT32_MAX] + * - If Efuse value is 3, any multiple of 16 between [16,16*UINT32_MAX] + */ +FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = behavior; + //Account of implicty multiplier applied to stage 0 timeout tick config value + hw->wdt_config1 = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL)); + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = behavior; + hw->wdt_config2 = timeout_ticks; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = behavior; + hw->wdt_config3 = timeout_ticks; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = behavior; + hw->wdt_config4 = timeout_ticks; + break; + default: + abort(); + } +} + +/** + * @brief Disable a particular stage of the RWDT + * + * @param hw Start address of the peripheral registers. + * @param stage Which stage to disable + */ +FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage) +{ + switch (stage) { + case WDT_STAGE0: + hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE1: + hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE2: + hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF; + break; + case WDT_STAGE3: + hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF; + break; + default: + abort(); + } +} + +/** + * @brief Set the length of the CPU reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of CPU reset signal + */ +FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.cpu_reset_length = length; +} + +/** + * @brief Set the length of the system reset action + * + * @param hw Start address of the peripheral registers. + * @param length Length of system reset signal + */ +FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length) +{ + hw->wdt_config0.sys_reset_length = length; +} + +/** + * @brief Enable/Disable the RWDT flashboot mode. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode. + * + * @note Flashboot mode is independent and can trigger a WDT timeout event if the + * WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled + * on flashboot, and should be disabled by software when flashbooting completes. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU0 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable CPU1 to be reset, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable the RWDT pause during sleep functionality + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0; +} + +/** + * @brief Enable/Disable chip reset on RWDT timeout. + * + * A chip reset also resets the analog portion of the chip. It will appear as a + * POWERON reset rather than an RTC reset. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_en(rtc_cntl_dev_t* hw, bool enable) +{ + hw->wdt_config0.chip_reset_en = (enable) ? 1 : 0; +} + +/** + * @brief Set width of chip reset signal + * + * @param hw Start address of the peripheral registers. + * @param width Width of chip reset signal in terms of number of RTC_SLOW_CLK cycles + */ +FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_width(rtc_cntl_dev_t *hw, uint32_t width) +{ + hw->wdt_config0.chip_reset_width = width; +} + +/** + * @brief Feed the RWDT + * + * Resets the current timer count and current stage. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw) +{ + hw->wdt_feed.feed = 1; +} + +/** + * @brief Enable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw) +{ + hw->wdt_wprotect = 0; +} + +/** + * @brief Disable write protection of the RWDT registers + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw) +{ + hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE; +} + +/** + * @brief Enable the RWDT interrupt. + * + * @param hw Start address of the peripheral registers. + * @param enable True to enable RWDT interrupt, false to disable. + */ +FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable) +{ + hw->int_ena.rtc_wdt = (enable) ? 1 : 0; +} + +/** + * @brief Check if the RWDT interrupt has been triggered + * + * @param hw Start address of the peripheral registers. + * @return True if the RWDT interrupt was triggered + */ +FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw) +{ + return (hw->int_st.rtc_wdt) ? true : false; +} + +/** + * @brief Clear the RWDT interrupt status. + * + * @param hw Start address of the peripheral registers. + */ +FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw) +{ + hw->int_clr.rtc_wdt = 1; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/src/esp32s2/include/hal/timer_ll.h b/components/soc/src/esp32s2/include/hal/timer_ll.h index 9e7818842..48d3bde9a 100644 --- a/components/soc/src/esp32s2/include/hal/timer_ll.h +++ b/components/soc/src/esp32s2/include/hal/timer_ll.h @@ -408,157 +408,6 @@ static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num) return hw->hw_timer[timer_num].config.use_xtal; } -/* WDT operations */ - -/** - * @brief Unlock/lock the WDT register in case of mis-operations. - * - * @param hw Beginning address of the peripheral registers. - * @param protect true to lock, false to unlock before operations. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect) -{ - hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE); -} - -/** - * @brief Initialize WDT. - * - * @param hw Beginning address of the peripheral registers. - * - * @note Call `timer_ll_wdt_set_protect` first - */ -FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw) -{ - hw->wdt_config0.sys_reset_length=7; //3.2uS - hw->wdt_config0.cpu_reset_length=7; //3.2uS - //currently only level interrupt is supported - hw->wdt_config0.level_int_en = 1; - hw->wdt_config0.edge_int_en = 0; -} - -/** - * @brief Set the WDT tick time. - * - * @param hw Beginning address of the peripheral registers. - * @param tick_time_us Tick time. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us) -{ - hw->wdt_config1.clk_prescale=80*tick_time_us; -} - -/** - * @brief Feed the WDT. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw) -{ - hw->wdt_feed = 1; -} - -/** - * @brief Set the WDT timeout. - * - * @param hw Beginning address of the peripheral registers. - * @param stage Stage number of WDT. - * @param timeout_Tick tick threshold of timeout. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick) -{ - switch (stage) { - case 0: - hw->wdt_config2=timeout_tick; - break; - case 1: - hw->wdt_config3=timeout_tick; - break; - case 2: - hw->wdt_config4=timeout_tick; - break; - case 3: - hw->wdt_config5=timeout_tick; - break; - default: - abort(); - } -} - -_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); -_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t"); - -/** - * @brief Set the WDT timeout behavior. - * - * @param hw Beginning address of the peripheral registers. - * @param stage Stage number of WDT. - * @param behavior Behavior of WDT, please see enum timer_wdt_behavior_t. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior) -{ - switch (stage) { - case 0: - hw->wdt_config0.stg0 = behavior; - break; - case 1: - hw->wdt_config0.stg1 = behavior; - break; - case 2: - hw->wdt_config0.stg2 = behavior; - break; - case 3: - hw->wdt_config0.stg3 = behavior; - break; - default: - abort(); - } -} - -/** - * @brief Enable/Disable the WDT enable. - * - * @param hw Beginning address of the peripheral registers. - * @param enable True to enable WDT, false to disable WDT. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable) -{ - hw->wdt_config0.en = enable; -} - -/** - * @brief Enable/Disable the WDT flashboot mode. - * - * @param hw Beginning address of the peripheral registers. - * @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable) -{ - hw->wdt_config0.flashboot_mod_en = enable; -} - -/** - * @brief Clear the WDT interrupt status. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_clear_intr_status(timg_dev_t* hw) -{ - hw->int_clr.wdt = 1; -} - -/** - * @brief Enable the WDT interrupt. - * - * @param hw Beginning address of the peripheral registers. - */ -FORCE_INLINE_ATTR void timer_ll_wdt_enable_intr(timg_dev_t* hw) -{ - hw->int_ena.wdt = 1; -} - #ifdef __cplusplus } #endif diff --git a/components/soc/src/esp32s2/rtc_wdt.c b/components/soc/src/esp32s2/rtc_wdt.c deleted file mode 100644 index 53861772a..000000000 --- a/components/soc/src/esp32s2/rtc_wdt.c +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "soc/rtc_wdt.h" -#include "soc/rtc.h" -#include "soc/efuse_periph.h" - - -bool rtc_wdt_get_protect_status(void) -{ - return READ_PERI_REG(RTC_CNTL_WDTWPROTECT_REG) != RTC_CNTL_WDT_WKEY_VALUE; -} - -void rtc_wdt_protect_off(void) -{ - WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); -} - -void rtc_wdt_protect_on(void) -{ - WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0); -} - - -void rtc_wdt_enable(void) -{ - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP); -} - -void rtc_wdt_flashboot_mode_enable(void) -{ - REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); -} - -void rtc_wdt_disable(void) -{ - bool protect = rtc_wdt_get_protect_status(); - if (protect) { - rtc_wdt_protect_off(); - } - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE2, RTC_WDT_STAGE_ACTION_OFF); - rtc_wdt_set_stage(RTC_WDT_STAGE3, RTC_WDT_STAGE_ACTION_OFF); - REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); - REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN); - if (protect) { - rtc_wdt_protect_on(); - } -} - -void rtc_wdt_feed(void) -{ - bool protect = rtc_wdt_get_protect_status(); - if (protect) { - rtc_wdt_protect_off(); - } - REG_SET_BIT(RTC_CNTL_WDTFEED_REG, RTC_CNTL_WDT_FEED); - if (protect) { - rtc_wdt_protect_on(); - } -} - -static uint32_t get_addr_reg(rtc_wdt_stage_t stage) -{ - uint32_t reg; - if (stage == RTC_WDT_STAGE0) { - reg = RTC_CNTL_WDTCONFIG1_REG; - } else if (stage == RTC_WDT_STAGE1) { - reg = RTC_CNTL_WDTCONFIG2_REG; - } else if (stage == RTC_WDT_STAGE2) { - reg = RTC_CNTL_WDTCONFIG3_REG; - } else { - reg = RTC_CNTL_WDTCONFIG4_REG; - } - return reg; -} - -esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms) -{ - if (stage > 3) { - return ESP_ERR_INVALID_ARG; - } - uint32_t timeout = (uint32_t) ((uint64_t) rtc_clk_slow_freq_get_hz() * timeout_ms / 1000); - if (stage == RTC_WDT_STAGE0) { - timeout = timeout >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL)); - } - WRITE_PERI_REG(get_addr_reg(stage), timeout); - return ESP_OK; -} - -esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms) -{ - if (stage > 3) { - return ESP_ERR_INVALID_ARG; - } - uint32_t time_tick; - time_tick = READ_PERI_REG(get_addr_reg(stage)); - *timeout_ms = time_tick * 1000 / rtc_clk_slow_freq_get_hz(); - - return ESP_OK; -} - -esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel) -{ - if (stage > 3 || stage_sel > 4) { - return ESP_ERR_INVALID_ARG; - } - if (stage == RTC_WDT_STAGE0) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, stage_sel); - } else if (stage == RTC_WDT_STAGE1) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG1, stage_sel); - } else if (stage == RTC_WDT_STAGE2) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG2, stage_sel); - } else { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG3, stage_sel); - } - - return ESP_OK; -} - -esp_err_t rtc_wdt_set_length_of_reset_signal(rtc_wdt_reset_sig_t reset_src, rtc_wdt_length_sig_t reset_signal_length) -{ - if (reset_src > 1 || reset_signal_length > 7) { - return ESP_ERR_INVALID_ARG; - } - if (reset_src == 0) { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, reset_signal_length); - } else { - REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, reset_signal_length); - } - - return ESP_OK; -} - -bool rtc_wdt_is_on(void) -{ - return (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN) != 0) || (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN) != 0); -} diff --git a/components/soc/src/hal/wdt_hal_iram.c b/components/soc/src/hal/wdt_hal_iram.c new file mode 100644 index 000000000..16b4e4ec8 --- /dev/null +++ b/components/soc/src/hal/wdt_hal_iram.c @@ -0,0 +1,200 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "hal/wdt_types.h" +#include "hal/wdt_hal.h" + +/* ---------------------------- Init and Config ----------------------------- */ + +void wdt_hal_init(wdt_hal_context_t *hal, wdt_inst_t wdt_inst, uint32_t prescaler, bool enable_intr) +{ + //Initialize HAL context + memset(hal, 0, sizeof(wdt_hal_context_t)); + if (wdt_inst == WDT_MWDT0) { + hal->mwdt_dev = &TIMERG0; + } else if (wdt_inst == WDT_MWDT1) { + hal->mwdt_dev = &TIMERG1; + } else { + hal->rwdt_dev = &RTCCNTL; + } + hal->inst = wdt_inst; + + if (hal->inst == WDT_RWDT) { + //Unlock RTC WDT + rwdt_ll_write_protect_disable(hal->rwdt_dev); + //Disable RTC WDT, all stages, and all interrupts. + rwdt_ll_disable(hal->rwdt_dev); + rwdt_ll_disable_stage(hal->rwdt_dev, WDT_STAGE0); + rwdt_ll_disable_stage(hal->rwdt_dev, WDT_STAGE1); + rwdt_ll_disable_stage(hal->rwdt_dev, WDT_STAGE2); + rwdt_ll_disable_stage(hal->rwdt_dev, WDT_STAGE3); +#ifdef CONFIG_IDF_TARGET_ESP32 + //Enable or disable level interrupt. Edge interrupt is always disabled. + rwdt_ll_set_edge_intr(hal->rwdt_dev, false); + rwdt_ll_set_level_intr(hal->rwdt_dev, enable_intr); +#else //CONFIG_IDF_TARGET_ESP32S2BETA + //Enable or disable chip reset on timeout, and length of chip reset signal + rwdt_ll_set_chip_reset_width(hal->rwdt_dev, 0); + rwdt_ll_set_chip_reset_en(hal->rwdt_dev, false); +#endif + rwdt_ll_clear_intr_status(hal->rwdt_dev); + rwdt_ll_set_intr_enable(hal->rwdt_dev, enable_intr); + //Set default values + rwdt_ll_set_appcpu_reset_en(hal->rwdt_dev, true); + rwdt_ll_set_procpu_reset_en(hal->rwdt_dev, true); + rwdt_ll_set_pause_in_sleep_en(hal->rwdt_dev, true); + rwdt_ll_set_cpu_reset_length(hal->rwdt_dev, WDT_RESET_SIG_LENGTH_3_2us); + rwdt_ll_set_sys_reset_length(hal->rwdt_dev, WDT_RESET_SIG_LENGTH_3_2us); + //Lock RTC WDT + rwdt_ll_write_protect_enable(hal->rwdt_dev); + } else { + //Unlock WDT + mwdt_ll_write_protect_disable(hal->mwdt_dev); + //Disable WDT and stages. + mwdt_ll_disable(hal->mwdt_dev); + mwdt_ll_disable_stage(hal->mwdt_dev, 0); + mwdt_ll_disable_stage(hal->mwdt_dev, 1); + mwdt_ll_disable_stage(hal->mwdt_dev, 2); + mwdt_ll_disable_stage(hal->mwdt_dev, 3); + //Enable or disable level interrupt. Edge interrupt is always disabled. + mwdt_ll_set_edge_intr(hal->mwdt_dev, false); + mwdt_ll_set_level_intr(hal->mwdt_dev, enable_intr); + mwdt_ll_clear_intr_status(hal->mwdt_dev); + mwdt_ll_set_intr_enable(hal->mwdt_dev, enable_intr); + //Set default values + mwdt_ll_set_cpu_reset_length(hal->mwdt_dev, WDT_RESET_SIG_LENGTH_3_2us); + mwdt_ll_set_sys_reset_length(hal->mwdt_dev, WDT_RESET_SIG_LENGTH_3_2us); + //Set tick period + mwdt_ll_set_prescaler(hal->mwdt_dev, prescaler); + //Lock WDT + mwdt_ll_write_protect_enable(hal->mwdt_dev); + } +} + +void wdt_hal_deinit(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + //Unlock WDT + rwdt_ll_write_protect_disable(hal->rwdt_dev); + //Disable WDT and clear any interrupts + rwdt_ll_feed(hal->rwdt_dev); + rwdt_ll_disable(hal->rwdt_dev); + rwdt_ll_clear_intr_status(hal->rwdt_dev); + rwdt_ll_set_intr_enable(hal->rwdt_dev, false); + //Lock WDT + rwdt_ll_write_protect_enable(hal->rwdt_dev); + } else { + //Unlock WDT + mwdt_ll_write_protect_disable(hal->mwdt_dev); + //Disable WDT and clear/disable any interrupts + mwdt_ll_feed(hal->mwdt_dev); + mwdt_ll_disable(hal->mwdt_dev); + mwdt_ll_clear_intr_status(hal->mwdt_dev); + mwdt_ll_set_intr_enable(hal->mwdt_dev, false); + //Lock WDT + mwdt_ll_write_protect_enable(hal->mwdt_dev); + } + //Deinit HAL context + hal->mwdt_dev = NULL; +} + +void wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_config_stage(hal->rwdt_dev, stage, timeout_ticks, behavior); + } else { + mwdt_ll_config_stage(hal->mwdt_dev, stage, timeout_ticks, behavior); + } +} + +/* -------------------------------- Runtime --------------------------------- */ + +void wdt_hal_write_protect_disable(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_write_protect_disable(hal->rwdt_dev); + } else { + mwdt_ll_write_protect_disable(hal->mwdt_dev); + } +} + +void wdt_hal_write_protect_enable(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_write_protect_enable(hal->rwdt_dev); + } else { + mwdt_ll_write_protect_enable(hal->mwdt_dev); + } +} + +void wdt_hal_enable(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_feed(hal->rwdt_dev); + rwdt_ll_enable(hal->rwdt_dev); + } else { + mwdt_ll_feed(hal->mwdt_dev); + mwdt_ll_enable(hal->mwdt_dev); + } +} + +void wdt_hal_disable(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_disable(hal->rwdt_dev); + } else { + mwdt_ll_disable(hal->mwdt_dev); + } +} + +void wdt_hal_handle_intr(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_feed(hal->rwdt_dev); + rwdt_ll_clear_intr_status(hal->rwdt_dev); + } else { + mwdt_ll_feed(hal->mwdt_dev); + mwdt_ll_clear_intr_status(hal->mwdt_dev); + } +} + +void wdt_hal_feed(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_feed(hal->rwdt_dev); + } else { + mwdt_ll_feed(hal->mwdt_dev); + } +} + +void wdt_hal_set_flashboot_en(wdt_hal_context_t *hal, bool enable) +{ + if (hal->inst == WDT_RWDT) { + rwdt_ll_set_flashboot_en(hal->rwdt_dev, enable); + } else { + mwdt_ll_set_flashboot_en(hal->mwdt_dev, enable); + } +} + +bool wdt_hal_is_enabled(wdt_hal_context_t *hal) +{ + if (hal->inst == WDT_RWDT) { + return rwdt_ll_check_if_enabled(hal->rwdt_dev); + } else { + return mwdt_ll_check_if_enabled(hal->mwdt_dev); + } +} +