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.

CCS/MSP430FR2311: ADC with a sequence of channels gets stuck on a value.

Part Number: MSP430FR2311

Tool/software: Code Composer Studio

Hi,

I've been doing a single channel ADC+UART to send my result to my PC via USB and plot it with MatLab. While the single channel version works fine I had problems when I tried to reconfigure the ADC for multiple channels.

I've been trying to do ADC sequence using 1.0,1.1,1.2 on my MSP430 and when I try to debug it the first sequence runs fine but then it just fills up my results with the same value constantly for some reason. My first guess was that somehow it accidentally switches back to single channel mode but this result value doesn't change with any of the used channels. These problems showed up in while I was debugging in CCS so it's not a communication problem.

If anyone could help me out what am I missing I'd be really grateful!

*Edited code



#include <msp430.h>
void Init_GPIO();

#define MCLK_FREQ_MHZ 8                     // MCLK = 8MHz
unsigned int ADC_Result[3];
unsigned int Request =0;
unsigned int i;
int main(void)
{

    WDTCTL = WDTPW | WDTHOLD;                                // Stop WDT

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
    __bis_SR_register(SCG0);                 // disable FLL
     CSCTL3 |= SELREF__REFOCLK;               // Set REFO as FLL reference source
     CSCTL1 = DCOFTRIMEN_1 | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_3;// DCOFTRIM=3, DCO Range = 8MHz
     CSCTL2 = FLLD_0 + 243;                  // DCODIV = 8MHz
     __delay_cycles(3);
     __bic_SR_register(SCG0);                // enable FLL


     CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK; // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
                                              // default DCODIV as MCLK and SMCLK source

     // Configure UART pins
     P1SEL0 |= BIT6 | BIT7;                    // set 2-UART pin as second function

     // Configure UART
     UCA0CTLW0 |= UCSWRST;
     UCA0CTLW0 |= UCSSEL__SMCLK;

     // Baud Rate calculation
     // 8000000/(16*9600) = 52.083
     // Fractional portion = 0.083
     // User's Guide Table 17-4: UCBRSx = 0x49
     // UCBRFx = int ( (52.083-52)*16) = 1
     UCA0BR0 = 52;                             // 8000000/16/9600
     UCA0BR1 = 0x00;
     UCA0MCTLW = 0x4900 | UCOS16 | UCBRF_1;

     UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
     UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt

    // __bis_SR_register(LPM3_bits|GIE);         // Enter LPM3, interrupts enabled

     // Configure ADC A0~2 pins
     P1SEL0 |= BIT0 + BIT1 + BIT2;
     P1SEL1 |= BIT0 + BIT1 + BIT2;
     // Configure ADC
     ADCCTL0 |= ADCSHT_2 | ADCMSC | ADCON;                       // 16ADCclks, MSC, ADC ON
     ADCCTL1 |= ADCSHP | ADCCONSEQ_1 | ADCSSEL_1;                // ADC clock ACLK, sampling timer, s/w trig.,single sequence
     ADCCTL2 &= ~ADCRES;                                         // 8-bit conversion results
     ADCMCTL0 |= ADCINCH_2 | ADCSREF_1;                          // A0~2(EoS); Vref=1.5V
     ADCIE |= ADCIE0;                                            // Enable ADC conv complete interrupt

     // Configure reference
     PMMCTL0_H = PMMPW_H;                                        // Unlock the PMM registers
     PMMCTL2 |= INTREFEN;                                        // Enable internal reference
     __delay_cycles(400);                                        // Delay for reference settling
     __no_operation();
    //Timer

       TB0CCTL0 |= CCIE;                             // TBCCR0 interrupt enabled
       TB0CCR0 = 50000;
       TB0CTL |= TBSSEL__SMCLK | MC__CONTINUOUS;     // SMCLK, continuous mode
       __bis_SR_register(GIE);

    while(1)
    {
        if(Request!=0)
        {
            i = 2;
            while(ADCCTL1 & ADCBUSY);                                // Wait if ADC core is active
            ADCCTL0 |= ADCENC | ADCSC;                               // Sampling and conversion start
            //__bis_SR_register(LPM0_bits | GIE);                      // Enter LPM0 w/ interrupts
            __no_operation();                                        // Only for debug
            __delay_cycles(5000);
            __no_operation();                                   // For debug only
        }
        //else ADCCTL0 &= ~ADCENC;
    }
}

//ADC_INTERRUPT***************************


#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
    {
        case ADCIV_NONE:
            break;
        case ADCIV_ADCOVIFG:
            break;
        case ADCIV_ADCTOVIFG:
            break;
        case ADCIV_ADCHIIFG:
            break;
        case ADCIV_ADCLOIFG:
            break;
        case ADCIV_ADCINIFG:
            break;
        case ADCIV_ADCIFG:
            ADC_Result[i] = ADCMEM0;
            if(i == 0)
            {
                __bic_SR_register_on_exit(LPM0_bits);              // Exist LPM0
            }
            else
            {
                i--;
            }
            break;
        default:
            break;
    }
}


