A Third ESP8266 Watchdog, Final Version
June 24, 2018
A Better ESP8266 Loop Watchdog with Better Recovery

I have just finished rewriting the third and final post in French on watchdogs for the ESP8266. Those three posts were not a translation of the three posts on the same subject published in English back in August of 2017 but a complete rewrite. I am overdosing on watchdogs and will not be translating the last three posts anytime soon. So this is a quick introduction to the new version of the loop watchdog library.

Here is the content of mdEspRestart.h, the header file for the mdEspRestart library.

uint8_t restartReason_t; typedef uint16_t restartCount_t; typedef uint32_t restartData_t; #define DEFAULT_RESTART_ADDRESS 0xFF #define LWD_TIMEOUT 12000 #define LOOP_END 0xFFFFFFFF #define REASON_LWD_RST 7 #define REASON_LWD_LOOP_RST 8 #define REASON_LWD_OVW_RST 9 #define REASON_USER_RESET 10 #define REASON_USER_RESTART 11 void lwdtInit(unsigned long timeout = LWD_TIMEOUT); void lwdtStamp(restartData_t data = LOOP_END); void lwdtFeed(void); restartReason_t getRestartReason(restartCount_t &count, restartData_t &data); void userReset(restartData_t data = 0); void userRestart(restartData_t data = 0); bool setRestartRtcAddress(uint8_t addr = DEFAULT_RESTART_ADDRESS);

The loop watchdog must be initialized with the lwdtInit() function usually near the end of the setup() function of the sketch. This function has an optional parameter, the wait time before the watch dog bites in not fed. The default value is LWD_TIMEOUT equal to 12 seconds which is double the wait time of the hardware watchdog of the ESP8266.

The loop watchdog must be fed at the beginning of the loop() function with the lwdtFeed() function. This is the only place where this function should appear. The function lwdtStamp() (or lwdtStamp(LOOP_END)) must be the last statement of the loop() function.

At the start of each important step in the sketch, progress is marked with the lwdtStamp(id) function where id is a unique numeric value between 0 and 2^32-2 = 0xFFFFFFFF-1 = 4,294,967,294. The biggest int is reserved for LOOP_END. I called this value the module identifier because, in my sketches, each task completed in loop() is done by a function that I call a module.

The getRestartReason() function is used near the beginning of the setup() function to handle the startup cycle. It returns the cause of the current restart and the number of consecutive times that the ESP was started for the same reason in the variable count. In addition to the seven codes for restarts already defined in the Espressif SDK, the library adds five. Three are associated with the loop watchdog while two are user initiated ESP reset or restarts. It will be possible to distinguish between a reset and a restart when using the functions userReset() and userRestart() to reboot the ESP. Also those functions provide a simple mechanism to save an int or other 32 bit value in RTC memory before rebooting the ESP. The value is recovered by getRestartReason in the variable data after the reboot.

RaisonValeurDescription
REASON_DEFAULT_RST 0 normal startup by power on
REASON_WDT_RST 1 hardware watch dog reset
REASON_EXCEPTION_RST 2 exception reset
REASON_SOFT_WDT_RST 3 software watch dog reset
REASON_SOFT_RESTART 4 software restart or reset
REASON_DEEP_SLEEP_AWAKE 5 wake from deep sleep
REASON_EXT_SYS_RST 6 external system reset
REASON_LWD_RST 7 loop watch dog reset
REASON_LWD_LOOP_RST 8 loop watch dog reset outside of loop()
REASON_LWD_OVW_RST 9 loop watch dog reset because if was overwritten
REASON_USER_RESET 10 reboot with userReset() (ultimately ESP.reset()) (3
REASON_USER_RESTART 11 reboot with userRestart() (ultimately ESP.restart()) (3

Notes

(1)The data variable contains the exception number.
(2)The data variable contains the last module indentifier entered with lwdtStamp().
(3)The data variable contains the value given as parameter for userReset() or userRestart().

You can download the mdEspRestart.zip library that can be loaded into the Arduino IDE with the library manager (menu: Sketch/Include Library/Add .ZIP Library...).

If you prefer to test it before installing it in the IDE, download esp_boot_lwdt.zip.

For situations where the RTC memory is almost entirely used for other purposes, there is a light version of the library, mdEspRestart.zip (SF = small footprint), which only takes 4 bytes. The esp_boot_lwdt_sf.zip example allows testing before installing in the IDE. To reduce the size of the record, the restartCount_t type is one byte and the restartData_t type occupies only two bytes. Finally, only three bits of restart.reason are used to confirm that restart is valid, the fourth is used as an additional startup reason flag. As a consequence the risk of mistaking garbage RTC memory for a valid restart struct goes from less than 4 hundreth of 1% to around 9.4%.

A Better ESP8266 Loop Watchdog with Better Recovery