|
|
View previous topic :: View next topic |
Author |
Message |
turbo2ltr
Joined: 27 Jan 2005 Posts: 12
|
Timer overflow handling using both CCP modules |
Posted: Wed Mar 30, 2005 3:52 pm |
|
|
I'm trying to use the free running 16bit timer 1 and the CCP modules in capture mode to capture the pulsewidth of two external (async) signal. Everything is working except for a glitch every so often.
Code: |
#int_timer1
void TimerISR()
{
OverFlow1++;
OverFlow2++;
}
#int_ccp1
void CcpISR()
{
CapFinish1 = CCP_1; // get the val
CCP1Update = true; // set the flag to notivy handler
OverFlow1b = OverFlow1; // get the overflow val
OverFlow1 = 0;
}
#int_ccp2
void Ccp2ISR()
{
CapFinish2 = CCP_2;
CCP2Update = true;
OverFlow2b = OverFlow2;
OverFlow2 = 0;
} |
The problem arises when the following occurs:
CCP1 interrupt is trigered. While in the CCP1 ISR, a CCP2 Interrupt occurs and then a TMR1 interrupt occurs, both before the CCP1 ISR finishes. When the CCP1 ISR is done, the assembly shows that the TMR 1 ISR has priority. When the TMR 1 ISR executes, the OverFlows are incrimented, but the CCP2 already captured the timer before the rollover occurred. So when the CCP2 ISR finally runs, I end up with an "extra" Overflow count this time, and then the next capture ends up missing one overflow.
I can't possibly be the first person to run into this problem. There is no way that I can see to figure out what interrupt came in first. So far my only idea is to write my own #int_global routine that would allow me to enable the interrupts before actually finishing the original interupt...which of course would get really messy.
Any other ideas?
This is on a 16F873.
Thanks,
Mike |
|
|
Guest
|
|
Posted: Wed Mar 30, 2005 4:29 pm |
|
|
u should turn off all the interrupts while in a isr,
i have a problem similar to yours.I search the samples on this forum
however all samples are weak,and dont let to rollover the timer1 more than 1,so write this code and tested with pic16f74 it is working with 0.5Hz-300khz without any change in software this 300khz limitation is the time required to enter an isr i used 20mhz xtal so,this code is powerful than the others from this forum,i use only one ccp pin but the two ccp can be used also u must change it accordingly.
******
If u modify this code and obtain a better performance please let me know!!!!!!!
******
Here is the complete program.
/***********************************************************************
***********************************************************************
***********************************************************************
***********************************************************************
Frekans metre 0.5hz-300khz arasi test edildi.Iyı calisiyor.
Timer1 kesmesini kullanmaz direk timer1if degeri kontrol edelirsede calisiyor
yaklasik ayni calisiyor.
***********************************************************************
***********************************************************************
***********************************************************************/
#include <16F74.h>
#device adc=8
#fuses NOWDT,HS, PUT, NOPROTECT, BROWNOUT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
int1 ccpcapturedonce=0,capbitti=0;
unsigned int rollover=0;
int16 ccpeski=0,ccpyeni=0,fark=0;
float sonuc=0;
#bit timer1if=0xc.0
#int_CCP1
CCP1_isr()
{
if(ccpcapturedonce==0){
timer1if=0;
enable_interrupts(INT_TIMER1);
ccpeski=CCP_1;
ccpcapturedonce=1;
rollover=0;
}
else
{
ccpyeni=CCP_1;
capbitti=1;
disable_interrupts(INT_TIMER1);
disable_interrupts(INT_CCP1);
}
}
#int_timer1
timer1_isr()
{
rollover++;
}
void main()
{
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL);
basla:
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
do{
}while(capbitti==0);
disable_interrupts(INT_TIMER1);
printf("Frequence test:\r\n");
if(ccpyeni>=ccpeski){fark=ccpyeni-ccpeski;}
else{
fark=ccpeski-ccpyeni;
if(rollover==0)rollover=1;
}
printf("eski=%lu\n",ccpeski);
printf("yeni=%lu\n",ccpyeni);
printf("fark=%lu\n",fark);
printf("roll=%U\n",rollover);
//printf("********Hesaplaniyor...\n");
if(rollover>=1){
sonuc=(1-((float)fark/65536))*13.1072+13.1072*(rollover-1);}
else {
sonuc=((float)fark/65536)*13.1072;
}
sonuc=1000/sonuc;
printf("sonuc=%f Hz\n",sonuc);
sonuc=0;
rollover=0;
ccpeski=0;
ccpyeni=0;
ccpcapturedonce=0;
capbitti=0;
goto basla;
} |
|
|
Guest
|
|
Posted: Wed Mar 30, 2005 4:29 pm |
|
|
u should turn off all the interrupts while in a isr,
i have a problem similar to yours.I search the samples on this forum
however all samples are weak,and dont let to rollover the timer1 more than 1,so write this code and tested with pic16f74 it is working with 0.5Hz-300khz without any change in software this 300khz limitation is the time required to enter an isr i used 20mhz xtal so,this code is powerful than the others from this forum,i use only one ccp pin but the two ccp can be used also u must change it accordingly.
******
If u modify this code and obtain a better performance please let me know!!!!!!!
******
Muhammed Kuzu
Here is the complete program.
/***********************************************************************
***********************************************************************
***********************************************************************
***********************************************************************
Frekans metre 0.5hz-300khz arasi test edildi.Iyı calisiyor.
Timer1 kesmesini kullanmaz direk timer1if degeri kontrol edelirsede calisiyor
yaklasik ayni calisiyor.
***********************************************************************
***********************************************************************
***********************************************************************/
#include <16F74.h>
#device adc=8
#fuses NOWDT,HS, PUT, NOPROTECT, BROWNOUT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
int1 ccpcapturedonce=0,capbitti=0;
unsigned int rollover=0;
int16 ccpeski=0,ccpyeni=0,fark=0;
float sonuc=0;
#bit timer1if=0xc.0
#int_CCP1
CCP1_isr()
{
if(ccpcapturedonce==0){
timer1if=0;
enable_interrupts(INT_TIMER1);
ccpeski=CCP_1;
ccpcapturedonce=1;
rollover=0;
}
else
{
ccpyeni=CCP_1;
capbitti=1;
disable_interrupts(INT_TIMER1);
disable_interrupts(INT_CCP1);
}
}
#int_timer1
timer1_isr()
{
rollover++;
}
void main()
{
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL);
basla:
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
do{
}while(capbitti==0);
disable_interrupts(INT_TIMER1);
printf("Frequence test:\r\n");
if(ccpyeni>=ccpeski){fark=ccpyeni-ccpeski;}
else{
fark=ccpeski-ccpyeni;
if(rollover==0)rollover=1;
}
printf("eski=%lu\n",ccpeski);
printf("yeni=%lu\n",ccpyeni);
printf("fark=%lu\n",fark);
printf("roll=%U\n",rollover);
//printf("********Hesaplaniyor...\n");
if(rollover>=1){
sonuc=(1-((float)fark/65536))*13.1072+13.1072*(rollover-1);}
else {
sonuc=((float)fark/65536)*13.1072;
}
sonuc=1000/sonuc;
printf("sonuc=%f Hz\n",sonuc);
sonuc=0;
rollover=0;
ccpeski=0;
ccpyeni=0;
ccpcapturedonce=0;
capbitti=0;
goto basla;
} |
|
|
turbo2ltr
Joined: 27 Jan 2005 Posts: 12
|
|
Posted: Wed Mar 30, 2005 4:34 pm |
|
|
It really helps if you put your code within code tags |
|
|
turbo2ltr
Joined: 27 Jan 2005 Posts: 12
|
|
Posted: Wed Mar 30, 2005 4:44 pm |
|
|
The code you posted does not help the problem I'm having. Adding the second CCP module makes a big difference in how the timer has to be handled. You just cant stop it in the CCP ISR like you are doing because the other CCP module might still be using it.
Thanks anyway. |
|
|
Guest
|
|
Posted: Wed Mar 30, 2005 5:19 pm |
|
|
i am not sure about this,i must study on it to say same thing but ccp isr can be stopped while other ccp occurs u can shutdown the other ccp and open it again however again i must study on it to say something,
I have just thing something that if u setup ccp to cap. at 16th or 4th edge u can increase the frequency band that can be measured .
Muhammed Kuzu |
|
|
Guest
|
|
Posted: Wed Mar 30, 2005 5:21 pm |
|
|
i am not sure about this,i must study on it to say same thing but ccp isr can be stopped while other ccp occurs u can shutdown the other ccp and open it again however again i must study on it to say something,
I have just thing something that if u setup ccp to cap. at 16th or 4th edge u can increase the frequency band that can be measured .
Muhammed Kuzu |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
turbo2ltr
Joined: 27 Jan 2005 Posts: 12
|
|
Posted: Wed Apr 06, 2005 11:37 am |
|
|
Thanks, while not exactly what I needed, it pointed me in the right direction to get my version to work. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Apr 07, 2005 1:25 am |
|
|
turbo2ltr wrote: |
Thanks, while not exactly what I needed, it pointed me in the right direction to get my version to work. | It would be nice to telll us how you solved your problem, this will increase our knowledge and make this forum more valuable for others to browse.. |
|
|
Guest
|
|
Posted: Thu Apr 07, 2005 8:20 am |
|
|
You got it. This code seems to work for me. It could probably stand to use some cleaning up so don't blame me if it's not 100% efficient. I think the if statement in the CCP int can be removed, but I don't want to remove it and post it saying it works without testing it.
Code: |
int32 OverFlow1;
int32 OverFlow2;
int32 OverFlow1b;
int32 OverFlow2b;
int16 CapFinish1;
int16 CapFinish1b;
int16 CapStart1;
int16 CapFinish2;
int16 CapFinish2b;
int16 CapStart2;
short CCP1Update;
short CCP2Update;
int NextOF1;
int NextOF2;
void main()
{
if(CCP1Update)
{
// handle new value here
}
if(CCP2Update)
{
// handle new value here
}
}
#int_timer1
void TimerISR()
{
// there was a timeout
// ccp1
if(bit_test(PIR1,CCP1IF) && (TMR_1 < CCP_1))
{ // if the CCP int is set and the current timer is less than the captured time
// this means that the capture was done prior to the rollover, dont incriment the overflow
// or it will be wrong when we handle the CCP interrupt. Instead remember to
// add 1 to the OverFlow after we handle the CCP int
NextOF1 = 1;
}
else
{ // even if the capture int is set, the capture val is less than the current timer so
// the capture happened after the rollover. Count the rollover now.
OverFlow1++;
NextOF1 = 0;
}
// ccp2
if(bit_test(PIR2,CCP2IF) && (TMR_1 < CCP_2))
{
NextOF2 = 1;
}
else
{
OverFlow2++;
NextOF2 = 0;
}
}
#int_ccp1
void CcpISR()
{
CapFinish1b = CCP_1;
CCP1Update = true;
if(bit_test(PIR1,TMR1IF))
{ // tmr 1 ISR pending
// means we got the tmr int after entering the CCP int
// if the tmr int occured before we entered the ccp int, it would
// have been handled first since it has priority by default.
// So the capture happened before the rollover so the overflow
// is always reset to 0
OverFlow1b = OverFlow1;
OverFlow1 = 0;
}
else
{
// no tmr int pending, save the overflow value
OverFlow1b = OverFlow1;
OverFlow1 = NextOF1 ;
NextOF1 = 0;
}
}
#int_ccp2
void Ccp2ISR()
{
CapFinish2b = CCP_2;
CCP2Update = true;
if(bit_test(PIR1,TMR1IF))
{ // tmr 1 ISR pending
// the capture happened before the rollover
OverFlow2b = OverFlow2;
OverFlow2 = 0;
}
else
{
OverFlow2b = OverFlow2;
OverFlow2 = NextOF2 ;
NextOF2 = 0;
}
} |
|
|
|
turbo2ltr
Joined: 27 Jan 2005 Posts: 12
|
|
Posted: Thu Apr 07, 2005 8:26 am |
|
|
dammit I really didn't want to post that as a guest.
I was going to edit it and add to the main routine.
Code: | int32 lowbyte;
int32 temp;
if(CCP1Update)
{
CapFinish1 = CapFinish1b;
CCP1Update = false;
if(CapFinish1 >=CapStart1)
{
lowbyte = CapFinish1 - CapStart1;
temp = (OverFlow1b * 0xffff) + lowbyte;
}
else
{
lowbyte = CapStart1 - CapFinish1;
temp = (OverFlow1b * 0xffff) - lowbyte;
}
// temp now equals the total timer value including the overflows.
// do what you will with it here
CapStart1 = CapFinish1;
} |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|