Preemption of higher priority task

Hello, I study FreeRTOS mechanisms on STM32L4 target. I suppose a problem on one of my tests. High priority task does not preempt low priority task. This is what is done : I create two task : Task one (priority 5), task two (priority 3) Os tick is set to 1ms. Task two loops on active waiting of 2ms (no OS waiting in its processing). Task one waits an OS event flag. Task one event is sent by hardware interruption routine each 5s. I monitor task execution by switch microcontroller digital outputs. What I watch : Each 5s, task one event is sent by interruption, but task one is never unblocked of event waiting. Task two is executed all the time by doing its active waitings. Do you know why OS scheduler does not apply task two preemption by task one ? Thanks.

Preemption of higher priority task

Hi Fabien I think it would be useful if you show the source code that you are using. When you post code, you can put the literal code between two lines which only contain 5 tildas ~ jus tlike I do here (you don’t see the tildas) : ~~~~~ void vtaskOne( void *pvParameter ) { } ~~~~~ Regards.

Preemption of higher priority task

Hi ! OK, I post my code. I’ve got a small overlay to create tasks, manage event groups,… Task characterisitics : ~~~~~ STATIC const SVOSstOsTask makstosTasksList[APOSeTASKNUMBER] = { [APOSeTASKONE] = { .pszname = “”, /< Empty name, to limit size of memory used */ .pv_taskFunc = &AP_OS_taskOne, /< Function of task */ .pkvtaskParam = NULL, /< Task parameters, not used */ .u16_stackSize = 512, /< Size of task size, in words (32 bits) */ .e_priority = SV_OS_eTSK_PRIO_HIGH, /< Priority of task */ .bCreateStarted = TRUE, }, [AP_OS_eTASK_TWO] = { .psz_name = “”, /< Empty name, to limit size of memory used */ .pv_taskFunc = &AP_OS_taskTwo, /< Function of task */ .pkv_taskParam = NULL, /< Task parameters, not used */ .u16_stackSize = 512, /< Size of task size, in words (32 bits) */ .e_priority = SV_OS_eTSK_PRIO_NORMAL, /< Priority of task */ .bCreateStarted = TRUE, }, }; ~~~~~ Task one processing : ~~~~~ void APOStaskOne(void * pviArgument) { u32 u32transmitFlag = 0; /* Conditions before test / HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); / Start HAL timer */ HAL_TIM_Base_Start_IT(DV_BOARD_CONFIG_getTIMHandler(CF_BOARD_CONFIG_eTIM2)); HALGPIOWritePin(GPIOB, GPIOPIN3, GPIOPINRESET); /* Infinite loop / for(;;) { / Wait for event */ u32_transmitFlag = xEventGroupWaitBits( SV_OS_getEvtGrp(AP_OS_eEVT_GRP_TASK_ONE), (AP_OS_CFG_EVT_GRP_TASK_ONE_FLAG1), TRUE, FALSE, 60000);
/* Event raised */
if(0 != (u32_transmitFlag & AP_OS_CFG_EVT_GRP_TASK_ONE_FLAG1))
{
  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
}
else
{
  /* Time-out */
}
} } ~~~~~ Task two processing : ~~~~~ void APOStaskTwo(void * pviArgument) { HALGPIOWritePin(GPIOA, GPIOPIN10, GPIOPIN_RESET); /* Infinite loop */ for(;;) { HAL_Delay(2); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10); } } ~~~~~ Hardware timer routine (Executed each 5s) : ~~~~~ void APOSPeriodicalActionsForTestscbk(void) { HALGPIOWritePin(GPIOB, GPIOPIN4, GPIOPIN_SET); triggerEventTaskONE(); HALGPIOWritePin(GPIOB, GPIOPIN4, GPIOPINRESET); } STATIC void triggerEventTaskONE(void) { BaseTypet u32higherPriorityTaskWoken; BaseTypet u32error; /* Raise flag */ u32_higherPriorityTaskWoken = pdFALSE; u32_error = xEventGroupSetBitsFromISR(SV_OS_getEvtGrp(AP_OS_eEVT_GRP_TASK_ONE), AP_OS_CFG_EVT_GRP_TASK_ONE_FLAG1, &u32_higherPriorityTaskWoken); /* Was the message posted successfully? / if(pdFAIL != u32_error) { / Request a context switch / portYIELD_FROM_ISR( u32_higherPriorityTaskWoken ); } else { / No need to switch context */ } } ~~~~~ Don’t hesitate if you’ve got questions ^^. Regards.

Preemption of higher priority task

