PIC24 Tutorial – Part 4 – Oscillators and PLLs

For this tutorial you’ll need the following:

  • A PIC24 hardware platform – such as our picoTRONICS24 or nanoTRONICS24 microcontroller development boards
  • Microchip’s FREE MPLAB X IDE – make sure you’ve got the latest version – they are updating it all the time
  • Microchip’s FREE C30 or XC16 C Compiler – also make sure you have the latest version
  •  We also assume you have working knowledge of C/C++ – if you don’t have this there a many good C/C++ tutorials availible on the internet.

This tutorial has been designed to work seamlessly with our picoTRONICS24 series development boards. Click here to download the example project for this tutorial.

Oscillator or clock basics

I guess by now you will have figured out, if you didn’t already know, that microcontrollers need some sort of oscillator to function. The reason for this is, the hardware inside the microcontroller is based on sequential logic, kind of like a flip-flop. PIC24 microcontollers are no exception to this rule. Without an oscillator, or probably more accurately a clock, the controller would cannot execute your program instructions, and as such, function. For this reason, it is very important to understand the fundamental nature of oscillators and timing settings for your microcontroller.  For those of you who have used microcontrollers before you’d be familiar with this concept. In fact you’ve probably seen the crystal or oscillator on your development board. The PIC24 series of microcontrollers are advanced devices and as such you can either use an external oscillator or their powerful internal oscillator.

Background

A general description of an oscillator is a device that oscillates with a repeatable variation, with respect to time – or in other words produces a wave with a constant frequency. The oscillator output will be made up of an amplitude and frequency response.

The amplitude refers to the difference of electric potential between the peaks and troughs or the “height” of the wave. The PIC24 series microcontrollers have 3.3V inputs so an oscillator with a 5V output will destroy your device. Best to get it right! The maximum DC characteristics for your microcontroller will be listed in the microcontrollers datasheet so it is easy enough to look up.

The AC characteristics of the oscillator are defined by the oscillators frequency rating. For most microcontrollers the main oscillator will typically be in the MHz range going up to hundreds of MHz in value. For the PIC24F family you’d usually use an oscillator in the range of 8-20 MHz. The PIC24F devices also contain internal phase lock loop (PLL) that can give the micro an effective million instruction per second (MIPS) value upwards of 100 – like having a 100MHz oscillator.

The PIC24F devices also contain a highly accurate, or stable, internal FRC oscillator than can be used instead of an external crystal oscillator – very convenient indeed. So you might ask why is a stable oscillator important? Well some application need very accurate timing, this would be anything that has to do with precise measurement of time or speed. In these cases the frequency error value for that oscillator needs to be minimized. This error value is commonly expressed as parts-per-million or PPM and indicates how much the oscillator will drift off its stated frequency. An example of an application that needs accurate timing is USB. One of the reasons we really like the PIC24FJ64GB004 microcontroller is that its internal oscillator is stable enough for USB2.0 – very rare in microcontroller.

The PIC24 micro’s are incredibly versatile in their oscillator inputs. In general there are three categories of oscillators (or clocks) that are compatible with these devices. They are: direct piezoelectric crystals (made of cut quartz), dedicated IC external clocks or the provided internal fast RC oscillator (FRC), so you can run the controller without an external input – we use this in most of our designs. The FRC oscillator is the least accurate of the three options, but is accurate for everything except the most timing critical applications.

The Microchip datasheet for your microcontroller has a section with the oscillator diagram. This is an excellent starting point to figure the oscillator setup for your microcontroller. A snapshot of this section of the datasheet for the PIC24FJ64GB004 is shown below.

PIC24FJ64GB004 Oscillator Configuration

The two oscillators

