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.

Timer Control via ADC10

Other Parts Discussed in Thread: MSP430G2231

Hello all,

I've been trying to blink onboard LEDs using timerA upmode, but I want to control the TACCR0 value using ADC. I setup the following circuit and connected it to P1.1. What I want to do is to read the value from ADC10MEM and set TACCR0 accordingly.

I debugged the code, ADC10 is working. CCR0 value is set correctly. But whenever I run the code, It starts to blink aperiodically, then after a few seconds blinking turns to normal. However, turning the potentiometer changes nothing, LED just blinks in a constant speed.

/*
* Controlling timer intervals using adc, and blink LED1 accordingly
*/
#include <msp430g2231.h>

// Timer Config
void configure_timer(x){
unsigned int i;
TACCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 0; // CCR0 initalized

//x -> ADC10MEM

//since ADC10MEM <= 1024 I multiplied it by 60 to get visible blinking

for(i=0;i<60;i++) //For loop addition to avoid multipication
CCR0 += x;

TACTL = TASSEL_2 + MC_1 + ID_1 + TAIE; // SMCLK, upmode, Clk/2, Interrupt enabled
}

int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
ADC10CTL1 = INCH_1; // input A1
ADC10AE0 |= 0x02; // PA.1 ADC option select
P1DIR |= 0x01; // Set P1.0 to output direction

while(1)
{
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
}
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
__bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
TACTL = MC_0; // Close timer to configuration
configure_timer(ADC10MEM);

}

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
P1OUT ^= 0x01; // Toggle P1.0
}

Any help on the problem is appreciated.

Thanks a lot in advance.

