1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
|
<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Programming the SA1110 Watchdog timer on the Simputer LG #88</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="piszcz.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue88/pramode.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="puryear.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<!--endcut ============================================================-->
<TABLE BORDER><TR><TD WIDTH="200">
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/2002/lglogo_200x41.png"
WIDTH="200" HEIGHT="41" border="0"></A>
<BR CLEAR="all">
<SMALL>...<I>making Linux just a little more fun!</I></SMALL>
</TD><TD WIDTH="380">
<CENTER>
<BIG><BIG><STRONG><FONT COLOR="maroon">Programming the SA1110 Watchdog timer on the Simputer </FONT></STRONG></BIG></BIG>
<BR>
<STRONG>By <A HREF="../authors/pramode.html">Pramode C.E</A></STRONG>
</CENTER>
</TD></TR>
</TABLE>
<P>
<!-- END header -->
<p>
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.
<h2> The Watchdog timer </h2>
<p>
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.
<p>
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.
<p>
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.
<h2> Resetting the SA1110 </h2>
<p>
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:
<p>
RSRR = RSRR | 0x1
</p>
<h2> The Operating System Timer </h2>
<p>
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.
<p>
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.
<p>
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'.
<p>
[<A HREF="misc/pramode/watchdog.c.txt">Text version of this listing</A>]
<p>
<pre>
/*
* 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);
}
</pre>
</p>
<p>
It would be nice to add an `ioctl' method which can be used
at least for getting and setting the timeout period.
<p>
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.
<p>
[<A HREF="misc/pramode/shutter_upper.c.txt">Text version of this listing</A>]
<p>
<pre>
#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);
}
}
</pre>
</p>
<h2> Conclusion </h2>
<p>
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!
<!-- *** BEGIN author bio *** -->
<P>
<P>
<!-- *** BEGIN bio *** -->
<P>
<img ALIGN="LEFT" ALT="[BIO]" SRC="../gx/2002/note.png">
<em>
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!
</em>
<br CLEAR="all">
<!-- *** END bio *** -->
<!-- *** END author bio *** -->
<!-- *** BEGIN copyright *** -->
<hr>
<CENTER><SMALL><STRONG>
Copyright © 2003, Pramode C.E.
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 88 of <i>Linux Gazette</i>, March 2003
</STRONG></SMALL></CENTER>
<!-- *** END copyright *** -->
<HR>
<!--startcut ==========================================================-->
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="piszcz.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue88/pramode.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="puryear.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->
|