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.

Problem dealing with multiple interrupts on the MSP430FR5739: UART and Timer_A

Other Parts Discussed in Thread: MSP430FR5739

Hello forum,

   My project consists of having a number of robots communicating among each other and saving the received data on to an SD Card. The robot  needs to keep its "ears open" meaning, I need to allow interrupts on one of the UART's RX while at same time keeping count of my "clock" through a Timer_A interrupt. The Timer_A interrupt simply increases a variable every second using a 37, 628Hz crystal as my ACLK source. After receiving data, the robot saves the it on to the SD card via the second UART of the MSP430FR5739. The problem I have is that if I ran the Timer_A interrupt, the UART's RX almost never receives data even though I know I'm sending data. 

  How can I allow the "interbot" driven UART's RX continuously listen to other robots and at the same time keep my time?

Below part of the code I'm working on.

/*
* main.c
*/

#include "msp430fr5739.h"
#include "common_functions.h"
#include "common_variables.h"
#include <stdio.h>
#include <stdlib.h>

void genPacket(void);
void txPacket(char *buffer);
void parsePacket(void);
void broadCast(void);
void savingToSdCard(void);


int sec = 0;
int min = 0;
int hrs = 0;

int initCorrect = 0;

char buff[28] = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@";

int keepCounting = 1;

void main(void) {

initClocks();
initUARTSdCard();
initUARTBot();

initLEDs();
initLEDWait(); // Sleep for 5 sec: 5*8MHz.
initUartBuffer();

_EINT();

initCorrect = 1;

setupTimer();

OperationMode = Counting;

while(initCorrect){

switch (OperationMode) {

case Broadcasting:
broadCast();
break;

case Saving:
savingToSdCard();
break;

case Counting:
keepCounting = 1; // Allow timer interruption.
__bis_SR_register(LPM3_bits + GIE);
break;

default:
OperationMode = Counting;
break;
}
}

}

void genPacket(void)
{

// generates the packet to be sent

}

void txPacket(char *buffer)
{
//Sends packet through dedicated "inter-bot" UART

}

void parsePacket(void)

 // Parses received packet  through dedicated "inter-bot" UART

}

void broadCast(void)
{
genPacket();
txPacket(buff);
OperationMode = Counting;
}

void savingToSdCard(void) // Saves received data on to SD card and operates on the packet
{
turnSdCard(ON);
writeDataToSDFile("append myData.txt", uartBuffer, 1);
turnSdCard(OFF);

parsePacket();

OperationMode = Counting;
}

// Receives data from other robots
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
switch(__even_in_range(UCA0IV,0x08)) // Tells the compiler that UCAxIV can take only even values up to 0x08 to make a more efficient jump table
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG

keepCounting = 0;

if (!pcktStartFlagBot && UCA0RXBUF == START_BYTE) {
pcktStartFlagBot = 1;
dataLength = 0; 
}
else if (pcktStartFlagBot && UCA0RXBUF != END_BYTE) {
uartBuffer[dataLength] = UCA0RXBUF;
dataLength++;
}
else if (pcktStartFlagBot && UCA0RXBUF == END_BYTE) {
pcktStartFlagBot = 0; //Reset framing
OperationMode = Saving; //Set flag to operate on received data package
}
break;

case 4:break; // Vector 4 - TXIFG
default: break;
}

//__bic_SR_register_on_exit(LPM3_bits+GIE); // Restores active mode on return
}

// Receives data from the SD card
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
{
switch(__even_in_range(UCA1IV,0x08))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG

byteRX_SD = UCA1RXBUF; // Store RXed character

if (!pcktStartFlagSD && byteRX_SD == START_BYTE) {
pcktStartFlagSD = 1;
dataLength = 0; 
}
else if (pcktStartFlagSD && byteRX_SD != END_BYTE) {
uartBuffer[dataLength] = byteRX_SD;
dataLength++;
}
else if (pcktStartFlagSD && byteRX_SD == END_BYTE) {
pcktStartFlagSD = 0;
}

break;

case 4:break; // Vector 4 - TXIFG
default: break;
}

//__bic_SR_register_on_exit(LPM3_bits+GIE); // Restores active mode on return
}

// After 37628 ticks, it increases the second counter
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0(void)
{

if (keepCounting) {
sec++;
if (sec == 59) { sec = 0; min ++; }
if ((sec % 10) == 0) {
OperationMode = Broadcasting; // Set flag to operate on received data package
}
if (min == 59) { min = 0; hrs++; }
if (hrs == 23) { hrs = 0; }

blinkLED4(1);
}

__bic_SR_register_on_exit(LPM3_bits+GIE); // Restores active mode on return
}

