I'm coding on PIC24F and I'm still fighting with oscillator configuration. Between configuration bits and SFRs such as CLKDIV and OSCCON I am a 'bit' lost... I've been making things work by trial and error but haven't yet understood exactly what I am doing :/ (like when you finally understand pointers and have the "ohh" moment).

I think the parts that I am missing are:

  • are configuration bits shortcuts for SFRs? do they overlap?
  • what are the default/start values and which ones should I touch?
  • how can I verify that the clock is running at the correct speed?

If more specific this needs to be, I'm trying to setup a PIC24FJ with an external 12Mhz crystal.


#pragma config POSCMOD = HS             // Primary Oscillator Select (HS Oscillator mode selected)
#pragma config I2C1SEL = PRI            // I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = OFF            // IOLOCK Protection (IOLOCK may be changed via unlocking seq)
#pragma config OSCIOFNC = OFF           // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as CLKO (FOSC/2))
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = PRI              // Oscillator Select (Primary Oscillator (XT, HS, EC))
#pragma config SOSCSEL = SOSC           // Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG             // Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = ON                // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) enabled)

#pragma config WDTPS = PS32768          // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Watchdog Timer Window (Windowed Watchdog Timer enabled; FWDTEN must be 1)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (Watchdog Timer is disabled)
#pragma config ICS = PGx1               // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF               // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF                // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = ON              // JTAG Port Enable (JTAG port is enabled)

Then in my main's init():

OSCCONbits.COSC = 0b010;
CLKDIVbits.DOZE = 0b000;

Am I right to assume the following:?

#define FOSC    12000000UL
#define FCY     FOSC/2

Yes, the clock chain on some of the PIC 24 is rather complicated, but it is all well explained in the datasheet and the family reference manual. Look in the datasheet chapter for the oscillator, find what specific family reference manual chapter it refers to, then read that. Carefully. All of it.

Sometimes I find it useful to print out the overall clocking diagram usually in the first few pages of the oscillator chapter. This can be useful to look at while reading other sections and filling in fields in the configuration registers and the runtime oscillator control registers.

Configuration bits are bits in special "registers" where you put static information at build time. These bits will be coded into the HEX file and set in the part when it is programmed. Some configuration needs to be known so that the device can run at all, so these must be set before run-time. That's what the configuration bits are. No, they aren't really SFRs.

The default values of all bits are clearly documented in the datasheet. Read it.

Since the clock chain can be complicated, verifying I got it right is one of the first things I do in a new project. After making sure the part is otherwise initialized and the runtime part of the clock chain is set up as I think it should be, I run code like this:

    btg LATB, #0    ;toggle RBO
    bra loop

Of course you pick a pin that won't hurt anything if toggled. RB0 is just the example I picked here.

The BTG instruction takes one cycle, and BRA takes 2. Each loop iteration therefore takes 3 cycles, and one whole period of RB0 therefore 6 cycles. Now you look at RB0 with a scope and see if you really get the expected instruction clock frequency divided by 6.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.