Jeff’s Ideas for Python on Hardware in 2020 – Time & Timekeeping #CircuitPython2020
Hi! I’m Jeff Epler, AKA @jepler. Python has long had a special place in my heart, because it is the computer language that makes me feel like I can accomplish anything I dream up.
When it comes to CircuitPython I’m new and have a lot to learn, but one thing I have seen is that it’s important to go in depth on an idea and make sure that the code in the core is ready to support a wide range of uses. When we do this, we can find and fix problems before a new user having her first experience with CircuitPython has trouble.
One direction I’d like to dive deep is timekeeping. If that sounds interesting to you, read on…
Timekeeping and Time Measurement
I’m a bit of a time nut, so I’d like to enable CircuitPython to keep better time. It won’t necessarily be my focus in 2020, but it’s a set of thoughts to fall back on if I’m ever idle. What would it take to make projects like these possible in CircuitPython?
GPS Disciplined Oscillator
Frequency Counter accurate to 1 ppm (6 digits)
Enhance the time module
In CircuitPython today, timekeeping depends on the “SysTick”, and requires attention from the CPU every millisecond or a tick can be lost. This happens regularly during certain tasks, like updating large numbers of neopixels. We should modify most of the routines in the time module to use a built in RTC counter instead of the SysTick counter, on all ports where this is possible. This would probably still count time at around 1ms granularity, but would no longer risk losing time even while doing tasks that fully occupy the CPU for more than 1ms at a time. This may also enable calibration of a board’s timing crystal, to reduce the number of seconds per day gained or lost while the device is running. Except optionally adding a calibration value in boot.py, this would be transparent to users of CircuitPython.
Enhance the frequencyio module
A GPS Disciplined Oscillator (GPSDO) is a clock signal (often 1MHz or 10MHz) that is regulated very precisely using the GPS time as a reference. A Frequency Counter is a device to measure the frequency of a signal.
A key sub-problem of these tasks is to continuously count the relative rates of two input signals in the background, while continuing to do Python tasks in the foreground. Right now, frequencyio only supports counting frequency in the foreground.
Enhance the pulseio module
WWVB is a radio signal that can be received almost everywhere in North America. Its signal can tell you the current time, once per minute. If you have a self-setting wall clock in your home, it’s probably using this kind of signal.
For a WWVB Receiver, you need to continuously receive a low bandwidth (1 symbol per second) signal in the background while the foreground Python code decodes the signal received in a previous minute and does other tasks such as updating a clock display. Right now, pulseio only supports recording pulses in the foreground.
Enhance timezone handling
For a World Clock, you need the ability to work with standard “tzinfo” files, to convert among local time, UTC time, and other world time zones. This might be as simple as porting the python package dateutil to circuitpython, or it might end up requiring new code designed just for CircuitPython. In the end, you would be able to convert times between UTC and various local times.
We are angry, frustrated, and in pain because of the violence and murder of Black people by the police because of racism. We are in the fight AGAINST RACISM. George Floyd was murdered, his life stolen. The Adafruit teams have specific actions we’ve done, are doing, and will do together as a company and culture. We are asking the Adafruit community to get involved and share what you are doing. The Adafruit teams will not settle for a hash tag, a Tweet, or an icon change. We will work on real change, and that requires real action and real work together. That is what we will do each day, each month, each year – we will hold ourselves accountable and publish our collective efforts, partnerships, activism, donations, openly and publicly. Our blog and social media platforms will be utilized in actionable ways. Join us and the anti-racist efforts working to end police brutality, reform the criminal justice system, and dismantle the many other forms of systemic racism at work in this country, read more @ adafruit.com/blacklivesmatter
Stop breadboarding and soldering – start making immediately! Adafruit’s Circuit Playground is jam-packed with LEDs, sensors, buttons, alligator clip pads and more. Build projects with Circuit Playground in a few minutes with the drag-and-drop MakeCode programming site, learn computer science using the CS Discoveries class on code.org, jump into CircuitPython to learn Python and hardware together, TinyGO, or even use the Arduino IDE. Circuit Playground Express is the newest and best Circuit Playground board, with support for CircuitPython, MakeCode, and Arduino. It has a powerful processor, 10 NeoPixels, mini speaker, InfraRed receive and transmit, two buttons, a switch, 14 alligator clip pads, and lots of sensors: capacitive touch, IR proximity, temperature, light, motion and sound. A whole wide world of electronics and coding is waiting for you, and it fits in the palm of your hand.
Get the only spam-free daily newsletter about wearables, running a "maker business", electronic tips and more! Subscribe at AdafruitDaily.com !
To do all of these timing things:
1) Set up a timer running at the full clock speed, which interrupts every time it overflows. The ISR (Interrupt Service Routine) increments an overflow counter.
2) Set up external and/or internal inputs to trigger the timer capture and execute an interrupt. The ISR in this case reads and stores the capture register, the overflow counter, and the input source; and then releases the counter register for the next input.
3) An interface presents the (capture, overflow, input) tuples to user code. Current (counter, overflow) tuples can also be obtained so you know what ‘now’ is.
With this general facility, all of your desires (except for timezone support) can be met:
If you record the Pulses times from the WWVB (or better yet the PPS from a GPS), then you know what time it is relative to the second (and also have an increasingly refined knowledge of how fast the system clock is running);
If you record the times of each input pulse you can compare the times of the zeroth and nth pulse to get a frequency. (It helps if your ISR in #2 can be set to record only the every nth pulse of a specific input, or you can use a prescalar counter on that input.). If the number of clock cycles between the pulses is >1e6 (and the jitter is low enough) you have PPM frequency measurement, even at low frequencies over short accumulation times.
I started implementing this for the SAMDx1 chips in the ‘pulse time’ branch at https://github.com/dmopalmer/circuitpython/tree/pulsetime
but so far I haven’t managed to get the counter to actually count.
At 48 MHz counter speed, a lot of moderately-high-precision applications are possible.
Thanks David! This looks like a great start. I haven’t understood the samd timers in depth yet, that’s for sure. How can we help you move this PR along? (Discussing it on GitHub or discord is probably better than here)