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.

ADC10 interrupt shutting off after one time through

Other Parts Discussed in Thread: MSP430G2553

I am trying to sample two channels and store the result in an array. So far I get through one successful conversion, trigger the interrupt, and then for whatever reason the ADC seems shut off and will not resume. I am using the G2553 controller. I apologize for the terribly formatted code.

I thought I had everything correctly configured and understood the sequence of conversion flow chart, but the debugger disagrees. 

How can I make the ADC convert a channel, interrupting to store a conversion when ADC10MEM receives a result, and then move onto the next channel?

#include <msp430g2553.h>

/*
* main.c
*/
void ConfigClock(); // declaring config function for uC CLK speeds
void ConfigADC(); // declaring config function for ADC10
void ConfigPorts(); // declaring config function for ADC10 input ports
volatile unsigned long CH0_Data[32]; // 32 ADC values stored here from PA1.0. TODO make dynamic
volatile unsigned long CH1_Data; // 32 ADC values stored here from PA1.1. TODO make dynamic
//volatile unsigned int count = 0; // counter for sensorData
unsigned long sampleCount = 0; // keeps track of how many times the ADC samples

int main(void) {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
ConfigClock();
ConfigADC();
ConfigPorts();
_BIS_SR(GIE); // enable interrupts
ADC10CTL0 |= ADC10IE; // ADC10 interrupt enabled
ADC10CTL0 |= ENC + ADC10SC;


while(1){


__bis_SR_register(CPUOFF + GIE); // will resume upon interrupt
ADC10CTL0 |= ADC10ON; // make sure ADC is on
ADC10CTL0 |= ENC + ADC10SC + ADC10IE; // enable, start conversion, enable interrupts

}
return 0;
}

/*
* Configures ports for their use by the ADc
*
*/
void ConfigPorts() {
P1DIR = 0x0000; // all pins on P1 are inputs
}
/*
* Configures ADC for dual channel sequencing and storage
*/
void ConfigADC() {
ADC10AE0 |= BIT0 + BIT1; // PA1.0 and PA1.1 are selected as channels for the ADC
ADC10CTL1 |= CONSEQ_3; // Control register set to convert sequence of channels repeatedly
ADC10CTL1 |= ADC10DIV_7; // prescale divider is now /8
ADC10CTL1 |= INCH_1; // input sequence is PA1.1, PA1.0
ADC10CTL1 |= ADC10SSEL_1; // select ACLK as source
ADC10CTL0 |= ADC10ON; // finally, turn the damn thing on.
}
/*
* Configures clock to operate at lower frequency for less power consumption
*/
void ConfigClock() {
// configure clock
BCSCTL1 |= CALBC1_1MHZ; // calibrate CLK for 1 MHz
DCOCTL |= CALDCO_1MHZ; // calibrate DCO for 1 MHZ
BCSCTL3 |= LFXT1S_2; // Enable VLO, LFXT1 = VLO
BCSCTL1 |= DIVA_3; // ACLK/8
// ACLK is sourced from VLO by default. ~12 kHz default
IFG1 &= ~OFIFG; // disable oscillator fault interrupt flag
BCSCTL2 |= DIVM_3; // set divider for MCLK to DCO/8
BCSCTL2 |= DIVS_3; // set divider for SCLK to DCO/8
BCSCTL2 |= SELM_0; // MCLK & SCLK are running off DCO.

}
/*
* The ADC interrupt is triggered once a conversion is complete and placed into ADC10MEM
*/
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void) {
CH0_Data[sampleCount++] = ADC10MEM;
__bic_SR_register_on_exit(CPUOFF);
}

  • Nolan Holmes said:
    _BIS_SR(GIE); // enable interrupts

    If using LPMs, it is a good idea to keep GIE clear until you're actually entering LPM. In your case it isn't a problem, but imagine that the interrupt that is supposed to wake you, happens before you enter LPM. Then you will enter LPM and no interrupt will ever come to wake you as it already happened. This also applies to after the waking interrupt.
    Just a hint.

    Nolan Holmes said:
    __bis_SR_register(CPUOFF + GIE); // will resume upon interrupt
    ADC10CTL0 |= ADC10ON; // make sure ADC is on
    ADC10CTL0 |= ENC + ADC10SC + ADC10IE; // enable, start conversion, enable interrupts

    ADC10ON can only be modified when ENC is clear. Also, neither ADC10ON, nor ENC or ADC10IE will auto-clear oafter you set them.
    All you need to do to trigger the next converison is setting ADC10SC. A tleast in theory.

    But what about your clock?

    You set ACLK as VLOCKL/8. Which means ~1.5kHz ACLK. Then you tell the ADC to use ACLK/8 as source. So you have effectively an ADC10CLK of ~200Hz. Which is by a factor of at least 2000 slower than the required clock speed for a proper conversion (450kHz for specified performance). With 5ms per conversion step, the charge in the conversion capacitor will vaporize long before it can be measured.

    It shouldn't affect the state machine, though, so conversions should continue, even if giving bogus results.

    Now some people have reported that they need to set ADC10SC twice for all but the first conversion. Why htis isn't officially filed as erratum (or even officially confirmed), it would be worth a try.

  • Thank You! It was indeed the ADC10SC and ENC bits that needed to be toggled to repeat another conversion.

    As for your concern about the clock speed, that is also very much appreciated. Currently my objective is to start at the lowest frequency possible and work my way up until the accuracy in passable, but now that saved me a few trial and error runs because I will start the clock around 400 Hz.

  • Nolan Holmes said:
    I will start the clock around 400 Hz.

    kHz, I hope :)

  • Jens-Michael Gross said:
    :)

    I see that you're back from your Hollywood debut ;-) How was the red carpet?

  • Brian Boorman said:
    I see that you're back from your Hollywood debut ;-) How was the red carpet?

    It's actually the second video, and both, the other one and this interview, were recorded some months ago, when I visited Texas.
    I wanted to post an article about my visit (and the 3rd award I got), but my girlfriend still hasn't taken the pictures of the "trophy" (while she can take 1000 pictures a day when at the zoo or other locations - how different the same thing can be when it is 'work' instead of 'fun'), so it didn't happen yet.

**Attention** This is a public forum