How to wake up a FreeRtos task from a high priority ISR?

Using:
  • Stm32F10x, F2xx, F4xx
  • FreeRtos 8.1.1
  • gcc-arm-none-eabi-4_8-2014q2
I have an ISR which must run with high interrupt priority, so that’s forbidden to call FreeRtos Api from within this ISR (see here and here). In some cases these ISR detects conditions, for which a sleeping FreeRtos task should be waked up with at least possible latency. Normally (if the ISR was allowed to call FreeRtos Api because of enough low priority) I would use a queue or semaphore to solve this. But how to realize that with a high priority ISR? My current interims approach is like this (briefly outlined):
volatile int flag = 0;

void XYZ_IRQHandler() {
    if (someCondition)
        flag = 1;
}

void FreeRtosTaskFunction(void* parameters) {
    for (;;) {
        if (flag == 1)
            doSomething();
        vTaskDelay(1);  // sleep 10ms (tick frequency is 100Hz)
    }
}
But this approach has the disadvantages:
  • Latency (from setting the flag in ISR until task wakeup) to is up to 1 FreeRtos tick.
  • Need to poll the flag (waste of cpu cycles).
Another approacht might be (not tested until now) to set up an additional low priority interrupt and trigger this from my high priority ISR using EXTI_GenerateSWInterrupt(). This way seems to solve the latency problem but for the cost of a EXTI line and also an additional IRQ channel. Any suggestions to solve this in a better way? What’s the FreeRtos prefered way to such things? Joe.

How to wake up a FreeRtos task from a high priority ISR?

You are venturing into the depths of ‘expert user’ territory, and non-portable code here, but something like the following should work: At the bottom of FreeRTOSConfig.h (or in a header file included from the bottom of FreeRTOSConfig.h) define a macro something along the lines of:
#define traceTASKSWITCHEDOUT() /* Must use this name. /
{
  if( flag != 0 )
  {
    / Give the semaphore on which the task you want
    to wake is blocked.  xSemaphoreGiveFromISR() is a
    much lighter function in the SVN head revision
    than in the current release!  You must use the
    'FromISR' version. */
    xSemaphoreGiveFromISR( ... );
    flag = 0;
  }
}
Then add the line: portYIELDFROMISR( pdTRUE ); after you set the flag to 1 in your ISR. Theory: Calling portYIELDFROMISR( pdTRUE ) will result in a context switch being requested. Inside the context switch interrupt the traceTASKSWITCHEDOUT() macro will get called before another task is selected to enter the running state – placing the task you want to run into the Ready state, and so making it the task that is selected to run (assuming it is the highest priority ready task). Regards.

How to wake up a FreeRtos task from a high priority ISR?

Thanks for this very interesting post; especially because it shows me a bit more how the task switching works in FreeRtos. I though about you approach for a while, but after then, I think that using a trace macro as a hook for productive functionality is a bit too hacky for my project. Now finally, it seems that I succeed using the EXTI approach.

How to wake up a FreeRtos task from a high priority ISR?

I agree with you, The recommended way, as in the FreeRTOS manual (btw, you bought one, right?…) is to use a binary semaphore. Some task is waiting on that semaphore ans the ISR uses xSemaphoreGiveFromISR() Alain Em 10-10-2014 22:10, Joe Merten escreveu: >
Thanks for this very interesting post; especially because it shows me a bit more how the task switching works in FreeRtos. I though about you approach for a while, but after then, I think that using a trace macro as a hook for productive functionality is a bit too hacky for my project.
How to wake up a FreeRtos task from a high priority ISR? https://sourceforge.net/p/freertos/discussion/382005/thread/140cde98/?limit=25#56a2
Sent from sourceforge.net because you indicated interest in https://sourceforge.net/p/freertos/discussion/382005/ https://sourceforge.net/p/freertos/discussion/382005 To unsubscribe from further messages, please visit https://sourceforge.net/auth/subscriptions/ https://sourceforge.net/auth/subscriptions

How to wake up a FreeRtos task from a high priority ISR?

Reopening the discussion:
Is there an estimative of the longest critical session handled inside freertos functions? ( the longest period of time where a normal interrupt will be delayed to be served)
My scenario: – STM32F103 (CM3) running at 72Mhz – My application only uses queues and soft timers – No calls to critical sessions in application code I have an interrupt which need to be served in an maximum of 200us, but, if some condition is met, this interrupt needs to send a message, although most of the times this will not happen. The message sending and its processing is not so critical, so the approach of making this interrupt a “high interrupt” and signaling and EXTI interrupt (where the message will be sent) would work, but I want to know if this is really needed (as I have other interrupts as Serial reception and etc. that also would be critical to serve with a maximum delay) Thank you P.S. for Allain: In Joe’s case is not possible to use any FreeRTOS API (like xSemaphoreGiveFromISR), because his interrupt have a highter priority and can preempt RTOS critical functions (which is used by FreeRTOS API), thats why he needs to split his interrupt in 2 parts, the first part with zero latency (is never delayed to be served, but can’t call any FreeRTOS API), and one where he calls API functions (and would be delayed by critical sessions) (regards from sis_embarcados 😉 )

How to wake up a FreeRtos task from a high priority ISR?

I don’t have the data for FreeRTOS, numbers were only collected for SafeRTOS, and it will depend on lots of factors (like compiler optimisation level). If you are only using queues and software timers then I would guess the longest for you is going to be in either the queue send or queue receive function so you could look at that – it uses both critical sections (where required) and scheduler locking (for the longer sections). Interrupts are not disabled when the scheduler is locked.

How to wake up a FreeRtos task from a high priority ISR?

Ok, I will profile these critical sections in my application Thank you

How to wake up a FreeRtos task from a high priority ISR?

One other method to do things like this is to appropriate a second interrupt vector that your high priority interrupt can manually trigger (maybe for some obscure device that you are not using), make that of low enough priority that it can use the FreeRTOS calls, and the high priority interrupt can be zero latency, and the lower priority interrupt can interact with the OS. I find that many processors have plenty of intterupt sources and normally with just a little bit of thought you can figure out how to trigger it (often there is a direct instruction to do so).

How to wake up a FreeRtos task from a high priority ISR?

Exactly Richard, that’s the aproach that Joe and I mentioned in our replies, in our cases we could use one of the external input interrupts that are not linked to any pin, and trigger it inside the zero latency interrupt thru the int flag setting.

How to wake up a FreeRtos task from a high priority ISR?

I’ve measured interrupt response time for my application when finding the best compromise between power dissipation/performance ie. using the lowest possible sysclock. So with just a Cortex-M3 @ 3 MHz I got typical 16 us and worst case 80 us from assertion of the highest prio interrupt until (FreeRTOS covered) ISR was called and set a GPIO pin (followed by setting a notification for the corr. handler task). There are 3 more concurrent interrupt sources at lower prio with associated handler tasks and a main control task. Compiler optimization level is ‘-Os’ (optimize for min. size). I’d guess that you’ll easily meet your deadline with 72 MHz sysclock.

How to wake up a FreeRtos task from a high priority ISR?

Thank’s for your numbers, HS2 ! I’ve just measured the maximum critical period in my system during ordinary execution and got no more than 10us, so I am assuming that will be enough execute it inside the “API call” priority range. Anyway, was a great exercise to understand all implications and workarounds, things were learned today 🙂