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.

MSP430F6779: MSP430F6779 ADC10 not reading full scale

Part Number: MSP430F6779


I am trying to read an analog input on A3. When I ramp up the voltage to around 2 Volts on the analog input, the ADC value seems to max out at 511. It looks like the 10th bit isn't being used. What register do I need to change to get it to read a full scale of 1023 and use all 10 bits? 

/* --------------------------- */
/* EVSE ADC10 Setup */
/* --------------------------- */
/* Prepare the ADC10A for configuration */
ADC10CTL0 &= ~ADC10ENC;
/* Clear pending interrupts to ensure trigger for DMA */
ADC10IFG = 0;

/* ADC on, ADC10 waits for trigger from the SD24, sampling time 2us 8xADCclk, auto next conv. */
ADC10CTL0 = ADC10SHT0 | ADC10ON | ADC10MSC;

/* Triggered by the SD24, SMCLK/6 = 4MHz, Pulse Sample Mode*/
ADC10CTL1 = ADC10SHP | ADC10SHS_0 | ADC10DIV_0 | ADC10SSEL_3 | ADC10CONSEQ_2; /* Single Channel, Repeat Conversion */

/* 10-bit conversion results */
ADC10CTL2 |= ADC10RES;

/* Enable ADC conv complete interrupt */
ADC10IE |= ADC10IE0;

/* A3 ADC input select; Vref=AVCC */
ADC10MCTL0 |= ADC10INCH_3 | ADC10SREF_0;

/* Enable ADC10 interrupts */
//ADC10IE = ADC10IE0 | ADC10OVIE | ADC10TOVIE;

/* Start ADC and wait for a software start conversion trigger */
ADC10CTL0 |= ADC10ENC + ADC10SC;

Thanks,

Mike

  • What speed is SMCLK (ADC10SSEL=3)? Data sheet (SLAS768E) Sec 5.57 shows the ADC clock requirements. In practice, MODCLK (ADC10SSEL=0) is always in spec, since the ADC is what that clock is designed for.

    More generally, if your source has high impedance you need a higher (longer) setting for ADC10SHT, to assure the sampling capacitor has time to charge.

  • Awesome Bruce. Changing ADC10SSEL=3 to ADC10SSEL=0 seemed to work great!! :) 

    Does the code below look right for taking multiple samples and averaging them? Or is it faster/better to just take one sample? 

    ISR(ADC10, adc10_interrupt)
    {
       switch (__even_in_range(ADC10IV, ADC10IV_ADC10IFG))
       {
          case ADC10IV_NONE:
          break;
          case ADC10IV_ADC10OVIFG:
          break;
          case ADC10IV_ADC10TOVIFG:
          break;
          case ADC10IV_ADC10HIIFG:
          break;
          case ADC10IV_ADC10LOIFG:
          break;
          case ADC10IV_ADC10INIFG:
          break;
          case ADC10IV_ADC10IFG:
                ADC10IFG &= ~ADC10IFG0;
                if( adcSampleNumber >= 10 )
                {
                      adcSampleNumber = 0;
                      adc10Average = adc10Total / 10.0;
                      adc10Voltage = (adc10Average / 1024) * 3.30;
                      adc10Total = 0.0;
                      ADC10CTL0 &= ~ADC10ENC; //Disable multiple samples after 100
                }
                else
                {
                      adcValues[adcSampleNumber] = ADC10MEM0;
                      adc10Total = adc10Total + ADC10MEM0;
                      adcSampleNumber = adcSampleNumber + 1;
                }
                break;
          }
    }

    Thanks for the help!

  • 1) You should be wary of using floating point in an ISR. (If you can avoid it entirely, e.g. using scaled-integer, that's even better.) I don't see the declarations of your variables; if it's only the termination condition (computing the average) maybe it doesn't matter so much, but if e.g. adcValues[] is float, you'll probably get overruns.

    2) With CONSEQ=2, setting ENC=0 doesn't stop the current conversion [Ref User Guide (SLAU208Q) Sec 27.2.7.6]. That means that after you compute the average you'll probably get one more IFG0, which will leave a stale value in adcValues[0]. [Edit: Maybe set IE0=0 in termination, then set IFG0=0 when you set IE0=1 to restart the sequence.]

    3) Averaging consecutive readings can reduce random noise on the signal. But that assumes the signal will stay stable for the entire averaging period. If this is the same experiment as the other thread, I think you'll have to design carefully to get even one ADC measurement within your sample window.

  • I was mainly using floating point just to convert the adc value to actual voltage just for initial testing to compare it to the voltage input. I will get rid of this code once everything is working.

    This is the same code as the other thread where I am measuring the high side of the PWM signal. I plan to make sure that the adc value is above some threshold to get rid of samples that aren't occurring during the high side of the PWM signal. 

    Would it be better to just take one sample then? 

  • OK, just be careful that your floating-point usage doesn't get in the way of what you're doing.

    Based on the estimations in the other thread, I suggest you start by focusing on getting one sample, rather than averaging. You may still want the array so you can see where the PWM (high) period ends.

    [Edit: For those wondering, this is the "other thread":

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1208935/msp430f6779-msp430f6779-measuring-voltage-of-pwm-signal

    ]

  • Does the code below look right for taking multiple samples and averaging them? Or is it faster/better to just take one sample?

    This is a horrible way to do it. Your signal should have been through an anti-aliasing filter (at least a simple RC filter if nothing else) which means that it isn't going to change at all using MSC. All this will do is average out ADC internal noise. If any. It also puts sharp requirements on the source impedance of the signal.

    If you want to use a digital low pass filter, use uniform samples at some multiple of the desired output sample rate. Best is a multiple that is a power of two since that creates a fixed point result.

  • Thanks for the suggestion David and Bruce! Below is my updated ADC10 ISR code. 

    ISR(ADC10, adc10_interrupt)
    {
       switch (__even_in_range(ADC10IV, ADC10IV_ADC10IFG))
       {
          case ADC10IV_NONE:
             break;
          case ADC10IV_ADC10OVIFG:
             break;
          case ADC10IV_ADC10TOVIFG:
             break;
          case ADC10IV_ADC10HIIFG:
             break;
          case ADC10IV_ADC10LOIFG:
             break;
          case ADC10IV_ADC10INIFG:
             break;
          case ADC10IV_ADC10IFG:
             ADC10CTL0 &= ~ADC10ENC;
             ADC_Result = ADC10MEM0; // Store ADC10 channel 0 result
             ADC10CTL1 ^= ADC10ISSH; // Toggle ISSH to provide trigger on each cycle (EQU0)
             ADC10CTL0 |= ADC10ENC;
             break;
          }
    }

     

**Attention** This is a public forum