如何在ESP32中禁用``中断看门狗''或增加ISR时间限制?

时间:2018-08-08 15:25:28

标签: arduino arduino-ide adafruit esp32

我正在使用 ESP32 DEVKIT link Adafruit VS1053编解码器+ MicroSD Breakout-MP3 / WAV / MIDI / OGG播放+录音-v4 {{3 }}录制然后播放声音。我正在使用Arduino IDE进行编码。

我现在面临一个问题,该模块出于播放目的使用硬件中断。但是当我尝试播放音轨时,ESP32会一次又一次地重置。调试日志显示:

Guru Meditation Error: Core  1 panic'ed (Interrupt wdt timeout on CPU1)
Core 1 register dump:
PC      : 0x400d1280  PS      : 0x00060834  A0      : 0x800d128f  A1      : 0x3ffc0bb0  
A2      : 0x3ffc241c  A3      : 0x3ffb1f20  A4      : 0x800d1779  A5      : 0x3ffb1f00  
A6      : 0x3ffc241c  A7      : 0x3f400f9c  A8      : 0x800d1280  A9      : 0x3ffc0b90  
A10     : 0x0000002b  A11     : 0x3f401067  A12     : 0x800d1691  A13     : 0x3ffb1ed0  
A14     : 0x3ffc241c  A15     : 0x00000000  SAR     : 0x0000001f  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  
Core 1 was running in ISR context:
EPC1    : 0x400d4123  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x400d1280

Backtrace: 0x400d1280:0x3ffc0bb0 0x400d128c:0x3ffc0bd0 0x40080e21:0x3ffc0bf0 0x400817d5:0x3ffc0c10 0x400d3ae5:0x00000000

Core 0 register dump:
PC      : 0x400ee86e  PS      : 0x00060934  A0      : 0x8008656c  A1      : 0x3ffc7910  
A2      : 0x00000008  A3      : 0x00000000  A4      : 0x00000001  A5      : 0x3ffc7f4c  
A6      : 0x00000000  A7      : 0x00000001  A8      : 0x3ffc3404  A9      : 0x3ffc33e8  
A10     : 0x00000000  A11     : 0x00000001  A12     : 0x00000000  A13     : 0x00000001  
A14     : 0x00060b20  A15     : 0x00000000  SAR     : 0x00000000  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  

Backtrace: 0x400ee86e:0x3ffc7910 0x40086569:0x3ffc7930

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:952
load:0x40078000,len:6084
load:0x40080000,len:7936
entry 0x40080310
Adafruit VS1053 Simple Test
VS1053 found

Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)行表示其中断为wdt。

我搜索了禁用中断WDT的方法,但没有帮助。 esp_int_wdt.h中的文件~Documents\Arduino\hardware\espressif\esp32\tools\sdk\include\esp32提供了两个功能,用于为两个或一个CPU启用中断WDT。没有禁用它的功能。

如何禁用ESP32中断WDT?

4 个答案:

答案 0 :(得分:4)

看门狗定时器在系统稳定性中起着重要作用。

不要禁用看门狗定时器,而要确保不要在loop()停留太长时间。您应该始终对代码进行结构设计,以使您在loop()中所做的工作最少,然后让它返回。当它返回支持您ESP32应用程序的软件时,它将执行重要的内务处理任务,并重置看门狗计时器。

例如,您永远不要写:

void loop() {
  while(1) {
    do_some_work();
  }
}

相反,您应该写:

void loop() {
  do_some_work();
}

如果您绝对必须在loop()中完成比监视程序计时器所允许的更多工作,请确保偶尔从代码中调用yield()delay();这将使系统赶上它需要做的事情。 yield()将在完成所有必要的客房整理工作后立即返回;完成所有必要的工作后,delay(milliseconds)将返回milliseconds

所以不要写

void loop() {
  unsigned long start_time = millis();

  while(millis() - start_time < 10*1000) { }

  do_some_work();
}

