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.

ADC10MEM reg giving zero value as adc output

Other Parts Discussed in Thread: MSP430G2553

Hi, I'm using msp-exp430g2 development kit and through this kit I'm doing 10bit ADC. I programmed the code and debugged it through CCS v6. The problem that I'm facing is that when I run the code and when I checked the ADC10MEM register I found out  that the value is coimg zero.I can't get it why is this happening so ? The analog input is actually heartbeat sound which I'm taking as input and is providing to the mcu. Since heartbeat sound is of low frequency signal so I preferred to use ACLK. I assigned the sampling rate as 100Hz.

I tried single stepping but all in vain. I couldn't exactly point out where the mistake is? Kindly please help me identify the mistake or any suggestion for my problem.

#include<msp430g2553.h>
void configure_adc(void);
void configure_timer(void);
int datain;
void main (void)
{

WDTCTL = WDTPW + WDTHOLD; // stop WDT
BCSCTL3 |= LFXT1S_2;      //ACLK set to operate in VLO mode i.e near 12khz since bcoz of low freq operation mode required
configure_adc();

while(1)
{
//__delay_cycles(1000); // Wait for ADC Ref to settle
ADC10CTL0 |= ENC + ADC10SC;            // Start Conversion
__bis_SR_register(CPUOFF + GIE);            // Low Power Mode 0 with interrupts enable
}
}

#pragma vector=TIMER0_A0_VECTOR

__interrupt void Timer0_A0 (void) {

// while (ADC10CTL1 & ADC10BUSY);          // check for ADC conversion is completed
  datain = ADC10MEM;
__bic_SR_register_on_exit(CPUOFF);          // Return to active mode
}
void configure_timer(void)
{
TA0CCTL0=CCIE;            // Enable Timer A0 interrupts, bit 4=1
TACCR0=119;                   // Count limit is set so that 100Hz frequency is obtained
TA0CTL=TASSEL_1 + MC_1;         // Timer A0 with ACLK, count UP
}
void configure_adc(void)
{
ADC10CTL0= SREF_0 + ADC10SHT_2 + ADC10ON + ADC10IE;    // VCC=3V 
ADC10CTL1= INCH_0 + SHS_2 + ADC10SSEL_0 + CONSEQ_2;   // SHS=2 bcoz timer A output unit 0, ADC10OSC as ADC10CLK source, single channel                                                                                                                                    repeated conv mode
ADC10AE0 |= BIT0;   //analog input enable P1.0
configure_timer();
}

Thanks.

  • You're enabling ADC10IE, but I don't see an ISR for it. I expect that your program is resetting repeatedly. This may or may not be the cause for ADC10MEM==0, but until you fix it you'll have trouble looking at anything else.

    Triggering the ADC from a timer is good, but you probably shouldn't be fetching ADC10MEM in the timer ISR; at that moment, the next conversion has already started, and may have already ended, so you may get the previous reading or the next reading.

    Recommendation: Don't remove ADC10IE, but rather define an ISR which does the fetching from ADC10MEM.
  • Two other things came to mind:
    1) I think you need to use OUTMOD_4 (toggle) in TA0CCTL0. At least that's what I do.
    2) If you're using the G2 Launchpad: Did you remove the jumper that connects P1.0 to LED1?
  • Yes I have removed the jumper that connects to LED1. I defined an ISR for adc something like that
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR (void)
    { datain = ADC10MEM;
    //__bic_SR_register_on_exit(CPUOFF); // Return to active mode }
    }
    and the rest of the code is same except few changes that you have mentioned.
    #pragma vector=TIMER0_A0_VECTOR

    __interrupt void Timer0_A0 (void) {
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
    }
    void configure_timer(void)
    {
    TA0CCTL0=OUTMOD_4 + CCIE; // Enable Timer A0 interrupts, bit 4=1
    TACCR0=119; // Count limit is set so that 100Hz frequency is obtained
    TA0CTL=TASSEL_1 + MC_1; // Timer A0 with ACLK, count UP
    }
    And now the code is working perfectly in a sense that I can observe adc values. But I have few questions why OUTMOD_4 needs to be added ?
    And how can I ensure that the sampling is done correctly?
  • You need to set OUTMOD so there will be an output signal (rising edge) on OUT0. In Figure 22-3, the output from the timer becomes SHI. OUTMOD_4 gives you that, though at a half-speed rate. I forgot to mention: you should double the timer rate (divide your current CCR0 setting by 2) to account for this.

    I recommend you do the wakeup (bic_..(CPUOFF)) in the ADC ISR rather than the timer. The way it is now might or might not work (race).
  • Should i remove the timer ISR then ?
    And by doubling the timer rate U mean something like this :

    TA0CCTL0=OUTMOD_4 + CCIE; // Enable Timer A0 interrupts, bit 4=1
    TA0CCR0=119; // Count limit is set so that 100Hz frequency is obtained
    TA0CCR1=60;
    TA0CTL=TASSEL_1 + MC_1;
  • You might as well remove the timer ISR (don't forget to remove the CCIE as well), unless you come up with something else to do with it.

    TA0CCR0=(120/2)-1; // 100Hz: 120 ticks for 2x toggles (one rising edge) with OUTMOD_4
    I'm assuming you know where the 120 came from (what's on ACLK?).
  • Well I don't know much timers. I set the ACLK in VLO mode that is ACLK must be operating at 12khz. And yes 120 is the count limit so that 12k/120 gives 100hz ( the desired sampling rate).
    Furthermore I wanted to know that how can I check that sampling is being done correctly? Right now I'm doing single stepping to check adc value at every instant .
  • Ah, I missed the VLOCLK setup. Keep in mind that VLOCLK can vary quite a bit (40% as I recall), but it doesn't change much short-term (minutes/hours). If it starts to cause you trouble, SMCLK (rather than ACLK) is also usually a good choice.

    For checking the timing: The simplest way is to toggle a GPIO pin in the ADC ISR, and watch/measure it on a scope or a logic analyzer.

    For checking the ADC data: There may be some debugger tricks to periodically fetch the sample value, but I don't know them. At the very least, you can set a breakpoint inside the ADC ISR, which would be less cumbersome than single-stepping.

    I usually use the UART to display ADC data. This wouldn't be trivial, but you should be able to "borrow" most of your code from one of the TI example programs.

    The Launchpad is limited to 9600bps, i.e. 960 bytes/sec. With an snprintf format like "%3x\r\n", that's 5 bytes per reading or 500 bytes/sec, which seems feasible. You'll probably want a serial Host program (e.g. PuTTY) that is capable of logging.

  • Oh, something else I forgot (it's been a while since I did this): In your ADC ISR, you'll want to add (after fetching ADC10MEM):
    ADC10CTL0 &= ~ENC;ADC10CTL0 |= ENC; // Toggle to re-enable the TA0 trigger

    In Figure 22-5 (SLAU144J) this moves you from the second bubble (INCH) to the third (Wait for trigger).
  • Thank you for such a detailed explanation. I have incorporated all the required changes stated above.
    One thing that I noticed during the program execution when I intentionally disconnected the analog input pin that was connected to my analog circuit , I still observed adc values on the screen although I thought it would give me completely zero during this time period?
  • When you disconnect an input pin, it "floats" -- it's effectively an antenna, picking up any energy near it.

    Try jumpering it to GND.

**Attention** This is a public forum