From aebbaa339ee5bd3fbe62c1870297fdb16e479467 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 23 Mar 2017 20:40:41 +0100 Subject: [PATCH 01/17] pdq2: config writes --- artiq/coredevice/pdq2.py | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 artiq/coredevice/pdq2.py diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py new file mode 100644 index 000000000..d0452e868 --- /dev/null +++ b/artiq/coredevice/pdq2.py @@ -0,0 +1,70 @@ +from artiq.language.core import (kernel, portable, delay_mu, delay) +from artiq.language.units import ns, us +from artiq.coredevice import spi + + +_PDQ2_SPI_CONFIG = ( + 0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX + ) + + +@portable +def _PDQ2_CMD(board, is_mem, adr, we): + return (adr << 0) | (is_mem << 2) | (board << 3) | (we << 7) + + +_PDQ2_ADR_CONFIG = 0 +_PDQ2_ADR_CRC = 1 +_PDQ2_ADR_FRAME = 2 + + +class PDQ2: + """ + + :param spi_device: Name of the SPI bus this device is on. + :param chip_select: Value to drive on the chip select lines + during transactions. + """ + + def __init__(self, dmgr, spi_device, chip_select=1): + self.core = dmgr.get("core") + self.bus = dmgr.get(spi_device) + self.chip_select = chip_select + + @kernel + def setup_bus(self, write_div=4, read_div=15): + """Configure the SPI bus and the SPI transaction parameters + for this device. This method has to be called before any other method + if the bus has been used to access a different device in the meantime. + + This method advances the timeline by the duration of two + RTIO-to-Wishbone bus transactions. + + :param write_div: Write clock divider. + :param read_div: Read clock divider. + """ + # write: 4*8ns >= 20ns = 2*clk (clock de-glitching 50MHz) + # read: 15*8*ns >= ~100ns = 5*clk (clk de-glitching latency + miso + # latency) + self.bus.set_config_mu(_PDQ2_SPI_CONFIG, write_div, read_div) + self.bus.set_xfer(self.chip_select, 16, 0) + + @kernel + def write(self, data): + """Write 16 bits of data. + + This method advances the timeline by the duration of the SPI transfer + and the required CS high time. + """ + self.bus.write(data << 16) + delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high + + @kernel + def write_config(self, config, board=0xf): + board &= 0xf + self.write( + (_PDQ2_CMD(board, 0, _PDQ2_ADR_CONFIG, 1) << 24) | + (config << 16) + ) From 1ce1b7cd710f28cc6f89a73810dfe5ca280936f7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 25 Mar 2017 21:16:22 +0100 Subject: [PATCH 02/17] doc: pdq2 spi backend --- doc/manual/core_drivers_reference.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 6def86ae8..09d9e8088 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -68,3 +68,9 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.sawg :members: + +:mod:`artiq.coredevice.pdq2` module +----------------------------------- + +.. automodule:: artiq.coredevice.pdq2 + :members: From b9c61ae2dae94350cd208e0b17050fd8b4ed6dc6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Mar 2017 11:41:39 +0200 Subject: [PATCH 03/17] pdq2: crc/frame register accessors --- artiq/coredevice/pdq2.py | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index d0452e868..737e60fe7 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -61,10 +61,46 @@ class PDQ2: self.bus.write(data << 16) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high + @kernel + def write_reg(self, adr, data, board): + self.write((_PDQ2_CMD(board, 0, adr, 1) << 24) | (data << 16)) + + @kernel + def read_reg(self, adr, board): + self.bus.set_xfer(self.chip_select, 16, 8) + self.write(_PDQ2_CMD(board, 0, adr, 0) << 24) + self.bus.read_async() + self.bus.set_xfer(self.chip_select, 16, 0) + return self.bus.input_async() & 0xff + @kernel def write_config(self, config, board=0xf): - board &= 0xf - self.write( - (_PDQ2_CMD(board, 0, _PDQ2_ADR_CONFIG, 1) << 24) | - (config << 16) - ) + self.write_reg(_PDQ2_ADR_CONFIG, config, board) + + @kernel + def read_config(self, board=0xf): + return self.read_reg(_PDQ2_ADR_CONFIG, board) + + @kernel + def write_crc(self, crc, board=0xf): + self.write_reg(_PDQ2_ADR_CRC, crc, board) + + @kernel + def read_crc(self, board=0xf): + return self.read_reg(_PDQ2_ADR_CRC, board) + + @kernel + def write_frame(self, frame, board=0xf): + self.write_reg(_PDQ2_ADR_FRAME, frame, board) + + @kernel + def read_frame(self, board=0xf): + return self.read_reg(_PDQ2_ADR_FRAME, board) + + @kernel + def write_mem(self, mem, adr, data, board=0xf): + pass + + @kernel + def read_mem(self, mem, adr, data, board=0xf): + pass From f13f6eb7be1921cb105d8a63e3f9e3429c8aaeda Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 13:50:17 +0200 Subject: [PATCH 04/17] pdq2: memory write --- artiq/coredevice/pdq2.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index 737e60fe7..4e7441d9a 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -51,24 +51,16 @@ class PDQ2: self.bus.set_config_mu(_PDQ2_SPI_CONFIG, write_div, read_div) self.bus.set_xfer(self.chip_select, 16, 0) - @kernel - def write(self, data): - """Write 16 bits of data. - - This method advances the timeline by the duration of the SPI transfer - and the required CS high time. - """ - self.bus.write(data << 16) - delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high - @kernel def write_reg(self, adr, data, board): - self.write((_PDQ2_CMD(board, 0, adr, 1) << 24) | (data << 16)) + self.bus.write((_PDQ2_CMD(board, 0, adr, 1) << 24) | (data << 16)) + delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high @kernel def read_reg(self, adr, board): self.bus.set_xfer(self.chip_select, 16, 8) - self.write(_PDQ2_CMD(board, 0, adr, 0) << 24) + self.bus.write(_PDQ2_CMD(board, 0, adr, 0) << 24) + delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high self.bus.read_async() self.bus.set_xfer(self.chip_select, 16, 0) return self.bus.input_async() & 0xff @@ -99,7 +91,17 @@ class PDQ2: @kernel def write_mem(self, mem, adr, data, board=0xf): - pass + self.bus.set_xfer(self.chip_select, 24, 0) + self.bus.write((_PDQ2_CMD(board, 1, mem, 1) << 24) | + ((adr & 0x00ff) << 16) | (adr & 0xff00)) + delay_mu(3*self.bus.ref_period_mu - self.bus.xfer_period_mu - + self.bus.write_period_mu) + self.bus.set_xfer(self.chip_select, 16, 0) + for i in len(data)//2: + self.bus.write((data[2*i] << 24) | (data[2*i + 1] << 16)) + delay_mu(-self.bus.write_period_mu) + delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu) + # get to 20ns min cs high @kernel def read_mem(self, mem, adr, data, board=0xf): From 2c7c6143ab8c9e34507d3db610a27fc95defd067 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 14:07:32 +0200 Subject: [PATCH 05/17] sma_spi: add demo target with SPI on four SMA --- artiq/gateware/targets/kc705_sma_spi.py | 80 +++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 artiq/gateware/targets/kc705_sma_spi.py diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py new file mode 100644 index 000000000..fbf26e78d --- /dev/null +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +import argparse + +from migen import * + +from migen.build.generic_platform import * +from misoc.targets.kc705 import soc_kc705_args, soc_kc705_argdict +from misoc.integration.builder import builder_args, builder_argdict + +from artiq.gateware.amp import build_artiq_soc +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import ttl_simple, spi + + +from .kc705_dds import _NIST_Ions + + +_sma_spi = [ + ("sma_spi", 0, + Subsignal("clk", Pins("Y23")), # user_sma_gpio_p + Subsignal("cs_n", Pins("Y24")), # user_sma_gpio_n + Subsignal("mosi", Pins("L25")), # user_sma_clk_p + Subsignal("miso", Pins("K25")), # user_sma_clk_n + IOStandard("LVCMOS33")), +] + + +class SMA_SPI(_NIST_Ions): + """ + SPI on 4 SMA for PDQ2 test/demo. + """ + def __init__(self, cpu_type="or1k", **kwargs): + _NIST_Ions.__init__(self, cpu_type, **kwargs) + + platform = self.platform + self.platform.add_extension(_sma_spi) + + rtio_channels = [] + + phy = ttl_simple.Output(platform.request("user_led", 2)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + ams101_dac = self.platform.request("ams101_dac", 0) + phy = ttl_simple.Output(ams101_dac.ldac) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = spi.SPIMaster(ams101_dac) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy( + phy, ofifo_depth=4, ififo_depth=4)) + + phy = spi.SPIMaster(self.platform.request("sma_spi")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy( + phy, ofifo_depth=128, ififo_depth=128)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + +def main(): + parser = argparse.ArgumentParser( + description="ARTIQ device binary builder / " + "KC705 SMA SPI demo/test for PDQ2") + builder_args(parser) + soc_kc705_args(parser) + args = parser.parse_args() + + soc = SMA_SPI(**soc_kc705_argdict(args)) + build_artiq_soc(soc, builder_argdict(args)) + + +if __name__ == "__main__": + main() From 555b3c38c15976bdbb1b838febe4b4e8619d1e1f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 14:42:41 +0200 Subject: [PATCH 06/17] sma_spi: free up user_sma pins --- artiq/gateware/targets/kc705_sma_spi.py | 78 +++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index fbf26e78d..818a5c4a2 100644 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -5,8 +5,11 @@ import argparse from migen import * from migen.build.generic_platform import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from misoc.targets.kc705 import soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict +from misoc.interconnect.csr import * from artiq.gateware.amp import build_artiq_soc from artiq.gateware import rtio @@ -16,6 +19,56 @@ from artiq.gateware.rtio.phy import ttl_simple, spi from .kc705_dds import _NIST_Ions +class _RTIOCRG(Module, AutoCSR): + def __init__(self, platform, rtio_internal_clk): + self._clock_sel = CSRStorage() + self._pll_reset = CSRStorage(reset=1) + self._pll_locked = CSRStatus() + self.clock_domains.cd_rtio = ClockDomain() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + # 10 MHz when using 125MHz input + self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) + + rtio_external_clk = Signal() + + pll_locked = Signal() + rtio_clk = Signal() + rtiox4_clk = Signal() + ext_clkout_clk = Signal() + self.specials += [ + Instance("PLLE2_ADV", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + p_REF_JITTER1=0.01, + p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, + # Warning: CLKINSEL=0 means CLKIN2 is selected + i_CLKINSEL=~self._clock_sel.storage, + + # VCO @ 1GHz when using 125MHz input + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + i_CLKFBIN=self.cd_rtio.clk, + i_RST=self._pll_reset.storage, + + o_CLKFBOUT=rtio_clk, + + p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=rtiox4_clk, + + p_CLKOUT1_DIVIDE=50, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=ext_clkout_clk), + Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk), + + AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), + MultiReg(pll_locked, self._pll_locked.status) + ] + + + + _sma_spi = [ ("sma_spi", 0, Subsignal("clk", Pins("Y23")), # user_sma_gpio_p @@ -63,6 +116,31 @@ class SMA_SPI(_NIST_Ions): self.add_rtio(rtio_channels) + def add_rtio(self, rtio_channels): + self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) + self.csr_devices.append("rtio_crg") + self.submodules.rtio_core = rtio.Core(rtio_channels) + self.csr_devices.append("rtio_core") + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = rtio.DMA(self.get_native_sdram_if()) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri]) + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.rtio_crg.cd_rtio.clk.attr.add("keep") + self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) + self.platform.add_false_path_constraints( + self.crg.cd_sys.clk, + self.rtio_crg.cd_rtio.clk) + + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.get_native_sdram_if()) + self.csr_devices.append("rtio_analyzer") + def main(): parser = argparse.ArgumentParser( From 0838981bed97c0b7bd137771c29814817cf0a933 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 23:45:46 +0200 Subject: [PATCH 07/17] coredevice.spi: kernel invariants and style --- artiq/coredevice/spi.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index 65943533f..69e80ab54 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -56,9 +56,14 @@ class SPIMaster: :param channel: RTIO channel number of the SPI bus to control. """ + + kernel_invariants = {"core", "ref_period_mu", "channel"} + def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) - self.ref_period_mu = self.core.seconds_to_mu(self.core.coarse_ref_period) + self.ref_period_mu = self.core.seconds_to_mu( + self.core.coarse_ref_period) + assert self.ref_period_mu == self.core.ref_multiplier self.channel = channel self.write_period_mu = numpy.int64(0) self.read_period_mu = numpy.int64(0) From 1e6e81a19e5b6bffa35af20a50f3323edcb06078 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 23:47:58 +0200 Subject: [PATCH 08/17] sma_spi: LVCMOS25 --- artiq/gateware/targets/kc705_sma_spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index 818a5c4a2..cbdf74a52 100644 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -75,7 +75,7 @@ _sma_spi = [ Subsignal("cs_n", Pins("Y24")), # user_sma_gpio_n Subsignal("mosi", Pins("L25")), # user_sma_clk_p Subsignal("miso", Pins("K25")), # user_sma_clk_n - IOStandard("LVCMOS33")), + IOStandard("LVCMOS25")), ] From 16b7f8f50c8a65b8a70e383589710a97c44e0563 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Apr 2017 23:57:08 +0200 Subject: [PATCH 09/17] sma_spi: cri/cd changes --- artiq/gateware/targets/kc705_sma_spi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index cbdf74a52..2ca47ccce 100644 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -67,8 +67,6 @@ class _RTIOCRG(Module, AutoCSR): ] - - _sma_spi = [ ("sma_spi", 0, Subsignal("clk", Pins("Y23")), # user_sma_gpio_p @@ -122,12 +120,14 @@ class SMA_SPI(_NIST_Ions): self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() - self.submodules.rtio_dma = rtio.DMA(self.get_native_sdram_if()) + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], [self.rtio_core.cri]) + self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From 78dd4b861425b8c9683b773a40e0a35590626ec9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 8 Apr 2017 10:38:32 +0200 Subject: [PATCH 10/17] pdq2: memory write, kernel_invariants --- artiq/coredevice/pdq2.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index 4e7441d9a..4fed5076e 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -1,5 +1,4 @@ -from artiq.language.core import (kernel, portable, delay_mu, delay) -from artiq.language.units import ns, us +from artiq.language.core import kernel, portable, delay_mu from artiq.coredevice import spi @@ -28,6 +27,8 @@ class PDQ2: during transactions. """ + kernel_invariants = {"core", "chip_select", "bus"} + def __init__(self, dmgr, spi_device, chip_select=1): self.core = dmgr.get("core") self.bus = dmgr.get(spi_device) @@ -66,7 +67,10 @@ class PDQ2: return self.bus.input_async() & 0xff @kernel - def write_config(self, config, board=0xf): + def write_config(self, reset=0, clk2x=0, enable=1, + trigger=0, aux_miso=0, aux_dac=0b111, board=0xf): + config = ((reset << 0) | (clk2x << 1) | (enable << 2) | + (trigger << 3) | (aux_miso << 4) | (aux_dac << 5)) self.write_reg(_PDQ2_ADR_CONFIG, config, board) @kernel @@ -97,7 +101,7 @@ class PDQ2: delay_mu(3*self.bus.ref_period_mu - self.bus.xfer_period_mu - self.bus.write_period_mu) self.bus.set_xfer(self.chip_select, 16, 0) - for i in len(data)//2: + for i in range(len(data)//2): self.bus.write((data[2*i] << 24) | (data[2*i + 1] << 16)) delay_mu(-self.bus.write_period_mu) delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu) From ed8edf318d5f7e0f95c5ed69d192897f7b9c4bf0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 8 Apr 2017 17:19:35 +0200 Subject: [PATCH 11/17] sma_spi: undo cri_con --- artiq/gateware/targets/kc705_sma_spi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index 2ca47ccce..cea74c574 100644 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -127,7 +127,6 @@ class SMA_SPI(_NIST_Ions): self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], [self.rtio_core.cri]) - self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From 20652ce128af4b1088a0eddd6ecdb2d85808389e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 9 Apr 2017 13:50:19 +0200 Subject: [PATCH 12/17] pdq2: align subsequent writes to end --- artiq/coredevice/pdq2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index 4fed5076e..5410e7d2f 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -98,8 +98,7 @@ class PDQ2: self.bus.set_xfer(self.chip_select, 24, 0) self.bus.write((_PDQ2_CMD(board, 1, mem, 1) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) - delay_mu(3*self.bus.ref_period_mu - self.bus.xfer_period_mu - - self.bus.write_period_mu) + delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) self.bus.set_xfer(self.chip_select, 16, 0) for i in range(len(data)//2): self.bus.write((data[2*i] << 24) | (data[2*i + 1] << 16)) From 8446cccb4eb0ff139ae1fc9366e9d13b96e8dd1a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Apr 2017 13:38:13 +0200 Subject: [PATCH 13/17] pdq2: mem_read --- artiq/coredevice/pdq2.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index 5410e7d2f..18ff1c773 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -35,7 +35,7 @@ class PDQ2: self.chip_select = chip_select @kernel - def setup_bus(self, write_div=4, read_div=15): + def setup_bus(self, write_div=24, read_div=64): """Configure the SPI bus and the SPI transaction parameters for this device. This method has to be called before any other method if the bus has been used to access a different device in the meantime. @@ -64,7 +64,7 @@ class PDQ2: delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high self.bus.read_async() self.bus.set_xfer(self.chip_select, 16, 0) - return self.bus.input_async() & 0xff + return int(self.bus.input_async() & 0xff) # FIXME: m-labs/artiq#713 @kernel def write_config(self, reset=0, clk2x=0, enable=1, @@ -94,7 +94,7 @@ class PDQ2: return self.read_reg(_PDQ2_ADR_FRAME, board) @kernel - def write_mem(self, mem, adr, data, board=0xf): + def write_mem(self, mem, adr, data, board=0xf): # FIXME: m-labs/artiq#714 self.bus.set_xfer(self.chip_select, 24, 0) self.bus.write((_PDQ2_CMD(board, 1, mem, 1) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) @@ -108,4 +108,21 @@ class PDQ2: @kernel def read_mem(self, mem, adr, data, board=0xf): - pass + self.bus.set_xfer(self.chip_select, 24, 8) + self.bus.write((_PDQ2_CMD(board, 1, mem, 0) << 24) | + ((adr & 0x00ff) << 16) | (adr & 0xff00)) + delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) + self.bus.set_xfer(self.chip_select, 0, 16) + for i in range(len(data)//2): + self.bus.write(0) + delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) + self.bus.read_async() + d = self.bus.input_async() + data[2*i] = (d >> 8) & 0xff + data[2*i + 1] = d & 0xff + return int(self.bus.input_async() & 0xff) # FIXME: m-labs/artiq#713 + delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu) + # get to 20ns min cs high + self.bus.set_xfer(self.chip_select, 16, 0) + + pass From 90cf11994e8d682e8df4d41aae655b5de5997abb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Apr 2017 13:38:29 +0200 Subject: [PATCH 14/17] spi: style --- artiq/coredevice/spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index 69e80ab54..6c4b3e7ea 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -1,6 +1,6 @@ import numpy -from artiq.language.core import (kernel, portable, now_mu, delay_mu) +from artiq.language.core import kernel, portable, now_mu, delay_mu from artiq.language.units import MHz from artiq.coredevice.rtio import rtio_output, rtio_input_data From 534e681d0b9e1bdd1147574a8439fba4ac59afa2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Apr 2017 20:49:46 +0200 Subject: [PATCH 15/17] pdq2: use 16 bit data, buffered read_mem() --- artiq/coredevice/pdq2.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq2.py index 18ff1c773..a4d35d04a 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq2.py @@ -100,29 +100,32 @@ class PDQ2: ((adr & 0x00ff) << 16) | (adr & 0xff00)) delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) self.bus.set_xfer(self.chip_select, 16, 0) - for i in range(len(data)//2): - self.bus.write((data[2*i] << 24) | (data[2*i + 1] << 16)) + for i in data: + self.bus.write(i << 16) delay_mu(-self.bus.write_period_mu) delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu) # get to 20ns min cs high @kernel - def read_mem(self, mem, adr, data, board=0xf): + def read_mem(self, mem, adr, data, board=0xf, buffer=8): + n = len(data) + if not n: + return self.bus.set_xfer(self.chip_select, 24, 8) self.bus.write((_PDQ2_CMD(board, 1, mem, 0) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) self.bus.set_xfer(self.chip_select, 0, 16) - for i in range(len(data)//2): + for i in range(n): self.bus.write(0) - delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) - self.bus.read_async() - d = self.bus.input_async() - data[2*i] = (d >> 8) & 0xff - data[2*i + 1] = d & 0xff - return int(self.bus.input_async() & 0xff) # FIXME: m-labs/artiq#713 - delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu) - # get to 20ns min cs high + delay_mu(-self.bus.write_period_mu) + if i > 0: + delay_mu(-3*self.bus.ref_period_mu) + self.bus.read_async() + if i > buffer: + data[i - 1 - buffer] = self.bus.input_async() & 0xffff + delay_mu(self.bus.write_period_mu) self.bus.set_xfer(self.chip_select, 16, 0) - - pass + self.bus.read_async() + for i in range(max(0, n - buffer - 1), n): + data[i] = self.bus.input_async() & 0xffff From 1a1edb13bf7fa25fa41f659a384c4708d3faa294 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 May 2017 18:05:41 +0200 Subject: [PATCH 16/17] pdq2 -> pdq --- artiq/coredevice/{pdq2.py => pdq.py} | 34 +++++++++++++-------------- doc/manual/core_drivers_reference.rst | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) rename artiq/coredevice/{pdq2.py => pdq.py} (83%) diff --git a/artiq/coredevice/pdq2.py b/artiq/coredevice/pdq.py similarity index 83% rename from artiq/coredevice/pdq2.py rename to artiq/coredevice/pdq.py index a4d35d04a..e7acd36aa 100644 --- a/artiq/coredevice/pdq2.py +++ b/artiq/coredevice/pdq.py @@ -2,7 +2,7 @@ from artiq.language.core import kernel, portable, delay_mu from artiq.coredevice import spi -_PDQ2_SPI_CONFIG = ( +_PDQ_SPI_CONFIG = ( 0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX @@ -10,16 +10,16 @@ _PDQ2_SPI_CONFIG = ( @portable -def _PDQ2_CMD(board, is_mem, adr, we): +def _PDQ_CMD(board, is_mem, adr, we): return (adr << 0) | (is_mem << 2) | (board << 3) | (we << 7) -_PDQ2_ADR_CONFIG = 0 -_PDQ2_ADR_CRC = 1 -_PDQ2_ADR_FRAME = 2 +_PDQ_ADR_CONFIG = 0 +_PDQ_ADR_CRC = 1 +_PDQ_ADR_FRAME = 2 -class PDQ2: +class PDQ: """ :param spi_device: Name of the SPI bus this device is on. @@ -49,18 +49,18 @@ class PDQ2: # write: 4*8ns >= 20ns = 2*clk (clock de-glitching 50MHz) # read: 15*8*ns >= ~100ns = 5*clk (clk de-glitching latency + miso # latency) - self.bus.set_config_mu(_PDQ2_SPI_CONFIG, write_div, read_div) + self.bus.set_config_mu(_PDQ_SPI_CONFIG, write_div, read_div) self.bus.set_xfer(self.chip_select, 16, 0) @kernel def write_reg(self, adr, data, board): - self.bus.write((_PDQ2_CMD(board, 0, adr, 1) << 24) | (data << 16)) + self.bus.write((_PDQ_CMD(board, 0, adr, 1) << 24) | (data << 16)) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high @kernel def read_reg(self, adr, board): self.bus.set_xfer(self.chip_select, 16, 8) - self.bus.write(_PDQ2_CMD(board, 0, adr, 0) << 24) + self.bus.write(_PDQ_CMD(board, 0, adr, 0) << 24) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high self.bus.read_async() self.bus.set_xfer(self.chip_select, 16, 0) @@ -71,32 +71,32 @@ class PDQ2: trigger=0, aux_miso=0, aux_dac=0b111, board=0xf): config = ((reset << 0) | (clk2x << 1) | (enable << 2) | (trigger << 3) | (aux_miso << 4) | (aux_dac << 5)) - self.write_reg(_PDQ2_ADR_CONFIG, config, board) + self.write_reg(_PDQ_ADR_CONFIG, config, board) @kernel def read_config(self, board=0xf): - return self.read_reg(_PDQ2_ADR_CONFIG, board) + return self.read_reg(_PDQ_ADR_CONFIG, board) @kernel def write_crc(self, crc, board=0xf): - self.write_reg(_PDQ2_ADR_CRC, crc, board) + self.write_reg(_PDQ_ADR_CRC, crc, board) @kernel def read_crc(self, board=0xf): - return self.read_reg(_PDQ2_ADR_CRC, board) + return self.read_reg(_PDQ_ADR_CRC, board) @kernel def write_frame(self, frame, board=0xf): - self.write_reg(_PDQ2_ADR_FRAME, frame, board) + self.write_reg(_PDQ_ADR_FRAME, frame, board) @kernel def read_frame(self, board=0xf): - return self.read_reg(_PDQ2_ADR_FRAME, board) + return self.read_reg(_PDQ_ADR_FRAME, board) @kernel def write_mem(self, mem, adr, data, board=0xf): # FIXME: m-labs/artiq#714 self.bus.set_xfer(self.chip_select, 24, 0) - self.bus.write((_PDQ2_CMD(board, 1, mem, 1) << 24) | + self.bus.write((_PDQ_CMD(board, 1, mem, 1) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) self.bus.set_xfer(self.chip_select, 16, 0) @@ -112,7 +112,7 @@ class PDQ2: if not n: return self.bus.set_xfer(self.chip_select, 24, 8) - self.bus.write((_PDQ2_CMD(board, 1, mem, 0) << 24) | + self.bus.write((_PDQ_CMD(board, 1, mem, 0) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu) self.bus.set_xfer(self.chip_select, 0, 16) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 09d9e8088..bbd0e39c6 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -69,8 +69,8 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.sawg :members: -:mod:`artiq.coredevice.pdq2` module +:mod:`artiq.coredevice.pdq` module ----------------------------------- -.. automodule:: artiq.coredevice.pdq2 +.. automodule:: artiq.coredevice.pdq :members: From fed24309b8fa785bf6b36f5ed66a05df12fe4831 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 May 2017 18:55:02 +0200 Subject: [PATCH 17/17] pdq: documentation --- artiq/coredevice/pdq.py | 76 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/pdq.py b/artiq/coredevice/pdq.py index e7acd36aa..b5ea70648 100644 --- a/artiq/coredevice/pdq.py +++ b/artiq/coredevice/pdq.py @@ -11,6 +11,16 @@ _PDQ_SPI_CONFIG = ( @portable def _PDQ_CMD(board, is_mem, adr, we): + """Pack PDQ command fields into command byte. + + :param board: Board address, 0 to 15, with ``15 = 0xf`` denoting broadcast + to all boards connected. + :param is_mem: If ``1``, ``adr`` denote the address of the memory to access + (0 to 2). Otherwise ``adr`` denotes the register to access. + :param adr: Address of the register or memory to access. + (``_PDQ_ADR_CONFIG``, ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``). + :param we: If ``1`` then write, otherwise read. + """ return (adr << 0) | (is_mem << 2) | (board << 3) | (we << 7) @@ -20,11 +30,22 @@ _PDQ_ADR_FRAME = 2 class PDQ: - """ + """PDQ smart arbitrary waveform generator stack. + + Provides access to a stack of PDQ boards connected via SPI using PDQ + gateware version 3 or later. + + The SPI bus is wired with ``CS_N`` from the core device connected to + ``F2 IN`` on the master PDQ, ``CLK`` connected to ``F3 IN``, ``MOSI`` + connected to ``F4 IN`` and ``MISO`` (optionally) connected to ``F5 OUT``. + ``F1 TTL Input Trigger`` remains as waveform trigger input. + Due to hardware constraints, there can only be one board connected to the + core device's MISO line and therefore there can only be SPI readback + from one board at any time. :param spi_device: Name of the SPI bus this device is on. - :param chip_select: Value to drive on the chip select lines - during transactions. + :param chip_select: Value to drive on the chip select lines of the SPI bus + during transactions. """ kernel_invariants = {"core", "chip_select", "bus"} @@ -54,11 +75,26 @@ class PDQ: @kernel def write_reg(self, adr, data, board): + """Set a PDQ register. + + :param adr: Address of the register (``_PDQ_ADR_CONFIG``, + ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``). + :param data: Register data (8 bit). + :param board: Board to access, ``0xf`` to write to all boards. + """ self.bus.write((_PDQ_CMD(board, 0, adr, 1) << 24) | (data << 16)) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high @kernel def read_reg(self, adr, board): + """Get a PDQ register. + + :param adr: Address of the register (``_PDQ_ADR_CONFIG``, + ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``). + :param board: Board to access, ``0xf`` to write to all boards. + + :return: Register data (8 bit). + """ self.bus.set_xfer(self.chip_select, 16, 8) self.bus.write(_PDQ_CMD(board, 0, adr, 0) << 24) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high @@ -69,32 +105,58 @@ class PDQ: @kernel def write_config(self, reset=0, clk2x=0, enable=1, trigger=0, aux_miso=0, aux_dac=0b111, board=0xf): + """Set configuration register. + + :param reset: Reset board (auto-clear). + :param clk2x: Enable clock double (100 MHz). + :param enable: Enable the reading and execution of waveform data from + memory. + :param trigger: Software trigger, logical OR with ``F1 TTL Input + Trigger``. + :param aux_miso: Use ``F5 OUT`` for ``MISO``. If ``0``, use the + masked logical OR of the DAC channels. + :param aux_dac: DAC channel mask to for AUX (``F5 OUT``) output. + :param board: Boards to address, ``0xf`` to write to all boards. + """ config = ((reset << 0) | (clk2x << 1) | (enable << 2) | (trigger << 3) | (aux_miso << 4) | (aux_dac << 5)) self.write_reg(_PDQ_ADR_CONFIG, config, board) @kernel def read_config(self, board=0xf): + """Read configuration register.""" return self.read_reg(_PDQ_ADR_CONFIG, board) @kernel def write_crc(self, crc, board=0xf): + """Write checksum register.""" self.write_reg(_PDQ_ADR_CRC, crc, board) @kernel def read_crc(self, board=0xf): + """Read checksum register.""" return self.read_reg(_PDQ_ADR_CRC, board) @kernel def write_frame(self, frame, board=0xf): + """Write frame selection register.""" self.write_reg(_PDQ_ADR_FRAME, frame, board) @kernel def read_frame(self, board=0xf): + """Read frame selection register.""" return self.read_reg(_PDQ_ADR_FRAME, board) @kernel def write_mem(self, mem, adr, data, board=0xf): # FIXME: m-labs/artiq#714 + """Write to DAC channel waveform data memory. + + :param mem: DAC channel memory to access (0 to 2). + :param adr: Start address. + :param data: Memory data. List of 16 bit integers. + :param board: Board to access (0-15) with ``0xf = 15`` being broadcast + to all boards. + """ self.bus.set_xfer(self.chip_select, 24, 0) self.bus.write((_PDQ_CMD(board, 1, mem, 1) << 24) | ((adr & 0x00ff) << 16) | (adr & 0xff00)) @@ -108,6 +170,14 @@ class PDQ: @kernel def read_mem(self, mem, adr, data, board=0xf, buffer=8): + """Read from DAC channel waveform data memory. + + :param mem: DAC channel memory to access (0 to 2). + :param adr: Start address. + :param data: Memory data. List of 16 bit integers. + :param board: Board to access (0-15) with ``0xf = 15`` being broadcast + to all boards. + """ n = len(data) if not n: return