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.

2 PWM channels on msp430g2553

Other Parts Discussed in Thread: MSP430G2553

Hi,

I am trying to program 2 PWM channels on the msp430g2553 - both channels can use the same base frequency.

I tried the following code: 


#include <msp430g2553.h>

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1DIR |= 0x0C; // P1.2/TA0.1 and P1.3 output
P1SEL |= 0x0C; // P1.2 and P1.3 TA1/2 options

P2DIR |= 0x02; // P2.1/TA1.1 output
P2SEL |= 0x02; // P2.1 options

CCR0 = 1000-1; // PWM Period
CCTL1 = OUTMOD_7; // CCR1 reset/set
CCTL2 = OUTMOD_7; // CCR1 reset/set
CCR1 = 10; // CCR1 PWM duty cycle
CCR2 = 500;
TACTL = TASSEL_2 + MC_1; // SMCLK, up mode



_BIS_SR(CPUOFF); // Enter LPM0
}

However this did not generate a PWM signal on P2.1. Am I missing something?
Thank you.
  • Marc Weintraub said:
    However this did not generate a PWM signal on P2.1. Am I missing something?


    Yes. TA1.1 is the output of TA1CCR1, but you program (TA0)CCR1.

    The G2553 has two independent TimerA modules.

  • Hi Marc,

    I have the same problem with the "2 PWM channels on msp430g2553" and I see also the problem with using the wrong timer ... :-)

    Maybe could you send me your fixed code version? So I could compare if there is a hardware failure ... or my msp skills are bad.

    Tank you

  • See Data-sheet of the chip you are using. Read the Peripheral: Timer_A3 (TA0, TA1) Section under Short-Form Description.

    It is far more useful to learn how to read Data-sheet and other documents then to ask specific questions one by one.

  • Thank you for your answer!

    Sorry of course I already read it. The problem is not the understanding more how to address or call the second timer?

    E.g.(compare msp430g2553.h)

    #define CCR0                   TACCR0         /* Timer A Capture/Compare 0 */
    #define CCR1                   TACCR1         /* Timer A Capture/Compare 1 */
    #define CCR2                   TACCR2         /* Timer A Capture/Compare 2 */

    .

    .

    .

    #include  <msp430g2553.h>

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;
    P1DIR |= 0x04; // Output
    P1SEL |= 0x04; // TA1 option

    CCR0 = 1000; // PWM Period
    CCTL1 = OUTMOD_6;// Reset/set
    CCR1 = 7; // Duty cycle
    CCTL2 = OUTMOD_6;// Reset/set
    CCR2 = 20; // Duty cycle

    TACTL = TASSEL_2 + MC_1;// SMCLK, up mode
    //f_BIS_SR(LPM0_bits);                       // Enter LPM0
    }

    Now we want to do that at PORT2.

    #include  <msp430g2553.h>

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;
    P2DIR |= 0x02; // Output
    P2SEL |= 0x02; // TA1 option

    CCR0 = 1000; // PWM Period
    CCTL1 = OUTMOD_6;// Reset/set
    CCR1 = 7; // Duty cycle
    CCTL2 = OUTMOD_6;// Reset/set
    CCR2 = 20; // Duty cycle

    TACTL = TASSEL_2 + MC_1;// SMCLK, up mode
    //f_BIS_SR(LPM0_bits);                       // Enter LPM0
    }

    How can I call timer 2? CCRx is wrong. But I cannot find the proper definitions.

    Thank you for your help!

  • I guess you are what I called another victim of the “easy to read” programming tools and practice.

    The G2553 chip has two Timers and thus two sets of registers to use them. As far as the CPU is concerned, one set (Timer0_A3) can be accessed at 0x012E, 0x0160-0x0166, and 0x0170-0x0176. The other set (Timer1_A3) can be accessed at 0x011E, 0x0180-0x0186, and 0x0190-0x0196.

    I do not know what programming tools you are using. It probably provided you with the “header file” that you quoted from. The practice is to define tons of “easy to read” words and aliases.

    You said that file defines CCR0 as TACCR0. If you read more and follow the trail, you probably will find that eventually CCR0 means 0x0172. CCTL1 eventually means 0x0164. Etc. Thus both your two versions of main() end up accessing the same Timer (Timer0_A3).

    But in your second version of main(), you meant to use the other Timer (Timer1_A3) which you called “Timer 2”. I guess you could try TA1CCR0, TA1CCTL1, etc. instead of CCR0, CCTL1, etc. But this is just a guess, as I do not know what tool and which version of that tool you are using.

    At the end of the day, the “header file” must end up translating them to 0x0192, 0x0184, etc. Personally, I think these “easy to read” practices make it "hard to write" and "hard to notice problems" hiding behind the friendly words.

  • Ok ok I see ... :-) ... it works. Thank you for your quick help! I used to work with other controllers ... Thank you very much!

    Wishes Florian

  • So I've been wrestling with the same problem of sorts. I've got my two PWMs going from the separate timers and everything is working only the examples in my textbook by John H. Davies implies that I can generate several channels from a single PWM and use the same set of capture compare registers across multiple channels. 

    I'm trying to drive an H-bridge so I need to have one channel in outmode2 and one in outmode6 and use CCR1 & CCR2 to create a deadband between them. So far I've only managed to generate two separate but identical if only inverted PWMs and offset their duty cycles to get my deadband which works it just takes twice code. I'd like to know how to do it with just one if anyone can help me. Here is the code I have so far, please excuse the mess and excess code for my ADC:

    #include <msp430.h>

    unsigned int value=0;


    int _system_pre_init(void)
    {
    /* Insert your low-level initializations here */
    /* Disable Watchdog timer to prevent reset during */
    /* long variable initialization sequences. */
    WDTCTL = WDTPW | WDTHOLD;

    /*==================================*/
    /* Choose if segment initialization */
    /* should be done or not. */
    /* Return: 0 to omit initialization */
    /* 1 to run initialization */
    /*==================================*/
    return 1;
    }


    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT

    BCSCTL1 = CALBC1_16MHZ; // Set range (CALBC1_1MHZ)
    DCOCTL = CALDCO_16MHZ; //(CALDCO_1MHZ) SMLK set to 150KHz?
    BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz
    P1SEL |= BIT5; //ADC Input pin P1.5

    /* Configure ADC Channel */
    ADC10CTL1 = INCH_5 + ADC10DIV_3 ; // Channel 5, ADC10CLK/4
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE; //Vcc & Vss as reference
    ADC10AE0 |= BIT5; //P1.5 ADC option

    __enable_interrupt(); // Enable interrupts.


    //TA0CCTL1 = OUTMOD_0 + OUT;
    P1DIR |= 0x0C; // P1.2 and P1.3 output
    P1SEL |= 0x0C; // P1.2 and P1.3 TA1/2 options
    P2DIR |= 0x0C;
    P2SEL |= 0x0C;

    TA0CCR0 =160-1; // PWM Period/2
    TA0CCR1 = 79-1; // CCR1 PWM duty cycle
    //TA0CCR2 = 120-1;
    TA0CCTL1 = OUTMOD_6; // CCR1 toggle/set
    TA0CTL = TASSEL_2 + MC_3 + TACLR + ID_0; // SMCLK, up-down mode

    TA1CCR0 = 160-1; // PWM Period/2
    TA1CCR1 = 81-1; // CCR1 PWM duty cycle
    //TA1CCR2 = 120-1;
    TA1CCTL1 = OUTMOD_2; // CCR1 toggle/set
    TA1CTL = TASSEL_2 + MC_3 + TACLR + ID_0; // SMCLK, up-down mode

    while(1)
    {
    __delay_cycles(1000); // Wait for ADC Ref to settle
    ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
    __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled
    value = ADC10MEM;
    }
    }

    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR (void)
    {
    __bic_SR_register_on_exit(CPUOFF); // Return to active mode
    }

  • #include <msp430g2553.h>
    int i=0;
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P1DIR |= BIT6; // P1.2/TA0.1 and P1.3 output
    P1SEL |= BIT6; // P1.2 and P1.3 TA1/2 options

    P2DIR |= BIT6; // P2.1/TA1.1 output
    P2SEL |= BIT6; // P2.1 options

    CCR0 = 1000-1; // PWM Period//1000
    CCTL1 = OUTMOD_7; // CCR1 reset/set
    CCTL2 = OUTMOD_7; // CCR1 reset/set
    CCR1 = 1; // CCR1 PWM duty cycle
    CCR2 = 500;
    TACTL = TASSEL_2 + MC_1; // SMCLK, up mode

    while(1)
    {

    for(i=0;i<6000;i++)
    {

    }
    CCR1++;
    if(CCR1>100)
    {
    CCR1=0;
    }

    }

    _BIS_SR(CPUOFF); // Enter LPM0
    }

**Attention** This is a public forum