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.

MSP430 : 2 PWM Signals Generation With Fixed Delay

Other Parts Discussed in Thread: MSP430G2553

Hi TI Folks,

We would like to ask if MSP430 can do the following:

1. Generate the first PWM signal at around 70khz,50% duty cycle

2. Generate the second PWM signal which is the same frequency and duty cycle of the first PWM but with fixed delay of 25% of the period with respect to the first PWM.


It will be two continuous PWM pulse trains with 25% period shifted for the second PWM signal with respect to the first PWM pulse train.

Appreciate if you could advise how can the above can be achieved. Below is what we are thinking.

Can it be done if we start the PWM generation and a delay function together and after the delay function expired, we start the second PWM?

Regards,

Weiren

  • If the MSP430 you use has 2 or more Timers, you can do that without much problem. Using only 1 Timer to do so is not possible.
  • Hi Old_Cow_Yellow,

    Thanks for your comments. We think the same too. Now at least we know a Guru thinks the same too.

    Any input from TI's Engineers?

    Regards,
    Weiren
  • Not from a TI engineer, but this would be a possible implementation:

    You start one timer module which controls the 1st PWM and simultaneously set a value for a compare interrupt that fires exactly after 25% of your duty cycle. In the ISR you start the 2nd PWM sourced from another timer module and disable the CCIE interrupt capability again. This interrupt only needs to be executed once.

    #FreeSampleCode

    #include "msp430g2553.h"
    
    void main( void )
    {
      WDTCTL   = WDTPW | WDTHOLD;                // Stop watchdog timer
    
      BCSCTL1  = CALBC1_1MHZ;                    // Set range to 1MHz
      DCOCTL   = CALDCO_1MHZ;                    // Set DCO step and modulation to 1MHz
    
      P1SEL    = 0x40;                           // Enable timer function for P1.6 (TA0.1)
      P1DIR    = 0x40;                           // Set P1.6 (TA0.1) to output direction
    
      P2SEL    = 0x02;                           // Enable timer function for P2.1 (TA1.1)
      P2DIR    = 0x02;                           // Set P2.1 (TA1.1) to output direction
    
      TA0CCR0  = 10000;                          // Period for 1st PWM: 10ms @ 1MHz
      TA0CCR1  = 2000;                           // Duty cycle for 1st PWM: 2ms @ 1MHz
      TA0CCR2  = 2500;                           // 25% of duty cycle to start 2nd PWM
      TA0CCTL1 = OUTMOD_7;                       // TA0.1 reset/set mode
      TA0CCTL2 = CCIE;                           // Compare interrupt for 25% of elapsed duty cycle
      TA0CTL   = TASSEL_2 | ID_0 | MC_1 | TACLR; // 1st PWM: SMCLK, divider 1, up-mode, clear
    
      TA1CCR0  = 10000;                          // Period for 2nd PWM: 10ms @ 1MHz
      TA1CCR1  = 2000;                           // Duty cycle for 2nd PWM: 2ms @ 1MHz
      TA1CCTL1 = OUTMOD_7;                       // TA1.1 reset/set mode
    
      __bis_SR_register( GIE );                  // Enable interrupts
    
      while( 1 );
    }
    
    #pragma vector = TIMER0_A1_VECTOR            // Compare interrupt for 25% elapsed duty cycle
    __interrupt void TIMER0_A1_ISR( void )
    {
      TA1CTL   = TASSEL_2 | ID_0 | MC_1 | TACLR; // 2nd PWM: SMCLK, divider 1, up-mode, clear
      TA0CCTL2 = 0x00;                           // Clear compare interrupt - executed only once
    }

    In this example, the period of both PWMs is 10ms, the duty cycle is 2ms and the 2nd PWM starts 2.5ms (25%) after the first one:

    All done on the MSP-EXP430G2 LaunchPad with a MSP430G2553 microcontroller.

    If your program has nothing else to do, then you can enter a low power mode, of course.

    Dennis

  • Hi Dennis,

    Thanks a lot for your codes. This helps a lot.

    Regards,
    Weiren
  • You now have to change the CCR values for your 70kHz and the 50% duty cycle. 70kHz will result in non integer values for CCR0 and CCR1. So this might introduce some errors, but you did not say how precise your PWMs have to be. And for 70kHz you probably should raise the DCO speed as well, otherwise CCR0 would be only 14(.286) @ 1MHz SMCLK and CCR1 even only 7. With a higher running clock, the lost fractional portion of the value introduces less error.

  • Hi Dennis,

    Thanks for your additional comments.
    Details wise, my customer will test out and see if it is within their specification. We are looking at how feasible this approach is at this moment.

    Regards,
    Weiren
  • Of course the inaccuracy of the clock source also generates an error. But this is an absolute deviation that is equal for both PWMs. If one is off by a specific time compared to a fixed 70kHz reference, then the other has the same deviation because both are sourced from the same clock source. And if one drifts, then the other does as well. The duty cycle is not affected by any drifts if you look at it as a percentage of the period. It changes according to the period drift, but 50% of the error free period will stay 50% of the period with error.

  • Dennis,

    I modified your code as follows. It might work too, but I do not have a scope. (Edit: a small correction "-1" is added to Lines 16 and 20.)

    #include "msp430g2553.h"
    
    void main( void )
    {
      WDTCTL   = WDTPW | WDTHOLD;                // Stop watchdog timer
    
      BCSCTL1  = CALBC1_1MHZ;                    // Set range to 1MHz
      DCOCTL   = CALDCO_1MHZ;                    // Set DCO step and modulation to 1MHz
    
      P1SEL    = 0x40;                           // Enable timer function for P1.6 (TA0.1)
      P1DIR    = 0x40;                           // Set P1.6 (TA0.1) to output direction
    
      P2SEL    = 0x02;                           // Enable timer function for P2.1 (TA1.1)
      P2DIR    = 0x02;                           // Set P2.1 (TA1.1) to output direction
    
      TA0CCR0  = 10000-1;                        // Period for 1st PWM: 10ms @ 1MHz
      TA0CCR1  = 2000;                           // Duty cycle for 1st PWM: 2ms @ 1MHz
      TA0CCTL1 = OUTMOD_7;                       // TA0.1 reset/set mode
    
      TA1CCR0  = 10000-1;                        // Period for 2nd PWM: 10ms @ 1MHz
      TA1CCR1  = 2000;                           // Duty cycle for 2nd PWM: 2ms @ 1MHz
      TA1CCTL1 = OUTMOD_7;                       // TA1.1 reset/set mode
    
      TA0R     = 2500-5;                         // 1st PWM: 25% of duty cycle head-start
      TA0CTL   = TASSEL_2 | ID_0 | MC_1;         // 1st PWM: SMCLK, divider 1, up-mode
      TA1CTL   = TASSEL_2 | ID_0 | MC_1 | TACLR; // 2nd PWM: SMCLK, divider 1, up-mode, clear
    
      while( 1 );
    }
    

  • Hi !

    This is the output of your code:

    So yes! It works!

    Dennis

  • Dennis,

    Thank you very much.

    OCY
  • That is a clever solution you have!
  • Dennis,

    The idea and the code are 99% yours.

    I am a little puzzled why the delay produced is 2.52 msec and not 2.500 msec. I was expecting an accurate delay down to a single count. I even tried to compensate the "-5" counts difference between lines 25 and 26. (For CPUX, use "-4" instead of "-5").

    BTW, there should be a "-1" in lines 16 and 17 for the periods.

    --OCY
  • Well, this deviation could be caused by the markers from the scope. I can measure it again with a more expanded waveform. Sometimes one click of the rotary encoder for the cursor jumps before the edge and the next behind.

    Dennis
  • I think this is close enough - your method works fine:

  • muchas gracias

**Attention** This is a public forum