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.
This commit is contained in:
parent
e2e4cd1a7f
commit
91841a53ff
51 changed files with 2014 additions and 1626 deletions
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -30,8 +30,7 @@
|
|||
#include "soc/timer_periph.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_wdt.h"
|
||||
#include "hal/timer_ll.h"
|
||||
#include "hal/wdt_hal.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
@ -51,14 +50,14 @@ void IRAM_ATTR esp_restart_noos(void)
|
|||
xt_ints_off(0xFFFFFFFF);
|
||||
|
||||
// Enable RTC watchdog for 1 second
|
||||
rtc_wdt_protect_off();
|
||||
rtc_wdt_disable();
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE1, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_200ns);
|
||||
rtc_wdt_set_time(RTC_WDT_STAGE0, 1000);
|
||||
rtc_wdt_flashboot_mode_enable();
|
||||
wdt_hal_context_t rtc_wdt_ctx;
|
||||
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
|
||||
uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
|
||||
wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
|
||||
// Reset and stall the other CPU.
|
||||
// CPU must be reset before stalling, in case it was running a s32c1i
|
||||
|
@ -72,14 +71,17 @@ void IRAM_ATTR esp_restart_noos(void)
|
|||
// Other core is now stalled, can access DPORT registers directly
|
||||
esp_dport_access_int_abort();
|
||||
|
||||
//Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
|
||||
// Disable TG0/TG1 watchdogs
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true);
|
||||
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
||||
wdt_hal_write_protect_disable(&wdt0_context);
|
||||
wdt_hal_disable(&wdt0_context);
|
||||
wdt_hal_write_protect_enable(&wdt0_context);
|
||||
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
|
||||
wdt_hal_write_protect_disable(&wdt1_context);
|
||||
wdt_hal_disable(&wdt1_context);
|
||||
wdt_hal_write_protect_enable(&wdt1_context);
|
||||
|
||||
// Flush any data left in UART FIFOs
|
||||
uart_tx_wait_idle(0);
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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
components/esp_common/src/int_wdt.c
Normal file
113
components/esp_common/src/int_wdt.c
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
//Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
|
||||
//Reconfigure TWDT (Timer Group 0)
|
||||
wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT0_TICK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
|
||||
wdt_hal_write_protect_disable(&wdt0_context);
|
||||
wdt_hal_config_stage(&wdt0_context, 0, 1000*1000/MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset
|
||||
wdt_hal_enable(&wdt0_context);
|
||||
wdt_hal_write_protect_enable(&wdt0_context);
|
||||
|
||||
//Disable wdt 1
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
//Disable IWDT (Timer Group 1)
|
||||
wdt_hal_write_protect_disable(&wdt1_context);
|
||||
wdt_hal_disable(&wdt1_context);
|
||||
wdt_hal_write_protect_enable(&wdt1_context);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -134,13 +137,16 @@ static void reconfigure_all_wdts(void)
|
|||
*/
|
||||
static inline void disable_all_wdts(void)
|
||||
{
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true);
|
||||
//Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
|
||||
//Task WDT is the Main Watchdog Timer of Timer Group 0
|
||||
wdt_hal_write_protect_disable(&wdt0_context);
|
||||
wdt_hal_disable(&wdt0_context);
|
||||
wdt_hal_write_protect_enable(&wdt0_context);
|
||||
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
//Interupt WDT is the Main Watchdog Timer of Timer Group 1
|
||||
wdt_hal_write_protect_disable(&wdt1_context);
|
||||
wdt_hal_disable(&wdt1_context);
|
||||
wdt_hal_write_protect_enable(&wdt1_context);
|
||||
}
|
||||
|
||||
static void print_abort_details(const void *f)
|
||||
|
@ -224,17 +230,16 @@ void esp_panic_handler(panic_info_t *info)
|
|||
}
|
||||
|
||||
// start panic WDT to restart system if we hang in this handler
|
||||
if (!rtc_wdt_is_on()) {
|
||||
rtc_wdt_protect_off();
|
||||
rtc_wdt_disable();
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
|
||||
rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us);
|
||||
rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
if (!wdt_hal_is_enabled(&rtc_wdt_ctx)) {
|
||||
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
|
||||
uint32_t stage_timeout_ticks = (uint32_t)(7000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
// 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
|
||||
// @ 115200 UART speed it will take more than 6 sec to print them out.
|
||||
rtc_wdt_set_time(RTC_WDT_STAGE0, 7000);
|
||||
rtc_wdt_enable();
|
||||
rtc_wdt_protect_on();
|
||||
wdt_hal_enable(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
|
||||
}
|
||||
|
||||
//Feed the watchdogs, so they will give us time to print out debug info
|
||||
|
@ -264,7 +269,9 @@ void esp_panic_handler(panic_info_t *info)
|
|||
|
||||
#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
|
||||
disable_all_wdts();
|
||||
rtc_wdt_disable();
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
panic_print_str("Entering gdb stub now.\r\n");
|
||||
esp_gdbstub_panic_handler((XtExcFrame*) info->frame);
|
||||
#else
|
||||
|
@ -285,7 +292,9 @@ void esp_panic_handler(panic_info_t *info)
|
|||
reconfigure_all_wdts();
|
||||
}
|
||||
#endif /* CONFIG_ESP32_ENABLE_COREDUMP */
|
||||
rtc_wdt_disable();
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
#if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||
|
||||
if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
components/soc/include/hal/wdt_hal.h
Normal file
180
components/soc/include/hal/wdt_hal.h
Normal file
|
@ -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
components/soc/include/hal/wdt_types.h
Normal file
71
components/soc/include/hal/wdt_types.h
Normal file
|
@ -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
|
|
@ -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
|
|
@ -23,3 +23,4 @@ entries:
|
|||
lldesc (noflash_text)
|
||||
cpu_hal (noflash)
|
||||
soc_hal (noflash)
|
||||
wdt_hal_iram (noflash)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef volatile struct {
|
||||
union {
|
||||
struct {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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
components/soc/soc/include/soc/rtc_cntl_periph.h
Normal file
18
components/soc/soc/include/soc/rtc_cntl_periph.h
Normal file
|
@ -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"
|
|
@ -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
components/soc/src/esp32/include/hal/mwdt_ll.h
Normal file
262
components/soc/src/esp32/include/hal/mwdt_ll.h
Normal file
|
@ -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
components/soc/src/esp32/include/hal/rwdt_ll.h
Normal file
297
components/soc/src/esp32/include/hal/rwdt_ll.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
components/soc/src/esp32s2/include/hal/mwdt_ll.h
Normal file
264
components/soc/src/esp32s2/include/hal/mwdt_ll.h
Normal file
|
@ -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
components/soc/src/esp32s2/include/hal/rwdt_ll.h
Normal file
311
components/soc/src/esp32s2/include/hal/rwdt_ll.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
components/soc/src/hal/wdt_hal_iram.c
Normal file
200
components/soc/src/hal/wdt_hal_iram.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue