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.

MSP430F2012: Timer goes off every second.....A/D goes off every 5 seconds???

Part Number: MSP430F2012

Can someone shed some light on something stupid I must be doing....Below is code...pwrDetect = 1...I am using a scope to monitor the LEDs and the A/D input (from where I can see a dip in the voltage on this pin when I am sampling).  In any event in the TIMERA0_VECTOR if I remove the ...LPM3 line I seem to see a sample every 5 seconds, if I have that line in there I get a sample every 2 seconds??  Can someone please tell me why I am not getting a sample every second.....I have the A/D clock at 1MHz with a /64 sampling period.  The timer runs off of VLO clock which after measuring it on a pin I set up the period for about 1 second.


#include <msp430f2012.h>
#include "LiPo.h"

volatile unsigned int ledSw = 0;
volatile unsigned int pwrDetect = 0;
unsigned int startup = 1;
volatile unsigned int *pBattVolt;

void main(void)
{
    struct PWM_F201x pwm;

    mcuWatchdogOff;
    mcu_clk_setup;
    configIO;

    AD_Config();
    pBattVolt = &ADC10MEM;

    pwm.Period = 11600; pwm.OnTime = 9400; pwm.mode = reset; pwm.cycle = up;
    pwm_config(&pwm);
    TACCTL0 |= CCIE;
    ADC10CTL0 |= ENC + ADC10SC;


    while (1){
        __bis_SR_register(LPM3_bits + GIE);
        //setting PWM to flash or not depending on switches thrown
        if (pwrDetect == 1) {  //pwr connected LEDs work off of timer
            P1OUT &= ~(BIT2 | BIT6); //LEDs off
            P1OUT |= BIT7; //MOSFETs on

            //based on analog voltage the P1SEL will choose which LED flashes off of timer
            //**************************
            if (*pBattVolt < RED_LIMIT){
                P1SEL = ((P1SEL & ~YELLOW) | RED);
            }
            else if (*pBattVolt > GREEN_LIMIT_CHG){
                P1SEL = ((P1SEL & ~YELLOW) | GREEN);
            }
            else{
               P1SEL |= YELLOW;
            }
            TACCTL1 = OUTMOD_3;
        }
        else{ //pwr not connected LEDs work off switch NOT timer
            P1OUT &= ~BIT7; //MOSFETs off
            if ((ledSw) == 1){ //led switch thrown
                P1SEL = 0;
                if (*pBattVolt < RED_LIMIT){
                    P1OUT &= ~YELLOW;
                    P1OUT |= RED;
                }
                else if (*pBattVolt > GREEN_LIMIT){
                    P1OUT &= ~YELLOW;
                    P1OUT |= GREEN;
                }
                else{
                    P1OUT |= YELLOW;
                }
                TACCTL1 = OUTMOD_1;
            }
            else if ((P1IN & BIT0) == 0){
                  P1OUT &= ~(BIT6 | BIT2);
                  P1SEL = 0;
            }
        }
    }
}

#pragma vector=TIMERA0_VECTOR
__interrupt void PWM_Output_Control(void)
{
    ADC10CTL0 |= ENC + REFON + ADC10ON + ADC10SC; //arm ADC for sample
//    __bic_SR_register_on_exit(LPM3_bits);  //wake up and run main!
}

#pragma vector=ADC10_VECTOR
__interrupt void BatteryVoltage(void)
{
  ADC10CTL0 &= ~(ENC + REFON + ADC10ON);    // disable ADC
  *pBattVolt = ADC10MEM;
  if (startup){
      P1IFG |= BIT5; //force interrupt to get pwr status
      P1IFG |= BIT0; //force interrupt to get LED switch
  }
  __bic_SR_register_on_exit(LPM3_bits);  //wake up and run main!
}

#pragma vector=PORT1_VECTOR
__interrupt void LED_Switch(void)
{
    if (P1IFG & BIT0){
        ledSw = P1IN & BIT0;
        P1IFG &= ~BIT0;
        P1IES ^= BIT0;
    }
    if (P1IFG & BIT5){
        pwrDetect = (P1IN & BIT5) >> 5;
        P1IFG &= ~BIT5;
        P1IES ^= BIT5;
    }
    startup = 0;
    __bic_SR_register_on_exit(LPM3_bits);  //wake up and run main!
}

Function definitions

void AD_Config(void)  //definition
{
    ADC10CTL0 = SREF_1 + REF2_5V + ADC10SHT_3 + REFON + ADC10IE + ADC10ON;
    ADC10CTL1 = INCH_1 + SHS_0 + ADC10DIV_0 + ADC10SSEL_2; //channel 1, clk (3.7MHz - 6.3MHz), divide clk by 8 to guarantee settling with HiZ input, TA1 source S/H
    ADC10AE0 = BIT1;
}

void pwm_config(struct PWM_F201x* p)  //definition
{
    TACCR0 = ( p -> Period );     //Period in Sec
    TACCR1 = ( p -> OnTime );     // On time in Sec
    if (p -> mode == normal)
        TACCTL1 |= OUTMOD_3;
    else if (p -> mode == invert)
        TACCTL1 |= OUTMOD_7;
    else if (p -> mode == reset)
        TACCTL1 |= OUTMOD_5;
    else
        TACCTL1 |= OUTMOD_3;

    if (p -> cycle == up)
        TACTL |= MC_1;
    else
        TACTL |= MC_2;

    TACTL |= TASSEL_1;
}


