mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/wdts' into 'master'
Feature/wdts This adds two watchdogs to esp-idf: - An interrupt watchdog. Kicks in if the FreeRTOS timer interupt on either the PRO_CPU or (when configured) the APP CPU isn't called for a configurable time. Panics, displaying which CPU caused the problem and the registers that may lead to the offending code. - A task watchdog. A task has to feed it every once in a while. If not, it will print the name of the offending tasks, as well as the tasks currently running on both CPUs, and optionally panic. Also adds a panic reason to the panic call, as well as fixes the panic code a bit. See merge request !148
This commit is contained in:
commit
38c6256db9
@ -81,8 +81,10 @@ config TRACEMEM_RESERVE_DRAM
|
||||
default 0x4000 if MEMMAP_TRACEMEM && !MEMMAP_TRACEMEM_TWOBANKS
|
||||
default 0x0
|
||||
|
||||
# Not implemented and/or needs new silicon rev to work
|
||||
config MEMMAP_SPISRAM
|
||||
bool "Use external SPI SRAM chip as main memory"
|
||||
depends on ESP32_NEEDS_NEW_SILICON_REV
|
||||
default "n"
|
||||
help
|
||||
The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the
|
||||
@ -152,4 +154,171 @@ config ULP_COPROC_RESERVE_MEM
|
||||
default 0
|
||||
depends on !ULP_COPROC_ENABLED
|
||||
|
||||
|
||||
choice ESP32_PANIC
|
||||
prompt "Panic handler behaviour"
|
||||
default FREERTOS_PANIC_PRINT_REBOOT
|
||||
help
|
||||
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
|
||||
invoked. Configure the panic handlers action here.
|
||||
|
||||
config ESP32_PANIC_PRINT_HALT
|
||||
bool "Print registers and halt"
|
||||
help
|
||||
Outputs the relevant registers over the serial port and halt the
|
||||
processor. Needs a manual reset to restart.
|
||||
|
||||
config ESP32_PANIC_PRINT_REBOOT
|
||||
bool "Print registers and reboot"
|
||||
help
|
||||
Outputs the relevant registers over the serial port and immediately
|
||||
reset the processor.
|
||||
|
||||
config ESP32_PANIC_SILENT_REBOOT
|
||||
bool "Silent reboot"
|
||||
help
|
||||
Just resets the processor without outputting anything
|
||||
|
||||
config ESP32_PANIC_GDBSTUB
|
||||
bool "Invoke GDBStub"
|
||||
help
|
||||
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
|
||||
of the crash.
|
||||
endchoice
|
||||
|
||||
config ESP32_DEBUG_OCDAWARE
|
||||
bool "Make exception and panic handlers JTAG/OCD aware"
|
||||
default y
|
||||
help
|
||||
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
|
||||
instead of panicking, have the debugger stop on the offending instruction.
|
||||
|
||||
|
||||
config INT_WDT
|
||||
bool "Interrupt watchdog"
|
||||
default y
|
||||
help
|
||||
This watchdog timer can detect if the FreeRTOS tick interrupt has not been called for a certain time,
|
||||
either because a task turned off interrupts and did not turn them on for a long time, or because an
|
||||
interrupt handler did not return. It will try to invoke the panic handler first and failing that
|
||||
reset the SoC.
|
||||
|
||||
config INT_WDT_TIMEOUT_MS
|
||||
int "Interrupt watchdog timeout (ms)"
|
||||
depends on INT_WDT
|
||||
default 10
|
||||
range 10 10000
|
||||
help
|
||||
The timeout of the watchdog, in miliseconds. Make this higher than the FreeRTOS tick rate.
|
||||
|
||||
config INT_WDT_CHECK_CPU1
|
||||
bool "Also watch CPU1 tick interrupt"
|
||||
depends on INT_WDT && !FREERTOS_UNICORE
|
||||
default y
|
||||
help
|
||||
Also detect if interrupts on CPU 1 are disabled for too long.
|
||||
|
||||
config TASK_WDT
|
||||
bool "Task watchdog"
|
||||
default y
|
||||
help
|
||||
This watchdog timer can be used to make sure individual tasks are still running.
|
||||
|
||||
config TASK_WDT_PANIC
|
||||
bool "Invoke panic handler when Task Watchdog is triggered"
|
||||
depends on TASK_WDT
|
||||
default n
|
||||
help
|
||||
Normally, the Task Watchdog will only print out a warning if it detects it has not
|
||||
been fed. If this is enabled, it will invoke the panic handler instead, which
|
||||
can then halt or reboot the chip.
|
||||
|
||||
config TASK_WDT_TIMEOUT_S
|
||||
int "Task watchdog timeout (seconds)"
|
||||
depends on TASK_WDT
|
||||
range 1 60
|
||||
default 5
|
||||
help
|
||||
Timeout for the task WDT, in seconds.
|
||||
|
||||
config TASK_WDT_CHECK_IDLE_TASK
|
||||
bool "Task watchdog watches CPU0 idle task"
|
||||
depends on TASK_WDT
|
||||
default y
|
||||
help
|
||||
With this turned on, the task WDT can detect if the idle task is not called within the task
|
||||
watchdog timeout period. The idle task not being called usually is a symptom of another
|
||||
task hoarding the CPU. It is also a bad thing because FreeRTOS household tasks depend on the
|
||||
idle task getting some runtime every now and then. Take Care: With this disabled, this
|
||||
watchdog will trigger if no tasks register themselves within the timeout value.
|
||||
|
||||
config TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
bool "Task watchdog also watches CPU1 idle task"
|
||||
depends on TASK_WDT_CHECK_IDLE_TASK && !FREERTOS_UNICORE
|
||||
default y
|
||||
help
|
||||
Also check the idle task that runs on CPU1.
|
||||
|
||||
#The brownout detector code is disabled (by making it depend on a nonexisting symbol) because the current revision of ESP32
|
||||
#silicon has a bug in the brown-out detector, rendering it unusable for resetting the CPU.
|
||||
config BROWNOUT_DET
|
||||
bool "Hardware brownout detect & reset"
|
||||
default y
|
||||
depends on NEEDS_ESP32_NEW_SILICON_REV
|
||||
help
|
||||
The ESP32 has a built-in brownout detector which can detect if the voltage is lower than
|
||||
a specific value. If this happens, it will reset the chip in order to prevent unintended
|
||||
behaviour.
|
||||
|
||||
choice BROWNOUT_DET_LVL_SEL
|
||||
prompt "Brownout voltage level"
|
||||
depends on BROWNOUT_DET
|
||||
default BROWNOUT_DET_LVL_SEL_25
|
||||
help
|
||||
The brownout detector will reset the chip when the supply voltage is below this level.
|
||||
|
||||
#The voltage levels here are estimates, more work needs to be done to figure out the exact voltages
|
||||
#of the brownout threshold levels.
|
||||
config BROWNOUT_DET_LVL_SEL_0
|
||||
bool "2.1V"
|
||||
config BROWNOUT_DET_LVL_SEL_1
|
||||
bool "2.2V"
|
||||
config BROWNOUT_DET_LVL_SEL_2
|
||||
bool "2.3V"
|
||||
config BROWNOUT_DET_LVL_SEL_3
|
||||
bool "2.4V"
|
||||
config BROWNOUT_DET_LVL_SEL_4
|
||||
bool "2.5V"
|
||||
config BROWNOUT_DET_LVL_SEL_5
|
||||
bool "2.6V"
|
||||
config BROWNOUT_DET_LVL_SEL_6
|
||||
bool "2.7V"
|
||||
config BROWNOUT_DET_LVL_SEL_7
|
||||
bool "2.8V"
|
||||
endchoice
|
||||
|
||||
config BROWNOUT_DET_LVL
|
||||
int
|
||||
default 0 if BROWNOUT_DET_LVL_SEL_0
|
||||
default 1 if BROWNOUT_DET_LVL_SEL_1
|
||||
default 2 if BROWNOUT_DET_LVL_SEL_2
|
||||
default 3 if BROWNOUT_DET_LVL_SEL_3
|
||||
default 4 if BROWNOUT_DET_LVL_SEL_4
|
||||
default 5 if BROWNOUT_DET_LVL_SEL_5
|
||||
default 6 if BROWNOUT_DET_LVL_SEL_6
|
||||
default 7 if BROWNOUT_DET_LVL_SEL_7
|
||||
|
||||
|
||||
config BROWNOUT_DET_RESETDELAY
|
||||
int "Brownout reset delay (in uS)"
|
||||
depends on BROWNOUT_DET
|
||||
range 0 6820
|
||||
default 1000
|
||||
help
|
||||
The brownout detector can reset the chip after a certain delay, in order to make sure e.g. a voltage dip has entirely passed
|
||||
before trying to restart the chip. You can set the delay here.
|
||||
|
||||
|
||||
|
||||
|
||||
endmenu
|
||||
|
39
components/esp32/brownout.c
Normal file
39
components/esp32/brownout.c
Normal file
@ -0,0 +1,39 @@
|
||||
// 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 <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
|
||||
#if CONFIG_BROWNOUT_DET
|
||||
/*
|
||||
This file is included in esp-idf, but the menuconfig option for this is disabled because a silicon bug
|
||||
prohibits the brownout detector from functioning correctly on the ESP32.
|
||||
*/
|
||||
|
||||
void esp_brownout_init() {
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG,
|
||||
RTC_CNTL_BROWN_OUT_ENA | (CONFIG_BROWNOUT_DET_LVL << RTC_CNTL_DBROWN_OUT_THRES_S) |
|
||||
RTC_CNTL_BROWN_OUT_RST_ENA | (((CONFIG_BROWNOUT_DET_RESETDELAY*150)/1000) << RTC_CNTL_BROWN_OUT_RST_WAIT_S) |
|
||||
RTC_CNTL_BROWN_OUT_PD_RF_ENA|RTC_CNTL_BROWN_OUT_CLOSE_FLASH_ENA);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -43,6 +43,9 @@
|
||||
#include "esp_ipc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_brownout.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "trax.h"
|
||||
|
||||
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
|
||||
@ -99,6 +102,10 @@ void IRAM_ATTR call_start_cpu0()
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
|
||||
|
||||
//Un-stall the app cpu; the panic handler may have stalled it.
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
//Enable clock gating and reset the app cpu.
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
|
||||
@ -144,10 +151,20 @@ void start_cpu0_default(void)
|
||||
#endif
|
||||
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
|
||||
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
|
||||
#if CONFIG_BROWNOUT_DET
|
||||
esp_brownout_init();
|
||||
#endif
|
||||
#if CONFIG_INT_WDT
|
||||
esp_int_wdt_init();
|
||||
#endif
|
||||
#if CONFIG_TASK_WDT
|
||||
esp_task_wdt_init();
|
||||
#endif
|
||||
ets_setup_syscalls();
|
||||
do_global_ctors();
|
||||
esp_ipc_init();
|
||||
spi_flash_init();
|
||||
|
||||
xTaskCreatePinnedToCore(&main_task, "main",
|
||||
ESP_TASK_MAIN_STACK, NULL,
|
||||
ESP_TASK_MAIN_PRIO, NULL, 0);
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#include "gdbstub.h"
|
||||
#include "esp_gdbstub.h"
|
||||
|
||||
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
|
||||
//implies a minimum size of about 320 bytes.
|
21
components/esp32/include/esp_brownout.h
Normal file
21
components/esp32/include/esp_brownout.h
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef __ESP_BROWNOUT_H
|
||||
#define __ESP_BROWNOUT_H
|
||||
|
||||
void esp_brownout_init();
|
||||
|
||||
#endif
|
@ -17,6 +17,6 @@
|
||||
#include <xtensa/config/core.h>
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
void gdbstubPanicHandler(XtExcFrame *frame);
|
||||
void esp_gdbstub_panic_handler(XtExcFrame *frame);
|
||||
|
||||
#endif
|
60
components/esp32/include/esp_int_wdt.h
Normal file
60
components/esp32/include/esp_int_wdt.h
Normal file
@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
#ifndef __ESP_INT_WDT_H
|
||||
#define __ESP_INT_WDT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @addtogroup Watchdog_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
This routine enables a watchdog to catch instances of processes disabling
|
||||
interrupts for too long, or code within interrupt handlers taking too long.
|
||||
It does this by setting up a watchdog which gets fed from the FreeRTOS
|
||||
task switch interrupt. When this watchdog times out, initially it will call
|
||||
a high-level interrupt routine that will panic FreeRTOS in order to allow
|
||||
for forensic examination of the state of the CPU. When this interrupt
|
||||
handler is not called and the watchdog times out a second time, it will
|
||||
reset the SoC.
|
||||
|
||||
This uses the TIMERG1 WDT.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the interrupt watchdog. This is called in the init code if
|
||||
* the interrupt watchdog is enabled in menuconfig.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_int_wdt_init();
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
21
components/esp32/include/esp_panic.h
Normal file
21
components/esp32/include/esp_panic.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
|
||||
#define PANIC_RSN_NONE 0
|
||||
#define PANIC_RSN_DEBUGEXCEPTION 1
|
||||
#define PANIC_RSN_DOUBLEEXCEPTION 2
|
||||
#define PANIC_RSN_KERNELEXCEPTION 3
|
||||
#define PANIC_RSN_COPROCEXCEPTION 4
|
||||
#define PANIC_RSN_INTWDT_CPU0 5
|
||||
#define PANIC_RSN_INTWDT_CPU1 6
|
||||
#define PANIC_RSN_MAX 6
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
void esp_set_breakpoint_if_jtag(void *fn);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
83
components/esp32/include/esp_task_wdt.h
Normal file
83
components/esp32/include/esp_task_wdt.h
Normal file
@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
|
||||
#ifndef __ESP_TASK_WDT_H
|
||||
#define __ESP_TASK_WDT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/** \defgroup Watchdog_APIs Watchdog APIs
|
||||
* @brief Watchdog APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup Watchdog_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
This routine enables a more general-purpose task watchdog: tasks can individually
|
||||
feed the watchdog and the watchdog will bark if one or more tasks haven't fed the
|
||||
watchdog within the specified time. Optionally, the idle tasks can also configured
|
||||
to feed the watchdog in a similar fashion, to detect CPU starvation.
|
||||
|
||||
This uses the TIMERG0 WDT.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the task watchdog. This is called in the init code, if the
|
||||
* task watchdog is enabled in menuconfig.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_task_wdt_init();
|
||||
|
||||
/**
|
||||
* @brief Feed the watchdog. After the first feeding session, the watchdog will expect the calling
|
||||
* task to keep feeding the watchdog until task_wdt_delete() is called.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
|
||||
void esp_task_wdt_feed();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Delete the watchdog for the current task.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void esp_task_wdt_delete();
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -14,6 +14,9 @@
|
||||
#ifndef _SOC_RTC_CNTL_REG_H_
|
||||
#define _SOC_RTC_CNTL_REG_H_
|
||||
|
||||
/* 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
|
||||
|
||||
|
||||
#include "soc.h"
|
||||
#define RTC_CNTL_OPTIONS0_REG (DR_REG_RTCCNTL_BASE + 0x0)
|
||||
|
@ -15,6 +15,16 @@
|
||||
#define __TIMG_REG_H__
|
||||
#include "soc.h"
|
||||
|
||||
/* The value that needs to be written to TIMG_WDT_WKEY to write-enable the wdt registers */
|
||||
#define TIMG_WDT_WKEY_VALUE 0x50D83AA1
|
||||
|
||||
/* Possible values for TIMG_WDT_STGx */
|
||||
#define TIMG_WDT_STG_SEL_OFF 0
|
||||
#define TIMG_WDT_STG_SEL_INT 1
|
||||
#define TIMG_WDT_STG_SEL_RESET_CPU 2
|
||||
#define TIMG_WDT_STG_SEL_RESET_SYSTEM 3
|
||||
|
||||
|
||||
#define REG_TIMG_BASE(i) (DR_REG_TIMERGROUP0_BASE + i*0x1000)
|
||||
#define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)
|
||||
/* TIMG_T0_EN : R/W ;bitpos:[31] ;default: 1'h0 ; */
|
||||
|
95
components/esp32/int_wdt.c
Normal file
95
components/esp32/int_wdt.c
Normal file
@ -0,0 +1,95 @@
|
||||
// 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 "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.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
|
||||
#include "esp_int_wdt.h"
|
||||
|
||||
#if CONFIG_INT_WDT
|
||||
|
||||
|
||||
#define WDT_INT_NUM 24
|
||||
|
||||
|
||||
void esp_int_wdt_init() {
|
||||
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_timers.wdt=1;
|
||||
TIMERG1.int_ena.wdt=1;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
//Take care: the tick hook can also be called before esp_int_wdt_init() is called.
|
||||
#if CONFIG_INT_WDT_CHECK_CPU1
|
||||
//Not static; the ISR assembly checks this.
|
||||
bool int_wdt_app_cpu_ticked=false;
|
||||
|
||||
void vApplicationTickHook(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_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
int_wdt_app_cpu_ticked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void vApplicationTickHook(void) {
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -25,8 +25,12 @@
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
|
||||
#include "esp_gdbstub.h"
|
||||
#include "esp_panic.h"
|
||||
|
||||
#include "gdbstub.h"
|
||||
|
||||
/*
|
||||
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
|
||||
@ -34,7 +38,7 @@ task switching / interrupt code runs into an unrecoverable error. The default ta
|
||||
overflow handler also is in here.
|
||||
*/
|
||||
|
||||
#if !CONFIG_FREERTOS_PANIC_SILENT_REBOOT
|
||||
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
//printf may be broken, so we fix our own printing fns...
|
||||
inline static void panicPutchar(char c) {
|
||||
while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
|
||||
@ -104,22 +108,22 @@ void commonErrorHandler(XtExcFrame *frame);
|
||||
static void haltOtherCore() {
|
||||
if (xPortGetCoreID()==0) {
|
||||
//Kill app cpu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C1<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C0<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||
} else {
|
||||
//Kill pro cpu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C1<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C0<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||
}
|
||||
}
|
||||
|
||||
//Returns true when a debugger is attached using JTAG.
|
||||
static int inOCDMode() {
|
||||
#if CONFIG_FREERTOS_DEBUG_OCDAWARE
|
||||
#if CONFIG_ESP32_DEBUG_OCDAWARE
|
||||
int dcr;
|
||||
int reg=0x10200C; //DSRSET register
|
||||
asm("rer %0,%1":"=r"(dcr):"r"(reg));
|
||||
@ -130,10 +134,26 @@ static int inOCDMode() {
|
||||
}
|
||||
|
||||
void panicHandler(XtExcFrame *frame) {
|
||||
int *regs=(int*)frame;
|
||||
//Please keep in sync with PANIC_RSN_* defines
|
||||
const char *reasons[]={
|
||||
"Unknown reason",
|
||||
"Unhandled debug exception",
|
||||
"Double exception",
|
||||
"Unhandled kernel exception",
|
||||
"Coprocessor exception",
|
||||
"Interrupt wdt timeout on CPU0",
|
||||
"Interrupt wdt timeout on CPU1",
|
||||
};
|
||||
const char *reason=reasons[0];
|
||||
//The panic reason is stored in the EXCCAUSE register.
|
||||
if (regs[20]<=PANIC_RSN_MAX) reason=reasons[regs[20]];
|
||||
haltOtherCore();
|
||||
panicPutStr("Guru Meditation Error: Core ");
|
||||
panicPutDec(xPortGetCoreID());
|
||||
panicPutStr(" panic'ed.\r\n");
|
||||
panicPutStr(" panic'ed (");
|
||||
panicPutStr(reason);
|
||||
panicPutStr(")\r\n");
|
||||
|
||||
if (inOCDMode()) {
|
||||
asm("break.n 1");
|
||||
@ -175,6 +195,44 @@ void xt_unhandled_exception(XtExcFrame *frame) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
|
||||
an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
|
||||
the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
|
||||
all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
|
||||
one second.
|
||||
*/
|
||||
static void reconfigureAllWdts() {
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
|
||||
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||
TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
|
||||
TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||
TIMERG0.wdt_config2=2000; //1 second before reset
|
||||
TIMERG0.wdt_config0.en=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
//Disable wdt 1
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en=0;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT
|
||||
/*
|
||||
This disables all the watchdogs for when we call the gdbstub.
|
||||
*/
|
||||
static void disableAllWdts() {
|
||||
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;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
|
||||
serial port and either jump to the gdb stub, halt the CPU or reboot.
|
||||
@ -187,6 +245,9 @@ void commonErrorHandler(XtExcFrame *frame) {
|
||||
"A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
|
||||
"A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
|
||||
|
||||
//Feed the watchdogs, so they will give us time to print out debug info
|
||||
reconfigureAllWdts();
|
||||
|
||||
panicPutStr("Register dump:\r\n");
|
||||
|
||||
for (x=0; x<24; x+=4) {
|
||||
@ -200,21 +261,23 @@ void commonErrorHandler(XtExcFrame *frame) {
|
||||
}
|
||||
panicPutStr("\r\n");
|
||||
}
|
||||
#if CONFIG_FREERTOS_PANIC_GDBSTUB
|
||||
#if CONFIG_ESP32_PANIC_GDBSTUB
|
||||
disableAllWdts();
|
||||
panicPutStr("Entering gdb stub now.\r\n");
|
||||
gdbstubPanicHandler(frame);
|
||||
#elif CONFIG_FREERTOS_PANIC_PRINT_REBOOT || CONFIG_FREERTOS_PANIC_SILENT_REBOOT
|
||||
esp_gdbstub_panic_handler(frame);
|
||||
#elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
panicPutStr("Rebooting...\r\n");
|
||||
for (x=0; x<100; x++) ets_delay_us(1000);
|
||||
software_reset();
|
||||
#else
|
||||
disableAllWdts();
|
||||
panicPutStr("CPU halted.\r\n");
|
||||
while(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void setBreakpointIfJtag(void *fn) {
|
||||
void esp_set_breakpoint_if_jtag(void *fn) {
|
||||
if (!inOCDMode()) return;
|
||||
setFirstBreakpoint((uint32_t)fn);
|
||||
}
|
173
components/esp32/task_wdt.c
Normal file
173
components/esp32/task_wdt.c
Normal file
@ -0,0 +1,173 @@
|
||||
// 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 <esp_types.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
#if CONFIG_TASK_WDT
|
||||
|
||||
static const char* TAG = "task_wdt";
|
||||
|
||||
typedef struct wdt_task_t wdt_task_t;
|
||||
struct wdt_task_t {
|
||||
TaskHandle_t task_handle;
|
||||
bool fed_watchdog;
|
||||
wdt_task_t *next;
|
||||
};
|
||||
|
||||
static wdt_task_t *wdt_task_list=NULL;
|
||||
|
||||
static void IRAM_ATTR task_wdt_isr(void *arg) {
|
||||
wdt_task_t *wdttask;
|
||||
const char *cpu;
|
||||
//Feed the watchdog so we do not reset
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
//Ack interrupt
|
||||
TIMERG0.int_clr_timers.wdt=1;
|
||||
//Watchdog got triggered because at least one task did not report in.
|
||||
ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n");
|
||||
for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
|
||||
if (!wdttask->fed_watchdog) {
|
||||
cpu=xTaskGetAffinity(wdttask->task_handle)==0?"CPU 0":"CPU 1";
|
||||
if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu="CPU 0/1";
|
||||
printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu);
|
||||
}
|
||||
}
|
||||
ets_printf("Tasks currently running:\n");
|
||||
for (int x=0; x<portNUM_PROCESSORS; x++) {
|
||||
ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
|
||||
}
|
||||
|
||||
#if CONFIG_TASK_WDT_PANIC
|
||||
ets_printf("Aborting.\n");
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void esp_task_wdt_feed() {
|
||||
wdt_task_t *wdttask=wdt_task_list;
|
||||
bool found_task=false, do_feed_wdt=true;
|
||||
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||
//Walk the linked list of wdt tasks to find this one, as well as see if we need to feed
|
||||
//the real watchdog timer.
|
||||
for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
|
||||
//See if we are at the current task.
|
||||
if (wdttask->task_handle == handle) {
|
||||
wdttask->fed_watchdog=true;
|
||||
found_task=true;
|
||||
}
|
||||
//If even one task in the list doesn't have the do_feed_wdt var set, we do not feed the watchdog.
|
||||
if (!wdttask->fed_watchdog) do_feed_wdt=false;
|
||||
}
|
||||
|
||||
if (!found_task) {
|
||||
//This is the first time the task calls the task_wdt_feed function. Create a new entry for it in
|
||||
//the linked list.
|
||||
wdt_task_t *newtask=malloc(sizeof(wdt_task_t));
|
||||
memset(newtask, 0, sizeof(wdt_task_t));
|
||||
newtask->task_handle=handle;
|
||||
newtask->fed_watchdog=true;
|
||||
if (wdt_task_list == NULL) {
|
||||
wdt_task_list=newtask;
|
||||
} else {
|
||||
for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) ;
|
||||
wdttask->next=newtask;
|
||||
}
|
||||
}
|
||||
if (do_feed_wdt) {
|
||||
//All tasks have checked in; time to feed the hw watchdog.
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
//Reset fed_watchdog status
|
||||
for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_task_wdt_delete() {
|
||||
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
|
||||
wdt_task_t *wdttask=wdt_task_list;
|
||||
//Wdt task list can't be empty
|
||||
if (!wdt_task_list) {
|
||||
ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?");
|
||||
return;
|
||||
}
|
||||
if (handle==wdt_task_list) {
|
||||
//Current task is first on list.
|
||||
wdt_task_list=wdt_task_list->next;
|
||||
free(wdttask);
|
||||
} else {
|
||||
//Find current task in list
|
||||
while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next;
|
||||
if (!wdttask->next) {
|
||||
ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!");
|
||||
return;
|
||||
}
|
||||
wdt_task_t *freeme=wdttask->next;
|
||||
wdttask->next=wdttask->next->next;
|
||||
free(freeme);
|
||||
}
|
||||
}
|
||||
|
||||
void esp_task_wdt_init() {
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
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=CONFIG_TASK_WDT_TIMEOUT_S*2000; //Set timeout before interrupt
|
||||
TIMERG0.wdt_config3=CONFIG_TASK_WDT_TIMEOUT_S*4000; //Set timeout before reset
|
||||
TIMERG0.wdt_config0.en=1;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
ESP_INTR_DISABLE(ETS_T0_WDT_INUM);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
|
||||
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
|
||||
TIMERG0.int_clr_timers.wdt=1;
|
||||
TIMERG0.int_ena.wdt=1;
|
||||
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
|
||||
}
|
||||
|
||||
#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
|
||||
void vApplicationIdleHook(void) {
|
||||
#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
#endif
|
||||
esp_task_wdt_feed();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -93,45 +93,6 @@ config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
|
||||
|
||||
If using the WiFi stack, this value must be at least 1.
|
||||
|
||||
#This still needs to be implemented.
|
||||
choice FREERTOS_PANIC
|
||||
prompt "Panic handler behaviour"
|
||||
default FREERTOS_PANIC_PRINT_REBOOT
|
||||
help
|
||||
If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is
|
||||
invoked. Configure the panic handlers action here.
|
||||
|
||||
config FREERTOS_PANIC_PRINT_HALT
|
||||
bool "Print registers and halt"
|
||||
help
|
||||
Outputs the relevant registers over the serial port and halt the
|
||||
processor. Needs a manual reset to restart.
|
||||
|
||||
config FREERTOS_PANIC_PRINT_REBOOT
|
||||
bool "Print registers and reboot"
|
||||
help
|
||||
Outputs the relevant registers over the serial port and immediately
|
||||
reset the processor.
|
||||
|
||||
config FREERTOS_PANIC_SILENT_REBOOT
|
||||
bool "Silent reboot"
|
||||
help
|
||||
Just resets the processor without outputting anything
|
||||
|
||||
config FREERTOS_PANIC_GDBSTUB
|
||||
bool "Invoke GDBStub"
|
||||
help
|
||||
Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
|
||||
of the crash.
|
||||
endchoice
|
||||
|
||||
config FREERTOS_DEBUG_OCDAWARE
|
||||
bool "Make exception and panic handlers JTAG/OCD aware"
|
||||
default y
|
||||
help
|
||||
The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
|
||||
instead of panicking, have the debugger stop on the offending instruction.
|
||||
|
||||
choice FREERTOS_ASSERT
|
||||
prompt "FreeRTOS assertions"
|
||||
default FREERTOS_ASSERT_FAIL_ABORT
|
||||
|
@ -152,9 +152,9 @@
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_IDLE_HOOK 0
|
||||
#define configUSE_IDLE_HOOK ( CONFIG_TASK_WDT_CHECK_IDLE_TASK )
|
||||
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configUSE_TICK_HOOK ( CONFIG_INT_WDT )
|
||||
|
||||
#define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ )
|
||||
|
||||
@ -231,6 +231,7 @@
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_uxTaskGetStackHighWaterMark 1
|
||||
#define INCLUDE_pcTaskGetTaskName 1
|
||||
|
||||
#if CONFIG_ENABLE_MEMORY_DEBUG
|
||||
#define configENABLE_MEMORY_DEBUG 1
|
||||
|
@ -1,7 +0,0 @@
|
||||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
void setBreakpointIfJtag(void *fn);
|
||||
|
||||
|
||||
#endif
|
@ -2078,6 +2078,17 @@ TickType_t uxTaskResetEventItemValue( void ) PRIVILEGED_FUNCTION;
|
||||
*/
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return the handle of the task running on a certain CPU. Because of
|
||||
* the nature of SMP processing, there is no guarantee that this
|
||||
* value will still be valid on return and should only be used for
|
||||
* debugging purposes.
|
||||
*/
|
||||
TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid );
|
||||
|
||||
|
||||
/*
|
||||
* Capture the current time status for future reference.
|
||||
*/
|
||||
|
@ -101,7 +101,7 @@
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "panic.h"
|
||||
#include "esp_panic.h"
|
||||
|
||||
/* Defined in portasm.h */
|
||||
extern void _frxt_tick_timer_init(void);
|
||||
@ -375,7 +375,7 @@ portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux) {
|
||||
|
||||
#if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
|
||||
void vPortFirstTaskHook(TaskFunction_t function) {
|
||||
setBreakpointIfJtag(function);
|
||||
esp_set_breakpoint_if_jtag(function);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2161,7 +2161,6 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_pcTaskGetTaskName == 1 )
|
||||
|
||||
char *pcTaskGetTaskName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
TCB_t *pxTCB;
|
||||
@ -2304,6 +2303,23 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||
We can't really calculate what we need, that's done on core 0... just assume we need a switch.
|
||||
ToDo: Make this more intelligent? -- JD
|
||||
*/
|
||||
//We do need the tick hook to satisfy the int watchdog.
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
{
|
||||
/* Guard against the tick hook being called when the pended tick
|
||||
count is being unwound (when the scheduler is being unlocked). */
|
||||
if( uxPendedTicks == ( UBaseType_t ) 0U )
|
||||
{
|
||||
vApplicationTickHook();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* configUSE_TICK_HOOK */
|
||||
|
||||
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
@ -3724,6 +3740,19 @@ TCB_t *pxTCB;
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid )
|
||||
{
|
||||
TaskHandle_t xReturn=NULL;
|
||||
|
||||
//Xtensa-specific: the pxCurrentPCB pointer is atomic so we shouldn't need a lock.
|
||||
if (cpuid < portNUM_PROCESSORS) {
|
||||
xReturn = pxCurrentTCB[ cpuid ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
@ -91,7 +91,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*******************************************************************************/
|
||||
|
||||
#include "xtensa_rtos.h"
|
||||
|
||||
#include "esp_panic.h"
|
||||
#include "sdkconfig.h"
|
||||
/*
|
||||
Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.
|
||||
Please change this when the tcb structure is changed
|
||||
@ -339,12 +340,12 @@ _xt_panic:
|
||||
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
|
||||
s32i a0, sp, XT_STK_A0
|
||||
|
||||
/* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
|
||||
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
|
||||
/* Set up PS for C, disable all interrupts, and clear EXCM. */
|
||||
movi a0, PS_INTLEVEL(7) | PS_UM | PS_WOE
|
||||
wsr a0, PS
|
||||
|
||||
//Call panic handler
|
||||
mov a2,sp
|
||||
mov a6,sp
|
||||
call4 panicHandler
|
||||
|
||||
1: j 1b /* loop infinitely */
|
||||
@ -462,6 +463,8 @@ _DebugExceptionVector:
|
||||
jx a3
|
||||
#else
|
||||
wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */
|
||||
movi a0,PANIC_RSN_DEBUGEXCEPTION
|
||||
wsr a0,EXCCAUSE
|
||||
call0 _xt_panic /* does not return */
|
||||
rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */
|
||||
#endif
|
||||
@ -489,6 +492,8 @@ _DoubleExceptionVector:
|
||||
#if XCHAL_HAVE_DEBUG
|
||||
break 1, 4 /* unhandled double exception */
|
||||
#endif
|
||||
movi a0,PANIC_RSN_DOUBLEEXCEPTION
|
||||
wsr a0,EXCCAUSE
|
||||
call0 _xt_panic /* does not return */
|
||||
rfde /* make a0 point here not later */
|
||||
|
||||
@ -522,6 +527,8 @@ _xt_kernel_exc:
|
||||
#if XCHAL_HAVE_DEBUG
|
||||
break 1, 0 /* unhandled kernel exception */
|
||||
#endif
|
||||
movi a0,PANIC_RSN_KERNELEXCEPTION
|
||||
wsr a0,EXCCAUSE
|
||||
call0 _xt_panic /* does not return */
|
||||
rfe /* make a0 point here not there */
|
||||
|
||||
@ -1024,6 +1031,8 @@ _xt_coproc_exc:
|
||||
#if XCHAL_HAVE_DEBUG
|
||||
break 1, 1 /* unhandled user exception */
|
||||
#endif
|
||||
movi a0,PANIC_RSN_COPROCEXCEPTION
|
||||
wsr a0,EXCCAUSE
|
||||
call0 _xt_panic /* not in a thread (invalid) */
|
||||
/* never returns */
|
||||
|
||||
@ -1607,6 +1616,28 @@ _xt_highint4:
|
||||
ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* On the ESP32, this level is used for the INT_WDT handler. If that triggers, the program is stuck with interrupts
|
||||
off and the CPU should panic. */
|
||||
rsr a0, EXCSAVE_4
|
||||
wsr a0, EXCSAVE_1 /* panic handler reads this register */
|
||||
/* Set EXCCAUSE to reflect cause of the wdt int trigger */
|
||||
movi a0,PANIC_RSN_INTWDT_CPU0
|
||||
wsr a0,EXCCAUSE
|
||||
#if CONFIG_INT_WDT_CHECK_CPU1
|
||||
/* Check if the cause is the app cpu failing to tick.*/
|
||||
movi a0, int_wdt_app_cpu_ticked
|
||||
l32i a0, a0, 0
|
||||
bnez a0, 1f
|
||||
/* It is. Modify cause. */
|
||||
movi a0,PANIC_RSN_INTWDT_CPU1
|
||||
wsr a0,EXCCAUSE
|
||||
1:
|
||||
#endif
|
||||
call0 _xt_panic
|
||||
|
||||
|
||||
.align 4
|
||||
.L_xt_highint4_exit:
|
||||
rsr a0, EXCSAVE_4 /* restore a0 */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user