Jump to content
Sign in to follow this  
chuckj

Precise Rtos Timing Using Ccp1

Recommended Posts

My apologies if this has been mentioned somewhere.

 

For PIC 18F processors( and perhaps others) you can use CCP1 and Timer1 to get an accurate tick period without using a software counter.

The key is using the CCP Compare Special Event Trigger to reload Timer 1.

 

Here is a code snippet to illustrate setting up 1 millisecond tick on a 40 MHz processor:

/**** Defines to make it easy to change clock frequency or prescaler ****/
//40 MHz clock
#define FOSC  40000000

#define TIMER1_CLOCKS_PER_US   ((FOSC/4)/1000000)

//Prescaler value must reflect PS1:PS0 values in PRESCALER_MASK!!
#define TIMER1_PRESCALER_VALUE  1
#define PS1PS0_MASK	0x00

#define MICROSECONDS_PER_TICK   1000

//Use CCP1 in compare mode with special event trigger to do timing.
// This way, the timer is reloaded in hardware so timing is very accurate
#define CCP1_1MS_LOAD (((TIMER1_CLOCKS_PER_US * MICROSECONDS_PER_TICK )/TIMER1_PRESCALER_VALUE)- 1)
//Reset timer and interrupt on timer compare mode match.
#define CCPX_COMPARE_SPECIAL_EVENT_TRIGGER  00001011b

#define MSB(x) (((x)>>8)&0xFF)
#define LSB(x) ((x)&0xFF)


/************* START OF CODE **************************/

//Initialization

int main( void )
{

 //Init Novo RTOS
 SysInit();

 //Create tasks here
 SysCreateTask(hMyTask, 1, MyTask);
 .....

 //Start tasks  here
 SysStartTask(hMyTask);
 .....

 //Load CCPR1L and CCPR1H so compare will fire at 1 millisecond(our tick period)
 //See #defines above for load calculations and values

 ccpr1l = LSB(CCP1_1MS_LOAD);
 ccpr1h = MSB(CCP1_1MS_LOAD);
 //Set up interrupt on CCP event.
 clear_bit(pir1, CCP1IF);
 clear_bit(ipr1, CCP1IP);
 set_bit(pie1, CCP1IE);
 //This causes a hardware reset of Timer1 when CCP compare hits.
 // CCPX_COMPARE_SPECIAL_EVENT_TRIGGER is #define above.
 ccp1con = CCPX_COMPARE_SPECIAL_EVENT_TRIGGER;

 //Set up timer 1 for 16 bit, prescaler = 1, PS1PS0_MASK is #define above
 t1con = (1<<RD16) | (1<<TMR1ON) | (PS1PS0_MASK);

 set_bit(intcon, GIE);

 while(1)
 {
Sys_Yield();
 }
}

void interrupt( void )
{
  if( pir1.CCP1IF == 1 )
  {
  //Handle ticker for NOVO RTOS
  SysTimerUpdate();
  clear_bit(pir1, CCP1IF);
  }
}

//Tasks, etc............

 

Note how simple the interrupt handler is. All counting and reloading is done by the CCP.

 

Hope you find this useful!

 

Thanks for a great product,

Chuck

Share this post


Link to post
Share on other sites

Your content will need to be approved by a moderator

Guest
You are commenting as a guest. If you have an account, please sign in.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×