[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]
LINUX GAZETTE
...making Linux just a little more fun!
Programming the SA1110 Watchdog timer on the Simputer
By Pramode C.E

In last month's article (Fun with Simputer and Embedded Linux), I had described the process of developing programs for the Simputer, a StrongArm based handheld device. The Simputer can be used as a platform for learning microprocessor and embedded systems programming. This article describes my attempts at programming the watchdog timer unit attached to the SA1110 CPU which powers the Simputer. The experiments should work on any Linux based handheld which uses the same CPU.

The Watchdog timer

Due to obscure bugs, your computer system is going to lock up once in a while - the only way out would be to reset the unit. But what if you are not there to press the switch? You need to have some form of `automatic reset'. The watchdog timer presents such a solution.

Imagine that your microprocessor contains two registers - one which gets incremented every time there is a low to high (or high to low) transition of a clock signal (generated internal to the microprocessor or coming from some external source) and another one which simply stores a number. Let's assume that the first register starts out at zero and is incremented at a rate of 4,000,000 per second. Lets assume that the second register contains the number 4,000,000,0. The microprocessor hardware compares these two registers every time the first register is incremented and issues a reset signal (which has the result of rebooting the system) when the value of these registers match. Now, if we do not modify the value in the second register, our system is sure to reboot in 10 seconds - the time required for the values in both registers to become equal.

The trick is this - we do not allow the values in these registers to become equal. We run a program (either as part of the OS kernel or in user space) which keeps on moving the value in the second register forward before the values of both become equal. If this program does not execute (because of a system freeze), then the unit would be automatically rebooted the moment the value of the two registers match. Hopefully, the system will start functioning normally after the reboot.

Resetting the SA1110

The Intel StrongArm manual specifies that a software reset is invoked when the Software Reset (SWR) bit of a register called RSRR (Reset Controller Software Register) is set. The SWR bit is bit D0 of this 32 bit register. My first experiment was to try resetting the Simputer by setting this bit. I was able to do so by compiling a simple module whose `init_module' contained only one line:

RSRR = RSRR | 0x1

The Operating System Timer

The StrongArm CPU contains a 32 bit timer that is clocked by a 3.6864MHz oscillator. The timer contains an OSCR (operating system count register) which is an up counter and four 32 bit match registers (OSMR0 to OSMR3). Of special interest to us is the OSMR3.

If bit D0 of the OS Timer Watchdog Match Enable Register (OWER) is set, a reset is issued by the hardware when the value in OSMR3 becomes equal to the value in OSCR. It seems that bit D3 of the OS Timer Interrupt Enable Register (OIER) should also be set for the reset to occur.

Using these ideas, it is easy to write a simple character driver with only one method - `write'. A write will delay the reset by a period defined by the constant `TIMEOUT'.

[Text version of this listing]


/*
 * A watchdog timer. 
 */

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <asm-arm/irq.h>
#include <asm/io.h>

#define WME 1
#define OSCLK 3686400 /* The OS counter gets incremented
                       * at this rate
                       * every second 
                       */

#define TIMEOUT 20 /*  20 seconds timeout */

static int major;
static char *name = "watchdog";

void
enable_watchdog(void)
{
    OWER = OWER | WME;
}

void
enable_interrupt(void)
{
    OIER = OIER | 0x8;
}

ssize_t 
watchdog_write(struct file *filp, const char *buf, size_t
               count, loff_t *offp)
{
    OSMR3 = OSCR + TIMEOUT*OSCLK;   
    printk("OSMR3 updated...\n");
    return count;
}

static struct file_operations fops = {write:watchdog_write};

int
init_module(void)
{
    major = register_chrdev(0, name, &fops);
    if(major < 0) {
       printk("error in init_module...\n");
       return major;
    }
    printk("Major = %d\n", major);
    OSMR3 = OSCR + TIMEOUT*OSCLK;
    enable_watchdog();
    enable_interrupt();
    return 0;
}


void
cleanup_module()
{
    unregister_chrdev(major, name);
}

It would be nice to add an `ioctl' method which can be used at least for getting and setting the timeout period.

Once the module is loaded, we can think of running the following program in the background (of course, we have to first create a device file called `watchdog' with the major number which `init_module' had printed). As long as this program keeps running, the system will not reboot.

[Text version of this listing]


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define TIMEOUT 20

main()
{
        int fd, buf;
        fd = open("watchdog", O_WRONLY);
        if(fd < 0) {
                perror("Error in open");
                exit(1);
        }
        while(1) {
                if(write(fd, &buf, sizeof(buf)) < 0) {
                        perror("Error in write, System may reboot any moment...\n");
                        exit(1);
                }
                sleep(TIMEOUT/2);
        }
}

Conclusion

If you are not bored to death reading this, you may be interested in knowing more about Linux on handheld devices (and in general, embedded applications). So, till next time, Bye!

 

[BIO] I am an instructor working for IC Software in Kerala, India. I would have loved becoming an organic chemist, but I do the second best thing possible, which is play with Linux and teach programming!


Copyright © 2003, Pramode C.E. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 88 of Linux Gazette, March 2003

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]