time-nuts@lists.febo.com

Discussion of precise time and frequency measurement

View all threads

Introducing 'Pico-Irig' with precision triggering scheme

S
simon@mungewell.org
Sat, Dec 28, 2024 8:06 PM

Hi all,
I've been working on my project and have achieved the milestone of
precise 1PPS synchronization to around +/-10ns, which I think may be of
interest to others here.

https://github.com/mungewell/pico-irig

In order to achieve the synchronization I use several state machines,
running at different clock rates on the Pico's PIO blocks, which trigger
and then count towards the 'start of next period'. The CPU's ISR then
self aligns to the PIO State Machine's clock and triggers the 'final'
(slow/12KHz) State Machine to start at exactly the correct time.

From my testing; multiple successive runs give the following 'start
time' (from async 1PPS to the 'final' state machine asserting it's
output), with a spread of 18ns.

$ cat precision2.dat
11 0.000083322
51 0.000083324
42 0.000083326
48 0.000083328
46 0.000083330
71 0.000083332
73 0.000083334
72 0.000083336
63 0.000083338
23 0.000083340

The precision trigger scheme is written up here:
https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md

Interested in comments and suggestions. MIT code to share for use in
other projects, cheers,
Simon.

Hi all, I've been working on my project and have achieved the milestone of precise 1PPS synchronization to around +/-10ns, which I think may be of interest to others here. https://github.com/mungewell/pico-irig In order to achieve the synchronization I use several state machines, running at different clock rates on the Pico's PIO blocks, which trigger and then count towards the 'start of next period'. The CPU's ISR then self aligns to the PIO State Machine's clock and triggers the 'final' (slow/12KHz) State Machine to start at exactly the correct time. From my testing; multiple successive runs give the following 'start time' (from async 1PPS to the 'final' state machine asserting it's output), with a spread of 18ns. -- $ cat precision2.dat 11 0.000083322 51 0.000083324 42 0.000083326 48 0.000083328 46 0.000083330 71 0.000083332 73 0.000083334 72 0.000083336 63 0.000083338 23 0.000083340 -- The precision trigger scheme is written up here: https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md Interested in comments and suggestions. MIT code to share for use in other projects, cheers, Simon.
SF
Sebastien F4GRX
Fri, Jan 3, 2025 12:04 AM

Hello,

First message on this list! I'm a ham and hacker with too many projects
including one to build a pps synchronizer from ttl chips (schematic is
done).

This is a very interesting project that I will reproduce soon, as I was
myself trying to achieve the same thing and I was wondering how to sync
the pico to 10 MHz. I was planning to sync of the pps alone, and
probably would have much worse results than yours.

It's amazing that you achieved that in Micropython, even if it had to be
slightly modified for the new clock source.

I have just one question, could the raw IRIG-B bits be output on another
GPIO with the same level of accuracy? I was planning a fully digital
time distribution system over plastic fiber.

Sebastien

On 12/28/24 21:06, simon--- via time-nuts wrote:

Hi all,
I've been working on my project and have achieved the milestone of
precise 1PPS synchronization to around +/-10ns, which I think may be
of interest to others here.

https://github.com/mungewell/pico-irig

In order to achieve the synchronization I use several state machines,
running at different clock rates on the Pico's PIO blocks, which
trigger and then count towards the 'start of next period'. The CPU's
ISR then self aligns to the PIO State Machine's clock and triggers the
'final' (slow/12KHz) State Machine to start at exactly the correct time.

From my testing; multiple successive runs give the following 'start
time' (from async 1PPS to the 'final' state machine asserting it's
output), with a spread of 18ns.

$ cat precision2.dat
     11 0.000083322
     51 0.000083324
     42 0.000083326
     48 0.000083328
     46 0.000083330
     71 0.000083332
     73 0.000083334
     72 0.000083336
     63 0.000083338
     23 0.000083340

The precision trigger scheme is written up here:
https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md

Interested in comments and suggestions. MIT code to share for use in
other projects, cheers,
Simon.


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

Hello, First message on this list! I'm a ham and hacker with too many projects including one to build a pps synchronizer from ttl chips (schematic is done). This is a very interesting project that I will reproduce soon, as I was myself trying to achieve the same thing and I was wondering how to sync the pico to 10 MHz. I was planning to sync of the pps alone, and probably would have much worse results than yours. It's amazing that you achieved that in Micropython, even if it had to be slightly modified for the new clock source. I have just one question, could the raw IRIG-B bits be output on another GPIO with the same level of accuracy? I was planning a fully digital time distribution system over plastic fiber. Sebastien On 12/28/24 21:06, simon--- via time-nuts wrote: > Hi all, > I've been working on my project and have achieved the milestone of > precise 1PPS synchronization to around +/-10ns, which I think may be > of interest to others here. > > https://github.com/mungewell/pico-irig > > In order to achieve the synchronization I use several state machines, > running at different clock rates on the Pico's PIO blocks, which > trigger and then count towards the 'start of next period'. The CPU's > ISR then self aligns to the PIO State Machine's clock and triggers the > 'final' (slow/12KHz) State Machine to start at exactly the correct time. > > From my testing; multiple successive runs give the following 'start > time' (from async 1PPS to the 'final' state machine asserting it's > output), with a spread of 18ns. > -- > $ cat precision2.dat >      11 0.000083322 >      51 0.000083324 >      42 0.000083326 >      48 0.000083328 >      46 0.000083330 >      71 0.000083332 >      73 0.000083334 >      72 0.000083336 >      63 0.000083338 >      23 0.000083340 > -- > > The precision trigger scheme is written up here: > https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md > > > Interested in comments and suggestions. MIT code to share for use in > other projects, cheers, > Simon. > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com
S
simon@mungewell.org
Fri, Jan 3, 2025 4:58 PM

Thank you for the comments. All of the SM (of a PIO block) are
synchronized together and run at the same clock division, meaning that
they can output GPIO at the same clock precision. There is option in the
code to synchronize another/2nd PIO block 2 CPU-clock cycles later.

The way my IRIG code works is that 'time' is held in the
State-Machine(s), and all the CPU has to do it pre-compute IRIG (or
SMPTE) bitstream and pre-load the FIFO before it's actually need to be
played out. The State-Machine(s) take the FIFO and assert the GPIO at
the exact moment in time that they are needed.

I added another SM example 'REGEN_1HZ' that you might like ;-)

Q. Do you actually need your Pico to be processing at 10MHz, or 'just'
synchronized to this precision?

If you adjusted the counter, my code would work for different SM clock
rates (I use 12KHz). But you need to remember that the CPU need 10-25us
(may be quicker with high CPU clock, I used 120MHz) to enter the ISR, to
be ready to 'see' the moment that the counter completes.

I was also in a Reddit discussion on how to time-stamp incoming GPIO
with good precision, and it seems that doing this with a PIO SM is also
a good option - which gets a precision of 1/4 of CPU clock. Since up-to
4 SMs can be run exactly synchronized you can parallel-up to measure
relative timing of up-to 4 inputs.

https://github.com/mungewell/pico-irig/issues/3

If you want, you can then slightly adjust SM clock dividers to
tweak/tune the rate and match the incoming clock rate. I spent a
while looking at how good the Pico's stock XTAL is (spoiler - not very)
and replacing it with TCXO. The next step is to replace with the 10MHz
from a GPSDO, which is why I am here...

Cheers, good luck with your project,
Simon.

On 2025-01-02 16:04, Sebastien F4GRX via time-nuts wrote:

Hello,

First message on this list! I'm a ham and hacker with too many projects
including one to build a pps synchronizer from ttl chips (schematic is
done).

This is a very interesting project that I will reproduce soon, as I was
myself trying to achieve the same thing and I was wondering how to sync
the pico to 10 MHz. I was planning to sync of the pps alone, and
probably would have much worse results than yours.

It's amazing that you achieved that in Micropython, even if it had to
be slightly modified for the new clock source.

I have just one question, could the raw IRIG-B bits be output on
another GPIO with the same level of accuracy? I was planning a fully
digital time distribution system over plastic fiber.

Sebastien

On 12/28/24 21:06, simon--- via time-nuts wrote:

Hi all,
I've been working on my project and have achieved the milestone of
precise 1PPS synchronization to around +/-10ns, which I think may be
of interest to others here.

https://github.com/mungewell/pico-irig

In order to achieve the synchronization I use several state machines,
running at different clock rates on the Pico's PIO blocks, which
trigger and then count towards the 'start of next period'. The CPU's
ISR then self aligns to the PIO State Machine's clock and triggers the
'final' (slow/12KHz) State Machine to start at exactly the correct
time.

From my testing; multiple successive runs give the following 'start
time' (from async 1PPS to the 'final' state machine asserting it's
output), with a spread of 18ns.
-- $ cat precision2.dat
     11 0.000083322
     51 0.000083324
     42 0.000083326
     48 0.000083328
     46 0.000083330
     71 0.000083332
     73 0.000083334
     72 0.000083336
     63 0.000083338
     23 0.000083340
-- The precision trigger scheme is written up here:
https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md
Interested in comments and suggestions. MIT code to share for use in
other projects, cheers,
Simon.


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