Ho ! I just watch that task one is executed when its waiting timeout is reached (60000ms). So I think that problem comes from my timer interruption which sends task one event, or the context switch request (portYIELDFROMISR).

Preemption of higher priority task

What does SVOSgetEvtGrp(APOSeEVTGRPTASK_ONE) evaluate too? Do you have configASSERT() defined? Regards.

Preemption of higher priority task

SVOSgetEvtGrp() returns reference on OS event group. APOSeEVTGRPTASK_ONE is an index to find event group address in an array. ~~~~~ EventGroupHandlet SVOSgetEvtGrp(u8 u8iEvtGrpIdx) {

if (SVOSCFGNBEVT_GROUPS > 0)

if( (u8iEvtGrpIdx > SVOSCFGNBEVTGROUPS) || (NULL == mapstosEvtGrpHandleList[u8iEvtGrpIdx]) ) { return NULL; } else { return mapstosEvtGrpHandleList[u8iEvtGrpIdx]; }

else

return NULL;

endif

} ~~~~~ I don’t have configASSERT(). xEventGroupSetBitsFromISR() returns 1 (pdPASS). u32_higherPriorityTaskWoken is set to 0 (pdFALSE). Regards.

Preemption of higher priority task

Please define configASSERT().

Preemption of higher priority task

Ok, I do that. I don’t know if it’s what you expect. ~~~~~ EventGroupHandlet SVOSgetEvtGrp(u8 u8iEvtGrpIdx) {

if (SVOSCFGNBEVT_GROUPS > 0)

if( (u8iEvtGrpIdx > SVOSCFGNBEVTGROUPS) || (NULL == mapstosEvtGrpHandleList[u8iEvtGrpIdx]) ) { configASSERT(0); //return NULL; } else { return mapstosEvtGrpHandleList[u8iEvtGrpIdx]; }

else

return NULL;

endif

} ~~~~~ ConfigASSERT is not reached. I check address of event group returned by this function. It’s correct, this is the address returned by xEventGroupCreate() at initialization.

Preemption of higher priority task

Have you defined configASSERT() in FreeRTOSConfig.h? Is it defined so that the code cannot continue if the assert test fails? Like disabling interrupts and sitting in a loop?

Preemption of higher priority task

ok ! yes, configASSERT is defined in FreeRTOSConfig.h. ~~~~~

define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

~~~~~ However, no assert test fails.

Preemption of higher priority task

Well I’m afraid I can’t see why it is not functioning. Are you 100% sure the interrupt is being triggered, and that the line HALGPIOTogglePin(GPIOB, GPIOPIN3); in APOStaskOne() is not executing. If there was a problem with the HALGPIOTogglePin() call then maybe you just aren’t seeing the output – if you set a break point on the line does it get hit? Regards.

Preemption of higher priority task

.PNG in attached file presents the result of output measures. Moreover, by breakpoints in debug, timer routine is well reached. In APOStaskOne(), HALGPIOTogglePin() call is not reached.

Preemption of higher priority task

My next test includes an OS waiting is in task Two (vTaskDelay()). From that, task One is executed. Task2 processing : ~~~~~ void APOStaskTwo(void * pviArgument) { u32 u32idxWait = 0; HALGPIOWritePin(GPIOA, GPIOPIN10, GPIOPINRESET); /* Infinite loop */ for(;;) { HAL_Delay(2); for(u32_idxWait = 0; u32_idxWait < 2000; u32_idxWait++); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10); vTaskDelay(1); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10); } } ~~~~~ You can find .PNG in attached file.

Preemption of higher priority task

Could you please zip up your complete project, including the build files, and ensuring there are no absoute paths that would prevent it building on my computer, then send it to r dot barry [at] freertos dot org.

Preemption of higher priority task

Ok, I prepare the archive.

Preemption of higher priority task

I sent you the archive by email.

Preemption of higher priority task

Assuming the tasks have been created as expected, and the interrupt is interrupting, I’m still struggling to see the source of the problem. I was hoping I would be able to build the project, but I don’t have the correct plug-ins. I notice the timer task has a lower priority – that should not matter as both of your tasks have delays in them, so the timer task should always execute – but are you ever finding the call to xEventGroupSetBitsFromISR() returns false? It would be interesting to know the state the tasks were in. You could try calling uxTaskGetSystemState() to ensure the task receiving the event is in the Blocked state as expected. You could also try reducing the block time of the same task, say to 5 seconds, then each time it unblocks increment a counter. That would let you know the task was still healthy, and that the tick rate really is 1ms (if the counter increments at any other rate than once per 5 seconds you would know there was a timing problem).

Preemption of higher priority task

