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.

UART (USCI_A0) and SPI (USCI_B0) - Interrupt problems

Other Parts Discussed in Thread: MSP430G2553

I'm using the MSP430G2553 (on the Launchpad) and trying to use it as a SPI<=>UART bridge,
tunneling all data traffic.
This works so far, my problem is that upon receiving a UART character the ISR also enters
the loop for sending a UART char, even if the condition if(IFG2 & UCB0RXIFG) should not be fullfilled.
So in my Windows terminal i receive a "0" character upon sending a uart character.
There is nothing connected to the Launchpad, so no reason a SPI receive should be fired.


#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void) {

       P1OUT |= BIT0; // LED on
       if (IFG2 & UCA0RXIFG) { // UART Character received
              while (!(IFG2 & UCB0TXIFG)); // Wait for SPI buffer ready
              UCB0TXBUF = UCA0RXBUF; // Send Character to SPI

              IFG2 &= ~UCA0RXIFG; // clear UART-Receive Flag
       }
       if (IFG2 & UCB0RXIFG) { // SPI Character received
              while (!(IFG2 & UCA0TXIFG)); // Wait for UART buffer ready
              UCA0TXBUF = UCB0RXBUF; // Send Character to UART

              IFG2 &= ~UCB0RXIFG; // clear SPI-Receive Flag
       }
       P1OUT &= ~BIT0; // LED off
}

full code incl UART/SPI setup here:

#include "msp430g2553.h"

