CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Timer overflow handling using both CCP modules

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
turbo2ltr



Joined: 27 Jan 2005
Posts: 12

View user's profile Send private message

Timer overflow handling using both CCP modules
PostPosted: Wed Mar 30, 2005 3:52 pm     Reply with quote

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








PostPosted: Wed Mar 30, 2005 4:29 pm     Reply with quote

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








PostPosted: Wed Mar 30, 2005 4:29 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 30, 2005 4:34 pm     Reply with quote

It really helps if you put your code within code tags
turbo2ltr



Joined: 27 Jan 2005
Posts: 12

View user's profile Send private message

PostPosted: Wed Mar 30, 2005 4:44 pm     Reply with quote

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








PostPosted: Wed Mar 30, 2005 5:19 pm     Reply with quote

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








PostPosted: Wed Mar 30, 2005 5:21 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Mar 30, 2005 5:21 pm     Reply with quote

See this thread. It has code to fix the Timer1 problem.
http://www.ccsinfo.com/forum/viewtopic.php?t=906
turbo2ltr



Joined: 27 Jan 2005
Posts: 12

View user's profile Send private message

PostPosted: Wed Apr 06, 2005 11:37 am     Reply with quote

PCM programmer wrote:
See this thread. It has code to fix the Timer1 problem.
http://www.ccsinfo.com/forum/viewtopic.php?t=906


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

View user's profile Send private message

PostPosted: Thu Apr 07, 2005 1:25 am     Reply with quote

turbo2ltr wrote:
PCM programmer wrote:
See this thread. It has code to fix the Timer1 problem.
http://www.ccsinfo.com/forum/viewtopic.php?t=906


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








PostPosted: Thu Apr 07, 2005 8:20 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Apr 07, 2005 8:26 am     Reply with quote

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;
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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