Page 1 of 2

GPS project

PostPosted: Sun May 17, 2020 10:37 pm
by Brutman
The Jr warped my brain a little bit today ...

The project is to create a highly accurate time server using a GPS directly connected to the machine. The GPS I've chosen is a Garmin 18X LVC, which is a weather-tight puck shaped receiver that communicates using a serial data stream. These are often mounted on trucks or boats, and this particular model also has an extra wire for "1PPS" (one pulse per second) which allows you to accurately detect the start of each new second. The 1PPS line can be configured to generate a pulse ranging in duration from 20 to 980ms, although 20ms works fine.

Problem #1: Com1 and Com2 are at non-standard addresses and IRQs. We use comswap or an option on jrconfig to fix this, but I was reminded of it again today. Grr.

Problem #2: The baud rate divisor number for the Jr is not the same as on any other PC. It's close but not perfect, so any software that does not use the BIOS to open the serial port is probably doing it wrong on the PCjr. The Jr starts with a 1.7895Mhz clock while the PC starts with a 1.8432Mhz clock. On the PC you take the clock and divide by 16 to get 115200. That gets divided by 24 to generate a 4800bps setting for the UART. On the Jr if you assume the source clock is the same you wind up with 4660 bps, which is quite a bit off. Adjust for the Jr and dividing by 23 instead gives you 4862, which is close enough to work but still off.

Problem #3: The machine's timer ticks ever 55ms, which is just slow. This can be reprogrammed to get millisecond accuracy, but it involves making the timer interrupt fire 64x faster. I'm don't think it crushes the machine to do that, but taken to an extreme it will make reading the UART more difficult.

Problem #4: The machine is just slow. Screen writes using the BIOS are painful. Screen scrolling is glacial.

At the moment I've got the 1PPS line hooked up to the carrier detect line on the serial port, and I have an interrupt handler that can detect when the pulse comes in. (It actually fires the interrupt twice - once when the pulse starts and once when it ends. You can tell which is which by examining the carrier detect pin.) I've also got the system timer re-programmed to be more accurate, and I can measure the duration of the pulse to within 2 milliseconds or so. (The measurements are variable, probably because of other things going on in the system.) I can read the time data from the GPS using polled I/O, and usually I get everything. You definitely have to compute the checksum though as once in a while a byte or two get dropped.

I thought I was going to be able to create a stratum-1 time server. It's not going to be that accurate, but it will still be pretty cool. (I think I can get the accuracy of the system time to within 2 milliseconds of the GPS time.)

Re: GPS project

PostPosted: Mon May 18, 2020 8:59 am
by Trixter
Candidate for the most-effort-for-least-result award!

We use PPS extensively at my trading firm, for hopefully obvious reasons. I never thought I'd see one hooked up to a PCjr.

Re: GPS project

PostPosted: Mon May 18, 2020 9:23 am
by Brutman
I also remembered problem #5 today - never touch the PCjr keyboard. The machine uses the non-maskable interrupt line for the keyboard handling, so you will miss timer ticks or drop characters when reading from the UART.

On the plus side I've:
  • Successfully wired the GPS to a power supply and a DB-25 connector, including choosing a good pin for the PPS line. (The Jr doesn't support Ring Indicate, so Carrier Detect is what I'm using.)
  • Wrote my first code to directly program the UART and setup an interrupt handler to handle it. And the machines never crashed.
  • Reused code I wrote for mTCP to get down to sub-millisecond timing precision.

The plan now is to get a timestamp from the serial port, then wait for the PPS. Each time I get the PPS I know a new second has started within 0.85ms. I'll trust the system time for 15 seconds to a minute, and then re-read the timestamp from the GPS to ensure that nothing has drifted. In between I'll be able to serve Simple NTP requests to other machines in the house with some reasonably good accuracy.

Technically it will be a stratum 1 timeserver, but very poorly implemented. I've been advised that I should not advertise it and add it to the various Internet facing NTP server pools, as it might be off quite a bit compared to the more professional gear. ;-0

Re: GPS project

PostPosted: Sat May 23, 2020 6:19 am
by MattCarp
Mike, What led you down this path? Why would you want to have a stratum 1 timeserver? I suppose there are applications, and, a zillion Google search results that could tell me the need for the precise time, but I'm curious what you're up to.

I infer from Jim's comment that this could be used in securities/commodities trading, but beyond saying that, I don't know exactly how timing would be used in this context.

Re: GPS project

PostPosted: Sat May 23, 2020 11:40 am
by Brutman
I'm wasting time. :-)

The machine keeps time by firing an interrupt 18.2 times per second, making it's timer granularity 55ms. If interrupts are masked because of keyboard decoding or disk I/O, then the timer tick is lost, and the clock gets slower. The filesystem can't even record a timestamp accurate to within a second; it only has two seconds of granularity. To put it bluntly, there is absolutely no need on earth to have accurate time on a PCjr.

However, I'm still going to have a PCjr with the world's most accurate time clock. ;-0 And with some TCP/IP code, it will be able to serve accurate time to other machines on my network. I'm pretty sure that I can get and distribute time from a PCjr that is accurate to within 2 or 3 milliseconds.

