unsigned int High; interrupt TimerOv(void) { High++; }
Then we can write the current time as follows unsigned long int GetTimer(void) { return (High<<sizeof(int))+ ReadReg(TimerCounter); }
Everything is simple, understandable, and wrong, as expected. Here the problem lies on the surface and is visible to anyone who wrote similar programs - in the process of reading the two halves of the extended timer, the youngest part may overflow, since it is asynchronous, and then the two parts will not be valid relative to each other. At the same time, we can get both the past time point and the future as the value of the extended timer, and both of these cases are worse. unsigned long int GetTimer(void) { DisableInt(); unsigned long Tmp=(High<<sizeof(int))+ ReadReg(TimerCounter); EnableInt(); return Tmp; }
Of course, when I write about the prohibition of interruption, it is assumed that the current value is saved with its restoration at the end, but these subtleties are omitted, they are not so important now. What is not good in this decision: 1) we prohibit interruptions, which is not encouraging, and 2) this solution will not work. Yes, exactly, although the method is approved, but not for this case. The fact is that the prohibition of interrupts does not allow the timer to work (it is hardware), so if during the interruption request period the counter overflow occurs, we get the low part equal to zero, and the high one is not modified, that is, the data is not valid. unsigned long int GetTimer(void) { DisableInt(); unsigned long TmpH=High; unsigned long TmpL=ReadReg(TimerCounter); if (TimerOvBit()) { TmpH++; TmpL=ReadReg(TimerCounter); }; EnableInt(); TmpH=(TmpH<<sizeof(int))+ TmpL; return Tmp; }
This is the first correct decision. There are drawbacks to this solution: 1) we still prohibit interrupts, 2) we need an additional hardware bit and we need to take care of the interrupt service, 3) we made certain assumptions about the modification of the older part. Are there any other solutions? unsigned long int GetTimer(void) { unsigned long TmpH,TmpL; do { TmpH=High; TmpL= ReadReg(TimerCounter); while (TmpH!=High); return (TmpH<<sizeof(int))+TmpL; }
This is the second right decision, pay attention to the fact that the reading of the counter is framed by calls to the older part, otherwise it is wrong. In general, this approach strongly resembles non-blocking algorithms when competing to resources that I like something with, there is some elegance in them. This method has many advantages, but one drawback - if our system is heavily loaded, then we can hang for a long time in the loop, as Jack writes, the execution time becomes unpredictable. unsigned long int GetTimer(void) { unsigned long TmpH,TmpL; TmpH=High; TmpL= ReadReg(TimerCounter); if (TmpH!=(TmpH=High)) TmpL= ReadReg(TimerCounter); return (TmpH<<sizeof(int))+TmpL; }
This is the third right decision and I, as the author, like it most. We do not prohibit interruptions, do not require anything from the equipment, make no assumptions, always get the right result, that is, 1) never get the value of the extended timer preceding the moment of entering the procedure and 2) never get the value following the time of exit from procedures, we have completely predictable behavior, and all this is practically free. Of course, if we have a highly loaded system, then we can get a time at the output that is significantly less than the time required to exit the procedure, but this is also true of the other two correct methods. If we really need the current value of time with a minimum deviation, then we must carry out all processing with prohibited interrupts, and this is clearly not our case. unsigned long int GetTimer(void) { unsigned long TmpHFirst,TmpH,TmpL; TmpHFirst=High; TmpL= ReadReg(TimerCounter); if (TmpHFirst!=(TmpH=High)) TmpL= ReadReg(TimerCounter); return (TmpH<<sizeof(int))+TmpL; }
unsigned long TmpWait; TmpWait=GetTimer()+SomeDelay; while (TmpWait > GetTimer()) ; /* */ while ((TmpWait - GetTimer()) > 0) ; /* */ }
These lines are not equivalent under certain conditions and it is interesting to consider why. I will send interested persons to the Linux manuals, look for the jiffies term.Source: https://habr.com/ru/post/273885/
All Articles