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.

CCS/MSP430G2553: PWM code doesn't lower intensity of LED

Part Number: MSP430G2553

Tool/software: Code Composer Studio

I'm trying to use PWM on my msp430 launchpand to increase/ decrease the intensity of the red LED, but for some reason my code is not making the LED change intensity. I want to use my timeA.c change the PWM signal. The only thing I can see that might be causing the problem is the difference in values for TACCR0 and TACCR1. Right now TACCR1 is greater than TACCR0 when it should be the other way around. Can someone help to fix this problem

Here is my timerA.c file

#include "LED.h"
#include "timerA.h"

void ConfigureTimerA(void)
{
   TA0CTL  =   (MC0   |   TACLR);
   TA0CTL  |=  (TASSEL_2 |ID_2  |   MC_1);
   //assign value to Time A0; capture/compare register0
   TA0CCR0 =   499;
   TA0CCR1 = 0;
  //enable capture
   TA0CCTL0    |=  CCIE;
   TA0CCTL1    |=  CCIE;
   TA0CTL       |=  TAIE;
}
unsigned int direction = 0;
#pragma vector = TIMER0_A0_VECTOR
// Interrupt service routine for CCIFG0
	__interrupt void Timer0_A0_routine(void)
{

            //light min
           if(TACCR1 == 0)
              direction = 0;
           //light max
           else if (TACCR0 == TACCR1)
               direction = 1;
           //light at min increase duty cycle
           if(direction == 0)
               TACCR1 --;
           //light at max decrease duty cycle
           else if(direction == 1)
               TACCR1++;

}

#pragma vector = TIMER0_A1_VECTOR
// Interrupt service routine for CCIFG1 and TAIFG
	__interrupt void Timer0_A1_routine(void)
{
	switch (TAIV){
	case TA0IV_NONE:
		break;
	case TA0IV_TACCR1: // CCIFG1 interrupt
	    TURN_OFF_LED1;
		break;

	case TA0IV_TAIFG: // TAIFG interrupt
	    TURN_ON_LED1;

		break;
	default: for (;;); // Should not be possible
	}
}

Here is my main file

#include <msp430.h>
#include "LED.h"
#include "pushbutton.h"
#include "timerA.h"

// Global variable
char LEDBit = LED1;

// Function prototypes
void ConfigureClockModule(void);

void main(void)
{
    // Stop the watchdog timer, and configure the clock module.
    WDTCTL = WDTPW + WDTHOLD;
    ConfigureClockModule();

    // Initialize port pins associated with the LEDs, and then turn off LEDs.
    InitializeLEDPortPins();


    // Configure timer A to generate the required interrupt.
    ConfigureTimerA();

    _enable_interrupts();

    // Infinite loop
    while (1) {

    }
}
void TimeDelay(unsigned int delay, unsigned int resolution){
    unsigned i;
    TA0CTL = (MC_0 |TACLR);
    TA0CCR0 = resolution;
    TA0CTL = (TASSEL_2|ID_2|MC_1);

    for(i=0; i<delay; i++){
        while(!(TA0CTL & TAIFG));
        TA0CTL &= !TAIFG;
//
        TA0CTL =(MC_0 |TACLR);
    }
}

void ConfigureClockModule(void)
{
    // Configure Digitally Controlled Oscillator (DCO) using factory calibrations.
    DCOCTL  = CALDCO_1MHZ;
    BCSCTL1 = CALBC1_1MHZ;
}

  • I think your definition (interpretation) of "direction" is backwards. When TACCR1 reaches 0, you continue decrementing (to 65535) rather than incrementing (up to 1). Try reversing the decision:

    if(TACCR1 == 0)
    direction = 1;
    else if (TACCR0 == TACCR1)
    direction = 0;
  • Thank you! It worked
    Do you know how to stop the blinking when the light increases intensity?
  • If you're talking about the "glitch" that happens when the LED is nearly off: This is a general problem using PWM with
    duty cycles near 0% and/or 100%. It doesn't have a general solution. (I'll mention: this is the reason for the CLLD
    mechanism in TimerB, but the G2553 doesn't have a TimerB.)

    It has to do with a race between the timer (TA0R) and the compare register (CCR1) -- if TA0R has already counted past
    CCR1, it won't trigger and the phase gets reversed. Software takes a finite time to do the update, that is the relevant
    time window near 0% (or 100%).

    This is compounded when using software PWM (your case) by the relative priorities of the CCR0/TAIFG/CCR1 interrupts --
    you can never be sure in what order they occurred.

    I suggest:
    1) updating CCR1 in the CCR1 (rather than CCR0) interrupt, since it always "misses". [This applies to both hardware and
    software PWM.]
    2) for software PWM: observe that if both TAIFG (on) and CCR1 (off) interrupts are indicated, the net effect on the LED
    is null.

    I just started typing, and came up with this for Timer0_A1_routine [there's probably a cleverer coding]:

    __interrupt void Timer0_A1_routine(void)
    {
       unsigned on, off;			// (16-bit)
        off = TA0CTL & TAIFG;
        on = TA0CCTL1 & CCIFG;
        if (on && off)
        {
        	// do nothing
        	TA0CTL &= ~TAIFG;
        	TA0CCTL1 &= ~CCIFG;
        }
        else if (off)
        {
        	TURN_OFF_LED1;
        	TA0CTL &= ~TAIFG;
        }
        else if (on)
        {
        	TURN_ON_LED1;
        	TA0CCTL1 &= ~CCIFG;
        }
        else
        {
        	// Huh? Why are we here?
        	for (;;);
        }
        if (on)	// CCR1
        {
           //light at min increase duty cycle
           if(direction == 0)
               TACCR1 --;
           //light at max decrease duty cycle
           else if(direction == 1)
               TACCR1++;
        }
    }
    

**Attention** This is a public forum