The actual time on the PCjr will be very precise, as I can tell in microseconds when a new second ticks from the GPS. It's just the overhead of interrupt handling, TCP/IP handling, and general jitter on the system that makes it less accurate when trying to serve it. Also, that interrupt can be masked just like the timer interrupt so the machine has to resync against the GPS timestamp every few minutes to ensure it's not drifting too far due to keyboard or disk activity.

I'll be posting instructions and code for anybody else who needs a highly accurate PCjr clock source.

Re: GPS project

PostPosted: Sun Jun 07, 2020 11:14 pm
by Brutman
I was travelling last week, and now I'm in quarantine in my own basement to make sure I don't spread anything I might have picked up. Surprisingly, it's taken me about 5 days to turn my attention back to the PCjr even though I'm basically trapped in a room with it. ;-0

Here is the current state of the project:

  • The machine is reading the serial stream from the GPS, waiting for the first one that gets transferred correctly, and then setting the system time and date from it. (There is a checksum on each timestamp from the GPS that helps to detect corruption or lost bytes.)
  • The once-per-second interrupt is being used to update a counter in memory. For those of you who are C/Unix programmers it is a time_t that you get from time( ), except my version of it gets updated at each pulse from the GPS instead of relying on the system timer.
  • The system timer interrupt is hooked and I've reprogrammed the 8253 to tick 64 times faster. The faster tick rate let's me compute the number of ticks since each time the GPS has pulsed, giving me about 0.85 ms of timer resolution.

I have some warts in the code but it generally works, and it is accurate enough to have exposed an ancient bug in my ping program. (Ping is where I first learned to reprogram the 8253 timer to get higher resolution timestamps.) I'll clean up the code and do some more testing/verification. After that, this will be version A of the code that just syncs the system time from the GPS.

Version B will include the TCP/IP code to serve as a time server using SNTP. I'm doing A and B because if anybody just wants to set the time from a GPS without running a time server they should have that option.

Yes, this is still a silly project. But it was pretty cool holding up a cell phone to the PCjr and watching them both update the time on the screen at the same moment. And now when I sync the time against an SNTP server on the public internet it reports 0 seconds of drift.


Re: GPS project

PostPosted: Mon Jun 08, 2020 8:18 am
by Trixter
"even though I'm basically trapped in a room with it" is how my projects have been going -- I'm WFH during the pandemic and at the end of the working day, I need a break and need to leave the room.

You wrote about reprogramming the timer to get higher-resoultion timestamps -- the timer 16-bit counter can be read at any time, so why is reprogramming necessary?

Re: GPS project

PostPosted: Mon Jun 08, 2020 9:31 am
by Brutman
The machine starts in Mode 3. I researched Mode 2 and it wasn't worth the hassle. I'm targeting millisecond accuracy.

Re: GPS project

PostPosted: Mon Jun 08, 2020 10:36 am
by Trixter
You can switch the system to mode 2 and leave it that way and the system continues on just fine. The interrupts are generated at the same rate, which is why the system remains stable, but the counter counts down linearly. I switch it to mode 2 in my joystick code (and many demo projects) and have just left it that way with no repercussions in my known memory.

The "Timing on the PC family under DOS" FAQ mentions this in section 7.4.2.

Re: GPS project

PostPosted: Mon Jun 08, 2020 11:14 am
by alanh
You silly software engineers and your 'code'. The 'proper' way to solve this is with a VCXO and three numerical counters. With something like an FPGA (or even CPLD), the logic is simple. Building one out of discrete logic is possible though, and might be a fun challenge for someone.

The idea is you have 14.318 MHz Voltage Controlled Oscillator (VCXO) with at least a +/- 75 ppm swing range (or higher). The output frequency at any moment is controlled by a voltage (hence the name) that can be easily produced digitally from a PWM duty cycle. For example, 5% duty would be 14318181 - (75 * .05) Hz, where a 95% duty would be 14318181 + (75 * .95) Hz. You run the VCXO output into a counter. You run the counter output into a latch that is latched on a consistent edge of the GPS PPS signal. If the number latched each second is lower than 14318181, you increase the PWM duty counter. If the number is higher than 14318181, you decrease the PWM duty counter.

The PWM duty cycle counter is just a reference number. You can keep it in it's own numerical counter with the +1 or -1 applied either using a carry-in + optional inverting input - or some other counter that has a inc/dec input (or build your own). The PWM reference count is compared to a free-running counter (from the same oscillator). If the PWM reference counter is less than the PWM free running counter, the PWM line is low - otherwise high.

The idea is to create a digital feedback circuit that compares the number of ticks from a local oscillator each GPS PPS second to 14318181 and slew/drift it over time if not equal (or within 1). Once the VCXO has recovered the GPS PPS clock with a reference of 14.318 MHz, that same oscillator output drives the PCjr system clock. So you don't have to do anything in hardware to maintain perfect GPS time. In fact the entire system's clocking will be, as Mona Lisa Vito would say, 'dead on balls accurate'.