Loss of Interrupts

dave—w wrote on Monday, July 24, 2017:

Hi,

I’m stuck trying to figure out why I’m losing bytes with a UART ISR. I send and receive packets of data and rarely I’m missing a byte on the receive side. (CRC causes the message to fail.) This happens on 2 different Microchip PICs, PIC32MX460F512L and PIC32MX470F512L. I’ve gone through the PIC documenation inside and out and haven’t found any problems there. So just to be sure, I want to ask about FreeRTOS (v8.1.2).

I’ve inserted the following code into port_asm.s:

 	.extern U2InterruptWrapper

////////////////////////////////////////////////////////////////////////////////
//
// UART interrupt service routine
//
////////////////////////////////////////////////////////////////////////////////

.set	nomips16
.set 	noreorder
.ent	U2InterruptWrapper

// interrupt entry point
U2InterruptWrapper:

	// save the current task context
	portSAVE_CONTEXT

	// call the C function to handle the interrupt
	jal U2InterruptHandler
	nop

	// restore the context of the next task to execute
	portRESTORE_CONTEXT

  .end  U2InterruptWrapper

My priority is 3, which I believe is the highest priority in the system. My PICs have 8 byte FIFOs and I’m using 115,200 BAUD which is about 83 usec per byte. With a 12.5 nsec clock time in the PIC, there should be plenty of time to read all the bytes from the FIFO.

Is there something I’m missing that might cause this to lose bytes?

Thanks for the new sets of eyes.

Dave

rtel wrote on Monday, July 24, 2017:

Can’t tell from the code you posted. Please show the U2InterruptHandler
code too.

I remember there was some discussion on the PIC32 UART interrupts some
years back. As I recall (?) it resulted from a change in the way
interrupts were handled between different PIC32 part numbers. You mind
find something in the forum on this.

dave—w wrote on Monday, July 24, 2017:

Here is the receive side…

void
U2InterruptHandler(
	void)

{
	U8 c;
	static BaseType_t YieldRequired;

	// look for receive interrupt
	if(IFS1bits.U2RXIF)
	{
		// look for more receive data
		while(U2STAbits.URXDA)
		{
			c = U2RXREG;
			*RxBufEnd = c;
			if(++RxBufEnd == (RxBuffer + BUF_SIZE))
				RxBufEnd = RxBuffer;

			// for every FS, increment the semaphore
			if(c == FS)
				// increment the task semaphore
				xSemaphoreGiveFromISR(UartRxSemaphore, &YieldRequired);

			if(U2STAbits.OERR)
				// clear overrun errors
				U2STAbits.OERR = FALSE;
		}

		// clear the receive interrupt flag
		IFS1bits.U2RXIF = FALSE;
	}
    
    ... <transmit side>
}

I will search the archives. Thanks for the advice.

Dave

rtel wrote on Monday, July 24, 2017:

Double check where the interrupt is being cleared - I think on some
devices it needs to be first in the ISR, and on others last. Perhaps
look at the drivers provided by Microchip for the device you are using
as a reference.

dave—w wrote on Monday, July 24, 2017:

Yes, thanks. Been there, done that. I conform to the Microchip usage.

BTW, I forgot the end of the ISR function I posted above. After the transmit side at the end of the function is:


	// context switch if necessary
	portEND_SWITCHING_ISR(YieldRequired);

I never fully understood what this is doing. I just followed the FreeRTOS examples. The only place this is used is on the RX side when passing the (counting) semaphore from the ISR to the task. Does this make sense?

Thanks again.

Dave

dave—w wrote on Friday, July 28, 2017:

I’m still having no luck tracking this down. I looked at the ISR vector table and everything appears to be normal with one thing I don’t understand. The CS0 interrupt vector is set to vPortYieldISR. I have no idea what that is, and I mentioned above that I didn’t know what the portEND_SWITCHING_ISR(YiedlRequired); code does. I would guess these 2 are related, but I don’t know.

Is this a required part of the ISR processing? (See post above.)

Thanks,

Dave

richard_damon wrote on Friday, July 28, 2017:

portEND_SWITCHING_ISR() performs or schedules a task switch if needed (based on the YieldRequired parameter). If an ISR does not use this at the end, then if it woke up a task tthat is now the highest priority, it won’t start to execute until something else cause a task switch (like possibly the time tick).

One some processors, this is performed by software triggering a lowest priority interrupt which forces the scheduler to run.

dave—w wrote on Friday, July 28, 2017:

Hi Richard,

Sorry for being dense… I’m guessing that when I do the GiveFromISR that the YieldRequired variable is loaded inside that routine. Then before I exit the ISR, the portEND_SWITCHING_ISR decides from the contents of YieldRequired whether or not to task switch.

But also, looking the the reference manual, I see a different function portYIELD_FROM_ISR().

Basically, I’m just looking for confirmation I’ve implemented this right and that is not the reason for missing interrupts.

Thanks!

Dave

richard_damon wrote on Friday, July 28, 2017:

The various ‘FromISR’ rooutines will set the value of the flag true if they wake up a higher priority task, and thus need to signal you to trigger a scheduler activation.

As to the way you use the variable, from what I have seen, different ports define the mechanism in different ways. (I suspect in part based on how old they are), and some have slightly different rules for how to use these functions.

dave—w wrote on Saturday, July 29, 2017:

Thanks for the guidelines.

Dave