The
Watchdog
Timer
We are
now
going to
look at
an
internal
timer,
called a
Watchdog
Timer
So what
is a
Watchdog
Timer?
Suppose
you have
written
a
program
that is
continuously
running
on a PIC.
Now, you
want to
make
sure
that
this
program
is
always
running,
and that
no
matter
what
happens
it will
never
stop.
The
first
thing
you
would
have, of
course,
is a
loop
back at
the end
of the
program
that
brings
us back
to the
start of
the
program.
But
consider
this
case.
Let us
say that
the PIC
is
monitoring
an
input.
When
this
input
goes
high, it
jumps to
another
part of
the
program
and
waits
for
another
pin to
go
high.
If the
second
pin
doesn’t
go high,
the PIC
will
just sit
there
and
wait.
It will
only
exit if
the
second
pin goes
high.
Let us
consider
another
example.
Suppose
you have
written
a
program.
You have
compiled
it
successfully,
and you
have
even
simulated
it over
and over
again
using a
simulator
such as
MPLAB.
Everything
seems to
work
fine.
You
program
the PIC
and
place it
into a
circuit.
However
after a
long
period
of time,
the
program
gets
stuck
somewhere
and the
PIC gets
caught
in a
loop.
What’s
needed
in both
cases is
some
kind of
reset if
the
program
gets
stuck.
This is
the
purpose
of a
watchdog
circuit.
A
watchdog
circuit
is
nothing
new.
Many
microprocessors
and
microcontrollers
have
them.
But how
does it
work?
Well,
inside
the PIC
there is
a
resistor/capacitor
network.
This
provides
a unique
clock,
which is
independent
of any
external
clock
that you
provide
in your
circuit.
Now,
when the
Watchdog
Timer
(abbreviated
to WDT)
is
enabled,
a
counter
starts
at 00
and
increments
by 1
until it
reaches
FF.
When it
goes
from FF
to 00
(which
is FF +
1) then
the PIC
will be
reset,
irrespective
of what
it is
doing.
The only
way we
can stop
the WDT
from
resetting
the PIC
is to
periodically
reset
the WDT
back to
00
throughout
our
program.
Now you
can see
that if
our
program
does get
stuck
for some
reason,
then the
WDT will
not be
set.
The WDT
will
then
reset
the PIC,
causing
our
program
to
restart
from the
beginning.
In order
to use
the WDT,
we need
to know
three
things.
First,
how long
have we
got
before
we need
to reset
the WDT,
secondly
how do
we clear
it.
Finally,
we have
to tell
the PIC
programming
software
to
enable
the WDT
inside
the PIC.
Let’s
look at
these
separately.
WDT
Times
The PIC
data
sheet
specifies
that the
WDT has
a period
from
start to
finish
of
18mS.
This is
dependant
several
factors,
such as
the
supply
voltage,
temperature
of the
PIC
etc.
The
reason
for the
approximation
is
because
the WDT
clock is
supplied
by an
internal
RC
network.
The time
for an
RC
network
to
charge
depends
on the
supply
voltage.
It also
depends
on the
component
values,
which
will
change
slightly
depending
on their
temperature.
So, for
the sake
of
simplicity,
just
take it
that the
WDT will
reset
every
18mS.
We can,
however,
make
this
longer.
Inside
the PIC
is a
thing
called a
Prescaler.
We can
program
this
prescaler
to
divide
the RC
clock.
The more
we
divide
the RC
clock
by, the
longer
it takes
for the
WDT to
reset.
The
prescaler
is
located
in the
OPTION
register
at
address
81h,
bits 0
to 2
inclusive.
Below is
a table
showing
the bit
assignments
with the
division
rates
and the
time for
the WDT
to time
out:
|
Bit
2,1,0 |
Rate |
WDT Time |
|
0,0,0 |
1:1 |
18mS |
|
0,0,1 |
1:2 |
36mS |
|
0,1,0 |
1:4 |
72mS |
|
0,1,1 |
1:8 |
144mS |
|
1,0,0 |
1:16 |
288mS |
|
1,0,1 |
1:32 |
576mS |
|
1,1,0 |
1:64 |
1.1Seconds |
|
1,1,1 |
1:128 |
2.3Seconds |
Remember
these
times
are
irrespective
of your
external
clock
frequency.
Think of
these
times as
real
time,
rather
than
clock
times.
To help
make
this
clear,
let us
suppose
we want
the WDT
to reset
our PIC
after
about
half a
second
as a
failsafe.
The
nearest
we have
is
576mS,
or 0.576
seconds.
All we
do is
send
b’101’
to our
OPTION
register,
as
follows:
movlw
b’101’
;This is
0x05 in
Hex
movwf
81h
;This is
the
Option
Register
Simple,
really.
Now,
there is
a
catch.
By
default
the
prescaler
is
assigned
to the
other
internal
timer.
This
means
that we
have to
change
the
prescaler
over to
the WDT.
First,
we have
to reset
the
other
counter
to 0
first.
We then
have to
change
to Bank
1 to
assign
the
prescaler
to the
WDT and
to set
up the
time,
and then
come
back to
Bank 0.
The code
is
below,
where xx
is the
prescaler
time:
bcf
STATUS,0
;make
sure we
are in
bank 0
clrf
01h ;address
of the
other
timer –
TMR0
bsf
STATUS,0
;switch
to bank
1
clrwdt
;reset
the WDT
and
prescaler
movlw
b’1xxx’
;Select
the new
prescaler
value
and
assign
movwf
OPTION
;it to
WDT
bcf
STATUS,0
;come
back to
bank 0
The
CLRWDT
command
above is
how we
clear
the WDT
before
it
resets
the PIC.
So, all
we need
to do is
calculate
where in
our
program
the WDT
will
time
out, and
then
enter
the
CLRWDT
command
just
before
this
point to
ensure
the PIC
doesn’t
reset.
If your
program
is long,
bear in
mind
that you
may need
more
than one
CLRWDT.
For
example,
if we
use the
default
time of
18mS,
then we
need to
make
sure
that the
program
will see
CLRWDT
every
18mS.
So now
we come
to the
point
where we
need to
work out
how long
our code
takes in
real
time.
The
principle
is very
simple,
but
could
cause
you to
pull
your
hair
out!
Instruction
Timing
As you
are
probably
already
aware,
the PIC
takes
the
external
clock
timing
and
divides
it by
4. This
internal
time is
called
an
instruction
cycle.
Now if
we have,
say, a
4MHz
xtal
connected
to the
PIC,
internally
the PIC
will run
at
1MHz.
In
timing
terms,
this is
1/(4MHz/4) =
1uS. Now, some instructions take just one instruction
cycle to
complete,
i.e.
1uS
using a
4MHz
crystal,
while
others
take two
cycles –
2uS – to complete. The data sheet tells us how many
cycles
each
instruction
takes.
The
easiest
way to
remember
this is
quite
simple.
Assume
ALL
instructions
take 1
cycle.
But, if
an
instruction
causes
the
program
to go
somewhere
else,
then it
will
take 2
cycles.
Let me
give you
a couple
of
examples.
The
movwf
command
takes
only one
cycle,
because
it is
only
moving
data
from one
place to
another.
The goto
command
takes 2
cycles,
because
it is
causing
the
Program
Counter
(PC) to
go
elsewhere
in the
program.
The
RETURN
command
takes 2
cycles,
because
it is
causing
the PC
to go
back in
the
program.
We think
you can
see the
pattern
here.
However,
there
are four
commands
which
can take
1 or 2
cycles.
These
are DECFSZ,
INCFSZ,
BTFSC
and
BTFSS.
These
commands
have one
thing in
common.
They
will
skip the
next
instruction
is a
certain
condition
is met.
If that
condition
is not
met,
then the
next
instruction
will be
carried
out.
For
example,
the
DECFSZ
command
will
decrement
the
value
stored
in the F
register
by 1.
If the
result
is not
0, then
the next
instruction
will be
executed.
This
instruction
therefore
takes 1
cycle.
If the
result
is 0,
then the
next
instruction
will be
skipped,
and the
one
following
that
will be
executed.
In this
instance
the
instruction
takes 2
cycles.
The
reason
is that
the
instruction
alters
the
value of
the PC.
It needs
one
cycle to
carry
out the
function,
and it
will
need
another
to alter
the PC
by an
extra
one.
To
clarify
this,
let us
look at
a sample
code,
and work
out how
many
instruction
cycles
it
takes.
movlw
02
movwf COUNT
loop
decfsz
COUNT
goto loop
end
Our
first
instruction
simply
moves
the
value 02
into w.
This
does not
cause
the
program
to off
course,
therefore
it is
only 1
cycle.
The next
instruction
is
similar,
in as
much
that it
moves
the
contents
of the w
register
into
COUNT.
Again,
this
will be
1
cycle.
Now, the
next
instruction
will
first
decrement
COUNT by
1. This
is 1
cycle.
It will
then do
a test
to see
if COUNT
is equal
to 0.
At this
stage it
doesn’t,
and so
we move
onto the
next
instruction.
The next
instruction
is a
goto
statement,
and so
is 2
cycles
long.
We come
back to
our
decfsz
instruction,
which
decrements
COUNT by
1
again.
This is
another
instruction
cycle.
It does
a test
to see
if COUNT
is equal
to 0.
This
time it
does,
and so
the next
instruction
is
skipped.
To skip
the next
instruction
requires
another
cycle.
We reach
the end
of the
program.
So in
total,
with the
value 02
placed
into
COUNT,
this
program
will
take a
total of
7
cycles.
If we
were
using a
4MHz
crystal
for our
clock,
then the
program
will
take:
1/(4MHz/4)
=
1uS
per
cycle,
therefore
7 cycles
takes 7
x
1uS =
7uS.
So you
can see
that it
can get
a little
confusing
when you
have
instructions
like
DECFSZ.
Programmer
Software
Inside
the PIC
there
are
things
called
‘Fuses’.
These
are not
the same
as the
fuses
you
would
find in
a mains
plug,
but
electronic
switches
which
are
‘blown’
by the
programmer.
Now, one
of these
fuses
has to
be
‘blown’
in
order
for the
WDT to
operate.
There
are two
ways of
doing
this.
One way
is to
write a
couple
of lines
at the
beginning
of your
program
to tell
the PIC
programming
software
to
enable
or
disable
certain
fuses.
The
other
way is
to tell
the PIC
programming
software
manually
which
fuses to
enable.
We will
look at
getting
your
program
to
instruct
the
programming
software
in a
later
tutorial,
when we
look at
including
other
files
and
macros.
To tell
the
programming
software
manually,
varies
from
program
to
program.
The
documentation
that
came
with the
programmer
should
tell you
how to
do
this.
As We
are using
the PICALLW
software,
which is
linked
on my
main
page, We
will
explain
how to
do
change
fuses
within
this
program.
The
fuses
are
configured
by
pressing
the F3
key, or
clicking
on the
‘Config’
button.
Then you
can
select
the fuse
you want
enabled,
in this
case the WDT, by
clicking
on the
box next
to it.
Sample
Program
Let us
write a
program,
where we
will
turn on
the WDT,
and let
the PIC
perform
a
function.
We will
first of
all
periodically
clear
the WDT,
to show
that the
program
works,
and then
remove
the
CLRWDT
command
to show
that the
PIC will
indeed
reset.
The
program
We have
chosen
is the
one used
in
tutorial
9 where
we cause
a row of LEDs to
light up
one at a
time
from
left to
right,
then
right to
left.
The
circuit
is shown
below,
and with
the RC
values
shown
will
give us
a clock
frequency
of
8KHz.
This
clock
speed
will
allow us
to
actually
see the
LEDs
moving
one by
one.
We
chose
this
program
because
it is
slow
enough
for us
to play
with the WDT, and
you can
easily
see when
the PIC
is
reset.
We have
removed
the
original
comments,
and We
have
replaced
them
with a
description
of the WDT
lines, a
running
total of
the time
from the
start
(assuming
a 8KHz
clock),
and the
number
of clock
cycles
at each
line.

