# PIC24 Internal Oscillator and Instruction cycles

I have some relative experience on AVR but just minimum with PICs. In order to start a project I've just wanted to verify that I was able to get the internal oscillator working at the right frequency. So, my first test was to toggle a pin and see the frequency I've got. The first test code was

#include <p24F16KA102.h>

_FOSCSEL(FNOSC_FRCDIV  & FNOSC_PRI );
_FOSC( POSCMOD_HS  );

int main(void)
{
TRISA = 0;          //Make all PORTAs all outputs

while (1)
{
LATAbits.LATA6= ~LATAbits.LATA6;
}
return 0;
}


The frequency measured on the RA6 is about 59 KHZ. This looked crazy out of a 8MHZ clock. It seems to be that LATAbits and the negation requires 14 Instructions !!

So I've searched on the internet in order to minimize the instructions to just toggle a pin and found out a built in assembly of BTG so I've repeated the above code replacing the LATAbits with  __builtin_btg(&LATA, 6);

Now the dissasembly shows there are 3 instruction to execute the loop and the toggling

029A  202C40     mov.w #0x2c4,0x0000
029C  A26010     btg [0x0000],#6
029E  37FFFD     bra 0x00029a


Now the frequency at PIN RA6 is 201 KHZ !!!

What am I doing wrong here ??? I've tried the configuration bits from the MPLAB without the code etc etc . Is this OK ? an 8MHZ clock will produce 201KHZ as the best option to toggle a PIN?

It is very likely I am doing something wrong hence why I decided to post this here after spending more than 6 hours trying.

From datasheets I know that each instruction requires 4 clock cycles but I am not sure on instruction cycles, clock cycles and execution cycles. I will appreciate any help or guidance. Perhaps I am more used to 8 bits where the ratio to clock cycles is smaller. What is the easiest and safe way to verify the clock frequency?

OK Thanks everyone for all the answers as all of them gave me a direction to follow. I have just tested the suggestions from Olin and Madmanguruman. As I did not find a direct way to put inline asm having address tags like loop: below, I've created a file test1.s with one function called loop1 with the code given by Olin below and just called it as shown in the code below:

 #include <p24F16KA102.h>

_FOSCSEL(FNOSC_FRCDIV  & FNOSC_PRI );
_FOSC( POSCMOD_HS  );
extern int loop1(void);
int main(void)
{
TRISA = 0;          //Make all PORTAs all outputs

loop1();
return 0;
}


Now the measured frequency at RA6 is about 335 KHZ. The loop is run every 1.47 microseconds (670 KHZ). This is, of course, double the frequency above as the scope actually measures two loop cycles, the one RA6 is high plus the one RA6 is low.

Then using the info from Olin below the clock rate should be 12 X 680KHZ = 8.16MHZ.

The only thing I am not 100% clear is how the frequency of the instructions is defined, i.e, should I have the time RA6 is high (or low) as the period?, then 1 instruction seems to be 2 ck cycles or.. should I use the time RA6 is high, then low , then back to high as the period? in this case then it should be 4 ck cycles per instruction.

Above is a matter of definition. My main question is answered as ( thank to all your help from this forum) I am positive the CK must be 8 MHZ, then, I know the maximum possible frequency toggling a port PIN is about 335 KHZ with the ck at 8MHZ ( here I mean the standard definition of frequency). Also, using the PLL I can be able to duplicate or cuadruplicate that rate.

-
Mind you MHz != MIPS (million instructions per second). –  jippie Jan 5 '13 at 20:56
For the PIC24 series, the MIPS value is equal to half of the oscillator frequency, so 8 MHz => 4 MIPS. For the PIC24E, their fastest PIC24 family, the 8 MHz internal oscillator can be boosted to 140 MHz using the PLL resulting in 70 MIPS. –  tcrosley Jan 5 '13 at 21:38
You're best off with asm("btg LATA, #6") as your bit-toggle instruction, as the __builtin_btg sometimes throws a compiler warning and has that extra mov.w instruction in there. The Microchip training course on their C30 compiler goes into some detail on the negation blowing up to 14 instructions (i.e. don't do that, use __builtin_btg or asm instead) ... welcome to the wonderful world of Microchip... :) –  Adam Lawrence Jan 5 '13 at 23:13
@jippie Yes but the point is that even 4 MIPs are producing 200Khz blink as the best case? –  Jose Vicente Jan 5 '13 at 23:35
@tcrosley, same thing my question perhaps not clear is that a 201 KHZ is the BEST blink possible at 8MHZ clock or a 4 MIPS processor? . May be a little more as if the extra MOV can be eliminated. –  Jose Vicente Jan 5 '13 at 23:37

What you are doing wrong is making instruction-level assumptions about compiled code. If you want to test the execution speed of instructions, you need to write a known loop in assembler. For example:

loop:
btg     LATA, #6
bra     loop


Next you carefully count how many cycles in one full RA6 output cycle. From the datasheet or programmers reference manual you can see tgat BTG takes one instruction cycle and BRA two. Each loop iteration therefore takes 3 cycles, and it takes two iterations for one complete cycle of RA6, so RA6 should toggle at 1/6 the instruction rate, or Fcy/6 using symbols from the Microchip documentation.

Now check whether that part uses 2 or 4 clocks per instruction cycle. Let's say this one uses 2, so now the RA6 frequency is Fosc/12.

Next you have to go thru the config settings and see exactly how the oscillator is derived. It can get pretty complicated on some of the newer parts. Many of them have additional clock chain state that can be adjusted at run time, so you have to look at the code too, not just the config settings. There can be various clock taps, dividers, and usually a PLL that is a multiplier but also usually with its on set of dividers. Eventually you should be able to start at your crystal frequency or the internal oscillator frequency if you're using that, follow thru the whole clock chain, determine what the instruction clock rate is, then divde that by 6 to get the RA6 frequency.

-
Thanks Olin, OK let me try that loop too it should produce a ~660KHZ assuming 2 cycles per instruction. –  Jose Vicente Jan 5 '13 at 23:48

Add a known delay to your code; eg. 1 ms delay. The compiled code will be optimized for the frequency the compiler is aware of and if that is the same as the set RC-clock, then you will measure a 500Hz block at the output. Without a known delay you are can only verify timing by analyzing the compiled machine code.

The output frequency with the proposed delay will be proportional to the actual RC frequency.

-
Thanks let me try that too, kind of using 2 __delay_ms() between a toggle, then see how much is the time in between if it matches the intended delay, then the frequency must be the intended ( 8 MHZ in my example) –  Jose Vicente Jan 5 '13 at 23:44