TS-7670 Watchdog

From embeddedTS Manuals

By default there is a /dev/watchdog with the tshwctl daemon running at the highest possible priority to feed the watchdog. This is a pipe that is created in userspace, so for many applications this may provide enough functionality for the watchdog by verifying that userspace is still executing applications. If you would like to have the watchdog functionality more tightly integrated with your application you can specify various feed options.

The watchdog is implemented in the microcontroller that is on this SBC alongside the CPU. This means that a completely separate device is responsible for the sanity of the CPU. The WDT has 100ms resolution, and can be fed for a length of time up to 6553.5s, which is 1h 49m 13s 500ms. Writing a 0, 1, 2, or 3 to the WDT has a special meaning that corresponds with our traditional WDT feed scheme:

Value Result
0 feed watchdog for .3s
1 feed watchdog for 2.7s
2 feed watchdog for 10.8s
3 disable watchdog

The watchdog is armed by default for 10s for the operating system to take over, after which the startup scripts autofeed the watchdog with:

echo a2 > /dev/watchdog

The /dev/watchdog fifo accepts 3 types of commands:

Value Function
f<3 digits> One time feed for a specified amount of time which uses the 3 digit number / 10. For example, "f456" would feed for 45.6 seconds.
"0", "1", "2", "3" One time feed with the value in the above table.
a<num 0-3> This value autofeeds with the value in the above table.

Most applications should use the f<3 digits> option to more tightly integrate this to their application. For example:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

void do_some_work(int data) {
	/* The contract for sleep(int n) is that it will sleep for at least n
	 * seconds, but not less.  If other kernel threads or processes require
	 * more time sleep can take longer, but when your process has a high
	 * priority this is usually measured in millseconds */
	sleep(5);
}

int read_some_io() {
	/* If this function (or do_some_work) misbehave and stall thee watchdog 
         * will not be fed in the main loop and cause a reboot.  You can test 
         * this by uncommenting the next line to force an infinite loop */
	// while (1) {}
	return 42;
}

int main(int argc, char **argv)
{
	int wdfd;
	/* In languages other than C/C++ this is still essentially the same, but
	 * make sure you are opening the watchdog file synchronously so the writes
	 * happen immediately.  Many languages will buffer writes together to make 
	 * them more efficient, but the watchdog needs the writes to be timed 
	 * precisely */
	wdfd = open("/dev/watchdog", O_SYNC|O_RDWR);

	while (1) {
		int data;
		/* This loop is expected to take about 5-6 seconds, but to allow some
		 * headroom for other applications, I will feed the watchdog for 10s. */
		write(wdfd, "f100", 4);

		data = read_some_io();
		do_some_work(data);
	}
}