Exact match. Not showing close matches.
PICList
Thread
'[PIC:] Preloading Timer0'
2004\02\03@091129
by
Anno, Jeff
|
Hello Pic People,
I am working on a cycle time monitoring project that uses a 16F628 (4.000
MHz, external crystal) with an LCD (16X2) and the built in USART (async at
19200). When a button is pressed, the time (in milliseconds) is reported to
the computer and the time is reset. I am using TMR0 with a 1:4 TMR0 Rate. I
would like to get an interrupt every 1.0000 ms, but right now it is not
quite correct. Everything seems to be working except getting the exact
interrupt time.
I think that this is true (please let me know if it's not):
Since an instruction cycle runs every 4th clock cycle, at 4MHz, that gives
me 1,000,000 instruction cycles/second. I am using a 1:4 TMR0 Rate, that
gives me a 250,000 clock to the TMR0 register. Since the TMR0 register is
8-bit register, an interrupt is generated when rolling over from 0xFF to
0x00 (is this 256 interrupts or 255?). So I get an interrupt every 0.001024
seconds (256 / 250,000).
I read that the TMR0 register can be preloaded with any 8-bit value. So I
thought if I preloaded it with a 0x06 I would get an interrupt every
millisecond (250 / 250000 = 0.001000).
If I preload the TMR0 register the reported time value is totally wrong. If
I don't preload the value then the actual time is = (reported time from pic
* 1.024) + (constant). The constant is a fixed value to compensate for
writing to the Serial Port.
This is the portion of my code where I preload the TMR0 register
bcf INTCON,T0IF ; Clear the TMR0 interrupt flag
movlw D'6' ; Preload TMR0 with a 6 to get
movwf TMR0 ; 250 inst cycles/interrupt (vs 256)
retfie ; Finished, reset GIE
Sorry for the long e-mail, but I didn't want to exclude any relevant info.
Any suggestions?
Thanks in advance,
Jeff
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@093449
by
Nigel Orr
pic microcontroller discussion list wrote:
> This is the portion of my code where I preload the TMR0 register
>
> bcf INTCON,T0IF ; Clear the TMR0 interrupt flag
> movlw D'6' ; Preload TMR0 with a 6 to get
> movwf TMR0 ; 250 inst cycles/interrupt (vs 256)
> retfie ; Finished, reset GIE
Have you corrected for the time between the interrupt firing and your ISR
getting to the above section? Count the number of instruction cycles above
the 'movwf TMR0', divide by 4 (your prescale) and add that to the '6'
above. Don't forget the interrupt latency (typically 3 instruction
cycles).
Nigel
--
Nigel Orr, Design Engineer spam_OUTnigelTakeThisOuT
axoninstruments.co.uk
Axon Instruments Ltd., Wardes Road,Inverurie,Aberdeenshire,UK,AB51 3TT
Tel:+44 1467 622332 Fax:+44 1467 625235
http://www.axoninstruments.co.uk
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@095606
by
Olin Lathrop
Anno, Jeff wrote:
> I am working on a cycle time monitoring project that uses a 16F628
> (4.000 MHz, external crystal) with an LCD (16X2) and the built in
> USART (async at 19200). When a button is pressed, the time (in
> milliseconds) is reported to the computer and the time is reset. I am
> using TMR0 with a 1:4 TMR0 Rate. I would like to get an interrupt
> every 1.0000 ms, but right now it is not quite correct. Everything
> seems to be working except getting the exact interrupt time.
Timer 2 is better suited to this task. I often use timer 2 to produce a
periodic 1mS interrupt. At 4MHz oscillator, you have 1000 instructions per
mS. A period of 250 with a prescaler of 4 will do this.
Take a look at my TIMER2_USEC and TIMER2_SETUP_INTR macros in STD.INS.ASPIC
at http://www.embedinc.com/pic. These make it very easy to set up timer 2
for this purpose. You define the oscillator frequency in the main include
file, then specify the desired interrupt period in uS and the macros do most
everything else. This also means your code won't break when some time later
the 4MHz oscillator is changed to 8MHz, 20MHz, or something else.
{Quote hidden}> Since an instruction cycle runs every 4th clock cycle, at 4MHz, that
> gives me 1,000,000 instruction cycles/second. I am using a 1:4 TMR0
> Rate, that gives me a 250,000 clock to the TMR0 register. Since the
> TMR0 register is 8-bit register, an interrupt is generated when
> rolling over from 0xFF to 0x00 (is this 256 interrupts or 255?). So I
> get an interrupt every 0.001024 seconds (256 / 250,000).
>
> I read that the TMR0 register can be preloaded with any 8-bit value.
> So I thought if I preloaded it with a 0x06 I would get an interrupt
> every millisecond (250 / 250000 = 0.001000).
You want to add a value into timer 0 each interrupt, not preload it.
However, I sortof remember that this resets the prescaler counter, so you
can't get deterministic results with the prescaler engaged. This means you
will have to take several timer 0 interrupts and keep a counter to get to
the 1mS period. Again, use timer 2. That's what it's for.
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@095607
by
Alan B. Pearce
.Since an instruction cycle runs every 4th clock cycle, at 4MHz,
>that gives me 1,000,000 instruction cycles/second. I am using
>a 1:4 TMR0 Rate, that gives me a 250,000 clock to the TMR0 register.
>Since the TMR0 register is 8-bit register, an interrupt is
>generated when rolling over from 0xFF to 0x00 (is this 256 interrupts
>or 255?). So I get an interrupt every 0.001024
>seconds (256 / 250,000).
Personally I would use a 4.096MHz crystal, and then you do not need to worry
about reloading the timer register.
However I suspect your problem is related to the 2 cycle delay when
reloading the register before the timer starts counting again, possibly
combined with not dealing with the offset count between the interrupt point,
and the count value when you reload.
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@122808
by
Scott Dattalo
|
On Tue, 3 Feb 2004, Anno, Jeff wrote:
> Hello Pic People,
>
> I am working on a cycle time monitoring project that uses a 16F628 (4.000
> MHz, external crystal) with an LCD (16X2) and the built in USART (async at
> 19200). When a button is pressed, the time (in milliseconds) is reported to
> the computer and the time is reset. I am using TMR0 with a 1:4 TMR0 Rate. I
> would like to get an interrupt every 1.0000 ms, but right now it is not
> quite correct. Everything seems to be working except getting the exact
> interrupt time.
If changing the oscillator frequency or switching to TMR2 do not work then
you may wish to consider another option. At every TMR0 interrupt, a
quantum of time will have passed by. You can easily accumulate these
quanta and convert the time to milliseconds:
TMR0_interrupt:
increment TMR0_RollOver flag
...
Main code:
while(TMRO_RollOver flag is greater than 0) {
decrement TMR0 RollOver flag
accumulated time = accumulated time + time for a TMR0 rollover
}
The reason for the counter is that you don't have to be too concerned
about missing an interrupt. Of course, this assumes that the TMR0 rollover
rate is faster than a millisecond. Or you may wish to place this untested
code directly in the interrupt routine.
radix dec
; uS_hi, uS_lo -- time in microseconds
; mS_hi, mS_lo -- time in milliseconds
TMRO_ROLLOVER_TIME EQU 256 * (TMR0_PRESCALE+1) * FOSC / 1000000 / 4
MOVLW LOW(TMRO_ROLLOVER_TIME)
ADDWF uS_lo,F
RLF known_zero,F ; pick up the carry
ADDLW HIGH(TMRO_ROLLOVER_TIME)
ADDWF us_hi,F
; if more than a thousand micro seconds have gone by, then
; subtract 1000 from the micro second counter and increment
; the millisecond counter:
MOVLW LOW(-1000) ;add -1000 is the same as subtracting
ADDWF uS_lo,W ;
RLF known_zero,W ;pick up the borrow
ADDLW HIGH(-1000) ;
ADDWF us_hi,W ;
SKPC
RETURN ;or GOTO... ; less than 1000 uS
; have been accumulated
; subtract 1000 from the uS counter
MOVWF us_hi ; W already holds the high byte.
MOVLW LOW(-1000) ;redo the low byte subtraction
ADDWF us_lo,F
INCF ms_lo,F ; Increment the millisecond counter
SKPNZ
INCF ms_hi,F
;(if the millisecond counter is more than 16-bits wide, then
; an extra SKPNZ / INCF can extend the counter.
Scott
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@143536
by
James Nick Sears
If you are using MPLAB the stopwatch feature is nice for getting rid of
those off by a few cycles timing errors.
Nick
{Original Message removed}
2004\02\03@162742
by
Andrew Warren
|
Anno, Jeff <.....PICLISTKILLspam
@spam@mitvma.mit.edu> wrote:
> If I preload the TMR0 register the reported time value is totally
> wrong. If I don't preload the value then the actual time is =
> (reported time from pic * 1.024) + (constant). The constant is a
> fixed value to compensate for writing to the Serial Port.
Jeff:
Your math is all correct, but you're missing some subtle details:
a) There's a certain amount of non-constant interrupt latency
time for which you need to compensate.
b) Writing to TMR0 stops the timer for two cycles.
c) Writing to TMR0 resets the prescaler.
To fix problem a), don't use MOVWF to reload the register; use ADDWF
instead. This also compensates for the time taken by your serial-
port code, so there's no longer any need to incorporate that time
into your reload value.
To fix problems b) and c), you need to know exactly where in its
count your prescaler is, so you can write to it two cycles before the
TMR0 register increments. Since you can't read the prescaler value
directly, nor sample and the test the TMR0 register fast enough to
catch the cycle in which it increments, you need to do something like
this to reload TMR0 in your interrupt-service routine:
; On entry, value of TMR0 and the prescaler are unknown.
BTFSS TMR0,0 ; Wait for TMR0's bit 0 to be
GOTO $-1 ; set, then wait 2 cycles.
; At this point, TMR0 and prescaler values
; must be one of the following:
;
; TMR0 Prescaler
; xxxxxxx1 2
; xxxxxxx1 3
; xxxxxxx0 0
; xxxxxxx0 1
BTFSC TMR0,0 ; Wait either 3 or 4 cycles.
GOTO $+1 ;
NOP ;
; At this point, TMR0 and prescaler values
; must be one of the following:
;
; TMR0 Prescaler
; xxxxxxx0 2
; xxxxxxx0 3
; xxxxxxx1 0
BTFSS TMR0,0 ; Wait either 4 or 5 cycles.
GOTO $+1 ;
GOTO $+1 ;
; At this point, TMR0 and prescaler values
; must be one of the following:
;
; TMR0 Prescaler
; xxxxxxx1 3
; xxxxxxx0 0
BTFSC TMR0,0 ; Wait either 2 or 3 cycles.
GOTO $+1 ;
; At this point, TMR0 and prescaler value
; must be:
;
; TMR0 Prescaler
; xxxxxxx0 2
GOTO $+1 ;Waste two cycles.
; At this point, TMR0 increments.
MOVLW RELOAD ; Reload TMR0. These two
ADDWF TMR0 ; instructions take 2 cycles,
; then TMR0 stops for 2 cycles,
; so TMR0 will start counting
; again just at the right time,
; 4 cycles after the previous
; increment.
As usual, this code hasn't been tested or even assembled; I just
typed it into my email client. Let me know if it works.
-Andy
=== Andrew Warren -- aiw
KILLspamcypress.com
=== Principal Design Engineer
=== Cypress Semiconductor Corporation
===
=== Opinions expressed above do not
=== necessarily represent those of
=== Cypress Semiconductor Corporation
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@163825
by
Anno, Jeff
Andy,
Thank You!!!! This helped tremendously, I'll try it tomorrow.
Thanks to EVERYONE who helped out. This list is the best!
-Jeff
{Original Message removed}
2004\02\03@173231
by
Andrew Warren
Anno, Jeff <.....PICLISTKILLspam
.....mitvma.mit.edu> wrote:
> Thank You!!!! This helped tremendously, I'll try it tomorrow.
You're welcome, Jeff, I hope it works.
Thinking about it now, I realize that it might be off by one...
You may have to add RELOAD+1 instead of RELOAD. Not sure,
though, and don't have any time today to go through it to be
sure.
-Andy
=== Andrew Warren -- EraseMEaiwspam_OUT
TakeThisOuTcypress.com
=== Principal Design Engineer
=== Cypress Semiconductor Corporation
===
=== Opinions expressed above do not
=== necessarily represent those of
=== Cypress Semiconductor Corporation
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@174516
by
Olin Lathrop
Andrew Warren wrote:
> Thinking about it now, I realize that it might be off by one...
> You may have to add RELOAD+1 instead of RELOAD. Not sure,
> though, and don't have any time today to go through it to be
> sure.
I know timer 0 can be made to work here, but I still haven't heard a good
reason the OP can't use timer 2. It's got hardware specifically for
creating a periodic interrupt, and would be "set and forget" in this
application. What's the problem?
*****************************************************************
Embed Inc, embedded system specialists in Littleton Massachusetts
(978) 742-9014, http://www.embedinc.com
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\03@181805
by
Andrew Warren
Olin Lathrop <PICLIST
spam_OUTmitvma.mit.edu> wrote:
> I know timer 0 can be made to work here, but I still haven't heard
> a good reason the OP can't use timer 2. It's got hardware
> specifically for creating a periodic interrupt, and would be "set
> and forget" in this application. What's the problem?
There's no "problem"... But he didn't ask about Timer2, so I
didn't give him an answer that involved Timer2.
-Andy
=== Andrew Warren -- @spam@aiwKILLspam
cypress.com
=== Principal Design Engineer
=== Cypress Semiconductor Corporation
===
=== Opinions expressed above do not
=== necessarily represent those of
=== Cypress Semiconductor Corporation
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.
2004\02\04@102039
by
John Hansen
At 02:54 PM 2/3/2004 +0000, you wrote:
>.Since an instruction cycle runs every 4th clock cycle, at 4MHz,
> >that gives me 1,000,000 instruction cycles/second.
>
>However I suspect your problem is related to the 2 cycle delay when
>reloading the register before the timer starts counting again, possibly
One easy way to set this up is the use the stopwatch in the MPLAB
simulator. Instead of counting instruction cycles you can simply run the
code between any two points and let the stopwatch tell you how much time
has elapsed. Then you can adjust the value you are putting into the timer
until you get the amount of time that you want.
John Hansen
--
http://www.piclist.com#nomail Going offline? Don't AutoReply us!
email KILLspamlistservKILLspam
mitvma.mit.edu with SET PICList DIGEST in the body
More... (looser matching)
- Last day of these posts
- In 2004
, 2005 only
- Today
- New search...