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.

MSP430 UART how to send/ receive multiple bytes?

Other Parts Discussed in Thread: MSP430WARE, MSP430G2553

hi,

How to send and receive multiple bytes in 1 shot? 

Now I'm using UCA0RX to receive 1 byte and send out through UCA1TX. I want to make it 4 byte, how to do that?

Is there any macro to do that? 

Thanks

Regards,

Ong

  • The USCI module buffers are only a single byte, so you will have to write a driver that handles the transmission of multiple bytes.

    In its simplest form of UART (using active state wait), something like this should work to transmit data

    unsigned char uartSend(unsigned char *pucData, unsigned char ucLength) 
    {
      while(ucLength--)
      {
        // Wait for TX buffer to be ready for new data
        while(!(UCA1IFG & UCTXIFG));
    
        // Push data to TX buffer
        UCA1TXBUF = *pucData;
    
        // Update variables
        ucLength--;
        pucData++;
      }
    
      // Wait until the last byte is completely sent
      while(UCA1STAT & UCBUSY);
    }
    Edit: Fixed typo in the above function

    On the receiving side (using active state wait), one should wait until the UCRXIFG flag is set, then read the content of the of the RX buffer.

    Note that it is a much better method to use interrupt driven UART/SPI.

    There are several examples in the MSP430ware found at http://www.ti.com/tool/msp430ware

    Hope this helps!

    Br,
    ABO 

    --
    PS. Thank you for clicking  Verify Answer  below if this answered your question!

  • Hi,

     If I want to send 2 bytes of data like 0x21 and 0x38, I have to write uartSend(0x2138,2); ?

    Thanks

  • Chu En Ong said:
    If I want to send 2 bytes of data like 0x21 and 0x38, I have to write uartSend(0x2138,2); ?

    No.

    In 'C' programming, the parameters that you pass when you call a function must match what the function is expecting - as shown in its prototype and/or definition.

    Look at the prototype of TIABO's suggested uartSend() function:

    TIABO said:
    unsigned char uartSend( unsigned char *pucData, unsigned char ucLength );

    What do you notice about the first parameter...?

  • Oops - typo:

    TIABO said:
    unsigned char uartSend( unsigned char *pucData, unsigned char ucLength ) 
    {
      while(ucLength--)
      {
        // Wait for TX buffer to be ready for new data
        while(!(UCA1IFG & UCTXIFG));
    
        // Push data to TX buffer
        UCA1TXBUF = pucData;   // pucData is a pointer! 
    
    

     
    Maybe that confused the OP?
  • If I want to pass the value in hexadecimal instead of ASCII number? How to do that?

    Thanks

  • As suggested, I do believe my suggested function contains a typo:

    unsigned char uartSend( unsigned char *pucData, unsigned char ucLength ) 
    { 
      while(ucLength--) 
      { 
        // Wait for TX buffer to be ready for new data 
        while(!(UCA1IFG & UCTXIFG)); 
    
        // Push data to TX buffer 
        UCA1TXBUF = *pucData; // Assigning the value pointed to by pucData to register UCA1TXBUF
      }
    }
    

    Chu En Ong said:
    I want to pass the value in hexadecimal instead of ASCII number? How to do that?

    If you want to send two bytes using the above function, you should do something like this:

      unsigned char dataArray[2] = {0x42, 0x43}; // Variable dataArray is now an unsigned char pointer (the type accepted by the function)
      uartSend(dataArray, 2);

    If you want to send a signle byte, stored in a variable of type unsigned char, you do something like this:

      unsigned char data = 0x42;
      uartSend(&data, 1); // The & in front of data means we're passing the address (i.e. pointer) of the data variable to the function.

    Br,
    ABO

  • Thanks for your help. Do you know how to receive 2 bytes of data from PC?

    The idea is receive data from PC through UCA0 and send out from MSP through UCA1.

    Now what I can do is receive 1 byte and send 2 bytes out. How to change it to receive 2 bytes?

    Here is my code. 

    #include "msp430x54x.h"

    unsigned char counter;
    unsigned int i = 0;
    unsigned char data[2]= {0x41,0x41};
    unsigned char data1[2]= {0x41,0x42};

    unsigned char uartSend(unsigned char *pucData, unsigned char ucLength)
    {
    while(ucLength)
    {
    // Wait for TX buffer to be ready for new data
    while(!(UCA1IFG & UCTXIFG));

    // Push data to TX buffer
    UCA1TXBUF = *pucData;

    // Update variables
    ucLength--;
    pucData++;
    }

    // Wait until the last byte is completely sent
    while(UCA1STAT & UCBUSY);
    }

    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    P3SEL = 0x20;
    P5SEL = 0x40; // P3.4,5 = USCI_A0 TXD/RXD
    P5DIR = 0xFF;
    P10SEL = 0x00; // P3.4,5 = USCI_A0 TXD/RXD
    P10DIR = 0xFF;
    P3DIR = 0xFF;
    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
    UCA1CTL1 |= UCSWRST; // **Put state machine in reset**
    UCA1CTL1 |= UCSSEL_2; // SMCLK
    UCA1BR0 = 6; // 1MHz 9600 (see User's Guide)
    UCA1BR1 = 0; // 1MHz 9600
    UCA1MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // Modln UCBRSx=0, UCBRFx=0,

    UCA0CTL1 &= ~UCSWRST; // over sampling
    UCA1CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
    UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

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

    }

    // Echo back RXed character, confirm TX buffer is ready first
    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    {

    counter = UCA0RXBUF;


    if(counter == 0x00)
    {
    uartSend(data ,2);
    P5OUT = 0x00;
    P3OUT = 0x00;
    P10OUT = 0x00;
    }
    else if(counter == 0x01)
    {
    uartSend(data1 ,2);
    P10OUT = 0x00;
    P5OUT = 0x00;
    P3OUT = 0x01;
    }
    else if(counter == 0x02)
    {
    UCA1TXBUF = 0xFF;
    P10OUT = 0x00;
    P5OUT = 0x00;
    P3OUT = 0x02;

    }

    }

  • Bytes are received one at the time. When a byte has been received in the UART RX FIFO, the UCAxIFG.UCRXIFG flag is set to 1.

    The MSP430 UART RX fifo is 1 byte. The best way is to use interrupts (triggering on UART RX "byte received") to copy the received byte to an internal buffer. Depending on your application, you can (a) configure a DMA channel to copy the received bytes for you (leaving more time for the CPU to do other things), or you can (b) use the CPU to copy the byte in an interrupt service routine (ISR).

    The simplest way, but the slowest, is to poll the UCAxIFG.UCRXIFG flag. So, to read two bytes, the sequence could be something like this:

    if(UCRXIFG is set) {
      // Clear the UCRXIFG flag
    
      // copy byte from RX FIFO to internal buffer
    }

    Hope this helps.

    Br,
    ABO 

  • dear;

    I have a project, due date in 10days, developing blinking cursor, help commands and pipe line all to be from shell(from CLI to control the msp430). my launchpad is g2553 series. I am newbie. any help please, especially i have no idea on the pipeline.

    thanks!

  • Garoma G. Gonfa said:
    I have a project, due date in 10days, [] I am newbie.

    Tight. Whoever gave you the project seems to think that it can be done. So either he also have the required background information or he's totally underestimating the task.

    There should be a G2553 USCI UART demo available. However, it does only echoing incoming data. it does not handle receiving or sending a data string.
    Blinking a cursor requires use of a timer to cyclic send an underline, backspace, underline etc.

    Well, building the pipeline and doing the help command is plain C and not MSP specific. The difficult part (because it deals with MSP interrupts and hardware) is stuffing the pipeline with incoming data and sending data that has been stuffed into the pipeline by the main code.

    However, this forum is full of threads dealing with UART I/O, implementation of a ringbuffer for background UART transfers etc. An dwith comments about the demo code available.

    Garoma G. Gonfa said:
    especially i have no idea on the pipeline

    Well, there are many different implementations possible.
    Pipeline might be that you just call a funciton to send a string or a single character and the function returns when it has been sent. Not very effective but easy to implement.
    On the receiving end, a simple buffer is allocated and the funciton waits until the required numbe rof bytes (or a terminating CR) has been received and then returns.
    Another implementation is using two ringbuffers which are stuffed with outgoing and incoming data while the sending ISR (interrupt service routine) empties the outgoing ringbuffer byte by byte while the main code fetches incoming data form the othe rringbuffe rbyte by byte and processes it. A very good implementation is a combination of both (stuff the ringbuffer until full, and return when all sending data has been put into the buffer)

    Anotehr possible implementaiton is a variable length buffer (complete decouplign of sender and receiver). Which can take large amounts of ram.

    Given teh low ram available on the 2553, I'd suggest going for the first solution. It's not really a pipeline as it blocks until everything is sent, but it is easiest to implement (you don't even need a TX interrupt handler). But definition of a pipeline is rather vague.

  • thanks for your suggestions; I think the professor just wanted me to bring something done hard for his own ongoing project. Yea I also don't feel comfortable with the short time period: 10days.

    anyways I will search the threads here to get the  ideas you indicated.

    BTW, the help is not only help, after somebody write help LED for instance the options come up should show number of LEDS, what the user can do, ON/OFF/TOGGLE and when the user entered one of them on the CLI, he/she should be able to put ON/OFF/Toggle the leds.

    the same is true for the ADC, and Button.

    I would be happy if i can get some code snippets in meantime, because I hope you guys have already done this stuffs while I am struggling to capture every thing in this short time while following the other courses also.

    heartfelt thanks!

  • Hi,

    I am now using MSP430F240 connecting with a wireless chip called ANT.  I can send message out, while when I am trying to receive the data sent to MSP430. There is overflow and cause a framing error for the UART. I guess it may be related with the baud rate.  I have several questions. Firstly, when UART is sending multiple datas out, does it automatically add some delay between different datas, or the delay between different datas are caused because the Tx buffer need some time to be ready for the next byte after it send out one byte?

    Second, If there is overflow for the RxBuf, which means the next byte comes before I read the first byte out from the Rx Buffer. What does it mean by reading a byte from the RxBuffer? Do I have to use a interrupt to read things from UART Rx Buffer out?

    Thanks very much.

    SiLi

  • hey all;

    I am doing a simple shell for msp430g2553. I want to on/off/toggle the leds from CLI. I have managed to send the action commands(led1 on/off/toggle), but i face a problem with the toggle.

    I have set some toggling delay but i couldn't make my shell go out of it.

    that is for instance:

    msp430>led1 on   //puts the red led on on the board

    msp430>   //i get prompt from my shell for any of my next command i want to enter

    but when i do the following:

    msp430>led1 toggle  //it toggles the led but couldn't go to the next execution after; how can i get out of this while the led is still toggling as my other commands

    i used for loop for the toggle code, but i need to limit by some control condition the execution of the program to go to the others once the toggle command is sent.

    my snippet is sth like:

    if(strcmp(buffer,"led1 toggle")==0)

    {

    for(;;)

    {

    P1OUT ^= BIT0;

    for(i=0;i<20000;i++);  //delay between the toggle

    }

    writeString('\n\r'); //i do have this function but i couldn't reach this point; it says unreachable, i understand the first for loop run to infinity but i want to give toggle command once so that the led can keep toggling and give other commands for the shell to change any instruction..i know it is somewhat conflicting.

    }

    any help is really appreciated!

    many thanks!

  • If your "toggle" command should make the LED toggle continuously, you should probably set up a timer that repeatedly generates interrupts. The interrupt service routine then should toggle the LED(s) that are to be toggled. This way you will get LEDs toggling in a timely fashion, and your CPU can handle the incoming commands.

    Alternatively, you can alter the interpretation of the toggle command - that is that it merely toggles the state of the LED (if LED 1 was off, "led1 toggle" would turn it off, if LED1 was on, "led1 toggle" would turn it on).

    Hope this helps!

    Br,
    ABO 

  • i only need the first idea because i can do the second with <led on> command

    if you know some basic codes about how to generate the interrupt and implement it with command please;

    i normally have many other commands such as help, ADC, Button, alias.Pipeline  I just want to implement them with if---else statements (to check the received commands) and implement their respective action in their separate function to be called.

    But this on/off/toggle is simple and short (i thought) and want to implement them in the if--else statement itself as i depicted in the first post.

    so would you please elaborate how to use the timer to implement the toggle command as your suggestion; i do have only three days lef

  • I suggest you look at the examples in the MSP430Ware, more specifically the timer example there (the up mode example toggles a pin on every timeout => LED). The example should get you going. http://www.ti.com/tool/msp430ware

    Here's some pseudo code on how you can do it (quick draft, probably some issues in it, but it should give you the general idea):

    uint8 ledsToggling = 0;
    
    #pragma vector=TIMER1_VECTOR
    __interupt void timerISR(void) {
     // Toggle LEDs given by ledsToggling variable
      LED_PORT ^= ledsToggling;
    }
    
    int main(void) {
     // Setup UART
      uartInit();
    
      ...
    
     // Infinite loop
      while(1) {
     // Retrieve command
        command = uartReceive();
    
     // Process command
        if(command == "led1 toggle") {
     // Add led1
          ledsToggling |= LED1_BITMASK;
    
     // configure timer to e.g. up mode
        
     // Start timer
        }
        else if(command == "led1 on") {
     // Remove LED1 from toggling leds
          ledsToggling &= ~LED1_BITMASK;
    
          if(ledsToggling == 0) {
     // Stop timer if no other leds are toggling
            timerStop();
          }
       
     // Turn led 1 on
          LED_PORT |= LED1_BITMASK;
        }
        ...
      }
    }
    
    
    Br,
    ABO 
  • First of all I would like to say many thanks! Your idea is really a massive help for me.

    thank you!!

  • Hi, in the exmple code, you should easily fnd a simple Tx interrupt. To trigger the interrupt, just make sure that you have enable GIE and TxIE. Then whenever your Txbuf is empty and ready to send another byte out, it would trigger the interrupt. So you can put your code for toggling inside the interrupt. It should work. Hope this helps.

     

  • it works ABO;

    thank u!

    I also put CCTL0=CCIE;

                    TACTL=TASSEL_2+MC_2

    and

    CCTLO = ~CCIE;

    TACTL = TASSEL_2+mc_2;

    in starts timer() and timerstop() i asked above.

    Now what I left with is giving the command >led1 led2 toggle which should able to toggle both leds alternatively/or at the same time.

    i have done it with a function call like this:

    void LED1_LED2_TOGGLE()
    {
        while(1)
        {
            P1OUT ^= BIT0;
            Delay_ms(500);
            P1OUT ^= BIT6;
        }
    }
    .....but the problem is the execution stays there forever due to the while loop which i need to break when i enter some other command.

    many thanks!

  • Hi,

    I donot know whether the question you posted just now is to reply to me, or someone else. So I just provide my opinion here. Whenever you want to stop the function in the interrupt, just Disable the TxIE outside. Or a more clever idea I think is that, put a case sentence inside your interrupt.

    Switch(i)

    case 1: LED1_LED2_TOGGLE();

    break;

    case 2: DisableTxIE();

    break;

    default: break;

     

    Then make i to 1 at the beginning of your program. Wheneve you want to stop that function, just change i to 2 in the main program. Then do the things you want. After that change i back to 1 when you need.Hope it helps.

  • Besides,when you change it back to 1, remember to enable TXIE again also

  • si li1,

    Yes, this thread has wandered somewhat off from the initial topic, but I'm currently unable to split it into two threads.

    I was trying to help Gada G. with his problem.

    Gada: 

    The idea is that you

    • in main() context configures the timer.
    • The timer will trigger interrupts
    • The interrupt service routine (ISR) toggles the LED
    • in main() context you set which LEDs should be toggled in the ISR

    The point with the "ledsToggling" variable was that you could have multiple LEDs toggling at the same time. As si li1 suggested, you can have a switch case in your interrupt service routine. By using a timer to set the toggling intervals, you do not need an infinite while loop in main context.

    You should try to play around with this. And again, the MSP430Ware examples will, I think, help you out a lot.

    Br,
    ABO 

  • Thank you guys, your ideas made me fix the issues i raised.

    It is a school project to be delivered next Monday(a kind of tight time limit with classes)  and I am a bit new to it.

    Now I am trying to display the content of ADC10MEM (strings of 0's and 1's) to my terminal after the ADC finish the conversion.

    The idea is the user is prompted to choose the channel [ i am a little confused with what channel is] and then supposed to see the binary string on the terminal back.

    i have normally two functions writechar(ch) and writestring(*str) which can display string of characters.

    I would be happy if you say me something on how to get the contents of ADC10MEM register and send it to the terminal as strings of 1's and o's.

    thanks a lot!

  • Again, see the MSP430Ware examples (e.g. adc).

    Converting a hexadecimal value into strings is a good exercise. (tips: bitshift hex value and put '1' or '0' based on least significant bit).

    Br,
    ABO 

  • yea, i have seen all the sample examples on slac485a about ADC i downloaded with CCS v5.2, but i couldn't see something about conversion or display. For me it is okay if i can display on my terminal hexadecimal or binary.

    this may be my last request please.

    thanks!

  • So you've figured out the ADC, thats great.

    To covert a hexadecimal value into a string of 1s and 0s, something like this would work (Printing most significant bit first).

    unsigned char adcValue = adcRead();
    unsigned char i, tmp;
    // Signal that number to come is binary by prepending a 'b'
    uartPut("b", 1);

    for(i=0; i<8; i++) {
    // Bitshift left i times and look only at most significant bit tmp = (adcValue << i) & 0x80;
    if(tmp == 0) {
    uartPut('0', 1);
    } else {
    uartPut('1', 1);
    }
    }

    // Write a new line character
    uartPut('\n', 1);

    I'm having major trouble with the text editor today, so bear with me on the formatting.

    Hope this helps!

    Br,
    ABO 

  • thank you ABO;

    I have run the ADC examples successfully, changed the parameters and played with it; it was okay and I think I have understood how the ADC normally works.

    But my project is a bit different and it is:

    1.a user is asked to select the input channel from CLI[1,2,3,4,5,6,7,8,9,10] 

    2.the program do a single conversion for that specific channel.

    3. the program send back to the terminal the binary or hexadecimal result of the conversion as string.

    your pseudo code above is really helping thanks a lot.

  • hi;

    Now i am trying to enable/disable the button on(p1.3) from CLI(my shell).

    Is there a way to change the states from low to high or vice versa by command? any hint please.

    thanks!

  • Gada G. said:
    Now i am trying to enable/disable the button on(p1.3) from CLI(my shell).

    If you want to disable the button, make the microcontroller ignore the signal toggling on P1.3.

    Gada G. said:
    Is there a way to change the states from low to high or vice versa by command? any hint please.

    The answer is yes (you can configure the state of GPIOs using Px, PxSEL, PxDIR registers), but what does this have to do with enabling/disabling the button?

    Br,
    ABO 

  • Hello all,

    I am trying to receive binary format file(.der ), file size: 693bytes  from  PC to board using MSP430UART using .And  send back file again from board. I have referred the answers here and also I have gone through example codes.

    My implementation is as follows,

    1. I used separate program for serialport communication, that will send file to board.

    2. below code for the board should receive the file and transmit back the file contents to PC.

    3. Using program for serialport communication, I can see the bytes received from the board to PC.

    I checked various ways for my work on the below code. Still need  about whether there is mistake in code. May i know about whether this code work for receiving 693 bytes binary file type?

    Also while receiving file byte by byte, i need to specify the stop byte in the code. After that file will be transmit back to PC. Any body please help me how can i specify stop bit for binary formatted file.

    This is my code,

    //Send a log message to to the serial terminal

    unsigned char uartSend(unsigned char *data)

    {

        ot_uint i=0;

        ot_uint len = strlen(data);

        while(len--){

             // wait for TXBUF to complete last send...

            // UCA0TXIFG is high when UCA0TXBUF is empty

            while (!(UCA0IFG&UCTXIFG));

            {

            tx[i]=*data;

            UCA0TXBUF = tx[i];

            data++;

            i++;

            }

        }

    }

    // Echo back RXed character, confirm TX buffer is ready first

    #pragma vector=USCI_A0_VECTOR

    __interrupt void USCI_A0_ISR(void)

    {

           int i;

             switch(__even_in_range(UCA0IV,4))

             {

             case 0:

                    break;                             // Vector 0 - no interrupt

             case 2:                                   // Vector 2 - RXIFG

              i=0;

              while (!(UCA0IFG&UCTXIFG));             // USCI_A0 TX buffer ready?

              {

              rx[i]=UCA0RXBUF;

              UCA0TXBUF = rx[i];

              i++;

              UCA0RXBUF++;

                  }// TX -> RXed character

              uartSend(rx);

              break;

             case 4:break;                             // Vector 4 - TXIFG

             default: break;

             }

    }

     on overall,

    1. I am trying to echo the data received to board from PC back to PC.

    2. question about stop byte is, to check whether the content transmitted back to the PC correctly ,with out any additional special characters . I will also check the file size in my other program that  that contains system calls open, read, write for serial communication for sending file from PC and receive file back to PC,

     

  • Hi,

    Can you clarify:

    1. You are trying to echo the data received from the PC back to the PC.
    2. You mention a "stop byte", I don't exactly understand what you want it for.

    Br,
    ABO 

  • Hi ,

    thank for your prompt reply.

    file that need be send to board is in my linux virtual machine. So i used separate program that implements open,write, read calls. for sending file, to the RX , TX Code for board in Windows 7. .

    these are the answers to your questions.

    1. yes i  am trying to echo the data received to board from PC back to PC.

    2. question about stop byte is, to check whether the content transmitted back to the PC( linux virtual machine) correctly ,with out any additional special characters . I will also check the file size in my other program that  that contains system calls open, read, write for serial communication for sending file from PC and receive file back to PC,

    thank you

  • aparna vegendla said:
    1. yes i  am trying to echo the data received to board from PC back to PC.


    To make an echo, what you need to do upon ISR is to

    1. Read the UART RX buffer into a variable
    2. Wait until TX buffer can accept new byte (not necessarily the same as 'byte has been transmitted')
    3. Send received value to TX buffer
    4. Clear interrupt flags if necessary

    The implementation depends somewhat on whether you have a multibyte RX/TX FIFO. I'm no MSP430 expert, but I do not think that is the case?

    2. Send the entire file, store the received data in another and compare the two on your PC. Would that work?

    Br,
    ABO

  •  

    thank you for your clear explanation. Now i got confirmation that ISR code work well.

    While writing the program for serial port communication, I had implemented in the way that i can see the sending file and received file at linux terminal. After file back to PC, program not terminating at the linux terminal. Code for the serial port communication is implemented correctly with return statement in the main function. That is the reason why I have asked for stop bit that makes exit of program.

    If you think exit of the program will depends on serial port communication program and there would be no problem to receive back file using the code that  i have posted here, i will go through the other problem.

     

     thanks for replies.

  • 1) You should make sure your ISR is not doing too much. It is e.g. not recommended to have a while() in ISRs, in case of an error, the device will lock up (eternal while loop) in the ISR.

    2) Your PC knows how many bytes it is sending, right? Exit the program when you have received as many bytes as you have sent. Not sure I understand your problem.

    Br,
    ABO 

  • 1) thank you. I have removed while(len--) from the ISR code, now output is being displayed with out disturbing code.

    2) yes my PC knows how many bytes it is sending. As you mentioned for exiting program, i tried to modify ISR with exit(1), that terminates program after transmitting back received 693 bytes from rx. That didn't work. My project consists of  lot's of functions that output code using uart. That might causing the problem of not exiting the program. I will look into the problem.

    thank you

  • TIABO said:
    Wait until TX buffer can accept new byte (not necessarily the same as 'byte has been transmitted')

    This step can be omitted if the MSP is not sending anything on its own but only echoing. Also, any kind of busy-wainting inside an ISR is a death sin anyway.
    Since RX and TX are running with the same baudrate, you cannot receive more than you can send. Once you received a new byte, you can be sure that TXBUF is ready to accept it. There can't be an TX overflow due to slow ISR handling, because then an overflow (and therefore a dropped byte) would have appeared on the RX side already.

    If of course the echo of incoming bytes cna be interleaved with data the MSP sends on its own, then a synchronization is required. However, in this case, the current ISR would cause receive overflows anyway. RX and TX msut be decoupled with separate buffers then.

  • Hi TI Guys

    I want to send multiple bytes from the MSP430g2553 to BN055 IMU, so I use the below uartSend function…would you please check it?
    Also I would like to do pooling for the incoming bytes which are multiple. The BNO55 responds automatically when sending to it. Could you please help me with this? hence I do not want to use interrupts.

    /////////////////////////UART send multiple Bytes////////////////////
    void uartSend(unsigned char *pucData, unsigned char ucLength)
    {
    while(ucLength)
    {
    // Wait for TX buffer to be ready for new data
    while(!(IFG2 & UCA0TXIFG));//check if not set
    //if set, TX interrupt is pending
    // Push data to TX buffer
    UCA0TXBUF = *pucData;
    // Update variables
    ucLength–; //– length of data left
    pucData++; //shift pointer
    }
    // Wait until the last byte is completely sent
    while(UCA0STAT & UCBUSY); //UCBUSY indicates if USCI transmitting or receiving
    }
    unsigned char setconfigmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x00};
    uartSend(setconfigmode,5);
    delay_ms(20); // delay_ms(20)

  • "would you please check it?"

    You should know whether it works or not. If t does, fine. If not, tell us what it does (or doesn't) and what you'd expect instead.
    This is not an online code verificator. :)
    But I guess you meant "ucLength - -;"

    What do you mean with 'pooling'?
    And why don't you want to use interrupts?

    For my projects, I use two 256 byte ringbuffers. Each buffer has a read and a write counter (byte size). If I want to send someting, I write it to the send buffer, while the ISR takes a byte from the send buffer and sends it until the read counter matches the write counter.
    Receiving works the same: the ISR writes all incoming bytes to the receive buffer (incrementing the read coutner) and when I call the getc() function, a byte is read from the receive buffer until its read count matches the write count. In which case it returns an error.
    Of ocurse there are checks for buffer overflow etc. And funcitons to check whether there is data in the receive buffer or space in the send buffer etc.
    I use this in all my projects. Once done, it is as simple as using the standard C library functions for getch, putch, puts etc..
    In later versions, I have extended this with triggers for thread handling, so a thread waiting for data doesn't execute at all until there is new data arriving etc. But that's going towards an own RTOS and complete overkill if you're just doing one or two projects.
  • Hello Jens-Michael,

    Currently I am using interrupts but my program is stuck when enters one of the LPMs. You saw my code before, but here it is:

    /*
     * Acceleration.c
     *
     *  Created on: Oct 6, 2016
     *      Author: Murtadha
     */
    #include "Acceleration.h"
    // the saved value of the previous measurement
    uint8_t cached_accelerationXMSB = 0, cached_accelerationXLSB = 0;
    
    uint8_t cached_accelerationYMSB = 0, cached_accelerationYLSB = 0;
    
    uint8_t cached_accelerationZMSB = 0, cached_accelerationZLSB = 0;
    
    uint8_t* acceleration_location;		// pointer to the location used in the transmit buffer for accelerometer data
    
    
    typedef struct uart                        // UART
    {   char *bufTXpnt;                        // UART TX buffer pointer
        unsigned int TXbuflen;                  // the lenght of TX block
        char *bufRXpnt;                       // UART RX buffer pointer
    
        unsigned int RXbuflen;                  // the lenght of RX block
        char RXbuffer[8];
    } uartstruct;
    
    /////  macro to get string and string len
    #define   TXSTRING(pnt) (TXdata((pnt), sizeof(pnt)-1))
    uartstruct uart;                 // declare a struct from typedef uartstruct
    
    void TXdata( char* pnt, unsigned int len){
      uart.bufTXpnt = pnt;
      uart.TXbuflen = len;
      uart.bufRXpnt = uart.RXbuffer;         // reset it to beginning of ram buffer
      IE2 |= UCA0TXIE + UCA0RXIE;            // enable USCI_A0 TX & RX interrupt
    }
    
    ///Intilizing the UART////////////////////////////////////////////////////
    void uart_init(void){
     IE2 &= ~(UCA0TXIE | UCA0RXIE); // Disable all USCIx0 (A) TX & RX interrupts
      UCA0CTL1 = UCSWRST;           // Set UCSWRST (hold USCI in Reset state)
      UCA0CTL1 |= UCSSEL_2;                     // CLK = SMCLK
    
    //   ------------ Configuring the UART(USCI_A0) ----------------//
    //     115200 BAUD, CLK=12MHz
        		  UCA0BR0 = 6;
        		  UCA0BR1 = 0;
    //    		//*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1
    //    		  // BITS| 7 6 5 4 | 3 2 1  |   0    |
        		  // UCAxMCTL = | UCBRFx  | UCBRSx | UCOS16 |
        		  UCA0MCTL = 0x81; //this works fine
    
        UCA0CTL1 &= ~UCSWRST;             // Clear UCSWRST to enable USCI_A0-UART
        UCA0CTL1 &= ~UCSYNC;
    
      IFG2 |= UCA0TXIFG;            // preset IFG flag always left on
    
     // IE2|=UCA0RXIE;
    }
    
    //**********************************************
    //Configure clocks and clock sources
    void set_UCS() {
    	/* DCO Frequency selected */
    	/* SCLK=SMCLK  P1.5  */
    	/*	Maximum SPI frequency for burst mode is 6.5 MHz	*/
    	//Set DCO to 12 MHz calibrated and use DCO/2 for SMCLK
    	//Note that this is technically a bit too high for operation at 2.2Volts (end of battery life).  8 MHz is maximum recommended.
    	//Does not seem to be a problem at room temperature.
    	DCOCTL = CALDCO_12MHZ;		//0x7A  01111010
    								//DCOx  011
    								//MODx	11010
    
    	/* External Crystal OFF, LFEXT1 is low frequency, ACLK is Divided by 1, RSELx=1110 */
    	// Set range  0x8E  10001110
    	BCSCTL1 = CALBC1_12MHZ;
    
    	// DCO -> SMCLK (Default), SMCLK / 2; DCO -> MCLK, MCLK / 2; DCOR Internal Resistor select
    	BCSCTL2 = DIVS_1 + DIVM_1 + SELM_0; // 0x52 = 00010010
    
    	/* 0.4 to 1MHz crystal , Using VLO for ACLK, Cap selected 1pF */
    	BCSCTL3 = LFXT1S_2;
    
    	IE1 &= 0xFD; /* Disable UCS interrupt */
    
    	return;
    }
    //********************************************************************
    
    //------------------- Configure the UART Clock source -------------------//
    void set_UARTUCS() {
    	     WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog
    	     DCOCTL  = 0;             // Select lowest DCOx and MODx settings
    	     BCSCTL1 = CALBC1_12MHZ;   // Set range
    	     DCOCTL  = CALDCO_12MHZ;   // Set DCO step + modulation
    
    	     // DCO -> SMCLK (Default)
    	     IE1 &= 0xFD; /* Disable UCS interrupt */
    
    	     return;
       }
    
    //--------- Setting the UART function for P1.1 & P1.2 --------//
    void setUARTPins() {
    
    	        //    P2DIR = 0xFF; // All P2.x outputs<
    	            //P2OUT &= 0x00; // All P2.x reset
    	            P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    	            P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    
    	         //   P1OUT &= 0x00;
    	         return;
    }
    
    //¦----------------------------- Delay Function  ---------------------------------------¦
    
    // This function will give us 1ms wait time, so for getting 10 ms,
    // then delay_ms(10) will give 10ms and delay_ms(100) will give 100ms
    void delay_ms(unsigned int ms)
    {
        unsigned int i;
        for (i = 0; i<= ms; i++)
           __delay_cycles(6000); // 6000 will give us 1ms
    }
    
    //¦----------------------------- US0TX ISR  ---------------------------------------¦
    #pragma vector=USCIAB0TX_VECTOR
    __interrupt void USCIAB0TX(void)                    // Shared A0/B0 TX IRQ vector
    {
      if (IFG2 & UCA0TXIFG){                            // check for UART TX
    
        if (uart.TXbuflen){                               // if not zero
          UCA0TXBUF = *uart.bufTXpnt++;
          --uart.TXbuflen;
        }
        else IE2 &= ~UCA0TXIE;                          // suspend IE if zero
      }
      else IFG2 = ~UCA0TXIFG;                          // clear a false UCB0 trigger
    }
    
    //¦----------------------------- US0RX ISR  ---------------------------------------¦
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCIAB0RX(void)                     // A0/B0 RX IRQ vector
    {
     if (IFG2 & UCA0RXIFG){                              // check for UART RX
    
       *uart.bufRXpnt++ = UCA0RXBUF;                     // copy data byte
    
    //     if (uart.bufRXpnt == (uart.RXbuffer[1])-'0')
    //   {
    //	   __bic_SR_register_on_exit(LPM3_bits);
    //   }
       }
     else IFG2 = ~UCA0RXIFG;
    }
    
    ///////////////getAcceleration will make the MSP430 talks to the BNO055
    void getAcceleration() {
    
         // Enable intterupts
    //////commented on 10/12/2016 //intterupts enabled in the main function below
    	__enable_interrupt();
    
    //	 IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
    //	 IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
    //	 _BIS_SR(GIE);                     // Enable the global interrupt
    
    	 //Put BNO055 in CONFIG mode********required (do not change)
    	    TXSTRING("\xAA\x00\x3D\x01\x00");    // Send this to the BNO055 to set up the CONFIG mode
    	    delay_ms(20); // do not change (80)
    	    while (IE2 & UCA0TXIE);
    
    	   //Put BNO055 in NORMAL power mode********required (do not change)
    		 TXSTRING("\xAA\x00\x3E\x01\x00");    // NORMAL power mode
    		 delay_ms(20); // do not change (20)  delay_ms(2000)
    		 while (IE2 & UCA0TXIE);
    
    		//Put BNO055 in AMG mode********selecting operating mode is required (do not change)
    		TXSTRING("\xAA\x00\x3D\x01\x07");    // Send this to the BNO055 to set up the ACC ONLY mode
    		delay_ms(80); // do not change (80) delay_ms(2000)
    		while (IE2 & UCA0TXIE);
    
    		TXSTRING("\xAA\x01\x08\x06");
    		delay_ms(10); //this delay is required..do not change (10) // delay_ms(10000)
    		while (IE2 & UCA0TXIE);
    		/*
    		 * ACC_DATA_X_LSB 0x08=RXbuffer[2];
    		 * ACC_DATA_X_MSB 0x09=RXbuffer[3];
    		 * ACC_DATA_Y_LSB 0x0A=RXbuffer[4];
    		 * ACC_DATA_Y_MSB 0x0B=RXbuffer[5];
    		 * ACC_DATA_Z_LSB 0x0C=RXbuffer[6];
    		 * ACC_DATA_Z_MSB 0x0D=RXbuffer[7];
    		 */
    		cached_accelerationXLSB = uart.RXbuffer[2];
    		cached_accelerationXMSB = uart.RXbuffer[3];
    		cached_accelerationYLSB = uart.RXbuffer[4];
    		cached_accelerationYMSB = uart.RXbuffer[5];
    		cached_accelerationZLSB = uart.RXbuffer[6];
    		cached_accelerationZMSB = uart.RXbuffer[7];
    
    		// Send this to the BNO055 to set up the CONFIG mode....DO NOT CHANGE or DELETE
    //		TXSTRING("\xAA\x00\x3D\x01\x00");    // Send this to the BNO055 to set up the CONFIG mode
    //	    delay_ms(10); // do not change (80) delay_ms(2000)
    //		while (IE2 & UCA0TXIE);
    //
    //		// Send this to the BNO055 to set up the SUSPEND mode....
    //		TXSTRING("\xAA\x00\x3E\x01\x02");    // SUSPEND power mode
    //	    delay_ms(20); // do not change (20)  delay_ms(2000)
    //		while (IE2 & UCA0TXIE);
    
    ///////commented on 10/12/2016 //
    		__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed
    
    		return;
        }
    
    //¦----------------------------- Main Function-------------------------------------------¦
    void doAccelerationSense() {
    	// void doAccelerationSense(bool update) {
    
    	// If called with update=true, perform a measurement
    		//if (update) {
    			cached_accelerationXMSB = 0;  // Considered an "invalid" value
    	        cached_accelerationXLSB = 0;  // means the sensor did not work
    
    	        cached_accelerationYMSB = 0;
    	        cached_accelerationYLSB = 0;
    
    	        cached_accelerationZMSB = 0;
    	        cached_accelerationZLSB = 0;
    
    	// *** Save state of all registers modified by the acceleration sensing code ***
    	        uint16_t original_P1DIR = P1DIR;
    	        uint16_t original_P1IE = P1IE;
    	        uint16_t original_P1OUT = P1OUT;
    	        uint16_t original_P1REN = P1REN;
    	        uint16_t original_P1SEL = P1SEL;
    	        uint16_t original_P1SEL2 = P1SEL2;
    
    	        set_UARTUCS();
    	        setUARTPins();
    	        uart_init();
    
    	    	// Enable intterupts
    //	        IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
    //	        IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
    //	        _BIS_SR(GIE);                     // Enable the global interrupt
    
    	        ///////////////getAcceleration will make the MSP430 talks to the BNO055
    	        getAcceleration();
    
    	        // *** Restore all registers modified by the acceleration sensing code back to their previously saved state ***
           		P1IE = original_P1IE;
           	    P1DIR = original_P1DIR;
           		P1REN = original_P1REN;
           		P1SEL = original_P1SEL;
           		P1SEL2 = original_P1SEL2;
           		P1OUT = original_P1OUT;
    
           		set_UCS(); //set the clocks back
    
    }
    //Acceleration.c (main function ends here)
    /////////////////////////////////////////////////////////////////////////////
    		// Save value to transmit buffer
    //		    acceleration_location = malloc(6);
    //			acceleration_location[0] = ((uint8_t*) &cached_accelerationXMSB)[0]; //check this (the order)
    //			acceleration_location[1] = ((uint8_t*) &cached_accelerationXLSB)[0]; // see line 196~
    //			acceleration_location[2] = ((uint8_t*) &cached_accelerationYMSB)[0];
    //			acceleration_location[3] = ((uint8_t*) &cached_accelerationYLSB)[0];
    //			acceleration_location[4] = ((uint8_t*) &cached_accelerationZMSB)[0];
    //			acceleration_location[5] = ((uint8_t*) &cached_accelerationZLSB)[0];
    //}
    

    This will be part of a project to be loaded on a sensor node and the data should be transmitted wirelessly (you see that I commented the part f malloc that takes care of the data and put them in to the radio buffer). But the program is stuck  when it gets to __bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed.

    I would like to get the program continue but I could not figure out how to do that. So would please help me with this? would you please suggest changes to be done? it is not necessarily to go to sleep at all, I just want the program to work. So please help me as I am stuck since a long time with this and this is affecting my studies as the major part of the project is to collect the data and analyze the data.

    thank you

  • After a quick look, well, LPM3 will disable SMCLK. And SMCLK is the clock for the UART. So the UART has no clock to send or receive anything. And if nothing is sent/received, no interrupt is generated. And without an interrupt, the CPU will remain in LPM.

    On 5x family, the USCI will request the clock when a start bit is detected (but on higher baudrates, it will be too late to properly receive the incoming byte). IIRC, the eUSCI will prevent SMCLK from being switched off at all, if active. Effectively turning LPM3 into LPM0-2.

    I'm not 100% sure if on 2x family SMCLK is really unconditinally switched off (none of my 2x family projects used LPM), but this might be the source of your problems. Try again with LPM0 for a start.

  • Replacing LPM3 with LPM0 did not change the situation, still stuck and the sensor does not transmit.

    But if I comment out this

         if (uart.bufRXpnt == (uart.RXbuffer+uart.RXbuffer[1]))
       {
    	   __bic_SR_register_on_exit(LPM0_bits);
       }

    in the RX ISR, and this

    __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ int until Byte RXed

    in the getAcceleration() function, then the sensor transmits, but weird data.

    Would you please suggest a way to modify the code such that I do not use LPM(s) but still using interrupts? as you said, interrupts are very good in handing the UART data

    Thank you

  • Sure you can do it without LPM.
    In your application, LPM merely acts as a semaphore: wait until you get a signal that the job is done.
    You can define a global variable (be sure it is declared volatile). Set it to 0 before you start the transfer and let the ISR set it to 1 when done. IN you main code, jsut wait until it switches from 0 to 1 before you continue.

    However, I guess your problem is a different one:
    In your IF conddition, you check whether your write pointer is the same as the expected end of the transmission. However, the 'expected end' is calculated with the secodn byte of the transmission, while it is checked even at the first byte, whiel the secodn byte is still zero (or whatever it was on the last transmission). So the IF condition is true right after the first byte received, ending the transfer (or at least the LPM). And you main code continues while the tranfer is still ongoing, working with the initial ram content or data partly from the previous transmission.
    You need ot extend your if condition, so that it ensures that the second (transmission length) byte has been received (uart.bufRXpnt > &uart.RXbuffer[1])
  • Thank you Jens-Mike

    But what does the >& does?

    uart.RXbuffer[1] will contain the length of incoming packet. So in my code I was checking if I received the whole packet. However, using >& checking resulted in the same thing. I am receiving the packets fine.

    But my problem is not in UART reception or transmission. The problem I think in placing the LPM0. i.e after I do all transmission and reception via UART, I set back the clocks and pins and then put the MSP430 into LPM0. But what will make it wake to continue with the rest of the program (assuming that the received data from the BNO055 need to be transmitted wirelessly)?

  • OK, I did this

    #include "msp430g2553.h"
    #include <stdio.h>
    char xLSB, xMSB, yLSB, yMSB, zLSB, zMSB;
    unsigned char setconfigmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x00};
    unsigned char setpowermode[5]={0xAA, 0x00, 0x3E, 0x01, 0x00};
    unsigned char setAMGmode[5]={0xAA, 0x00, 0x3D, 0x01, 0x07};
    unsigned char readACC[4]={0xAA, 0x01, 0x08, 0x06};
    
    #define TXD BIT2
    #define RXD BIT1
    
    typedef unsigned char uint8_t;
    
    volatile uint8_t rx_counter = 0;
    
    #define BUFFER_SIZE 8
    char RXbuffer[BUFFER_SIZE];
    
    void set_UCS() {//------------------- Configure the Clocks -------------------//
    	     WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog
    	     DCOCTL  = 0;             // Select lowest DCOx and MODx settings
    	     BCSCTL1 = CALBC1_12MHZ;   // Set range
    	     DCOCTL  = CALDCO_12MHZ;   // Set DCO step + modulation // DCO -> SMCLK (Default)
    	     IE1 &= 0xFD; /* Disable UCS interrupt */
    	     return;
       }
    
    void setMSP430Pins() {//--------- Setting the UART function for P1.1 & P1.2 --------//
    	            P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    	            P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    	         return;
    }
    
    void uart_init(void){
    	P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    	P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    	UCA0CTL1 = UCSWRST;           // Set UCSWRST (hold USCI in Reset state)
        UCA0CTL1 |= UCSSEL_2;                     // CLK = SMCLK
    //   ------------ Configuring the UART(USCI_A0) ----------------//
    //     115200 BAUD, CLK=12MHz
        		  UCA0BR0 = 6;
        		  UCA0BR1 = 0;
    //    		//*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1
    //    		  // BITS| 7 6 5 4 | 3 2 1  |   0    |
        		  // UCAxMCTL = | UCBRFx  | UCBRSx | UCOS16 |
        		  UCA0MCTL = 0x81; //this works fine
        UCA0CTL1 &= ~UCSWRST;             // Clear UCSWRST to enable USCI_A0-UART
        UCA0CTL1 &= ~UCSYNC;
      IFG2 |= UCA0TXIFG;            // preset IFG flag always left on
    }
    /////////////////////////UART send multiple Bytes////////////////////
    void uartSend(unsigned char *pucData, unsigned char ucLength)
    {
    	while(ucLength)
    	{
    		// Wait for TX buffer to be ready for new data
    		while(!(IFG2 & UCA0TXIFG));//check if not set
    		                           //if set, TX interrupt is pending
    		// Push data to TX buffer
    		UCA0TXBUF = *pucData;
    		// Update variables
    		ucLength--; //-- length of data left
    		pucData++;  //shift pointer
    	}
    	// Wait until the last byte is completely sent
    	while(UCA0STAT & UCBUSY); //UCBUSY indicates if USCI transmitting or receiving
    }
    //////////////////////////////UART receive multiple Bytes///////
    void USCI_ISR( void )
    {
      RXbuffer[rx_counter] = UCA0RXBUF;
    
      if( ++rx_counter >= 2 )
      {
        rx_counter = 0;
        IFG2 = ~UCA0RXIFG;//reset RX flag
      }
    }
    
    //¦----------------------------- Delay Function  ---------------------------------------¦
    void delay_ms(unsigned int ms)
    {
        unsigned int i;
        for (i = 0; i<= ms; i++)
           __delay_cycles(6000); // 6000 will give us 1ms
    }
    //¦----------------------------- Main  -------------------------------------------¦
    void main(void) {
    
    	set_UCS();
    	uart_init();
    
    	//Make sure the BNO055 in config mode
        uartSend(setconfigmode,5);
        while(1)
        {
        while(!(IFG2 & UCA0RXIFG));
        USCI_ISR();
        }
    
        xMSB = RXbuffer[2];
        xLSB = RXbuffer[3];
        yMSB = RXbuffer[4];
        yLSB = RXbuffer[5];
        zMSB = RXbuffer[6];
        zLSB = RXbuffer[7];
    
         delay_ms(20); // delay_ms(20)
    }

    However, code will still in the while(!(IFG2 & UCA0RXIFG));
    I used while(1) as this is the only try that allowed me to get the received bytes and out them into the string RXbuffer. With out using the while(1) I will only get the 1st byte. Would anyone please check the RX ISR and tell me how to make it receive the whole packet and check the exit the ISR when receiving it in full?

    Thank you

  • "But what does the >& does?"

    It's not '>&' but rather '>' and '&'.
    '&' is, not only the binary 'and' operator but also the unary reference operator: it gives the address of the following lvalue.

    So "(&ptr[n])" gives the same value as "(ptr+sizeof(ptr[0])*n)": the address of the 2nd (index 1) element of the array.
    The code is therefore checking whether the byte that contains the message size has been already received at all. A check that your original code was missing, so the size could still be 0 and the check would succeed even though nothing has been received yet.

    UCA0CTL1 &= ~UCSYNC;
    this line is superfluous, as
    UCA0CTL1 = UCSWRST;
    already did it. However, if this bit were set, clearing it would require setting SWRST again to initialite the UART for a completely different operation mode, as it would switch from SPI to UART mode, invalidating the current configuration.

    I don'T see you setting IE2.UCA0RXIE, nor is GIE set anywhere, so your ISR is never called by an interrupt.
    Well, you do it manually. Which wouldn't work if it were really declared as ISR (ISRs have a different entry/exit code and can't be called manually, even though the compiler might not complain)

    When clearing SWRST in UART mode, UCA0TXIFG is always instantly set, no need to set it manually.

    Your main code has code after the while(1) loop. The compiler shoudl compain about unreachabel code. However, if there were no while(1) loop, the main funciton would exit into the void, acting undefined (some compilers generate exit code that goes into LPM0, leaving interrutps enabled, some go into LPM4). YOu should have a while(1) or an LPM0; at the end of main (best a combination of both), so it never exits.

    Finally, your 'ISR' has some flaws.
    First, there is no need to manually clear RXIFG. You have read RXBUF, so it is already cleared. Worse, if it is not clear, this means that you have just received another byte after reading RXBUF, and claring RXIFG will make your code ignore it.
    Then, if you got your second byte, rx_counter gets reset to 0. But if you still receive data, you will overwrite your received two bytes with the next two and so forth. I don't think this is intentional.
    If you jsut want to receive two bytes, then check rx_counter right at the start of the function, and when it is >=2, then manually clear RXIFG, else read RXBUF and increment the counter. So you stop storing incoming bytes after the 2nd, as rx_counter will only count up to 2 and then 'lock' there.

    Why your code hangs in the while? Maybe you have already received all the bytes, bu tsince you continue looping, you will enter the wait for RXIFG again and again and finally stall there when no further bytes are received.

    If you want to receive 2 bytes and then continue, well, remove the IF case from your 'ISR'. It prevents detection of the end of reception outside if this function.
    In the while(1) test for rx_count. And when it is >=2, do a break (break out of the while(1)).

    Don't forget to put a while(1) at the end of main.

**Attention** This is a public forum