Click here to Skip to main content
15,894,410 members
Articles / Abstract

Time Bias Using System Ticks

Rate me:
Please Sign up or sign in to vote.
4.38/5 (3 votes)
17 Dec 2015CPOL4 min read 7.9K   1   2
Time Bias using system ticks

Introduction

There are many times where accurate timing of future events are necessary to launch a process; unfortunately there is usually no clear cut solution.

In Windows there are three ways to measure time:

  • one based on the system time clock - this can have dangerous effects if day light savings time happens or someone manually adjusts the clock, a process waiting to do something in 5 seconds from now might be waiting an hour and 5 minutes or get completely passed.
  • Use a system call back with a wait timer - this works good but you will not be able to monitor how much time has passed.
  • GetTickCount and GetTickCount64 - these are both easy to use, but the former wraps every 49.7 days and the later is not available before Windows Vista.

On other platforms; such as embedded systems, there is no real-time clock so timing must be done by counting a specific interrupt caused by the processor or some other designated chip; some embedded libraries like Arduino will do this for you with a call to millis().

In this article I'm going to work with GetTickCount and how to get around the 49.7 day limit issue. Although I will be showing this in VB.net code, nothing written here will be specific to the language or OS, as this can be easily adapted to other languages and platforms.

Background

I develop software in industrial control; as such a great deal of my code uses timers, based on clocks, ticks and callbacks. The majority of my work uses PCs to control processes, by reading in information from the IO and making split decisions back out. I have built a few embedded devices in my time also.

Nothing I'm presenting here should be considered for real-time control with out looking at the trade-offs. Not all embedded system will be able to use what I layout, each specific device will have to be addressed separately.

Last year there was an article published on line about how a certain airplane manufacture required their panes to be totally powered down around every 48 days because of a bug with some of the code running on the systems. Does this sound familiar?

Apparently someone was using a some sort a call like GetTickCount and comparing an old value to a new value to calculate any number of things. This works most of the time until the 32 integer fills and rolls over to zero causing all sorts of havoc.

I can't say what the platform they are using or anything else about it as I've never worked on one, but there are tricks to work around this.

Using the code

My solution is to bump up the value to a larger 64 bit number

VB.NET
Private _current As Int64
Private _last As UInt32
Private Declare Function GetTickCount Lib "kernel32" () As UInt32

    Sub New()
        _current = GetTickCount()
        _last = _current
    End Sub

    Private Sub update()
        Dim t As UInt32 = GetTickCount()

        If t < _last Then
            'roll over detected
            Dim tmp As Int64 = t Or &H100000000   '32 second bit
            _current += (tmp - _last)
        Else
            _current += (t - _last)
        End If

        _last = t
    End Sub

That's about it. All I'm doing it getting an initial value and holding it into a larger container and also a 32 marker for knowing what I got last time. so as the code gets updated; I grab the newest tick count, if it looks smaller than the last one a rollover happened so I will use a 2^32 bit and the current value or'd together and then subtract the value from the _last value to get the difference of time that occurred between calls and add it to the _current marker.

Because the _current marker is 64 bit I'm sure that the value will not roll over in my given life time (a restart is much more likely)

Points of Interest

I ended up wrapping this code into a .NET Date style structure, this allowed me to convert the value back to a Date or vice versa, add or subtract milliseconds and such. If I need to save a timestamp to file or log I will always convert to a Date structure incase of the computer restart.

On embedded systems with out a real time clock, it's not very likely any need to convert to date and time or represent any time stamps in the past, so I'll use an unsigned number to hold and buffer.

If you have to be the one counting the interrupts, get out of the code as quickly as possible and I would keep the code as simple as Var++; you should never bog an interrupt down with much work. use your normal loop code to check for the overflows using the Var as little as possible because you never know when it will get interrupted.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Van Doren Sales
United States United States
I've been a professional developer since the late 90's and got hired on with Doubl-Kold in may of 2000 through February of 2018. I have since moved on to Van Doren Sales for new challenges. I have a few core languages under my belt, but D-lang has gotten my interest lately.

I currently have interest into more embedded systems, as they continue to fascinate me more than any other technologies currently.

The majority of my free time is spent on my wife and kids, and numerous other hobbies.

Comments and Discussions

 
QuestionDo you have to take account of the roll-over event? Pin
George Swan17-Dec-15 23:27
mveGeorge Swan17-Dec-15 23:27 
AnswerRe: Do you have to take account of the roll-over event? Pin
Matt McGuire18-Dec-15 3:31
professionalMatt McGuire18-Dec-15 3:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.