vTaskNotifyGiveFromISR running into hard fault

Task 1, Task 2 same priority, time spliced.

Task 3 higher priority.

Task 3 services 8 different ISRs.

I use vTaskNotifyGiveFromISR(ISRTaskHandle, &pxHigherPriorityTaskWoken);

portYIELD_FROM_ISR( pxHigherPriorityTaskWoken );

from the ISR to unblock Task 3.

Task 3 is blocked using ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(50));

When task 3 is done checking for 8 ISRs, I use taskYIELD();

I am running into a hard fault when I try using vTaskNotifyGiveFromISR. Task 3 is getting created, but I am unable to unblock it.

If I add the following to FreeRTOSConfig.h
#define configASSERT( ( x ) ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

What do I define x to be? Seems like a different data types are used for x in the free RTOS C files.

I added this code to the MCU startup file:
/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
static void HardFault_Handler(void)
{
__asm volatile
(
" tst lr, #4 n"
" ite eq n"
" mrseq r0, msp n"
" mrsne r0, psp n"
" ldr r1, [r0, #24] n"
" ldr r2, handler2_address_const n"
" bx r2 n"
" handler2_address_const: .word prvGetRegistersFromStack n"
);
}

I am getting a compiler error for the assembly code E0003 unexpected trailing operands
Thanks,
Priya

The calls to vTaskNotifyGiveFromISR() increment the notification count of the target task - which is good because you are effectively counting the number of interrupts outstanding. The call to ulTaskNotifyTake() with the first parameter set to pdTRUE clears the count though. If that matters or not depends on how you are detecting that interrupt have occurred. If you poll each to see then it is probably ok - if you are relying on a one to one mapping between the number of timer vTaskNotifyGiveFromISR() is called and the number of times you process an interrupt then you will need to set the first parameter to pdFALSE instead of pdTRUE.

Calling taskYIELD() will yield processing time to any other tasks that are able to run and have the same priority as the task calling taskYIELD(). If there are no other such tasks it will have no effect. What is the intended behaviour of calling taskYIELD() here?

Please show the code used to create the task, including how its handle is stored.

It doesn’t need to be anything - as you have it is fine - the C pre-processor populates x for you when it expands the macro.

Which chip are you using? Which compiler are you using?

The calls to vTaskNotifyGiveFromISR() increment the notification count of the target task - which is good because you are effectively counting the number of interrupts outstanding. The call to ulTaskNotifyTake() with the first parameter set to pdTRUE clears the count though. If that matters or not depends on how you are detecting that interrupt have occurred. If you poll each to see then it is probably ok - if you are relying on a one to one mapping between the number of timer vTaskNotifyGiveFromISR() is called and the number of times you process an interrupt then you will need to set the first parameter to pdFALSE instead of pdTRUE.

In all the ISR routines, I set flags to keep track of the interrupt having fired. The task polls these flags and clears it after servicing. Is this OK with the syntax as it is?

Calling taskYIELD() will yield processing time to any other tasks that are able to run and have the same priority as the task calling taskYIELD(). If there are no other such tasks it will have no effect. What is the intended behaviour of calling taskYIELD() here?

I put in taskYIELD thinking lower priority tasks can get a turn. This is probably taken care off by ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS(50)); Once the ISR is serviced, if there are no others remaining, task 3 will be blocked again. Let me know if otherwise.

Please show the code used to create the task, including how its handle is stored.

xTaskCreate( ISRTask, “ISR”, mainISR_TASK_STACK_SIZE, NULL, ( unsigned portBASE_TYPE ) mainISR_TASK_PRIORITY, &ISRTaskHandle);

vTaskStartScheduler();

Which chip are you using? Which compiler are you using?
TM4C1290NCPDT, TI v16.9.3.LTS

Thanks,
Priya

If you are separately setting flags in the interrupts then make sure the flags are not binary, but count the interrupts. Additionally you are going to need a critical section in the task where it decrements the count value to protect against the task and interrupt
accessing the lags at the same time.

taskYIELD will only yield to tasks of equal priority - really recommend reading the first chapters in the book.

Here is my code for Task 3:

void ISRTask(void * pvParameters)
{

    for( ;; )
    {
        ulTaskNotifyTake( pdFALSE, portMAX_DELAY);

        if (flagRotaryPWMISR){
             ProcessRotaryPWM_ISR();
             flagRotaryPWMISR = 0;
         }

         if (flagRotaryTimerISR){
             ProcessRotaryTimer2_ISR();
             flagRotaryTimerISR = 0;
         }

         if (flagLinearMotorPWMISR){
             ProcessLinearMotor_ISR();
             flagLinearMotorPWMISR = 0;
         }

         if (flagLinearMotorTimer2ISR){
             ProcessLinearMotorTimer2_ISR();
             flagLinearMotorTimer2ISR = 0;
         }

         if (flagSensorTimerISR){
             ProcessSensorTimer_ISR();
             flagSensorTimerISR = 0;
         }

         if (flagSensorADCSamplerISR){
             ProcessSensorADCSampler_ISR();
             flagSensorADCSamplerISR = 0;
         }

         if (flagThermistorADCSamplerISR){
             ProcessThermistorADCSampler_ISR();
         }
     }
}

I have just found the hard fault happens when I use vTaskNotifyGiveFromISR from timer interrupts. If the interrupt is from any other module listed, I am not seeing a hard fault.

Can you confirm if this code (ulTaskNotifyTake( pdFALSE, portMAX_DELAY); ) will block task 3 when the ISRs are done being serviced and let the lower priority tasks run? Is this code adequate to count the number of times vTaskNotifyGiveFromISR happens?

Thanks,
Priya

Yes it will - but you code is neither counting the interrupts so you know you have processed all of them, nor protecting the flags, so has race conditions. I suspect you will miss interrupts, and maybe even process the same ones multiple times.

If your interrupt increments the flag flagLinearMotorPWMISR, then in your task you can decrement it using:

taskENTER_CRITICAL();
flagLiniearMotorPWMISR--;
taskEXIT_CRITICAL();

to prevent the flag being written to by the interrupt and the task at the same time. I would imagine PWM interrupts to be extremely fast though - so consider processing them directly in the handler rather than deferring to a task.

Regarding the crashes. Have you looked through this list, taking particular note of interrupt priorities and having configASSERT() defined. Using the latest version of FreeRTOS will help as it has more asserts defined to check configuration matches hardware.

I would imagine PWM interrupts to be extremely fast though - so consider processing them directly in the handler rather than deferring to a task.

The code in production currently does this. It does synchronized printing in the PWM ISR as well. This involves interrupts happening inside an ISR. If deferring this to a task is not a good idea, it is possible the production firmware is good enough as it is. Let me know if otherwise.

Thanks,
Priya