micropython / micropython-esp32

Old port of MicroPython to the ESP32 -- new port is at https://github.com/micropython/micropython
MIT License
669 stars 216 forks source link

time.ticks_ms() as uint32_t and time.ticks_us() as uint64_t based on esp_timer_impl_get_time() #228

Closed smeenka closed 5 years ago

smeenka commented 6 years ago

Herby I propose to implement the time.ticks_us() as a full uint64_t without any masking and time.ticks_ms() as full uint32_t without any masking.

The implementation is based on esp_timer_impl_get_time(), a 64 bit microsecond counter. uint64_t with microseconds will overflow in 2^64 / (1e6 60 60 24 365) = 292471,21 year uint32_t with milliseconds will overflow in 2^32 / (1e3 60 60 * 24) = 49,71 days

With this implementation there is no need anymore to calculate time diffs with ticks_diff. And far less cpu cycles is spend in calculating the ticks, and ticks diffs

The original implementation is based on gettimeofday. If one sets the timeofday to the correct value, the resulting value of function time.ticks_us() and time.ticks_ms() make a jump to a value beyond the 32 bits value, leaving the 32 bits remainder as resulting value.

This is very unhandy, as it is very difficult to cope with the jump in the absolute value in ticks, if one uses an OS (asyncio) based on ticks_ms. Starting the OS can only be done after setting the timeofday, and while running it is not possible to adjust the timeof day, due to the possible ticks jump.

Testing of the microseconds timer can be done with next code:

import utime as time

def showtime(us):
    useconds = us % 1000000
    tseconds  = us // 1000000

    tminutes = tseconds // 60
    seconds  = tseconds % 60

    thours   = tminutes // 60
    minutes  = tminutes % 60

    tdays    = thours // 24
    hours    = thours % 24

    tyears   = tdays // 365
    days     = tdays %  365

    print ("years:%s  days:%s  h:%2s  m:%2s  s:%2s  us:%s  raw:%s"%(tyears, days,hours,minutes,seconds,useconds,us) )

while (True):
    us = time.ticks_us()
    showtime(us)
    time.sleep(10)
robert-hh commented 6 years ago

That looks like a good change. For backward compatibility, ticks_diff should still work. Did you check that?

smeenka commented 6 years ago

Function time_ticks_diff in utime_mphal.c: // we assume that the arguments come from ticks_xx so are small ints

So time.ticks_diff does work for time.time_ms() but not for time.ticks_us().

The proposed change for time.ticks_us() is not backwards compatible. But note that time.ticks_diff() is not needed anymore, as time.ticks_us() not overflows in mankind expected lifetime (understatement?).

robert-hh commented 6 years ago

120 years is about 3,7 * 10**15, which can be coded in 52 bits. So 64 bits are pretty safe.

dpgeorge commented 5 years ago

ticks_ms(), ticks_us() use small integers so they are efficient and deterministic since they don't need to allocate on the heap. This is fundamental to the operation and use of all the ticks functions.

In upstream commit https://github.com/micropython/micropython/commit/e1fe3abd0928c5e3545c546b02317aff72c72590 the call to gettimeofday() was replaced with the more efficient esp_timer_get_time().