View previous topic :: View next topic |
Author |
Message |
dan king
Joined: 22 Sep 2003 Posts: 119
|
CCP1 rollover |
Posted: Wed Oct 26, 2016 1:39 pm |
|
|
I'm using CCP1 tied to an IR RX/TX pair to measure the speed of an object passing by (18F2553). I've never used the CCP module before but I do have working code modified from the code library that works but my issue is, how do I handle the pulse count delta when an object passes by that is slower than the 16 bit timer can store? I have TIMER1 set to the slowest count rate (div_8). Since the delta is generated by the difference of the start and stop edges, I can't even monitor if TIMER1 rolled over since the start edge may have been near 65535 at the starting (falling in my case) edge.
Any insight is appreciated.
Thanks,
Dan |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Wed Oct 26, 2016 1:45 pm |
|
|
The CCP doesn't roll over. The timer does.
When the timer rolls over, it can generate an interrupt.
Increment a counter in the interrupt for the timer.
Then when the CCP interrupts, you can use a 32 bit value from the CCP (low 16bits) combined with the counter from the timer interrupt (make32, or combine the values using a union).
Just make sure the timer interrupt has higer priority than the CCP one. The CCP 'holds' the logged time, so can be read at any point until the next edge. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Oct 26, 2016 2:02 pm |
|
|
Would that require that the initial TIMER1 value be 0 at the instant the starting CCP interrupt occurred? The code sample I'm using allows TIMER1 to free run and the ISR captures the start and stop values from TIMER1 so the first TIMER1 interrupt may not indicate an overflow for the first time through. Can I set_TIMER1(0) at the start of a capture in the CCP ISR?
I will generate a small test program to show my code shortly.
I understand the CCP doesn't roll over, poor word choice on my part.
Thanks for the fast response. |
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Wed Oct 26, 2016 2:11 pm |
|
|
Excellent, that works. Thanks for the guidance.
Dan |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Thu Oct 27, 2016 1:16 am |
|
|
Good.
No, you don't want to set the timer to zero in the first ISR (actually this is OK for slow signals, but otherwise can cause problems, since it takes time to get into the ISR). All of these approaches are best done by working holding the 'last' and 'current' values, and then calculating using the 'delta' between these.
Though you have got it working, it is worth looking at an approach like:
Code: |
union {
int16 word16[2];
int32 whole;
} CCPval;
int32 delta=0;
#INT_TIMER1
void timer_overflow(void)
{
CCPval.word16[1]++; //increments the high 16 bits
}
#INT_CCP1
void ccp_got_edge(void)
{
static int32 old;
static int1 OK=FALSE;
CCPval.word16[0]=CCP1; //copy the 16bits from the CCP register
if (OK)
{
delta=CCPval.whole-old; //calculate the delta between the calls
}
else
OK=TRUE; //start working after second call
old=CCPval.whole;
}
|
Now, this requires _two_ calls before it'll update delta (this is the point of the 'OK' flag). Does the maths as 32bit, combining the 16bits from the CCP, with the timer overflow count. delta is the 32bit difference count between the calls.
In the 'main', once delta is non zero, you have a working value.
Beware though. Remember that the chip only accesses 'byte at a time', so you need to disable interrupts, and copy 'delta; into the value you are going to use in the main (or do a repeated copy, and check that it hasn't changed). So:
Code: |
int32 local_delta;
//then to read delta.
//either
disable_interrupts(GLOBAL);
local_delta=delta;
enable_interrupts(GLOBAL);
//or
while (local_delta != delta)
local_delta=delta;
//then work with the local copy
|
|
|
|
dan king
Joined: 22 Sep 2003 Posts: 119
|
|
Posted: Thu Oct 27, 2016 10:19 am |
|
|
I just used the principle of your example extending the timing to 32 bits and the results are excellent. That makes much better sense in that I don't need to worry about the state of the timer1 overflow and just let everything run. Thanks again for the help.
Dan |
|
|
|