///>>>Included in common_functions.h<<<<//

void initClocks(void)
{
WDTCTL = WDTPW + WDTHOLD; // stop watchdog

// XT1 Setup
PJSEL0 |= BIT4 + BIT5;

CSCTL0_H = 0xA5;
CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting: 8MHz, DCOSEL = 0 if 1, then DCO = 24MHz
CSCTL2 = SELA_0 + SELS_3 + SELM_3; // set ACLK = XT1; MCLK = DCO
CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; // set all dividers
CSCTL4 |= XT1DRIVE_0;
CSCTL4 &= ~XT1OFF;

do
{
CSCTL5 &= ~XT1OFFG;
// Clear XT1 fault flag
SFRIFG1 &= ~OFIFG;
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
}

void initUARTBot(void)
{
// Configure UART 0
UCA0CTL1 |= UCSWRST;
UCA0CTL1 = UCSSEL_2; // Set SMCLK = 8MHz as UCBRCLK
UCA0BR0 = 52; // (8000000Hz / 9600bps) / 16 = 52.083
UCA0BR1 = 0;
// OS16 enabled because we are using SMCLK @ 8MHz High Freq.
// 52.083-52 = 0.083 *16 = 1.33
// UCBRSx value 0.3335= 0x42 (See UG)
UCA0MCTLW = 0x4911 ; // UCBRFx = 1, UCBRSx = 0x49, UCOS16 = 1 (Refer User Guide)
UCA0CTL1 &= ~UCSWRST; // Release from reset

// Configure UART pins
P2SEL1 |= UART_RXBot + UART_TXBot;
P2SEL0 &= ~(UART_RXBot + UART_TXBot);

UCA0IE |= UCRXIE; // Enable RX interrupt
}

void initUARTSdCard(void)
{
// Configure UART 1
UCA1CTL1 |= UCSWRST;
UCA1CTL1 = UCSSEL_2; // Set SMCLK = 8MHz as UCBRCLK
UCA1BR0 = 52; // (8000000Hz / 9600bps) / 16 = 52.083
UCA1BR1 = 0;
// OS16 enabled because we are using SMCLK @ 8MHz High Freq.
// 52.083-52 = 0.083 *16 = 1.33
// UCBRSx value 0.3335= 0x42 (See UG)
UCA1MCTLW = 0x4911 ; // UCBRFx = 1, UCBRSx = 0x49, UCOS16 = 1 (Refer User Guide)
UCA1CTL1 &= ~UCSWRST; // Release from reset

// Configure UART pins
P2SEL1 |= UART_RXSd + UART_TXSd;
P2SEL0 &= ~(UART_RXSd + UART_TXSd);

UCA1IE |= UCRXIE; // Enable RX interrupt
}

void setupTimer(void)
{
TA0CCTL0 = CCIE; // Enable clock interrupt
TA0CCR0 = 32768-1; // Count from 0-32767
TA0CTL = TASSEL_1 + MC_1 + TACLR; // + TAIE; // Start Timer from ACLK(XTAL@32.768kHZ), Up Mode, clear
}

  • Hi Andres,

    It seems to me you're trying to do too much inside the Timer_A interrupt handler. You have a modulo nested inside, which is very expensive (both size and speed) on the MSP430 (no hardware divide). Also, near the end you called an external function, blinkLED4(). Presumably this function takes up at least several milliseconds, else you would not notice the blink. All this combined hogs the CPU from servicing any other interrupt, meaning that you'll lose almost all the data from the UART.

    Tony

  • Hi Tony, 

       Yes, you are right. Also, after reading the response from Jens-Michel Gross in this thread (http://tinyurl.com/cuovtpq)  I simply left the "sec++;" line inside the Timer_A interrupt and I'm moving the rest of the code over to the while inside of my main routine. Any further suggestions on how to keep time (besides the RTC which seems to be poorly documented in terms of examples)?

    Andres

  • Hi Andres,

    The RTC on the MSP430FR5739 looks like one of those "smart" peripherals where it starts counting seconds as soon as LFXT1 is up. Try reading from the calendar registers and see if that's the case.

    You can also co-opt the WDT as an interval timer if you're not using the watchdog. It can generate eight different interrupt intervals, from 1.95ms to 18h12m16s.

    Or you can just stick with your current Timer_A setup, but instead of calculating the minutes and hours, it may be better to just reference w.r.t. seconds elapsed since last event and so on.

    Hope this helps.

    Tony

**Attention** This is a public forum