Electrical – How to calculate the Timer Preload Properly on PIC32MX575F


I am trying to achieve 1 second on a timer in PIC32MX575F but somehow I am not reaching what I want.
Some people says I have to look into the the PLLDIV, some other people says I should look into the PLLMUL.
I have followed a couple of equations but none of them are reaching the 1 second interrupt.
I don't know what I am doing wrong so I want to know what is the best way to calculate.

Here is my code:

void initTIMER2(void) {
   T2CONbits.ON = 0;
   IFS0bits.T2IF = 0;
   T2CON = 0x0;
   TMR2 = 0;
   T2CONbits.TCKPS = 0b111;//1:256 prescale value
   T2CONbits.T32 = 0;//16 bit timer

   IPC2bits.T2IS = 0;
   IPC2bits.T2IP = 2;
   IEC0bits.T2IE = 1;

   T2CONbits.ON = 1;

This is the configs I have made:

#pragma config FNOSC = FRC // 

#pragma config FPBDIV = DIV_1 

T2CONbits.TCKPS = 0b111

After some investigation it seems the code is calling OSCConfig( OSC_FRC_PLL, OSC_PLL_MULT_20, OSC_PLL_POST_2, OSC_PB_DIV_1) somewhere. I already made calculations with these new values but without success.
So if OSC_FRC_PLL is declared as #define OSC_FRC_PLL (1 << _OSCCON_NOSC_POSITION) it means by the datasheet "001 = Fast RC Oscillator with divide-by-N with PLL module (FRCDIV+PLL)".

Please take a look at the Diagram: Block Diagram

Best Answer

#pragma config FNOSC = FRC // Oscillator Selection
You've chosen the 8MHz FRC oscillator as your system clock, so it doesn't make any difference what the PLLMUL or PLLDIV settings are as you're not using the PLL in that mode.

#pragma config FPBDIV = DIV_1 // Peripheral Clock divisor
Your Peripheral Bus clock is not being divided, so it is set to the same value - 8MHz - that's what your Timer2 module sees as its input.

T2CONbits.TCKPS = 0b111;//1:256 prescale value
You've selected a 1:256 prescaler in your Timer2 module, so it is going to be running at (8MHz/256) = 31.25kHz

Now all that's left is to set PR2 to an appropriate value.
The value you have (0x6768) is 26472 decimal.
The timer module will count up from 0 until it reaches that value, and we've just worked out that its counting at 31.25kHz, so it should take 0.847104 seconds - and then reset back to 0 and carry on counting up again.
This should give you a repetition rate of 1.18Hz

Since you're aiming for 1Hz, you should set your PR2 to the same value as the timer's input frequency - in your case 31250 (0x7A12).

So, from your comments it seems that your system clock is not 8MHz, but 80Mhz (if my quick glance at the OSCConfig parameters is correct).
Following the procedure above would lead you to a PR2 value of 312500 - which doesn't fit into a 16-bit register ... So with these settings you can't achieve a 1Hz interrupt rate.

Some options might be:
- run your Timer2 in 32-bit mode by chaining it to Timer3
- slow down the Peripheral Bus clock by changing the PB_DIV setting in your OSCConfig() call
- leave Timer2 running at 10Hz (which it probably is running at now) and add a counter to the interrupt function so that you only do stuff every 10th interrupt