PDA

View Full Version : Why does TIMER slow down when using longer pause



GrandPa
- 5th July 2007, 17:43
This is probably a beginner question but I've look everywhere and can't find any answer. I'm using PicBasic Pro with Microcode Studio and COLT Bootloader. This is PIC 18F4620, internal clock, 4X PLL.

I have this very simple program and the count (TMR var) is slowing down with a longer pause. Can someone explain why? Is this because I'm using internal clock?

Thanks!

'PIC 18F4620
DEFINE RESET_ORG 800h
DEFINE OSC 32

DEFINE LCD_LINES 4
define LCD_DREG PORTD
DEFINE LCD_RSREG PORTC
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTC
DEFINE LCD_EBIT 1

OSCCON = %11110000 '8 mhz, internal osc
OSCTUNE = %11000000 '4x PLL enabled
INTCON = %10100000 'Interrupt enabled

T0CON.0 = 1 '1:256 prescaler
T0CON.1 = 1
T0CON.2 = 1
T0CON.3 = 0 'prescaler enabled
T0CON.4 = 1
T0CON.5 = 0 'int clk
T0CON.6 = 0 '16 bits timer
T0CON.7 = 1 '0= disabled

TMR var word 'Speed waves Min speed

on interrupt goto SetTime

TMR = 0

start:
LCDout $FE,1, "timer: " , #tmr
pause 500
goto start

'pause = 50 ---> count up to 1450 approx (30 sec)
'pause = 500 ---> count up to 150 approx (30 sec)

disable
SetTime:
TMR = TMR + 1
resume
enable

end

Dave
- 5th July 2007, 18:03
GrandPa , Although you are running an interrupt routine it will wait for the pause command to finish before servicing the interrupt. The interrupt flag is set right away but the call isn't made untill the command is finished. It's in the manual....

Dave Purola,
N8NTA

skimask
- 5th July 2007, 18:16
This is probably a beginner question but I've look everywhere and can't find any answer.
It's not in there...kinda/sorta between the lines it is...kinda...
If you're using the 'On Interrupt', PBP won't check 'Interrupts' until it's finished executing the current command.
So, for example, if you've set up the progam to get a TMR interrupt every 100ms, and you've got a 500ms pause, you'll most likely miss 4-6 timer interrupts, because PBP is busy concentrating on the PAUSE (or ignoring the interrupts, whichever way you like it.
It's not because you're using the internal clock, it's the way you've got it set up.
If you use a short pause in a loop to create a longer pause, you'll get more repeatable results over a larger range of pauses.
There are other ways of doing this, but this should get you started...
Another thought...you might NOT want to use TMR as a variable...too close to TMR0, TMR1, etc.etc...

DEFINE RESET_ORG 800h
DEFINE OSC 32
DEFINE LCD_LINES 4
define LCD_DREG PORTD
DEFINE LCD_RSREG PORTC
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTC
DEFINE LCD_EBIT 1
osccon=$f0 : osctune=$c0 : intcon=$a0 : t0con=$97 : tmr var word : temp var word
on inter rupt goto SetTime
TMR = 0
enable
start: LCDout $FE,1, "timer: " , #tmr
for temp = 1 to 500
pause 1
next temp
goto start
disable
SetTime:
TMR = TMR + 1 : resume
enable
end


EDIT: I see Dave beat me to the punch!

GrandPa
- 5th July 2007, 21:59
I would like first to thank Dave and Skimask for their answer. Actually I submitted a simplified version of the proble I got with timer.

I first tried with this. As you can see I used TIMER1 as the clock source for TIMER3. Then I read TMR3H and TMR3L in a loop.

Without any interrupt and I can't see why the Timer register is affected by how often it is read during a certain time. This is why I tried with no luck using interrupt. So the question is still the same. Why do I get different values when I use longer pause ???


DEFINE RESET_ORG 800h
DEFINE OSC 32

DEFINE LCD_LINES 4
DEFINE LCD_DREG PORTD
DEFINE LCD_RSREG PORTC
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTC
DEFINE LCD_EBIT 1

OSCCON = %11110000 '8 mhz, internal osc
OSCTUNE = %11000000 '4x PLL enabled

