Friday, June 12, 2015

PIC18f system clock and delay routine using C18

I just started with the PIC18f, so I planning to go into fundamental. With bunch of tutorials and forum discussions online, I still encounter some difficulties to get started with PIC18f.
Simple problem, yet I do a lot of readings before I successfully compile the led blinking (with 1 second delay).

The first problem is setting the system clock. And the second problem is using the C18 default delay routine.

The PIC18f4550/PIC18f4553 has three clock blocks which are primary oscillator, secondary oscillator, and internal oscillator.




The primary oscillator is normally used for high speed oscillator (>=4MHz), secondary oscillator for low speed oscillator such as 32.768kHz. Internal oscillator has two different clock signals; main output is an 8 MHz clock source and second clock source is the internal RC oscillator provides a nominal 31 kHz output.

Primary oscillator has 4 modes which are HS, HSPLL, XT, XTPLL. Depending of frequency of oscillator, suitable mode need to be assigned as shown as table below:

Resonators Freq
Mode
4.0MHz
XT
8.0MHz/16.0MHz
HS

Crystal Freq
Mode
4.0MHz
XT
4.0MHz/8.0MHz/20.0MHz
HS

For some projects, MCU doesnt need to operate at high speed, config CPUDIV can be used to scale the operating frequency into lower speed.

For some applications that require high speed clock, MICROCHIP provides PLL (phase locked loop) function, it is a frequency multiplier to generate a fixed 96MHz from a fixed 4MHz input. On top of that, a PLLDIV is assigned to divide the oscillator frequency to 4MHz which enable the adoption of oscillator with various frequency range.

















The PIC18f's maximum allowable frequency is 48MHz, so after the PLL the 96MHz is divided into half to suit the MCU operating frequency.

The overall setting for CPU frequency is as follow:
1:      #pragma config PLLDIV  = 5                        // (20 MHz crystal)
2:      #pragma config CPUDIV  = OSC1_PLL2    // Divide 96MHz with two
3:      #pragma config USBDIV  = 2                      // Clock source from 96MHz PLL/2
4:      #pragma config FOSC   = HSPLL_HS         // HS oscillator, PLL enabled (HSPLL)  

For more information on setting, open the mplab, go to Help->Topics...->PIC18 Config Settings. From there, choose selected microcontroller, and all settings are listed and explained.

........................................................................................................................................
For PIC18f4553/4550, maximum CPU Speed is 48 MHz (12 MIPS) which means at CPU operating frequency of 48 MHz, it is able to run 12 millions instruction per second. So one instruction need 4 cycles to process.

In order to have one second delay, you need to do nothing for 12 millions instruction time.
For one micro second delay, 12 instructions of _do_nothing are needed. Which in turn,  two micro second delay, 24 (12x2) instructions of _do_nothing are needed.

Microchip c18 provides <delays.h> library to help set the timing, the <delays.h> is located at
"C:\Program Files (x86)\Microchip\mplabc18\v3.47\h\delays.h"

I wrote my own routine on top on <delays.h> and name it as "delay.h"
For one micro second -
#define delay1MicroSecond()    {Delay10TCYx(1); Delay1TCY(); Delay1TCY();}
// delay 12 instructions

#define delay10MicroSecond() Delay10TCYx(12)      // delay 120  instructions

#define delay1MiliSecond() Delay1KTCYx(12)     //delay 12000 instructions

#define delay100MiliSecond() Delay10KTCYx(120) //delay 1,200,000 instructions

#define delay200MiliSecond() Delay10KTCYx(240) //delay 2,400,000 instructions

All delay routines are in the multiplication of 12 (provided that the CPU operating frequency is 48MHz).

For other CPU frequency, scaling is needed to get the correct timing.
Examples:
                  48MHz = 12 MIPS        // for one micro second, delay 12 instructions
                  32MHz =   9 MIPS        // for one micro second, delay   9 instructions
                  24MHz =   6 MIPS        // for one micro second, delay   6 instructions
                  16MHz =   3 MIPS        // for one micro second, delay   3 instructions

..............................................................................................................................................

To blink led,
the pic18f has one general rule to read/write IO - read from port and write to latch.

First set the IO pin to output,
#define mInitAllLEDs()     TRISBbits.TRISB6=0; TRISBbits.TRISB7=0; //define output
//pic18f rule for input/output is
//0 = output;
//1 = input;

#define mLED_1              LATBbits.LATB6    // write to particular bit (pin b6)
#define mLED_2              LATBbits.LATB7    // write to particular bit (pin b7)

// to on led just assigned mLED_1 = 1;
// to off led just assigned mLED_1 = 0;
..............................................................................................................................................

Now you can start with blinking led, all the source codes can be downloaded at github.