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.

MSP430F5529 Timer Setup for Digital Output Signal

Other Parts Discussed in Thread: MSP430F5529

Hello!

I am a little new to the MSP430 family and I thought this community was pretty helpful so far, so here's my question!  I am using an MSP430F5529 Launchpad for this project.

My project deals with taking in an analog velocity signal (0-3.3 V) and creating a pulse for every foot that was traveled according to the velocity.  Right now, I need the digital output pulse to have a maximum toggle frequency of at least 50 kHz, higher is fine.  I am trying to set up a timer-based ISR which calls at a much higher frequency by having the timer based on the SMCLK which in turn should be controlled by the DCO, which I wanted to set to about 8MHz.  So far, I have been unable to call the ISR faster than the normal ~32 kHz frequency which leads me to believe that configuring the timer for a higher frequency was not successful.  This is what I have attempted through browsing the sample codes available on this topic:

/*THE NEXT SECTION SETS DCO TO ~8MHz, CONTROLS THE SMCLK*/


  UCSCTL3 = SELREF_2;                       // Set DCO FLL reference = REFO
  UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
  UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx

  // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
  do
  {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
                                                                 // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG;                      // Clear fault flags
  }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

  __bis_SR_register(SCG0);                  // Disable the FLL control loop
  UCSCTL1 = DCORSEL_5;                      // Select DCO range 16MHz operation
  UCSCTL2 |= 249;                           // Set DCO Multiplier for 8MHz
                                                            // (N + 1) * FLLRef = Fdco
                                                            // (249 + 1) * 32768 = 8MHz
  __bic_SR_register(SCG0);                  // Enable the FLL control loop

  // Worst-case settling time for the DCO when the DCO range bits have been
  // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
  // UG for optimization.
  // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
  __delay_cycles(250000);


  //Timer Setup

  TA1CCTL0 = CCIE;                                  // CCR0 interrupt enabled
  TA1CTL = TASSEL_2 + MC_2 + TACLR + ID_3;              // SMCLK, continuous, clear TAR, /8

// Timer1 A0 interrupt service routine
#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void)
{
    P4OUT ^= BIT7;

}

I have the SMCLK divided by 8 solely so I can tell that the LED on P4.7 is toggling at a slower frequency or higher frequency based on if I configured the clock to work or not.  Eventually, I want the ISR to be called at least at 50 kHz or higher, but I can't seem to configure the clocks correctly.  Any help/advice you can lend me will be greatly appreciated!


Thanks,

Thomas

  • I never use DCO, because on all MSP430F5xx boards have XT2 that is used as MCLK. There is also XT2 on MSP430F5529 LP.

    If you just need output signal with adjustable frequency, it can be used timer output mode (OUTMOD_X) that will toggle output pins directly without any ISR function.

    //*******************************************************************************
    //  MSP430F552x Demo - Timer0_A5, PWM TA1.1-2, Up Mode, DCO SMCLK
    //
    //  Description: This program generates two PWM outputs on P1.2,P1.3 using
    //  Timer1_A configured for up mode. The value in CCR0, 512-1, defines the PWM
    //  period and the values in CCR1 and CCR2 the PWM duty cycles. Using ~1.045MHz
    //  SMCLK as TACLK, the timer period is ~500us with a 75% duty cycle on P1.2
    //  and 25% on P1.3.
    //  ACLK = n/a, SMCLK = MCLK = TACLK = default DCO ~1.045MHz.
    //
    //                MSP430F552x
    //            -------------------
    //        /|\|                   |
    //         | |                   |
    //         --|RST                |
    //           |                   |
    //           |         P1.2/TA0.1|--> CCR1 - 75% PWM
    //           |         P1.3/TA0.2|--> CCR2 - 25% PWM
    //
    //   Bhargavi Nisarga
    //   Texas Instruments Inc.
    //   April 2009
    //   Built with CCSv4 and IAR Embedded Workbench Version: 4.21
    //******************************************************************************

    #include <msp430f5529.h>

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1DIR |= BIT2+BIT3;                       // P1.2 and P1.3 output
      P1SEL |= BIT2+BIT3;                       // P1.2 and P1.3 options select
      TA0CCR0 = 512-1;                          // PWM Period
      TA0CCTL1 = OUTMOD_7;                      // CCR1 reset/set
      TA0CCR1 = 384;                            // CCR1 PWM duty cycle
      TA0CCTL2 = OUTMOD_7;                      // CCR2 reset/set
      TA0CCR2 = 128;                            // CCR2 PWM duty cycle
      TA0CTL = TASSEL_2 + MC_1 + TACLR;         // SMCLK, up mode, clear TAR

      __bis_SR_register(LPM0_bits);             // Enter LPM0
      __no_operation();                         // For debugger
    }

  • Try this first. If the LED blinks about once per second. If that works, add your code to speed up the clock to 16 MHz.

    #include "msp430f5529.h"

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD; /* Good dog, no barking */
     
      P4DIR |= BIT7; /* Digital out to a LED */

      TA1CCTL0 = CCIE;
      TA1CTL = TASSEL_2 + MC_2 + TACLR + ID_3;
     
      __bis_SR_register(GIE); /* Enable maskable interrupts */

      while(1) { /* CPU does nothing and thus no harm */ }
    }

    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void TIMER1_A0_ISR(void)
    {
        P4OUT ^= BIT7;
    }

  • Thanks for your reply!

    I've been fiddling around with your suggestion for a while now, but I'm having trouble determining how exactly the number that gets written to TA0CCRx relates to the period of the PWM signal.  Is there an equation to easily determine this?  It will become important later when I'm trying to change the frequency of the signal, rather than the duty cycle.

    -Thomas

  • Thomas O'Connor said:

    but I'm having trouble determining how exactly the number that gets written to TA0CCRx relates to the period of the PWM signal.  Is there an equation to easily determine this?  It will become important later when I'm trying to change the frequency of the signal, rather than the duty cycle.

    Everything is explained in Timer section of slau208 MSP430x5xx and MSP430x6xx Family User's Guide. Frequency and duty cycle also can be changed on the fly.

  • I've figured out how to update the frequency and duty cycle of the PWM just fine, but when I check the output on the oscilloscope, there seem to be missing pulses every now and then.  When I consistently change the frequency of the PWM between two values, the missing pulses occur uniformly.  Is there a way to smoothly update the frequency of the PWM without it missing pulses?  I've read the timers section of the user's guide several times but I still don't understand why updating the period causes missed/overlong pulses.  Any thoughts?

    Thanks again for the advice,

    -Thomas

  • Thomas O'Connor said:

    Is there a way to smoothly update the frequency of the PWM without it missing pulses?  I've read the timers section of the user's guide several times but I still don't understand why updating the period causes missed/overlong pulses.  Any thoughts?

    Stop the timer when you need to make update (PWM / freq), and keep on output pin needed logic state (POUT / PSEL). When update is done, start timer, and again enable out in right moment (PSEL). Analyze output and adjust code until you reach the target. MSP430F5529 is fast enough to work with 1 MHz output (based on timer) without any missing pulses.

  • I looked at section 17.2.2 Starting the Timer in the user's guide and found out how to stop/restart the timer by clearing and writing to TAxCCR0.  However, whenever I write a 0 to TAxCCR0 as it says, I get no output from the PWM.  Here is my implementation of the code:

    Where SampleConversionFlag = says when the ADC is done taking/averaging 8 samples.

    CLVAvg = the average value of the signal from the ADC.

    CLVfreq = the necessary conversion I need to do in order to convert the ADC signal to hertz.

    CLVconversion = the conversion from hertz to the necessary PWM period to be written to the TAxCCR0 register.

    while(1) {
    P2OUT ^= BIT0;
    if(SampleConversionFlag == 1){
    P4OUT ^= BIT7;
    CLVfreq = CLVAvg*44.44444444*0.000805664; //44.44 converts Volts to pulses/sec; other term converts 3.3V/4096 (ADC resolution)
    P1SEL |= BIT2+BIT3; // P1.2 and P1.3 options select
    CLVconversion = 1/(CLVfreq/512/64.1);

    TA0CCR0 = 0;
    P1OUT &= BIT2;
    TA0CCR0 = CLVconversion-1;          // PWM Period
    TA0CCTL1 = OUTMOD_7;                  // CCR1 reset/set
    TA0CCR1 = CLVconversion*0.5;       // CCR1 PWM duty cycle (50%) for output pin P1.2
    }

    }

    I don't get an output signal when the TA0CCR0 = 0; line is there.  When I have the P1OUT &= BIT2; portion in without the TA0CCR0 = 0; line, the code works as before where certain pulses will randomly go missing, resulting in a "long" pulse.  Any ideas on how to fix this issue? Or should I approach the problem in a different manner?

    Thanks for everything,

    -Thomas

  • Thomas O'Connor said:
    I don't get an output signal when the TA0CCR0 = 0; line is there.

    While the users guide says so, it doesn't really stop the timer. I just makes the timer count from 0 to 0 (in up or up/down mode) by limiting the count range to 0. It is like shorting a battery to switch the power off.

    To really stop the timer (and save some nA), clear the MCx bits in TA0CTL to set the timer in stop mode.

    Thomas O'Connor said:
    When I have the P1OUT &= BIT2; portion in without the TA0CCR0 = 0; line, the code works as before where certain pulses will randomly go missing, resulting in a "long" pulse.

    This happens because you change the period and duty cycle unsynchronized to the timer count. If you change CCR0 or CR1 to a value that is smaller than the current timer count, the timer will do a complete cycle before it comes to the new trigger point and perform the output change.

    TimerB provides a sync feature where the register changes take effect next time the timer counts to 0. TimerA doesn't have this, so you either wait until the timer overflows before you apply the changes (still risky when CCR1 is set to a value close to 0), or you stop and reset the timer before you change the registers and then start the timer again.

**Attention** This is a public forum