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 Sequence of Channels (reading multiple analog inputs)

Other Parts Discussed in Thread: MSP430FR5725

Hello.  I'm using the MSP430FR5725 and I need to read in multiple analog inputs (A1, A14, A15).  How can I choose which value I want to use from the sequence?

Based on the MSP430FR57xx data sheet (Fig. 16-7 specifically), could I choose which value I want to read by simply, in the ISR, setting a count value (ie count = 15), then having it decrement and clear the flag?  Could this be accomplished so I know which channel I'm reading, or is there a simpler way to accomplish this?

  • The FR5725 has an ADC10_B module. The ADC10 sequence mode samples all channels from x down to 0. So if you need A15, A14 and A1, the sequence will sample ALL channel sfrom A15 down to A0, even though you don't need most of them.

    To pick one sample from the sequence, there are two possible ways:

    - you let the ADC10 trigger an interrupt at every conversion and only store the results of the 1st, second and 14th call of the ISR.

    - you use DMA to copy all 16 conversion results into a 32 byte memory location (e.g. an array of 16*unsigned int) and pick the results you want.

    Alternatively, you use single channel signle conversion, trigger an itnerrupt on each conversion and inside the ISR you switch the channel nr and restart the conversion. THis will give you the highest sampling rate and also allows you to sample all three channels with different sampling rates (e.g. A1 as fast as possible, but A14 and A15 only every so often)

  • Jens-Michael Gross said:

    - you let the ADC10 trigger an interrupt at every conversion and only store the results of the 1st, second and 14th call of the ISR.

    With this option, could I do something like:

    //ADC set to sequence of channels, starting at A15
    adc_count = 15;
    #pragma vector = ADC10_VECTOR
    __interrupt void ADC_ISR(void){
          if(adc_count == 15){
                A15_result = ADC10MEM0;
          }
          else if(adc_count == 14){
                A14_result = ADC10MEM0;
          }
          else if(adc_count == 1){
                A1_result = ADC10MEM0;
          }
          adc_count--;
    }
  • Yes, I had something like this in mind.

    However, even if you don't need the result, you should read ADC10MEM. I'm not sure whether the ADC10 interrutp is cleared when the ISR is called, or whther it is cleared only when you read ADC10MEM0. (I'd have to look it up in the users guide). It's good style anyway, as most other ISRs require this for sure.
    If you set adc_count in main, then you should declare it volatile. Else it may be a static variable inside teh ISR. And the ISR sets it back once it reached 0 - and restarts the ADC sequence.

  • http://pastebin.com/raw.php?i=fiN7HGFK

    That's what I changed my ISR to.  Based on the User's Guide, the AD channel is read, then converted and stored into ADC10MEM0.  ADC10IFG0 is set.  Next, the AD channel is decremented and the process is repeated.  With interrupt flags, is the ISR called each time the flag is set?  If it is, for my "if adc_count == 0", I might just disable the interrupt, too.

  • I've been stepping through my code, and when I get to my ADC ISR, I monitor the active INCHx.  I have yet to get it to go down.  It always stays at the INCHx I set in my ADC init.  Here is my ADC initialization.

    void adc_init()
    {
    //Disable ENC to set bits
    ADC10CTL0 &= ~ADC10ENC;
    //Hold time, multiple sample, ADC on
    ADC10CTL0 |= ADC10SHT_2 + ADC10MSC + ADC10ON;
    //Single channel, SMCLK, hold pulse
    ADC10CTL1 |= ADC10CONSEQ_1 + ADC10SSEL_3 + ADC10SHP + !ADC10SHS_0;
    //10-bit conversion results
    ADC10CTL2 |= ADC10RES;
    //Vref set, read A15->A0
    ADC10MCTL0 |= ADC10SREF_0 + ADC10INCH_15;
    //Enable interrupt
    ADC10IE |= ADC10IE0;
    }
  • Ok, I got the INCHx to go from A15->A0.  Here is my new ADC initialization.

    void adc_init()
    {
    //Disable ENC to set bits
    ADC10CTL0 &= ~ADC10ENC;
    //Hold time, multiple sample, ADC on
    ADC10CTL0 |= ADC10SHT_0 + !ADC10MSC + ADC10ON;
    //Single channel, SMCLK, hold pulse
    ADC10CTL1 |= ADC10CONSEQ_1 + ADC10SSEL_3 + ADC10SHP + !ADC10SHS_0;
    //10-bit conversion results
    ADC10CTL2 |= ADC10RES;
    //Vref set, read A15->A0
    ADC10MCTL0 |= ADC10SREF_0 + ADC10INCH_15;
    //Enable interrupt
    ADC10IE |= ADC10IE0;
    }
    
    

    Also, in order to start the next conversion (INCHx-1), ADC10ENC needs to be toggled.  So, at the end of my ADC ISR, I just have.

     //Enable conversion of next channel
    ADC10CTL0 &= ADC10ENC;
    ADC10CTL0 |= ADC10ENC;
  • mpgorans said:
    ADC10CTL0 |= ADC10SHT_0 + !ADC10MSC + ADC10ON;

    THis surely won't work. !ADC10MSC results in 0x00, as ADC10MSC is !=0 and therefore true, !ADC10MSC results in false, which is 0. Similar for ADC10SHS_0, which is 0 and therefore false, so !ADC10SHS_0 results in 0xff.
    You cannot clear and set bits in an |= instruction. With |= you can only set bits. Clearing bits is done with an & operator of the inverse bits:  "a &= ~(x)" clears the bits of x in a.
    And you should never us '+' to add bits in an expression. Use '|' instead to join bits and bitfields.

    If you want to clear and set bits, or mask bitfields, either use an &= instruction followed by an |=, or use a direct assignment (which also won't cause intermediate states of the target register then).

    ADC10CTL0 = (ADC10CTL0 & ~ ADC10MSC) | ADC10SHT_0 | ADC10ON;

    mpgorans said:
    Also, in order to start the next conversion (INCHx-1), ADC10ENC needs to be toggled.  So, at the end of my ADC ISR, I just have.

    Not necessary if you have ADC10MSC set. Also, I don't think that toggling ADC10ENC is the right thing to do. It's ADC10SC that starts the next convesion (unless ADC10MSC is set, and ADC10SHP, in which case the sequence runs automatically and ADC10SC starts the next sequence)

**Attention** This is a public forum