It is possible to use CCR0 to do PWM in addition to CCR1 and up by using continuous mode and output compare toggle mode. This requires an ISR for each CCR used. It is glitch free and allows different PWM periods for each output if desired.
The basic ISR is simple:
__interrupt void isr_ccr0(void) // - ISR for CCR0 { // static unsigned s = 0; // State static unsigned d; // On duration // TA1CCR0 += (s++ & 1) ? (pwm_period[0] - d) : (d = pwm_on[0]); } //Each time the ISR occurs, the output time is advanced in to the future. The lsb of a state variable toggles between adding the on duration or off duration to the previous time. When the lsb is 0, then the on duration is used, and also saved for later. When the lsb is 1, then the off duration is calculated from the saved on duration and the PWM period. Toggling of the output pin is automatic because the CCR output mode is set to toggle.
Complete code for 3 PWM outputs using CCR0, CCR1, and CCR2 of Timer 1
#include <msp430.h> static unsigned pwm_on[3]; // PWM on duration static unsigned pwm_period[3]; // Total PWM period - on duration + off duration // #pragma vector = TIMER1_A0_VECTOR // - ISR for CCR0 __interrupt void isr_ccr0(void) // { // static unsigned s = 0; // State static unsigned d; // On duration // TA1CCR0 += (s++ & 1) ? (pwm_period[0] - d) : (d = pwm_on[0]); } // // #pragma vector = TIMER1_A1_VECTOR // - ISR for CCR1, CCR2 __interrupt void isr_ccr12(void) // { // static unsigned s1 = 0; // State static unsigned d1; // On duration static unsigned s2 = 0; // static unsigned d2; // // switch(TA1IV) { // case 0x02: // - CCR1 TA1CCR1 += (s1++ & 1) ? (pwm_period[1] - d1) : (d1 = pwm_on[1]); break; // case 0x04: // - CCR2 TA1CCR2 += (s2++ & 1) ? (pwm_period[2] - d2) : (d2 = pwm_on[2]); break; // } // } // // static void pwm_init(void) // { // P2DIR |= (BIT0 | BIT2 | BIT4); // PWM outputs on P2.0, P2.2, P2.4 P2SEL |= (BIT0 | BIT2 | BIT4); // Enable timer compare outputs P2SEL2 &= ~(BIT0 | BIT2 | BIT4); // // TA1CTL = TASSEL_2 | ID_3 | MC_2; // Setup timer 1 for SMCLK / 8, continuous mode // TA1CCTL0 = TA1CCTL1 = TA1CCTL2 = OUTMOD_4 | CCIE; // Set timer output to toggle mode, enable interrupt TA1CCR0 = TA1CCR1 = TA1CCR2 = TA1R + 1000; // Set initial interrupt time } // // int main(void) // { // WDTCTL = WDTPW | WDTHOLD; // // DCOCTL = 0; // Run DCO at 8 MHz BCSCTL1 = CALBC1_8MHZ; // DCOCTL = CALDCO_8MHZ; // // pwm_init(); // Initialize PWM // // Setup PWM period pwm_period[0] = pwm_period[1] = pwm_period[2] = 20000; pwm_on[0] = 1000; // Setup servo times pwm_on[1] = 1500; // pwm_on[2] = 2000; // // _enable_interrupts(); // Enable all interrupts // for(;;) { // } // // return 0; // } //