Essentially Timer1 is reset and started by a regular event (interrupt triggered by an edge on GPIO.2) from that point onward I need to generate a couple of pulses at specific times by referencing the timer registers ... (Timer1 does not have time to generate an overflow - if it does it goes to sleep and waits for an input on GPIO.2)
It all seems to work as expected but closer examination of a simple LED flash indicator exhibits an unexpected behaviour - it sometimes generates a much briefer pulse than the designed 1mS.
so ...
c1mSTime = 250 i.e. 250 x 4 uS
PulseWidth = c1mSTime + Timer1
GPIO.4 = 1
loop3:
Compare(Timer1, PulseWidth)
movwf CompResult
if (CompResult <> cGreaterThan) then
goto loop3
end if
GPIO.4 = 0
Compare is a word comparison function in assembler the result of which returns in the w reg (didn't know if there's a way to get it back as a direct return from the function name reference).
Now ... is what I am doing bad practice ? Timer1 continues running and I was wondering if the timer's registers are getting updated during my testing.
So how does my code fail and make an unexpected short pulse ?
All the examples I can find do these things by preloading the timer and looking out for the overflow flag - which I can't do in this case.
I plan to look at CCP support as this might be an better alternative but I'd like to understand why my initial solution is misbehaving but would value a "best" practice solution suggestion.
All a bit new at the moment - started simple but now feel as though I fell in the deep end !
Thanks
Andrew
Last edit: Andrew Jameson 2021-03-10
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Most PIC have instruction cycles measured in Nano Seconds so a Micro Second is a long time to many devices.
I suspect your short pulse is a glitch generated by the timer rollover.
I had intended to follow up on the millis() function with a micros() Function exposed as a software interrupt but as the PIC architecture fails to implement an IRQ instruction I put it on the back burner.
If you look in the GCBASIC\libraries folder you will find millis.h.
Have a read through that and you will get a better understanding of how I handled the rollover and timer portability.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There are times when programming feels like opening a combination lock - worse, you're never certain if the door is actually there.
According to the datasheets the CCP compare mode is continuously watching Timer1. So if Timer1 is running, it must at some stage match the state of the CCPR1 register and I would have expected it to the set CCP1IF.
So - reducing it to the tiniest code fragment :
It's a 12f683 :
CCP1CON = 0x0A
CCPR1L = 255
CCPR1H = 1
TMR1ON = 1
do
if (PIE1.CCP1IF = 1) then
PIE1.CCP1IF = 0
ss = ss + 1
end if
loop
Needless to say ss never gets incremented - what am I missing ?
Thanks
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Found it ! And it is covered by a Microchip application note. Reading non-latched live timer registers ... by the time I've read TMR1H, TMR1L has incremented and overflowed into TMR1H ... I spotted that Timer1 was varying around a count of 240 - 260 and that was the key.
The solution would be to do a multiple read - which is what Microchip suggest or to stop the timer to take a copy of the registers.
Ideally I'd like to find out how to trigger a CCP timer match interrupt. The interrupt works if I set the CCP mode select bits as 1011 but it resets Timer1 count to zero ... I can't get CCP mode select bit 1010 to trigger an interrupt - datasheet says "yes" - chip says "no". (Don't want to involve the CCP1 pin as I'm using its INT support; an input.)
In the interim, might have a look at using 1011 trigger and then restore Timer1's registers back to what they had been.
Any comment ?
Thanks Andrew
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Got it working without having to reset Timer1. The CCP1IF bit flag seems to be only valid from within the interrupt handler :
12F683
CCP1CON = 0b00001010
On Interrupt CCP1 Call CCP1_Interrupt_Handler
sub CCP1_Interrupt_Handler
if (CCP1IF = 1) then
CCP1IF = 0
CCPMatchFlag = 1
end if
end sub ;(CCP1_Interrupt_Handler)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
PIC in question is a 12f683 ...
Essentially Timer1 is reset and started by a regular event (interrupt triggered by an edge on GPIO.2) from that point onward I need to generate a couple of pulses at specific times by referencing the timer registers ... (Timer1 does not have time to generate an overflow - if it does it goes to sleep and waits for an input on GPIO.2)
It all seems to work as expected but closer examination of a simple LED flash indicator exhibits an unexpected behaviour - it sometimes generates a much briefer pulse than the designed 1mS.
so ...
c1mSTime = 250 i.e. 250 x 4 uS
PulseWidth = c1mSTime + Timer1
GPIO.4 = 1
loop3:
Compare(Timer1, PulseWidth)
movwf CompResult
if (CompResult <> cGreaterThan) then
goto loop3
end if
GPIO.4 = 0
Compare is a word comparison function in assembler the result of which returns in the w reg (didn't know if there's a way to get it back as a direct return from the function name reference).
Now ... is what I am doing bad practice ? Timer1 continues running and I was wondering if the timer's registers are getting updated during my testing.
So how does my code fail and make an unexpected short pulse ?
All the examples I can find do these things by preloading the timer and looking out for the overflow flag - which I can't do in this case.
I plan to look at CCP support as this might be an better alternative but I'd like to understand why my initial solution is misbehaving but would value a "best" practice solution suggestion.
All a bit new at the moment - started simple but now feel as though I fell in the deep end !
Thanks
Andrew
Last edit: Andrew Jameson 2021-03-10
Did you consider using the Millis() function to handle the timing for you?
it would make your code less device dependent and more portable too.
https://sourceforge.net/p/gcbasic/discussion/629990/thread/ff0785c717/
Thanks Chris,
It's a thought but I need to get down to pulses in the range of 100uS - 200uS.
Do you think that CCP can do it ? I thought that I could just stick the value I want into the CCP registers and sit and wait for a flag ?
Rather than move away from what I'd implemented, I'd like to understand why it fails and creates a short pulse.
The CCP can easily do that.
Most PIC have instruction cycles measured in Nano Seconds so a Micro Second is a long time to many devices.
I suspect your short pulse is a glitch generated by the timer rollover.
I had intended to follow up on the millis() function with a micros() Function exposed as a software interrupt but as the PIC architecture fails to implement an IRQ instruction I put it on the back burner.
If you look in the GCBASIC\libraries folder you will find millis.h.
Have a read through that and you will get a better understanding of how I handled the rollover and timer portability.
Hi Chris and et al ...
There are times when programming feels like opening a combination lock - worse, you're never certain if the door is actually there.
According to the datasheets the CCP compare mode is continuously watching Timer1. So if Timer1 is running, it must at some stage match the state of the CCPR1 register and I would have expected it to the set CCP1IF.
So - reducing it to the tiniest code fragment :
It's a 12f683 :
CCP1CON = 0x0A
CCPR1L = 255
CCPR1H = 1
TMR1ON = 1
do
if (PIE1.CCP1IF = 1) then
PIE1.CCP1IF = 0
ss = ss + 1
end if
loop
Needless to say ss never gets incremented - what am I missing ?
Thanks
Just a thought - what are you using as the TIMER1 clock source? Maybe the clock source is not working.
Thanks David but Timer1 is running and using Fosc4 :
TICON = 0b00000001
Found it ! And it is covered by a Microchip application note. Reading non-latched live timer registers ... by the time I've read TMR1H, TMR1L has incremented and overflowed into TMR1H ... I spotted that Timer1 was varying around a count of 240 - 260 and that was the key.
The solution would be to do a multiple read - which is what Microchip suggest or to stop the timer to take a copy of the registers.
Ideally I'd like to find out how to trigger a CCP timer match interrupt. The interrupt works if I set the CCP mode select bits as 1011 but it resets Timer1 count to zero ... I can't get CCP mode select bit 1010 to trigger an interrupt - datasheet says "yes" - chip says "no". (Don't want to involve the CCP1 pin as I'm using its INT support; an input.)
In the interim, might have a look at using 1011 trigger and then restore Timer1's registers back to what they had been.
Any comment ?
Thanks Andrew
Got it working without having to reset Timer1. The CCP1IF bit flag seems to be only valid from within the interrupt handler :
12F683
CCP1CON = 0b00001010
On Interrupt CCP1 Call CCP1_Interrupt_Handler
sub CCP1_Interrupt_Handler
if (CCP1IF = 1) then
CCP1IF = 0
CCPMatchFlag = 1
end if
end sub ;(CCP1_Interrupt_Handler)
You're checking the wrong register.
The CCP1IF intr flag bit is in PIR1, not PIE1. PIE1 is the intr enable register (CCP1IE).
Hi Jerry,
Amazing what effect a typo can make ! It's gone from utter frustration and code that didn't work to one where everything works as expected !
So grateful for your keen observation !
Regards,
Andrew