summaryrefslogtreecommitdiffstatshomepage
path: root/docs/library/utime.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/library/utime.rst')
-rw-r--r--docs/library/utime.rst141
1 files changed, 116 insertions, 25 deletions
diff --git a/docs/library/utime.rst b/docs/library/utime.rst
index 8310673830..109c3560cc 100644
--- a/docs/library/utime.rst
+++ b/docs/library/utime.rst
@@ -82,37 +82,128 @@ Functions
.. function:: ticks_ms()
- Returns an increasing millisecond counter with arbitrary reference point,
- that wraps after some (unspecified) value. The value should be treated as
- opaque, suitable for use only with ticks_diff().
+ Returns an increasing millisecond counter with an arbitrary reference point,
+ that wraps around after some value. This value is not explicitly exposed,
+ but we will refer to it as `TICKS_MAX` to simplify discussion. Period of
+ the values is `TICKS_PERIOD = TICKS_MAX + 1`. `TICKS_PERIOD` is guaranteed
+ to be a power of two, but otherwise may differ from port to port. The same
+ period value is used for all of ticks_ms(), ticks_us(), ticks_cpu() functions
+ (for simplicity). Thus, these functions will return a value in range
+ [0 .. `TICKS_MAX`], inclusive, total `TICKS_PERIOD` values. Note that only
+ non-negative values are used. For the most part, you should treat values
+ returned by these functions as opaque. The only operations available for them
+ are ``ticks_diff()`` and ``ticks_add()`` functions described below.
+
+ Note: Performing standard mathematical operations (+, -) or relational
+ operators (<, <=, >, >=) directly on these value will lead to invalid
+ result. Performing mathematical operations and then passing their results
+ as arguments to ``ticks_diff()`` or ``ticks_add()`` will also lead to
+ invalid results from the latter functions.
.. function:: ticks_us()
Just like ``ticks_ms`` above, but in microseconds.
-.. only:: port_wipy or port_pyboard
+.. function:: ticks_cpu()
+
+ Similar to ``ticks_ms`` and ``ticks_us``, but with the highest possible resolution
+ in the system. This is usually CPU clocks, and that's why the function is named that
+ way. But it doesn't have to a CPU clock, some other timing source available in a
+ system (e.g. high-resolution timer) can be used instead. The exact timing unit
+ (resolution) of this function is not specified on ``utime`` module level, but
+ documentation for a specific port may provide more specific information. This
+ function is intended for very fine benchmarking or very tight real-time loops.
+ Avoid using it in portable code.
+
+ Availability: Not every port implements this function.
+
+
+.. function:: ticks_add(ticks, delta)
+
+ Offset ticks value by a given number, which can be either positive or negative.
+ Given a ``ticks`` value, this function allows to calculate ticks value ``delta``
+ ticks before or after it, following modular-arithmetic definition of tick values
+ (see ``ticks_ms()`` above). ``ticks`` parameter must be a direct result of call
+ to ``tick_ms()``, ``ticks_us()``, ``ticks_cpu()`` functions (or from previous
+ call to ``ticks_add()``). However, ``delta`` can be an arbitrary integer number
+ or numeric expression. ``ticks_add()`` is useful for calculating deadlines for
+ events/tasks. (Note: you must use ``ticks_diff()`` function to work with
+ deadlines.)
+
+ Examples::
+
+ # Find out what ticks value there was 100ms ago
+ print(tick_add(time.ticks_ms(), -100))
+
+ # Calculate deadline for operation and test for it
+ deadline = tick_add(time.ticks_ms(), 200)
+ while ticks_diff(deadline, time.ticks_ms()) > 0:
+ do_a_little_of_something()
+
+ # Find out TICKS_MAX used by this port
+ print(tick_add(0, -1))
+
+
+.. function:: ticks_diff(ticks1, ticks2)
+
+ Measure ticks difference between values returned from ticks_ms(), ticks_us(), or ticks_cpu()
+ functions. The argument order is the same as for subtraction operator,
+ ``tick_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. However, values returned by
+ ticks_ms(), etc. functions may wrap around, so directly using subtraction on them will
+ produce incorrect result. That is why ticks_diff() is needed, it implements modular
+ (or more specifically, ring) arithmetics to produce correct result even for wrap-around
+ values (as long as they not too distant inbetween, see below). The function returns
+ **signed** value in the range [`-TICKS_PERIOD/2` .. `TICKS_PERIOD/2-1`] (that's a typical
+ range definition for two's-complement signed binary integers). If the result is negative,
+ it means that `ticks1` occured earlier in time than `ticks2`. Otherwise, it means that
+ `ticks1` occured after `ticks2`. This holds `only` if `ticks1` and `ticks2` are apart from
+ each other for no more than `TICKS_PERIOD/2-1` ticks. If that does not hold, incorrect
+ result will be returned. Specifically, if 2 tick values are apart for `TICKS_PERIOD/2-1`
+ ticks, that value will be returned by the function. However, if `TICKS_PERIOD/2` of
+ real-time ticks has passed between them, the function will return `-TICKS_PERIOD/2`
+ instead, i.e. result value will wrap around to the negative range of possible values.
+
+ Informal rationale of the constraints above: Suppose you are locked in a room with no
+ means to monitor passing of time except a standard 12-notch clock. Then if you look at
+ dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a
+ long sleep), then once you finally look again, it may seem to you that only 1 hour
+ has passed. To avoid this mistake, just look at the clock regularly. Your application
+ should do the same. "Too long sleep" metaphor also maps directly to application
+ behavior: don't let your application run any single task for too long. Run tasks
+ in steps, and do time-keeping inbetween.
+
+ ``ticks_diff()`` is designed to accommodate various usage patterns, among them:
+
+ Polling with timeout. In this case, the order of events is known, and you will deal
+ only with positive results of ``ticks_diff()``::
+
+ # Wait for GPIO pin to be asserted, but at most 500us
+ start = time.ticks_us()
+ while pin.value() == 0:
+ if time.ticks_diff(time.ticks_us(), start) > 500:
+ raise TimeoutError
+
+ Scheduling events. In this case, ``ticks_diff()`` result may be negative
+ if an event is overdue::
+
+ # This code snippet is not optimized
+ now = time.ticks_ms()
+ scheduled_time = task.scheduled_time()
+ if ticks_diff(now, scheduled_time) > 0:
+ print("Too early, let's nap")
+ sleep_ms(ticks_diff(now, scheduled_time))
+ task.run()
+ elif ticks_diff(now, scheduled_time) == 0:
+ print("Right at time!")
+ task.run()
+ elif ticks_diff(now, scheduled_time) < 0:
+ print("Oops, running late, tell task to run faster!")
+ task.run(run_faster=true)
+
+ Note: Do not pass ``time()`` values to ``ticks_diff()``, and should use
+ normal mathematical operations on them. But note that ``time()`` may (and will)
+ also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
- .. function:: ticks_cpu()
-
- Similar to ``ticks_ms`` and ``ticks_us``, but with higher resolution (usually CPU clocks).
-
-.. only:: port_unix or port_pyboard or port_wipy or port_esp8266
-
- .. function:: ticks_diff(old, new)
-
- Measure period between consecutive calls to ticks_ms(), ticks_us(), or ticks_cpu().
- The value returned by these functions may wrap around at any time, so directly
- subtracting them is not supported. ticks_diff() should be used instead. "old" value should
- actually precede "new" value in time, or result is undefined. This function should not be
- used to measure arbitrarily long periods of time (because ticks_*() functions wrap around
- and usually would have short period). The expected usage pattern is implementing event
- polling with timeout::
-
- # Wait for GPIO pin to be asserted, but at most 500us
- start = time.ticks_us()
- while pin.value() == 0:
- if time.ticks_diff(start, time.ticks_us()) > 500:
- raise TimeoutError
.. function:: time()