Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More accurate time reporting #519

Closed
dhalbert opened this issue Jan 10, 2018 · 24 comments
Closed

More accurate time reporting #519

dhalbert opened this issue Jan 10, 2018 · 24 comments

Comments

@dhalbert
Copy link
Collaborator

Several users have asked for time reporting that's more precise than the millisecond ticks provided by time.monotonic(). Use cases and proposals welcome here.

@dhalbert dhalbert added this to the Long term milestone Jan 10, 2018
@CameronDevine
Copy link

I was attempting to work with a 433Mhz radio transmitter which required writing to a pin at 200 microsecond intervals. Even if a function similar to the Arduino micros() had less than 1 microsecond resolution this would allow time calculations that are not possible with the time.monotonic() function.

@tannewt
Copy link
Member

tannewt commented Jan 10, 2018

@CameronDevine Interesting! How much data do you know you need to write ahead of time? Something like PulseOut might be adequate. It looks like it requires a carrier PWM signal though it could just be constant.

@dhalbert
Copy link
Collaborator Author

came from here: asking there as well: https://forums.adafruit.com/viewtopic.php?f=60&t=129222

@l8gravely
Copy link

I too would like to see something better than monotonic, since it's not stable and loses precision as time goes on. Or maybe I just need to learn the CircuitPython way to do longer term ramping up/down of a NeoPixel, while not doing a busy wait, so I can handle other inputs that come in.

Right now I just try to do:

timetofire = timer.Monotonic() + delay
while True:
now= timer.Monotonic()
if (now > timetofire):
timetofire = now + delay
# do NeoPixel incremental update here

continue on looking for keyboard input, etc.

Does this make sense? I also wish it was more clearly documented what resolution monotonic is counting in, since it's not quite seconds, but maybe milliseconds?

@tannewt
Copy link
Member

tannewt commented Mar 5, 2018

@l8gravely On the SAMD21 it is millisecond.

I'm still unsure we want to provide precise timing because we pause the VM from time to time to do other things. I'm worried about making timing promises we don't always keep. If we did, I think we could introduce a precisetime module for it.

@l8gravely also follow #619 for a different way to do things concurrently.

@CameronDevine
Copy link

Would it be possible to have a variable which states the approximate interval at which time.monotonic() is increased? This would save people form having to write code to guess what the interval is, since it appears to change based on which board is being used.

@jepler
Copy link
Member

jepler commented Apr 9, 2018

like @l8gravely I want a monotonic time source which doesn't lose precision. In my project, I want to show the seconds and fractions of seconds based on NTP time, but it starts to lose precision as the monotonic() value gets large.

For me, directly exposing common_hal_time_monotonic(), possibly via the microcontroller module, seems like a good first step. I'm not sure whether exposing it as a 64-bit value (restricting it to devices with support for longs) is better, or exposing it as unix-style (seconds,microseconds} is better. The latter is sure less convenient for doing math on, and forces the choice of a fractional second size of microseconds or coarser (rather than nanoseconds or 2^-32s) in order to avoid overflows while doing arithmetic (+, -) on timestamps with limited integer precision available.

@tannewt
Copy link
Member

tannewt commented Apr 9, 2018

I was thinking we could add a precise_time module too.

@margaret
Copy link

I'm going to take a stab at this (pycon sprints)

@CBMalloch
Copy link

I'm trying to sample a 1kHz modulated light beam at 100µs intervals. About every 1/32 sec I go into a coma for almost 1/32 sec while the system does its other things. More precise timing would not help unless we also had a "suspend the other system things for a mo while I do this time-critical thing" function...

@tannewt
Copy link
Member

tannewt commented Sep 11, 2018

@CBMalloch how is the light beam being interfaced to the microcontroller? We may be able to add a C helper for it.

It's highly unlikely we'll ever allow for predictable timing in Python execution. There are too many critical things happening around the VM to do it.

@jak3kay
Copy link

jak3kay commented Oct 8, 2018

As time.monotonic() becomes less precise over time I support having a precise_time module with a custom timer with millisecond precision. It would be very useful if the module had a resettable timer that is independent of the changing precision provided by time.monotonic(). A precise_time module could provide something like this to allow timing of events with higher precision:

