'RTCC Finer Points [was Re: 16C84 Interrupts]'
Jerry Ethridge wrote:
>For anyone who is trying to create accurate interrupt times
>on the pic, you must be aware that when you load the rtcc
>with a value, the prescaler is cleared to zero. What this
>means is that when the rtcc reaches 0, and your interrupt
>service routine starts, the prescaler has continued to accumulate
>instruction counts. Lets say that it takes a dozen or so counts
>to finally get around to clearing the interrupt flag, incrementing
>or decrementing your time counter, and then loading the rtcc with
>your preload value. The prescaler has been accumulating instruction
>ticks and will be incrementing the rtcc when it rolls over. However
>when you preload the rtcc, those ticks get wiped out and reset to zero.
>Every interrupt cycle loses time!
>The solution is to pick your crystal frequency and your prescaler value
>such that you never write to the rtcc. It should be allowed to overflow.
>This way, the prescaler is never cleared to zero and no clock ticks are
This is a solution. Here are some others:
* Don't use the prescaler at all. Problem with this is that the interrupt
rate will be rather fast.
* If using the internal clock to drive the prescaler, then the prescaler
value is *known* at all times in the interrupt routine, as it continues to
run. Jerry alludes to this in his description above. If the prescaler is
set to 16 for instance, about 16 instructions into the interrupt routine it
will count around to 0 again. (probably 15 or less since launching the
interrupt uses some cycles). Writing the RTCC at that point would still
reset the prescaler, but this wouldn't cause a timing error as it is already
0. (There is also the issue of the poorly-documented "2-cycle
synchronization delay". Is this also reset?) In any case, my point is that
when using internal clocks, the timing error resulting from writing to the
RTCC during an interrupt routine will be constant, although possibly hard to
figure out exactly. This is also a way to get "fractional" resolution of
the interrupt rate without having to "jitter" the reload count. But there
may be a long wait if a large prescale value is used.
* The 12-bit PICs (16C5X) have a similar RTCC, but no interrupt capability.
Timing on them is done by polling the RTCC. In this case, writing to RTCC
is the last resort, since it is hard (not impossible) to determine the
contents of the prescaler. One of the digital clock app notes from
Microchip made the mistake of writing, they probably didn't test it over a
long enough time to see that it didn't work. One way to trigger an action
every "n" (n < 256) RTCC counts is to read and compare with an expected value:
movfw RTCC ;Get RTCC value
xorwf exprtcc,0 ;Compare to expected value
skpz ;Skip if expected value reached
goto wt4rtcc ;Keep looping until value reached.
movlw n ;Number of RTCC counts required till next time.
addwf exprtcc,1 ;Update the expected value for next time.
The code below this routine will then execute 7 to 12 cycles after RTCC
reaches the expected value. The prescaler must be set to 8 or more if using
the internal clock option, if externally clocked the RTCC must not increment
faster than once every 5 instruction cycles. Great simplification is
possible if n=256, if n is a power of 2, the general routine above could
also be simplified.
> >The solution is to pick your crystal frequency and your prescaler value
> >such that you never write to the rtcc. It should be allowed to overflow.
> >This way, the prescaler is never cleared to zero and no clock ticks are
Mike Keitz wrote:
Thank you Mike,
I like these solutions and in fact have added them to my PIC notes file.
It can be difficult however to analyze the system to come up with accurate
timing when messing with the RTCC. For example, If you have anything but a
very simple interrupt routine that may make several decisions and make any
number of jumps that may or may not involve two cycle instructions then you
will have to analyze every possible path and compensate for time lost in the
I just chose a simple solution to minimize my own effort. My own lazyness
has resulted in many elegant yet simple soulutions :).
For example, for a clock, I would go with a 4194304 crystal (common freq),
and set the prescaler to 16. Then I would let the RTCC overflow and never
write to it. This will result in 256 interrupts a second. Use a software
variable as a counter and everytime this counter reaches zero voila, 1
With the prescaler set to 16 along with the RTCC counter, this will give you
4096 instructions to play with between each interrupt. For a clock, this
should be plenty.
If you need ms resolution go with a 8192000 (also common) crystal and a
prescaler value of 8.
This will result in a 1ms interrupt.
If however you are turning your real time clock on and off, and need lots of
processing between interrupts, a more thorough analysis of timing should be
done and a method similar to the ones Mike suggested above should be used.
Very interesting discussion. Thanks!
Jeff D. Pipkins
|There should be an app note about this. Here's the straight scoop.
If you want the timer to interrupt you at a constant rate,
here's how it can be done. I put this code in my timer ISR:
Where "timerpd" is a constant, and TMR0 is another word for rtcc.
Note that I'm using the OSC clock for the timer, and NOT the
external timer clock option. I don't know exactly how that
would affect the timing. Using the above strategy will cause
your code, in the isr, to execute once every "timerpd" instruction
cycles, as long as you don't disable interrupts in the main code.
Note that interrupt latency is not an issue! The counter keeps
counting after it overflows, and the more interrupt latency,
the further it counts, but the constant is SUBTRACTED from the
current count, instead of just resetting the current count,
and then trying to fudge-factor the interrupt latency.
I've measured it on a logic analyzer (using a 16C84) and it's
right on the money every time.
It's important to note that I'm not using the prescaler.
As a couple of others pointed out, the prescaler gets cleared
during the subtraction above because the timer is written to.
The bottom line is, if you want to have a regular heartbeat
timer interrupt, you must not use the prescaler, or you must
not ever write to the timer.
Hope this helps,
Jeff Pipkins <bangate.compaq.com> ------------------- Pipkins
Lead, Communications VP, Quartet Activities Chairman,
Lone Star Statesmen Barbershop Chorus
Opinions above are mine personally; use only at your own risk.
This is OK but without using the prescaler, and the RTCC only having
8 bits, you are limited to something less than 256 cycles
between each interrupt. Of course if the only thing you are doing
is a very simple clock circuit, it would probably be fine. This method
would also be very tricky to use if you were using alot of different
interrupts. Although this thread has mainly been about the 16C84, have
you seen all the interrupt options in the 74's? My typical ISR would
take up a good chunk of my processing time if I were limited to less
than 256 cycles between heartbeats.
At least by using the prescaler, it gives you some breathing room to
do a few things before you are interrupted by your heartbeat. As Jeff
points out above, never write to RTCC when using the prescaler.
My own personal preference is to always use the prescaler and to never
modify the RTCC. I don't know why it was designed to clear the prescaler
when the RTCC has been modified. Real time clocks would be a breeze to
design with just about any crystal value and RTCC preload value if the
the prescaler were not cleared in this manner. Oh well, I'm not the
designer, just the guy that has to work around someone elses design :>)
More... (looser matching)
- Last day of these posts
- In 1995
, 1996 only
- New search...