BCSCTL3 |= 0x20; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ;

thanks

 

  • Hi Steve,

    Steve Wenner said:
    In any event in the TIMERA0_VECTOR if I remove the ...LPM3 line I seem to see a sample every 5 seconds, if I have that line in there I get a sample every 2 seconds??

    With the LPM3 line there, you wake up the CPU and execute the code in the while(1) statement immediately after the Timer_A ISR. If pwrDetect = 1, then you change timer modes by modifying TACCTL1 from OUTMOD_5 (reset) to OUTMOD_3 (set/reset).

    Without it, you don't wake up and don't execute that code until later and stay in the same mode. Thus, it takes longer for the next interrupt to happen than the previous scenario.

    Also, I did want to point out the note at the top of page 358 in the MSP430x2xx Family User's Guide.

    It is recommended to stop the timer before modifying its operation (with exception of the interrupt enable, and interrupt flag) to avoid errant operating conditions. When the timer clock is asynchronous to the CPU clock, any read from TAR should occur while the timer is not operating or the results may be unpredictable. Alternatively, the timer may be read multiple times while operating, and a majority vote taken in software to determine the correct reading. Any write to TAR will take effect immediately.

    Regards,

    James

  • Hi James...

    Not sure I understand what you mean??....I do an ENC (ADC10SC) conversion just before hitting the while loop....After processing AD I wake up THEN the timer interrupt would go off and re-arm the AD converter....The timer is running on VLO (a very slow clock)...The A/D is clocked with 1MHz / 64 for sample+ 13 * 1Mhz for conversion.....I have placed breakpoints and OUTMODE_3 is set correctly and doesn't change (other than from the start of the code and OUTMODE_5)....

    I think the issue is in my Timer IRQ....Enalbing the Ref and AD in the same command as ENC and ADC10SC.  I'm basically using up 30us of my sampling time while the reference is unstable

    i really don't understand how I move to 5 seconds by NOT waking up after the TIMER_A0 IRQ?  I am in MC_1 (Count up mode and I roll each time)

    Thanks

    STeve

    On further notice....when I run the following line of code:

        ADC10CTL0 |= (ENC + ADC10SC);
    

    BEFORE the while loop, I automatically get a conversion in ADCMEM WITHOUT jumping into my ADC ISR?  How is this possible what is going on?  

  • The ADC is setup to use MCLK but in LPM3 that doesn't run. Which means that the ADC is only getting clocks while the ISR is running.

    Some of the MSP430s have a clock request system that will keep clocks running regardless of low power mode if a peripheral is using it. Perhaps you should be using the ADC10OSC.

  • David...
    Yes I see that in the datasheet however the following coarse code is working....Can you explain this? Notice...I am in LPM3 and using MCLK for the converter....I have
    a large impedance and need a settling time of 80us so the ADC10OSC (5Mhz) i don't believe will cut it (best is /64 divider)....

    #include <msp430f2012.h> #include "LiPo.h" volatile unsigned int *pBattVolt; int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT pBattVolt = &ADC10MEM; BCSCTL3 |= 0x20; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1DIR |= BIT6; //p1.6 to TA1 P1SEL |= BIT6; TACCR0 = 500; TACCR1 = 400; TACCTL1 = OUTMOD_3; TACTL |= TASSEL_1 | MC_1; TACCTL0 |= CCIE; TACCTL1 |= CCIE; ADC10CTL0 = SREF_1 + REF2_5V + ADC10SHT_3 + REFON + ADC10IE + ADC10ON; ADC10CTL1 = INCH_1 + SHS_0 + ADC10DIV_0 + ADC10SSEL_2; ADC10AE0 |= 0x02; while(1) { __bis_SR_register(LPM3_bits + GIE); if (*pBattVolt > 793) TACCTL1 |= (TACCTL1 & ~0x00E0) | OUTMOD_3; else TACCTL1 |= (TACCTL1 & ~0x00E0) | OUTMOD_5; } } #pragma vector=TIMERA0_VECTOR __interrupt void TakeA_D(void) { ADC10CTL0 |= ENC + ADC10SC; } #pragma vector=TIMERA1_VECTOR __interrupt void EnableA_D(void) { switch (TAIV) { case 2: ADC10CTL0 |= REFON + ADC10ON; break; case 4: break; case 10: break; default: break; } } #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR(void) { __bic_SR_register_on_exit(LPM3_bits); }

    .....a follow up.....I'm not completely sure here but the above worked.
    I've since revisited what you suggested (thank you btw) and divided down by 5 and it is working ....I'm also able to disable the reference and ADC within the ADC ISR which is great news (with MCLK and before I
    would get ghosting and the ISR wasn't always getting hit)! My only concern here may be
    stability over temperature but I guess I can live with that.

  • 6.3MHz/8 and then sample for 64 clocks should exceed 80us. Worst case.