这将导致看门狗定时器关闭,而您想写

void loop() {
  delay(10*1000);

  do_some_work();
  start_time = millis();
}

甚至更好,如果您的循环可能满足了多种需求:

void loop() {
  static unsigned long start_time1 = millis();
  static unsigned long start_time2 = millis();

  if(millis() - start_time >= 10*1000) {
    do_some_work1();
    start_time1 = millis();
  }

  if(millis() - start_time >= 20*1000) {
    do_some_work2();
    start_time2 = millis();
  }
}

答案 1 :(得分:1)

我不知道如何使用arduino禁用监视程序,但是我可以告诉您如何使用esp-idf及其make menuconfig

禁用监视程序。
  1. 打开menuconfig:make menuconfig
  2. 输入component config
  3. 输入ESP32-specific
  4. interrupt watchdog删除星星

P.S。根据{{​​3}},void esp_int_wdt_init()用于初始化中断看门狗。在IWDT中启用menuconfig时将调用此函数。因此,您可以尝试找到此函数的调用并将其删除;)

但是: 我建议您不要禁用看门狗。取而代之的是,尝试使用FreeRTOS任务在中断时执行大量代码。

我不确定如何在arduino平台上完全做到这一点,但我可以告诉我如何使用esp-idf

首先,创建带有签名void f(void*)的中断处理程序

void MyHandler(void* pData){
    /* Your code here */
    vTaskDelete(NULL); // delete current taks, must have
}

第二,您必须在中断处理程序中使用xTaskCreatexTaskCreatePinnedToCore创建新任务。例如,xTaskCreate(MyHandler, "int_handler", 256, NULL, 4, NULL);(签出esp-idf docs

仅此而已,现在您可以在中断上运行大代码了。除此之外,我建议您不要创建太多任务。系统可能会挂起。

P.S。如果您需要每秒处理大量中断请求,请尝试使用api reference

答案 2 :(得分:0)

#include "soc/rtc_wdt.h"

rtc_wdt_protect_off();
rtc_wdt_disable();

或在menuconfig中将其关闭。我也同意其他海报,但是您不应将其关闭,而应使用以下功能:

rtc_wdt_feed();

我通常创建一个最低优先级的FreeRTOS任务,该任务仅循环并以小于超时的延迟调用feed方法,从而为足够高的优先级“业务逻辑”运行留出足够的时间。示例:

在menuconfig或代码中将超时设置为250毫秒:

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);
tc_wdt_set_time(RTC_WDT_STAGE0, 250);

然后在您的任务中执行此操作:

while(true) {
    rtc_wdt_feed();
    vTaskDelay(pdMS_TO_TICKS(100));
}

这将同时馈送FreeRTOS WDT和RTC WDT并在系统陷入循环中或在您的时间要求内未处理时重置系统。您需要处理超时问题以及需要多长时间喂一次定时器才能使它正确地适用于您的系统。请注意,Wifi,PHY和BT并不确定,因此,如果您选择定时,则将有很多不确定性取决于“网络”中的DAQ。

答案 3 :(得分:0)

我遇到了类似的问题。尽管我没有解决方案,但是我可以在Arduino + ESP32中进行确认,但以上答案似乎都无法解决这个问题。 特别是:

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);
tc_wdt_set_time(RTC_WDT_STAGE0, 250);`

然后在您的任务中执行此操作:

while(true) {
    rtc_wdt_feed();
    vTaskDelay(pdMS_TO_TICKS(100));
}

尽管可以很好地编译,但它似乎以一种非常可靠的方式根本没有任何作用。

实际上,我可以触发WDT超时,并且完全可以重现,所以我认为WDT超时根本不会增加,也不会给WDT供食。

我怀疑loop();(特定于arduino的任务)中的任何内容都不能希望更改,禁用或以任何方式篡改看门狗。另外,yield();delay(nnn);似乎什么也没做,无论我放置在哪里,无论我放置在其中多少个。