I have a task waiting on a notification, I aim for a semaphore-like binary behaviour.
The stuff works fine as long as I call xTaskNotifyGive( taskHandle ) within another task (not ISR). The waiting task awake from :
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
Now I want to do the same thing from my ISR (InterruptCan1High), I call :
xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR( taskHandle, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
…and the waiting task never wake. Interrupt comes and comes, multiple vTaskNotifyGiveFromISR() are done.
NESTED_INTERRUPT_ENTRY_IRQ() is some assembler code we defined in order to manage nesting interrupt. But I don’t use it for rtos tick interrupt and the swi interrupt cause it seems conflict with freeRtos stuff.
We have CANBUS interrupt using NO rtos stuff at all and I use these define in order it works.
I’ll test what you talk about stepping through vTaskNotifyGiveFromISR(), I’ll be right back.
I can’t recall if the TMS570 port support interrupt nesting or not, but know the generic ARM Cortex-R port does. If the port does implement interrupt nesting it could be dangerous to have your own code on some interrupts and use FreeRTOS code on other interrupts if those two interrupts could nest with each other (don’t know that for a fact, hence I say ‘could’).
I have the same issue, actually it seems that none of the FromISR calls are working, I have tried at least task notification, semaphores, queues and deferred interrupt handling.
My setup is very simple, just one simple task having only waiting point and a separate timer interrupt routine (60 ms interval) trying to wake it up. Tick is 1 ms. The code is straight from the text book. Using debugger I can see that it looks like the FromISR is working correctly but the task is not unblocked. The task and the interrupt priorities are the same (1). Maybe there is something very basic missing from my setup. Is there something specific in the configuration file that needs to be added to make it work? This is my freertos configuration .h
#define MPLAB_PIC24_PORT
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configCPU_CLOCK_HZ ( ( unsigned long ) 16000000 ) /* Fosc / 2 */
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 4 )
#define configMINIMAL_STACK_SIZE ( 115 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) (6000) )
#define configMAX_TASK_NAME_LEN ( 4 )
#define configUSE_TRACE_FACILITY 0 // For tracing
#define configUSE_16_BIT_TICKS 1
#define configIDLE_SHOULD_YIELD 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define configUSE_MUTEXES 1
#define configKERNEL_INTERRUPT_PRIORITY 0x01
Have you followed the instructions on the documentation page for the
PIC24, and used the examples provided as a template?
The instructions from the web page (which is somewhat historic):
"Interrupt service routines that cannot cause a context switch have no
special requirements and can be written as per the compiler documentation.
Interrupt service routines that can cause a context switch must execute
with priority portKERNEL_INTERRUPT_PRIORITY, and only call taskYIELD()
at the very end of the service routine after the interrupt source has
been cleared. See the file serial.c included in the demo application for
an example."
The example provided:
void __attribute__((__interrupt__, auto_psv)) _U2TXInterrupt( void )
{
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* If the transmit buffer is full we cannot get the next character.
Another interrupt will occur the next time there is space so this does
not matter. */
IFS1bits.U2TXIF = serCLEAR_FLAG;
while( !( U2STAbits.UTXBF ) )
{
if( xQueueReceiveFromISR( xCharsForTx, &cChar,
&xHigherPriorityTaskWoken ) == pdTRUE )
{
/* Send the next character queued for Tx. */
U2TXREG = cChar;
}
else
{
/* Queue empty, nothing to send. */
xTxHasEnded = pdTRUE;
break;
}
}
if( xHigherPriorityTaskWoken != pdFALSE )
{
taskYIELD();
}
}
I just tried this in the simulator and it seems to work.
I think I have followed the instructions as such. I’m not using the PIC24 demo project, my HW is something else than the explorer board.
It’s getting a bit weird. I played with xQueueSendFromISR and if I go through the code line-by-line (using step-into in MPLABX) it works. But if I let the code run freely, it doesn’t. I followed the code and found strange behaviour in queue.c at line 1258. I assume that the scheduler works correctly and calls the xQueueGenericReceive to wake up the task. Something happens at line 1258 when it uses taskENTER_CRITICAL() macro. By using “step-into” the debugger passes the taskENTER_CRITICAL and enters the next code line after at line 1264 and eventually comes out of the xQueueReceive in the task as expected. But if I use “step-over” or set a breakpoint at line 1264, it will never reach that line (just stays running and never wakes up the task). Here’s the FreeRTOS code for taskENTER_CRITICAL()
Thanks Richard, that seemed to solve the problem! I was using old ISR template and didn’t check the interrupt flag setting at all (assumed it to be correct one). I was just too blind to see the solution.
Now it works, I have to admit that I don’t know exactly why.
But when the error was there, stepping through xTaskGenericNotifyFromISR() the problem was that the original state of the thread is taskNOTIFICATION_RECEIVED instead of taskWAITING_NOTIFICATION and the task was NOT unblock by the call.