Merge branch 'feature/esp32s2beta_wdt' into 'feature/esp32s2beta'

esp32s2beta: Re-enable interrupt WDT, RTC_WDT, Task wdt

See merge request espressif/esp-idf!5786
This commit is contained in:
Angus Gratton 2019-09-19 11:10:58 +08:00
commit bcaaaa1632
11 changed files with 259 additions and 118 deletions

View File

@ -13,8 +13,8 @@ MEMORY
{
/* I/O */
dport0_seg (RW) : org = 0x3FF00000, len = 0x10
iram_loader_seg (RWX) : org = 0x40062000, len = 0x2000 /* 8KB, IRAM */
iram_seg (RWX) : org = 0x40064000, len = 0x4000 /* 16KB, IRAM */
iram_loader_seg (RWX) : org = 0x40062000, len = 0x4000 /* 16KB, IRAM */
iram_seg (RWX) : org = 0x40066000, len = 0x4000 /* 16KB, IRAM */
/* 16k at the end of DRAM, before ROM data & stack */
dram_seg (RW) : org = 0x3FFF8000, len = 0x4000
}

View File

@ -189,7 +189,7 @@ static esp_err_t bootloader_main(void)
ets_set_appcpu_boot_addr(0);
#endif
#if CONFIG_BOOTLOADER_WDT_ENABLE && CONFIG_IDF_TARGET_ESP32
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
ESP_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS);
rtc_wdt_protect_off();
rtc_wdt_disable();
@ -199,7 +199,7 @@ static esp_err_t bootloader_main(void)
rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS);
rtc_wdt_enable();
rtc_wdt_protect_on();
#elif CONFIG_IDF_TARGET_ESP32
#else
/* disable watch dog here */
rtc_wdt_disable();
#endif

View File

@ -28,7 +28,8 @@
#include "soc/dport_access.h"
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_wdt.h"
#include "soc/rtc_periph.h"
#include "soc/i2s_reg.h"
#include "driver/periph_ctrl.h"
#include "xtensa/core-macros.h"
@ -63,12 +64,32 @@ void esp_clk_init(void)
rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);
#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
// WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed.
// If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times.
// 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();
#endif
#ifdef CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS
select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL);
#else
select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
#endif
#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();
#endif
uint32_t freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ;
rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M;
switch(freq_mhz) {

View File

@ -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 "driver/rtc_io.h"
#include "freertos/FreeRTOS.h"
@ -311,9 +311,9 @@ void start_cpu0_default(void)
do_global_ctors();
#if CONFIG_ESP_INT_WDT
//esp_int_wdt_init();
//Initialize the interrupt watch dog for CPU0.
//esp_int_wdt_cpu_init();
esp_int_wdt_init();
//Initialize the interrupt watch dog
esp_int_wdt_cpu_init();
#endif
esp_cache_err_int_init();
esp_crosscore_int_init();
@ -368,31 +368,28 @@ static void do_global_ctors(void)
static void main_task(void* args)
{
// Now that the application is about to start, disable boot watchdogs
REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
//Enable allocation in region where the startup stacks were located.
heap_caps_enable_nonos_stack_heaps();
//Initialize task wdt if configured to do so
#ifdef CONFIG_ESP_TASK_WDT_PANIC
//ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true))
ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true));
#elif CONFIG_ESP_TASK_WDT
//ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false))
ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false));
#endif
//Add IDLE 0 to task wdt
// TODO: cpu_start.c: re-enable task WDT - IDF-753
#if 0
#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
if(idle_0 != NULL){
ESP_ERROR_CHECK(esp_task_wdt_add(idle_0))
ESP_ERROR_CHECK(esp_task_wdt_add(idle_0));
}
#endif
#endif
// Now that the application is about to start, disable boot watchdog
#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
rtc_wdt_disable();
#endif
app_main();
vTaskDelete(NULL);
}

View File

