Hi,
Well, I rarely post about code problems, because its almost always a dumb mistake on my part, and I'm sure this one is no different.
Background:
Like many projects on the web, I'm using the 'capture' mode of the CCP module on a PIC16F684 (newer pics don't have extra functionality so I used this one to test). Frequency input ranges from roughly 2Hz to ~350Hz, and I'm having trouble picking up overflow of timer1 (when input is less than ~2Hz).
With a 4MHz clock, /8 prescaler, max period is 65535 * 8us = ~524ms.
I have some other things going on, like a timer pinging every 100ms that sets a flag to tell the main routine to send something via SPI, so, the capture mode of the CCP module, along with interrupts is handy.
The basic idea is, whenever the capture fires (every rising edge) its interrupt saves the capture results, along with a copy of how many times timer1 has overflowed. Sets a flag to indicate a capture, then use the following pseudo code:
So my main routine just looks for the 'capture found' flag, and just checks if Measured period is less than 65536 before doing anything.
For debugging, when it overflows, I send a byte out a software UART (tested and working fine). Every so often, almost randomly - maybe once every.. 30 seconds - it sends out an overflow byte, despite capturing a frequency well within its range.
I have used the above equation in the interrupt, in the main routine (when checking for the flag) and both give the same results. That is, its very accurate the majority of the time, but occasionally, it measures a period over 16-bits. I am fairly sure there is a problem with the overflow_count, as this would cause erroneous results from the above equation.
Here's some proper code for the interrupt:
And in the main routine...
So, Period_val is a uint - 16-bit variable, Period_val_long_a is a unsigned long, 32-bits. The above code will occasionally spit out a 'P' from the UART despite a continuous input of around 100Hz. The other part of the main code computes an RPM value from the period, using a division routine (fully tested) and most of the time, the result is bang on.
If anyone has some working reliable interrupt driven CCP capture code, to continuously measure an input period *and* detect overflow, I would be grateful. So far the only one I have found that does this is here:
https://www.ccsinfo.com/forum/viewtopic.php?t=53557&highlight=ccp
https://www.ccsinfo.com/forum/viewtopic.php?t=53557&highlight=ccp
I can follow it, but there are subtle differences between CSS and mikroC. For example, it has separate routines for each interrupt source, where-as I have a single ISR, that checks each flag every time. It could be that I suppose, I have so many versions to check :/
Sorry for posting yet another 'I'm stuck!' question. But I usually over complicated things to the point I can't see the simple mistakes.
Cheers,
BT.
Ps. Roman, big fan of your website, and timing code, would appreciate your input here!
Well, I rarely post about code problems, because its almost always a dumb mistake on my part, and I'm sure this one is no different.
Background:
Like many projects on the web, I'm using the 'capture' mode of the CCP module on a PIC16F684 (newer pics don't have extra functionality so I used this one to test). Frequency input ranges from roughly 2Hz to ~350Hz, and I'm having trouble picking up overflow of timer1 (when input is less than ~2Hz).
With a 4MHz clock, /8 prescaler, max period is 65535 * 8us = ~524ms.
I have some other things going on, like a timer pinging every 100ms that sets a flag to tell the main routine to send something via SPI, so, the capture mode of the CCP module, along with interrupts is handy.
The basic idea is, whenever the capture fires (every rising edge) its interrupt saves the capture results, along with a copy of how many times timer1 has overflowed. Sets a flag to indicate a capture, then use the following pseudo code:
Code:
If (New_capture < Old_Capture)
Overflow_count--
Measured period = (Overflow_count * 65536) + New_capture - Old_capture;
Old_capture = New_Capture
So my main routine just looks for the 'capture found' flag, and just checks if Measured period is less than 65536 before doing anything.
For debugging, when it overflows, I send a byte out a software UART (tested and working fine). Every so often, almost randomly - maybe once every.. 30 seconds - it sends out an overflow byte, despite capturing a frequency well within its range.
I have used the above equation in the interrupt, in the main routine (when checking for the flag) and both give the same results. That is, its very accurate the majority of the time, but occasionally, it measures a period over 16-bits. I am fairly sure there is a problem with the overflow_count, as this would cause erroneous results from the above equation.
Here's some proper code for the interrupt:
Code:
void interrupt()
{
if (PIR1.TMR1IF)
{
flags.TMR1_OF = 1;
TMR1_OV_cnt1++;
PIR1.TMR1IF = 0;
}
if (PIR1.CCP1IF)
{
TMR1_OV_temp = TMR1_OV_cnt1; // get a copy of the overflow counter
TMR1_OV_cnt1 = 0; //
Old_capture = New_capture;
Hi(New_capture) = CCPR1H;
Lo(New_capture) = CCPR1L;
// check if timer1 overflowed whilst we are servicing this:
if (PIR1.TMR1IF)
{
if (Hi(New_capture) == 0)
{
TMR1_OV_temp++;
TMR1_OV_cnt1++;
PIR1.TMR1IF = 0;
}
}
// get difference
Period_val_long = (New_capture - Old_capture);
if (Old_capture > New_capture)
{
TMR1_OV_temp--; // if the new is less than the old , allow one overflow
}
Higher(Period_val_long) = TMR1_OV_temp; // add 16*overflow to our 24-bit counter.
flags.Cap_found = 1;
PIR1.CCP1IF = 0;
}
And in the main routine...
Code:
do {
if (flags.TMR1_OF)
{
flags.TMR1_OF = 0;
if (TMR1_OV_cnt1 > 1)
{
TMR1_OV_cnt1 = 3; // cap our overflow
SoftUARTsend('O');
continue;
}
}
if (flags.Cap_found) // if we have a capture
{
flags.Cap_found = 0;
// disable interrupts to copy ISR value)
INTCON.GIE = 0;
Period_val_long_a = Period_val_long;
INTCON.GIE = 1;
if (Higher(Period_val_long_a)) // just checks the second MSByte of a long, anything other than 0, means its > 65535 = overflow.
{
LED1 = 0;
SoftUARTsend('P');
continue;
}
Period_val = Period_val_long_a; // truncate to 16-bits, as upper 16-bits are 0
So, Period_val is a uint - 16-bit variable, Period_val_long_a is a unsigned long, 32-bits. The above code will occasionally spit out a 'P' from the UART despite a continuous input of around 100Hz. The other part of the main code computes an RPM value from the period, using a division routine (fully tested) and most of the time, the result is bang on.
If anyone has some working reliable interrupt driven CCP capture code, to continuously measure an input period *and* detect overflow, I would be grateful. So far the only one I have found that does this is here:
https://www.ccsinfo.com/forum/viewtopic.php?t=53557&highlight=ccp
https://www.ccsinfo.com/forum/viewtopic.php?t=53557&highlight=ccp
I can follow it, but there are subtle differences between CSS and mikroC. For example, it has separate routines for each interrupt source, where-as I have a single ISR, that checks each flag every time. It could be that I suppose, I have so many versions to check :/
Sorry for posting yet another 'I'm stuck!' question. But I usually over complicated things to the point I can't see the simple mistakes.
Cheers,
BT.
Ps. Roman, big fan of your website, and timing code, would appreciate your input here!