//UART INTERRUPT*******************

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
  {
    case USCI_NONE: break;
    case USCI_UART_UCRXIFG:
      while(!(UCA0IFG&UCTXIFG));
      //TODO:
      //Amikor bejövő érték: kezdődjön az ADC, és küldje vissza a kapott értékeket

      //UCA0TXBUF = UCA0RXBUF;
      if(Request==0)
      {
          Request=1;
      __no_operation();
      }
      else
      {
          Request=0;
          ADCCTL0 &= ~(ADCENC | ADCSC);
      }

      break;
    case USCI_UART_UCTXIFG: break;
    case USCI_UART_UCSTTIFG: break;
    case USCI_UART_UCTXCPTIFG: break;
    default: break;
  }
}

// Timer B0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER0_B0_VECTOR
__interrupt void Timer_B (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_B0_VECTOR))) Timer_B (void)
#else
#error Compiler not supported!
#endif
{
    if(Request!=0)
    {
    Request=0;
    UCA0TXBUF = ADC_Result[i];
    __delay_cycles(5000);
    UCA0TXBUF = ADC_Result[i]>>8;
    TB0CCR0 += 50000;                             // Add Offset to TBCCR0
    }
}



//INIT***************

void Init_GPIO()
{
    P1DIR = 0xFF; P2DIR = 0xFF;
    P1REN = 0xFF; P2REN = 0xFF;
    P1OUT = 0x00; P2OUT = 0x00;
}

  • This code doesn't build. Please post the code you are actually using.

        __delay_cycles(5000);

    This delay is much longer than the time required for the entire conversion sequence, so if your timer goes off while the ADC is running the ADC interrupt will be blocked, and you'll lose all but the A0 reading.

  • Sry, grabbed the wrong file.
    Here is my code stripped from the unnecessary parts. This is just the ADC sequence and in the CSS debugger all 3 ADC_Result is stuck on the same value. Also I removed the jumper from the 1.0 led if it matters.

    #include <msp430.h>
    
    unsigned char ADC_Result[3];                                    // 8-bit ADC conversion result array
    unsigned char i;
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;                                   // Stop WDT
    
        // Configure ADC A0~2 pins
        P1SEL0 |= BIT0 + BIT1 + BIT2;
        P1SEL1 |= BIT0 + BIT1 + BIT2;
    
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        // Configure ADC
        ADCCTL0 |= ADCSHT_2 | ADCMSC | ADCON;                       // 16ADCclks, MSC, ADC ON
        ADCCTL1 |= ADCSHP | ADCCONSEQ_1 | ADCSSEL_1;                // ADC clock ACLK, sampling timer, s/w trig.,single sequence
        ADCCTL2 &= ~ADCRES;                                         // 8-bit conversion results
        ADCMCTL0 |= ADCINCH_2 | ADCSREF_1;                          // A0~2(EoS); Vref=1.5V
        ADCIE |= ADCIE0;                                            // Enable ADC conv complete interrupt
    
        // Configure reference
        PMMCTL0_H = PMMPW_H;                                        // Unlock the PMM registers
        PMMCTL2 |= INTREFEN;                                        // Enable internal reference
        __delay_cycles(400);                                        // Delay for reference settling
        __no_operation();
    
        while(1)
        {
            i = 2;
            while(ADCCTL1 & ADCBUSY);                                // Wait if ADC core is active
            ADCCTL0 |= ADCENC | ADCSC;                               // Sampling and conversion start
            __bis_SR_register(LPM0_bits | GIE);                      // Enter LPM0 w/ interrupts
            __no_operation();                                        // Only for debug
            __delay_cycles(5000);
            __no_operation();
        }
    }
    
    // ADC interrupt service routine
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC_VECTOR
    __interrupt void ADC_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
        switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
        {
            case ADCIV_NONE:
                break;
            case ADCIV_ADCOVIFG:
                break;
            case ADCIV_ADCTOVIFG:
                break;
            case ADCIV_ADCHIIFG:
                break;
            case ADCIV_ADCLOIFG:
                break;
            case ADCIV_ADCINIFG:
                break;
            case ADCIV_ADCIFG:
                ADC_Result[i] = ADCMEM0;
                if(i == 0)
                {
                    __bic_SR_register_on_exit(LPM0_bits);              // Exist LPM0
                }
                else
                {
                    i--;
                }
                break;
            default:
                break;
        }
    }
    

  • When I put this on a Launchpad, I see ADC_Result changing. The values fluctuate by themselves when the pins are floating, and read appropriately when I jumper to 3V3 or GND.

    You need to also remove the jumper from J7 (P1.2, light sensor).

    How are you testing this? I'm pretty sure the ADC continues to run while you're at a breakpoint, so you need to choose carefully where to stop. The top of the while(1) loop in main is probably a good place.

  • I also removed P1.2 jumper. I use 3 potmeters connedted to 3v3,gnd and P1.0,1.1,1.2

    I ran the code step by step with F6 and Run to lines, and it works fine but the problem occurs if I let the code run then sometimes the code is stuck at this line:

    __bis_SR_register(LPM0_bits | GIE);

    And I can't step over it and if I try crtl+R the debugger gives this message "GEL Expression: GEL_Go(0xf174)"

  • I recommend you not try to step through this code, since the ADC keeps running while you're stopped.

    Try setting a breakpoint at the first line of the while(1) loop. At this point the ADC is idle. Each time you Continue, you should get a new set of readings.

**Attention** This is a public forum