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.

TM4C123GXL: Only getting into RX Interrupt once. Why?

Other Parts Discussed in Thread: SYSBIOS, MSP430G2553

Hi guys, long time no talk! Ok, here’s what’s going on:

I have written code to communicate via UART with a bno055 inertial measurement unit board. The board requires UART communication at 115200 baud. No problem.

In my code, I send a command packet of five bytes and then wait for a two byte response. I have a blocking “while” loop in my code that waits until I’ve received the two byte response before progressing. The problem is I’m hanging in that blocking while loop because the two bytes aren’t coming in. However, I have a saleae logic analyzer on the RX line so I know that I am indeed getting two bytes, 0xEE and 0x01. Furthermore, I get into my RX interrupt once, but only once. When my code doesn’t get a two byte response it resends the command, which causes two more bytes to come back on the RX line from the bno055. With my logical analyzer I can see a ton of bytes coming in over the RX line when I let the code run, but I’m only getting into my RX interrupt once in the very beginning of my code. I’ve done a lot of troubleshooting and it seems like my lack of getting back into the RX interrupt must be the reason my code is not functioning. Everything else - shifting the commands out via the EOT TX interrupt, for instance - seems to be working just fine, corroborated by my logic analyzer. But my code hangs waiting for a two byte data packet that won't show up.

My question is: why am I only getting into my RX interrupt once? I have disabled the FIFO for UART 2, so I should be getting into my RX interrupt every time I receive a byte. I can’t figure out where I must have gone wrong. I have attached the code for my UART 2 initialization and ISR. If anyone has any ideas, please let me know.

Thanks!

void uart2_init(){
	//initializes UART2 
	//sets up transmit and receive interrupts
	//0. Init Clock to UART2 and Port D
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	//Give it time for clocks to start
	SysCtlDelay(10);
	//Disable UART before programming
	UARTDisable(UART2_BASE);
	//1.  set baud rate, txe/rxe, stp2 (clear then and fen), and wlen (8 bit_)
	UARTConfigSetExpClk(UART2_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
	UARTFIFODisable(UART2_BASE); //DISABLE FIFO. This should make my interrupt every time I get a byte.
	//1.5. Set up AFSEL To D6, D7 and UNLOCK D7
	HWREG(GPIO_PORTD_BASE+GPIO_O_LOCK) = GPIO_LOCK_KEY;
	HWREG(GPIO_PORTD_BASE+GPIO_O_CR) |= GPIO_PIN_7;
	SysCtlDelay(30);
	GPIOPinConfigure(GPIO_PD6_U2RX);
	GPIOPinConfigure(GPIO_PD7_U2TX);
	//Set D6 as Input (RX) and D7 as Output (TX)
	GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_7);
	GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_6);
	//A little redundancy shouldn't hurt.
	GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_6 | GPIO_PIN_7);
	//Enable Global NVIC Interrupt
	IntEnable(INT_UART2);
	//Enable Local Interrupts
	UARTIntEnable(UART2_BASE, (UART_INT_TX | UART_INT_RX)); //enable Tx and Rx int
	UARTTxIntModeSet(UART2_BASE, UART_TXINT_MODE_EOT); //set Tx mode to EOT
	UARTFIFOLevelSet(UART2_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8); //set Rx to trigger with two bytes
	//Disable for now so I don't get stuck in the TX isr.
	UARTIntDisable(UART2_BASE, UART_INT_TX);
	//Link a function to the UART Interrupt
	UARTIntRegister(UART2_BASE, isr_uart2);
	//Enable UART2
	UARTEnable(UART2_BASE);
	
	//these will change based on our state, but we can use this as a table of contents
	array_tx[index_start_byte] = start_byte;
	array_tx[index_rw] = write;
	array_tx[index_reg_address] = reg_address_page;
	array_tx[index_data_length] = 0x01;
	array_tx[index_data] = page_zero;
//	printf("INIT: UART2\n");
}
	


