فهرست منبع

WDT: Add LL and HAL for watchdog timers

This commit updates the watchdog timers (MWDT and RWDT)
in the following ways:

- Add seprate LL for MWDT and RWDT.
- Add a combined WDT HAL for all Watchdog Timers
- Update int_wdt.c and task_wdt.c to use WDT HAL
- Remove most dependencies on LL or direct register access
  in other components. They will now use the WDT HAL
- Update use of watchdogs (including RTC WDT) in bootloader and
  startup code to use the HAL layer.
Darian Leung 6 سال پیش
والد
کامیت
91841a53ff
51فایلهای تغییر یافته به همراه2017 افزوده شده و 1629 حذف شده
  1. 11 9
      components/app_trace/gcov/gcov_rtio.c
  2. 1 1
      components/bootloader/subproject/main/ld/esp32/bootloader.ld
  3. 1 1
      components/bootloader/subproject/main/ld/esp32s2/bootloader.ld
  4. 26 15
      components/bootloader_support/src/bootloader_init.c
  5. 5 2
      components/bootloader_support/src/esp32/flash_encrypt.c
  6. 1 3
      components/esp32/CMakeLists.txt
  7. 13 9
      components/esp32/clk.c
  8. 10 3
      components/esp32/cpu_start.c
  9. 0 113
      components/esp32/int_wdt.c
  10. 12 11
      components/esp32/sleep_modes.c
  11. 19 17
      components/esp32/system_api_esp32.c
  12. 1 3
      components/esp32s2/CMakeLists.txt
  13. 13 9
      components/esp32s2/clk.c
  14. 9 3
      components/esp32s2/cpu_start.c
  15. 0 86
      components/esp32s2/int_wdt.c
  16. 12 11
      components/esp32s2/sleep_modes.c
  17. 21 16
      components/esp32s2/system_api_esp32s2.c
  18. 0 428
      components/esp32s2/task_wdt.c
  19. 3 1
      components/esp_common/CMakeLists.txt
  20. 4 1
      components/esp_common/include/esp_private/system_internal.h
  21. 113 0
      components/esp_common/src/int_wdt.c
  22. 31 33
      components/esp_common/src/task_wdt.c
  23. 43 34
      components/esp_system/panic.c
  24. 8 2
      components/esp_system/port/panic_handler.c
  25. 1 0
      components/soc/CMakeLists.txt
  26. 1 11
      components/soc/include/hal/timer_types.h
  27. 180 0
      components/soc/include/hal/wdt_hal.h
  28. 71 0
      components/soc/include/hal/wdt_types.h
  29. 0 198
      components/soc/include/soc/rtc_wdt.h
  30. 1 0
      components/soc/linker.lf
  31. 9 0
      components/soc/soc/esp32/include/soc/rtc_cntl_reg.h
  32. 2 2
      components/soc/soc/esp32/include/soc/rtc_cntl_struct.h
  33. 5 0
      components/soc/soc/esp32/include/soc/timer_group_caps.h
  34. 9 0
      components/soc/soc/esp32/include/soc/timer_group_reg.h
  35. 10 0
      components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h
  36. 2 0
      components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h
  37. 4 0
      components/soc/soc/esp32s2/include/soc/timer_group_caps.h
  38. 10 0
      components/soc/soc/esp32s2/include/soc/timer_group_reg.h
  39. 3 0
      components/soc/soc/esp32s2/include/soc/timer_group_struct.h
  40. 18 0
      components/soc/soc/include/soc/rtc_cntl_periph.h
  41. 0 1
      components/soc/src/esp32/CMakeLists.txt
  42. 262 0
      components/soc/src/esp32/include/hal/mwdt_ll.h
  43. 297 0
      components/soc/src/esp32/include/hal/rwdt_ll.h
  44. 0 151
      components/soc/src/esp32/include/hal/timer_ll.h
  45. 0 151
      components/soc/src/esp32/rtc_wdt.c
  46. 0 1
      components/soc/src/esp32s2/CMakeLists.txt
  47. 264 0
      components/soc/src/esp32s2/include/hal/mwdt_ll.h
  48. 311 0
      components/soc/src/esp32s2/include/hal/rwdt_ll.h
  49. 0 151
      components/soc/src/esp32s2/include/hal/timer_ll.h
  50. 0 152
      components/soc/src/esp32s2/rtc_wdt.c
  51. 200 0
      components/soc/src/hal/wdt_hal_iram.c