@ -1,4 +1,4 @@
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
// 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.
@ -39,38 +39,18 @@
//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) {
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;
int_wdt_app_cpu_ticked=false;
}
}
}
#else
static void IRAM_ATTR tick_hook(void) {
if (xPortGetCoreID()!=0) return;
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;
}
#endif
void esp_int_wdt_init(void) {
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
@ -92,9 +72,9 @@ void esp_int_wdt_init(void) {
void esp_int_wdt_cpu_init(void)
{
esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID());
esp_register_freertos_tick_hook_for_cpu(tick_hook, 0);
ESP_INTR_DISABLE(WDT_INT_NUM);
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, 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.
@ -103,4 +83,4 @@ void esp_int_wdt_cpu_init(void)
#endif
#endif // CONFIG_ESP_INT_WDT

View File

@ -470,32 +470,6 @@ static inline void disableAllWdts(void)
TIMERG1.wdt_wprotect = 0;
}
static void esp_panic_wdt_start(void)
{
if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
return;
}
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_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.
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 7);
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
void esp_panic_wdt_stop(void)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
#if CONFIG_ESP32S2_PANIC_PRINT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT
static void esp_panic_dig_reset(void) __attribute__((noreturn));
@ -628,7 +602,18 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
int core_id = xPortGetCoreID();
// start panic WDT to restart system if we hang in this handler
esp_panic_wdt_start();
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);
// 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();
}
//Feed the watchdogs, so they will give us time to print out debug info
reconfigureAllWdts();
@ -653,7 +638,7 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
#if CONFIG_ESP32S2_PANIC_GDBSTUB
disableAllWdts();
esp_panic_wdt_stop();
rtc_wdt_disable();
panicPutStr("Entering gdb stub now.\r\n");
esp_gdbstub_panic_handler(frame);
#else
@ -674,7 +659,7 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
reconfigureAllWdts();
}
#endif /* CONFIG_ESP32_ENABLE_COREDUMP */
esp_panic_wdt_stop();
rtc_wdt_disable();
#if CONFIG_ESP32S2_PANIC_PRINT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT
panicPutStr("Rebooting...\r\n");
if (frame->exccause != PANIC_RSN_CACHEERR) {

View File

@ -34,6 +34,7 @@
#include "soc/spi_mem_reg.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "soc/rtc_wdt.h"
#include "driver/rtc_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -218,27 +219,6 @@ void IRAM_ATTR esp_deep_sleep_start(void)
}
}
static void rtc_wdt_enable(int time_ms)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_RTC);
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * time_ms / 1000);
SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
static void rtc_wdt_disable(void)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
/**
* Helper function which handles entry to and exit from light sleep
* Placed into IRAM as flash may need some time to be powered on.
@ -305,7 +285,17 @@ 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
rtc_wdt_enable(1000);
bool wdt_was_enabled = rtc_wdt_is_on(); // 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();
}
// Enter sleep, then wait for flash to be ready on wakeup
esp_err_t err = esp_light_sleep_inner(pd_flags,
@ -331,7 +321,9 @@ esp_err_t esp_light_sleep_start(void)
esp_timer_impl_unlock();
DPORT_STALL_OTHER_CPU_END();
rtc_wdt_disable();
if (!wdt_was_enabled) {
rtc_wdt_disable();
}
portEXIT_CRITICAL(&light_sleep_lock);
return err;
}

View File

@ -31,6 +31,7 @@
#include "soc/timer_group_struct.h"
#include "soc/cpu.h"
#include "soc/rtc.h"
#include "soc/rtc_wdt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/xtensa_api.h"
@ -254,14 +255,14 @@ void IRAM_ATTR esp_restart_noos(void)
xt_ints_off(0xFFFFFFFF);
// Enable RTC watchdog for 1 second
REG_WRITE(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
REG_WRITE(RTC_CNTL_WDTCONFIG0_REG,
RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M |
(RTC_WDT_STG_SEL_RESET_SYSTEM << RTC_CNTL_WDT_STG0_S) |
(RTC_WDT_STG_SEL_RESET_RTC << RTC_CNTL_WDT_STG1_S) |
(1 << RTC_CNTL_WDT_SYS_RESET_LENGTH_S) |
(1 << RTC_CNTL_WDT_CPU_RESET_LENGTH_S) );
REG_WRITE(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 1);
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();
// Reset and stall the other CPU.
// CPU must be reset before stalling, in case it was running a s32c1i

View File

@ -28,12 +28,14 @@
#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 "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) ({ \
@ -114,13 +116,24 @@ static void reset_hw_timer(void)
}
}
/*
* 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(&twdt_spinlock);
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)
@ -129,7 +142,7 @@ static void task_wdt_isr(void *arg)
TIMERG0.wdt_wprotect=0;
//Acknowledge interrupt
TIMERG0.int_clr.wdt=1;
//We are taking a spinlock while doing I/O (ets_printf) here. Normally, that is a pretty
//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.
@ -138,26 +151,29 @@ static void task_wdt_isr(void *arg)
ASSERT_EXIT_CRIT_RETURN((twdt_config->list != NULL), VOID_RETURN);
//Watchdog got triggered because at least one task did not reset in time.
ets_printf("Task watchdog got triggered. The following tasks did not reset the watchdog in time:\n");
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");
ets_printf(" - %s (%s)\n", pcTaskGetTaskName(twdttask->task_handle), cpu);
ESP_EARLY_LOGE(TAG, " - %s (%s)", pcTaskGetTaskName(twdttask->task_handle), cpu);
}
}
ets_printf(DRAM_STR("Tasks currently running:\n"));
ESP_EARLY_LOGE(TAG, "%s", DRAM_STR("Tasks currently running:"));
for (int x=0; x<portNUM_PROCESSORS; x++) {
ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(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
ets_printf("Aborting.\n");
portEXIT_CRITICAL(&twdt_spinlock);
ESP_EARLY_LOGE(TAG, "Aborting.");
portEXIT_CRITICAL_ISR(&twdt_spinlock);
// TODO: Add support reset reason for esp32s2beta.
// esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
abort();
}
portEXIT_CRITICAL(&twdt_spinlock);
portEXIT_CRITICAL_ISR(&twdt_spinlock);
}
/*

View File

@ -0,0 +1,148 @@
// 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();
}
}
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);
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);
}

View File

@ -6,6 +6,7 @@ set(SOC_SRCS "cpu_util.c"
"rtc_pm.c"
"rtc_sleep.c"
"rtc_time.c"
"rtc_wdt.c"
"soc_memory_layout.c"
"spi_periph.c"
"ledc_periph.c"