//printf(" \n");
void isr_uart2(void){
	uint32_t trigger;
	trigger = UARTIntStatus(UART2_BASE, true);
	
	if ((trigger & UART_INT_RX)== UART_INT_RX){ //ISR triggers each time I receive a byte.
		printf("RX: UART2 ISR.\n");
		printf("RX: Index: %u \n", index_rx);
		UARTIntClear(UART2_BASE, UART_INT_RX);
		array_rx[index_rx] = UARTCharGet(UART2_BASE);
		printf("Data Received: %u \n", array_rx[index_rx]);
		index_rx++;
		
		if (array_rx[0] == 0xEE && index_rx > 1){
			printf("In RX If \n");
			index_rx = 0;
//			if (array_rx[1] != 0x01){datapacketsuccess = false;}
//			else if (array_rx[1] == 0x01){datapacketsuccess = true;}
			switch (array_rx[1]){
				case 0x01: 
					printf("WRITE_SUCCESS \n");
					datapacketsuccess = true;
					break;
				case 0x03: 
					printf("WRITE_FAIL \n");
					break;
				case 0x04: 
					printf("REGMAP_INVALID_ADDRESS \n");
					break;
				case 0x06: 
					printf("WRONG_START_BYTE \n");
					break;
				case 0x07: 
					printf("BUS_OVER_RUN_ERROR \n");
					break;
				case 0x08: 
					printf("MAX_LENGTH_ERROR \n");
					break;
				case 0x09: 
					printf("MIN_LENGTH_ERROR \n");
					break;
				case 0x0A: 
					printf("RECEIVE_CHARACTER_TIMEOUT \n");
					break;
				default:
					printf("There was an error. \n");
					break;
			}
			datapacketreceived = true;
		}
		
		if (array_rx[0] == 0xBB && index_rx>7){
			printf("RX: 0xBB // Data Packet Received \n");
			index_rx=0;
		}

	}
	
	
	if ((trigger & UART_INT_TX) == UART_INT_TX){ 
		//printf("TX: In  UART2 Transmit ISR\n"); 
		UARTIntClear(UART2_BASE, UART_INT_TX);
		UARTCharPut(UART2_BASE, array_tx[index]);
		//printf("%u \n", index);
		index++;
		if (index>packet_length_write){		
			UARTIntDisable(UART2_BASE, UART_INT_TX);
			index=1;
			
			//delay until I receive the data back from the bno055.
			while (datapacketreceived == false){printf("stuck waiting for data packet \n");}
			delay_ms(50);
				
			//If failed, resend the last packet
			if (datapacketsuccess == false){
				printf("Data Packet Failed. Resending. \n");
				UARTCharPut(UART2_BASE, start_byte);
				UARTIntEnable(UART2_BASE, UART_INT_TX);
			}
			else if (datapacketsuccess == true){
				printf("Data Packet Success. State:: %u \n", state);
			//if successful, figure out what to do:
				switch (state){
					case 1: //Page 0 successfully selected.	Next is Config Mode Select.
						printf("TX: Page Select Done. Setting Boolean True. \n");
						array_tx[index_reg_address] = reg_address_opr;
						pageselectdone = true;
						state = 2;	
						break;
					
					case 2: //Config Mode successfully selected. Next is Power Mode Normal.
						printf("TX: Config Mode Select Done. \n");
						array_tx[index_reg_address] = reg_address_power;
						configmodeselectdone = true;
						state = 3;
						break;
				
					case 3: //Power Mode Normal select done. Next is Selecting NDOF Mode.
						printf("TX: Power Mode Select Done. Setting Boolean True. \n");
						array_tx[index_reg_address] = reg_address_opr;
						array_tx[index_data] = ndof_mode;
						powermodeselectdone = true;
						state = 4;
						break;
			
					case 4:
						printf("TX: NDOF Mode Select Done. Setting Commands to Read. \n");
						array_tx[index_reg_address] = 0x3D;//reg_address_lia;
						array_tx[index_rw] = read;
						array_tx[index_data_length] = 0x06;
						oprmodeselectdone = true;
						state = 5;
						break;
						//Start regular 200 ms timer. Within the timer interrupt I will query the LIA.
					
					case 5:
					break;
					
					default:
						printf("TX: There was an Error in the State Number. \n");
						break;
		
				}
			}
		}
	}
}

  • A few observations

    You are doing a lot of processing in that interrupt. Probably better to move it outside.

    All those prints in the interrupt are not doing you any favours

    You do have a wait loop, but it looks like it is in the interrupt.  That's not going to work well.

    Robert

  • Good observations Robert!

    Most all of those print statements will be commented out as soon as I know where everything is going, and I regularly comment them out to make sure they're not the source of the problem. I'm pretty sure at the moment they aren't.

    The wait loop in the interrupting definitely isn't working, I've since taken it out. I don't know why though. I have blocking wait loops in the main.c, and when these booleans are set true, I progress to the next step in the main code. So I know that interrupts can still trigger and run in blocking code external to the ISR, but I found that is definitely not true with blocking code *within* the ISR.

    Still not the fix of the Receive ISR. I turned the RX FIFO back on and now things are working a little better though I haven't worked out the bugs. I wish I knew why it wasn't working with FIFO turned off.
  • Hi,

    Several more problem(s):

    a) Your line: UARTFIFOLevelSet(UART2_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8); set the FIFO for maximum depth - maybe it should be better to set it to 1 instead. Take into account you must check in interrupt if any other bytes are present in your FIFO, despite ones producing that interrupt. 

    b) 

    Zero_PD said:
    I have disabled the FIFO for UART 2

    but we cannot see where you did it - take into account you must place this statement immediately after UARTEnable, since this functions silently enables also the FIFO.

    c) You enable interrupts for TX and several lines below in your code you disable it. Don't do that - stay with one option or don't touch it if not needed. 

  • Hi Petrei, thank you very much for the reply.

    a) I'm pretty sure that line sets the RX FIFO to trigger at the minimum depth of 2 bytes of data received, 1/8 the depth of the FIFO. I'm inferring that from this line from the tiva datasheet:

    The trigger points at which the FIFOs generate interrupts is controlled via the UART Interrupt FIFO
    Level Select (UARTIFLS) register (see page 922). Both FIFOs can be individually configured to
    trigger interrupts at different levels. Available configurations include ⅛, ¼, ½, ¾, and ⅞. For example,
    if the ¼ option is selected for the receive FIFO, the UART generates a receive interrupt after 4 data
    bytes are received.


    b) so I thought I had disabled the FIFO when I called these two lines of code:

        //1.  set baud rate, txe/rxe, stp2 (clear then and fen), and wlen (8 bit_)
        UARTConfigSetExpClk(UART2_BASE, SysCtlClockGet(), 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
        UARTFIFODisable(UART2_BASE); //DISABLE FIFO. This should make my interrupt every time I get a byte.
    

    But you're saying that when I enable UART later on, that re-enables the FIFO? That means it would have been set to two bytes the whole time which...hm..doesn't make a lot of sense. If I try writing the FIFO disable line after the UARTEnable line, maybe my code will work as expected.

    c) I disabled it temporarily because, since I have it set to EOT mode, I would have been immediately thrown into my EOT interrupt. With EOT, you have to be continually enabling and disabling the TX interrupt to keep from getting stuck in the TX interrupt whenever you're not actively sending data.

  • Well, a wait loop in the interrupt will certainly keep it from working.

    I would restructure the interrupt so it only does receive and transmit. Then you have something you can work on.

    Do your parsing outside the interrupt rather than in it as you do now.

    Robert
  • I wouldn't be so sure about the prints. I believe you mentioned having a logic analyzer, that's a lot less intrusive than a print.

    One of the first pieces of instrumentation I'd add would be to set an output on isr entry and reset it on exit. That alone starts giving you useful results.

    Robert
  • One more thing to consider. It's usually a good idea to exhaust the source of interrupts before existing. In the best case not doing so imposes extra overhead, in the worst case you lose interrupts.

    Robert
  • Oh, and apparently the timeout interrupt is actually separate from the receive interrupt on this peripheral. You need to deal with both.

    Robert
  • Hi Zero_PD

    Agree with Robert, the while loop looks oddly formed and adding printf in a while loop often ends badly. That is at least with Tivalib UARTprintf(). You must be running Free_ROTS or Sysbios seeing all the (printf)?

    Perhaps this may help:

     //delay until I receive the data back from the bno055.
    
     while (datapacketreceived == false){printf("stuck waiting for data packet \n");}
    
     delay_ms(50);
    
    /****************************************/
    ui32Timeout = 10;
    
    while
        (!datapacketreceived)
    {
      ui32Timeout--;
    
        delay_ms(50);
    
         printf("stuck waiting for data packet \n");
    };
    
    

  • BTW: What I first posted would not work seems it needing a timeout in the handler. Don't forget ample project heap/stack size entries required with so many printf. Chester G. mention this fact in recent post this forum and CCS forum guru backed it up with wiki article links.
  • Be aware that the library function UARTEnable() will also enable the FIFOs. Even if you called UARTFIFODisable() previously.
    I usually run the UARTs at fairly high speed so the FIFOs are my friend.
    You just have to make sure you enable the RX timeout interrupt and in the ISR use a while loop to get all of the available characters in the FIFO.

    Randy
  • Hello Randy

    One more thing to note is the the trigger level must be crossed for the RX Interrupt during FIFO mode to fire. Else the Receive Timeout has to be used

    Regards
    Amit
  • May I note that these last 2 posts seem to have well "retired" this thread?    And that poster Randy indeed employed RX Timeout.

    As I'm inexpert w/these MCU's UART - doesn't it make sense to "always" employ the RX Timeout?   (non-exclusively, but why would RX Timeout ever (productively) be disabled [under normal UART operation]?)

  • As I most always use the FIFOs, the RX Timeout is a must.
    There is no good reason that I can think of not to enable it. But, when needed and not enabled, it can cause a lot of grief.
    This holds true for just about all ucontroller UARTs I have ever used.

    Randy
  • I've never figured out a case where it made any sense to disable the receive timeout. Heck, I've never been convinced it makes any sense to treat it differently from the receive interrupt.

    Robert
  • @ "dual" R's,

    Merci mes amis.   La reponse officiel (seemed) to promote RX Timeout as an option (else condx.) & that's outside our (now 3 man) camp...

  • Hi Amit,

    It's good to know that UARTEnable automatically enables the FIFO even if you disabled it previously. That explains why I wasn't getting into my RX interrupt every time I received a byte. I'd inadvertently re-enabled the FIFO.

    A question for you. I've set my FIFO to a level of two bytes. This means it triggers afters two bytes are received. However, when I get a packet of eight bytes, I find that they are all received at the same time, even though my fifo level is two bytes. I don't go into my RX interrupt four times for an eight byte packet. Do you know why this is?

  • Hello ZeroPD.

    The interrupt is asserted when the threshold is crossed. Hence if you set it to 2 bytes and write 8 bytes to the RXFIFO, the trigger threshold is true and the interrupt shall be fired. So as long as the RXFE flag is not set, you can safely read the N bytes.

    Regards
    Amit
  • You've just hit on the primary reason you set the threshold below full. That gives you allowance for extra latency before entering the interrupt to empty the FIFO. You then simply empty the FIFO by reading until there are no characters left in it, thus reducing the number of interrupts.

    That read action is typically required in any case. All the UARTs I've worked with will only assert the receive interrupt when crossing the threshold. If the FIFO is not emptied below the threshold the receive interrupt will no fire again even if characters are left in the FIFO when exiting the interrupt.

    Robert
  • Amit and Robert,

    The only that worries me about setting the threshold low is this. I am waiting for a packet of 8 bytes. I enter my receive interrupt when the first two come in. If I enter and immediately start reading, will I read the first two and then leave the interrupt while the others are coming in? I am worried I could get "out of sync" by not having the RX interrupt level precisely set to the packet length. If I read the first two bytes, then left my RX interrupt (I set my index back to 0 before I leave the interrupt), then the next six bytes come in and overwrite the first two...it could get messy.

    This is why I was planning on turning off the RX FIFO so I go into my interrupt every time I receive an individual byte. Then I'm grabbing data byte-by-byte and can control the process a little better than hoping all the data has gotten into my RX FIFO before I start reading.
  • Hello Zero_PD,

    That is what worries me as well. You should reset the index count to 0 only when 8 bytes are received. A global variable can be used to know where the buffer has to be written to. Otherwise you may have to do the same in a blocking statement in the interrupt handler or increase the threshold or use the RXTO interrupt.

    Regards
    Amit
  • Zero_PD said:
    If I enter and immediately start reading, will I read the first two and then leave the interrupt while the others are coming in

    If you are fast enough, yes.

    Zero_PD said:
    I am worried I could get "out of sync" by not having the RX interrupt level precisely set to the packet length.

    That won't work anyway. As soon as you lose a character or get an extra one due to noise or other outside influences you will be out of sync. This will happen. You must have synchronization done at a higher level by the protocol.

    Typically you have some method of determining start of packet, special character, special character sequence, quiet period etc... You have to deal with short packets, bad packets and long packets.

    Zero_PD said:
    This is why I was planning on turning off the RX FIFO so I go into my interrupt every time I receive an individual byte.

    Just do the receive and transmit in the interrupt, leave the packetization/depacketization/synchronization to a higher level process outside the interrupt.

    Robert

  • +1 on both Amit and Robert.
    Use the ISR to handle sending and receiving of the data only. Put the received data in a buffer and handle the rest in a foreground process.
    You will never be able to reliably handle this in the ISR. Expecting x-number of bytes and staying "in sync" just doesn't happen in the real world.

    Randy
  • Especially with a Baudot of 115200 BPS. Novice idea might include slowing down RX data rate to 1200-2400 BPS as not to overflow the FIFO. Slowly speed up data rate when the hand shake in upper level app has been developed and working.
  • Dear Zero_PD

    I am testing the UART communications between MSP430G2553 and BNO055. I am sending 4 bytes as shown below and I must receive 3 bytes
    My question is how can I read these 3 bytes given that the UART receive buffer can accommodate one byte (as I understand).?
    And how can I read the receive buffer of the UART?
    And how can I turn on LED for a given received data?

    Thank you

    #include "msp430g2553.h"
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog

    //------------------- Configure the Clocks -------------------//

    if (CALBC1_12MHZ==0xFF) // If calibration constant erased
    {
    while(1); // do not load, trap CPU!!
    }

    DCOCTL = 0; // Select lowest DCOx and MODx settings
    BCSCTL1 = CALBC1_12MHZ; // Set range
    DCOCTL = CALDCO_12MHZ; // Set DCO step + modulation

    //---------------- Configuring the LED's ----------------------//

    P1DIR |= BIT0 + BIT6; // P1.0 and P1.6 output
    P1OUT &= ~BIT0 + BIT6; // P1.0 and P1.6 = 0

    //--------- Setting the UART function for P1.1 & P1.2 --------//

    P1SEL |= BIT1 + BIT2; // P1.1 UCA0RXD input
    P1SEL2 |= BIT1 + BIT2; // P1.2 UCA0TXD output

    //------------ Configuring the UART(USCI_A0) ----------------//

    UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
    UCA0CTL1 |= UCSSEL_3; // CLK = SMCLK

    // 115200 BAUD, CLK=12MHz
    UCA0BR0 = 6; //this is working
    UCA0BR1 = 0; //this is working
    //*ours: UCBRF = 8, UCBRS = 0, UCOS16 = 1
    // UCBRF = 11, UCBRS = 0, UCOS16 = 1
    // BITS| 7 6 5 4 | 3 2 1 | 0 |
    // UCAxMCTL = | UCBRFx | UCBRSx | UCOS16 |
    UCA0MCTL = 0x81; //this works fine

    {

    while( !(IFG2 & UCA0TXIFG) );


    UCA0TXBUF = 0xAA; // Transmit a byte

    while( !(IFG2 & UCA0TXIFG) );
    UCA0TXBUF = 0x01; // Transmit 2nd byte

    while( !(IFG2 & UCA0TXIFG) );
    UCA0TXBUF = 0x00; // Transmit 3rd byte

    while( !(IFG2 & UCA0TXIFG) );
    UCA0TXBUF = 0x01; // Transmit 4th byte
    }
    }
  • Hello Murthada,

    I hope you have realized that the code that you have posted is MSP device code (does not work on a TM4C) and that you have posted it on the TM4C forum....

    Regards
    Amit
  • Hello Amit

    I apologize, so let me rephrase my question:
    How can I read the UART receive buffer?

    Thank you
  • Hello Murtadha,

    Again: Are you using a TM4C device, and if yes, then please include the code the pertaining to TM4C.

    Regards
    Amit