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.

MSP430F5437A: Occasional Unexpected Values from the ADC.

Prodigy 30 points

Replies: 5

Views: 77

Part Number: MSP430F5437A

We are using 3 channels on the ADC. One for a temperature read, one for a battery level, and one for ambient light level. Occasionally we are seeing ADC value that are unexpected. For example a temperature value that works out to be 10 degrees off from the previous temperature. Or the battery level will drop from 70-80% down to 30-40%. Most of the time it works as expected.

Since this is a battery device we are putting the MSP430 into LMP3 low power mode. We are shutting the ADC down before going to sleep to reduce the current. When the micro wakes up we reinitialize the ADC before doing a temperature or battery read. I read on a previous post that we should clear out the control register before making any changes, i.e. ADC12CTL0 = 0;, except that was for a different MSP. () I'm guessing that it would hold over for other variants of the MSP as well. Can someone explain why we should clear that register out before making any changes? Could this be causing the occasional unexpected ADC value?

I've posted the code we use below for reference.



/** * initialize_adc_sensor */ void initialize_adc (t_adc * adc, const t_io_pin * nref, const t_io_pin * pref, const t_io_pin * sensor) { adc->pos_reference = pref; adc->neg_reference = nref; adc->sensor = sensor; /* * init IOs */ *(adc->pos_reference->port->selection) |= (adc->pos_reference->bit); // *(adc->neg_reference->port->selection) |= (adc->neg_reference->bit); // *adc->pos_reference->port->selection |= adc->pos_reference->pin->bit; /* enable IO */ initialize_io_pin (adc->neg_reference, LOW); initialize_io_pin (adc->sensor, TRISTATE); initialize_io_pin (get_gpio(IO_ALS_PIN), TRISTATE); //if (!read_pin(get_gpio(IO_V_24AC))) //initialize_io_pin(get_gpio(IO_BATT_EN), HIGH); //else initialize_io_pin(get_gpio(IO_BATT_EN), TRISTATE); /* * initialize ADC */ REFCTL0 = 0; // ADC12_A ref control registers ADC12CTL0 = ADC12REFON+ADC12REF2_5V+ADC12ON+ADC12MSC+ADC12SHT0_15; // Turn on ADC12, extend sampling time // to avoid overflow of results ADC12CTL1 = ADC12SHP+ADC12CONSEQ_3; // Use sampling timer, single sequence ADC12CTL2 |= ADC12TCOFF+ADC12REFOUT+ADC12PDIV; //Divide the clk by 4 to slow down ADC Sampling ADC12MCTL0 = ADC12SREF_7 | ADC12INCH_0; // ADC A0 - Stop at A0 | ADC12EOS ADC12MCTL1 = ADC12SREF_7 | ADC12INCH_1; // ADC A1 ADC12MCTL4 = ADC12SREF_7 | ADC12INCH_5 | ADC12EOS; // ADC A5 - Stop at A5 | ADC12EOS ADC12CTL0 |= ADC12ENC; // Enable conversions ADC12CTL0 |= ADC12SC; // Start convn - software trigger adc_wake_up (adc); adc_reset (adc); ADC12IE = ADC12IE0 | ADC12IE1; // Enable ADC12IFG.0,1,4 //ADC12IE = 0x13; // Enable ADC12IFG.0,1,4 }
/**
 * adc_wake_up
 */
void
adc_wake_up (t_adc * adc)
{
  ENTER_CRITICAL ();

  /*
   * timer configuration
   */
  assert ((TA1CTL & 0xfffe) == 0x0);

  TA1CTL = TASSEL__SMCLK | ID0 | ID1;	/* use SMCLK as clock source */

  /*
   * timer event-capture configuration
   */
  TA1CCTL1 = OUT |		/* out bit value */
    CAP |			/* set to capture mode */
    CCIS0 |			/* capture input CCIxB = CBOUT ->
				 * datasheet p.28 */
    SCS |			/* Synchronize the comparator signal to
				 * timer clock */
    CM1;			/* capture on rising edge */

  assert (!(TA1CTL & MC__UP));

  EXIT_CRITICAL ();
}
/**
 * called when the system comes out of low-power.
 */
void
thermistor_wakeup (t_thermistor * thr)
{
  /*
   * init IOs
   */
  initialize_io_pin (thr->adc->sensor, TRISTATE);
  initialize_io_pin (get_gpio(IO_ALS_PIN), TRISTATE);

  adc_wake_up (thr->adc);

  adc_reset (thr->adc);
  delay10ms(5);
  ADC12CTL0 = ADC12REFON+ADC12REF2_5V+ADC12ON+ADC12MSC+ADC12SHT0_15; // Turn on ADC12, extend sampling time
  ADC12CTL0 |= ADC12ENC;                    // Enable conversions
  ADC12CTL0 |= ADC12SC;                   // Start convn - software trigger
  delay10ms(1);
  ADC12IE = 0x13;                           // Enable ADC12IFG.3
}

5 Replies

  • What does adc_reset() do?

    The hazard I see here is that with CONSEQ=3 and MSC=1, setting ENC=0 doesn't stop the ADC immediately [Ref User Guide (SLAU208Q) Sec 28.2.7.6]. If you set REFON=0 while the conversions are still running, I suspect you'll get incorrect readings. 

  • Hi 

    Have your been problem solved?

    Eason

    If the post helped solve your issue, please click on the  'This resolved my issue'  button.

  • In reply to Eason Zhou:

    No, but I haven't had time to look into this as I've been working on a different project.

  • In reply to Bruce McKenney47378:

    Sorry forgot to add this one. Good point about stopping the conversion. I'm onto another project at the moment, but will try it out and see if it helps.


    /** * adc_reset */ void adc_reset (t_adc * adc) { ENTER_CRITICAL (); TA1CCTL1 = 0; // clear capture config TA1CTL = 0; // turn off Timer A /* * disable all interrupts (clear flags too) */ TA1CCTL1 &= ~CCIE; /* disable capture interrupt */ TA1CTL &= ~TAIE; /* disable timer interrupt */ TA1CTL &= ~TAIFG; /* clear interrupt flag */ TA1CCTL1 &= ~CCIFG; /* clear interrupt capture flag */ /* * reset ADC state-machine */ adc->status = SAMPLE_UNDEF; adc->state = ADC_IDLE; assert (!(TA1CTL & MC__UP)); EXIT_CRITICAL (); }

  • In reply to Tim O'Hara:

    OK, good luck with you.

    Eason

    If the post helped solve your issue, please click on the  'This resolved my issue'  button.

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.