Electronic – PIC24 Internal Oscillator and Instruction cycles

coscillatorpic

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)
{       
    AD1PCFG = 0xffff;   //make ADC pins all digital
    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)
{       
    AD1PCFG = 0xffff;   //make ADC pins all digital
    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.

Best Answer

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.