Using CCS v10, and currently have an MSP430F5638 running on a custom SBC. Using TB0 to create PWM for LED dimming. TB0 is working fine, getting the desired frequency and duty cycle on scope. But I have a number of questions. I have included portions of a simplified version that is working the same as the full version. The full program sends a lot of data to the attached LCD for test and development - that code has been removed for clarity.
void main(void) { WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer // setup functions // setup_430_ports(); setup_430_clocks(); // use XT2 @ 20 MHz // setup testing for LED PWM Dimmer set_LED_TB0_dim(); // no code accessible after LED function runs // LCD_put_string_4_cc(170, 20, "AFTER LED TB0 CALL", red, white); }
void set_LED_TB0_dim(void) { float xt2 = 20e6, frequency, dutycycle; WDTCTL = WDTPW+WDTHOLD; // Stop WDT P4SEL |= BIT6; // P4.6 peripheral option select P4DIR |= BIT6; // P4.6 output // left most 0 not required since only 1 TB TBCCR0 = 100; // set CCR0 cycle period register TBCCTL6 = OUTMOD_7; // set CCR6 Output mode, reset/set TBCCR6 = 50; // set CCR6 PWM duty cycle TBEX0 = 0; // has no effect, 0 = '/1' by default // enable CCR6 interrupt - required for ISR to run // but disables TB0, no PWM out //TBCCTL6 = CCIE; // ID_0 = /1 by default // add enable interrupt - not necessary (+ TBIE), removed TBCTL = TBSSEL_2 + MC_1 + ID_0 + TBCLR; // SMCLK, up mode to CCR0, /1, TB clear // compute frequency & duty cycle for LCD diagnostics frequency = xt2/TBCCR0; // not accurate for > 50% and < 100%, need to cast int as float dutycycle = (float)TBCCR0/TBCCR6; // no timer output without this? __bis_SR_register(LPM0_bits + GIE); // enter LPM0 with interrupts enabled, CPU off, runs in regular routines //__bis_SR_register(GIE); // interrupts enabled, runs in regular routines //__bic_SR_register_on_exit(LPM0_bits); // exit LPM0 - can only run from ISR's } // ISR from msp430f66xx_tb_03.c and modified // Timer_B0 CCR6 Interrupt Vector (TBIV) handler // changed from B1 to B0 - BOTH MUST BE B1 TO WORK???? #pragma vector=TIMERB1_VECTOR __interrupt void TIMERB1_ISR(void) { switch( __even_in_range(TBIV,14) ) { case 0: break; // No interrupt case 2: break; // CCR1 not used case 4: break; // CCR2 not used case 6: break; // CCR3 not used case 8: break; // CCR4 not used case 10: break; // CCR5 not used case 12: // CCR6 overflow { __bic_SR_register_on_exit(LPM0_bits); // exit LPM0, can only run from ISR LCD_put_string_4_cc(170, 40, "IN TB0 ISR CASE 12", red, white); break; } case 14: break; // CCR7 not used default: { LCD_put_string_4_cc(190, 0, "IN TB0 ISR DEFAULT CASE", white, red); break; // no default } } }
main() Questions
1. Why doesn't any code in main() run after the call to set_LED_TB0_dim()?
set_LED_TB0_dim() Questions
- MSP430F5638 only has one TB, so looks like 0 suffix is superfluous TBCCR0 and TB0CCR0 both work
- TBCCTL6 = CCIE required for ISR to run, but disables TB0, no PWM output
- Why does set_LED_TB0_dim() go into LPM mode? Won’t run without it.
- Why is CCIE required, but not TBIE?
- __bis_SR_register(LPM0_bits + GIE) Works with or without LPM0_bits (I’m not checking power in real-time – but looks the same 142 ma)
I really don't want TB0 to put the CPU into LPM, but code won't run without it.
ISR Questions
1. Why does the ISR name require B1 in the vector and function name, and not B0? This is TB0, but won't work with B0.