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.

Updating Timer Register on MSP430F5529

Other Parts Discussed in Thread: MSP430F5529

Hello Everyone,

I am currently having issues with updating the timer capture/compare register for timer A1 on an MSP430F5529 Launchpad.  I need to constantly update the value of this register to adjust the output frequency of a digital signal in accordance with an analog input.  My algorithm works for updating the frequency according to the input signal, and when I use a constant value for the capture/compare register it works fine.  However, my issue arises when I repeatedly refresh the capture/compare register.  Every now and then (not periodic) there are 'missing' pulses, or extra-long pulses on the oscilloscope.  I have attempted stopping the timer by using TA1CTL = MC_0, then writing the new value for the frequency to the capture/compare register, and then restarting the timer with TA1CTL = MC_1 but when I do this I don't get any output whatsoever. 

I have heard of a way of using timer B to synchronize how it updates the frequency, but I am unsure of how to do this.  Could anyone lend me an example of this?  Or suggest any other remedies to this rather irksome problem?  I'm so close to solving this!  Here is the snippet of my code that deals with setting up timer A, updating it's register value, and then the interrupt it uses to toggle the digital output:

//***************** BEGIN TIMER INTERRUPT SETUP *****************\\


TA1CCTL0 = CCIE;                  //enable timerA1 interrupts
TA1CCR0 = 10;                         //set value for timerA1 to count up to
TA1CTL = TASSEL_1 + MC_1 + TACLR + ID_0; //use SMCLK for timerA1, up mode, clear TA, /2
__bis_SR_register(GIE); //enable maskable interrupts


//***************** END INTERRUPT TIMER SETUP *******************************\\

Math_Sub_Routine(){

//A bunch of math also goes on in this subroutine, but not related to the timer, relates to finding the Timer_Register_Value, works fine.

Timer_Register_Value = Timer_Calib / Foot_Pulse_Freq;
//TA1CTL = MC_0;                                                                         //this was my attempt at stopping the timer
TA1CCR0 = Timer_Register_Value;
//TA1CTL = MC_1;                                                                        //and restarting after the  value had been written.

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//Timer1 Interrupt used to output digital signal

#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void)
{

if(Foot_Pulse_Output_Enable == 1){
P2OUT ^= BIT0;                                      //toggles GPIO P2.2
}

}


// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Thanks to everyone who replies in advance, you have all been helpful in the past.

Thanks!

Thomas

  • As an update, I have swapped over the Timer A interrupt to a Timer B interrupt with the same sort of initialization and configuration, getting the same results.  I'm still not sure how to perfectly implement the Timer B function that allows it to properly reset the period, but here's the new snippet of code for reference.  If anyone knows how to utilize Timer B to avoid missed pulses/long pulses, please let me know!

    //***************** BEGIN TIMER B INTERRUPT SETUP *****************\\


    TBCCTL0 = CCIE; // TBCCR0 interrupt enabled
    TBCCR0 = 1000; //Capture/Compare register value
    TBCTL = TBSSEL_1 + MC_1 + TBCLR; // ACLK, upmode, clear TBR

    __bis_SR_register(GIE); //enable maskable interrupts


    Timer_Calib = Timer_Calib_Freq*Timer_Calib_Reg_Value; //Value used for calibrating foot pulse to Timer A


    //***************** END INTERRUPT TIMER SETUP *******************************\\

    Math_Sub_Routine(){

    //blah blah, non-related stuff.

    Timer_Register_Value = Timer_Calib / Foot_Pulse_Freq;
    TBCCR0 = Timer_Register_Value;

    }

    // Timer B0 interrupt service routine
    #pragma vector=TIMERB0_VECTOR
    __interrupt void TIMERB0_ISR (void)
    {
    P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
    P2OUT ^= BIT0;
    }

    Again, thank you in advance for looking at my issue and trying to help.

    -Thomas

  • Hello,

    You could try with this:

    If you are using up mode, clear the TXR register each time you refresh the compare register.

    If you are using continuous mode, refresh the timer like this "TXCCRY += newTimingPeriod;"

  • Alrighty,

    So I've come to a solution about this issue.  Apparently it is not a great idea to update the frequency of the timer  (A or B) in up-mode.  This can cause the timer to have extra-long pulses if the new period is smaller than the old period.  I fixed the issue by running the timer in continuous mode and then writing the new period to a temporary variable and then updating the timer comparison register with the temporary variable.  A simple demonstration of this is code is shown below, resulting in a full period for 2 different frequencies, without any issues:

    #include <msp430.h>

    /*
    * main.c
    */
    int main(void) {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P1DIR |= 0x01; // Set P1.0 to output direction
    P2DIR |= BIT0;

    TBCCTL0 = CCIE; // TBCCR0 interrupt enabled
    TBCCR0 = 10000;
    TBCTL = TBSSEL_1 + MC_2 + TBCLR; // ACLK, contmode, TBR counts to 0, clear TBR


    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
    __no_operation(); // For debugger
    }

    // Timer B0 interrupt service routine
    #pragma vector=TIMERB0_VECTOR
    __interrupt void TIMERB0_ISR (void)
    {
    static unsigned int k = 0;
    static unsigned int tempccr0 = 10000;


    P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR
    P2OUT ^= BIT0;  //Digital output signal on P2.0
    if(k==2){
    tempccr0 += 20000;
    k++;
    }
    else if(k==3){
    tempccr0 += 20000;
    k = 0;
    }
    else{
    tempccr0 += 50000;
    k++;
    }
    TBCCR0 = tempccr0;
    }

    Maybe this will help anyone in the future who ran into my problem.

    -Thomas

  • Thomas O'Connor said:
     I fixed the issue by running the timer in continuous mode and then writing the new period to a temporary variable and then updating the timer comparison register with the temporary variable.

    That's indeed an alternative way. It also allows different PWM frequencies and duty cycles on the same timer module. However, each update requires a software interrupt that must be handled before the new destination is reached.

    Thomas O'Connor said:
    Apparently it is not a great idea to update the frequency of the timer  (A or B) in up-mode.  This can cause the timer to have extra-long pulses if the new period is smaller than the old period.

    Actually, the TimerB is designed to circumvent this problem by latching writes to the CCR registers and synchronizing the update to the next timer overflow. I don't know why it didn't work for you.

    But I have an idea. Just guessing, based on your observations. In your code you do

    TBCCTL0 = CCIE + CLLD_1; // TBCCR0 interrupt enabled
    TBCCR0 = 50000;
    TBCTL = TBSSEL_1 + MC_1 + TBCLR; // ACLK, upmode, TBR counts to 0, clear TBR

    So on power-up, TBCCR0 is zero. You program the CCR0 to update CCL0 on timer overflow. Then you write 50000 to CCR0. Now no overflow has happened yet, so the 50000 doesn't make it into CCL0. When you start the timer, it stays on 0 (counts form 0 to 0).
    It is possible that in this situation, the update will never happen.

    So set CCLD_0, write the inital value to CCR0, then set CCLD_1.

    Usually, you use CCLD_1 on CCR1 or CCR2, and leave CCR0 constant, once the PWM frequency has been set.

    The combination of CCLD_1 on CCR0 with timer in up or up/down mode will probably not work.

**Attention** This is a public forum