On the MSP430F2274 datasheet (page 38) the base frequency varies between 4kHz-20kHz and has a temp drift of 0.5%/degC and a supply voltage drift of 4%/V.
So in order to make it useful we need to calibrate it. The method below will calibrate the VLO against the main oscillator. The accuracy of this calibration routine will only be as accurate as the main oscillator. If you're using one of the calibrated DCO frequencies (+/- 1%) then the end result will be the VLO within about 2% of actual. This will be more accurate if the main oscillator is sourced from a crystal.
This calibration routine uses Timer A in the capture mode to capture the number of main clock cycles between subsequent ACLK cycles. This routine only counts one pulse, for more consistency you may want to count multiple ACLK cycles and average them.
/** Calibrate VLO. Once this is done, the VLO can be used semi-accurately for timers etc.
Once calibrated, VLO is within ~2% of actual when using a 1% calibrated DCO frequency and temperature and supply voltage remain unchanged.
@return VLO frequency (number of VLO counts in 1sec)
@pre SMCLK is 4MHz
@pre MCLK is 8MHz
@pre ACLK sourced by VLO (BCSCTL3 = LFXT1S_2; in MSP430F2xxx)
@note Calibration is only as good as MCLK source. Obviously, if using the internal DCO (+/- 1%) then this value will only be as good as +/- 1%. YMMV.
@note On MSP430F248 or MSP430F22x2 or MSP430F22x4, must use TACCR2. On MSP430F20x2, must use TACCR0.
Check device-specific datasheet to see which module block has ACLK as a compare input.
For example, see page 23 of the MSP430F24x datasheet or page 17 of the MSP430F20x2 datasheet, or page 18 of the MSP430F22x4 datasheet.
@note If application will require accuracy over change in temperature or supply voltage, recommend calibrating VLO more often.
@post Timer A settings changed
@post ACLK divide by 8 bit cleared
*/
unsigned int calibrateVlo()
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
delayMs(1000);
BCSCTL1 |= DIVA_3; // Divide ACLK by 8
TACCTL2 = CM_1 + CCIS_1 + CAP; // Capture on ACLK
TACTL = TASSEL_2 + MC_2 + TACLR; // Start TA, SMCLK(DCO), Continuous
while ((TACCTL0 & CCIFG) == 0); // Wait until capture
TACCR2 = 0; // Ignore first capture
TACCTL2 &= ~CCIFG; // Clear CCIFG
while ((TACCTL2 & CCIFG) == 0); // Wait for next capture
unsigned int firstCapture = TACCR2; // Save first capture
TACCTL2 &= ~CCIFG; // Clear CCIFG
while ((TACCTL2 & CCIFG) ==0); // Wait for next capture
unsigned long counts = (TACCR2 - firstCapture); // # of VLO clocks in 8Mhz
BCSCTL1 &= ~DIVA_3; // Clear ACLK/8 settings
vloFrequency = ((unsigned int) (32000000l / counts));
return vloFrequency;
}