Part Number: MSP430F5438A
Tool/software: Code Composer Studio
I have a task where I need to send sinusoidal PWM to LE diode. Frequency of such sine is changed via buttons and it goes from 1 Hz to 16 Hz.
MSP430 Timers are pretty sophisticated, and using appropriate output mode (reset/set = OUTMODE7) , they can easily generate PWM output, and send it to selected periphery, which is in my case Port4, pin 3, where is LE diode. Thus I am using compare register TB0CCR3, for resetting the impulse, and TB0CCR0 register for setting the impulse of PWM, all according to SLAU401E.
Problem is that sometimes when I change frequency to an even number(it is never an odd number), TB0CCR3 register seems to get stuck at value 0x0000, and won't change, thus making output to be zero, or in other words, LE diode does not emit light. Also, there is no regularity when this happens, only thing I can say, it does not happen with odd frequencies, just with even ones, and that happens sometimes with no regularity.
Interrupts were written in assembly, and main program was written in C.
Here are the codes:
/**
* @file main.c
* @brief Sinusoidal-wise PWM
*
* Here we have a main function which simulates changing of an LE diode brightness in sinusoidal manner.
* Frequency of such sine can go from 1 Hz to 16 Hz, and it is changed with UP and DOWN buttons.
* Currently used frequency is presented on multiplexed 7-segment display.
* Project is done on TI MSP430F5438A board.
*
* @date 22.4.2017
* @author Nikola Gajic (nikola.gajic93@yahoo.com)
*/
#include <msp430.h>
#include "function.h"
/** Counter that stores how many times a sample was used for PWM pulse width */
unsigned int cnt = 0;
/** Variable where used frequency is stored */
unsigned int frequency = 1;
/** Variable that will store appropriate sample of sine */
unsigned int sample = 0;
/** Array with 256 equidistant samples of sine generated in Matlab */
unsigned int sine_values[] = {
127, 130, 133, 136, 139, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, 181, 184,
187, 190, 193, 195, 198, 200, 203, 205, 208, 210, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231,
233, 235, 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 250, 251, 252, 252, 253, 253,
253, 254, 254, 254, 254, 254, 254, 254, 253, 253, 252, 252, 251, 251, 250, 249, 248, 247, 246, 245,
244, 243, 241, 240, 239, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220, 218, 216, 214, 211, 209,
207, 204, 202, 199, 196, 194, 191, 188, 186, 183, 180, 177, 174, 171, 168, 166, 163, 159, 156, 153,
150, 147, 144, 141, 138, 135, 132, 129, 125, 122, 119, 116, 113, 110, 107, 104, 101, 98, 95, 91,
88, 86, 83, 80, 77, 74, 71, 68, 66, 63, 60, 58, 55, 52, 50, 47, 45, 43, 40, 38,
36, 34, 32, 30, 28, 26, 24, 22, 20, 19, 17, 15, 14, 13, 11, 10, 9, 8, 7, 6,
5, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2,
3, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, 23, 25, 27, 29,
31, 33, 35, 37, 39, 41, 44, 46, 49, 51, 54, 56, 59, 61, 64, 67, 70, 73, 75, 78,
81, 84, 87, 90, 93, 96, 99, 102, 105, 108, 111, 115, 118, 121, 124, 127
};
/**
* @brief Main function
*
* Initialization of necessary parameters
*/
int main(void)
{
WDTCTL = WDTPW | WDTHOLD;
/* buttons */
P2DIR &= 0xCF; // set P2.4 and P2.5 as in
P2IES |= BIT4 | BIT5; // set P2.4 and P2.5 irq as h->l transition
P2IFG &= ~(BIT4 | BIT5); // clear P2.4 and P2.5 IFG
P2IE |= BIT4 | BIT5; // enable P2.4 and P2.5 isr
/* 7-seg LED display*/
P11DIR |= 0x03; // setting P11.0 and P11.1 as out
P6DIR |= ~BIT7; // setting P6 pins as out
P4DIR |= BIT3; // P4.3 set as out
P4SEL |= BIT3; // P4.3 use for TimerB0
TB0CCTL3 = OUTMOD_7; // reset/set outmode
TB0CCR0 = 255; // period
TB0CCR3 = sine_values[sample]; // initial pulse width value
//TB0CTL = ID_3; // divide SMCLK with 8
//TB0EX0 = TBIDEX_1; // divide resulting frequency with 2, thus making starting frequency to be equal SMCLK/16
TB0CCTL0 |= CCIE; // enables TB0CCR0 isr
TB0CCTL0 &= ~CCIFG; // clears interrupt flag
TB0CTL = TBSSEL__SMCLK | MC__UP | TBCLR; // use SMCLK clock source, configure timer for UP mode and clear it
__enable_interrupt();
while(1)
{
P11OUT &= ~BIT1;
WriteLed(frequency / 10);
P11OUT |= BIT1;
__delay_cycles(2000);
P11OUT &= ~BIT0;
WriteLed(frequency % 10);
P11OUT |= BIT0;
__delay_cycles(2000);
}
}
/*void __attribute__ ((interrupt(PORT2_VECTOR))) P2ISR (void)
{
__delay_cycles(1000);
if ((P2IFG & BIT4) != 0) { // check if P2.4 flag is set
if (0 == (P2IN & BIT4)) { // check if P2.4 is still pressed
frequency = (frequency + 1) & 0xf; // incrising frequency by one with module of 16
//factor = setFreq();
}
P2IFG &= ~BIT4; // clear P2.4 flag
}
if ((P2IFG & BIT5) != 0) { // check if P2.5 flag is set
if (0 == (P2IN & BIT5)) { // check if P2.5 is still pressed
frequency = (frequency - 1) & 0xf; // decrising frequency by one with module of 16
//factor = setFreq();
}
P2IFG &= ~BIT5; // clear P2.5 flag
}
return;
}*/
/*void __attribute__ ((interrupt(TIMER0_B0_VECTOR))) TB0CCR0ISR (void)
{
sample = (sample + frequency) &0xff;
TB0CCR3 = sine_values[sample];
return;
}*/