Günay

  • Hello again,

    I fixed some parts but it does not affect the result. Instead of editing the previous post, I thought it's better to explain what I've changed in a seperate post.

    /*
    * Controlling timer intervals using adc, and blink LED1 accordingly
    */
    #include <msp430g2231.h>

    // Timer Config
    void configure_timer(x){
    unsigned int i;
    TACCTL0 |= CCIE; // CCR0 interrupt enabled
    CCR0 = 0; // CCR0 initalized

    //x -> ADC10MEM

    //since ADC10MEM <= 1024 I multiplied it by 60 to get visible blinking

    for(i=0;i<64;i++) //For loop addition to avoid multipication
    CCR0 += x;

    TACTL = TASSEL_2 + MC_1 + ID_1;  // SMCLK, upmode, Clk/2, Interrupt enabled (+ TAIE; deleted)
    }

    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    ADC10CTL0 |= ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled
    ADC10CTL1 = INCH_1; // input A1
    ADC10AE0 |= 0x02; // PA.1 ADC option select
    P1DIR |= 0x01; // Set P1.0 to output direction

    while(1)
    {
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
    }
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
    TACTL &= MC_0; // Close timer to configuration 
    configure_timer(ADC10MEM);

    }

    // Timer A0 interrupt service routine
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
    P1OUT ^= 0x01; // Toggle P1.0
    }


    I marked all my changes with red. Changing the count is not important but I thought I found a crucial mistake in the TACLT &= MC_0 line, and removing TAIE bit. However no improvements in the result :/ 

    The thing happening is very few slow blinking then continious constant periodic fast blinking despite any change in the potentiometer. Only initial pattern is changing with the potentiometer but there is no logical pattern related that I could found.

    Thanks a lot again,

    Günay

  • Now you don't know - it's timer or ADC or both that does not work. So - debug them separately.

    Write test code for timer alone, by compiling with various constants passed to  configure_timer() function.

    When you are sure your timer code is OK - then check ADC.

  • Thank you for your reply,

    I've just tested timer part with different possible ADC10MEM values, it seem OK. Also checked the ADC part it is OK too. It was not unexpected since the seperate codes are as beginner as I am :) 

    When I debug the complete code it reads different values from ADC channel and writes to the TACCR0 correctly, as I observed from CCS debug. It seem perfect but I cannot understand what could be a problem when running the code.

    So, I'm open to new ideas (:

    Thanks again.

  • When you reconfigure timer - you reset it. So it's cycle starts from beginning, Right? Now answer to yourself - how often do you update timer CCR register? How fast your ADC is generating new ADC readings? Understood where's problem and why you are getting rapid flashing?

  • OK I've got the problem and to fix it it's the best solution I could found:

    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
    TACTL &= 0xFFCF; // Close timer to configuration
    if(ADC10BUSY == 0)                          //This line will stop timer to be configured continuously 
    configure_timer(ADC10MEM);
    }

    But the problem is, now it never configures the timer. It just skips the if statement. Then the question is how can I make the ADC wait after a conversion? Since the external circuit is analog there is noise and some instability I think and the input channel of ADC continuously changing. Therefore ADC is always busy. Is this project idea impossible or am I missing something? 

    Maybe I can stop put a delay cycle after ADC conversion? I'll try that one an update the post then. I think writing here brings inspiration somehow :)

  • Hi,

    Take a look at IImars' post, it seems all your problems starts in your timing. I do not know if you have experience in embedded systems, but one of the main problems is the timing. It seems you are launching correctly the timer, but you are triggering an ADC conversion so quickly (while(1)) that the timer does not have time to reach the value before the timer is reconfigured again on ADC ISR.

    About your question

    Gunay Turan said:
    if(ADC10BUSY == 0)                          //This line will stop timer to be configured continuously 
    configure_timer(ADC10MEM);

    ADC10BUSY is not the state of ADC operation, is only a mnemonic whose value is 0x0001, that is to say, you are writing a condition like if(0x0001 == 0), it will never be true, for that you never enter in configure_timer function. So with this condition you are not checking the ADC state. If you really want to check the state of this bit, you would have to do something like if((ADC10CTL1 & ADC10BUSY)  == 0)

    About noise in your ADC input, you could modify the ADC input value hundred of  times, but if you do not launch a conversion, any interrupt occurs. And even the input varies during the reading, the ADC only get a one sample in a certain moment.

    On the other hand, it is not required (and according to IImars's post you will have to avoid it) the configuration of TACTL each time you launch it. Simply with this line on the main :TACTL = TASSEL_2  + ID_1;  will be sufficient. For start/stop the timer, you only will do :  TACTL |= MC_1;/ TACTL &= MC_0;

  • The last version of the code has this ISR:

    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
    ADC10CTL0 |= ~ENC;                              // Close ADC conversion
    TACTL &= 0xFFCF;                                    // Close timer to configuration
    configure_timer(ADC10MEM);                // Configure timer
    __delay_cycles(1000000);                      // Wait for the timer to work for a while
    ADC10CTL0 |= ENC;                                // Enable ADC conversion again
    }

    This ISR made some improvements but I don't have the performance as I expected before I started to this project.

    I wanted to get such quick response and easily recognizable speed change as in this video : http://www.youtube.com/watch?v=mjls228-sGA

    The result I got is a stop in the timer for a while (like 2 sec. or so) then blinkinking. But blinking does not continue because some interrupt occurs without touching the external circuit (due to noise I think, as I said above). 

  • Hi,

    I'm beginner on the embedded systems. This MSP430 Launchpad is my first study on the area. I followed some basic steps on the launchpadwiki, and now I'm trying to combine them. Thank you for your help.

    Is T da S said:

    Take a look at IImars' post, it seems all your problems starts in your timing. I do not know if you have experience in embedded systems, but one of the main problems is the timing. It seems you are launching correctly the timer, but you are triggering an ADC conversion so quickly (while(1)) that the timer does not have time to reach the value before the timer is reconfigured again on ADC ISR.

    About noise in your ADC input, you could modify the ADC input value hundred of  times, but if you do not launch a conversion, any interrupt occurs. And even the input varies during the reading, the ADC only get a one sample in a certain moment.

    I think my previous post covers that problem. But only thing I can do is put a time constraint on ADC. This reduces response time, and after the interval the instability problem pops up again. I can put a button control on ADC to sample maybe but it will destroy the elegance (:

    I understood the ADC10BUSY part. Thanks on that too.

    Last: I am postponing the timer configuration improvement you proposed because I tried it after you said but the project stopped working at all. I will give my effort on that later (: Overall working is the first priority for now.

  • Hi again,

    Maybe that works, but using a delay (and a big delay in particular) or any type of waiting inside of an ISR, you are breaking the basis of embedded programming.

    And as a tip, try to  launch the ADC reading with a higher cadence than the greatest timing possible. If you want to see the LED blinking with a cadence of 100 ms, launch an ADC reading each 1 second, or you will never see the change.

  • Thank you so much for your help and suggestions. 

    And special thanks to Ilmars becaude of the reasoning he gave :)

    This forum is very useful and I will contribute it as much as possible :)

    Best regards

**Attention** This is a public forum