MSP430 Timer Function to Delay an LED

132 Views Asked by At

I am trying to write a function for another program that implements one of the timers for the MSP430FR2355 board. I would like to be able to:

  1. Turn on my LED
  2. Start a timer that runs in the background
  3. Turn off the LED once the timer is up

Below is my code that should outline what I need. Again, this is for another project but I need to be able to work with timers before I can use them with my other code.

The code below initializes the LED and the timer and has three other helper functions:

  1. A function to turn on my LED
  2. A function to turn off my LED
  3. And a function to start the timer. (takes a parameter of the delay in milliseconds)

I would just like the code to run once, turn the LED on, wait 10 seconds, and then turn the LED off. The problem is that no matter what I put for the delay, the interrupt statement is always hit in about 2 seconds and I dont know why.

Any help would be appreciated.

#include <msp430.h>
#include <stdbool.h>

#define YELLOW_LED_PIN BIT4

volatile bool timerExpired = false;

void initialize() {
    P1DIR |= YELLOW_LED_PIN;
    P1OUT &= ~YELLOW_LED_PIN;

    // Configure Timer
    TB0CTL |= TBCLR;
    TB0CTL |= TBSSEL__ACLK;
    TB0CTL |= MC__UP;
    TB0CCTL0 |= CCIE;  // Enable Timer_A interrupt
    __enable_interrupt();  // Enable global interrupts
}

void turnOnYellowLED() {
    P1OUT |= YELLOW_LED_PIN;
}

void turnOffYellowLED() {
    P1OUT &= ~YELLOW_LED_PIN;
}

void setTimer(int timerMS) {
    // Convert milliseconds to timer counts (ACLK = 32.768 kHz)
    TB0CCR0 = (timerMS * 32.768);

    // Start the timer
    TB0CTL |= MC__UP;

    // Reset the flag
    timerExpired = false;
}

int main(void) {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    initialize();

    turnOnYellowLED();
    // Example: Set a timer for 5000 ms (5 seconds)
    setTimer(10000);

    while (1) {
        // Your main loop logic here


        // Check if the timer has expired
        if (timerExpired) {
            // Timer expired, do something
            turnOffYellowLED();
            // Additional actions...
        }
    }

    return 0;
}

#pragma vector = TIMER0_B0_VECTOR
__interrupt void ISR_TB0_CCR0(void) {
    // Timer_A0 interrupt service routine
    TB0CTL &= ~MC__UP;    // Stop the timer
    TB0CCTL0 &= ~CCIFG;   // Clear interrupt flag
    timerExpired = true;  // Set the flag indicating that the timer has expired
}

1

There are 1 best solutions below

0
emiled On
  1. When computing the compare value for your timer, you perform a multiplication of a floating point number and an integer. The result of this will be a float, which will then be truncated to the lower integer. The problem is that if the value is bigger than 65535 (0xFFFFu), it leads to undefined behaviour. See section 6.3.1.4 of the C standard:

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.

If you are lucky, the implementer of the compiler saturates this value to the maximum value representable, in this case 0xFFFF. This would explain why you get a two seconds interrupt (65535 counts at 32.768kHz is 2 seconds).

  1. If you want delays longer than 2 seconds you have to use a prescaler for the timer clock. This would be the ID bits of the TB0CTL. For example if you set these bits to 0b11, you can have delays up to 16 seconds. See in the reference manual on page 409 for more details. If you need longer delays, you will have to set the source clock for your timer to SMCLK, configure SMCLK to be sourced from the REFO and divide this further using the DIVM bits (see page 101 of the reference manual).

  2. You are setting a flag manually to indicate that the interrupt was serviced and polling it in the main loop. This is unnecessary because you could just poll the TBIFG flag from the TB0CTL register. This way you would not even need to implement the ISR.