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.

Problems with ADC trying to read multiple channels

Other Parts Discussed in Thread: MSP430F2232, MSP430F1232

Hello everyone,

I seem to have some kind of problem trying to use ADCs in my code. I need to measure voltage on the row of 8 potentiometers, and additionaly i measure 2 other voltages. My device is MSP430F2232 which according to the datasheet has 12 ADC inputs. Out of these 12 i need 10. So i figured, the easiest way to read them is to use sequence of channels mode. The channels i use are A0-7, and A12-13, which are enabled by the following code

    ADC10AE0 |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7;             // A0-7 enable
    ADC10AE1 |= BIT4 + BIT5; //A12-13 enable

Besides i choose Channel 13 as a highest channel in my sequence of conversions in ADC10CTL1 register.

The results are supposed to be stored in the array. Here's my whole program

#include "msp430x22x2.h"
unsigned int ADC[10];
int c;
void main(void)
{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
    BCSCTL1 = CALBC1_16MHZ;  // Kalibrierdaten des Herstellers
    DCOCTL = CALDCO_16MHZ;    // Kalibrierdaten des Herstellers

    ADC10CTL1 = INCH_13 + CONSEQ_1;            // Channel 13 single sequence
    ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
    ADC10DTC1 = 10;                         // 10
    ADC10AE0 |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7;             // A0-7 enable
      ADC10AE1 |= BIT4 + BIT5; //A12-13 enable
//PWM
  P1DIR |= BIT2;
  TACCTL0 = CCIE;                                   // Enable Periodic interrupt
  TACCR0 = 1024;                                    // Periode
  TACTL = TASSEL_2 + MC_1;                         // Quelle SMCLK, aufwärts zählen
  CCTL1 = OUTMOD_7;    //PWM Reset/Set
  P1SEL |= BIT2;        //Pin als TA1
  for (;;)
  {
    ADC10CTL0 &= ~ENC;
    while (ADC10CTL1 & BUSY);               // Wait if ADC10 core is active
    ADC10SA = (short)&ADC[0];               // Data buffer start
    CCR1 = ADC[0];
    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE);        // LPM0, ADC10_ISR will force exit
  }
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    c++;
  __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    ADC10CTL0 |= ENC + ADC10SC;                    // Enable Sampling and start conversion.
}

(The PWM part is only to test which channel corresponds to which part of the data stored in array.)

So the problem is, the data in the array is located in very strange fashion. Data from some ADC is not written at all!

From what i know it's supposed to go like that: first number stored in the array is the result of the first conversion i.e. the voltage from the highest channel i chose. In my case channel 13. The second would be 12 and so on.

In my case this rule only seem to apply to the first 2 conversions. The whole list goes like that

[0] A13

[1] A12

[2] meaningless number about 500

[3] meaningless number about 500*

[4] A3

[5] A4

[6] A7

[7] A6

[8] A5

[9] A4 (for the second time!)

*The [2] and [3] show some numbers which i can not influence by rotating my potentiometers.

Data from A0, A1 and A2 is not there at all.

When using the same principle i tried to read data from channels A0-7, it worked perfectly! And even numbers of array variables made sense. So i think there is a problem with how i configure those 2 channels A12 and A13. Could it be those 2 strange numbers are in fact data from 2 unused ADCs which aren't even connected on my PCB?

