NetBurner 3.5.8
PDF Version
Watchdog

Example Path: examples/PlatformSpecific/SOMRT1061/Watchdog

Supported Platforms: SOMRT1061

Watchdog (SOMRT1061)

Overview

This example shows how to use the hardware watchdog on the SOMRT1061 module (i.MX RT1061) 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:

WatchdogEnable(4000); // reboot the module if not serviced within ~4 seconds
...
WatchdogService(); // call this comfortably more often than the timeout

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.

Note
The i.MX RT1061 has two other watchdog blocks (WDOG2 and the RTWDOG), but on the SOMRT1061 neither can be used as a reliable watchdog, so this example uses WDOG1. See Why only WDOG1 at the end.

Quick start – the serial menu

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:

  1. Press E and accept the 4 s default. The watchdog is now armed, and a background task services it automatically, so the module keeps running.
  2. Press X. Servicing stops; a few seconds later the module reboots on its own. That reboot – timed to the moment you stopped servicing – is the watchdog doing its job.
  3. Press B to trigger a plain software reboot instead, for comparison.

Using WDOG1 in your own application

The API is just four calls (all in src/nbwatchdog.h):

void WatchdogEnable(uint32_t timeoutMs); // arm the watchdog
void WatchdogService(); // service (restart) it
bool WatchdogIsEnabled(); // is it armed?
uint32_t WatchdogTimeoutMs(); // the timeout currently set

Usage is: arm once with a timeout, then service it from healthy code more often than that timeout.

A few rules worth knowing:

  • Timeout range is 1 to 128 seconds (values are clamped to that range and resolve in 0.5 s steps).
  • The reboot happens slightly before the configured timeout. That is intentional (see the next section) and is the safe direction for a watchdog – it errs toward rebooting a little early, never late.
  • Once armed, the watchdog cannot be turned off – only a reset clears it. This is by hardware design: it stops buggy code from silently disabling its own safety net. Choose the timeout accordingly.
  • Service from a dedicated task, not from a loop that can block. If the code that services the watchdog can get stuck waiting on something, it will stop servicing and reboot the module by accident. This example services WDOG1 from a small dedicated task – see below.
  • Firmware updates are handled for you. Arming the watchdog also makes reprogramming safe automatically – see Servicing during firmware updates.

How the automatic reboot works

On the SOMRT1061 a watchdog timeout does not simply reset-and-reboot the way you might expect. A raw i.MX hardware watchdog reset resets the CPU core, but the module does not cleanly reboot from it – it hangs, and only a power cycle recovers it. (Two reasons: the watchdog's external WDOG_B reset pin is not routed on the module, and a clean reboot on this module requires a specific software-reset sequence – ForceReboot() / DoSWReset() in arch/cortex-m7/cpu/MIMXRT10xx/source/cpu_hal.cpp – that a bare hardware reset does not perform.)

So WatchdogEnable() does not rely on the raw reset. Instead it arms WDOG1 with a pre-timeout interrupt that fires just before the hardware timeout, and that interrupt performs a clean ForceReboot() – the proper, bootable reset path on this module. The net effect is exactly what you want:

not serviced in time -> clean, automatic reboot back into the application.

The raw (hanging) reset is only ever reached if the core is so wedged that interrupts no longer run at all (for example a hard fault with interrupts masked) – and a board in that state needs a power cycle regardless. For the normal case of a hung or stuck task, the pre-timeout interrupt catches it and reboots cleanly.

Service from a dedicated task, not an input loop

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.

Servicing during firmware updates (automatic)

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 Alternate Boot Monitor).

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.

Reset signals on the SOMRT1061 (RSTI / RSTO) and what a reset affects

Because a watchdog is a reset source, it is worth being clear about how reset actually reaches things on this module.

  • RSTI (reset-in) is an active-low reset input to the module, pulled up on the SOM by a 10 kΩ resistor (R6) to 3.3 V. Driving it low – from a reset button or a baseboard supervisor – forces a full module reset. This is the correct hardware way to reset the whole module from outside.
  • RSTO (reset-out) is a reset output, so a carrier board can hold its own devices in reset in step with the SOM.

A watchdog reboot does not drive these pins to external chips. The watchdog resets the i.MX RT1061 internally; peripherals on the board come back because the boot firmware re-initialises them. For example the Ethernet PHY (DP83825I) is reset by a dedicated GPIO, Pin_B0_07 (board net E_RST), each time the network stack starts (arch/cortex-m7/cpu/MIMXRT10xx/source/ethernet.cpp), and the external HyperRAM/PSRAM is re-initialised by the FlexSPI controller. If your baseboard needs its devices reset in lock-step with the module, wire them to RSTO** (or to RSTI-driven logic) – do not expect the watchdog to reach them.

Reading why the module last reset

On every boot the example decodes the processor's reset-status registers (SRC->SRSR and WDOG1->WRSR) and prints a human-readable cause (menu key R): power-on, external reset pin, software reset, and so on.

Note
An honest limitation on this module. The clean watchdog reboot, a menu ForceReboot(), a reprogram and an external reset all go through the same software-reset sequence (DoSWReset()), so in the status registers they look identical – there is no bit left over that says "the watchdog did this," and no application-accessible register survives the reboot to record it. In practice you therefore observe a watchdog reboot live – the module reboots the instant you stop servicing it – rather than from the post-reboot status bits. The example clears SRC->SRSR each boot so the bits do not accumulate across resets.

Expected serial output

Application: SOMRT1061 Watchdog
NNDK Revision: <release>
Target: SOMRT1061 (i.MX RT1061)
Last reset cause (SRC->SRSR = 0x00000001, WDOG1->WRSR = 0x0010)
Power-on / reset-pin / reprogram / clean watchdog reboot
(RSTI, POR or DoSWReset -- indistinguishable here; see ReadMe)
========== SOMRT1061 Watchdog Menu ==========
Status: WDOG1 off | Auto-service: ON
...

After arming and pressing X:

Stopping the service. Within about 4000 ms the pre-timeout interrupt
will fire and issue a clean ForceReboot(). ...
waiting for watchdog reboot... 12
<module reboots on its own>
void ForceReboot(bool fromIRQ=false)
Initiates an immediate hardware-level system reset of the NetBurner device.

Recovery (if you ever wedge a board)

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 module's Alternate Boot Monitor** to load a recovery application; see the NNDK documentation (/nburn/docs/NetBurner/...) for the SOMRT1061 recovery procedure.

Why only WDOG1

The i.MX RT1061 also contains a second watchdog (WDOG2) and a separate real-time watchdog (RTWDOG). On the SOMRT1061 neither can be used as a dependable watchdog, so this example uses WDOG1 exclusively. WDOG1 is the general-purpose application watchdog and is all you need on this module.

Further reading

  • src/nbwatchdog.h / src/nbwatchdog.cpp – the watchdog helper API.
  • arch/cortex-m7/cpu/MIMXRT10xx/include/MIMXRT1061.h – WDOG and SRC register and bit-field definitions.
  • arch/cortex-m7/cpu/MIMXRT10xx/source/cpu_hal.cppDoSWReset(), the software-reset path behind ForceReboot().
  • arch/cortex-m7/cpu/MIMXRT10xx/source/ethernet.cpp – the Ethernet PHY reset GPIO (Pin_B0_07, board net E_RST).
  • docs/root/NXP/IMXRT1060RM.pdf – reference-manual chapters "WDOG" and "SRC" (System Reset Controller / SRSR).