Does anyone knows how to use "hardware reset watchdog"

Started by flavigny, October 10, 2012, 05:31:09 PM

Previous topic - Next topic

flavigny

Hello,
While I was wrote my application, I dreamed to add an external watchdog on power supply. I bought a piece on ebay so named: http://www.ebay.ca/itm/Internet-WatchDog-automatically-RESET-your-router-/270736567283?pt=LH_DefaultDomain_0&hash=item3f09282bf3
I received it today, it appears that it is rather an usb relay without the functionality of watchdog.
So I come back to the iMX233 reference, I read section 23.7: "Watchdog Reset Function"
I also see in the log: " mxs watchdog: initialized, heartbeat 19 sec ... "
Is this piece available to user ?

Diving on Google, I found:
#define HW_RTC_BASE     0x8005c000
#define HW_RTC_WATCHDOG     (*(volatile uint32_t *)(HW_RTC_BASE + 0x50))

I tried:
(*(volatile unsigned int __attribute__((force))  *)  (0x8005C050) )=(unsigned short)(10);
and I got a segmentation fault  :(.

I also read some lines about /dev/watchdog (see: https://support.bluetechnix.at/wiki/SBC-i.MX51_Software_User_Manual#Watchdog)
if I try: cat /dev/watchdog, OlinuxIno reboots!

so I hope the solution is easy for non dummies guys (not me!)

Is it somewhere an example of code using this method  ?

Regards.
PO.

davidjf2001

Seems to me it is already enabled. That is why when you shut down the board reboots. My guess is if linux crashes enough to no longer hit the watchdog the board will reboot as it is.

andersop

#2
This implementation is pretty standard across most ARM SoCs I have encountered. It's a standard file (as you have already discovered, /dev/watchdog). By default, if you don't do anything with the file, it is not enabled.

To enable/"arm" the WDT: open /dev/watchdog and write anything to it.

To "kick"/refresh the WDT: write anything to /dev/watchdog again.

As far as I can tell there is no way to disable/disarm the WDT once it has been started. (Generally this is by design - don't want a runaway app to be able to accidentally disarm it somehow)

It also appears that the WDT on this board is hardcoded to a delay of 19 seconds - so you must refresh it at least once every 19 seconds or the board will reboot.

I am using this successfully on the board already. You should be able to experiment from the command line: do an "echo asdf > /dev/watchdog" and wait, if you do nothing else the board should reset in a little while. Here's a simple shell script to test the timeout, I've included the output of a demo run:

Quote
root@imx233-olinuxino-maxi:~# echo "poke" > /dev/watchdog; CNT=0; while true; do sleep 1; CNT=$((CNT+1)); echo $CNT; done
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLFC
PowerPrep start initialize power...
Battery Voltage = 2.16V
...(reboot continues)...


Sample C code is dead simple (up to you to generate proper .h file if your app structure requires it, etc).

// I might be missing an include here, if so try unistd.h, sys/types.h, sys/stat.h?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

static int mWDT_file = -1;

// call this once at application start to arm the WDT
boolean wdt_enable( void )
{
mWDT_file = open("/dev/watchdog", O_WRONLY);
if (mWDT_file == -1)
{
perror("watchdog");    // failed to open for some reason
}
else
{
write(mWDT_file, "\0", 1);
return true;
}
return false;
}

// call this at least once every so often as long as the app is running "normally"
void wdt_clear( void )
{
if (mWDT_file != -1)
{
write(mWDT_file, "\0", 1);
}
}


flavigny

#3
Thanks a lot,
I will use it (already mentioned in another post, copied here for completeness)
Now, I mix the watchdog with 0.5 Hz led blinking:
---------/home/root/led:------------------------------X%
#!/bin/sh
#set led according to parameter
echo out> /sys/class/gpio/gpio65/direction
echo $1 > /sys/class/gpio/gpio65/value
#kick the dog
echo a > /dev/watchdog

---------------------------------------X%

and in my aplication, I add the function awake, to be called 'frequently':
---------------------------------------X%
int awake(int appel,int delay) {
   static int led=1;
   static time_t timeprevious;
   // if (delay >0) printf ("appel: %d ATTENTE DE %d\"\r\n",appel,delay);
   time_t timenow;
   int count=delay;
   while (count>=0) {
    time(&timenow);
    if (delay==0 || timenow != timeprevious) {
       count=count-1;
       led=!led;
       sprintf (cmdled,"/home/root/led %d",led);
          system(cmdled);
       timeprevious=timenow;
    }
    sleep (1);
   }
   return 0;
}
---------------------------------------X%

PO ;).