MSP430 PWM Channels

Im new to MCU and MSP430 Programming and was confused about PWM Channels. I have a MSP430g2231 Chip thats included in the launchpad and was wondering How many PWM channels it has and how to determine how much PWM other microcontrollers have is it based on Timers compare channels? in this chip there seem to only be two channels CCR0 and CCR1 so can it only drive two in continuous mode?

tsukukinsei,

If you are looking for information on PWM, look at the device family user guide in the section about the timers…

http://www.ti.com/litv/pdf/slas694b

You can find a link for this on any TI device page under documents. Also there is useful chip specific information that you can find in each devices data sheet.

If you are completely new to microcomputers, I would recommend not starting with PWM it is not the easiest thing to dive into if you have no experience. Just my opinion though :-P. If you want to, read up on how the timers work in the device. I haven’t looked, but I’m sure theres an article or post somewhere online that does a good job explaining. Eventually I might discuss this on my blog, but not for a while.

Best of luck.

-NJC


http://msp430launchpad.blogspot.com

There is one timer and two capture compare registers. This means only one Timer based PWM. You can do it in software, but…

How about something like this. Use the PWM period at the total timer period. Use the ISR for each CCRx and get two PWM’s?

Change TACCRx to get your PWM… Change clock to get PWM period you need? Not great but…

TACTL = TASSEL_2 + ID_0 + MC_2 + TAIE; // SMCLK, no div, cont mode

TACCR0 = 0x03FF; // Capture compare 0

TACCR1 = 0x01FF; // Capture compare 1

TACCTL0 = CCIE; // Enable interrupt

TACCTL1 = CCIE; // Enable interrupt

_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt

}

// Timer A0 interrupt service routine for TACCR0

#pragma vector=TIMERA0_VECTOR

__interrupt void Timer_A0 (void)

{

P1OUT &= ~BIT0; // Blue LED OFF

}

// Timer_A2 Interrupt Vector (TAIV) handler for everything except TACCR0

#pragma vector=TIMERA1_VECTOR

__interrupt void Timer_A1(void)

{

switch( TAIV )

{

case 2: P1OUT &= ~BIT4; // Green LED OFF

break;

case 10: P1OUT |= BIT0; // Blue LED ON

P1OUT |= BIT4; // Green LED ON

break;

}

}

OK. If you keep it simple this works. Crank the speed to 8MHz. Setup an interrupt and do the pwm in the ISR. Ugly… Yes, but I can do PWM at 100Hz on 4 outputs and still have time to do some other stuff. Gas it up to 16MHz if you must.

I put sparkfun’s trackball on the breadboard to turn the led’s on and off and to switch between the colors to change teh intensity just to see it work. I ran out of pins on the G2211 so don’t have all the colors on the trackball.

volatile unsigned int uiLEDBlueInt = 20;

volatile unsigned int uiLEDRedInt = 20;

volatile unsigned int uiLEDGreenInt = 20;

volatile unsigned int uiLEDWhiteInt = 20;

volatile unsigned int uiLampON = 0;

const unsigned int cLEDIncr = 100;

const unsigned int cLEDStep = 2;

void main(void)

