On 15/06/10 16:10, Chuck Guzis wrote:
On 15 Jun 2010 at 8:39, Philip Pemberton wrote:
No -- the hardware only stores "time since
last edge". So the edges
are always one "virtual nanosecond" wide. The code extends these to
two PLL clock cycles for the DPLL counter reset, and also stores
whether there was a data pulse (transition) in the current data
window.
Okay, it was the commentary that was throwing me off. This looks
something like the code that I use.
I've done a bit of improvement on the commenting (see below) -- this
should clarify it a bit. Also, I got GCD mixed up with LCM -- you want
the greatest common divisor to set TIMER_INCREMENT, not the lowest
common multiple.
Ideally you want NSECS_PER_* to be as low as possible, and
TIMER_INCREMENT as close to 1 as possible. Pick a pair of NSECS_PER_...
values which have a common factor, then divide both by that factor and
leave TIMER_INCREMENT set to 1.
If you want speed over all else, you can increase TIMER_INCREMENT
further, which will speed up the loop at a cost of killing accuracy. You
might be able to turn the clock-error accumulators into floating point
values, but IME you usually need double-precision for that, and floating
point math tends to be slower than integer math (even on modern CPUs
with fast FPUs).
At the end of the day, it's a starting point...
/**
* This is a software implementation of Jim Thompson's Phase-Jerked Loop
* design, available from
AnalogInnovations.com as the PDF file
* "FloppyDataExtractor.pdf".
*
* This consists of:
* A data synchroniser which forces RD_DATA to be active for 2 clock cycles.
* A counter which increments constantly while the PLL is running, and is
* reset to zero when a data bit is detected.
* A flip-flop which changes state when the counter reaches half its maximum
* value
*
* The actual values of NSECS_PER_ACQ and NSECS_PER_PLLCK don't really matter.
* What actually matters is the ratio between the two -- if you have a 40MHz
* acquisition clock and a PLL clock of 16MHz (data rate 500kbps), then the
* starting values will be NSECS_PER_ACQ=25 and NSECS_PER_PLLCK=62.5. Problem
* is, 62.5 isn't an integer multiple, so we might have issues with
* short-term clock jitter. So we multiply by two, which gives us
* NSECS_PER_ACQ=50 and NSECS_PER_PLLCK=125, and a timestep of 0.5ns. Much
* better.
*
* We can also change the PJL Counter maximum value if it makes the math
* work out better. Be careful though -- reducing the value WILL reduce the
* number of available phase-shift steps and thus the PLL accuracy.
*
* Now we know the ticks-per-acqclk and ticks-per-pllclk values, we can
* figure out the optimal timer increment --
* TIMER_INCREMENT = gcd(NSECS_PER_ACQ, NSECS_PER_PLLCK)
* (gcd == greatest common divisor)
*
* Ideally we want a TIMER_INCREMENT greater than 1. If we get an increment
* of 1, then the loop has to run at 1x speed and will be SLOW. Try
* increasing NSECS_PER_ACQ and NSECS_PER_PLLCK (multiply them by the same
* number e.g. 2, 4, 8, ...), then run the gcd again. Problem is, this isn't
* going to gain much if anything in speed because you're going to be running
* more loops at a faster rate, thus it's a zero-gain :-/
*/
--
Phil.
classiccmp at philpem.me.uk
http://www.philpem.me.uk/