Search code examples
cmsp430

MSP430G2553 Timer Intervals


After reading the text about five times and googling I've decided to reach out for help. I'm currently in the process of using Timer_A interrupt to turn on/off two LEDS in intervals of 1 second/10 seconds/1 minute one at a time. The default program will turn on/off the LEDS every second but I cannot find a way to turn them off after 10 seconds and a minute. I can use __delay_cycles(xxxx) to achieve this but apparently doing so would defeat the purpose of the timer. This is my code.

#include <msp430.h>

#define RedLED BIT0
#define GreenLED BIT6

#define RedLEDToggle (P1OUT ^= RedLED)
#define GreenLEDToggle (P1OUT ^= GreenLED)

unsigned int counter = 0;


void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;
    //WDTCTL = WDT_MDLY_32;

    P1DIR = RedLED | GreenLED;
    P1OUT = RedLED | GreenLED;

    TACTL = TASSEL_2 | ID_3 | MC_3 | TAIE;

    TACCR0 = 62500;

    _enable_interrupts();


    LPM1;
}

#pragma vector=TIMER0_A1_VECTOR

__interrupt void Timer_A(void)
{

if ( counter == 10)
{
switch (TAIV)
    {
    case 0x02: break;
    case 0x04: break;
    case 0x0A: RedLEDToggle | GreenLEDToggle;
        break;
    }
}
else
{
counter ++;
}       
}

Solution

  • To achieve 10 second interrupt interval, you need to apply input divider to the timer. It is not possible to achieve 1 minute without peripheral support (see the other answers on how to implement that with a software counter).

    The problem is that msp430 microcontrollers have 16-bit registers, not capable of holding numerical values larger than 65535. Using low-frequency oscillator running at 32768 Hz (as is typical - you don't provide any details about the hardware clock sources of your system, if they have a different frequency, please mention that) the register overflows once every 2 seconds unless an input divider is applied. The maximum value of input divider on MSP430x2xxx family MCUs is 8, so it's not possible to set a hardware timer more than 8 * 2 = 16 seconds in the future. Refer to MSP430x2xxx family user's guide for further details.

    This code calls the interrupt once 10 seconds:

    #include <msp430.h>
    
    #define RedLED BIT0
    #define GreenLED BIT6
    
    #define RedLEDToggle (P1OUT ^= RedLED)
    #define GreenLEDToggle (P1OUT ^= GreenLED)
    
    // 10 seconds, assuming 32768 Hz ACLK source and divider 8
    #define TIMER_PERIOD (10u * (32768 / 8))
    
    void main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;
    
        P1DIR = RedLED | GreenLED;
        P1OUT = RedLED | GreenLED;
    
        // reset timer A config (not strictly needed)
        TACTL = TACLR;
    
        // ACLK as clock source, divider 8, continuous mode, interrupt enabled
        TACTL = TASSEL_1 | ID_3 | MC_2 | TAIE;
    
        // set the period
        TACCR1 = TIMER_PERIOD;
    
        // enable capture/compare interrupts for CCR1
        TACCTL1 = CCIE;
    
        _enable_interrupts();
    
        LPM1;
    }
    
    #pragma vector=TIMER0_A1_VECTOR
    
    __interrupt void Timer_A(void)
    {
        switch (TAIV) {
        case 0x02:
            // CCR1 interrupt
            RedLEDToggle;
            GreenLEDToggle;
            // set the time of the next interrupt
            TACCR1 += TIMER_PERIOD;
            break;
        }
    }