{

WDTCTL = WDTPW + WDTHOLD; // Hold watchdog timer.

DCOCTL = DCO0 + DCO1; // This one setup 8.2MHz

BCSCTL1 = RSEL0 + RSEL2 + RSEL3; // but may slow it down later

// BCSCTL2 |= 0; // MSP430 clocks.

// Port setups.

// Port 1 P1.3 is already wired to a SMD switch SW2.

P1DIR = BIT5 + BIT6 + BIT7; // Pins to be outputs

P1SEL = 0; // Function select. No special func

P1OUT = 0; // Output value or pull up resistor

P1REN = 0; // Which inputs have the resistor enabled

P1IE = BIT0 + BIT1 + BIT2 + BIT3 + BIT4; // Interrupt enable

P1IES = 0; // Interrupt enable edge select

P1IFG = 0; // Clear interrupt requests

// Defines for Port 1

#define ipButton BIT0; // Trackball button pressed

#define ipRight BIT1; // Trackball rolled right

#define ipLeft BIT2; // Trackball rolled left

#define ipUp BIT3; // Trackball rolled up

#define ipDown BIT4; // Trackball rolled down

#define opLEDButtonWhite BIT5; // Trackball button LED

#define opLEDButtonBlue BIT6; // Daylight white LED

#define opLEDGreen BIT7; // Green LED

//Port 2 Don’t use P2.7 as an input or excess current will flow

P2DIR = 0xFF; // Pins to be in and out

P2SEL = 0; // XIN and XOUT I/O

P2OUT = 0; // Output value or pull up resistor

P2REN = 0; // Which inputs have the resistor enabled

P2IE = 0; // Interrupt enable

P2IES = 0; // Interrupt enable edge select

P2IFG = 0; // Clear interrupt requests

// Defines for Port 2

#define opLEDBlue BIT6;

#define opLEDRed BIT7;

// Timer A setup.

// Several clocks can be used for the timer. Various dividing ratios and

// 4 modes available. TACCR0 useless in up mode. TAIE enables the interrupt

// at each rollover. Using TACCR0 at 8.2Mhz as 100Hz interrupt timing.

TACTL = TASSEL_2 + ID_0 + MC_1; // SMCLK, no div, up mode,

TACCR0 = 0x01FF; // Capture compare 0 not used

TACCR1 = 0x0000; // Capture compare 1 not used

TACCTL0 = CCIE; // Enable interrupt

//TACCTL1 = CCIE; // Enable interrupt

// GIE must be enabled to allow any ISR to work.

_BIS_SR(GIE); // Enter LPM0 w/ interrupt

for(;:wink:

{

}

}

// Interrupt service routine for Port 1

#pragma vector = PORT1_VECTOR

__interrupt void Port_1(void)

{

static unsigned int uiSelBlue = 1;

static unsigned int uiSelRed = 1;

static unsigned int uiSelGreen = 1;

//static unsigned int uiSelWhite = 1;

static unsigned int uiLRMove = 0;

static unsigned int uiLimitR = 1;

static unsigned int uiLimitL = 0;

// It would be good to disable the GIE here

_BIC_SR(GIE); // Dis-allow interrupts

if (P1IFG & BIT0)

{

P1IFG &= ~BIT0; // Reset interrupt flag

if (uiLampON == 0) // If OFF turn ON

{

uiLampON = 1; // If ON turn OFF

}

else

{

uiLampON = 0;

}

uiLRMove = 0; // Reset left or right move

}

if (P1IFG & BIT1) // Entry of BIT1 isr

{

P1IFG &= ~BIT1; // Reset interrupt flag

uiLRMove++;

if (uiLRMove > 2 && uiLimitR == 0) // If really mean to change color

{

if (uiSelRed == 1 && uiLRMove > 0)

{

uiSelRed = 0;

uiSelGreen = 1;

uiSelBlue = 0;

uiLimitR = 0;

uiLRMove = 0;

uiLimitL = 0;

P1OUT &= ~opLEDButtonBlue;

P1OUT &= ~opLEDButtonWhite;

}

if (uiSelGreen == 1 && uiLRMove > 0)

{

uiSelRed = 0;

uiSelGreen = 0;

uiSelBlue = 1;

uiLimitR = 0;

uiLRMove = 0;

uiLimitL = 0;

P1OUT &= ~opLEDButtonWhite;

P1OUT |= opLEDButtonBlue;

}

if (uiSelBlue == 1 && uiLRMove > 0)

{

uiSelRed = 1;

uiSelGreen = 1;

uiSelBlue = 1;

uiLimitR = 1;

uiLRMove = 0;

uiLimitL = 0;

P1OUT |= opLEDButtonWhite;

P1OUT &= ~opLEDButtonBlue;

}

}

}

if (P1IFG & BIT2)

{

P1IFG &= ~BIT2; // Reset interrupt flag

uiLRMove++;

if (uiLRMove > 2 && uiLimitL == 0) // If really mean to change color

{

if (uiSelRed == 1 && uiSelGreen == 1 && uiSelBlue == 1 && uiLRMove > 0)

{

uiSelRed = 0;

uiSelGreen = 0;

uiSelBlue = 1;

uiLimitL = 0;

uiLRMove = 0;

uiLimitR = 0;

P1OUT &= ~opLEDButtonWhite;

P1OUT |= opLEDButtonBlue;

}

if (uiSelBlue == 1 && uiLRMove > 0)

{

uiSelRed = 0;

uiSelGreen = 1;

uiSelBlue = 0;

uiLimitL = 0;

uiLRMove = 0;

uiLimitR = 0;

P1OUT &= ~opLEDButtonBlue;

P1OUT &= ~opLEDButtonWhite;

}

if (uiSelGreen == 1 && uiLRMove > 0)

{

uiSelRed = 1;

uiSelGreen = 0;

uiSelBlue = 0;

uiLimitL = 1;

uiLRMove = 0;

uiLimitR = 0;

P1OUT &= ~opLEDButtonBlue;

P1OUT &= ~opLEDButtonWhite;

}

}

}

if (P1IFG & BIT3)

{

P1IFG &= ~BIT3; // Reset interrupt flag

uiLEDBlueInt = uiLEDBlueInt + (cLEDStep * uiSelBlue);

uiLEDGreenInt = uiLEDGreenInt + (cLEDStep * uiSelGreen);

uiLEDRedInt = uiLEDRedInt + (cLEDStep * uiSelRed);

if (uiLEDBlueInt > cLEDIncr) uiLEDBlueInt = cLEDIncr;

if (uiLEDGreenInt > cLEDIncr) uiLEDGreenInt = cLEDIncr;

if (uiLEDRedInt > cLEDIncr) uiLEDRedInt = cLEDIncr;

uiLRMove = 0; // Reset left or right move

}

if (P1IFG & BIT4)

{

P1IFG &= ~BIT4; // Reset interrupt flag

if (uiLEDBlueInt > 0)

{

uiLEDBlueInt = uiLEDBlueInt - (cLEDStep * uiSelBlue);

}

if (uiLEDGreenInt > 0)

{

uiLEDGreenInt = uiLEDGreenInt - (cLEDStep * uiSelGreen);

}

if (uiLEDRedInt > 0)

{

uiLEDRedInt = uiLEDRedInt - (cLEDStep * uiSelRed);

}

uiLRMove = 0; // Reset left or right move

}

if (P1IFG & BIT5)

{

P1IFG &= ~BIT5; // Reset interrupt flag

}

if (P1IFG & BIT6)

{

P1IFG &= ~BIT6; // Reset interrupt flag

}

if (P1IFG & BIT7)

{

P1IFG &= ~BIT7; // Reset interrupt flag

}

_BIS_SR(GIE); // Allow interrupts

}

// Interrupt service routine for Port 2

#pragma vector = PORT2_VECTOR

__interrupt void Port_2(void)

{

P2IFG = 0;

}

// Interrupt service routine for Timer A0 TACCR0

#pragma vector = TIMERA0_VECTOR

__interrupt void Timer_A0(void)

{

static unsigned int uicounts; // Number of times in isr

uicounts++; // Increment PWM scan number

if (uicounts > cLEDIncr) uicounts = 0; // Check for overflow

if (uicounts < uiLEDBlueInt && uiLampON) //

{

P2OUT |= opLEDBlue;

}

else

{

P2OUT &= ~opLEDBlue;

}

if (uicounts < uiLEDGreenInt && uiLampON)

{

P1OUT |= opLEDGreen;

}

else

{

P1OUT &= ~opLEDGreen;

}

if (uicounts < uiLEDRedInt && uiLampON)

{

P2OUT |= opLEDRed;

}

else

{

P2OUT &= ~opLEDRed;

}

/*if (uicounts < uiLEDWhiteInt && uiLampON)

{

P1OUT |= opLEDWhite;

}

else

{

P1OUT &= ~opLEDWhite;

}*/

}

The meter clock on instructables has 2PWMs and uses the “less gifted” microcontroller that comes with the Launchpad (MSP430G2211).

http://www.instructables.com/id/MSP430- … hpad-chip/