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/MSP430F5438A: sinusoidal modulation PWM

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;
}*/
interruptP2.asm

  • Nikola,
    Have you checked out our examples in TI Resource Explorer? We have some in assembly and c for this part showing how to do PWM.

    My immediate thought is that you are setting CCR3 to 0, as you have many entries of 0 in your sine_values array. Is this possible?
  • Thanks for the response.

    I don't see why would zeros be a problem. As TB0R register reaches value of 255, TB0CCIFG0 is set and interrupt is requested. Also, output is set because OUTMODE_7 is chosen. In interrupt service routine, I change value of sample used for generating PWM pulse width. In case when I change it to zero and returning to main program, there should be another timer clock executed, when TB0R is changed from 255 to 0 (TB0R is reset after reaching TB0CCR0 because timer works in UP mode). At this moment output should be reset, because TB0R reached value in compare register TB0CCR3, that was changed in previous interrupt routine to zero.
    Tho, I also had this in mind, because it is the easiest solution. I will just change all zeros to one. I will check this when I get board, cause I share it with another colleague.

    Tho, to clear this out. TB0CCR3 seems to be stuck at zero because in some occasions, code never reaches interrupt routine of Timer B0. Thus value of this register is never changed, thus pulse width of PWM is always set to zero, thus LE diode does not emit light. When I press either button to change frequency, it starts working good again. After few more key presses(during which everything worked fine, LE diode was emitting light in sinusoidal manner, according to set frequency), it just stops, with no regularity between two of such cases, except it never happens when i change frequency from even to odd number. I wonder what could be a problem? Is there any reason why interrupts stop being generated, after some button was pressed? Does it have to do something with particular time when button was pressed?

    In meantime I will check TI Resource Explorer. Wasn't aware of it. I have mostly been relied on SLAU208P document.

    Best regards!

  • Hi Nikola,
    Just checking in. Have you made any progress with trying the new values?

    I suspect your experience a combination of CCR values that is preventing the Timber B ISR from ever firing. I see that you have ISR's commented at the bottom of your main.c, did you see this issue when you had the C implementation of the ISR's?
  • Hi again.

    It's been a while since I posted the question about the issue I am having. I had time to work on my problem.

    Unfortunately, I didn't resolve the issue about Timer B interrupt routine written in assembly. I tried everything, and literally had no idea what to do next anymore.

    So, I did use the one written in C, which was fine. It probably has something to do with the way I am using array of sine values inside routine (particular values were not the problem, cause I changed them all to same value once when I tried, and still had the same issue ). I I need to do more reading. 

    Task is doing great, and I am having no problem this way, thus this thread can be forgotten.

    Thanks for your help Cameron and for showing some other approaches toward solving problems.

    Best regards!

    Nikola Gajic

  • Good to hear, let me know if you have more trouble here.

**Attention** This is a public forum