void main(void) {
		WDTCTL = WDTPW + WDTHOLD; // Stop WDT

		// UART:
		P1DIR |= BIT0; 			// Set the LED on P1.0 as output
		// SPI:
		P1DIR |= BIT3;			// Set P1.3 as "reset slave"
		P1OUT = 0x00;

		// UART set DCO (1MHz):
		BCSCTL1 = CALBC1_1MHZ; 	// Set DCO
		DCOCTL = CALDCO_1MHZ;

		// UART + SPI config of P1:
		// P1.1 = UART_RX, P1.2 = UART_TX, P1.4 = SPI_STE, P1.5 = SPI_CLK, P1.6 = SPI_SOMI, P1.7 = SPI_SIMO
		P1SEL = BIT1+BIT2+BIT4+BIT5+BIT6+BIT7;
		P1SEL2 = BIT1+BIT2+BIT4+BIT5+BIT6+BIT7;

		// UART Setup (9600-8N1):
		UCA0CTL1 |= UCSSEL_2; 	// SMCLK
		UCA0BR0 = 104; 			// 1MHz/9600 = 104.., lower 8 bit (UCA0BR = 16bit long)
		UCA0BR1 = 0; 			// 1MHz/9600 = 104.., higher 8 bit
		UCA0MCTL = UCBRS0; 		// Modulation UCBRSx = 1

		// SPI Setup (9600), 3-pin, 8-bit SPI master:
		UCB0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC;
		UCB0CTL1 |= UCSSEL_2;	// SMCLK
		UCB0BR0 = 104;			// 1MHz/9600 = 104.., lower 8 bit (UCB0BR = 16bit long)
		UCB0BR1 = 0;			// 1MHz/9600 = 104.., higher 8 bit
		//UCA0MCTL = 0;			// No modulation

		UCB0CTL1 &= ~UCSWRST;	// Start USCI - SPI
		UCA0CTL1 &= ~UCSWRST; 	// Start USCI - UART
		IE2 |= UCA0RXIE + UCB0RXIE; 		// Enable USCI_A0+B0 RX interrupt

		P1OUT &= ~BIT3;			// Now with SPI signals initialized,
		P1OUT |= BIT3; 			// reset slave
		__delay_cycles(75);		// Wait for slave to initialize

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


#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void) {

	P1OUT |= BIT0;	// LED on
	if (IFG2 & UCA0RXIFG) { 			// UART Character received
		 while (!(IFG2 & UCB0TXIFG));	// Wait for SPI buffer ready
		 UCB0TXBUF = UCA0RXBUF;			// Send Character to SPI

		 IFG2 &= ~UCA0RXIFG;			// clear UART-Receive Flag
	}
	if (IFG2 & UCB0RXIFG) {				// SPI Character received
		while (!(IFG2 & UCA0TXIFG));	// Wait for UART buffer ready
		UCA0TXBUF = UCB0RXBUF;			// Send Character to UART

		IFG2 &= ~UCB0RXIFG;				// clear UART-Receive Flag
	}
	P1OUT &= ~BIT0; // LED off
}
 

  • Melwin said:
    the ISR also enters the loop for sending a UART char, even if the condition if(IFG2 & UCB0RXIFG) should not be fullfilled.

    First, it shouldn't be a loop. Loops are a death sin inside an ISR. Especially busy-waiting loops. Interrupts are there to tell you when an interrupt condition is met. You must not wait for it inside an ISR. FI your current approach requires this, the approach is wrong and should be reconsidered.
    in your case, especially since SPi and UART likely run with a different baudrate, you MUST implement some kind of buffer mechanism (e.g. a ring buffer). Else you'll get an SPI incoming datat overflow while you wait for sending the last outgoing UART byte - and while you wait, the opposite direction is also stalled.

    This being said, it is natural that when you get RXIFG set, you also get TXIFG set. Because both directions use the same baudrate, anything you wrote to TXBUF when or before receiving the last charater will have been sent in the time it takes to receive the next character. In case of SPI, this is also synchronized (RXIFG always happen 1/2 clock cycle after TXIFG)

    If you don't set the TXIE bit, TXIFG won't call the ISR, but it is still set whenever TXBUF is empty.

    Hint: draw a timing diagram in which you can see what will happen when on a timeline. (x-axis is time, perhaps in clock cycles). Draw when data is writtne to TXBUF, when it gets sent bit by bit etc. Then you'll see where your problems are.

    An UART/SPI bridge is way more complex than it sounds a tthe first moment. In fact, it is nearly impossible if the bridge doesn't know about the SPI side protocol. If you receive something on UART you can forward it to the SPi slave. However, when you do so, you resceive something form the slave. it is data you have to send to UART? Or is it dummy dat athat has to be discarded? And when the slave has something to send? If you don't poll it, you will not get it. And if you poll, how do you do it?

    You can't simply pass the data through, you'll have to know the SPI slave. And worst, if the SPi device is master and the bridge is slave, this won't work at all. When the master sends soemthing, it expects an immediate answer, However, you'll have ot passit on UART and wai for the answer on UART before you can forward the answer to the SPI master - which will be way too late even if the UART woudl have a much higher baudrate than the SPI (and usually, it is quite the opposite).

    Melwin said:
              UCB0TXBUF = UCA0RXBUF; // Send Character to SPI
                  IFG2 &= ~UCA0RXIFG; // clear UART-Receive Flag

    Reading UCA0RXBUF has implicitely cleared UCA0RXIFG. if it is (still) set at thsi point, this means that another byte ahs arrived jus tthat moment. So manually clearing the IF Gbti after reading RXBUF is best case superfluous and will worst case drop (well, not really, but hide from detection) the next received byte.

  • Beginners question answered at large, thank you !
     

  • Hey guys,


    I have a question that is related to this one here. On my MSP430G2553 I've configured the UART interface on UCA and the SPI interface (as Master) on UCB.

    The SPI receive interrupt is disabled (UCB0RXIE = 0). However, if I write a character to UCB0TXBUF (SPI) the UCB0RXIFG flag is set. Why is the receive interrupt flag set, when I write something to the transmit buffer? Nothing is wired on the SPI pins. Is it because the master automatically awaits a response from the slave?

    And another thing: to determine which interface triggered the receive interrupt, I use two if's:

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCI0RX_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
       if(IFG2 & UCA0RXIFG)
       {
         // do UART stuff
       }
       if(IFG2 & UCB0RXIFG)
       {
         // do SPI stuff
       }
    }

    Is that the best way to do it?

    - Andreas

  • Andreas Brunner said:
    The SPI receive interrupt is disabled (UCB0RXIE = 0). However, if I write a character to UCB0TXBUF (SPI) the UCB0RXIFG flag is set. Why is the receive interrupt flag set, when I write something to the transmit buffer?

    This very question cropped up in another thread a few days ago, here's the answer:

    http://e2e.ti.com/support/microcontrollers/msp430/f/166/p/370009/1301952.aspx#1301952

  • One thing is still not clear to me though. It makes sense that you receive a character everytime you transmit one due to SPI's functionality, but what is the purpose of two different interrupt enables (UCA0RXIE and UCB0RXIE) if the same ISR is triggered, no matter which one of these two is enabled? (recall: UART was configured on UCA0 and SPI on UCB0).

    It would seem more reasonable to me that if I disable the SPI interrupt by clearing UCB0RXIE the corresponding interrupt flag would not be set (and thus not trigger the ISR). That would make it possible to use the UART Rx Interrupt while sending on the SPI (and thus triggering an RX interrupt after every character), without any additional workarounds.

    EDIT: Apparently it doesn't work the other way around. If only UCB0RXIE is set, UCA0RXIFG (UART interrupt flag) is set but the interrupt is not triggered. This is how it should be in my opinion. So why doesn't that work the same way for the SPI interrupt?

  • First, it is consistent for master and slave mode to have both interrupts. In slave mode, you could ignore the TX interrupt and still get RX interrupts (the master is providing the clock) when you don’t have to send anything.
    Also, RXIFG and TXIFG happen with 1/2 clock cycle delay, and depending on phase, the order is different. Doesn’t make much of a difference if SPICLK is in the range of MCLK, but on slow SPI clock, it does. Well, with the right phase, you can indeed use the RX interrupt to handle the TX case too in SPI mode. However, keep in mind that after you wrote the last byte to TXBUF, you will get two more RX interrupts (one for the byte that started sending when you wrote the last byte to TXBUF, and one for the byte you wrote to TXBUF). And you won’t get an initial RX interrupt to start sending at all. So it is still easier to handle both independently.

    The IFG bits are set independently of the IE bits. The IE bits are ANDed with the IFG bits and GIE to grant an interrupt. However, the IFG bits are always set and cleared by hardware depending on the hardware events. Without IE and GIE, they just don’t call an ISR.
    On 2x family, the RX (and TX respectively) interrupts of UCA and UCB call the same ISR. However, you can see by checking the IFG bits which one caused the interrupt call.
    In I2C mode, you have all RX and TX of UCB (and TX of UCA) calling the TX interrupt while the status interrupts of UCB are arriving on the RX ISR, together with the RX interrupts of UCA. Again, the IFG bits will tell you which one called the ISR.
    And on 5x family, UCA and UCB have both their own interrupt on which all their interrupts are executed. Here again, you need to check the IFG bits to see which event caused the interrupt.

  • Thank you for your detailed answer. 

    So only if the respective IE bit is set, the ISR gets called? And in the ISR I have to use the IFG bits to determine which interrupt was called, right?


    I think the problem was that both IFG bits were set where only one was enabled. But since both IFG bits were set by hardware, both

    if(IFG2 & UCA0RXIFG)
    {
       // do UART stuff
    }
    if(IFG2 & UCB0RXIFG)
    {
       // do SPI stuff
    } 

    were true.

  • Indeed.
    The processor does something like this:
    If (xxIFG && xxIE && GIE) call ISR;
    Where GIE and xxIE are set or cleared by the user and xxIFG is set and cleared by hardware and can also be set and cleared by the user.

     In your example, yes, this is a (the) problem. If RXIE isn’t set, the ISR won’t be called for RXIFG, but of course RXIFG itself is set, and in the ISR the test will return true.
    Depending on the MSP, many modules provide an interrupt vector register (IV). If read, it will return an index for the highest pending interrupt (the one that called the ISR). Only interrupts where the IE bit is set will be reported. And with reading this register, the corresponding IFG bit will also be cleared at the same time.
    This works well with the __even_in_range intrinsic and a switch statement.
    However, for I2C, this shouldn’t be used, as clearing the RXIFG bit (by reading the IV register) may cause the receive process to continue, possibly leading to a receive overflow.
    Well, in I2C mode, you won’t get both, RX and TX interrupts. So your IF cascade will work fine.
    Also, you can check for IE and IFG bit in the IF, so those cases where IE isn’t set will be ignored.

  • Hi guys

    Would you please take a look at my code and tell me wht is wrong with it. I am using this to communicate with BN055 IMU which is connected to and MSP430G2553 launchpad via UART.
    The problem is in the last line, when I send TXSTRING("\xAA\x01\x08\x06") to the BNO055 to read the acceleration I get BB 06 00 00 00 00 00 00. The BB 06 is header but the data are not there (all 00).

    Should I clear the RXBUF before transmitting a new set of bytes? if so, how to clear the RXBUF given that UCA0RXBUF is read (not read/write)?

    Thank you

    M

    #include "msp430g2553.h"
    #include <stdio.h>
    char xLSB, xMSB, yLSB, yMSB, zLSB, zMSB;
    #define TXD BIT2
    #define RXD BIT1
    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 TXbuffer[8];
        char RXbuffer[8];
    } uartstruct;
    
    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 --------//
    
    	        //    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;
    }
    void uart_init(void){
     IE2 &= ~(UCA0TXIE | UCA0RXIE | UCB0TXIE | UCB0RXIE); // Disable all USCIx0 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;
    }
    
    #define   TXSTRING(pnt) (TXdata((pnt), sizeof(pnt)-1)) //  macro to get string and string len
    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
    }
    
    //¦----------------------------- 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+8 && uart.RXbuffer[0]==0xBB)           // got 8 bytes in yet?  <<<<
    	   uart.RXbuflen=uart.RXbuffer[1];
       __bic_SR_register_on_exit(LPM3_bits);
    
      }
     else IFG2 &= ~UCA0RXIFG;
    }
    
    //¦----------------------------- Main  -------------------------------------------¦
    void main(void) {
    
    	set_UCS();
    	setMSP430Pins();
    
    	uart_init();
    	delay_ms(500);
    
    	TXSTRING("\xAA\x00\x3D\x01\x00");    // Send this to the BNO055 to set up the config mode
    	while( !(IFG2 & UCA0TXIFG) && uart.RXbuffer[1]==0x01);
    
    		TXSTRING("\xAA\x00\x3F\x01\x20");    // reset
    
    		delay_ms(60);
    
    		while( !(IFG2 & UCA0TXIFG) && uart.RXbuffer[1]==0x01);
    		TXSTRING("\xAA\x00\x3E\x01\x00");    // Normal power mode
    		delay_ms(10);
    
    //
    		while( !(IFG2 & UCA0TXIFG) && uart.RXbuffer[1]==0x01);
    		TXSTRING("\xAA\x00\x07\x01\x00");    // Send this to the BNO055 to set up page 0
    			delay_ms(10);
    
    			while( !(IFG2 & UCA0TXIFG) && uart.RXbuffer[1]==0x01);
    		TXSTRING("\xAA\x00\x3D\x01\x07");    // Send this to the BNO055 to set up the 9DOF mode
    			delay_ms(120);
    //
    			while( !(IFG2 & UCA0TXIFG) && uart.RXbuffer[1]==0x01);
    
    			TXSTRING("\xAA\x01\x08\x06");
    			while( !(IFG2 & UCA0TXIFG));
    			delay_ms(120);
    			xLSB = uart.RXbuffer[2];
    		  xMSB = uart.RXbuffer[3];
    		  yLSB = uart.RXbuffer[4];
    		  yMSB = uart.RXbuffer[5];
    		  zMSB = uart.RXbuffer[6];
    		  zMSB = uart.RXbuffer[7];
    		__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed
    
    	while(1)
    	{ }
    }
    

  • Line 96 seems to be wrong. Should read ~UCB0TXIFG. Same for line 111. But not relevant.
    Line 146 should be while (IE2 & UCATXIE); As you clear IE when done sending.
    It is possible that the while condition checksd for TXIFG the very moment the flag gets set. Then your code continues while the next instruction is interrupted by the ISR for the still ongoing transfer.

    Also, the delay is a bad idea. You don't know how long the response time is. Best case, you're wasting time, worst case, it takes longer to answer. Your RX ISR exits LPM after receiving 8 bytes. So why don't you just enter LPM0 to wait for the transfer done? (Later, a tiemr ISR should check for a timeout in case the device doesn't answer). Or is line 154 meant to do this? Then it should of course be put befire readign your results from RXBuffer. :) Also, line 108 exits LPM after each received byte, not after a completed transfer. Makes not much sense. The whole RX IST logic looks suspicious. Remember, in UART mode, you receive only if somethign is sent. There is no auto-receive if you send something (liek SPI)(, and no continuous data stream until you NACK the reception (like I2C). SO it makes not much sense to wait for 8 bytes to be received and then set the length to the 2nd received byte. You should listen to the data until the firs tbyte received is 0xbb, then take the next byte for the expected transmission length, and exit LPM (and stop further receive) when all expected bytes are there. (if you don't get 0xbb or won't get all the expected bytes for soeme reason, the RX funciton will stall, so a timerout timer ISR should be used anyway)

    Your RX ISR doesn't stop receiving after having 8 bytes shuffled into the 8 byte buffer. If you receive additional data for some reason, you're overwriting your memory.

    However, I don't know your slave device in detail, so I can't say whether there is a problem in the command sequence itself.
  • Thank you Jens-Michael

    I took your advices into consideration and added these lines to the program, and now I am getting the data. The slave device is the BNO055 (I am talking to the accelerometer of it)

     IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
         IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
         _BIS_SR(GIE);                     // Enable the global interrupt

    Here is the full code, if there is any more suggestions then I will be happy

    #include "msp430g2553.h"
    #include <stdio.h>
    char xLSB, xMSB, yLSB, yMSB, zLSB, zMSB;
    #define TXD BIT2
    #define RXD BIT1
    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 TXbuffer[8];
        char RXbuffer[8];
    } uartstruct;
    
    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 --------//
    
    	        //    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;
    }
    void uart_init(void){
     IE2 &= ~(UCA0TXIE | UCA0RXIE | UCB0TXIE | UCB0RXIE); // Disable all USCIx0 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;
    }
    
    #define   TXSTRING(pnt) (TXdata((pnt), sizeof(pnt)-1)) //  macro to get string and string len
    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
    }
    
    //¦----------------------------- 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+8 && uart.RXbuffer[0]==0xBB)           // got 8 bytes in yet?  <<<<
    //	   uart.RXbuflen=uart.RXbuffer[1];
    //   __bic_SR_register_on_exit(LPM3_bits);
    
      // if (!--uart.RXbuflen){
       if (uart.bufRXpnt == uart.RXbuffer+8)
       {
    	   __bic_SR_register_on_exit(LPM3_bits);
       }
       }
     else IFG2 = ~UCA0RXIFG;
    }
    
    //¦----------------------------- Main  -------------------------------------------¦
    void main(void) {
    
    	set_UCS();
    	setMSP430Pins();
    
    	uart_init();
    
    	 IE2 |= UCA0TXIE;                  // Enable the Transmit interrupt
    	 IE2 |= UCA0RXIE;                  // Enable the Receive  interrupt
    	 _BIS_SR(GIE);                     // Enable the global interrupt
    
    	 //Put BNO055 in Normal power mode********required (do not change)
    	 TXSTRING("\xAA\x00\x3E\x01\x00");    // LOW power mode
    	 delay_ms(20); // delay_ms(20)
    	 while (IE2 & UCA0TXIE);
    
    	//Put BNO055 in ACC only 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); // delay_ms(80)
    	while (IE2 & UCA0TXIE);
    
    	TXSTRING("\xAA\x01\x08\x06");
    	delay_ms(10); //this delay is reuired....do not delete // delay_ms(10)
    	while (IE2 & UCA0TXIE);
    
    	//copy the data
    			xMSB = uart.RXbuffer[2];
    			xLSB = uart.RXbuffer[3];
    			yMSB = uart.RXbuffer[4];
    			yLSB = uart.RXbuffer[5];
    			zMSB = uart.RXbuffer[6];
    			zLSB = uart.RXbuffer[7];
    
    //	UCA0CTL1 = UCSYNC;
    		__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ int until Byte RXed
    
    
    }

  • How to use timer ISR to check for receive completion?

    Thank you

  • There are lots of ways.
    You can use a tiemr timeout (e.g. the watchdog timer in counter mode). You start the timer when you start the receive and when it expires (interrupt) before you got all data, you have a timeout situation.

    You can set-up a timer to count in up mode, so it generates an interrupt every millisecond. In its ISR you count down a global (volatile!) variable to zero. If you want a timeout, set this variable to the required tiem in milliseconds. If it reaches zero, you have reached the timeout.

    Personally, I use a timer in cont mode, driven by 1MHz SMCLK (divided from 8/16MHz MCLK). In the timer ISR, I increment the compare value by 1000, so the next interrupt happens 1000 ticks=1ms later. The ISR code checks whether the new setting is still in the future, so I can detect if the ISR wasn't called for more than 1ms due to blocked interrupts (e.g. during flash erase/write or other reasons) and can compensate for this. And for timeouts, I use the said global variable. I also use this ISR to so multiple software watchdogs: each supervised function has a global variable. They all set the variable to a certain value at a checkpoint. The ISR counts them down and as long as none of them reaches zero, it triggers the hardware watchdog. This way, the software can triger its software watchdog at way grater intervals and only at safe points (e.g. the main loop)

    As a bonus, I can use the same timer for shorter delays too: I use a compare unit (as CCR0 is used for th 1ms interrupt) and se tthe compare value to TAR+x (where x is the required milliseconds). Then I check for the itnerrupt flag being set in a busy loop. THis way, I can do fairly exact delays of 6µs or more (on 8MHz MCLK), taking the overhead for calign the funciotn and doing the math into account. If no intrrupt happens or the ISR is done wile the tiem is not up yet, the delay is exact. Otherwise it ends after the ISR is done.

**Attention** This is a public forum