I am using a hardware timer to execute a task at a faster rate than what the FreeRTOS ticks will allow (1kHz limit).
Currently, I am using a 100us period (10kHz rate).
In this timer’s interrupt handler, I call xSemaphoreGiveFromISR(taskSemphr, higherPrioTskWkn), but this doesn’t work, as the task continues to wait on if(xSemaphoreTake(taskSemphr, portMAX_DELAY) == pdTRUE).
The HW timer’s interrupt priority is set to (configMAX_SYSCALL_INTERRUPT_PRIORITY-1).
I also have vApplicationTickHook() enabled.
Perhaps there is an interaction? Or perhaps I am polling this task incorrectly?
First of all, the taskHandle is probably misnamed, right? It should be a semaphore handle which of course you can name whatever you like, but just to make sure you don’t mistakingly pass a task handle here?
Could it be that your ISR fires so fast that no task has a chance to execute?
Hi @RAc
Yes, you’re right about the taskHandle being renamed - I made a typo in my question.
I’ll edit my post now (it is a semaphore in my code).
Yes, I guess it is possible that this task hasn’t finished executing by the time the semaphore is given again.
However, other tasks are definitely executing.
won’t work as written (unless higherPrioTskWkn is a pointer variable; normally an address operator on a variable is used). Can you post some real code from your code base?
Once again, my apologies for my mistake.
I agree, it makes things tricky when you get bits and bobs of incorrect information.
In the mean time, we have found the problems.
Firstly, the stack size of the task wasn’t big enough.
Secondly, it looks like the task requires some kind of ‘boot-up delay’ when it executes for the first time.
We believe that some of the variables used by the task are not initialised in time for the first execution of this task.
So, the task’s structure looks like this now:
void myTask(void *param)
{
//init local vars
vTaskDelay(100); // delay of 100 ticks (in my case, ms) for init of task & vars
while(1)
{
if(xSemaphoreTake(taskSemphr, portMAX_DELAY) == pdTRUE)
{
//do task's stuff
}
}
}
ok, thanks for the wrap up, great you got it working!
One piece of advice though: The delay you put in before the while() loop is (according to the comment behind it) one of the top ten trap doors in concurrent programming. DO find out WHY you need a delay and DO NOT use an absolute delay; instead, synchronize the task execution with whatever is needed to set up everything correctly. If you just put in some random delay that appears to work without knowing the inner works, Murphy will mandate that the delay is too short in some random installation out there in the field. Or you may have barked up the wrong tree and the delay is just something that looks like it solved your problem whereas in reality it just deferrs it.
I did a bit more digging into the task’s ‘boot-up delay’ I mentioned.
First, I removed the delays from the relevant tasks and then I started a debug session.
The system doesn’t run past a certain point (when it enters a task that used to have a delay for the first time, I believe).
Here is the full call stack:
The debugger always stops me here in port.c (I started and stopped the processor a few times):
Another level up shows that it is waiting on taskEXIT_CRITICAL():
Another level up shows it hasn’t exited vPortExitCritical():
The second last reference has no source code to refer to:
And then the final level on the call stack is a completely unrelated General Purpose Timer interrupt handler (used for FreeRTOS Runtime stats):
Update: I’ve paused it a few more times, and it always lands at the same place in pxPortInitialiseStack(). Sometimes the functions ‘higher’ in the call stack are different, but GPT2_IRQHandler() is always the highest function on the call stack, so this is probably where the issue lies?
I think you are going in the wrong direction in the stack trace. The GPT2_IRQHandler is the last item on the stack, so it seems that you are stuck in that ISR. Perhaps there is an interrupt flag that needs to be cleared so you can exit the ISR, or it is generating interrupts faster than you can process them.
Thank you for your reply!
Are you referring to GPT2_IRQHandler()?
If so, I know that I haven’t included a call to portYIELD_FROM_ISR(), but I thought that was only necessary if we call a FreeRTOS function to start another task?
Because there must be something to set the value of higherPrioTskWkn?
If you are referring to the interrupt handler I spoke of earlier, I am indeed calling portYIELD_FROM_ISR(xHigherPrioTskWkn);, right after giving the semaphore.
Thank you for your response.
I believe that the interrupt flags are cleared, and that the Cortex-M7 I am using should handle the rate of these GPT interrupts (100us period).
I have two ideas as to what it might be:
The GPT2 interrupt occurred at the same time as the FreeRTOS tick handler
Two interrupts of the same priority occurred at approximately the same time, causing the second interrupt to disrupt the first interrupt’s IRQ handler.
Could you perhaps give your opinion on whether any of them could give this behaviour?
I have two more questions:
What interrupt priority does the FreeRTOS tick handler have?
What happens if a FreeRTOS tick occurs while we are busy with another IRQ handler?
Usually the lowest prio. See configKERNEL_INTERRUPT_PRIORITY in FreeRTOSConfig.h
It’s delayed/kept pending given it has the lowest interrupt prio.
You could/should set your non-FreeRTOS GPT2 interrupt to a (logically) prio >= configMAX_SYSCALL_INTERRUPT_PRIORITY +1 if you want to avoid any interference with the FreeRTOS part (interrupts/critical sections) of your application.
Then and with nested interrupts enabled (default) your GPT2 interrupt will interrupt any other running ISR of an interrupt with a logically lower prio.