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/MSP430F5529: Fading LED with PWM and WDT_ISR

Part Number: MSP430F5529

Tool/software: Code Composer Studio

Hello!  I have a piece of code that successfully fades an LED in and out smoothly in about 6 seconds total.  I am curious if there is a way to let a WDT_ISR do the LED brightness changes?  (Perhaps in interval mode)?

#include <msp430.h>

void _delay_ms(volatile unsigned int length){
    volatile unsigned int delay = 0;
    for(delay = 0; delay < length; delay++){
        _delay_cycles(1000);
    }
}

int main(void){

    WDTCTL = WDTPW + WDTHOLD;   // Stop WDT

//**NOTE: This setup requires putting a jumper between LED1 and P1.2 on the board**

    P1DIR |= BIT2;      //Set up Timer A 0.1(P1.2) for output
    P1SEL |= BIT2;      //P1.2 special function
    SFRIE1 |= WDTIE;    //Enable WDT interrupt

    TA0CCR0 = 350;
    TA0CCTL1 = OUTMOD_7;
    TA0CCR1 = 0;

    TA0CTL = TASSEL_1 + MC_1;

    volatile signed int i = 0;

    while(1){

        for(i = 1; i < 309; i += 5){
            TA0CCR1 = i;
            _delay_ms(50);
        }

        for(i = 309-1; i > 0; i -= 5){
            TA0CCR1 = i;
            _delay_ms(50);
        }
    }
}

  • I changed the code a bit, and I believe I have the WDT_ISR working correctly.  It correctly fades the LED without issue.  I have a problem now with 2 other interrupts I am trying to implement.  I want to make switch 1 pause the fading and switch 2 resume it.  I thought that all I had to do was stop and restart the WDT to achieve this, but it seems I am mistaken.  If I could get some help with this, I would greatly appreciate it.

    #include <msp430.h>
    
    void _delay_ms(volatile unsigned int length){
        volatile unsigned int delay = 0;
        for(delay = 0; delay < length; delay++){
            _delay_cycles(1000);
        }
    }
    
    int main(void)
    {
        WDTCTL = WDT_MDLY_32;   //Set WDT interval
        _EINT();                // enable interrupts
    
        //**NOTE: This setup requires putting a jumper between LED1 and P1.2 on the board**
    
        P1DIR |= BIT2;      // Set up Timer A 0.1(P1.2) for output
        P1SEL |= BIT2;      // P1.2 special function
        SFRIE1 |= WDTIE;    // Enable WDT interrupt
    
        P1DIR &= ~BIT1;     // set P1.1 as input (SW2)
        P1REN |= BIT1;      // enable pull-up resistor
        P1OUT |= BIT1;      // required for proper IO
        P1IE |= BIT1;       // enable interrupt at P1.1
        P1IES |= BIT1;      // enable hi->lo edge for interrupt
        P1IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        P2DIR &= ~BIT1;     // set P2.1 as input (SW1)
        P2REN |= BIT1;      // enable pull-up resistor
        P2OUT |= BIT1;      // required for proper IO
        P2IE |= BIT1;       // enable interrupt at P2.1
        P2IES |= BIT1;      // enable hi->lo edge for interrupt
        P2IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        TA0CCR0 = 350;
        TA0CCTL1 = OUTMOD_7;
        TA0CCR1 = 0;
    
        TA0CTL = TASSEL_1 + MC_1;
    
        while(1){}  // Sit here and wait
    }
    
    #pragma vector = WDT_VECTOR
    __interrupt void watchdog_timer(void)
    {
        volatile signed int i = 0;
        for(i = 1; i < 309; i += 5){
            TA0CCR1 = i;
            _delay_ms(50);
        }
    
        for(i = 309-1; i > 0; i -= 5){
            TA0CCR1 = i;
            _delay_ms(50);
        }
    }
    
    // this ISR handles the SW1 key press
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
        // let us clear the flag
        P2IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW1 is not pressed, return
        if((P2IN&BIT1)!=0x00)
        return;
        WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
    }
    
    // this ISR handles the SW2 key press
    #pragma vector = PORT1_VECTOR
    __interrupt void PORT1_ISR(void)
    {
        // let us clear the flag
        P1IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW2 is not pressed, return
        if((P1IN&BIT1)!=0x00)
        return;
        WDTCTL = WDT_MDLY_32;   //Set WDT interval
    }
    

  • 1) Interrupts are disabled on entry to an ISR. So while watchdog_timer() is running, the buttons won't interrupt it. That's one reason for having ISRs be very short.

    2) The Watchdog interval is 32ms, but the ISR takes 6 seconds. By the time it's finished, the WDT will have triggered another interrupt. WDTIFG's priority is higher than either of the Port IFGs [Ref data sheet (SLAS590N) Table 6-1], so it will (always) go first, and the Port ISRs will never run.

    I suggest you move the fading code (back) into main() and have the buttons set an on/off byte which controls how the fading loops work.

  • Oh I see.  Trying that was impossible in the first place.  I changed it back to having the loop in main, and I tried making a simple int variable to act as a 0/1 flag.  My buttons still don't pause/restart the fade for some reason.  Instead, SW1 causes the LED to pause after a full fade cycle while SW2 fails to restart it.  Here is my updated code:

    #include <msp430.h>
    
    volatile signed int i = 0;
    volatile unsigned int j = 1;
    
    void _delay_ms(volatile unsigned int length)
    {
        volatile unsigned int delay = 0;
        for(delay = 0; delay < length; delay++)
        {
            _delay_cycles(1000);
        }
    }
    
    int main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;   // Stop watchdog timer
        _EINT();                    // enable interrupts
    
        // **NOTE: This setup requires putting a jumper between LED1 and P1.2 on the board**
    
        P1DIR |= BIT2;      // Set up Timer A 0.1(P1.2) for output
        P1SEL |= BIT2;      // P1.2 special function
    
        P1DIR &= ~BIT1;     // set P1.1 as input (SW2)
        P1REN |= BIT1;      // enable pull-up resistor
        P1OUT |= BIT1;      // required for proper IO
        P1IE |= BIT1;       // enable interrupt at P1.1
        P1IES |= BIT1;      // enable hi->lo edge for interrupt
        P1IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        P2DIR &= ~BIT1;     // set P2.1 as input (SW1)
        P2REN |= BIT1;      // enable pull-up resistor
        P2OUT |= BIT1;      // required for proper IO
        P2IE |= BIT1;       // enable interrupt at P2.1
        P2IES |= BIT1;      // enable hi->lo edge for interrupt
        P2IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        TA0CCR0 = 350;
        TA0CCTL1 = OUTMOD_7;    // Timer A in up/down mode
        TA0CCR1 = 0;
    
        TA0CTL = TASSEL_1 + MC_1;
    
        while(j == 1)  // Sit here and wait for interrupt
        {
            for(i = 1; i < 309; i += 5){
                TA0CCR1 = i;
                _delay_ms(50);
            }
    
            for(i = 309-1; i > 0; i -= 5){
                TA0CCR1 = i;
                _delay_ms(50);
            }
        }
    }
    
    // this ISR handles the SW1 key press
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
        // let us clear the flag
        P2IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW1 is not pressed, return
        if((P2IN&BIT1)!=0x00)
        {
            return;
        }
        // Pause fading
        if(j == 1)
        {
            j = 0;
        }
    }
    
    // this ISR handles the SW2 key press
    #pragma vector = PORT1_VECTOR
    __interrupt void PORT1_ISR(void)
    {
        // let us clear the flag
        P1IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW2 is not pressed, return
        if((P1IN&BIT1)!=0x00)
        {
            return;
        }
        // Continue fading
        if(j == 0)
        {
            j = 1;
        }
    }
    

  • Okay, I have it VERY close to proper operation.  I changed my loop a bit to account for a coding error.  Now, the behavior is such that SW1 always pauses the fade, but SW2 randomly decides the direction of the fade when it resumes.  Sometimes when I press it, it will resume the fade in the direction it was going, and sometimes it will invert the direction of the fade.

    #include <msp430.h>
    
    volatile signed int i = 0;
    volatile unsigned int j = 1;
    
    void _delay_ms(volatile unsigned int length)
    {
        volatile unsigned int delay = 0;
        for(delay = 0; delay < length; delay++)
        {
            _delay_cycles(1000);
        }
    }
    
    int main(void)
    {
        WDTCTL = WDTPW + WDTHOLD;   // Stop watchdog timer
        _EINT();                    // enable interrupts
    
        // **NOTE: This setup requires putting a jumper between LED1 and P1.2 on the board**
    
        P1DIR |= BIT2;      // Set up Timer A 0.1(P1.2) for output
        P1SEL |= BIT2;      // P1.2 special function
    
        P1DIR &= ~BIT1;     // set P1.1 as input (SW2)
        P1REN |= BIT1;      // enable pull-up resistor
        P1OUT |= BIT1;      // required for proper IO
        P1IE |= BIT1;       // enable interrupt at P1.1
        P1IES |= BIT1;      // enable hi->lo edge for interrupt
        P1IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        P2DIR &= ~BIT1;     // set P2.1 as input (SW1)
        P2REN |= BIT1;      // enable pull-up resistor
        P2OUT |= BIT1;      // required for proper IO
        P2IE |= BIT1;       // enable interrupt at P2.1
        P2IES |= BIT1;      // enable hi->lo edge for interrupt
        P2IFG &= ~BIT1;     // clear any erroneous interrupt flag
    
        TA0CCR0 = 350;
        TA0CCTL1 = OUTMOD_7;    // Timer A in up/down mode
        TA0CCR1 = 0;
    
        TA0CTL = TASSEL_1 + MC_1;
    
        while(1)  // Sit here and wait for interrupt
        {
            for(i; j == 1 && i < 309; i += 5)
            {
                TA0CCR1 = i;
                _delay_ms(50);
            }
    
            for(i; j == 1 && i > 0; i -= 5){
                TA0CCR1 = i;
                _delay_ms(50);
            }
        }
    }
    
    // this ISR handles the SW1 key press
    #pragma vector = PORT2_VECTOR
    __interrupt void PORT2_ISR(void)
    {
        // let us clear the flag
        P2IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW1 is not pressed, return
        if((P2IN&BIT1)!=0x00)
        {
            return;
        }
        // Pause fading
        if(j == 1)
        {
            j = 0;
        }
    }
    
    // this ISR handles the SW2 key press
    #pragma vector = PORT1_VECTOR
    __interrupt void PORT1_ISR(void)
    {
        // let us clear the flag
        P1IFG &= ~BIT1;
    
        //debouncing section
        __delay_cycles(25000);
    
        // if SW2 is not pressed, return
        if((P1IN&BIT1)!=0x00)
        {
            return;
        }
        // Continue fading
        if(j == 0)
        {
            j = 1;
        }
    }
    

**Attention** This is a public forum