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.

MSP430F5438A: ADC Manual Conversion Hangs Using VCC Reference

Part Number: MSP430F5438A

Our application reads 5 inputs in single sequence, manually triggered in main(). We are not using an interrupts.

4 inputs are stored into 3 ADC memory segments, and 1 is stored into 1 ADC memory segment.

3 inputs use the shared reference, and 2 use the VCCS- reference.

Configuration is presented below:

    // Enable VREF=2.5V shared reference, disable temperature sensor
    REFCTL0   |= REFMSTR+REFVSEL_2+REFON+REFTCOFF;

    // Configure for sequence of A5-A7, A12 and A 13
    ADC12CTL0   =  ADC12ON+ADC12MSC+ADC12SHT0_2;   // Turn on ADC12, set sampling time
    ADC12CTL1   =  ADC12SHP + ADC12CONSEQ_1;       // Use sampling timer, single sequence

    ADC12MCTL3  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5
    ADC12MCTL4  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5
    ADC12MCTL5  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5

    ADC12MCTL6  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6
    ADC12MCTL7  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6
    ADC12MCTL8  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6

    ADC12MCTL9  =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7
    ADC12MCTL10 =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7
    ADC12MCTL11 =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7

    ADC12MCTL12 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12
    ADC12MCTL13 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12
    ADC12MCTL14 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12

    ADC12MCTL15 =  ADC12INCH_13 + ADC12EOS;        // Ref=Vcc, channel = A13, end seq.

    ADC12CTL0   |= ADC12ENC;                       // Enable conversions

The conversion and memory read is presented below:

        ADC12IFG  = 0x00;                                    // Clear flags
        ADC12CTL0 |= ADC12SC;                                // Start conversion
        while (!(ADC12IFG & 0x4000));                        // Wait for conversion to complete

        Input1  = ADC12MEM3 + ADC12MEM4 + ADC12MEM5;
        Input1  = ANALOG_IBAT / 3;

        Input2 = ADC12MEM6 + ADC12MEM7 + ADC12MEM8;
        Input2 = ANALOG_ILAMP / 3;

        Input3  = ADC12MEM9 + ADC12MEM10 + ADC12MEM11;
        Input3  = ANALOG_VBAT / 3;

        Input4 = ADC12MEM0 + ADC12MEM1 + ADC12MEM2;
        Input4 = ANALOG_LIGHT / 3;

        Input5  = ADC12MEM15;

The first conversion is always successful. After the second conversion however, the application hangs. Viewing the Register in Debug mode, values are not written to memory and the interrupt flags are not set following the second conversion request.

We resolved this problem by commenting out the line "ADC12IFG  = 0x00" and re-allocating the memory segments from ADC12MEM[12-14] to ADC12MEM[0-3]. In other words - separating the two inputs that use the VCCS- reference.

It's important to note that out of the 1500 boards that were manufactured, only 20 are exhibiting this behavior. We have done extensive circuit tracing and (nearly) ruled out external factors, particularly with the VCC- line.

