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.

ADC Repeated-Single-Channel-Conversion

Other Parts Discussed in Thread: MSP430G2553, MSP430G2452

Hi everyone,

I am trying to do a single-conversion adc with several arbitrary inputs, i.e config pin 1, convert, stop then config pin 2, convert, stop etc, take average of 50 samples, store in memory and display via UART. I want to do several single conversion, one after another instead of a sequence.  I have luck with single input, but not with several inputs. Can anyone point out what's wrong and is this the correct approach? I just started learning C and hardware programming, so bear with me. Below is my code:


#include<msp430g2553.h>

#include "UART.h"

volatile int voltRaw[5];

volatile float voltage = 0;

unsigned int avg_voltage = 0;

unsigned int average[50];

unsigned int i = 0;

int ii = 0;

int a = 0;

void Config_ADC(void);

void Start_ADC1(void);

void Start_ADC2(void);

void Start_ADC3(void);

void Start_ADC4(void);

void Start_ADC5(void);

void Display_ADC(int a);

void main(void) {

Config_ADC();

Start_ADC1();

_enable_interrupt();

Display_ADC(a);

Start_ADC2();

_enable_interrupt();

Display_ADC(a);

Start_ADC3();

_enable_interrupt();

Display_ADC(voltRaw[2]);

Start_ADC4();

_enable_interrupt();

Display_ADC(voltRaw[3]);

Start_ADC5();

_enable_interrupt();

Display_ADC(voltRaw[4]);

}

void Config_ADC()

{

ADC10CTL0 = SREF_1 + REF2_5V + REFON + ADC10ON + ADC10IE + ADC10SHT_3 + MSC;

ADC10CTL1 = ADC10DIV_5 + ADC10SSEL_3 + CONSEQ_2;

}

void Start_ADC1()    // Connected to an external multiplexer

{

P2DIR = BIT7;

P2OUT = 0;

P2DIR = BIT6;

P2OUT = 1;

_delay_cycles(100);

ADC10CTL1 |= INCH_0;

ADC10CTL0 |= ENC + ADC10SC;

while (ADC10CTL1 & ADC10BUSY);

a = 6;

voltRaw[0] = avg_voltage;

}

void Start_ADC2()  // Connected to the same external multiplexer

{

P2DIR = BIT7;

P2OUT = 1;

P2DIR = BIT6;

P2OUT = 1;

_delay_cycles(100);

ADC10CTL1 |= INCH_0;

ADC10CTL0 |= ENC + ADC10SC;

while (ADC10CTL1 & ADC10BUSY);

a = 5;

voltRaw[1] = avg_voltage;

}

void Start_ADC3()

{

ADC10CTL1 &= 0x0FFF;

ADC10CTL1 |= INCH_3;

ADC10CTL0 |= ENC + ADC10SC;

while(ADC10CTL1 & ADC10BUSY);

a = 4;

voltRaw[2] = avg_voltage;

}

void Start_ADC4()

{

ADC10CTL1 &= 0x0FFF;

ADC10CTL1 |= INCH_4;

ADC10AE0 = BIT4;

ADC10CTL0 |= ENC + ADC10SC;

while(ADC10CTL1 & ADC10BUSY);

a = 3;

voltRaw[3] = avg_voltage;

}

void Start_ADC5()

{

ADC10CTL1 &= 0x0FFF;

ADC10CTL1 |= INCH_5;

ADC10CTL0 |= ENC + ADC10SC;

while(ADC10CTL1 & ADC10BUSY);

a = 0;

voltRaw[4] = avg_voltage;

}

void Display_ADC(int a)

{

uart_puts_numbers(a);

put('-');

uart_puts_numbers(avg_voltage);

put(' ');

voltage = (avg_voltage * 2.5)/1024;

_delay_cycles(8000000);

}

#pragma vector = ADC10_VECTOR

__interrupt void ADC10_ISR(void)

