0
votes

I generated the code for a timer (timer2) using mplab code configurator. In the combo, I select the max time for the timer period. So Im using a postescaler of 1:16 in T2OUTPS (1111) and a prescaler of 16 in T2CKPS (1x) The period should be several seconds, but it triggers once every half second (aprox). I don't understand what's the problem, cause it doesn't matters what value I give to the pre and postscaler, the period is the same

Here is the relevant code. This is how I initialize the timer:

void TMR2_Initialize(void) {
  // Set TMR2 to the options selected in the User Interface

  T2CON = 0b01111011;
  //T2CON = 0x3A;
  //T2CON.T2OUTPS = 0b0000;


  // PR2 255; 
  PR2 = 0xFF;

  // TMR2 0x0; 
  TMR2 = 0x00;

  // Clearing IF flag before enabling the interrupt.
  PIR1bits.TMR2IF = 0;

  // Enabling TMR2 interrupt.
  PIE1bits.TMR2IE = 1;

  // Start TMR2
  TMR2_StartTimer();
}

void TMR2_StartTimer(void) {
   // Start the Timer by writing to TMRxON bit
   T2CONbits.TMR2ON = 1;
}

And this is how I handle the interrupt:

void interrupt SYS_InterruptHigh(void)
{
  if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
      TMR2_ISR();
  }   

......


void TMR2_ISR(void) {

  // clear the TMR2 interrupt flag
  PIR1bits.TMR2IF = 0;


  if (colorUpdate%4 == 1)
  {
      LED_Color(0xFFFF,0x0000,0xFFFF);
  }
  else if (colorUpdate%4 == 2)
  {
      LED_Color(0x0000,0xFFFF,0xFFFF);
  }
  else if (colorUpdate%4 == 3)
  {
      LED_Color(0xFFFF,0xFFFF,0x0000);    
  }
  else if (colorUpdate%4 == 0)
  {
       LED_Color(0x0000,0xFFFF,0x0000);   
  }

  colorUpdate++;
  if (colorUpdate>1000)
      colorUpdate = 0;

  LED_UpdateImage();

  LATCbits.LATC6 = 1;

  LATCbits.LATC6 = 0;

}
2
What PIC do you use, and what's your system clock frequency? Are there separate bits that enable the post/pre-scalers - one of these not being enabled would make turn your approx 0.5s to approx 8s, which seems to be similar to what you expect.Sigve Kolbeinson
I use pic18f24k50.i think there is no bits to enable the scalers but ill look as soon as i get homerreiv23
What frequency is your pic running at?Sigve Kolbeinson
Is the PLL is enabled? If so was it factored into the timer calculation?jolati
the frequency is 16 MHz. PLL is enabled with 3x PLL ratio mode selectedrreiv23

2 Answers

0
votes

TMR2 must be reloaded in the interrupt routine.

Also, it's a good idea to avoid the overhead of function calls from within the interrupt service routine. Do the minimum necessary. When possible, if you can tolerate minor deviation in timing, signal external tasks to do the actual work.

0
votes

This started as a comment, but I was running out of space, so I'm posting as an answer.

It's not clear from OP's latest comment if f_OSC is 16 MHz or if f_OSC is 16 MHz x 3 (PLL) / CPUDIV - in this case the min/max f_OSC is 8/24 MHz respectively.

But let's work with f_OSC = 16 MHz. As far as I can tell, Timer2 clock source is f_OSC/4 = 4 MHz, and the combined effect of post and pre scalers is /256, so TMR2 increments at 15625 Hz (@16 MHz f_OSC). with PR2 at 255, I'd expect TMR2IF to trigger at every 255/15625 = 0.01632 s, (~60 Hz). At f_OSC = 8 MHz, this would be every 0.03264 s (~30 Hz), at f_OSC = 24 MHz (16 MHz x 3 / 2), this would be every 0.01088 s (~90 Hz)

Based on this, I think your expectation of the interrupt interval may be based on an incorrect premise, as it's far off what you'd get with your f_OSC.

Even the observed interrupt interval, is far longer than calculated above. I suspect this is due to one of the following:

  1. The interrupt is starved - it, or other higher-priority tasks take so long to execute that the TMR2_ISR() only execute approximately every half second.
  2. The pin C6 pulse has so short duration that you don't capture all of them with your scope/LA/whatever test equipment you use.

I would suggest doing one or both of the following to investigate:

  1. Move LATCbits.LATC6 = 1; to the top of TMR2_ISR() - this way the high duration of the pulse will indicate the execution time of the ISR, and the frequency of the signal will tell you how often the ISR is executed. This should also make it easier to spot if the pulse duration is too short to capture all of them.

  2. Test your timer setup in a program where you have the same setup as now, but the Timer 2 ISR does only two things - reset TMR2IF and toggle pin C6 (toggle as opposed to pulse also makes it easier to capture - but of course your interrupt frequency is twice the frequency of the square wave on C6)