Showing posts with label MSP430F2274. Show all posts
Showing posts with label MSP430F2274. Show all posts

Friday, August 5, 2011

Reading the supply voltage using the MSP430's internal Analog to Digital Converter

Many times you need to measure the supply voltage (Vdd) of the MSP430. The MSP430 has an ADC input channel which is connected to Vdd/2. The divide by two is required because the MSP430's internal reference is 2.5V, so Vdd must be divided by two for full resolution.

Two simple routines for reading the supply voltage of the MSP430 family are shown below. Some MSP430 devices use the 10-bit ADC, e.g. the MSP430F2274, and some use the 12-bit ADC, e.g. the MSP430F248. Refer to the datasheet for your part to determine which is used. 

Using the ADC10:
/** Reads the MSP430 supply voltage using the Analog to Digital Converter (ADC).
On ez430 boards, this is approx. 3600mV
@return Vcc supply voltage, in millivolts
*/
unsigned int getVcc3()
{
ADC10CTL0 = SREF_1 + REFON + REF2_5V + ADC10ON + ADC10SHT_3;  // use internal ref, turn on 2.5V ref, set samp time = 64 cycles
ADC10CTL1 = INCH_11;                        
delayMs(1);                                     // Allow internal reference to stabilize
ADC10CTL0 |= ENC + ADC10SC;                     // Enable conversions
while (!(ADC10CTL0 & ADC10IFG));                // Conversion done?
unsigned long temp = (ADC10MEM * 5000l);        // Convert raw ADC value to millivolts
return ((unsigned int) (temp / 1024l));
}

Using the ADC12:
/** Private helper method to setup ADC for one-shot conversion and read out value according to registers.
Inserts a delay before beginning conversion if REFON
@return the raw ADC value with the specified commands.
@todo move the VREF warmup to startup and leave on to avoid 17mSec blocking delay each time?
*/
unsigned int getAnalogInput(unsigned int adc12ctl0, unsigned int adc12ctl1, unsigned char adc12mctl0)
{
#define ADC_VREF_DELAY_MS 17   
ADC12CTL0 = adc12ctl0;
ADC12CTL1 = adc12ctl1;
ADC12MCTL0 = adc12mctl0;
if (adc12ctl0 & REFON)                    // if internal reference is used...
delayMs(ADC_VREF_DELAY_MS);           // 17mSec delay required to Vref capacitors
ADC12CTL0 |= ENC;                         // Enable conversions
ADC12CTL0 |= ADC12SC;                     // Start conversions
while (!(ADC12IFG & 0x01));               // Conversion done?
return ADC12MEM0;    // Read out 1st ADC value
}


/** Measures Vcc to the MSP430, nominally 3.3V
- ADC measures VCC/2 compared to 2.5V reference
- If Vcc = 3.3V, ADC output should be (1.65/2.5)*4095 = 2703
- Therefore (halfVcc/2.5)*4095 = ADC reading and (Vcc/2.5)*4095 = 2*ADC
- So Vcc*4096 = 5*ADC and VCC=5*ADC/4095

@return Vcc in millivolts
*/
unsigned int getVcc3()
{
unsigned int ctl0 = REFON + REF2_5V + ADC12ON + SHT0_15;  // turn on 2.5V ref, set samp time=1024 cycles
unsigned int ctl1 = SHP;                                  // Use sampling timer, internal ADC12OSC
unsigned char mctl0 = SREF_1 + INCH_11;                   // Channel A10, Vcc/2
unsigned long vcc = (unsigned long) getAnalogInput(ctl0, ctl1, mctl0);
unsigned long mult = vcc * 5000l;
return ((unsigned int)(mult / 4096l));
}

Thursday, June 3, 2010

Calibrating the MSP430 Very Low Power Oscillator

The MSP430F2xxx contains an internal 12kHz very low power low frequency oscillator (VLO). The frequency varies by part, temperature, and supply voltage. On an MSP430F248 the VLO runs at approx. 9.4kHz and on an MSP430F2274 it's approx. 12kHz.
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;
}