There are two main oscillators on the PIC24F’s, both with independent IO pins, and both that can be used for clocking purposes. The primary oscillator (which can be replaced by the internal FRC oscillator) has IO pins labeled OSCI & OSCIO. In general if you aren’t using the internal FRC oscillator then the oscillator connected to OSCI will run the main processor. The other oscillator is a secondary clock, its IO pins are labeled SOSCI and SOSCO. This oscillator is generally used for timekeeping applications such as the RTCC, alarm clocks and time sensitive measurements applications. Often a secondary timing oscillator, like a 32.768 kHz crystal, is attached to the SOSCI/SOSCO.

The PIC24F devices have ten main modes for the oscillator. As you’d remember from the previous tutorial these are controlled by the configuration bits FOSC and POSCMD. Whilst ten options sounds like a lot Microchip provides a simple table with the configuration bit values required for each oscillator mode. A copy of the table for the PIC24FJ64GB004 is shown below.

PIC24FJ64GB004 oscillator modes

Normal Usage

As we’ve said in general we find the high accuracy internal FRC oscillator provided with the PIC24F devices to be more than suitable for most applications. This also means you don’t need to solder an external oscillator to your board. If you need higher accuracy though, our picoTRONICS24 and nanoTRONICS24 PIC24 development boards provide a place to solder an external crystal – don’t forget the accompanying capacitors!

The operation of the oscillator in the PIC24F devices is controlled by three Special Function Registers (SFRs):

  • OSCCON
  • CLKDIV
  • OSCTUN – you’ll need an oscilloscope to use this register effectively

Once you’ve selected the correct configuration bits you will also need to put in the corresponding selection to the OSCCON register. See your devices datasheet or our example code for all the details.

If you want to change the speed you PIC executes instructions are you can divide the clock with the CLKDIV register. This register has several bits that control the manner in which the clock will be divided, check the datasheet for all the details. The CLKDIV.DOZE<2:0> is the division taken before the clock is sent to the core processor. For example, if we connect an 8MHz clock to the PIC24F, without using the PLL (more on it later) and set the DOZE<2:0> register value to divide by 4, then the processor will be clocked at 2MHz. Hopefully this is all starting to make sense.

Using the inbuilt PLL

The PIC24F devices include an extremely useful PLL. The PLL can be used to multiple up the clock input to make your device run faster – of course this also means it uses more power. It is also necessary if you are planning on using USB in your application! It is also useful if you need a lot of processing power for your application. Before you turn on the PLL you need to correctly select FOSC and POSCMD. Followed by enabling the PLL with the PLLEN bit. The PLL division / multiplication factor is best explained by the following diagram from the PIC24FJ64GB004 datasheet. Don’t worry if it doesn’t all make sense – you can download our example code from this tutorial and it will set it all up for you.

PIC24FJ64GB004 PLL configuration

Example Code Time

This just about covers the basics of the PIC24F oscillator and PLL setup, so it is time for some example code. The project files containing this example code can be downloaded here. This example code is designed to run the following setup:

The example code configures the microcontrollers oscillator up in software, allowing the user to change the processors clock speed at compile time (by changing the appropriate #define) or, with some small changes, at software run-time!

[code language=”cpp”]
/*
* File: main.c
* Author: Modtronics Australia
* www.modtronicsaustralia.com
*
* Created on 10 June 2013, 2:55 PM
*/

#include
#include

#include
#include

// Microcontroller config words (fuses) – get these wrong and nothing will work correctly, if at all!!
_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & ICS_PGx1 & FWDTEN_OFF & WINDIS_OFF & FWPSA_PR32 & WDTPS_PS8192)
_CONFIG2(IESO_OFF & FNOSC_FRCPLL & OSCIOFNC_OFF & POSCMOD_NONE & PLL96MHZ_ON & PLLDIV_DIV2 & FCKSM_CSECME & IOL1WAY_OFF)
_CONFIG3(WPFP_WPFP0 & SOSCSEL_IO & WUTSEL_FST & WPDIS_WPDIS & WPCFG_WPCFGDIS & WPEND_WPENDMEM)
_CONFIG4(DSWDTPS_DSWDTPS3 & DSWDTOSC_LPRC & RTCOSC_LPRC & DSBOREN_OFF & DSWDTEN_OFF)

