Sunday 17 March 2024

Avoiding Arduino millis() Rollover Bugs

If you are using the millis() function to measure time on an Arduino, you might be tempted to do something like this:-

unsigned long timer_expires_at = millis() + SOME_DURATION; while (millis() < timer_expires_at) { [do other stuff while waiting for the timer to expire] } [do stuff that should happen after the timer expires]

For the most part, that will work well. But after around 49.7 days (4,294,967,296 a.k.a 232 milliseconds, to be exact), you might run into a problem. If millis() + SOME_DURATION exceeds 4,294,967,295, it will rollover and your comparison will match prematurely. Of course, you would have to be pretty unlucky for this to occur in practice, but - as Mary Chapin Carpenter put it - Sometimes you're the Louisville Slugger, sometimes you're the ball.

I had plans sketched out for a small C++ class to handle this elegantly when I decided to do a quick bit of Googling to see if I was reinventing the wheel entirely here and I came across the most beautiful simple, and elegant solution to the problem in https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover/12588#12588. It is a long, detailed reply and well-worth reading, but the gist of it is to just change the logic very slightly:-

unsigned long timer_started_at = millis(); while (millis() - SOME_DURATION < timer_started_at) { [do other stuff while waiting for the timer to expire] } [do stuff that should happen after the timer expires]

It should be pretty clear how this avoids the problem after ~49.7 days, but it may be less obvious why it doesn't just shift the problem to the other end.  Imagine that your Arduino has been powered on for 30 seconds, so a call to millis() will return a value of 30,000. You want to wait for 40 seconds, so you set SOME_DURATION to 40,000. Subtracting 40,000 from 30,000 in the condition of the while() loop will indeed cause a rollover (30,000 - 40,000 mod 4,294,967,296 = 4,294,957,296), but the result of that rollover will still satisfy the condition in the way we want.

No comments:

Post a Comment