I have a function calculate() to calculate data. I want to protect it using semaphore.
But the function calculate() can be called in task or ISR, so I not sure I need to use API xSemaphoreTake or xSemaphoreTakeFromISR.
You can NOT protect a function like that with a semaphore (or a mutex), unless it can do something if it is called while protected. Imagine that it is in the protected section with the semaphore taken, then the interrupt occurs, The function will see the semaphore taken but can’t wait for it to be given, as you can’t leave the ISR and then come back.
Code sections that need protection from reentry by ISRs need to use critical sections which disable interrupts (and thus need to be kept small).
If you really need to decide, then some ports provide a function to determine if you are currently inside an ISR, so you could check and do the right action.
I would first think carefully if this is actually being setup right, as generally ISRs should be short and not calling a lot of functions, especial those that do a lot of calculations or need to access protected stuff for long. You might want to see if that part would be better done in a task signaled by the ISR.
Thanks for your reply. I want to respond to your idea.
Imagine that it is in the protected section with the semaphore taken, then the interrupt occurs, The function will see the semaphore taken but can’t wait for it to be given, as you can’t leave the ISR and then come back.
→ My function will take and give a semaphore before exit.
My code:
void calculate()
{
xSemaphoreTake // or xSemaphoreTakeFromISR
…
xSemaphoreGive // or xSemaphoreGiveFromISR
} If you really need to decide, then some ports provide a function to determine if you are currently inside an ISR, so you could check and do the right action.
→ Could you share me the ports to determine if process is currently inside an ISR?
Richard means that a task currently executing calculate can be interrupted after xSemaphoreTake and before xSemaphoreGive is called. I.e. right in the middle of the calculation. Then your ISR failes to xSemaphoreTakeFromISR and can’t calculate.
However, if calculate is called in an ISR it is or should be a short function. Then you should enclose calls to calculate in task(s) by a critical section using taskENTER/EXIT_CRITICAL().
If there is just 1 ISR (with a priority at or below configMAX_SYSCALL_INTERRUPT_PRIORITY) calling calculate or your MCU doesn’t support nested interrupts you don’t really need to use taskENTER/EXIT_CRITICAL_FROM_ISR() because a critical section disables interrupts at or below configMAX_SYSCALL_INTERRUPT_PRIORITY and once an ISR is executed, no task can run (on a single core MCU).
Some (e.g. Cortex-M) ports provide xPortIsInsideInterrupt to determine the current execution context.
That could be used to use the critical section inside calculate for tasks only and/or using the FROM_ISR version when in an ISR if you have to.
Alternatively you could provide 2 wrappers of calculate. 1 to be called from tasks and 1 FromISR using the appropriate locking mechanism.
As mentioned I think Cortex-M ports provide it. But just find it in the FreeRTOS sources…
If you simply write 2 wrappers (a task and a FromISR implementation) using the right critical section (or maybe none in ISR, if possible) internally, you don’t need to check the context at runtime.
You can check RX’s PSW.U bit to determine whether your program is in ISR or not as follows (if you don’t want to use 2 wrappers which are advised by Hartmut).
(A) PSW.U == 1 → Your program is in task context
(B) PSW.U == 0 → Your program is in ISR context
Basically the PSW.U shows which kind of stack pointer (i.e. User Stack Pointer or Interrupt Stack Pointer) is used and in case of FreeRTOS’ Renesas RX port the PSW.U can be used to check the program status as above way.
Could the calculate() function be refactored to accept the values it needs as parameters to avoid a critical section inside of calculate? Then the calling function can acquire the needed lock and the needed parameters before calling calculate().
Alternatively, can the code be refactored so calculate() is called in only a single place. It sounds from here that having two paths to the computation breaks single-responsibility, creating a critical section challenge.