dsPIC33/PIC24 families have 4 source for supplying the system clock:
- Primary Oscillator
- Secondary Oscillator
- Free Running RC Oscilltaor
- Low Power RC Oscillator
Simplified 16-bit System Clock
With few limitations, application programs are free to switch between any of the four clock sources at any time.
Clocking switching is controlled by a combination of the FCKSM1 bit in the configuration word FOSC and the Oscillator Control Special Function Register (OSCCON). When the FCKSM1 configuration bit has been set to '0' the clock can be switched by writing to OSCCON.
To limit the possibility of unintentional clock switching, OSCCON must undergo a specific unlock sequence before it can be written. The MPLAB® XC16 C compiler provides two built-in functions to unlock and write to the uppoer and lower bytes of OSCCON:
- The lower byte, OSCCONL is written with the special function __builtin_write_OSCCONL
- The high byte, OSCCONH is written with the special function __builtin_write_OSCCONH
When exiting reset the clock source set by the FOSC configuration word is copied to the Current Oscillator Selection bits (COS<2:0>) in OSCCON. The current clock source can be read at anytime by the application software.
Procedure to Switch the Clock in a 16-bit MCU or dsPIC® DSC
At a minimum, performing a clock switch requires this basic sequence:
- If required, read the COSC bits (OSCCON<14:12>) to determine the current oscillator source.
- Perform the unlock sequence to allow a write to the OSCCON register high byte.
- Write the appropriate value to the NOSC control bits (OSCCON<10:8>) for the new oscillator source.
- Perform the unlock sequence to allow a write to the low byte of OSCCON
- Set the OSWEN bit to initiate the oscillator switch
Once OWSEN is set the MCU will begin to switch the clock. The newly selected oscillator may take several instruction cycles to become stable. OSWEN will remain high until the new clock is established as the system clock.
Sample Code to change to Low Power RC Oscillator (LPRC)
current_clock = OSCCONbits.COSC ; // if needed
__builtin_write_OSCCONH(5) ; // 5 = LPRC clock selection
__builtin_write_OSCCONL(1) ; // Sets OSWEN bit