Sharing global variables with multiple Interrupt Service Routines in C - c

I am writing a program in C for PIC32 uC , that have a global variable(uint32_t type) that can be read/modified from multiple Interrupt Service Routines and from the main.
I know that is not safe so I was wondering how to make it safe ? Is there an example that show how to make it safe ?
Edit 1:
Can interrupts interrupt each other? yes
Does the ISR update the variable? yes
Does main update the variable? yes
Are writes and reads to the variable atomic and how do you know? Not sure
Is there a RTOS present? No

If you really need to keep global variables that can be modified during the servicing of several interrupts that can interrupt each other, I suggest you following way to do:
Make all sequences of actions (read and/or write) on these variables "atomic" by disabling all interrupts before, then re-enable all interrupts after. On PIC32, you could do this by writing the global interrupt flag GIE.
Declare these variables as volatile to avoid any unexpected optimization from compiler.
Rename these variables with a specific prefix to identify them clearly, as Shared_XXXX, but it depends on the naming convention you are using.
Put all sequences of actions on these variables in functions named with a specific prefix to identify them clearly, as Atomic_XXXX(). To implement the point 1: either these functions must all start by disabling all interrupts and end by reenabling all interrupts, or alternately you can systematically pass atomic functions as callback parameter to a function that will disable all interupts, call the callback function and reenables all interrupt.

Related

tx_semaphore inside a Interrupt

I want to read out RS232 data periodically. I have created an interrupt for this purpose. However, my RS232 functions need semaphores. I found out that I cannot execute a TX(Thread X) function in the interrupt. What do I have to do to make my TX function work inside the interrupt?
If your RTOS provides a way to do it, then use that. If not, then here's some other options:
Disable the specific interrupt from the background program during variable access.
In case interrupts aren't interruptible on your MCU, you could implement a "poor man's mutex" described here: https://electronics.stackexchange.com/questions/409545/using-volatile-in-embedded-c-development/409570#409570
Use inline assembler and ensure reads/writes are done in a single instruction.
There's also a very bad idea/last resort, and that is to toggle the global interrupt mask.
First, make sure you are calling _tx_thread_context_save and _tx_thread_context_restore at the beginning and end of your ISR, respectively. See here for more information: https://learn.microsoft.com/en-us/azure/rtos/threadx/chapter3#isr-template
Second, you cannot create a semaphore in an interrupt, so make sure you create it elsewhere.

How can I determin if execution takes place in thread mode or if an exception is active? (ARMv7-A architecture)

