@@ -82,9 +82,22 @@ Functions
8282
8383 .. function :: ticks_ms()
8484
85- Returns an increasing millisecond counter with arbitrary reference point,
86- that wraps after some (unspecified) value. The value should be treated as
87- opaque, suitable for use only with ticks_diff().
85+ Returns an increasing millisecond counter with an arbitrary reference point,
86+ that wraps around after some value. This value is not explicitly exposed,
87+ but we will refer to it as `TICKS_MAX ` to simplify discussion. Period of
88+ the values is `TICKS_PERIOD = TICKS_MAX + 1 `. `TICKS_PERIOD ` is guaranteed
89+ to be a power of two, but otherwise may differ from port to port. The same
90+ period value is used for all of ticks_ms(), ticks_us(), ticks_cpu() functions
91+ (for simplicity). Thus, these functions will return a value in range
92+ [0 .. `TICKS_MAX `], inclusive, total `TICKS_PERIOD ` values. Not that only
93+ non-negative values are used. For the most part, you should treat values
94+ return by these functions as opaque. The only operations available for them
95+ are ``ticks_diff() `` and ``ticks_add() `` functions described below.
96+
97+ Note: Performing standard mathematical operations (+, -) on these value
98+ will lead to invalid result. Performing such operations and then passing
99+ results as arguments to ``ticks_diff() `` or ``ticks_add() `` will also lead to
100+ invalid result.
88101
89102 .. function :: ticks_us()
90103
@@ -105,22 +118,59 @@ Functions
105118
106119.. only :: port_unix or port_pyboard or port_wipy or port_esp8266
107120
108- .. function :: ticks_diff(old, new )
121+ .. function :: ticks_diff(ticks1, ticks2 )
109122
110- Measure period between consecutive calls to ticks_ms(), ticks_us(), or ticks_cpu().
111- The value returned by these functions may wrap around at any time, so directly
112- subtracting them is not supported. ticks_diff() should be used instead. "old" value should
113- actually precede "new" value in time, or result is undefined. This function should not be
114- used to measure arbitrarily long periods of time (because ticks_*() functions wrap around
115- and usually would have short period). The expected usage pattern is implementing event
116- polling with timeout::
123+ Measure ticks difference between values returned from ticks_ms(), ticks_us(), or ticks_cpu()
124+ functions. The argument order is the same as for subtraction operator,
125+ ``tick_diff(ticks1, ticks2) `` has the same meaning as ``ticks1 - ticks2 ``. However, values returned by
126+ ticks_ms(), etc. functions may wrap around, so directly using subtraction on them will
127+ produce incorrect result. That is why ticks_diff() is needed, it implements modular
128+ (or more specifically, ring) arithmetics to produce correct result even for wrap-around
129+ values (as long as they not too distant inbetween, see below). The function returns
130+ **signed ** value in the range [`-TICKS_PERIOD/2 ` .. `TICKS_PERIOD/2-1 `] (that's a typical
131+ range definition for two's-complement signed binary integers). If the result is negative,
132+ it means that `ticks1 ` occured earlier in time than `ticks2 `. Otherwise, it means that
133+ `ticks1 ` was after `ticks2 `. This holds `only ` if `ticks1 ` and `ticks2 ` are apart from
134+ each other for no more than `TICKS_PERIOD/2-1 ` ticks. If that does not hold, incorrect
135+ result will be returned. Specifically, if 2 tick values are apart for `TICKS_PERIOD/2-1 `
136+ ticks, that value will be returned by the function. However, if `TICKS_PERIOD/2 ` of
137+ real-time ticks has passed between them, the function will return `-TICKS_PERIOD/2 `
138+ instead, i.e. result value will wrap around to the negative range of possible values.
139+
140+
141+ ``ticks_diff() `` is designed to accommodate various usage patterns, among them:
142+
143+ Polling with timeout. In this case, the order of events is known, and you will deal
144+ only with positive results of ``ticks_diff() ``::
117145
118146 # Wait for GPIO pin to be asserted, but at most 500us
119147 start = time.ticks_us()
120148 while pin.value() == 0:
121- if time.ticks_diff(start, time.ticks_us()) > 500:
149+ if time.ticks_diff(time.ticks_us(), start ) > 500:
122150 raise TimeoutError
123151
152+ Scheduling events. In this case, ``ticks_diff() `` result may be negative
153+ if an event is overdue::
154+
155+ # This code snippet is not optimized
156+ now = time.ticks_ms()
157+ scheduled_time = task.scheduled_time()
158+ if ticks_diff(now, scheduled_time) > 0:
159+ print("Too early, let's nap")
160+ sleep_ms(ticks_diff(now, scheduled_time))
161+ task.run()
162+ elif ticks_diff(now, scheduled_time) == 0:
163+ print("Right at time!")
164+ task.run()
165+ elif ticks_diff(now, scheduled_time) < 0:
166+ print("Oops, running late, tell task to run faster!")
167+ task.run(run_faster=true)
168+
169+ Note: Do not pass ``time() `` values to ``ticks_diff() ``, and should use
170+ normal mathematical operations on them. But note that ``time() `` may (and will)
171+ also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
172+
173+
124174.. function :: time()
125175
126176 Returns the number of seconds, as an integer, since the Epoch, assuming that underlying
0 commit comments