Timer task never gets unblocked

j99yu wrote on Tuesday, November 01, 2016:

Platform: ATSAMG55J19
FreeRTOS version: 8.0.1 (most recent version available in Atmel Studio 7)

I’m trying to defer function processing by calling xTimerPendFunctionCallFromISR() in a USB handler ISR.
I followed the example from http://www.freertos.org/xTimerPendFunctionCallFromISR.html and have something like the following in my function UHP_Handler():

    ...
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	xTimerPendFunctionCallFromISR(ohci_bottomhalf, 
								&IntInfo,
								NULL,
								&xHigherPriorityTaskWoken);
	
	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    ...

When the timer task runs, it gets blocked on portYIELD_WITHIN_API() when there are no messages in the queue and then it never seems to unblock even after messages get queued.

I have the task priorities set up such that the timer task priority has highest priority (largest numeric value) and have the USB interrupt priority set up as 11 (which is lower priority than configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY) .

Other relevant code :

#define configMAX_PRIORITIES                            ( ( uint32_t ) 5 )
#define configPRIO_BITS                                 4
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			0x0f
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	10
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

I have three tasks running: idle task (priority 0), timer task (priority 4), and an application task (priority 1).

Question:

Why isn’t the timer task running after portYIELD_FROM_ISR() gets called in the interrupt handler? The first time that the interrupt handler executes, xHigherPriorityTaskWoken does get set to pdTRUE, but in every subsequent execution, this variable equals pdFALSE.

rtel wrote on Tuesday, November 01, 2016:

I cannot see anything obviously wrong in your code.

Why isn’t the timer task running after portYIELD_FROM_ISR() gets
called in the interrupt handler? The first time that the interrupt
handler executes, xHigherPriorityTaskWoken does get set to pdTRUE,
but in every subsequent execution, this variable equals pdFALSE.

This would seem to indicate that the first time it is called it
successfully unblocks the timer task, but in subsequent calls the timer
task was not found to be in the blocked state - maybe because it was:

  1. Unblocked by the first ISR, but never executed. That could be due to
    a memory corruption, perhaps. Do you have configASSERT() defined?
    (Google it for the documentation page). Do you have
    configCHECK_FOR_STACK_OVERFLOW set to 2?

  2. The task was unblocked, and it executed, but the implementation of
    the function that was executed caused the timer task to enter the
    blocked state before the function had returned. What is the function
    you are deferring to the timer task doing? Is it blocking on anything
    else or does it just run to completion?

j99yu wrote on Sunday, November 06, 2016:

configASSERT is defined and I’ve changed configCHECK_FOR_STACK_OVERFLOW from 1 to 2.
No difference.

The behaviour seems to be case 1) you mentioned. No context switching is happening after portEND_SWITCHING_ISR(); execution simply resumes in the task that was running prior to the interrupt. I assume that the correct behaviour is that vTaskSwitchContext() gets run at some point after portEND_SWITCHING_ISR(). However, this is not happening.

What could be preventing a context switching from occuring? How does a context switch happen from within an ISR anyway?

rtel wrote on Monday, November 07, 2016:

How does a
context switch happen from within an ISR anyway?

You are using an ARM Cortex-M, right? If so then the context switch
happens in the PendSV interrupt, and the interrupt that asks for the
context switch simply sets the PendSV interrupt pending. Once the
PendSV is set pending it will execute immediately that all other higher
priority interrupts have completed.

I assume you have the PendSV interrupt installed? Are you seeing other
context switches or is it always the same task that is running (perhaps
re-reading the thread the answer to that would be obvious, but I’m
replying via email).

I would recommend updating to the latest version of FreeRTOS as it will
contain many more configASSERT() calls that might highlight your issue…
You can do that by simply copying the latest source files (including
the port layer) over the top of the source files you are currently using.

j99yu wrote on Tuesday, November 08, 2016:

I can see context switches happening up until the point that the USB interrupt is enabled. Could it be that these interrupts are occuring at too high a frequency (every ms) and keep preempting the PendSV interrupt, never allowing it to run?

rtel wrote on Tuesday, November 08, 2016:

Interrupts at 1ms is not going to be a problem.

I can see context switches happening up until the point that the USB
interrupt is enabled.

That is a big clue. Have you posted the code of the USB ISR? Is the
USB working in an application that is not using FreeRTOS?

j99yu wrote on Thursday, November 10, 2016:

This is the code for the USB ISR:

void UHP_Handler()
{
	
	uint32_t int_status;
	uint32_t rh_status;
	uint32_t rh_port_status;
    struct interruptInfo IntInfo;

	rh_status = OHCI->HcRhStatus;
	rh_port_status = OHCI->HcRhPortStatus;

	/**
	 * Read interrupt status (and flush pending writes).  We ignore the
	 * optimization of checking the LSB of hcca->done_head; it doesn't
	 * work on all systems (edge triggering for OHCI can be a factor).
	 */
	int_status = OHCI->HcInterruptStatus;

	/* We only care about interrupts that are enabled */
	int_status &= OHCI->HcInterruptEnable;

	IntInfo.int_status= int_status;
	IntInfo.rh_port_status= rh_port_status;
	IntInfo.rh_status= rh_status;
	
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	
	xTimerPendFunctionCallFromISR(ohci_bottomhalf, 
								&IntInfo,
								NULL,
								&xHigherPriorityTaskWoken);

	portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

After raising the PendSV interrupt priority to be above that of the USB ISR, it now gets invoked. Is there an issue, however, setting the PendSV priority to be one of the highest?

davedoors wrote on Thursday, November 10, 2016:

Are you clearing the interrupt? How often is the interrupt executing? When you answer the second question don’t say how often you think it is executing, measure it, you might be surprised. Your post basically says only higher priority interrupt will execute after the USB interrupt which might mean the USB interrupt is executing all the time.