Hi,
I'm using the STM32F103ZD.
The TIM2_IRQHandler() interrupt handler decrements a value, checks for zero, if so does some action and (re-) sets this value to 1. So each call to this interrupt handler should execute some action. Also higher priority interrupts are active.
If the program execution fails I see in the debugger that 'value' has decremented through zero to 0xffff and lower. Is this some atomic problem? Or is the interrupt handler somehow re-entered while executing?
// variabele declaration volatile static unsigned short value=1; // timer 2 interrupt handler void TIM2_IRQHandler(void){ // an update event is detected if(TIM2->SR&TIM_SR_UIF){ // clear the update event interrupt flag TIM2->SR&=~TIM_SR_UIF; // decrement some value value--; // value is zero if (!value){ // do something DoSomething(); // preset value value=1; }//if }//if }//TIM2_IRQHandler
Who can help me out? Thanks Henk
Note the description:
read/clear (rc_w0) Software can read as well as clear this bit by writing 0. Writing ‘1’ has no effect on the bit value.
The meaning is not that it is a write-only register. Only that only writes of zero bits will make a difference, while writes of ones will not matter.
When you read it, a 1 means there is an event to process a 0 means that there is no event pending.
Writing back means 1 doesn't affect the bit 0 clears that bit.
But when you do a read-modify-write, there is a time delay between the read and the write since the code:
reg &= ~flag;
is basically: old_reg = reg reg = old_reg & ~flag;
So your ~flag will clear the bit you want to clear. But any zero in "old_reg", i.e. the sampled value of the register some nanoseconds earlier, that is no longer a zero in reg because the event happened in the middle of your read/modify/write, will also be cleared.
So if reg looks like:
t+0: 00010000 <= here, you sample the current flags to decide what to do in the ISR ... t+5: 00010000 <= here, the processor samples the current value for the read/modify/write t+6: 00010010 <= here a new flag arrives t+7: 00010010 <= here you write (00010000 & ~00010000) = (00010000 & 11101111) = 00000000) t+8: 00000000 <= and end result - two bits got cleared by your "one-bit" clear
If you instead of "reg &= ~flag" write "reg = ~flag", then the outcome is:
t+0: 00010000 <= here you sample the current flags to decide what to do ... t+5: 00010000 t+6: 00010010 <= new flag arrives t+7: 00010010 <= and you write ~00010000 = 11101111 t+8: 00000010 <= and the outcome is that the new flag survived
So it is critical to avoid a read/modify/write.
Per,
What you have explained there covers what I consider to be an incredibly frequent error.
One such situation occurred for me just a few months ago I was involved in looking at outstanding problems in some (rather nasty) source code.
I came across this very fault in a low level driver and had a difficult time getting through to some people who claimed to be seasoned firmware engineers that they were doing it wrong.
Their argument: the compiler is supposed to look after situations like that.
After persuading them to try changing the code, the problem was no longer witnessed.
Most (but not all) of the team then took the situation on board.
Per, you are my hero.
I allready did change my code into IS/INVERSE and indeed a software glitch which happend some times now completely was gone. But I thought this was a coincidence and looked further for other causes.
I did not realize that time also plays a major role.
thanks!
The tricky part is that the spuriously lost flag may happen on average very 10 minutes. Or every 10 hours. Maybe even once/month. It's just a question of how often the flags gets set and how often some other flag gets serviced and cleared.
Dices can be dangerous around software, unless the intention is to use Monte Carlo methods to intentionally play with probabilities. In the majority of cases, we want our code to be as predictable as possible. Which means we want determinism.