{

// voltRaw = ADC10MEM;

average[i] = ADC10MEM;

if (i < 50)

{

i++;

}

else

{

avg_voltage = 0;

for(ii = 0; ii < 50; ii++)

{

avg_voltage = avg_voltage + average[ii];

}

avg_voltage = avg_voltage/50;

i = 0;

ADC10CTL0 &= ~ENC;

}

}


  • i am trying the same thing,

    under the same testing voltage, i get different value for adc.

    Have you solved your problem? Need some guidance.

    Below is my code:

    #include "msp430g2452.h"
    #include "lcd16.h"

    #define NSAMPLES 0X20
    #define MIDDLE (NSAMPLES/2)
    #define RANGE 4

    void main (void)
    {
    unsigned int samples [NSAMPLES];
    unsigned int samples1 [NSAMPLES];
    unsigned int average;
    unsigned int average1;


    WDTCTL = WDTPW + WDTHOLD; // Stop WDT

    lcdInit();

    ADC10CTL0 = SREF_1 + ADC10SHT_0 + MSC + REFON + REF2_5V + ADC10ON;
    delayUs(50);
    ADC10CTL1 = SHS_0 + ADC10DIV_5 + ADC10SSEL_0 + CONSEQ_2;


    ADC10DTC1 = NSAMPLES;

    for (;;)
    {

    //Read port A0

    ADC10CTL0 &= ~ENC;
    ADC10CTL1 &= ~INCH_1;
    ADC10CTL1 |= INCH_0;
    ADC10AE0 = BIT0;
    while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
    ADC10SA = (unsigned int) samples;
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

    average = samples[0];

    gotoXy (0,0);
    printInt(average);
    delayMs(500);


    //Read port A1

    ADC10CTL0 &= ~ENC;
    ADC10CTL1 &= ~INCH_0;
    ADC10CTL1 |= INCH_1;
    ADC10AE0 = BIT1;
    while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
    ADC10SA = (unsigned int) samples1;
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

    average1 = samples1[0];

    gotoXy (0,1);
    printInt(average1);
    delayMs(500);

    }
    }

  • Kean Tan said:

    Start_ADC1();

    _enable_interrupt();

    Display_ADC(a);

    Start_ADC2();

    _enable_interrupt()

    enter LPM after Display_ADC(a) and exit LPM after 50 samples are read for that particular channel, like below,

    Start_ADC1();

    _enable_interrupt();

    <Enter LPM3>

    Display_ADC(a);

    Start_ADC2();

    _enable_interrupt();

    if(i<50){......}

    else{......  <Exit LPM3>}

  • Tan Chin Yew said:
    ADC10AE0 = BIT0;
    while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
    ADC10SA = (unsigned int) samples;
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

    average = samples[0];

    gotoXy (0,0);
    printInt(average);
    delayMs(500);

    each sample and conversion takes 4+12+1=17 ADC10OSC clock cycles so after starting the conversion wait till its done

    add while (ADC10CTL1 & BUSY);  after starting the conversion. and disable it after conversion is done and before u start printing this value.

  • chethu gowda said:
    add while (ADC10CTL1 & BUSY);  after starting the conversion. and disable it after conversion is done and before u start printing this value.

    In repeated single conversion, BUSY won't go low. Instead wait for ADC10IFG being set,a s this indicates a new value available at ADC10MEM0. Reading ADC10MEM0 will clear ADC10IFG.

  • chethu gowda said:

    each sample and conversion takes 4+12+1=17 ADC10OSC clock cycles so after starting the conversion wait till its done

    do i need to add my sampling time?

  • Jens-Michael Gross said:

    In repeated single conversion, BUSY won't go low. Instead wait for ADC10IFG being set,a s this indicates a new value available at ADC10MEM0. Reading ADC10MEM0 will clear ADC10IFG.

    i add while(ADC10CTL0 & ~ADC10IFG), but it doesnt seem to work. My lcd display show up blank.

    ADC10CTL0 &= ~ENC;
    ADC10CTL1 &= ~INCH_0;
    ADC10CTL1 |= INCH_1;
    ADC10AE0 = BIT1;
    while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
    ADC10SA = (unsigned int) samples;
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start

     while(ADC10CTL0 & ~ADC10IFG)

  • Tan Chin Yew said:
    do i need to add my sampling time?

    The sample and hold time and the clock divider will decide your sampling time. you need not worry about it as you have already initialized these parameters.

    chethu gowda said:

    each sample and conversion takes 4+12+1=17 ADC10OSC clock cycles so after starting the conversion wait till its done

    What I mean to say is after starting the ADC conversion it takes about 17 ADC10OSC clock cycles to sample give you the data, so you should wait till the data is made available instead of immediately trying to display it.

  • Tan Chin Yew said:
     while(ADC10CTL0 & ~ADC10IFG)

    I guess you have done it like

    while(ADC10CTL0 & ~ADC10IFG);

    you put a break point at immediately after this and check for the value in samples[0], and make sure the problem is not with your display module.

  • Tan Chin Yew said:
    do i need to add my sampling time?

    my mistake.

    I meant do i need to increase my sampling time? 

  • Tan Chin Yew said:
    I meant do i need to increase my sampling time? 

    The sampling time determines the number of samples the ADC module takes from your analog signal for it's measurement, if your signal is stable one the sampling rate will not matter much.

    and if your signal has too much of noise/glitches and you dont want to miss them then you can keep the lowest possible sampling time which is 4 ADC10CLKs.

    But in this case the problem is not with the sampling time.

    Like I said, try reading the ADC memory register and make sure the display is proper first.

  • Tan Chin Yew said:
     while(ADC10CTL0 & ~ADC10IFG)

    This will loop forever. You basically take ADC10CTL0, AND it with the inversed value of ADC10IFG, which basically clears the ADC10IFG bit from the content of ADC10CTL0 and loops if there are any othe rbits remaining. Which is always the case.

    What you have to do is

    while(!(ADC10CTL0&ADC10IFG));

    THi swill take ADC10CTL0, clear out all bits except the ADC10IFG bit and loop if the result is zero.

  • Jens-Michael Gross said:

     while(ADC10CTL0 & ~ADC10IFG)

    This will loop forever. You basically take ADC10CTL0, AND it with the inversed value of ADC10IFG, which basically clears the ADC10IFG bit from the content of ADC10CTL0 and loops if there are any othe rbits remaining. Which is always the case.

    What you have to do is

    while(!(ADC10CTL0&ADC10IFG));

    THi swill take ADC10CTL0, clear out all bits except the ADC10IFG bit and loop if the result is zero.

    [/quote]

    i inverse the flag because the datasheet mentions

    "When using the DTC this flag is set when a block of transfers is completed."

    so when i want it to out from loop, i need it to be zero when transfer completed.

  • Tan Chin Yew said:
    i inverse the flag because the datasheet mentions
    "When using the DTC this flag is set when a block of transfers is completed."
    so when i want it to out from loop, i need it to be zero when transfer completed.


    But you didn't inverse the flag or have to.

    You have to inverse the check for the flag.

    What you did was not inverting the flag, you were clearing the flag out of the register content and checkign the remaining values.

    To invert the flag (or invert the test for the flag), you have to first isolate the flag (register & flag), then either check for it being false or invert the result and check for the result being true.

    Either (!(register & flag)) or (~(register&flag))

  • sorry for late reply,

    thank for the correction,

    i tried (!(register & flag)),

    it doesnt work also.

  • Tan Chin Yew said:
    i tried (!(register & flag)),
    it doesnt work also.

    At least the check is okay now. If your display remains blank, this may have oteh rreasons. Does it show anything at all? Maybe your send is broken? What about sending a 'hello world' message at startup?

    Anotehr thing to do: you 'wait if aADC10 is active'. This wait should happen immediately after clearing ENC. So the ADC isn't active when you switch the channel. You should also clear ADC10SC at this point, as the ADC is (re)started by a rising edge of ADC10SC.

**Attention** This is a public forum