Background:
Event Log/Total Accumulated time applications need ultra low power clock/timer to keep track of accumulated time. Traditionally, this is accomplished by running the device in Sleep mode for low power and use of an external 32,768 KHz crystal to run the Timer 2 as a background clock. However, this can be an expensive open for applications designed to be thrown away when the task is completed.
Another lower-cost alternative is to use the Low Power RC (LPRC) oscillator based Watchdog Timer (WDT) to wake up at designated intervals (such as one second) to implement an algorithm and then sleep again. But the accuracy of the LPRC is not calibrated at the factory.
Problem:
Is there a way to use the WDT without an external crystal and maintain an accurate time base?
Solution
The 16 MHz High-Frequency Internal Oscillator (HFINTOSC) is included within most PIC® MCU devices and is factory calibrated to be within 1~3%. This internal clock can be used, at initial startup, as a base timer to calibrate the WDT period. The HFINTOSC can be used at startup to run as the system instruction clock and feed the Timer 0. Every time Timer 0 overflows, 256 instruction cycles are completed. The overflow can be used to increment a 16-bit variable (calibration WDT). Through a software routine, the variable will begin incrementing after a WDT reset and will stop incrementing when a WDT timeout occurs.
The variable (calibration WDT) will contain the number of instructions based on an accurate clock. This instruction count value can then be used as a reference time base value for every WDT overflow. With this known accuracy, the WDT can be used to control the device in Sleep mode, thus shutting down the instruction clock for lower power in-between WDT resets and maintain an accurate time base.
Sample Code
Below are snippets of code showing the key sections, the establishment of the key variable and the main section of code that measures the WDT.
The calibration structure HAS to be persistent or the compiler will clear its value before running this calibration routine, effectively destroying the calibration value.
persistent struct calibrationS {
unsigned int WDT;
unsigned int base;
unsigned int interval;
unsigned char count;
} calibration;
OSCCON = 0x70; // set oscillator to 16 Mhz
WDTCON = 0x15; // 1 second timeout, WDT on
if (STATUSbits.nTO == 1) {
while (OSCSTATbits.HFIOFS == 0); // wait for 16 Mhz oscillator to stabalize
while (OSCSTATbits.LFIOFR == 0); // wait for LF oscillator to stabalize
OPTION_REG = 0x88; // TMR0 internal instuction timer assignement, 1:1 prescaller
calibration.WDT = 0;
INTCONbits.TMR0IF = 0;
CLRWDT();
TMR0 = 0;
while (1) {
if (INTCONbits.TMR0IF == 1) {
INTCONbits.TMR0IF = 0;
calibration.WDT++;
}
}
}
Further Calibration
The WDT LPRC can also be affected by temperature, so to improve the accuracy further, multiple HFINTOSC measurements can be taken at intervals but the math to calculate an average instruction count variable can use processing time and power. An easier solution is to reference a look-up table to determine the number of LPRC periods needed for a fixed time period. Below is a sample look-up table for a multiple calibrated design.
persistent structure calibrationS {
unsigned int WDT;
0 13,213 9195489 , // WDT Calibration[0], calibration.WDT= 13213, Variation= -25%, Deviation= 0% -25.00% 0.00%
1 13,389 9074613 , // WDT Calibration[1], calibration.WDT= 13389, Variation= -23.36%, Deviation= 1.64% -23.36% 1.64%
2 13,565 8956874 , // WDT Calibration[2], calibration.WDT= 13565, Variation= -21.76%, Deviation= 1.6% -21.76% 1.60%
3 13,741 8842151 , // WDT Calibration[3], calibration.WDT= 13741, Variation= -20.2%, Deviation= 1.56% -20.20% 1.56%
4 13,917 8730330 , // WDT Calibration[4], calibration.WDT= 13917, Variation= -18.68%, Deviation= 1.52% -18.68% 1.52%
5 14,093 8621301 , // WDT Calibration[5], calibration.WDT= 14093, Variation= -17.19%, Deviation= 1.49% -17.19% 1.49%
6 14,269 8514963 , // WDT Calibration[6], calibration.WDT= 14269, Variation= -15.75%, Deviation= 1.44% -15.75% 1.44%
7 14,445 8411215 , // WDT Calibration[7], calibration.WDT= 14445, Variation= -14.34%, Deviation= 1.41% -14.34% 1.41%
8 14,621 8309965 , // WDT Calibration[8], calibration.WDT= 14621, Variation= -12.96%, Deviation= 1.38% -12.96% 1.38%
9 14,797 8211124 , // WDT Calibration[9], calibration.WDT= 14797, Variation= -11.62%, Deviation= 1.34% -11.62% 1.34%
10 14,973 8114606 , // WDT Calibration[10], calibration.WDT= 14973, Variation= -10.31%, Deviation= 1.31% -10.31% 1.31%
11 15,149 8020331 , // WDT Calibration[11], calibration.WDT= 15149, Variation= -9.02%, Deviation= 1.29% -9.02% 1.29%
12 15,325 7928222 , // WDT Calibration[12], calibration.WDT= 15325, Variation= -7.77%, Deviation= 1.25% -7.77% 1.25%
13 15,501 7838204 , // WDT Calibration[13], calibration.WDT= 15501, Variation= -6.55%, Deviation= 1.22% -6.55% 1.22%
14 15,677 7750207 , // WDT Calibration[14], calibration.WDT= 15677, Variation= -5.35%, Deviation= 1.2% -5.35% 1.20%
15 15,853 7664165 , // WDT Calibration[15], calibration.WDT= 15853, Variation= -4.18%, Deviation= 1.17% -4.18% 1.17%
16 16,029 7580011 , // WDT Calibration[16], calibration.WDT= 16029, Variation= -3.04%, Deviation= 1.14% -3.04% 1.14%
Excel Calibration Tool
To make it easier to calculate the look-up table for the calibration values, the downloadable Excel file below allows you to generate the values for the table.