TIME equ
9FH
;
Variable
for the
delay
loop.
PORTB
equ
06H
; Port B
address.
TRISB
equ
86H
; Port B
Tristate
address.
PORTA
equ 05H
; Port A
address.
TRISA
equ
85H
; Port A
Tristate
address.
STATUS
equ
03H
; Page
select
register.
COUNT1
equ
0CH
; Loop
register.
COUNT2
equ
0DH
;
Loop
register.
bsf
STATUS,5
; 1
cycle,
0.5mS
movlw
00H ; 1 cycle, 1.0mS
movwf
TRISB
; 1
cycle,
1.5mS
movlw
00H ;
1 cycle,
2.0mS
movwf
TRISA
; 1
cycle,
2.5mS
bcf
STATUS,5
; 1
cycle,
3.0mS
movlw
00H ; 1 cycle, 3.5mS
movwf
PORTA
; 1
cycle,
4.0mS
;
Start of
main
program
RUN
movlw
01H
; 1
cycle,
4.5mS
movwf
PORTB
; 1
cycle,
5.0mS
call
DELAY
; 2
cycles,
486mS
call
DELAY
; 2
cycles,
967mS
; Move
the bit
on Port
B left,
then
pause.
rlf
PORTB,1
; 1
cycle,
967.5mS
call DELAY
; 2
cycles,
1.45S
call
DELAY
; 2
cycles,
1.93S
rlf
PORTB,1
; 1
cycle,
1.93S
call
DELAY
; 2
cycles,
2.41S
call
DELAY
;
2
cycles,
2.89S
rlf
PORTB,1
; 1 cycle, 2.89S
call
DELAY
; 2
cycles,
3.37S
call
DELAY
; 2
cycles,
3.85S
rlf
PORTB,1
; 1
cycle,
3.85S
call
DELAY
; 2
cycles,
4.34S
call
DELAY
; 2
cycles,
4.82S
rlf
PORTB,1
; 1
cycle,
4.82S
call
DELAY
; 2
cycles,
5.30S
call
DELAY
; 2
cycles,
5.78S
rlf
PORTB,1
; 1
cycle,
5.78S
call
DELAY
; 2
cycles,
6.26S
call
DELAY
; 2
cycles,
6.74S
rlf
PORTB,1
; 1
cycle,
6.74S
call
DELAY
; 2
cycles,
7.22S
call
DELAY
; 2
cycles,
7.70S
rlf
PORTB,1
; 1
cycle,
7.70S
; Now
move
onto
Port A,
and move
the bit
left.
rlf
PORTA,1
; 1
cycle,
7.70S
call
DELAY
;
2
cycles,
8.19S
call
DELAY
;
2
cycles,
8.67S
rlf
PORTA,1
; 1 cycle, 8.67S
call
DELAY
; 2
cycles,
9.15S
call DELAY
; 2
cycles,
9.63S
rlf
PORTA,1
; 1
cycle,
9.63S
call
DELAY
; 2
cycles,
10.11S
call
DELAY
; 2
cycles,
10.59S
rlf
PORTA,1
; 1
cycle,
10.59S
call
DELAY
; 2
cycles,
11.07S
call
DELAY
; 2
cycles,
11.55S
; Move
the bit
back on
Port A
rrf
PORTA,1
; 1
cycle,
11.55S
call
DELAY
; 2
cycles,
12.04S
call
DELAY
; 2
cycles,
12.52S
rrf
PORTA,1
; 1
cycle,
12.52S
call
DELAY
; 2
cycles,
12.99S
call
DELAY
; 2
cycles,
13.48S
rrf
PORTA,1
; 1
cycle,
13.48S
call
DELAY
; 2
cycles,
13.96S
call
DELAY
; 2
cycles,
14.44S
rrf
PORTA,1
; 1
cycle,
14.44S
; Now
move the
bit back
on Port
B
rrf
PORTB,1
; 1
cycle,
14.44S
call
DELAY
;
2
cycles,
14.92S
call
DELAY
; 2
cycles,
15.40S
rrf
PORTB,1
; 1
cycle,
15.40S
call
DELAY
; 2
cycles,
15.89S
call
DELAY
; 2
cycles,
16.37S
rrf
PORTB,1
; 1
cycle,
16.37S
call
DELAY
; 2
cycles,
16.84S
call
DELAY
; 2
cycles,
17.33S
rrf
PORTB,1
; 1
cycle,
17.33S
call
DELAY
; 2
cycles,
17.81S
call
DELAY
; 2
cycles,
18.29S
|