configMAX_SYSCALL_INTERRUPT_PRIORITY

alsaleem wrote on Sunday, April 09, 2017:

I have an application on STM32F4 that has many interrupts. some have high priority and others have low priority.

My freeRTOS file config has these values (the default).

*#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
*#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

*#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
*#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

The controller has 4 priotity bits (#define __NVIC_PRIO_BITS 4U). This results in 16 levels.
Both configKERNEL_INTERRUPT_PRIORITY & configMAX_SYSCALL_INTERRUPT_PRIORITY will take priority greater than 16

(1) Is my conclusion correct?
(2) How to modify these to allow to categorize interrupts with priorities higher or lower than sysTick?
SysTick interrupt calls HAL_IncTick/osSystickHandler.

(2) Knowing that interrupt should be short and processing should be done later, my application can not wait the task (the task that does processing) to take its “turn” to do processing.
Is there a way to force scheduler to switch to a specific task from ISR?

Thanks.

heinbali01 wrote on Sunday, April 09, 2017:

My freeRTOS file config has these values (the default).

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

That all looks OK to me.

The controller has 4 priority bits (#define __NVIC_PRIO_BITS 4U).
This results in 16 levels.

Level 0 is the normal (non-interrupt) level, so 15 levels remain, from 15 (low) to 1 (high).
Correction, that should have been:
Indeed 16 different priorities, 15 being the lowest, 0 the highest. Priority 0 can not be masked.

Both configKERNEL_INTERRUPT_PRIORITY & configMAX_SYSCALL_INTERRUPT_PRIORITY will take priority greater than 16

No

The value of these macro’s will be used to write NVIC registers.
The configLIBRARYxxx macro’s have a number between 0 and 15, and can be used to call NVIC_SetPriority().

Consider configKERNEL_INTERRUPT_PRIORITY and configMAX_SYSCALL_INTERRUPT_PRIORITY as a bit-mask of the form "pppp....", that can be used to set an NVIC register.

Knowing that interrupt should be short and processing should be done later,
my application can not wait the task (the task that does processing) to take
its “turn” to do processing.
Is there a way to force scheduler to switch to a specific task from ISR?

Yes of course, the best ways is to have the task block on ulTaskNotifyTake() and wake it up from an interrupt by calling vTaskNotifyGiveFromISR() with a handle to that task. That task will be come active immediately, provided that it has the highest priority of all runnable tasks at that moment.
Once your application is debugged, remember to switch off options for stack checking, to disable configASSERT(), and enable compiler optimisations.

An example from FreeRTOS+TCP is:

void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

	/* Ethernet RX-Complete callback function, elsewhere declared as weak. */
    ulISREvents |= EMAC_IF_RX_EVENT;
	/* Wakeup the prvEMACHandlerTask. */
	if( xEMACTaskHandle != NULL )
	{
		vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
	}
}

More text in this post

Regards.

hs2sf wrote on Sunday, April 09, 2017:

(1) Your conclusion is correct but remember these are low-level HW values.
You should also have as look here for further details.

(2) What’s the purpose for interrupt priorities lower than SysTick interrupt prio ?
SysTick interrupt usually has the lowest prio to avoid interferences with any other interrupt used.

I’ve added a tiny helper macro in FreeRTOSConfig.h to help myself dealing with logical rather than HW interrupt priorities.
So the logical prio order is the same as the FreeRTOS task prio order.

// helper macro for logical -> real Cortex-M interrupt priorities

// logical [0 .. IntPrio] => real [configLIBRARY_LOWEST_INTERRUPT_PRIORITY .. configMAX_SYSCALL_INTERRUPT_PRIORITY]
#define uxPortIntPrio(p)    ( UBaseType_t(configLIBRARY_LOWEST_INTERRUPT_PRIORITY) - p )

and I’m using when calling the NVIC CMSIS interface:

NVIC_SetPriority( IrqNumber, uxPortIntPrio( IntPrio ) );

with a used prio range low…high = 1…N i.e. intentionally above SysTick interrupt prio 0

(3) Your priority scheme should ensure that the priority driven scheduler runs the desired task(s).
So if you want to run a certain post-processing task signalled by its ‘coupled’ ISR you should consider them as an corresponding pair.
E.g. if you have a very latency sensitive HW interface you should give the interrupt and its associated handler task the highest prio.
Obviously the prios selected should match your overall application requirements i.e. taking into account your other HW interfaces/ISRs and tasks.
Also keep in mind that FreeRTOS task (software) priorities are are not directly related to HW interrupt priorities.

Good luck, HS2

rtel wrote on Sunday, April 09, 2017:

Normally SysTick and PendSV should be the lowest priority interrupts in the system. Therefore it is not possible have an interrupt hat has a priority lower than them.

STM32 is an exception to this IF you are using the drivers generated by the STM32 Cube. PendSV MUST still be given the lowest interrupt priority, but unfortunately due to the way the STM32 drivers are implemented SysTick will need to be the highest interrutp priority. That is because the implementation of the drivers busy wait inside interrupts for the tick count to change (yes!), and that will cause a deadlock if the SysTick has a priority lower than the busy waiting interrupt. Please do not take that as an example of best practice!

Note priority 0 is a valid interrupt priority, and in fact is the highest priority possible, and the default priority for any interrupt. That is why interrupts that use the FreeRTOS API must not use the default priority assigned to the interrupt. The confusion comes because priority 0 cannot be masked, and writing 0 into the mask register (BasePRI) unmasks all interrupts.

Interrupt priorities on ARM Cortex-M are complex, which is why we have this page to try and explain it: http://www.freertos.org/RTOS-Cortex-M3-M4.html and the newer the version of FreeRTOS you have the more configASSERT() statements have been included to automatically catch misconfigurations.

alsaleem wrote on Sunday, April 09, 2017:

Thank ALL for this thorough explanation.
I realized that I missed diffrentiating priorities when creating tasks.

I appreciate your help.