From b44d6517d1cbf960804c0c5c3c9f8bdf2a20d484 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 14:23:22 +0000 Subject: [PATCH] suservo: use 125 MHz SDR ADC * easier timing * natural sampling on rising edge * timing, signal robustness * adjust the servo iteration timing --- artiq/gateware/suservo/adc_ser.py | 27 +++++++++++------------ artiq/gateware/suservo/pads.py | 23 ++++++------------- artiq/gateware/suservo/servo.py | 7 +++--- artiq/gateware/test/suservo/test_adc.py | 7 +++--- artiq/gateware/test/suservo/test_servo.py | 4 ---- 5 files changed, 28 insertions(+), 40 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 865017e18..7fd33c304 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -19,9 +19,9 @@ ADCParams = namedtuple("ADCParams", [ "t_cnvh", # CNVH duration (minimum) "t_conv", # CONV duration (minimum) "t_rtt", # upper estimate for clock round trip time from - # sck at the FPGA to clkout at the FPGA. + # sck at the FPGA to clkout at the FPGA (cycles) # this avoids having synchronizers and another counter - # to signal end-of transfer (CLKOUT cycles) + # to signal end-of transfer # and it ensures fixed latency early in the pipeline ]) @@ -51,11 +51,11 @@ class ADC(Module): assert p.lanes == len(sdo) # set up counters for the four states CNVH, CONV, READ, RTT - t_read = p.width*p.channels//p.lanes//2 # DDR - assert 2*p.lanes*t_read == p.width*p.channels + t_read = p.width*p.channels//p.lanes # SDR + assert p.lanes*t_read == p.width*p.channels assert all(_ > 0 for _ in (p.t_cnvh, p.t_conv, p.t_rtt)) assert p.t_conv > 1 - count = Signal(max=max(p.t_cnvh, p.t_conv, t_read, p.t_rtt) - 1, + count = Signal(max=max(p.t_cnvh, p.t_conv - 1, t_read, p.t_rtt + 1) - 1, reset_less=True) count_load = Signal.like(count) count_done = Signal() @@ -92,7 +92,7 @@ class ADC(Module): ) fsm.act("READ", self.reading.eq(1), - count_load.eq(p.t_rtt), # account for sck ODDR delay + count_load.eq(p.t_rtt), # again account for sck ODDR delay pads.sck_en.eq(1), If(count_done, NextState("RTT") @@ -113,21 +113,20 @@ class ADC(Module): self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) self.comb += [ # falling clkout makes two bits available - self.cd_ret.clk.eq(~pads.clkout) + self.cd_ret.clk.eq(pads.clkout) ] k = p.channels//p.lanes - assert 2*t_read == k*p.width + assert t_read == k*p.width for i, sdo in enumerate(sdo): - sdo_sr0 = Signal(t_read - 1) - sdo_sr1 = Signal(t_read - 1) + sdo_sr = Signal(2*t_read) self.sync.ret += [ If(self.reading & sck_en_ret, - sdo_sr0.eq(Cat(sdo[0], sdo_sr0)), - sdo_sr1.eq(Cat(sdo[1], sdo_sr1)) + sdo_sr[1:].eq(sdo_sr), + sdo_sr[0].eq(sdo), ) ] self.comb += [ - Cat(reversed([self.data[i*k + j] for j in range(k)])).eq( - Cat(sdo, zip(sdo_sr0, sdo_sr1))) + Cat(reversed([self.data[i*k + j] for j in range(k)]) + ).eq(sdo_sr) ] diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index 91dfb3783..a57655c2f 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -22,7 +22,7 @@ class SamplerPads(Module): self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), - DDROutput(0, self.sck_en, sck), + DDROutput(self.sck_en, 0, sck), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), Instance( @@ -43,8 +43,7 @@ class SamplerPads(Module): # platform.add_period_constraint(sampler_pads.clkout_p, 8.) for i in "abcd": sdo_se = Signal() - sdo_d = Signal() - sdo = Signal(2) + sdo = Signal() setattr(self, "sdo{}".format(i), sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) @@ -53,24 +52,16 @@ class SamplerPads(Module): Instance( "IDELAYE2", p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", - p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=31, + p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=15, p_REFCLK_FREQUENCY=200., - i_IDATAIN=sdo_se, o_DATAOUT=sdo_d), - Instance("IDDR", - p_DDR_CLK_EDGE="SAME_EDGE", - i_C=~self.clkout, i_CE=1, i_S=0, i_R=0, - i_D=sdo_d, o_Q1=sdo[0], o_Q2=sdo[1]) # sdo[1] older + i_IDATAIN=sdo_se, o_DATAOUT=sdo), ] - # 4, -0+1.5 hold (t_HSDO_DDR), -0.2+0.2 skew + # 8, -0+1.5 hold (t_HSDO_DDR), -0.5+0.5 skew platform.add_platform_command( "set_input_delay -clock {clk} " - "-max 1.6 [get_ports {port}]\n" + "-max 2 [get_ports {port}] -clock_fall\n" "set_input_delay -clock {clk} " - "-min -0.1 [get_ports {port}]\n" - "set_input_delay -clock {clk} " - "-max 1.6 [get_ports {port}] -clock_fall -add_delay\n" - "set_input_delay -clock {clk} " - "-min -0.1 [get_ports {port}] -clock_fall -add_delay", + "-min -0.5 [get_ports {port}] -clock_fall", clk=dp.clkout, port=sdop) diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index 31491429a..c40e7c318 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -16,14 +16,15 @@ class Servo(Module): self.comb += j.eq(i), l.eq(k) t_adc = (adc_p.t_cnvh + adc_p.t_conv + adc_p.t_rtt + - adc_p.channels*adc_p.width//2//adc_p.lanes) + 1 + adc_p.channels*adc_p.width//adc_p.lanes) + 1 t_iir = ((1 + 4 + 1) << iir_p.channel) + 1 t_dds = (dds_p.width*2 + 1)*dds_p.clk + 1 + t_cycle = max(t_adc, t_iir, t_dds) assert t_iir + (2 << iir_p.channel) < t_cycle, "need shifting time" self.start = Signal() - t_restart = t_cycle - t_iir - t_adc + t_restart = t_cycle - t_adc assert t_restart > 0 cnt = Signal(max=t_restart) cnt_done = Signal() @@ -39,7 +40,7 @@ class Servo(Module): self.done.eq(self.dds.done), ] self.sync += [ - If(iir_done & ~cnt_done & ~token[0], + If(self.adc.done & ~cnt_done, cnt.eq(cnt - 1), ), If(self.adc.start, diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py index 6f74c19ea..c561dbd51 100644 --- a/artiq/gateware/test/suservo/test_adc.py +++ b/artiq/gateware/test/suservo/test_adc.py @@ -31,15 +31,15 @@ class TB(Module): srs = [] for i in range(p.lanes): name = "sdo" + string.ascii_lowercase[i] - sdo = Signal(2, name=name, reset_less=True) + sdo = Signal(name=name, reset_less=True) self.sdo.append(sdo) setattr(self, name, sdo) sr = Signal(p.width*p.channels//p.lanes, reset_less=True) srs.append(sr) self.sync.adc += [ - sdo.eq(Cat(self._dly(sr[-1], 3), self._dly(sr[-2], 3))), + sdo.eq(self._dly(sr[-1], -1)), If(adc_sck_en, - sr[2:].eq(sr) + sr[1:].eq(sr) ) ] cnv_old = Signal(reset_less=True) @@ -54,6 +54,7 @@ class TB(Module): self.comb += [ adc_sck_en.eq(self._dly(self.sck_en, 1)), self.sck_en_ret.eq(self._dly(adc_sck_en)), + adc_clk_rec.eq(self._dly(self.sck, 1)), self.clkout.eq(self._dly(adc_clk_rec)), ] diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index c8b43349e..8d0443ef8 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -93,10 +93,6 @@ def main(): "adc": (8, 0), "ret": (8, 0), "async": (2, 0), - }, - special_overrides={ - io.DDROutput: test_adc.DDROutput, - io.DDRInput: test_adc.DDRInput })