How to handle (millis) rollover?


#1

I’m not sure how to handle the “millis” rollover(s) in uLisp. If I’m right there’s a second rollover in the “middle” where the number flips from the highest possible positive value to zero and counts down to negative from there. How would I produce a sensible difference between two timestamps within uLisp that is never affected by any of the two rollover cases?

Thanks for your help!


#2

Are you asking about this on a 32-bit platform or an 8/16-bit platform?


#3

That’s 32 bit (Waveshare RP2040-Zero). I know, in that case I theoretically should not ask that at all because the rollover is supposed to happen after 25 days. Strangely, I experience a lock-up of my code after about 9 hours, which would correspond to the 16 bit rollover. I’ve no idea what’s happening there; maybe the fault after about 9 hours is just a strange coincidence. Still I’d like to know how to handle this rollover problem, currently I cannot wrap my head around it.

Edit: FYI the current piece of code that checks whether a time interval has passed:

(defvar timestamp (millis))
(defvar now 0)

...
    
(setf now (millis))
(when (> (abs (- now timestamp)) polltime)
    	(setf timestamp now)
            ... do something else ... )

#4

Here’s an explanation for versions of uLisp with 16-bit integers. In these the (millis) function returns the bottom 16 bits of the 64-bit Arduino milliseconds counter. So rollovers as you call them are the result of converting this to a 16-bit signed integer:

Arduino millis (in hex) Count in milliseconds uLisp returns
#x0000 0 0
#x7fff 32767 32767
#x8000 32768 -32768
#xffff 65535 -1
#10000 65536 0
and so on…

You can use (millis) to time up to 65535 millis, or 65.5 seconds, by doing the following calculation:

(defun millis-fix ()
  (let ((m (millis)))
    (if (minusp m) (+ 65536 m) m)))

Beyond that you would need to check (millis) repeatedly, at least every 65 seconds, and keep count of when it wraps around. The time would then be:

(+ (millis-fix) (* counter 65536))

Or you could write a uLisp extension that returned the number of milliseconds as a list of values, or a string giving milliseconds as a decimal number, up to the full 64-bit precision of the Arduino millis.

The above also applies on platforms with 32-bit integers, but after 2147483647 milliseconds, or about 24.9 days. I can’t think what might be happening after 9 hours in your code; 9 hours is about 2^25 milliseconds; perhaps that’s a clue?


#5

Thanks a lot for your detailed explanation! Currently I’ve no clue what might cause the lock-up (it’s not exactly a crash), but your summary will help me to avoid misconceptions in that context.

Thanks again!