+ 11 - 9
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();

+ 1 - 1
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)

+ 1 - 1
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)

+ 26 - 15
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)

+ 5 - 2
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) {

+ 1 - 3
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")
 

+ 13 - 9
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;

+ 10 - 3
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);

+ 0 - 113
components/esp32/int_wdt.c

@@ -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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include <esp_types.h>
-#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

+ 12 - 11
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;

+ 19 - 17
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);
-
-    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 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);

+ 1 - 3
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")
 

+ 13 - 9
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;

+ 9 - 3
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

+ 0 - 86
components/esp32s2/int_wdt.c

@@ -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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include <esp_types.h>
-#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

+ 12 - 11
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;

+ 21 - 16
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);

+ 0 - 428
components/esp32s2/task_wdt.c

@@ -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 <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include "sdkconfig.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "freertos/queue.h"
-#include "freertos/semphr.h"
-#include <esp_types.h>
-#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; x<portNUM_PROCESSORS; x++) {
-        ESP_EARLY_LOGE(TAG, "CPU %d: %s", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
-    }
-
-    esp_task_wdt_isr_user_handler();
-    if (twdt_config->panic){     //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);
-}
-
-

+ 3 - 1
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)

+ 4 - 1
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.

+ 113 - 0
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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include <esp_types.h>
+#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

+ 31 - 33
components/esp32/task_wdt.c → 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

+ 43 - 34
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 <string.h>
@@ -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);
-
-    //Disable wdt 1
-    timer_ll_wdt_set_protect(&TIMERG1, false);
-    timer_ll_wdt_set_enable(&TIMERG1, false);
-    timer_ll_wdt_set_protect(&TIMERG1, 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 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);
-
-    timer_ll_wdt_set_protect(&TIMERG1, false);
-    timer_ll_wdt_set_enable(&TIMERG1, false);
-    timer_ll_wdt_set_protect(&TIMERG1, 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);
+
+    //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) {

+ 8 - 2
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);
         }
     }
 

+ 1 - 0
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)

+ 1 - 11
components/soc/include/hal/timer_types.h

@@ -22,6 +22,7 @@ extern "C" {
 #include <stdbool.h>
 #include <esp_bit_defs.h>
 #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
  */

+ 180 - 0
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 <stdbool.h>
+#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

+ 71 - 0
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

+ 0 - 198
components/soc/include/soc/rtc_wdt.h

@@ -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 <stdint.h>
-#include <stdbool.h>
-#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

+ 1 - 0
components/soc/linker.lf

@@ -23,3 +23,4 @@ entries:
     lldesc (noflash_text)
     cpu_hal (noflash)
     soc_hal (noflash)
+    wdt_hal_iram (noflash)

+ 9 - 0
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)

+ 2 - 2
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*/

+ 5 - 0
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)

+ 9 - 0
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)

+ 10 - 0
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

+ 2 - 0
components/soc/soc/esp32s2/include/soc/rtc_cntl_struct.h

@@ -20,6 +20,8 @@
 extern "C" {
 #endif
 
+#include <stdint.h>
+
 typedef volatile struct {
     union {
         struct {

+ 4 - 0
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)

+ 10 - 0
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: */

+ 3 - 0
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 <stdint.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 18 - 0
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"

+ 0 - 1
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")
 

+ 262 - 0
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 <stdint.h>
+#include <stdbool.h>
+#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

+ 297 - 0
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 <stdlib.h>
+#include <stdbool.h>
+#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

+ 0 - 151
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

+ 0 - 151
components/soc/src/esp32/rtc_wdt.c

@@ -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);
-}

+ 0 - 1
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")

+ 264 - 0
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 <stdint.h>
+#include <stdbool.h>
+#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

+ 311 - 0
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 <stdlib.h>
+#include <stdbool.h>
+#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

+ 0 - 151
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

+ 0 - 152
components/soc/src/esp32s2/rtc_wdt.c

@@ -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);
-}

+ 200 - 0
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 <string.h>
+#include <stdbool.h>
+#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);
+    }
+}
+