I ahve been reading the taskENTER_CRITICAL_FROM_ISR() api page here: This page describes the FreeRTOS taskENTER_CRITICAL_FROM_ISR() and taskEXIT_CRITICAL_FROM_ISR() API macros
And in the example it shows that if you are calling a function from a ISR where you use taskENTER/EXIT_CRITICAL_FROM_ISR() then you also need to implement the same inside that function.
Sometimes you need to use library functions that you don’t have access to the source code (to modify it) but need to call them from the ISR.
Couple of questions:
I assume that if they are defined as inline AND the compiler does treat them as such it’s ok and don’t need to do anything. Correct?
but if they are not defined as inline or the compiler does not treat them as inline then what do you do? In the second case I initially thought of creating a wrapper function but immediately occurred to me that does not solve the problem.
What does this mean ? How is this related to compiler inlining ?
Which problem do you want to solve ? Can you provide an example ?
First, you need to verify that the functions ARE in fact callable from an ISR. Some functions just aren’t because they do things like call malloc, or want to block for something.
If this is the case, then you need to move that code out of the ISR and into a task.
If the code is really usable from an ISR, but needs atomic access to data that is accessed by other interrupts, then you can wrap the whole function in a taskENTER/EXIT_CRITICAL_FROM_ISR() and any task level code that is accessing that same data needs to wrap its access in a taskENTER/EXIT_CRITICAL() call.
This also underlines that you should do LESS in ISRs and delegate as much work as possible to a task. This avoids a lot of trouble dealing with the restrictions of the ISR context.
Thank Hartmut and Richard,
yes, I always keep the ISR as short as possible. My reasoning about the inline function being called form the ISR is that if it is declared inline then everything of that function is effectively replacing the text of the function name/call. So no need to put the enter/exit_critical_from_ISR in that second function would be pointless.
I am not trying to solve any problem specifically, it was just a thought that came to mind after reading the enter/exit_critical_from_ISR API page and the example they provide there.
when you say “If the code is really usable from an ISR, but needs atomic access to data that is accessed by other interrupts, then you can wrap the whole function in a taskENTER/EXIT_CRITICAL_FROM_ISR()” do you mean placing the the taskENTER/EXIT_CRITICAL_FROM_ISR() before and after the function call BUT in the ISR routine? If so, that is what I was wondering…
From my understanding of the example shown in the API page it looks like you have to add taskENTER/EXIT_CRITICAL_FROM_ISR() also inside the function called from the ISR.
Why ? That’s the point of a critical section (and also a mutex - they share the same idea), once entered you’re in and safe until exit.
Also forget the idea that code inlining solves any of the concurrent data access issues where you need protection by a critical section or mutex. It doesn’t.
Don’t think of the domain protected by the critical section as a ‘textual context’, it is an execution context. Everything that is executed between those to statements will be executed without being able to be interrupted, call instructions in between don’t matter.
Well, the page is trying to show that the calls to
taskENTER/EXIT_CRITICAL_FROM_ISR() can be nested, i.e., you can call these functions (well, macros) as many times as you want - keeping in mind that the complementary function is called a similar number of times.
That is to say that if you call
taskEXIT_CRITICAL_FROM_ISR() 3 times, then
taskEXIT_CRITICAL_FROM_ISR() must also be called 3 times.