I had a code like below to make some Flgas set/clear;
unsigned short FlagReg; int main(void) { ... FlagReg = FlagReg | 0x0001; // makes first bit TRUE ... } void Timer1Handler(void) _irq { ... FlagReg = FlagReg & 0xFFFD; // makes second bit FALSE ... }
This code seems to work. It works correct normally but it doesn't sometimes. It's because making second bit at timer1 interrupt doesn't work.
So, I thought of its assembly. It's like below:
main: LDR R0,[PC,#xxxx] LDR R0,[R0,#xxxx] ORR R0,R0,0x0001 -> interrupt may occur at this line LDR R1,[PC,#xxxx] LDR R0,[R1,#xxxx]
If timer interrupt occurs at shown line what will happens? I think, makeing clear second bit will be not valid. Second bit was made clear and register was changed at timer0 interrupt but the value to write into register has been alerady calculated at previous line.
I hope that I could explain the problem. What can I do to solve this problem?
Best regards.
You have several options.
1) Some Cortex-M processors have the bit-banding feature. It allows you to flip bits atomically. Look it up. This is the easiest option.
2) You can disable interrupts (or just one interrupt) for the duration of flag modification in main(). Not very nice for a number of reasons.
3) You can design your logic in such a way that you don't need to modify the same variable both in main() and the interrupt handler. This way is portable since it does not rely on special CPU features like bit-banding, and it does not need disable interrupts.
One more thing. If the variable is modified in an interrupt handler and its value is used in main(), you must declare it as volatile.
I would just switch from flags to two separate 'char' variables. And make sure they are volatile.
The main loop can look at your char variable. It will be random if it picks up the value before or after the interrupt happens. But both alternatives will be correct. If that is enough, or if the interrupt handler does some other operations too, will decide if it is enough to just have this 'char' variable declared volatile.
It is always important to look at the used data structures and try to make them as "easy" as possible when it comes to synchronization. That is a reason why ring buffers are so much liked - the interrupt handler can insert and the main loop can consume. Or the main loop can insert and the interrupt consume. But the main loop is the only one modifying one index and the interrupt is the only one modifying the other index - so volatile is enough to make it work well.