|
NetBurner 3.5.8
PDF Version |
Example Path: examples/PlatformSpecific/MODRT1171/Watchdog
Supported Platforms: MODRT1171
This example shows how to use the hardware watchdog on the MODRT1171 module (i.MX RT1171) to automatically recover a hung application by rebooting it. A watchdog is a hardware timer that resets the processor unless the application keeps restarting it ("servicing" it). If the application locks up and stops servicing the watchdog, the timer expires and the module reboots itself back into a working state.
The example is driven by a simple serial menu on the debug console, and on every boot it reports why the module last reset.
Arming and servicing the watchdog is done through a small helper API in src/nbwatchdog.h:
That is the whole idea: arm it once, then call WatchdogService() regularly from healthy code. Stop servicing it (because you crashed or hung) and the module reboots on its own.
Connect a terminal to the debug serial port. The menu:
| Key | Action |
|---|---|
| R | Show why the module last reset |
| E | Arm the watchdog (prompts for a timeout in seconds) |
| F | Service the watchdog once |
| A | Toggle automatic servicing on/off |
| X | Stop servicing -> demonstrate the automatic reboot |
| B | ForceReboot() – a plain software reboot, for comparison |
| ? | Redisplay the menu |
A typical session:
The API is just four calls (all in src/nbwatchdog.h):
Usage is: arm once with a timeout, then service it from healthy code more often than that timeout.
A few rules worth knowing:
WatchdogEnable() arms WDOG1, and an expired timeout performs a full hardware reset of the i.MX RT1171. Verified on this hardware, the module reboots cleanly from that reset, straight back into the application:
not serviced in time -> hardware reset -> automatic reboot back into the application.
The watchdog reset also resets the WDOG block itself, so the module always boots un-armed – an application that arms the watchdog can never trap itself in a reset loop faster than its own startup.
Because the reset happens entirely in hardware, it works no matter how badly the software is wedged: a hung task, a spinning interrupt handler, or a hard fault with interrupts masked all end the same way, with the watchdog resetting the module.
This example services WDOG1 from its own small task (WatchdogServiceTask in src/main.cpp), not from the menu loop. That is deliberate. The menu loop blocks on gets() waiting for a keypress; if the servicing lived in that loop, an idle console (nobody typing) would stop the servicing and reboot the module. A separate service task keeps the watchdog serviced no matter what the rest of the application is doing. The menu's X command simply tells that task to stop, which is how the demonstration reboot is triggered.
In a real application you would go one step further and make the service task service the watchdog only while your critical work is making progress (for example, only if a "heartbeat" counter bumped by that work keeps changing) – so that a hang in the work itself still trips the watchdog.
Reprogramming the module writes the new application to flash, and a flash write stalls normal task scheduling – long enough that an armed watchdog would otherwise reset the module in the middle of the update. If that happened, and the application re-armed the watchdog on boot, updates could become impossible to complete and the application unrecoverable (short of the recovery-jumper procedure).
There is no good reason to arm the watchdog but leave updates able to trip it, so WatchdogEnable() takes care of it automatically: it registers the NetBurner watchdog service hook (watchdog_service_function), which the flash/update routines call throughout an update. Nothing extra is required on your part – an armed watchdog simply survives a firmware update.
A watchdog reboot resets the i.MX RT1171 internally; it does not drive a reset out to devices on your carrier board. On-module peripherals come back because the boot firmware re-initializes them as the module starts up. If your carrier board has devices that must be reset in lock-step with the module, reset them from your application at startup, or wire them to the module's reset circuitry per the MODRT1171 hardware documentation.
On every boot the example decodes the processor's System Reset Status Register (SRC->SRSR) and prints a human-readable cause (menu key R). The i.MX RT1171 reset controller keeps per-core status, so the example can distinguish power-on/reset-pin, a CM7 software reset, a raw watchdog timeout, RTWDOG3/RTWDOG4, the code watchdog (CDOG), a CM4-initiated reset, JTAG, temperature and over-voltage resets. The example clears SRC->SRSR each boot, so each boot reports exactly the reset that caused it rather than an accumulation of history.
Two details worth knowing, both verified on hardware:
After a ForceReboot() or a reprogram:
After a power cycle:
After a watchdog reset:
(SRSR reports each source twice – once per core – which is why the values above pair a low bit with its high-half twin.)
After arming and pressing X:
Because the watchdog cannot be turned off once armed, application code that arms it at boot and then hangs before servicing it can create a boot loop. This example avoids that by staying un-armed at boot – so arming it here can never brick the board. If your own code does get a board stuck, use the MODRT1171 recovery procedure to load a known-good application: see MODRT1171.
WDOG1 is the general-purpose application watchdog on the i.MX RT1171 and is all a NetBurner application needs. Of the other watchdog blocks, WDOG2 is a second instance of the same peripheral, RTWDOG3 is a low-power watchdog in the CM7 domain, and RTWDOG4 belongs to the CM4/low-power domain and has no CM7 interrupt vector. System startup disables all of them on every boot, so an application watchdog must be armed explicitly – which is exactly what WatchdogEnable() does with WDOG1.