Any help would be appreciation. Thank you.

  • >  ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1; // Use sampling timer, single sequence

    This uses ADC12MCTL0-2 for conversions, but the contents of those registers are "undefined" after Reset [Ref User Guide (SLAU208Q) Table 28-3]. This might be why you only see the symptom sometimes. Try instead something like:

    >  ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1 + ADC12CSTARTADD_3; // Use sampling timer, single sequence, start at MEM3

    ------------

    Per UG Sec 28.2.7.2, you need to explicitly clear ADC12SC before setting it again for the next sequence. I'm not quite sure how your change made it better (something to do with CSTARTADD, maybe) but you probably need to do that.

  • Thank you for the response. I had in fact missed the CSTARTADD instruction, but had tried different MCTL arrangements including using the first 13 MCTL's sequentially, but nothing aside from separating the A13 input from the others in memory seems to work. I also tested the solution you suggested to no avail. Nevertheless I will implement this instruction.

    We do not reset the SC bit (in debug I see the SC bit reset itself, but we should still reset it manually) and this is one of the first things I tried early in our testing. If I place the reset immediately following the interrupt flag...

    ADC12CTL0 |= ADC12SC;
    while (!(ADC12IFG & 0x4000));
    ADC12CTL0 &=~ADC12SC;

    ...the lock up still occurs. Only if the SC bit is reset after reading memory does this work. This is particularly strange because placement before or after reading memory shouldn't matter. In fact, TI's "msp430x54xA_adc12_09.c" example resets the bit before reading MCTL.

    Other workarounds we have discovered are setting the SC bit twice in a row...

    ADC12CTL0 |= ADC12SC;
    ADC12CTL0 |= ADC12SC;
    while (!(ADC12IFG & 0x4000));

    ...or resetting the ENC bit between conversions...

    ADC12CTL0 |= ADC12SC + ADC12ENC;
    while (!(ADC12IFG & 0x4000));
    ADC12CTL0 &=~ADC12SC;
    ADC12CTL0 &=~ADC12ENC;

    These are fine as far as workarounds go, but implementation of any of these suggests the MCU may not be operating within spec. Thoughts?

  • We were able to confirm that the issue followed the MCU and not the board. I also created an example program (based on TI's own ""msp430x54xA_adc12_09.c" example program) that replicates the issue we are seeing.

    The program below runs without modification on a functioning MCU. On a malfunctioning MCU, the first ADC conversion request will be successful, but the second request will cause the program to hang. The requested conversion never occurs and so the ICR is never triggered.

    There are 3 "workarounds" that are commented out. Uncommenting any one of the three workarounds will allow the program to run on a malfunctioning MCU, but I contend that neither of these workarounds should be necessary if the MCU is working to specification (SLAU208Q).

    I'm not ruling out the possibility that there is something incorrect with the programming, or that the issue is with the board the MCU is installed on, and I welcome any discussion challenging my findings.

    Otherwise, I hope this helps anyone else who may be experiencing the same issue. 

    #include <msp430.h>
    
    volatile unsigned int results[13];
    
    int main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
    
      // Enable A/D channel inputs
      P6SEL = 0xE0;
      P7SEL = 0x30;
    
      // Enable VREF=2.5V shared reference, disable temperature sensor
      REFCTL0 |= REFMSTR+REFVSEL_2+REFON+REFTCOFF;
    
      ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_2; // Turn on ADC12, set sampling time
      ADC12CTL1 = ADC12SHP+ADC12CONSEQ_1;       // Use sampling timer, single sequence
      ADC12MCTL0 = ADC12INCH_5+ADC12SREF_1;     // Ref=VREF, channel = A5
      ADC12MCTL1 = ADC12INCH_5+ADC12SREF_1;
      ADC12MCTL2 = ADC12INCH_5+ADC12SREF_1;
      ADC12MCTL3 = ADC12INCH_6+ADC12SREF_1;     // Ref=VREF, channel = A6
      ADC12MCTL4 = ADC12INCH_6+ADC12SREF_1;
      ADC12MCTL5 = ADC12INCH_6+ADC12SREF_1;
      ADC12MCTL6 = ADC12INCH_7+ADC12SREF_1;     // Ref=VREF, channel = A7
      ADC12MCTL7 = ADC12INCH_7+ADC12SREF_1;
      ADC12MCTL8 = ADC12INCH_7+ADC12SREF_1;
      ADC12MCTL9 = ADC12INCH_12;                // Ref=Vcc, channel = A12
      ADC12MCTL10 = ADC12INCH_12;
      ADC12MCTL11 = ADC12INCH_12;
      ADC12MCTL12 = ADC12INCH_13 + ADC12EOS;    // Ref=Vcc, channel = A13
      ADC12IE = 0x08;                           // Enable ADC12IFG.3
      ADC12CTL0 |= ADC12ENC;                    // Enable conversions
    
      while(1)
      {
        ADC12CTL0 |= ADC12SC;                   // Start convn - software trigger
    
        // Workaround 1 - Set conversion bit twice
        /*
        ADC12CTL0 |= ADC12SC;
        */
    
        // Workaround 2 - Reset enable bit between conversions
        /*
        ADC12CTL0 &=~ADC12SC;
        ADC12CTL0 &=~ADC12ENC;
        ADC12CTL0 |= ADC12SC + ADC12ENC;
        */
    
        __bis_SR_register(LPM4_bits + GIE);     // Enter LPM4, Enable interrupts
        __no_operation();                       // For debugger
      }
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch(__even_in_range(ADC12IV,34))
      {
      case  0: break;                           // Vector  0:  No interrupt
      case  2: break;                           // Vector  2:  ADC overflow
      case  4: break;                           // Vector  4:  ADC timing overflow
      case  6: break;                           // Vector  6:  ADC12IFG0
      case  8: break;                           // Vector  8:  ADC12IFG1
      case 10: break;                           // Vector 10:  ADC12IFG2
      case 12:                                  // Vector 12:  ADC12IFG3
        ADC12CTL0 &=~ADC12SC;                   // For sequence-of-Channels mode, ADC12SC must be cleared by software after each sequence to trigger another sequence
        results[0] = ADC12MEM0;                 // Move results, IFG is cleared
        results[1] = ADC12MEM1;                 // Move results, IFG is cleared
        results[2] = ADC12MEM2;                 // Move results, IFG is cleared
        results[3] = ADC12MEM3;                 // Move results, IFG is cleared
        results[4] = ADC12MEM4;                 // Move results, IFG is cleared
        results[5] = ADC12MEM5;                 // Move results, IFG is cleared
        results[6] = ADC12MEM6;                 // Move results, IFG is cleared
        results[7] = ADC12MEM7;                 // Move results, IFG is cleared
        results[8] = ADC12MEM8;                 // Move results, IFG is cleared
        results[9] = ADC12MEM9;                 // Move results, IFG is cleared
        results[10] = ADC12MEM10;               // Move results, IFG is cleared
        results[11] = ADC12MEM11;               // Move results, IFG is cleared
        results[12] = ADC12MEM12;               // Move results, IFG is cleared
    
        // Workaround 3 - Reset conversion bit after reading memory
        /*
        ADC12CTL0 &=~ADC12SC;
        */
    
        __bic_SR_register_on_exit(LPM4_bits);   // Exit active CPU, SET BREAKPOINT HERE
      case 14: break;                           // Vector 14:  ADC12IFG4
      case 16: break;                           // Vector 16:  ADC12IFG5
      case 18: break;                           // Vector 18:  ADC12IFG6
      case 20: break;                           // Vector 20:  ADC12IFG7
      case 22: break;                           // Vector 22:  ADC12IFG8
      case 24: break;                           // Vector 24:  ADC12IFG9
      case 26: break;                           // Vector 26:  ADC12IFG10
      case 28: break;                           // Vector 28:  ADC12IFG11
      case 30: break;                           // Vector 30:  ADC12IFG12
      case 32: break;                           // Vector 32:  ADC12IFG13
      case 34: break;                           // Vector 34:  ADC12IFG14
      default: break;
      }
    }

**Attention** This is a public forum