/****************************************************************************/
/* Useful Macros */
#define BITS2WORD(sfrBitfield) ( *((unsigned int*) &sfrBitfield) )
// Convert a bitfield to a word (unsigned int).
#define BITS2BYTEL(sfrBitfield) ( ((unsigned char*) &sfrBitfield)[0] )
// Return the low byte (as a unsigned char) of a bitfield.
#define BITS2BYTEH(sfrBitfield) ( ((unsigned char*) &sfrBitfield)[1] )
// Return the high byte (as a unsigned char) of a bitfield.

/****************************************************************************/
/* User Configurable Definitions */

// If the following line is uncommented the uC will use the internal oscillator,
// comment the line out to use the external oscillator
#define USE_FRC_CLOCK

// Processor clock frequency selection
#define CLOCK_FREQ 32000000ULL // Use 32MHz clock – default for demo board
//#define CLOCK_FREQ 16000000ULL // Use 16MHz clock
//#define CLOCK_FREQ 8000000ULL // Use 8MHz clock
//#define CLOCK_FREQ 4000000ULL // Use 4MHz clock

/*
*
*/
int main(int argc, char** argv) {

unsigned int pllCounter;
OSCCONBITS OSCCONbitsCopy;

// Copy the current Clock Setup
OSCCONbitsCopy = OSCCONbits;
// Slow output clock down to 4Mhz
CLKDIVbits.CPDIV = 3;
// Enable the PLL – Note: Fuse bits don’t do this
CLKDIVbits.PLLEN = 1;
// Wait for the PLL to stabalise
for (pllCounter = 0; pllCounter < 600; pllCounter++);

// Check to see what clock setup is defined – either internal or external
#ifdef USE_FRC_CLOCK
// Setup the uC to use the internal FRCPLL mode
OSCCONbitsCopy.NOSC = 1;
OSCCONbitsCopy.OSWEN = 1;
#else
// Setup the uC to use the external crystal with the PLL
OSCCONbitsCopy.NOSC = 3;
OSCCONbitsCopy.OSWEN = 1;
#endif

// Switch over to the new clock setup
__builtin_write_OSCCONH( BITS2BYTEH( OSCCONbitsCopy ) );
__builtin_write_OSCCONL( BITS2BYTEL( OSCCONbitsCopy ) );
// Wait for this transfer to take place
while (OSCCONbits.COSC != OSCCONbits.NOSC);
// Setup the DIV bits for the FRC, this values means the config word needs to be: PLLDIV_DIV2
CLKDIVbits.RCDIV0 = 0;

// Setup the PLL divider for the correct clock frequency
if (CLOCK_FREQ == 32000000)
{
CLKDIVbits.CPDIV = 0;
}
else if (CLOCK_FREQ == 16000000)
{
CLKDIVbits.CPDIV = 1;
}
else if (CLOCK_FREQ == 8000000)
{
CLKDIVbits.CPDIV = 2;
}
else if (CLOCK_FREQ == 4000000)
{
CLKDIVbits.CPDIV = 3;
}

// Check that the PLL is enabled again and locked properly to the new setup
CLKDIVbits.PLLEN = 1;
// Note – don’t want to do this check if we are running in the MPLAB X simulator as it won’t work
#ifndef __MPLAB_SIM
while(_LOCK != 1);
#endif

// At this point the PIC24FJ64GB004 clock setup will be complete with the PLL
// enabled and ready for operation with USB2.0

//Loop forever and do nothing
while(1)
{
}
return (EXIT_SUCCESS);
}
[/code]

Wrapping it all up

This completes our tutorial on the PIC24F series microcontroller oscillator and PLL setup. The example project from this tutorial can be downloaded here.

Good luck!

Comments are closed.