PIC C, Internal Oscillator Calibration

(12C508, 12C509, 12CE518, 12CE519)

copyright, Peter H. Anderson, Baltimore, MD, May, '99


Note. This discussion applies only to the 12C5 12-bit core devices. The calibration of such 14-bit core devices as the 12C671 and 12C672 is handled differently. This is treated in a separate discussion.

With Microchip 12-bit core devices having an internal oscillator, Microchip supplies the part with a MOVLW k programmed at the highest memory location; 0x01ff for the 12C508 and 0x03ff for the 12C509, where k is a calibration constant for that particular device which is to be written to the OSCCAL register.

Unlike other PIC devices which begin program execution at location 0x000, PICs having internal oscillators start at the highest program address. Thus, the first line which is executed is Microchip's MOVLW k.

The program counter then rolls over to 0x000.

Thus, when using the internal oscillator, it is important that the value of the W register be written to the OSCCAL register prior to the W register being overwritten. Ideally, one would like MOVWF OSCCAL to be located at program location 0x000.

Using the CCS PCB compiler I found I was able to force this with a;

	#rom 0x000={0x0025}
where 0x0025 is the opcode for MOVWF 05 (OSCCAL). The CCS PCB compiler then generated code beginning at location 0x001.

This is illustrated in program OSCCAL_1.C. Note that the value of OSCCAL is then displayed on the serial LCD.

Windowed EEPROM.

Windowed EEPROM versions pose a difficulty in that when the EEPROM is erased, the MOVLW k is also erased.

A solution when working with windowed EEPROMs might be to first run OSSCAL_1.C and note the value of OSCCAL which is displayed. If working with several windowed EEPROMs, this might require uniquely identifying each one with a small lable on the underside of the device.

In all future programs of this particular EEPROM, force the Microchip MOVLW k at the highest address;

	#rom 0x01ff={0x0ckk}	// 12C508
or	#rom 0x03ff={0x0ckk}	// 12C509
where kk is the oscillator calibration constant. Note that MOVLW is the opcode 0x0c.

For example; if using a 12C509 and the calibration constant is 0xc8;

	#rom 0x03ff={0x0cc8}	// MOVLW 0xc8
Assume you have five different windowed EEPROMs. You might label each as #1, #2, etc and then run program OSCCAL_1.C for each device and note each calibaration constant and then develop a table;
#ifdef DEV_1
#rom 0x03ff={0x0c8c}	// cal constant = 0x8c

#ifdef DEV_2
#rom 0x03ff={0x0cf0}	// cal constant = 0xf0

#ifdef DEV_3
#rom 0x03ff={0x0ca8}

Then, prior to compiling, note the device you will be using and #define the appropriate device;
#define DEV_2

Program OSCCAL_1.C.

// Program OSCCAL_1.C. PIC C, CCS PCB, 12C509
// Illustrates how to write oscillator calibration constant to
// OSCCAL and then display the value.
// For windowed EEPROM versions, this value might be noted such that
// after the first erase, the appropriate data may be reprogrammed into
// location 0x01ff (12C508) or 0x03ff (12C509).
// Serial LCD is connected to GP.0.  Serial data is 9600 baud, inverted.
// copyright, Peter H. Anderson, Baltimore, MD, May, '99

#include <12c509.h>

void set_dirs(void);		// note that DIRS is global
void set_options(void);		// OPTIONS is global

// delay routines
void delay_ms(long t);
void delay_10us(int t);

// LCD routines
void lcd_init(void);
void out_RAM_str(int *s);
void lcd_hex_byte(int val);
void lcd_dec_byte(int val, int digits);
int num_to_char(int val);
void lcd_char(int ch);
void lcd_new_line(void);

#define TxData 0

#define OUT 0
#define IN 1

static int DIRS, OPTIONS;

#rom 0x0000 = {0x0025}  // This is MOVWF OSSCAL

void main(void)
// Note that first statement is actually MOVWF OSCCAL
   lcd_hex_byte(OSCCAL);   // display value of OSCCAL

void set_options(void)

void set_dirs(void)

// timing and LCD routines are the standard routines used in other examples.