From e7dbed3b02920ea4f17ba7a768e0864b5e7a0d23 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Oct 2016 19:23:45 +0800 Subject: [PATCH] gateware: KC705 satellite target --- .../gateware/targets/kc705_drtio_satellite.py | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 artiq/gateware/targets/kc705_drtio_satellite.py diff --git a/artiq/gateware/targets/kc705_drtio_satellite.py b/artiq/gateware/targets/kc705_drtio_satellite.py new file mode 100644 index 000000000..dbb4b8958 --- /dev/null +++ b/artiq/gateware/targets/kc705_drtio_satellite.py @@ -0,0 +1,163 @@ +import argparse + +from migen import * +from migen.build.platforms import kc705 + +from misoc.cores.i2c import * +from misoc.cores.sequencer import * + +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import ttl_simple +from artiq.gateware.drtio.transceiver import gtx_7series +from artiq.gateware.drtio import DRTIOSatellite + + +# TODO: program Si5324 free-run mode, with automatic switching +def get_i2c_program(sys_clk_freq): + # NOTE: the logical parameters DO NOT MAP to physical values written + # into registers. They have to be mapped; see the datasheet. + # DSPLLsim reports the logical parameters in the design summary, not + # the physical register values (but those are present separately). + N1_HS = 0 # 4 + NC1_LS = 19 # 20 + N2_HS = 1 # 5 + N2_LS = 511 # 512 + N31 = 31 # 32 + + i2c_sequence = [ + # PCA9548: select channel 7 + [(0x74 << 1), 1 << 7], + # Si5324: configure + [(0x68 << 1), 2, 0b0010 | (4 << 4)], # BWSEL=4 + [(0x68 << 1), 3, 0b0101 | 0x10], # SQ_ICAL=1 + [(0x68 << 1), 6, 0x07], # SFOUT1_REG=b111 + [(0x68 << 1), 25, (N1_HS << 5 ) & 0xff], + [(0x68 << 1), 31, (NC1_LS >> 16) & 0xff], + [(0x68 << 1), 32, (NC1_LS >> 8 ) & 0xff], + [(0x68 << 1), 33, (NC1_LS) & 0xff], + [(0x68 << 1), 40, (N2_HS << 5 ) & 0xff | + (N2_LS >> 16) & 0xff], + [(0x68 << 1), 41, (N2_LS >> 8 ) & 0xff], + [(0x68 << 1), 42, (N2_LS) & 0xff], + [(0x68 << 1), 43, (N31 >> 16) & 0xff], + [(0x68 << 1), 44, (N31 >> 8) & 0xff], + [(0x68 << 1), 45, (N31) & 0xff], + [(0x68 << 1), 137, 0x01], # FASTLOCK=1 + [(0x68 << 1), 136, 0x40], # ICAL=1 + ] + + program = [ + InstWrite(I2C_CONFIG_ADDR, int(sys_clk_freq/1e3)), + ] + for subseq in i2c_sequence: + program += [ + InstWrite(I2C_XFER_ADDR, I2C_START), + InstWait(I2C_XFER_ADDR, I2C_IDLE), + ] + for octet in subseq: + program += [ + InstWrite(I2C_XFER_ADDR, I2C_WRITE | octet), + InstWait(I2C_XFER_ADDR, I2C_IDLE), + ] + program += [ + InstWrite(I2C_XFER_ADDR, I2C_STOP), + InstWait(I2C_XFER_ADDR, I2C_IDLE), + ] + program += [ + InstEnd(), + ] + return program + + +class Si5324ResetClock(Module): + def __init__(self, platform, sys_clk_freq): + self.si5324_not_ready = Signal(reset=1) + + # minimum reset pulse 1us + reset_done = Signal() + si5324_rst_n = platform.request("si5324").rst_n + reset_val = int(sys_clk_freq*1.1e-6) + reset_ctr = Signal(max=reset_val+1, reset=reset_val) + self.sync += \ + If(reset_ctr != 0, + reset_ctr.eq(reset_ctr - 1) + ).Else( + si5324_rst_n.eq(1), + reset_done.eq(1) + ) + # 10ms after reset to microprocessor access ready + ready_val = int(sys_clk_freq*11e-3) + ready_ctr = Signal(max=ready_val+1, reset=ready_val) + self.sync += \ + If(reset_done, + If(ready_ctr != 0, + ready_ctr.eq(ready_ctr - 1) + ).Else( + self.si5324_not_ready.eq(0) + ) + ) + + si5324_clkin = platform.request("si5324_clkin") + self.specials += \ + Instance("OBUFDS", + i_I=ClockSignal("rtio_rx"), + o_O=si5324_clkin.p, o_OB=si5324_clkin.n + ) + + +class Satellite(Module): + def __init__(self, toolchain="vivado"): + self.platform = platform = kc705.Platform(toolchain=toolchain) + + rtio_channels = [] + for i in range(8): + phy = ttl_simple.Output(platform.request("user_led", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + for sma in "user_sma_gpio_p", "user_sma_gpio_n": + phy = ttl_simple.Inout(platform.request(sma)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + sys_clock_pads = platform.request("clk156") + self.clock_domains.cd_sys = ClockDomain(reset_less=True) + self.specials += Instance("IBUFGDS", + i_I=sys_clock_pads.p, i_IB=sys_clock_pads.n, + o_O=self.cd_sys.clk) + sys_clk_freq = 156000000 + + i2c_master = I2CMaster(platform.request("i2c")) + sequencer = ResetInserter()(Sequencer(get_i2c_program(sys_clk_freq))) + si5324_reset_clock = Si5324ResetClock(platform, sys_clk_freq) + self.submodules += i2c_master, sequencer, si5324_reset_clock + self.comb += [ + sequencer.bus.connect(i2c_master.bus), + sequencer.reset.eq(si5324_reset_clock.si5324_not_ready) + ] + + self.comb += platform.request("sfp_tx_disable_n").eq(1) + self.submodules.transceiver = gtx_7series.GTX_1000BASE_BX10( + clock_pads=platform.request("si5324_clkout"), + tx_pads=platform.request("sfp_tx"), + rx_pads=platform.request("sfp_rx"), + sys_clk_freq=sys_clk_freq) + self.submodules.rx_synchronizer = gtx_7series.RXSynchronizer( + self.transceiver.rtio_clk_freq) + self.submodules.drtio = DRTIOSatellite( + self.transceiver, self.rx_synchronizer, rtio_channels) + + def build(self, *args, **kwargs): + self.platform.build(self, *args, **kwargs) + + +def main(): + parser = argparse.ArgumentParser(description="KC705 DRTIO satellite") + parser.add_argument("--toolchain", default="vivado", + help="FPGA toolchain to use: ise, vivado") + args = parser.parse_args() + + top = Satellite(args.toolchain) + top.build() + +if __name__ == "__main__": + main()