precise_time.reset() 
# do processing 
process_time = precise_time.time()

jepler added a commit to jepler/circuitpython that referenced this issue Oct 21, 2018
This is intended to be compatible with Python 3.7's time.monotonic_ns.
The "actual resolution" is 1ms due to this being the unit at which
common_hal_time_monotonic ticks.

Closes adafruit#519
@parsko41
Copy link

Hi all,
I'm also interested in a better timer. I'm more interested in knowing how long it takes to execute stuff. So, a read-only timer, to the usec would be very useful.

I've been playing with this and just realized that time.monotonic() is only good to 1 decimal. But, learned that is dependent on time since last restarted or reset(?)

Just wanted to chime in to say that I am also looking for the feature.

Thanks,

-Parsko

@gmparis
Copy link

gmparis commented Nov 3, 2018

I'll chime in on this too, since I recently ran into this limitation after switching a project from Arduino to CircuitPython. The project requires events triggered with at least 0.1 second resolution, but using monotonic() begins to fail. The only fix is to have the device reset as the resolution limit approaches. This is insufficient for my use case. I can't think of another way around it.

Even a rollover counter like millis() is preferable to monotonic(), as at least I can keep track of the rollovers and manage my own counter. Helping people port from Arduino also would argue for a millis()-like function, even if such does not exist in CPython.

Thanks for listening!
Greg

@tannewt
Copy link
Member

tannewt commented Nov 4, 2018

@gmparis time.monotonic_ns() will be released with the next 4.x alpha. Feel free to try a test build from here until then.

@tballas
Copy link

tballas commented Dec 13, 2018

So, I just put 4.0.0 alpha 5 on my Trinket M0 expecting to be able to use time.monotonic_ns() This is what I get in REPL:

Adafruit CircuitPython 4.0.0-alpha.5 on 2018-12-10; Adafruit Trinket M0 with samd21e18
>>> import time
>>> help(time)
object <module 'time'> is of type module
  __name__ -- time
  monotonic -- <function>
  sleep -- <function>
  struct_time -- <class 'struct_time'>
>>> time.monotonic_ns()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'monotonic_ns'
>>>

I wonder why it's not enabled?

@dhalbert
Copy link
Collaborator Author

We're only enabling time.monotonic_ns() on the Express builds. We need Python long integers for monotonic_ns() or else the values will wrap around after a few seconds. Unfortunately there's not enough room in the Trinket or Gemma builds for long integers (longints).

@tballas
Copy link

tballas commented Dec 13, 2018

Ah, that's unfortunate to hear. Thank you for explaining.

@l8gravely
Copy link

l8gravely commented Dec 13, 2018 via email

@framlin
Copy link

framlin commented Dec 19, 2018

Hello, I am totally new to this circuitpython stuff.
What I am looking for, is a timer-callback, that will be executed repeatedly after a certain period of time (something like setInterval(callback, period) in JavaScript).
This should run asynchronous, that means, that my program is not sleeping, but could do other stuff meanwhile.
Is that possible with circuitpython? If so, is there any example?

@dhalbert
Copy link
Collaborator Author

@framlin - sorry, we don't have callbacks or other asynchronous features right now (they are in MicroPython but we're not using them). We're working on coming up with simpler concurrency mechanisms that are easy to understand, e.g. #1380.

@zamfi
Copy link

zamfi commented Mar 14, 2019

I was able to get this running on my Metro M0 Express, but it looks like time.monotonic_ns() still only returns a value with a resolution of milliseconds.

Is there an equivalent to the micros() call available on the Arduino platform?

@kevinjwalters
Copy link

kevinjwalters commented Nov 11, 2019

@dhalbert Why does it make the builds bigger, is this just because literal ints end up with a larger representation in mpy files? Would having yet another function to return (seconds, milliseconds) as an (int,int) tuple be another option to support all boards?

(Discussion/issue in https://forums.adafruit.com/viewtopic.php?f=60&t=158501 reminded me of this)

@dhalbert
Copy link
Collaborator Author

@kevinjwalters The builds are bigger because we need longints to support time.monotonic_ns() values, which are larger than regular ints.

We have talked about adding another function, but it would not be in time, because we don't want to add new functionality to a standard module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests