Skip to content

Commit 40d4a36

Browse files
committed
Prior to creating latency branch
1 parent bc54c3f commit 40d4a36

File tree

2 files changed

+81
-56
lines changed

2 files changed

+81
-56
lines changed

gps/README.md

Lines changed: 80 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,8 @@ cleared by power cycling the GPS.
532532

533533
### 3.3.1 Changing baudrate
534534

535-
The if you change the GPS baudrate the UART should be re-initialised
536-
immediately after the `baudrate` coroutine terminates:
535+
If you change the GPS baudrate the UART should be re-initialised immediately
536+
after the `baudrate` coroutine terminates:
537537

538538
```python
539539
async def change_status(gps, uart):
@@ -561,32 +561,36 @@ measured in seconds) polls the value, returning it when it changes.
561561

562562
* `version` Initially `None`. A list of version strings.
563563
* `enabled` Initially `None`. A dictionary of frequencies indexed by message
564-
type.
565-
* `antenna` Initially 0. Values:
564+
type (see `enable` coroutine above).
565+
* `antenna` Initially 0. Values:
566566
0 No report received.
567567
1 Antenna fault.
568568
2 Internal antenna.
569569
3 External antenna.
570570

571-
## 3.5 The parse method
571+
## 3.5 The parse method (developer note)
572572

573-
The default `parse` method is redefined. It intercepts the single response to
574-
`VERSION` and `ENABLE` commands and updates the above bound variables. The
575-
`ANTENNA` command causes repeated messages to be sent. These update the
576-
`antenna` bound variable. These "handled" messages call the message callback
577-
with the `GPS` instance followed by a list of sentence segments followed by any
578-
args specified in the constructor.
573+
The null `parse` method in the base class is overridden. It intercepts the
574+
single response to `VERSION` and `ENABLE` commands and updates the above bound
575+
variables. The `ANTENNA` command causes repeated messages to be sent. These
576+
update the `antenna` bound variable. These "handled" messages call the message
577+
callback with the `GPS` instance followed by a list of sentence segments
578+
followed by any args specified in the constructor.
579579

580580
Other `PMTK` messages are passed to the optional message callback as described
581581
[in section 3.2](./README.md#32-constructor).
582582

583583
# 4. Using GPS for accurate timing
584584

585585
Many GPS chips (e.g. MTK3339) provide a PPS signal which is a pulse occurring
586-
at 1s intervals whose leading edge is a highly accurate time reference. It may
587-
be used to set and to calibrate the Pyboard realtime clock (RTC). These drivers
588-
are for MicroPython only. The RTC functionality is for STM chips (e.g. Pyboard)
589-
only (at least until the `machine` library supports an `RTC` class).
586+
at 1s intervals whose leading edge is a highly accurate UTC time reference.
587+
588+
This driver uses this pulse to provide accurate subsecond UTC and local time
589+
values. The driver requires MicroPython because PPS needs a pin interrupt.
590+
591+
On STM platforms such as the Pyboard it may be used to set and to calibrate the
592+
realtime clock (RTC). This functionality is not currently portable to other
593+
chips.
590594

591595
See [Absolute accuracy](./README.md#45-absolute-accuracy) for a discussion of
592596
the absolute accuracy provided by this module (believed to be on the order of
@@ -603,7 +607,7 @@ and `GPS_RWTimer` for read/write access.
603607
* `as_tGPS.py` The library. Provides `GPS_Timer` and `GPS_RWTimer` classes.
604608
* `as_GPS_time.py` Test scripts for above.
605609

606-
### 4.1.1 Usage xxample
610+
### 4.1.1 Usage example
607611

608612
```python
609613
import uasyncio as asyncio
@@ -645,8 +649,10 @@ the base classes are supported. Additional functionality is detailed below.
645649
Mandatory positional args:
646650
* `sreader` The `StreamReader` instance associated with the UART.
647651
* `pps_pin` An initialised input `Pin` instance for the PPS signal.
652+
648653
Optional positional args:
649-
* `local_offset` See `AS_GPS` details for these args.
654+
* `local_offset` See [base class](./README.md##21-constructor) for details of
655+
these args.
650656
* `fix_cb`
651657
* `cb_mask`
652658
* `fix_cb_args`
@@ -663,8 +669,10 @@ This takes three mandatory positional args:
663669
* `sreader` The `StreamReader` instance associated with the UART.
664670
* `swriter` The `StreamWriter` instance associated with the UART.
665671
* `pps_pin` An initialised input `Pin` instance for the PPS signal.
672+
666673
Optional positional args:
667-
* `local_offset` See `GPS` details.
674+
* `local_offset` See [base class](./README.md##32-gps-class-constructor) for
675+
details of these args.
668676
* `fix_cb`
669677
* `cb_mask`
670678
* `fix_cb_args`
@@ -674,7 +682,7 @@ Optional positional args:
674682
interrupt context so it should return quickly and cannot allocate RAM. Default
675683
is a null method. See below for callback args.
676684
* `pps_cb_args` Default `()`. A tuple of args for the callback. The callback
677-
receives the `GPS_Timer` instance as the first arg, followed by any args in
685+
receives the `GPS_RWTimer` instance as the first arg, followed by any args in
678686
the tuple.
679687

680688
## 4.3 Public methods
@@ -683,53 +691,59 @@ These return an accurate GPS time of day. As such they return as fast as
683691
possible. To achieve this they avoid allocation and dispense with error
684692
checking: these functions should not be called until a valid time/date message
685693
and PPS signal have occurred. Await the `ready` coroutine prior to first use.
686-
Subsequent calls may occur without restriction. A usage example is in the time
687-
demo in `as_GPS_time.py`.
694+
Subsequent calls may occur without restriction; see usage example above.
688695

689696
* `get_ms` No args. Returns an integer: the period past midnight in ms.
690697
* `get_t_split` No args. Returns time of day in a list of form
691698
`[hrs: int, mins: int, secs: int, μs: int]`.
692699

700+
These methods use the MicroPython microsecond timer to interpolate between PPS
701+
pulses. They do not involve the RTC. Hence they should work on any MicroPython
702+
target supporting `machine.ticks_us`.
703+
693704
See [Absolute accuracy](./README.md#45-absolute-accuracy) for a discussion of
694705
the accuracy of these methods.
695706

696707
## 4.4 Public coroutines
697708

698-
* `ready` No args. Pauses until a valid time/date message and PPS signal have
709+
All MicroPython targets:
710+
* `ready` No args. Pauses until a valid time/date message and PPS signal have
699711
occurred.
700-
* `set_rtc` No args. STM hosts only. Sets the Pyboard RTC to GPS time. Coro
701-
pauses for up to 1s as it waits for a PPS pulse.
702-
* `delta` No args. STM hosts only. Returns no. of μs RTC leads GPS. Coro
703-
pauses for up to 1s.
704-
* `calibrate` Arg: integer, no. of minutes to run default 5. STM hosts only.
705-
Calibrates the Pyboard RTC and returns the calibration factor for it. This
706-
coroutine sets the RTC (with any existing calibration removed) and measures
707-
its drift with respect to the GPS time. This measurement becomes more precise
708-
as time passes. It calculates a calibration value at 10s intervals and prints
709-
progress information. When the calculated calibration factor is repeatable
710-
within one digit (or the spcified time has elapsed) it terminates. Typical run
711-
times are on the order of two miutes.
712+
713+
STM hosts only:
714+
* `set_rtc` No args. Sets the RTC to GPS time. Coroutine pauses for up
715+
to 1s as it waits for a PPS pulse.
716+
* `delta` No args. Returns no. of μs RTC leads GPS. Coro pauses for up to 1s.
717+
* `calibrate` Arg: integer, no. of minutes to run default 5. Calibrates the
718+
RTC and returns the calibration factor for it.
719+
720+
The `calibrate` coroutine sets the RTC (with any existing calibration removed)
721+
and measures its drift with respect to the GPS time. This measurement becomes
722+
more precise as time passes. It calculates a calibration value at 10s intervals
723+
and prints progress information. When the calculated calibration factor is
724+
repeatable within one digit (or the spcified time has elapsed) it terminates.
725+
Typical run times are on the order of two miutes.
712726

713727
Achieving an accurate calibration factor takes time but does enable the Pyboard
714728
RTC to achieve timepiece quality results. Note that calibration is lost on
715729
power down: solutions are either to use an RTC backup battery or to store the
716730
calibration factor in a file (or in code) and re-apply it on startup.
717731

718-
Crystal oscillator frequency (and hence calibration factor) is temperature
719-
dependent. For the most accurate possible results allow the Pyboard to reach
720-
working temperature before calibrating.
732+
Crystal oscillator frequency has a small temperature dependence; consequently
733+
the optimum calibration factor has a similar dependence. For best results allow
734+
the hardware to reach working temperature before calibrating.
721735

722736
## 4.5 Absolute accuracy
723737

724738
The claimed absolute accuracy of the leading edge of the PPS signal is +-10ns.
725739
In practice this is dwarfed by errors including latency in the MicroPython VM.
726740
Nevertheless the `get_ms` method can be expected to provide 1 digit (+-1ms)
727741
accuracy and the `get_t_split` method should provide accuracy on the order of
728-
+-70μs (standard deviation).
742+
+-70μs (standard deviation). This is based on a Pyboard running at 168MHz.
729743

730-
Without an atomic clock synchronised to a Tier 1 NTP server this is hard to
731-
prove. However if the manufacturer's claim of the accuracy of the PPS signal is
732-
accepted, the errors contributed by MicroPython can be estimated.
744+
Without an atomic clock synchronised to a Tier 1 NTP server absolute accuracy
745+
is hard to prove. However if the manufacturer's claim of the accuracy of the
746+
PPS signal is accepted, the errors contributed by MicroPython can be estimated.
733747

734748
The driver interpolates between PPS pulses using `utime.ticks_us()` to provide
735749
μs precision. The leading edge of PPS triggers an interrupt which records the
@@ -742,10 +756,12 @@ Sources of error are:
742756
* Variations in interrupt latency.
743757
* Inaccuracy in the `ticks_us` timer.
744758
* Latency in the function used to retrieve the time.
759+
* Mean value of the interrupt latency.
745760

746761
The test program `as_GPS_time.py` has a test `usecs` which aims to assess the
747762
first two. It repeatedly uses `ticks_us` to measure the time between PPS pulses
748-
over a minute then calculates some simple statistics on the result.
763+
over a minute then calculates some simple statistics on the result. On targets
764+
other than a 168MHz Pyboard this offers a way of estimating overheads.
749765

750766
## 4.6 Test/demo program as_GPS_time.py
751767

@@ -758,7 +774,8 @@ runs.
758774
end of the run, print the error in μs/hr and minutes/year.
759775
* `usec(minutes=1)` Measure the accuracy of `utime.ticks_us()` against the PPS
760776
signal. Print basic statistics at the end of the run. Provides an estimate of
761-
the absolute accuracy of the `get_t_split` method.
777+
some limits to the absolute accuracy of the `get_t_split` method as discussed
778+
above.
762779

763780
# 5. Supported Sentences
764781

@@ -789,22 +806,23 @@ subclassed. If a correctly formed sentence with a valid checksum is received,
789806
but is not supported, the `parse` method is called. By default this is a
790807
`lambda` which ignores args and returns `True`.
791808

792-
An example of overriding this method may be found in the `as_rwGPS.py` module.
809+
A subclass may override `parse` to parse such sentences. An example this may be
810+
found in the `as_rwGPS.py` module.
793811

794-
A subclass may redefine this to attempt to parse such sentences. The method
795-
receives an arg `segs` being a list of strings. These are the parts of the
796-
sentence which were delimited by commas. `segs[0]` is the sentence type with
797-
the leading '$' character removed.
812+
The `parse` method receives an arg `segs` being a list of strings. These are
813+
the parts of the sentence which were delimited by commas. See
814+
[section 2.5](./README.md#25-subclass-hooks) for details.
798815

799-
It should return `True` if the sentence was successfully parsed, otherwise
800-
`False`.
816+
The `parse` method should return `True` if the sentence was successfully
817+
parsed, otherwise `False`.
801818

802-
Where a sentence is successfully parsed, a null `reparse` method is called.
803-
This may be overridden in a subclass.
819+
Where a sentence is successfully parsed by the driver, a null `reparse` method
820+
is called. It receives the same string list as `parse`. It may be overridden in
821+
a subclass, possibly to extract further information from the sentence.
804822

805823
## 6.2 Special test programs
806824

807-
These tests allow NMEA parsing to be verified in the absence of GPS hardware
825+
These tests allow NMEA parsing to be verified in the absence of GPS hardware:
808826

809827
* `astests.py` Test with synthetic data. Run on CPython 3.x or MicroPython.
810828
* `astests_pyb.py` Test with synthetic data on UART. GPS hardware replaced by
@@ -823,10 +841,17 @@ The PPS signal on the MTK3339 occurs only when a fix has been achieved. The
823841
leading edge occurs on a 1s boundary with high absolute accuracy. It therefore
824842
follows that the RMC message carrying the time/date of that second arrives
825843
after the leading edge (because of processing and UART latency). It is also
826-
the case that on a second boundary minutes, hours and the date may roll over.
844+
the case that on a one-second boundary minutes, hours and the date may roll
845+
over.
827846

828847
Further, the local_time offset can affect the date. These drivers aim to handle
829-
these factors.
848+
these factors. They do this by storing the epoch time (as an integer number of
849+
seconds) as the fundamental time reference. This is updated by the RMC message.
850+
The `utc`, `date` and `localtime` properties convert this to usable values with
851+
the latter two using the `local_offset` value to ensure correct results.
852+
853+
A discussion of how the precision timing methods interpolate between epoch
854+
times may be found here [section 4.5](./README.md##45-absolute-accuracy).
830855

831856
[MicroPython]:https://micropython.org/
832857
[frozen module]:https://learn.adafruit.com/micropython-basics-loading-modules/frozen-modules

gps/as_GPS.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def _set_date_time(self, utc_string, date_string):
269269
except ValueError: # Bad date or time strings
270270
return False
271271
wday = self._week_day(y, m, d)
272-
t = self._mktime((y, m, d, hrs, mins, int(secs), wday - 1, 0, 0))
272+
t = int(self._mktime((y, m, d, hrs, mins, int(secs), wday - 1, 0, 0)))
273273
self.epoch_time = t # This is the fundamental datetime reference.
274274
self._dtset(wday) # Subclass may override
275275
return True

0 commit comments

Comments
 (0)