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.

Receiving multiple bytes from UART problem

Other Parts Discussed in Thread: MSP430F5529

Hi there, I'm currently trying to implement UART code on an MSP430f5529 launchpad to communicated with an OBD2-UART board from sparkfun (https://www.sparkfun.com/products/9555).

I can confirm that the transmit function is working as the board fully acknowledges the first transmit. My problem lies in receiving bytes from the board. At the moment my function UART_transmit() works correctly, but when UART_receive() is called when it hits  __bis_SR_register(LPM0_bits + GIE) (lets call this point 1), the program automatically skips to the __bic_SR_register_on_exit(LPM0_bits + GIE) instruction in the RXIE interrupt (I'll label this point 2). At this point the program gets stuck and refuses to continue.

#include "msp430x552x.h"
//#include "delay.h"
#include <stdlib.h>
#include <stdio.h>


unsigned int _rxCounter =0;
char rx[50];

unsigned char *transmit;
unsigned char currChar;
unsigned char charCount;
unsigned char newChar;

int UART_isBusy(void);
void UART_receive(void);
void UART_transmit(unsigned char *cmd, unsigned char count);

void main(void)
{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  P3SEL = BIT3+BIT4;                        // P3.4,5 = USCI_A0 TXD/RXD
  UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
  UCA0CTL1 |= UCSSEL_2;                     // SMCLK
  UCA0BR0 = 6;                              // 1MHz 9600 (see User's Guide)
  UCA0BR1 = 0;                              // 1MHz 9600
  UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;   // Modln UCBRSx=0, UCBRFx=0,
                                              // over sampling
  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  //UCA0IE |= UCRXIE;

   //__enable_interrupt();


  UART_transmit("ATZ\r", 4);
  UART_receive();
  UART_transmit("ATSP0\r", 6);
  //rx[0] = '\0';
  UART_receive();
  UART_receive();
  UART_transmit("0100\r", 5);
  UART_receive();
  UART_receive();

  while(1);

  //__bis_SR_register(LPM0_bits + GIE);       // Enter LPM0, interrupts enabled
  //__no_operation();                         // For debugger
}

void UART_transmit(unsigned char *cmd, unsigned char count)
{
    transmit = cmd;
    charCount = count;
    UCA0IE |= UCTXIE;

    __bis_SR_register(LPM0_bits + GIE);
    __no_operation();
	//while(UART_isBusy());						//Trap function while transmitting. Note this may not be necessary, if not working comment out
}

void UART_receive(void)
{
    UCA0IE |= UCRXIE;

    __bis_SR_register(LPM0_bits + GIE);				//POINT 1
    __no_operation();
	//while (UART_isBusy());						//Trap function while receiving. Note this may not be necessary, if not working comment out

}

int UART_isBusy(void)
{
	return (UCA0STAT & UCBUSY);
}

// Echo back RXed character, confirm TX buffer is ready first
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
    switch(__even_in_range(UCA0IV,4)){
    case 0:break;
    case 2:
    	newChar = UCA0RXBUF;
		if (newChar == '\r') {
			//rx[_rxCounter] = '\0';					//null terminate received string
			_rxCounter = 0;							//Reset rxCounter for next received string
			UCA0IE &= ~UCRXIE;
			__bic_SR_register_on_exit(LPM0_bits + GIE);	// POINT 2, Exit LPM
		}
		else {
			rx[_rxCounter++] = newChar;
		}
        break;
    case 4:
        if(charCount) {
            UCA0TXBUF = *transmit++;
            while (!(UCA0IFG&UCTXIFG));             // USCI_A0 TX buffer ready?
            charCount--;
        }
        else {
			UCA0IE &= ~UCTXIE;						//Disable TX interrupts
            __bic_SR_register_on_exit(LPM0_bits + GIE);	//Exit LPM
            __delay_cycles(1000000);
            //UCA0TXBUF = 0x00;
        }
        break;
    default: break;
    }
}

Help would be greatly appreciated!

Regards, Anmol Thind

  • Hi I'd just like to update this post before people spend time on it!

    I've managed to get the receiving working by switching to a polling based method for UART_receive() instead of an interrupt driven method. I'm not sure why this makes a difference but the program is functioning well now.

  • One thing is that the compiler doesn’t know that the ISR magically changes your global variables, without any apparent function call in the main code. TO tell that some variables may behave erratically, you need to declare them volatile. Do so for all global vars that are read or written inside an ISR. It prevents the compiler from delaying writes or using a copy of the var in a processor register.

    Also, it is not really a good idea to reset _rx_counter in your ISR when an CR is detected. This way, main cannot know how much data was received. At least terminate the string with a ‘0’ then (compatible with the standard string functions).

**Attention** This is a public forum