Would appreciate any help or suggestions!

  • Vladimir Semin said:
    So i think there is a problem with how i configure those 2 channels A12 and A13

    Those are fine. Please note that by enabling ADC10AEx bits you are not selecting ADC channels to process by DTC sequence. You shall refer to User's Guide. DTC will do A13... A4 sampling which is 10 consecutive channels as you request. DTC sequence can't have gaps. Why you are thinking that A4 is measured twice - I don't know. perhaps just coincidence. [2] till [5] shall have A11 till A8 measurements

  •  

    Ilmars said:
    DTC will do A13... A4 sampling which is 10 consecutive channels as you request. DTC sequence can't have gaps.

    Well, as far as i understood reading the User's guide, there's no such thing as A8, A9, A10 or A11. It's impossible to enable these channels or to choose them as a highest channel for conversion sequence. So where would these 10 consecutive channels come from?

    My logic was that if these channels aren't present, DTC would just hop over them and proceed with channels which are actually there. So after A12 it goes to A7, then A6. Altogether 10 channels (A12-13, A0-7). Seems that i was wrong.

    Does it mean that i should set ADC10DTC1 as 13 and just ignore stuff corresponding to A8-11?

  • Ilmars said:
    Why you are thinking that A4 is measured twice - I don't know.

    Well, i was changing the voltage connected to the A4 pin, and these 2 array variables were changing simultaneously no matter what i did.

  • Vladimir Semin said:
    Well, as far as i understood reading the User's guide, there's no such thing as A8, A9, A10 or A11. It's impossible to enable these channels or to choose them as a highest channel for conversion sequence.

    Actually you can't disable or enable ADC channels :) Indeed it is possible to chose mentioned channels as highest channel.

    Note that ADC10AEx are not "ADC channel enable" but input pin control bits which disconnect digital input buffer from ADC input.

    Please read "ADC introduction chapter", pay special attention to "ADC10 Block Diagram" where you can see that channel A11 is connected to internal AVCC divider, A10 connected temperature sensor, A9 is internally connected to A3 and A8 is internally connected to A4.

  • Thank you, Ilmars, for your help. Using your tips i actually got it to work!

    I usually have trouble reading and understanding such diagrams especially when they are big and scary :), so i often skip them and just read the text. Now, i understand that was not a very smart thing to do :)

  • First, the ADC10 always samples a sequence from INCH_x down to INCH_0. So you have 14 results. Since the DTC is only set up for 10 results, you’ll get an ADC10 interrupt after the first 10 conversion, then four more for the remaining (not covered by DTC) conversion. But in the meantime, your main code continues. There might be a racing condition, an already pending interrupt when you enter LPM on the second loop that makes your code immediately exiting LPM etc.

    I’m not sure what “CCR1=ADC[0]” shall do. There is no valid result in ADC[0] – at least on the first run. So it is probably 0, causing eternal timer interrupts on every timer tick.

    The values on A11 to A8 are internal. A11 is VCC/2. Since you use VCC as reference, the result will of course be 1/2 of the maximum (~511). A10 is the temperature sensor. A value around 500 seems likely. You can change this by heating or cooling the MSP. A9 and A8 are sampled the external reference inputs (VeREF-, VeREF+). On your MSP, these are indeed connected to the same pin as A3 and A4.
    So your observations can be perfectly explained by looking at the users guide and the datasheet.
    J

  • Hello,

    I am also tryin gto read multiple channels from adc of msp430f1232 but havin gsome problems. can you please help me if you found the help?

    My code looks like this..

    I initialized ADC as

    ADC10CTL1 = 0x401E;
    ADC10AE0 = 0x1C; //Port A2, A3 and A4 Enabled for Analogue
    ADC10AE1 = 0x00;
    ADC10DTC0 = 0x00;
    ADC10DTC1 = 0x01;

    void main()
    //———————————
    {
    Init();
    value1 = (unsigned int *)0x20B;
    value2 = (unsigned int *)0x20D;
    value3 = (unsigned int *)0x20F;
    // value = &MOD_Ua;
    __enable_interrupt(); // Enable all interrupts
    for(;;)
    {
    // counter = counter + 1;
    // if (counter >= 20)
    // {
    // counter = 0;
    // P1OUT = P1OUT ^ BIT3;
    // }

    if (!(ADC10CTL1 & BIT0)) // if not busy
    {
    ADC10SA = 0x20B; // Data buffer start
    ADC10CTL0 |= ENC + ADC10SC; // Start sampling and conversion
    }
    }
    }

    #pragma vector = ADC10_VECTOR

    __interrupt void ADC10_ (void)
    //————————————————————————————————
    //--------------------------------------------------------------------------------
    // ADC10 interrupt
    //--------------------------------------------------------------------------------
    {
    {
    P1OUT = P1OUT ^ BIT3;
    MOD_Uc = *value1;
    MOD_Ub = *value2;
    MOD_Ua = *value3;
    }
    }



    When i start debugging i enters in adc interrupt once and after that adc busy bit stays high and does not allow me to start sampling again. i saw in the ddebugger that adcmem register values keep on chaning.

    Also can you help me when it is said in the document that write to register ADC10SA is required to initiate DTC transfer.

    ANy help will be appreciated.
  • Idon't see you initializing ADC10CTL0.
    So ADC10ON is not set, MSC is not set. This means 1) the ADC10 isn't really running and 2) each conversion needs its own trigger. Also, I don't see ADC10IE being set, so I wonder how you got your one interrupt.
    But maybe you just missed to post the first line of your ADC init code.

    You don't set ADC10CT. That means, only the very first conversion result is moved into the buffer (ADC10DT1 is set to 1) and the interrupt is generated. The next conversions go into the void until you reload ADC10SA. But you won't ever see BUSY clear agian, since you configured the ADC for repeated sequence. So it is never done.
    Please use the 'telling# defines when configuring hardware. Then it would be obvious, that "ADC10CTL1=0c401e" programs the ADC for repeated sequence, not single sequence.
    If you'd use 0x4016 instead (single sequence), the busy bit would clear at sequence end (after 5 conversions). Still only the first conversion would be copied to the buffer by the DTC, the others rot in ADC10MEM until overwritten by the next conversion.

    Also, keep in mind that a complete sequence goes from start input to A0 (5 conversions in your case for each sequence) .
    Also, on some MSPs (not the 1232, though), converting an input that is not configured for input (like A0-A1 in your case) will still disable the digital port pin circuitry during conversion. This will disturb any digital activity on this pin, creating digital output glitches or trigger input interrupts. A lot of the MSP430F2xx and especially the MSP430G2xx devices suffer this.
  • Another hint: you should reserve your buffer using the compiler/linker. Like defining globally (outside a function):
    unsigned int value[5];
    Then you can do
    ADC10SA=(unsigned int)value;
    and later
    MOD_Uc= value[0]; etc.
    Keep in mind that value[0] (or *value1 in your code) has the conversion result of A4 (reverse order, A4 is sampled and stored first);

    Using declared variables instead of fixed locations ensures that you don't overwrite your program's global vars with data if th elinekr has plcaed them where you choose to put your buffer. Tthe linker doesn't know that you are wildly tossing data into undefined memory locations.

**Attention** This is a public forum