GPS project
Re: GPS project
I tried to read that post on my laptop and it got really warm and then started emitting smoke. Google Translate also couldn't tell what language that was in. However, that sounds like a really neat project. Is there a Python program or a pre-compiled binary for Windows 10 available?
Re: GPS project
What part of 'dead on balls accurate' is hard to understand? 
The cliff notes version is no local oscillator is 100.00000% accurate to the frequency printed on the can. You know this, hence the problem you are trying to solve with GPS.
So get an oscillator with a +/- fine frequency adjustment. Count the number of ticks between GPS pulses per second. If the tick count is smaller than the desired frequency, turn up the fine adjustment knob. If it's higher, turn down the fine adjustment knob. Create a PID loop to do this automatically every second. Bingo, you have a local oscillator that averages to 100.00000000% accuracy (or however accurate GPS is at least). Let the frequency you choose be 14.318 MHz (the crystal frequency of a 4.77 MHZ 8088 like the PCjr) and use your shinny dead on balls accurate oscillator as the system clock reference. Now you don't have to write any Python, run any Windows 10, or any of that Satan-worshiping software stuff!!!
The cliff notes version is no local oscillator is 100.00000% accurate to the frequency printed on the can. You know this, hence the problem you are trying to solve with GPS.
So get an oscillator with a +/- fine frequency adjustment. Count the number of ticks between GPS pulses per second. If the tick count is smaller than the desired frequency, turn up the fine adjustment knob. If it's higher, turn down the fine adjustment knob. Create a PID loop to do this automatically every second. Bingo, you have a local oscillator that averages to 100.00000000% accuracy (or however accurate GPS is at least). Let the frequency you choose be 14.318 MHz (the crystal frequency of a 4.77 MHZ 8088 like the PCjr) and use your shinny dead on balls accurate oscillator as the system clock reference. Now you don't have to write any Python, run any Windows 10, or any of that Satan-worshiping software stuff!!!
Re: GPS project
So you causally throw in a control system and you talk about the rest of us being Satan worshippers? 
Re: GPS project
Just correcting my math:alanh wrote:For example, 5% duty would be 14318181 - (75 * .05) Hz, where a 95% duty would be 14318181 + (75 * .95) Hz.
5% duty would be 14318181 - (75 * 14.31 * .95) Hz (, where a 95% duty would be 14318181 + (75 * 14.31 * .95) Hz.
So 14317161 MHz (5%) to 14319212 MHz (95%)
Re: GPS project
So I got back to this project and I decided to try mode 2 of the 8253 timer out. Short story, it works ...
This code is better because it doesn't change the interrupt interval from the 8253 like the previous code, so that interrupt is firing back at the normal 18.2 times per second. I had it firing 64x faster before which is slightly noticeable on the machine, and also raises the chances than an interrupt will be missed. The biggest challenge was doing the math correctly without doing floating point. I'm using 32 bit integers to keep things faster than using emulated floating point, and it is slightly sloppy but it works.
I think my timing resolution is comfortably under 1ms now where before it was in the 1 to 2ms range. When the GPS 1PPS causes an interrupt I increment my own "seconds since the epoch" counter, the BIOS ticks and the 8253 counter are read and squirreled away. The interrupt gets handled, my code resumes, and it sees that the interrupt has recently fired. It then snapshots the BIOS ticks and 8253 counter again, does the math, and computes the current timestamp. This is taking on the order of 600 to 700 microseconds to do. (Screen access time is not counted; it's just the time to finish the interrupt handler, get back to the main program loop, figure out the time needs to be displayed, and then compute the current time.)
Assuming 650 microseconds and machine running at 4.77Mhz that works out to 3100 clock cycles. I actually have a V20 which is slightly better than the stock 8088 but the machine is running C code that isn't highly optimized and it's still doing integer division on the math. This doesn't seem unreasonable, and if I can knock off a few division instructions I can save a lot of clock cycles. (Shifting 10 bits right instead of dividing by 1000 would save a lot of cycles at the expense of some accuracy.)
Mike
This code is better because it doesn't change the interrupt interval from the 8253 like the previous code, so that interrupt is firing back at the normal 18.2 times per second. I had it firing 64x faster before which is slightly noticeable on the machine, and also raises the chances than an interrupt will be missed. The biggest challenge was doing the math correctly without doing floating point. I'm using 32 bit integers to keep things faster than using emulated floating point, and it is slightly sloppy but it works.
I think my timing resolution is comfortably under 1ms now where before it was in the 1 to 2ms range. When the GPS 1PPS causes an interrupt I increment my own "seconds since the epoch" counter, the BIOS ticks and the 8253 counter are read and squirreled away. The interrupt gets handled, my code resumes, and it sees that the interrupt has recently fired. It then snapshots the BIOS ticks and 8253 counter again, does the math, and computes the current timestamp. This is taking on the order of 600 to 700 microseconds to do. (Screen access time is not counted; it's just the time to finish the interrupt handler, get back to the main program loop, figure out the time needs to be displayed, and then compute the current time.)
Assuming 650 microseconds and machine running at 4.77Mhz that works out to 3100 clock cycles. I actually have a V20 which is slightly better than the stock 8088 but the machine is running C code that isn't highly optimized and it's still doing integer division on the math. This doesn't seem unreasonable, and if I can knock off a few division instructions I can save a lot of clock cycles. (Shifting 10 bits right instead of dividing by 1000 would save a lot of cycles at the expense of some accuracy.)
Mike
Re: GPS project
Another project update, and some shade to throw at the PCjr ...
To recap there are two basic approaches to improve the timer resolution on a PC:
The second option makes the 8253 tick faster. You add your own interrupt handler to count the faster ticks, and every so often you call the BIOS handler to update the BIOS time. This gives you faster ticks while still keeping the BIOS/DOS time accurate. You can speed up the tick rate by 64x to get to 1ms timing accuracy. My mTCP Ping code uses this technique.
Well, that approach doesn't work great on a PCjr because even when just sitting around doing nothing, the machine loses interrupts when ticking at the faster rate. Over a 15 minute period it might only lose 100 to 200ms, and that is pretty sad. The machine is fine with a normal 55ms tick, but ticking 16x faster or more causes interrupts to be lost. And if you use the keyboard the situation is worse because the PCjr uses the non-maskable interrupt line to decode the keyboard. In contrast, my 386-40 has no problems even with a 128x faster tick rate.
So what does this mean?
I'm going with the second approach, even though timer ticks are being lost. While that is sad, it is not too much of a problem because the GPS fires an interrupt every second, so I only have to worry about how many timer ticks are lost in a second. (The 15 minute period I measured over is 900x longer than I need to worry about, which is extreme.) Running the 8253 64x faster gives 0.85ms resolution, or 1165 ticks per second. Every tick that gets lost throws away 0.85ms, but I doubt more than 2 ticks per second are getting lost. So on a PCjr I'll have to settle for times that are within 5ms of the GPS. That is acceptable for DOS. ;-0
Faster machines should not have any problems with lost interrupts. My 386-40 has been running 30 minutes and the time has not drifted by a measurable amount yet, and that is running the 8253 128x faster. (That gives it better than 0.5ms of timing resolution.)
The GPS part of the code is done. Next I need to turn it into an SNTP (Simple NTP) server. Stay tuned ...
To recap there are two basic approaches to improve the timer resolution on a PC:
- Keep the 8253 ticking at the same rate, but try to read its internal counters too.
- Speed up the 8253 timer to tick more often.
The second option makes the 8253 tick faster. You add your own interrupt handler to count the faster ticks, and every so often you call the BIOS handler to update the BIOS time. This gives you faster ticks while still keeping the BIOS/DOS time accurate. You can speed up the tick rate by 64x to get to 1ms timing accuracy. My mTCP Ping code uses this technique.
Well, that approach doesn't work great on a PCjr because even when just sitting around doing nothing, the machine loses interrupts when ticking at the faster rate. Over a 15 minute period it might only lose 100 to 200ms, and that is pretty sad. The machine is fine with a normal 55ms tick, but ticking 16x faster or more causes interrupts to be lost. And if you use the keyboard the situation is worse because the PCjr uses the non-maskable interrupt line to decode the keyboard. In contrast, my 386-40 has no problems even with a 128x faster tick rate.
So what does this mean?
I'm going with the second approach, even though timer ticks are being lost. While that is sad, it is not too much of a problem because the GPS fires an interrupt every second, so I only have to worry about how many timer ticks are lost in a second. (The 15 minute period I measured over is 900x longer than I need to worry about, which is extreme.) Running the 8253 64x faster gives 0.85ms resolution, or 1165 ticks per second. Every tick that gets lost throws away 0.85ms, but I doubt more than 2 ticks per second are getting lost. So on a PCjr I'll have to settle for times that are within 5ms of the GPS. That is acceptable for DOS. ;-0
Faster machines should not have any problems with lost interrupts. My 386-40 has been running 30 minutes and the time has not drifted by a measurable amount yet, and that is running the 8253 128x faster. (That gives it better than 0.5ms of timing resolution.)
The GPS part of the code is done. Next I need to turn it into an SNTP (Simple NTP) server. Stay tuned ...
Re: GPS project
How are you detecting that the PCjr is losing ticks just sitting idle?
You're all insane and trying to steal my magic bag!
Re: GPS project
Basically using a stopwatch ...
A 386 with the same code is solid, even when ticking 128x faster than the normal 18 times a second.
- Synchronize DOS time to GPS time. DOS time measures down to two decimal places, but the BIOS timer tick is still 55ms so DOS time can be off by as much as 0.05 seconds.
- Let the machine sit. While it is sitting it takes an interrupt from the GPS once a second and the timer interrupt hook gets hit 64 or 128 times faster than the regular timer interrupt.
- Measure the drift on the DOS time vs. the GPS time after 10 minutes. Up to 0.11 seconds is assumed normal because of the BIOS tick is 55ms. I'm seeing much more than that amount of time being lost - DOS time is slower by up to .3 or .5 seconds. (There is some variability to it.)
A 386 with the same code is solid, even when ticking 128x faster than the normal 18 times a second.
Re: GPS project
The lost time is likely due to extended time spent in an interrupt handler and/or with interrupts disabled.
The BIOS updates the value in the BDA at 40:6C; a quick look at the PCjr BIOS source doesn't show anything egregious in either 08h or 1ch, so maybe DOS is doing something stupid or costly. DOS runs in the slower 128K, so anything dumb gets amplified on a PCjr.
The BIOS updates the value in the BDA at 40:6C; a quick look at the PCjr BIOS source doesn't show anything egregious in either 08h or 1ch, so maybe DOS is doing something stupid or costly. DOS runs in the slower 128K, so anything dumb gets amplified on a PCjr.
You're all insane and trying to steal my magic bag!
Re: GPS project
I scrubbed the code pretty hard and limited the times when I disabled interrupts.
While DOS generally is resident in the first 128K of memory (which is slow), my program was active and not really doing anything that required DOS. Interrupt handling and things that touch low memory will be slow, but the machine was not primarily running from that region of memory.
When I dust off an XT I'll see if it has this problem too. It will be interesting to see if this is a "PCjr is slow" issue or "slow machines are slow" issue.
Mike
While DOS generally is resident in the first 128K of memory (which is slow), my program was active and not really doing anything that required DOS. Interrupt handling and things that touch low memory will be slow, but the machine was not primarily running from that region of memory.
When I dust off an XT I'll see if it has this problem too. It will be interesting to see if this is a "PCjr is slow" issue or "slow machines are slow" issue.
Mike