In NIOS2 port queueYIELD_IF_USING_PREEMPTION expanded into TRAP instruction. This instruction immediatelly call task switching, not pending like PendSV on Cortex-M.
Look at code. In xQueueGenericSend we can see this sequence:
taskENTER_CRITICAL();
...
queueYIELD_IF_USING_PREEMPTION();
...
taskEXIT_CRITICAL();
After expanding macros:
vTaskEnterCritical();
...
asm volatile ( "trap" ); // task switching
...
vTaskExitCritical();
Let’s insert body of vTaskEnterCritical/vTaskExitCritical:
portDISABLE_INTERRUPTS();
( pxCurrentTCB->uxCriticalNesting )++;
...
// pxCurrentTCB->uxCriticalNesting == 1
asm volatile ( "trap" ); // change pxCurrentTCB !!!
// pxCurrentTCB->uxCriticalNesting == 0
...
if( pxCurrentTCB->uxCriticalNesting > 0U )
{
// Not executed!
( pxCurrentTCB->uxCriticalNesting )--;
if( pxCurrentTCB->uxCriticalNesting == 0U )
portENABLE_INTERRUPTS();
}
It’s clear?
We disable interrupt and increase uxCriticalNesting for first task. Then we switch to second task with zero uxCriticalNesting. We NOT enable interrupt at return from xQueueGenericSend. Application hang.
Workaround: Do not use portCRITICAL_NESTING_IN_TCB for port with immediate task switching.
Remark: Ports for Cortex-M do not affected.