T1CON.7 = 1 '16 bits read/write
T1CON.6 = 0 'clock from internal osc
T1CON.5 = 1 '1:8 prescale
T1CON.4 = 1 '1:8 prescale
T1CON.3 = 0 'osc shut off
T1CON.2 = 1
T1CON.1 = 0 'Internal clock
T1CON.0 = 1 'enabled

T3CON.7 = 1 '16 bits read/write
T3CON.5 = 1 '1:8 prescale
T3CON.4 = 1 '1:8 prescale
T3CON.1 = 1 'clock from timer1
T3CON.0 = 1 'enabled

myTMR var word
myTMR = 0
TMR3H = 0
TMR3L = 0

start:
gosub gettime
LCDout $FE,1, "timer: " , #myTMR
pause 500
goto start

'pause = 50 ---> count up to 660 approx (30 sec)
'pause = 500 ---> count up to 60 approx (30 sec)

getTime
myTMR.BYTE1 = TMR3H
myTMR.BYTE0 = TMR3L
return

end

skimask
- 5th July 2007, 23:14
I would like first to thank Dave and Skimask for their answer. Actually I submitted a simplified version of the proble I got with timer.

I first tried with this. As you can see I used TIMER1 as the clock source for TIMER3. Then I read TMR3H and TMR3L in a loop.

Without any interrupt and I can't see why the Timer register is affected by how often it is read during a certain time. This is why I tried with no luck using interrupt. So the question is still the same. Why do I get different values when I use longer pause ???


I'd be willing to bet that TMR3 is rolling over so fast, that you're not seeing the actual value; you're actually seeing just the lower 16 bits of that value. If TMR3 had 32 bits, you might see the value increasing past 65535.
The difference between using pause 50 and pause 500 might be just enough difference in the number of instructions to give you that difference that you're seeing.
Try this and see how fast it actually rolls over:
I added another counter that'll pick up the number of times that TMR3 rolled over and a counter that'll show you how fast the loop goes thru (which really doesn't have anything to do with how fast TMR3 counts other than the oscillator's speed).
DEFINE RESET_ORG 800h
DEFINE OSC 32
DEFINE LCD_LINES 4
DEFINE LCD_DREG PORTD
DEFINE LCD_RSREG PORTC
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTC
DEFINE LCD_EBIT 1
OSCCON = %11110000 '8 mhz, internal osc
OSCTUNE = %11000000 '4x PLL enabled
T1CON.7 = 1 '16 bits read/write
T1CON.6 = 0 'clock from internal osc
T1CON.5 = 1 '1:8 prescale
T1CON.4 = 1 '1:8 prescale
T1CON.3 = 0 'osc shut off
T1CON.2 = 1
T1CON.1 = 0 'Internal clock
T1CON.0 = 1 'enabled
T3CON.7 = 1 '16 bits read/write
T3CON.5 = 1 '1:8 prescale
T3CON.4 = 1 '1:8 prescale
T3CON.1 = 1 'clock from timer1
T3CON.0 = 1 'enabled
myTMR var word
oldmyTMR var word
myTMR = 0
rollover var word
timesthru var word
TMR3H = 0
TMR3L = 0
lcdout $fe , 1
start:
myTMR.byte1 = tmr3h
myTMR.byte0 = tmr3l
if oldmyTMR > myTMR then rollover = rollover + 1 'TMR3 rolled over back to zero because the old value is greater than the new value
LCDout $FE,$80, "timer:" , DEC myTMR , " "
lcdout $fe , $c0, "rollover:",DEC rollover, " "
lcdout $fe , $94, "times thru:", DEC timesthru, " "
oldmyTMR = myTMR
timesthru = timesthru + 1
goto start

GrandPa
- 6th July 2007, 00:35
Hi and thank you for all that tried to help.

I made 2 BIG mistakes that make it failed.

FIRST: I assumed that when using TIMER1 clock as the source for TIMER3 I will have the output of the timer (with prescaler). Seems to be wrong, I'm just using the same clock that's all.

SECOND: ----- This was the real catch ------
I'm using PORTC.0 and PORTC.1 for the LCD display. C0 is also TIMER3 clk input. C1 is TIMER1 osc input. I fist moved the LCD wires to somewhere else and I was amazed to find out that TIMER3 stopped. I know think that I was sending some clock signal with the LCD. One thing that help me find this was that I had about 1 count for every pass within the loop. hehehe

I solved this issue by using HPWM out to T0CK1 input.


Thanks again!