diff --git a/atusb/fw3/an/README b/atusb/fw3/an/README new file mode 100644 index 0000000..8e0d2fc --- /dev/null +++ b/atusb/fw3/an/README @@ -0,0 +1,25 @@ +workflow: + +- connect zprobe (note: it currently inverts because it didn't have any + other chips around. this may change later.) + +- capture the USB signals at an interesting moment with a sample rate of + 50 MSa/s + +- zoom into the frame(s) of interest + +- download the data with + ./get.py + +- decode with + ./dec.py + + For manual decoding, set the coders to D+ and D- (we need D- for SE0 + and SE1 detection), then click on a rising clock edge left of the + packet and move the cursor to the right. + +- if there are problems with the clock, the analog signal and digital + signals derived from it can be examined after running dec.py with + ./plot + + (Note that the digital zprobe hides any analog anomalies.) diff --git a/atusb/fw3/an/dec.py b/atusb/fw3/an/dec.py new file mode 100755 index 0000000..8534857 --- /dev/null +++ b/atusb/fw3/an/dec.py @@ -0,0 +1,127 @@ +#!/usr/bin/python + +from tmc.wave import * +from tmc.dxplore import dxplore +from tmc.decode import d_usb_stream + + +# +# Clock recovery: we assume that each change in the wave is triggered by a +# clock edge. We know the clock's nominal period and resynchronize on each +# edge. Additionally, we can obtain a list of times when a timing violation +# has occurred. +# +# Note that the timing violations logic doesn't make much sense in its present +# form, since it mainly measures noise (particularly if we're digitizing slow +# edges) and not clock drift. +# +# A more useful metric would be accumulated error from some point of reference +# or at least the timing of same edges, to eliminate (generally harmless) time +# offsets introduced by digitizing. +# +# So it would probably make more sense for "recover" not to check for timing +# violations at all, and leave this to more specialized functions. +# +def recover(self, period, min = None, max = None, t0 = None): + if t0 is None: + t0 = self.data[0] + v = not self.initial + res = [] + violations = [] + for t in self.data: + v = not v + if t <= t0: + continue + n = 0 + while t0 < t-period/2: + res.append(t0) + t0 += period + n += 1 + if min is not None: + if t0-t > n*min: + violations.append(t) + if max is not None: + if t-t0 > n*max: + violations.append(t) + t0 = t + return res, violations + + +# +# Load the analog waves saved by get.py +# +wv = waves() +wv.load("_wv") + +# +# Digitize the waves and save the result. +# +dp = wv[0].digitize(1.5, 1.8) +dm = wv[1].digitize(1.5, 1.8) +wv = waves(dp, dm, dp-dm) +wv.save("_dig") + +# +# Also record the differential signal. +# +wd = wv[1]-wv[0] +dd = wd.digitize(-0.5, 0.5) +wd.save("_diff") + +# +# Run clock recovery on D+/D-. We only need one, but check both to be sure. +# +#p = 1/1.5e6 +p = 1/12e6 +dp_t, viol = recover(dp, p, p*0.9, p*1.1) +print viol +dm_t, viol = recover(dm, p, p*.9, p*1.1, t0 = dp.data[0]) +print viol + +# +# Shift the clock by half a period, add a few periods to get steady state and +# SE0s (if any), and then sample the data lines. +# +clk = map(lambda t: t+p/2, dp_t) +clk.extend((clk[-1]+p, clk[-1]+2*p, clk[-1]+3*p)) +dp_bv = dp.get(clk) +dm_bv = dm.get(clk) + +# +# Save a wave with the recovered clock to make it easier to find the bits in +# analog graphs. +# +dd.data = dp_t; +dd.save("_clk") + +# +# For decoding, we need a fake bit clock. We generate it by doubling each data +# bit and generating a L->H transition during this bit. +# +dpd = [] +dmd = [] +dck = [] + +# err, silly, seems that we've mixed up D+ and D- all over the place :-) +print d_usb_stream(dm_bv[:], dp_bv[:]) + +for v in dp_bv: + dpd.append(v) + dpd.append(v) + dck.append(0) + dck.append(1) + +for v in dm_bv: + dmd.append(v) + dmd.append(v) + +# +# Display the reconstructed digital signal. Note that the absolute time is only +# correct at the beginning and that relative time is only accurate over +# intervals in which no significant clock resynchronization has occurred. +# +# In fact, dxplore should probably have an option to either turn off time +# entirely or to display a user-provided time axis. The latter may be a bit +# tricky to implement. +# +dxplore((dmd, dpd, dck), 0, p/2, labels = ("D+", "D-", "CLK")) diff --git a/atusb/fw3/an/get.py b/atusb/fw3/an/get.py new file mode 100755 index 0000000..685e00f --- /dev/null +++ b/atusb/fw3/an/get.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +from tmc.scope import rigol_ds1000c + +#-800, +1600 +s = rigol_ds1000c() +#s.debug = False + +pos = s.hor.pos +scale = s.hor.scale +t0 = pos-scale*s.div_hor/2 +t1 = pos+scale*s.div_hor/2 +print t0, t1 + +#zoom = 10 +#step = scale/s.samples_per_div/zoom +#print step +step = 4e-9 +step = 2e-9 + +w = s.wave((s.ch[0], s.ch[1]), start = t0, end = t1, step = step) +w[0] = 3.3-w[0] +w[1] = 3.3-w[1] + +s.hor.pos = pos +s.hor.scale = scale + +w[0].label = "D+"; +w[1].label = "D-"; + +w.save("_wv") diff --git a/atusb/fw3/an/plot b/atusb/fw3/an/plot new file mode 100755 index 0000000..1dea789 --- /dev/null +++ b/atusb/fw3/an/plot @@ -0,0 +1,12 @@ +#!/bin/sh +# +# Plot output of "dec" +# +gnuplot -persist <