I am using FreeRTOS on an ARM Cortex A9 CPU und I'm desperately trying to find out if it is possible to determin if the processor is executing a normal thread or an interrupt service routine. It is implemented in V7-a architecture.
I found some promising reference hinting the ICSR register (-> VECTACTIVE bits), but this only exist in the cortex M family. Is there a comparable register in the A family as well? I tried to read out the processor modes in the current processor status register (CPSR), but when read during an ISR I saw that the mode bits indicate supervisor mode rather than IRQ or FIQ mode.
Looks a lot like there is no way to determine in which state the processor is, but I wanted to ask anyway, maybe I missed something...
The processor has a pl390 General Interrupt Controller. Maybe it is possible to determine the if an interrupt has been triggered by reading some of it's registers?
If anybody can give me a clue I would be very greatfull!
Edit1:
The IRQ Handler of FreeRTOS switches the processor to Superviser mode:
And subsequently switches back to system mode:
Can I just check if the processor is in supervisor mode and assume that this means that the execution takes place in an ISR, or are there other situations where the kernel may switches to supervisor mode, without being in an ISR?
Edit2:
On request I'll add an overal background description of the solution that I want to achieve in the first place, by solving the problem of knowing the current execution context.
I'm writing a set of libraries for the CortexA9 and FreeRTOS that will access periphery. Amongst others I want to implement a library for the available HW timer from the processor's periphery.
In order to secure the access to the HW and to avoid multiple tasks trying to access the HW resource simultaneously I added Mutex Semaphores to the timer library implementation. The first thing the lib function does on call is to try to gain the Mutex. If it fails the function returns an error, otherwise it continouses its execution.
Lets focus on the function that starts the timer:
static ret_val_e TmrStart(tmr_ctrl_t * pCtrl)
{
ret_val_e retVal = RET_ERR_DEF;
BaseType_t retVal_os = pdFAIL;
XTtcPs * pHwTmrInstance = (XTtcPs *) pCtrl->pHwTmrInstance;
//Check status of driver
if(pCtrl == NULL)
{
return RET_ERR_TMR_CTRL_REF;
}else if(!pCtrl->bInitialized )
{
return RET_ERR_TMR_UNINITIALIZED;
}else
{
retVal_os = xSemaphoreTake(pCtrl->osSemMux_Tmr, INSTANCE_BUSY_ACCESS_DELAY_TICKS);
if(retVal_os != pdPASS)
{
return RET_ERR_OS_SEM_MUX;
}
}
//This function starts the timer
XTtcPs_Start(pHwTmrInstance);
(...)
Sometimes it can be helpful to start the timer directly inside an ISR. The problem that appears is that while the rest of function would support it, the SemaphoreTake() call MUST be changed to SemaphoreTakeFromISR() - moreover no wait ticks are supported when called from ISR in order to avoid a blocking ISR.
In order to achieve code that is suitable for both execution modes (thread mode and IRQ mode) we would need to change the function to first check the execution state and based on that invokes either SemaphoreTake() or SemaphoreTakeFromISR() before proceeding to access the HW.
That's the context of my question. As mentioned in the comments I do not want to implement this by adding a parameter that must be supplied by the user on every call which tells the function if it's been called from a thread or an ISR, as I want to keep the API as slim as possible.
I could take FreeRTOS approch and implement a copy of the TmrStart() function with the name TmrStartFromISR() which contains the the ISR specific calls to FreeRTOS's system resources. But I rather avoid that either as duplicating all my functions makes the code overall harder to maintain.
So determining the execution state by reading out some processor registers would be the only way that I can think of. But apparently the A9 does not supply this information easily unfortunately, unlike the M3 for example.
Another approch that just came to my mind could be to set a global variable in the assembler code of FreeRTOS that handles exeptions. In the portSAVE_CONTEXT it could be set and in the portRESTORE_CONTEXT it could be reset.
The downside of this solution is that the library then would not work with the official A9 port of FreeRTOS which does not sound good either. Moreover you could get problems with race conditions if the variable is changed right after it has been checked by the lib function, but I guess this would also be a problem when reading the state from a processor registers directly... Probably one would need to enclose this check in a critical section that prevents interrupts for a short period of time.
If somebody sees some other solutions that I did not think of please do not hesitate to bring them up.
Also please feel free to discuss the solutions I brought up so far.
I'd just like to find the best way to do it.
Thanks!
On a Cortex-A processor, when an interrupt handler is triggered, the processor enters IRQ mode, with interrupts disabled. This is reflected in the state field of CPSR. IRQ mode is not suitable to receive nested interrupts, because if a second interrupt happened, the return address for the first interrupt would be overwritten. So, if an interrupt handler ever needs to re-enable interrupts, it must switch to supervisor mode first.
Generally, one of the first thing that an operating system's interrupt handler does is to switch to supervisor mode. By the time the code reaches a particular driver, the processor is in supervisor mode. So the behavior you're observing is perfectly normal.
A FreeRTOS interrupt handler is a C function. It runs with interrupts enabled, in supervisor mode. If you want to know whether your code is running in the context of an interrupt handler, never call the interrupt handler function directly, and when it calls auxiliary functions that care, pass a variable that indicates who the caller is.
void code_that_wants_to_know_who_called_it(int context) {
if (context != 0)
// called from an interrupt handler
else
// called from outside an interrupt handler
}
void my_handler1(void) {
code_that_wants_to_know_who_called_it(1);
}
void my_handler2(void) {
code_that_wants_to_know_who_called_it(1);
}
int main(void) {
Install_Interrupt(EVENT1, my_handler1);
Install_Interrupt(EVENT2, my_handler1);
code_that_wants_to_know_who_called_it(0);
}

Avoiding Race Condition with event queue in event driven embedded system

I am trying to program stm32 and use event driven architecture. For example I am going to toggle a pin when timer interrupt occurs and transfer some data to external flash when ADC DMA buffer full interrupt occurs and so on..
There will be multiple interrupt sources each with same priority which disables nesting.
I will use the interrupts to set a flag to signal my main that interrupt occured and process data inside main. There will be no processing/instruction inside ISRs.
What bothers me is that accessing a variable(flags in this case) in main and ISRs may cause race condition bug in the long run.
So I want to use an circular event queue instead of flags.
Only ISRs will be able to write to event queue buffer and increment "head".
Only main will be able to read the event queue(and execute instructions according to event) and increment "tail".
Since ISR nesting is disabled and each ISR will access different element of event queue array and main function will only react when there is new event on event queue, race condition is avoided right? or am I missing something?
Please correct me if I am doing something wrong.
Thank you.
If the interrupt only sets a variable and nothing gets done until main context is ready to do it then there is really no reason to have an interrupt at all.
For example: if you get a DMA complete hardware interrupt and set a variable then all you have achieved is to copy one bit of information from a hardware register to a variable. You could have much simpler code with identical performance and less potential for error by instead of polling a variable just not enabling the interrupt and polling the hardware flag directly.
Only enable the interrupt if you are actually going to do something in interrupt context that cannot wait, for example: reading a UART received data register so that the next character received doesn't overflow the buffer.
If after the interrupt has done the thing that cannot wait it then needs to communicate something with main-context then you need to have shared data. This will mean that you need some way of preventing race-conditions. The simplest way is atomic access with only one side writing to the data item. If that is not sufficient then the old-fashioned way is to turn off interrupts when main context is accessing the shared data. There are more complicated ways using LDREX/STREX instructions but you should only explore these once you are sure that the simple way isn't good enough for your application.

stm32 - Interrupt handle

In external interrupt function, I want to reset by calling main function. But afterwards, if I have a new interrupt trigger, MCU thinks that It's handling in interrupt function and It doesn't call interrupt function again. What is my solution? (in my project, I'm not allowed to call soft Reset function)
Calling main() in any event is a bad idea, calling it from an interrupt handler is a really bad idea as you have discovered.
What you really need is to modify the stack and link-register so that when the interrupt context exits,, it "returns" to main(), rather than from whence it came. That is a non-trivial task, probably requiring some assembler code or compiler intrinsics.
You have to realise that the hardware will not have been restored to its reset state; you will probably need at least to disable all interrupts to prevent them occurring while the system is re-initialising.
Moreover the standard library will not be reinitialised if you jump to main(); rather than the reset vector. In particular, any currently allocated dynamic memory will instantly leak away and become unusable. In fact all of the C run-time environment initialisation will be skipped - leaving amongst for example static and global data in its last state rather than applying correct initialisation.
In short it is dangerous, error-prone, target specific, and fundamentally poor practice. Most of what you would have to do to make it work is already done in the start-up code that is executed before main() is called, so it would be far simpler to invoke that. The difference between that and forcing a true reset (via the watchdog or AICR) is that the on-chip peripheral state remains untouched (apart from any initialisation explicitly done in the start-up). In my experience, if you are using a more complex peripheral such as USB, safely restarting the system without a true reset is difficult to achieve safely (or at least it is difficult to determine how to do it safely) and hardly worth the effort.
Reset by calling main() is wrong. There is code in front of main inserted by the linker and C-runtime that you will skip by such soft-reset.
Instead, call NVIC_SystemReset() or enable the IWDG and while(1){} to reset.
The HAL should have example files for the watchdog timer.
SRAM is maintained. Any value not initialized by the linker script will still be there.
Calling Main() from any point of your code is a wrong idea if you are not resetting the stack and setting the initial values.
There is always a initialization function ( that actually calls Main()) which is inside an interrupt vector, usually this function can be triggered by calling the function NVIC_SystemReset(void) , be sure than you enable this interrupt so it can be software triggered.
As far as I know, when get inside and interrupt code, other interruptions are inhibit, I am thinking on two different options:
Enable the interruptions inside the interruption and call the function NVIC_SystemReset(void)
Modify the stack and push the direction of the function NVIC_SystemReset(void) so when you go out of the interruption it could be executed.

How come a compiler cannot detect if a global variable is changed by another thread?

I was just going through concepts of the volatile keyword. I just gone through this link, this link is telling about why to use the volatile keyword in case of program using interrupt handler. They have mentioned in one example:
int etx_rcvd = FALSE;
void main()
{
...
while (!ext_rcvd)
{
// Wait
}
...
}
interrupt void rx_isr(void)
{
...
if (ETX == rx_char)
{
etx_rcvd = TRUE;
}
...
}
They are saying since compiler is not able to know ext_rcvd is getting updated in an interrupt handler. So compiler uses optimization intelligence and assumes that this variable value is always FALSE and it never enters into the while{} condition. So to prevent these situation we use volatile keyword, which stops compiler to use its own intelligence.
My question is, While compiling, how compiler is not able to know that ext_rcvd is getting updated in interrupt handler? PLease help me to find its answer, I am not getting correct answer for this.
The compiler cannot analyze all the codes or running processes that can modify the memory location of ext_rcvd.
In your example, you mentioned that ext_rcvd is being updated in an interrupt handler. That is correct. The interrupt handler is a piece of code launched by the Operating System, when the CPU receives an interrupt. That piece of code is actually the driver code. In the driver code, ext_rcvd may have another name but point to the same memory location.
So in order to know if ext_rcvd is updated somewhere else, the compiler needs to analyze the libraries and drivers' code and to figure out that they are updating the exact same memory location that you name ext_rcvd in your code. This cannot be done before execution time.
The same goes for multi-threading. The compiler cannot know a-priori if a certain thread is updating the exact memory location used by another thread. For example if another thread makes a syscall() then the compiler needs to look in the code handling the syscall().
When the CPU receives an interrupt, it stops whatever it's doing (unless it's processing a more important interrupt, in which case it will deal with this one only when the more important one is done), saves certain parameters on the stack and calls the interrupt handler. This means that certain things are not allowed in the interrupt handler itself, because the system is in an unknown state. The solution to this problem is for the interrupt handler to do what needs to be done immediately, usually read something from the hardware or send something to the hardware, and then schedule the handling of the new information at a later time (this is called the "bottom half") and return. The kernel is then guaranteed to call the bottom half as soon as possible -- and when it does, everything allowed in kernel modules will be allowed.
I think when the interrupt is called whatever is working is stopped and the variable is set to TRUE, not satisfying the while condition.
But when you use volatile keyword it makes C checks the variable value again.
Of course, I'm not 100% sure about this, I'm open for answers for change mine.
interrupt is not a C specified keyword, so whatever is discussed is not C specified behavior.
Yes the compiler could see that etx_rcvd is modified inside an interrupt routine and therefore assume etx_rcvd could change at any time outside the interrupt function and make int etx_rcvd --> volatile int etx_rcvd.
Now the question is should it do that?
IMO: No, it is not needed.
An interrupt function could modify global variables and the code flow is such that non-interrupt functions access only happens in a interrupt protected block. An optimizing compiler would be hindered by having implied volatile with int etx_rcvd. So now code needs a way to say non_volatile int etx_rcvd to prevent the volatile assumption OP seeks.
C all ready provides a method to declare variables volatile (add volatile) and non-volatile (do not add volatile). If an interrupt routine could make variables volatile without them being declared so, the code would need a new keyword to insure non-volatility.

Resources