Increase a priority of task in ISR

Hi,
ideally I would like to increase the priority of a task inside an ISR and only is certain conditions (tested inside the ISR - if a flag is set) but I see there isn’t a ISR version for the vTaskPrioritySet().

Because of that I assume changing the priority of a task inside an ISR is not good practice?
Or are there ways to do it?

I can work around it but would make the code more complex.

Thank you :slight_smile:

You are right that I don’t see a version of vTaskPrioirtySetFromISR, but looking at the code, I don’t see a reason one could not be made, but maybe it is long enough to handle some of the cases that it wasn’t created.

One alternative, assuming that the Timer/Service task has been given a high priority as is the common case, would be to have the ISR pend a callback that does the operation.

I will say that changing the priority of a task is an unusual action, and perhaps you might describe why you need to do this, as there might be some other way to do this.

I presume this is some sort of ‘exceptional’ condition, as that is the main thing I can think of.

Thank you Richard,

I find small pointers/comments like that very useful to get me to think in better ways on how to use freeRTOS.

The micro works as SPI slave and the SPI ISR is only called when CS goes back high and I have to control a busy signal signalling the master when the reply is ready so the master SPI can clock it out of the slave micro (the one this code runs on). Most messages can take long time to reply to the master and is ok to wait for the task to put together the reply even many ms later. But there are some messages that need to be replied immediately. That is why I was thinking of dynamically changing the task priority.

By pend a callback you mean using xTimerPendFunctionCallFromISR()? I didn’t look into that function because the xTimer prefix was misleading. But it seems that might be a solution.
If I understand correctly the API, both pvParameter1 and ulParameter2 can be left blank, correct? I am asking because in the sample the wording “interface” in xInterfaceToService is confusing. What is meant by interface?

Also what do you mean by “but maybe it is long enough to handle some of the cases that it wasn’t created.”?

Thank you

My first thought for that pattern, some are high priority, and some are low, is to have the Task start at the high priority, and if it wakes up and sees that the request is low priority, drop its priority while it processes, and the return back high when it loops to its wait again.

This way the logic for the message is all in the task, and the ISR is kept simple.

At least for most systems, this would simplify the logic, and the impact of starting the task at high priority and it dropping the priority is fairly small, just a possible cost of two context switches if some operation between these priorities is running.

Thank you Richard :slight_smile:

I have a suspicion that it might not be a good idea to provide vTaskPrioritySetFromISR() as this may compromise future priority inheritance enhancements (the function would have to trace/stack all dependencies if the task whose priority is supposed to be raised owns a mutex).

The 8.x implementation of vTaskSetPriority (I don’t have other code available right now) is definitely not ISR safe as it calls taskYIELD_IF_USING_PREEMPTION() which in some ports may not be ISR safe.

@Rik001: You may want to keep two distinct tasks with appropriate priorities to handle high and low priority host commands, just make sure to enforce mutual exclusion between the two . however in that case, you may run into priority inversion due to the priority inheritance scheme mentioned before, so this may be one of the few cases where you may want to prefer binary semaphores over muteces.

Thank you RAc :slight_smile:

I was thinking of keeping it slightly simpler. To make the SPI task high priority and that processes only the few time sensitive messages. Then all other messages to be processed by the xTimerPendFunctionCallFromISR() which I think is what Richard was referring to.
Would that also work?

Thank you

Well, the only significant difference between that design and the earlier one proposed would be that in the timer case, your low pri messages would be handled in the timer task instead of your dedicated low pri task. Whether that serves your purposes or not would depend on what priority your timer task runs on, and of course whether the timer expiration code would be efficient enough not to starve out other timers.

Another issue that addresses all solutions (except the one you propsed initially if it would work) of course is host protocol design. If the host protocol is strictly serialized (meaning it always waits on the busy signal for an answer even if there is a high pri command pending), you’ll be safe. But if you must be prepared for the host to clock out a high pri command even if there is a pending low pri response, you’ll need to address potential race conditions between the different tasks that “compete” for answering.

es, the existing code is definitely not ISR safe, but my comment was that you should be able to create an equivalent one that is, and taskYIELD_IF_USING_PREEMPTION would just become a conditional setting of the higher priority task was woken flag. It also needs the critical sections changed to the FromISR version.

It can’t impede future priority inheritance enhancements as those don’t depend on the task changing the priority of the task (but it might make the operation longer and less desirable for being in an ISR).

You’re right, of course. The point I raised is independent of what thread of execution (task or ISR) performs the operation. Thanks for pointing it out (politely too, appreciated! :wink:)

Hi,

As others have already pointed out its not good practice and can not be done from an ISR, but…

If you really really really need something like that you could defer interrupt processing to a task. What I mean is you have a very high-priority task that waits for an event from the ISR. It will of course be slightly delayed, compared to being executed directly from the ISR. But the delay might not be too much due to the high priority. You can do some magic in the ISR to “context switch” directly to the high prio task in case it’s awoken. This means your real ISR is very short and the rest is in “task context” as opposed to “interrupt context” where you can call vTaskPrioritySet(). This kind of interrupt processing is sometimes called “top and bottom half”.

Thank you @RAc, @robert.berger and @richard-damon.
No idea what happened but I did not get the notifications and seeing those replies only now as I was looking for some old posts.
Thank you as always! :slight_smile:

What is the best and, most importantly the fastest way, way to “context switch” from the ISR as suggested above?

Thank you :slight_smile:

It depends on the port, but generally there is a macro in portmacro.h called portYIELD_FROM_ISR or portEND_SWITCHING_ISR that will invoke the scheduler and switch to the new highest priority task that is awake.

These macros tend to take a parameter which is expected to be the ‘wasWoken’ flag, and the switch occurs if it is non-zero.