5.2.9 Oscillator Calibration Constants

Some Baseline and Mid-range devices have an oscillator calibration constant pre-programmed into their program memory. This constant can be read and written to the OSCCAL register to calibrate the internal RC oscillator.

On some Baseline PIC devices, the calibration constant is stored as a movlw instruction at the top of program memory, e.g., the PIC10F509 device. On Reset, the program counter is made to point to this instruction and it is executed first before the program counter wraps around to 0x0000, which is the effective Reset vector for the device. The default runtime startup routine (see 5.10.2 Runtime Startup Code) will automatically include code to load the OSCCAL register with the value contained in the W register after Reset on such devices. No other code is required.

For other chips, such as PIC12F629 device, the oscillator constant is also stored at the top of program memory, but as a retlw instruction. The compiler’s startup code will automatically generate code to retrieve this value and perform the configuration. This value can also be read at runtime by calling __osccal_val(), whose prototype is provided in <xc.h>. For example:

unsigned char calVal;
calVal = __osccal_val();

Loading of the calibration value at startup can be turned off via the -mno-osccal option (see 4.6.1.15 Osccal Option).

Note: The location that stores the calibration constant is never code protected and will be lost if you reprogram the device. Thus, the calibration constant must be saved before the device is erased. The constant must then be reprogrammed at the same location along with the new program and data.
If you are using an in-circuit emulator (ICE), the location used by the calibration retlw instruction cannot be programmed and subsequent calls to __osccal_val() will not work. If you wish to test code that calls this function on an ICE, you must program a retlw instruction at the appropriate location. Remember to remove this instruction when programming the actual part so you do not destroy the calibration value.

Legacy projects can use the macro _READ_OSCCAL_DATA(), which maps to the __osccal_val() function.