0
votes

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.

1
This is not a true multithreaded environment, so a race condition might be really applicable only between the main code and the ISR. But it is easily solvable by disabling the interrupts in the critical section of the main code.Eugene Sh.
Do volatile int flag; [global] and, in main, do: int copy; cli(); copy = flag; flag = 0; sti(); if (copy) ... The ISR can simply set flag as desired.Craig Estey
You've explained the solution clearly enough, but you have not really explained the problem you are trying to solve. Describe the race condition scenario that will cause an error, because it is not clear what you mean. You could use bit-banding to read and clear flags atomically rather than using read-modify-write of event flags, or use separate Booleans. All having a queue will do, is you will process in the order the interrupts were processed, but that is non-deterministic because you have disabled preemption. It also sounds like you have invented a hypothetical problem.Clifford
Sounds good to me. I often do this but with a simple multithread tasker where I can signal a semaphore to indicate that an event has been loaded onto the queue and so needs attention from the I/O handler thread:)Martin James
@EugeneSh. I read somewhere that enabling and disabling interrupts causes big delays in interrupt response times. I don't know if its true but if it is, I need fast response from interrupts.NOpE

1 Answers

0
votes

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.