Thank you for the comments. All of the SM (of a PIO block) are synchronized together and run at the same clock division, meaning that they can output GPIO at the same clock precision. There is option in the code to synchronize another/2nd PIO block 2 CPU-clock cycles later. The way my IRIG code works is that 'time' is held in the State-Machine(s), and all the CPU has to do it pre-compute IRIG (or SMPTE) bitstream and pre-load the FIFO before it's actually need to be played out. The State-Machine(s) take the FIFO and assert the GPIO at the **exact** moment in time that they are needed. I added another SM example 'REGEN_1HZ' that you might like ;-) Q. Do you actually need your Pico to be processing at 10MHz, or 'just' synchronized to this precision? If you adjusted the counter, my code would work for different SM clock rates (I use 12KHz). But you need to remember that the CPU need 10-25us (may be quicker with high CPU clock, I used 120MHz) to enter the ISR, to be ready to 'see' the moment that the counter completes. I was also in a Reddit discussion on how to time-stamp incoming GPIO with good precision, and it seems that doing this with a PIO SM is also a good option - which gets a precision of 1/4 of CPU clock. Since up-to 4 SMs can be run **exactly** synchronized you can parallel-up to measure relative timing of up-to 4 inputs. https://github.com/mungewell/pico-irig/issues/3 If you want, you can then slightly adjust SM clock dividers to tweak/tune the rate and **match** the incoming clock rate. I spent a while looking at how good the Pico's stock XTAL is (spoiler - not very) and replacing it with TCXO. The next step is to replace with the 10MHz from a GPSDO, which is why I am here... Cheers, good luck with your project, Simon. On 2025-01-02 16:04, Sebastien F4GRX via time-nuts wrote: > Hello, > > First message on this list! I'm a ham and hacker with too many projects > including one to build a pps synchronizer from ttl chips (schematic is > done). > > This is a very interesting project that I will reproduce soon, as I was > myself trying to achieve the same thing and I was wondering how to sync > the pico to 10 MHz. I was planning to sync of the pps alone, and > probably would have much worse results than yours. > > It's amazing that you achieved that in Micropython, even if it had to > be slightly modified for the new clock source. > > I have just one question, could the raw IRIG-B bits be output on > another GPIO with the same level of accuracy? I was planning a fully > digital time distribution system over plastic fiber. > > Sebastien > > > On 12/28/24 21:06, simon--- via time-nuts wrote: >> Hi all, >> I've been working on my project and have achieved the milestone of >> precise 1PPS synchronization to around +/-10ns, which I think may be >> of interest to others here. >> >> https://github.com/mungewell/pico-irig >> >> In order to achieve the synchronization I use several state machines, >> running at different clock rates on the Pico's PIO blocks, which >> trigger and then count towards the 'start of next period'. The CPU's >> ISR then self aligns to the PIO State Machine's clock and triggers the >> 'final' (slow/12KHz) State Machine to start at exactly the correct >> time. >> >> From my testing; multiple successive runs give the following 'start >> time' (from async 1PPS to the 'final' state machine asserting it's >> output), with a spread of 18ns. >> -- $ cat precision2.dat >>      11 0.000083322 >>      51 0.000083324 >>      42 0.000083326 >>      48 0.000083328 >>      46 0.000083330 >>      71 0.000083332 >>      73 0.000083334 >>      72 0.000083336 >>      63 0.000083338 >>      23 0.000083340 >> -- The precision trigger scheme is written up here: >> https://github.com/mungewell/pico-irig/blob/main/docs/precision_trigger.md >> Interested in comments and suggestions. MIT code to share for use in >> other projects, cheers, >> Simon. >> _______________________________________________ >> time-nuts mailing list -- time-nuts@lists.febo.com >> To unsubscribe send an email to time-nuts-leave@lists.febo.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com
S
simon@mungewell.org
Fri, Jan 3, 2025 5:17 PM

On 2025-01-02 16:04, Sebastien F4GRX via time-nuts wrote:

I have just one question, could the raw IRIG-B bits be output on
another GPIO with the same level of accuracy? I was planning a fully
digital time distribution system over plastic fiber.

I do output the 'raw' FIFO bits via GPIO, but due to PIO code size
limits this uses the 'other' PIO block which is slightly delayed sync.
However I have the FIFO output during an earlier 12KHz period, so that
the values are ready/available for use by the main State-Machines. This
obviously could be re-jigged for particular application.

My IRIG data stream is encode 2-bit per symbol, one for data high/low
and one for 'Px/PR'.
Simon.

On 2025-01-02 16:04, Sebastien F4GRX via time-nuts wrote: > I have just one question, could the raw IRIG-B bits be output on > another GPIO with the same level of accuracy? I was planning a fully > digital time distribution system over plastic fiber. I do output the 'raw' FIFO bits via GPIO, but due to PIO code size limits this uses the 'other' PIO block which is slightly delayed sync. However I have the FIFO output during an earlier 12KHz period, so that the values are ready/available for use by the main State-Machines. This obviously could be re-jigged for particular application. My IRIG data stream is encode 2-bit per symbol, one for data high/low and one for 'Px/PR'. Simon.