This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

help with ADC conversion



Hi i am using a MSP430FG4618 experiments board. I have this program....to display battery status on the LCD screen. I wanted to ask whether 
the way i m doing the ADC conversion is correct or not. So initially what happens I choose the internal voltage divider using ADC12MCTL0
Running on a 3V battery just now. So for example the value at divide for 3v will be 1.5 v ..which can be then converted to an ADC value(the
variable defined as unsigned ADC Value) .Now considering this value is copied to ADC12MEM0.I perform some conversion in the
interrupt routine in the ISR to convert it back into voltage( BAT_VOLT variable defined) . Multiple conversions are enabled by setting MSC.
This program is not working....The battery symbol for full battery is displayed...However, when voltage falls below 2.5 the symbol doesnt 
change.(SEE ISR ) ..BAT_full and BAT_50 are variables defined in LCD_defs.h...just to dispaly the LCDMEM values on screen.
Can anyone help with this??? does this code makes sense??
///////////////////////////////////////////////////////////CODE START/////////////////////////////////////////////////////////
#include  <msp430fg4618.h>
#include <stdint.h>
#include<intrinsics.h> //For add_bcd_short function to be used
#include "LCD_defs.h" // P7_A1...P1_A0....all defined here
unsigned int ADCValue;
double BAT_VOLT;
void LCD_all_off(void);

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

//LCD_A S0-S21 configuration
LCDAPCTL0 = LCDS24 | LCDS20 | LCDS16 | LCDS12 | LCDS8 | LCDS4;

// LCD_A configuration
LCDACTL = LCDFREQ_192 | LCD4MUX | LCDSON | LCDON; // (ACLK = 32768)/192, 4-mux LCD, LCD_A on, Segments on
LCDAVCTL0 = LCDCPEN; // Charge pump enable
LCDAVCTL1 = VLCD_3_44;
LCD_all_off();

// ADC CONFIGURATION

P6SEL |= 0x01; // Enable A/D channel A0
//ADC12CTL0 = ADC12ON + SHT0_8 + MSC; // Turn on ADC12, set sampling time
ADC12CTL0 = REFON + REF2_5V + ADC12ON + SHT0_8+ MSC;//reference used 2.5 v , MSC= multiple sample and conversion starts another
//conversions as one ends// SHT0_8 ..256 cycles of clock
ADC12CTL1 = SHP + CONSEQ_2; // Use sampling timer, set mode//repeat single channel conversions
ADC12IE = 0x01; // Enable ADC12IFG.0
ADC12CTL0 |= ENC; // Enable conversions
ADC12MCTL0=SREF_1+INCH_11; // selecting reference and channel 11(( Avcc-Avss)/2)
__enable_interrupt(); // Enable interrupts
ADC12CTL0 |= ADC12SC; // Start conversion
for(;;){
__bis_SR_register(LPM3_bits + GIE);
}
}

#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
ADCValue= ADC12MEM0; // Move conversion result, IFG is cleared
BAT_VOLT= (double)((ADCValue)*(2.5/4095)) ; //coverting the value from ADC into voltage

if (BAT_VOLT>=1.25){ //using voltage divide 2.5/2 =1.25 (not sure abt this bit??)
BAT_FULL; // Any battery value above 2.5 gives symbol battery full
}else{
BAT_50;} //any battery value below 2.5 gives low battery symbol(BAT_50 or BAT_LOW...same thing defined)

}


//LCD clear routine
void LCD_all_off(void)
{
LCDM2 = 0x00;
LCDM3 = 0x00;
LCDM4 = 0x00;
LCDM5 = 0x00;
LCDM6 = 0x00;
LCDM7 = 0x00;
LCDM8 = 0x00;
LCDM9 = 0x00;
LCDM10 = 0x00;
LCDM11 = 0x00;
LCDM12 = 0x00;
LCDM13 = 0x00;
}


  • Hmmm, Why do you set P6SEL.0 for Channel A0 if  you're sampling from channel A11?

    You configure SHT0_8 which is the S&H tiem for channel 0..7. For channels 8..15 you'll have to set SHT1_8. With your current setting, you make conversions on channel 11 with only 4 clock cycles sampling time, which is probably much too short.

    After enabling the reference, you don't wait for it to settle. So the first conversions (until the reference has settled) will give a much too-high result.

    You do not change the default frequency of MCLK (which is somewhere around ~1MHz then). The ADC runs on default clockj with 5-6MHz. With 4+13 clock cycles  So a conversionr esult is ready every ~3 MCLK cycles with the current SHT settings. I guess, your main code doesn't ever reach the endless loop because the interrupts are coming much faster than they can be executed.
    I doubt that with even the 'correct' SHT1_8 setting (256 cycles) the resulting 54 ms = 54 MCLK cycles are enough to wake up from LPM3 and execute the ISR.
    Even more since your ISR does slow floating point calculations. For your code, you don't need any float calculations. Since your just need a trigger level of 1.25V and 1.25V is 1/2 of the reference, you only need to check whether ADC12MEM is > 0x7ff or not.

    But even if you need an exact voltage, it is better to work on integer arithmetics.
    25.V/4095 is a constant. It is 0.0006105. Multiply it by 65536 and you'll get 40.01. Which is fairly close to 40 if the 0.025% error don't count.
    So ADCMEMx*40L (don't skip the 'L',a s you'll need to do a long multiplication) gives a fast integer result which is 65536 times your voltage. Or in other words, the upper word of the long result is the integer part of the voltage (0,1,2) and the lower word is the fraction.
    If you just want to compare with a fixed voltage, just multiply the comparison voltage with 65536 and compare the two long values.
    if you need a 'printed' value, you can multiply the result further by e.g. 1000 (or use 40000L right away), so the upper word gives the voltage in mV.

    But the biggest problem probably is your configuration of ADC12MCTL0. It has to be set before your set the ENC bit. Else the settings are ignored (see users guide: "modifyable only when ENC=0"). So you're actually sampling channel A0 against VCC in your program wihtout noticing. And this conversion most likely always results in 0xfff.

     

**Attention** This is a public forum