Can you put a break in timers.c in the task-function: ~~~~~ static void prvTimerTask( void *pvParameters ) { TickType_t xNextExpireTime; BaseType_t xListWasEmpty;
/* Just to avoid compiler warnings. */
( void ) pvParameters;

for( ;; )
{
    /* Put a break on this statement: */
    xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
~~~~~ It sounds like this helping task doesn’t run Regards.

Preemption of higher priority task

Hi, thank you very much for your answer. I checked xEventGroupSetBitsFromISR() returned value. It is always pdPASS. Then, I used uxTaskGetSystemState() service to get status of tasks. I’ve got 4 tasks. Task one priority 5, Task two priority 3, Idle task priority 0 and another task priority 2. When task one eventBit is sent, task one stays in eBlocked status ! Other tasks are in eReady status (Task 2 is in eReady status, I find it strange. It reads task status. In my opinion, it should be in eRunning status) I set a counter in task one to count number of unblockings. With block time sets to 5s, counter returns 12 after 1 minute. So, task one is still healthy and there is no timing problem. I think that the problem comes from the hw timer interruption context (priority competition,…). I test another behavior. Hw timer routine does nothing. Periodically, between 2 active waitings, task two sends event to task one. Yet, task one is unblocked. See attached .PNG file. Regards.

Preemption of higher priority task

I agree with Hein, we need to see at which point the deviation from expected behaviour occurs, and the first thing to do is see if the timer task is ever processing the message. To explain: Setting an event bit is not a deterministic operation because you don’t know how many tasks will be unblocked. As FreeRTOS does not permit non-deterministic operations from an interrupt the ‘set bits’ operation is deferred to the task level – and actually occurs in the daemon task (the timer task). The function that executes in the timer task is vEventGroupSetBitsCallback(), which is defined in event_groups.c. Please place a break point in that function to see if it ever gets called. If it does get called then the message is sent to the timer task correctly, and the timer task is processing the message, so we will have to follow it up from there. If it doesn’t get called then we will have to see why not. Regards.

Preemption of higher priority task

I set a breakpoint in this function. It never hits. I don’t use OS timer. I use STM32L4 hw timer to send task one event. Regards.

Preemption of higher priority task

The timer task is not related to hardware timers, only software timers. You cannot call the ‘set bits from isr’ function unless the timer task is being created – and I can see from your code that it is being created, although at a low priority. If xEventGroupSetBitsFromISR() is returning pdTRUE, then the ‘set bits’ message is being posted to the daemon task. However, if vEventGroupSetBitsCallback() is not being called then either the daemon task is not running, or the daemon task is running but the messages is not being processed correctly. You say you have “another task” at priority 2. Is that the timer service task? Its priority is lower than the priority of your two application tasks, but your two application tasks both block, so it should get CPU time all the same. However, as a first experiment try setting configTIMERTASKPRIORITY to ( configMAX_PRIORITIES – 1 ) in FreeRTOSConfig.h. Is the break point in vEventGroupSetBitsCallback() hit now? Regards.

Preemption of higher priority task

OK, it works ! Indeed, the other task priority 2 was the timer service task. vEventGroupSetBitsCallback() was never called. Task TWO blocked the timer task. I set configTIMERTASKPRIORITY to ( configMAX_PRIORITIES – 1 ), and it works. Timer service task is executed in priority. vEventGroupSetBitsCallback() is called. Task one is unblocked. (See results in attached .PNG file) What is the best priority value for timer service task ? the highest value ? Thanks a lot for your support. Regards, Fabien

Preemption of higher priority task

…in which case the problem seems to be in the call to HALDelay(2), or at least, my assumption of what HALDelay() was doing. I assumed HAL_Delay() was calling vTaskDelay() with a block time of 2 ticks. That would of allowed the timer task to execute. However, looking at the code it appears HAL_Delay() delay is defined as:
__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}
So - it is just polling the time and never entering the blocked state - hence it was preventing all lower priority tasks from ever executing at all. HAL_Delay() is a weak function, so it looks like it should be overridden by an RTOS friendly version, such as: void HALDelay( uint32t ulTimems ) { vTaskDelay( pdMSTOTICKS( ulTimems ) ); } The best priority for the the timer task is dependent on the application - although having it at the highest priority is common, especially if you are using it as a deferred itnerrupt handler. Regards.

Preemption of higher priority task

In my case, I think it's better to set the highest priority. In my release code, I rareley use HAL_Delay() and just for 1ms waiting. So, I think that I will not redefine it. I call it a lot in my freeRTOS test project to measure the impact of an active waiting on OS scheduler. Thanks for your advices. Fabien