mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-25 03:08:27 +08:00
phaser: add jesd204b rtio dds
gateware: add jesd204b awg gateware: copy phaser (df3825a) dsp/tools: update satadd mixin phaser: no DDS stubs dsp: accu fix phaser: cleanup/reduce sawg: kernel support and docs sawg: coredevice api fixes sawg: example ddb/experiment phaser: add conda package examples/phaser: typo sawg: adapt tests, fix accu stb sawg: tweak dds parameters sawg: move/adapt/extend tests sawg: test phy, refactor phaser: non-rtio spi phaser: target cli update phaser: ad9154-fmc-ebz pins phaser: reorganize fmc signal naming phaser: add test mode stubs phaser: txen is LVTTL phaser: clk spi xfer test phaser: spi for ad9154 and ad9516 phaser: spi tweaks ad9154: add register map from ad9144.xml ad9516: add register map from ad9517.xml and manual adaptation ad9154_reg: just generate getter/setter macros as well ad9154: reg WIP ad9154: check and fix registers kc705: single ended rtio_external_clk use single ended user_sma_clk_n instead of p/n to free up one clock sma kc705: mirror clk200 at user_sma_clock_p ad9516_regs.h: fix B_COUNTER_MSB phase: wire up clocking differently needs patched misoc kc705: feed rtio_external_clock directly kc705: remove rtio_external_clk for phaser phaser: spi tweaks ad9516: some startup ad9516_reg fixes phaser: setup ad9516 for supposed 500 MHz operation ad9516: use full duplex spi ad9154_reg: add CONFIG_REG_2 ad9154_reg: fixes phaser: write some ad9154 config ad9154_reg: fixes ad9154: more init, and human readable setup ad9154/ad9516: merge spi support ad9154: status readout Revert "kc705: remove rtio_external_clk for phaser" This reverts commit d500288bb44f2bf2eeb0c2f237aa207b0a8b1366. Revert "kc705: feed rtio_external_clock directly" This reverts commit 8dc7825519e3e75b7d3d29c9abf10fc6e3a8b4c5. Revert "phase: wire up clocking differently" This reverts commit ad9cc450ffa35abb54b0842d56f6cf6c53c6fbcc. Revert "kc705: mirror clk200 at user_sma_clock_p" This reverts commit 7f0dffdcdd28e648af84725682f82ec6e5642eba. Revert "kc705: single ended rtio_external_clk" This reverts commit a9426d983fbf5c1cb768da8f1da26d9b7335e9cf. ad9516: 2000 MHz clock phaser: test clock dist phaser: test freqs ad9154: iostandards phaser: drop clock monitor phaser: no separate i2c phaser: drive rtio from refclk, wire up sysref phaser: ttl channel for sync ad9154: 4x interp, status, tweaks phaser: sync/sysref 33V banks phaser: sync/sysref LVDS_25 inputs are VCCO tolerant phaser: user input-only ttls phaser: rtio fully from refclk ad9154: reg name usage fix ad9154: check register modifications Revert "ad9154: check register modifications" This reverts commit 45121d90edf89f7bd8703503f9f317ad050f9564. ad9154: fix status code ad9154: addrinc, recal serdes pll phaser: coredevice, example tweaks sawg: missing import sawg: type fixes ad9514: move setup functions ad9154: msb first also decreasing addr phaser: use sys4x for rtio internal ref phaser: move init code to main phaser: naming cleanup phaser: cleanup pins phaser: move spi to kernel cpu phaser: kernel support for ad9154 spi ad9154: add r/w methods ad9154: need return annotations ad9154: r/w methods are kernels ad9154_reg: portable helpers phaser: cleanup startup kernel ad9154: status test ad9154: prbs test ad9154: move setup, document phaser: more documentation
This commit is contained in:
parent
2bc5dc4ecb
commit
4a0eaf0f95
68
artiq/coredevice/ad9154.py
Normal file
68
artiq/coredevice/ad9154.py
Normal file
@ -0,0 +1,68 @@
|
||||
from artiq.language.core import kernel, syscall
|
||||
from artiq.language.types import TInt32, TNone
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def ad9154_init() -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def ad9154_write(addr: TInt32, data: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def ad9154_read(addr: TInt32) -> TInt32:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def ad9516_write(addr: TInt32, data: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def ad9516_read(addr: TInt32) -> TInt32:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
class AD9154:
|
||||
"""AD9154-FMC-EBZ SPI support
|
||||
|
||||
There are two devices on the SPI bus, a AD9154 DAC and a AD9516 clock
|
||||
divider/fanout.
|
||||
|
||||
Register and bit names are in :mod:`artiq.coredevice.ad9154_reg` and
|
||||
:mod:`artiq.coredevice.ad9516_reg` respectively.
|
||||
|
||||
The SPI bus does not operate over RTIO but directly. This class does not
|
||||
interact with the timeline.
|
||||
"""
|
||||
def __init__(self, dmgr, core_device="core"):
|
||||
self.core = dmgr.get(core_device)
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
"""Initialize and configure the SPI bus."""
|
||||
ad9154_init()
|
||||
|
||||
@kernel
|
||||
def dac_write(self, addr, data):
|
||||
"""Write `data` to AD9154 SPI register at `addr`."""
|
||||
ad9154_write(addr, data)
|
||||
|
||||
@kernel
|
||||
def dac_read(self, addr):
|
||||
"""Read AD9154 SPI register at `addr`."""
|
||||
return ad9154_read(addr)
|
||||
|
||||
@kernel
|
||||
def clock_write(self, addr, data):
|
||||
"""Write `data` to AD9516 SPI register at `addr`."""
|
||||
ad9516_write(addr, data)
|
||||
|
||||
@kernel
|
||||
def clock_read(self, addr):
|
||||
"""Read AD9516 SPI register at `addr`."""
|
||||
return ad9516_read(addr)
|
2980
artiq/coredevice/ad9154_reg.py
Normal file
2980
artiq/coredevice/ad9154_reg.py
Normal file
File diff suppressed because it is too large
Load Diff
291
artiq/coredevice/ad9516_reg.py
Normal file
291
artiq/coredevice/ad9516_reg.py
Normal file
@ -0,0 +1,291 @@
|
||||
# = auto-generated, do not edit
|
||||
from artiq.language.core import kernel
|
||||
|
||||
|
||||
AD9516_SERIAL_PORT_CONFIGURATION = 0x000
|
||||
AD9516_SDO_ACTIVE = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_LSB_FIRST = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_SOFT_RESET = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_LONG_INSTRUCTION = 1 << 3 # 1, 0x01 R/W
|
||||
AD9516_LONG_INSTRUCTION_MIRRORED = 1 << 4 # 1, 0x01 R/W
|
||||
AD9516_SOFT_RESET_MIRRORED = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_LSB_FIRST_MIRRORED = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_SDO_ACTIVE_MIRRORED = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PART_ID = 0x003
|
||||
|
||||
AD9516_READBACK_CONTROL = 0x004
|
||||
AD9516_READ_BACK_ACTIVE_REGISTERS = 1 << 0 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PFD_AND_CHARGE_PUMP = 0x010
|
||||
AD9516_PLL_POWER_DOWN = 1 << 0 # 2, 0x01 R/W
|
||||
AD9516_CHARGE_PUMP_MODE = 1 << 2 # 2, 0x03 R/W
|
||||
AD9516_CHARGE_PUMP_CURRENT = 1 << 4 # 3, 0x07 R/W
|
||||
AD9516_PFD_POLARITY = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_R_COUNTER_LSB = 0x011
|
||||
AD9516_R_COUNTER_MSB = 0x012
|
||||
|
||||
AD9516_A_COUNTER = 0x013
|
||||
|
||||
AD9516_B_COUNTER_LSB = 0x014
|
||||
AD9516_B_COUNTER_MSB = 0x015
|
||||
|
||||
AD9516_PLL_CONTROL_1 = 0x016
|
||||
AD9516_PRESCALER_P = 1 << 0 # 3, 0x06 R/W
|
||||
AD9516_B_COUNTER_BYPASS = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_RESET_ALL_COUNTERS = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_RESET_A_AND_B_COUNTERS = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_RESET_R_COUNTER = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_SET_CP_PIN_TO_VCP_2 = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_2 = 0x017
|
||||
AD9516_ANTIBACKLASH_PULSE_WIDTH = 1 << 0 # 2, 0x00 R/W
|
||||
AD9516_STATUS_PIN_CONTROL = 1 << 2 # 6, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_3 = 0x018
|
||||
AD9516_VCO_CAL_NOW = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_VCO_CALIBRATION_DIVIDER = 1 << 1 # 2, 0x03 R/W
|
||||
AD9516_DISABLE_DIGITAL_LOCK_DETECT = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_DIGITAL_LOCK_DETECT_WINDOW = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_LOCK_DETECT_COUNTER = 1 << 5 # 2, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_4 = 0x019
|
||||
AD9516_N_PATH_DELAY = 1 << 0 # 3, 0x00 R/W
|
||||
AD9516_R_PATH_DELAY = 1 << 3 # 3, 0x00 R/W
|
||||
AD9516_R_A_B_COUNTERS_SYNC_PIN_RESET = 1 << 6 # 2, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_5 = 0x01a
|
||||
AD9516_LD_PIN_CONTROL = 1 << 0 # 6, 0x00 R/W
|
||||
AD9516_REFERENCE_FREQUENCY_MONITOR_THRESHOLD = 1 << 6 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_6 = 0x01b
|
||||
AD9516_REFMON_PIN_CONTROL = 1 << 0 # 5, 0x00 R/W
|
||||
AD9516_REF1_REFIN_FREQUENCY_MONITOR = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_REF2_REFIN_FREQUENCY_MONITOR = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_VCO_FREQUENCY_MONITOR = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_7 = 0x01c
|
||||
AD9516_DIFFERENTIAL_REFERENCE = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_REF1_POWER_ON = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_REF2_POWER_ON = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_USE_REF_SEL_PIN = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_SELECT_REF2 = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_DISABLE_SWITCHOVER_DEGLITCH = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PLL_CONTROL_8 = 0x01d
|
||||
AD9516_HOLDOVER_ENABLE = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_EXTERNAL_HOLDOVER_CONTROL = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_HOLDOVER_ENABLEreg001D = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_LD_PIN_COMPARATOR_ENABLE = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_PLL_STATUS_REGISTER_DISABLE = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_PLL_READBACK = 0x01f
|
||||
AD9516_DIGITAL_LOCK_DETECT = 1 << 0 # 1, 0x00 R
|
||||
AD9516_REF1_FREQUENCY_THRESHOLD = 1 << 1 # 1, 0x00 R
|
||||
AD9516_REF2_FREQUENCY_THRESHOLD = 1 << 2 # 1, 0x00 R
|
||||
AD9516_VCO_FREQUENCY_THRESHOLD = 1 << 3 # 1, 0x00 R
|
||||
AD9516_REF2_SELECTED = 1 << 4 # 1, 0x00 R
|
||||
AD9516_HOLDOVER_ACTIVE = 1 << 5 # 1, 0x00 R
|
||||
AD9516_VCO_CAL_FINISHED = 1 << 6 # 1, 0x00 R
|
||||
|
||||
AD9516_OUT6_DELAY_BYPASS = 0x0a0
|
||||
|
||||
AD9516_OUT6_DELAY_FULL_SCALE = 0x0a1
|
||||
AD9516_OUT6_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W
|
||||
AD9516_OUT6_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W
|
||||
|
||||
AD9516_OUT6_DELAY_FRACTION = 0x0a2
|
||||
|
||||
AD9516_OUT7_DELAY_BYPASS = 0x0a3
|
||||
|
||||
AD9516_OUT7_DELAY_FULL_SCALE = 0x0a4
|
||||
AD9516_OUT7_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W
|
||||
AD9516_OUT7_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W
|
||||
|
||||
AD9516_OUT7_DELAY_FRACTION = 0x0a5
|
||||
|
||||
AD9516_OUT8_DELAY_BYPASS = 0x0a6
|
||||
|
||||
AD9516_OUT8_DELAY_FULL_SCALE = 0x0a7
|
||||
AD9516_OUT8_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W
|
||||
AD9516_OUT8_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W
|
||||
|
||||
AD9516_OUT8_DELAY_FRACTION = 0x0a8
|
||||
|
||||
AD9516_OUT9_DELAY_BYPASS = 0x0a9
|
||||
|
||||
AD9516_OUT9_DELAY_FULL_SCALE = 0x0aa
|
||||
AD9516_OUT9_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W
|
||||
AD9516_OUT9_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W
|
||||
|
||||
AD9516_OUT9_DELAY_FRACTION = 0x0ab
|
||||
|
||||
AD9516_OUT0 = 0x0f0
|
||||
AD9516_OUT0_POWER_DOWN = 1 << 0 # 2, 0x00 R/W
|
||||
AD9516_OUT0_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT0_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT1 = 0x0f1
|
||||
AD9516_OUT1_POWER_DOWN = 1 << 0 # 2, 0x02 R/W
|
||||
AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT1_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT2 = 0x0f2
|
||||
AD9516_OUT2_POWER_DOWN = 1 << 0 # 2, 0x00 R/W
|
||||
AD9516_OUT2_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT2_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT3 = 0x0f3
|
||||
AD9516_OUT3_POWER_DOWN = 1 << 0 # 2, 0x02 R/W
|
||||
AD9516_OUT3_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT3_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT4 = 0x0f4
|
||||
AD9516_OUT4_POWER_DOWN = 1 << 0 # 2, 0x02 R/W
|
||||
AD9516_OUT4_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT4_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT5 = 0x0f5
|
||||
AD9516_OUT5_POWER_DOWN = 1 << 0 # 2, 0x02 R/W
|
||||
AD9516_OUT5_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W
|
||||
AD9516_OUT5_INVERT = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_OUT6 = 0x140
|
||||
AD9516_OUT6_POWER_DOWN = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_OUT6_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W
|
||||
AD9516_OUT6_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_OUT6_CMOS_B = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_OUT6_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W
|
||||
|
||||
AD9516_OUT7 = 0x141
|
||||
AD9516_OUT7_POWER_DOWN = 1 << 0 # 1, 0x01 R/W
|
||||
AD9516_OUT7_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W
|
||||
AD9516_OUT7_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_OUT7_CMOS_B = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_OUT7_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_OUT7_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W
|
||||
|
||||
AD9516_OUT8 = 0x142
|
||||
AD9516_OUT8_POWER_DOWN = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_OUT8_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W
|
||||
AD9516_OUT8_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_OUT8_CMOS_B = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_OUT8_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_OUT8_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W
|
||||
|
||||
AD9516_OUT9 = 0x143
|
||||
AD9516_OUT9_POWER_DOWN = 1 << 0 # 1, 0x01 R/W
|
||||
AD9516_OUT9_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W
|
||||
AD9516_OUT9_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_OUT9_CMOS_B = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_OUT9_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W
|
||||
|
||||
AD9516_DIVIDER_0_0 = 0x190
|
||||
AD9516_DIVIDER_0_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_0_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_0_1 = 0x191
|
||||
AD9516_DIVIDER_0_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_0_START_HIGH = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_0_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_0_NOSYNC = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_0_BYPASS = 1 << 7 # 1, 0x01 R/W
|
||||
|
||||
AD9516_DIVIDER_0_2 = 0x192
|
||||
AD9516_DIVIDER_0_DCCOFF = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_0_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_1_0 = 0x193
|
||||
AD9516_DIVIDER_1_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_1_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_1_1 = 0x194
|
||||
AD9516_DIVIDER_1_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_1_START_HIGH = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_1_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_1_NOSYNC = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_1_BYPASS = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_1_2 = 0x195
|
||||
AD9516_DIVIDER_1_DCCOFF = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_1_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_2_0 = 0x196
|
||||
AD9516_DIVIDER_2_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_2_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_2_1 = 0x197
|
||||
AD9516_DIVIDER_2_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_2_START_HIGH = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_2_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_2_NOSYNC = 1 << 6 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_2_BYPASS = 1 << 7 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_2_2 = 0x198
|
||||
AD9516_DIVIDER_2_DCCOFF = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_2_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_3_0 = 0x199
|
||||
AD9516_DIVIDER_3_HIGH_CYCLES_1 = 1 << 0 # 4, 0x02 R/W
|
||||
AD9516_DIVIDER_3_LOW_CYCLES_1 = 1 << 4 # 4, 0x02 R/W
|
||||
|
||||
AD9516_DIVIDER_3_1 = 0x19a
|
||||
AD9516_DIVIDER_3_PHASE_OFFSET_1 = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_3_PHASE_OFFSET_2 = 1 << 4 # 4, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_3_2 = 0x19b
|
||||
AD9516_DIVIDER_3_HIGH_CYCLES_2 = 1 << 0 # 4, 0x01 R/W
|
||||
AD9516_DIVIDER_3_LOW_CYCLES_2 = 1 << 4 # 4, 0x01 R/W
|
||||
|
||||
AD9516_DIVIDER_3_3 = 0x19c
|
||||
AD9516_DIVIDER_3_START_HIGH_1 = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_3_START_HIGH_2 = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_3_FORCE_HIGH = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_3_NOSYNC = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_3_BYPASS_1 = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_3_BYPASS_2 = 1 << 5 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_3_4 = 0x19d
|
||||
AD9516_DIVIDER_3_DCCOFF = 1 << 0 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_4_0 = 0x19e
|
||||
AD9516_DIVIDER_4_HIGH_CYCLES_1 = 1 << 0 # 4, 0x02 R/W
|
||||
AD9516_DIVIDER_4_LOW_CYCLES_1 = 1 << 4 # 4, 0x02 R/W
|
||||
|
||||
AD9516_DIVIDER_4_1 = 0x19f
|
||||
AD9516_DIVIDER_4_PHASE_OFFSET_1 = 1 << 0 # 4, 0x00 R/W
|
||||
AD9516_DIVIDER_4_PHASE_OFFSET_2 = 1 << 4 # 4, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_4_2 = 0x1a0
|
||||
AD9516_DIVIDER_4_HIGH_CYCLES_2 = 1 << 0 # 4, 0x01 R/W
|
||||
AD9516_DIVIDER_4_LOW_CYCLES_2 = 1 << 4 # 4, 0x01 R/W
|
||||
|
||||
AD9516_DIVIDER_4_3 = 0x1a1
|
||||
AD9516_DIVIDER_4_START_HIGH_1 = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_4_START_HIGH_2 = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_4_FORCE_HIGH = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_4_NOSYNC = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_4_BYPASS_1 = 1 << 4 # 1, 0x00 R/W
|
||||
AD9516_DIVIDER_4_BYPASS_2 = 1 << 5 # 1, 0x00 R/W
|
||||
|
||||
AD9516_DIVIDER_4_4 = 0x1a2
|
||||
AD9516_DIVIDER_4_DCCOFF = 1 << 0 # 1, 0x00 R/W
|
||||
|
||||
AD9516_VCO_DIVIDER = 0x1e0
|
||||
|
||||
AD9516_INPUT_CLKS = 0x1e1
|
||||
AD9516_BYPASS_VCO_DIVIDER = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_SELECT_VCO_OR_CLK = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_POWER_DOWN_VCO_AND_CLK = 1 << 2 # 1, 0x00 R/W
|
||||
AD9516_POWER_DOWN_VCO_CLOCK_INTERFACE = 1 << 3 # 1, 0x00 R/W
|
||||
AD9516_POWER_DOWN_CLOCK_INPUT_SECTION = 1 << 4 # 1, 0x00 R/W
|
||||
|
||||
AD9516_POWER_DOWN_AND_SYNC = 0x230
|
||||
AD9516_SOFT_SYNC = 1 << 0 # 1, 0x00 R/W
|
||||
AD9516_POWER_DOWN_DISTRIBUTION_REFERENCE = 1 << 1 # 1, 0x00 R/W
|
||||
AD9516_POWER_DOWN_SYNC = 1 << 2 # 1, 0x00 R/W
|
||||
|
||||
AD9516_UPDATE_ALL_REGISTERS = 0x232
|
73
artiq/coredevice/sawg.py
Normal file
73
artiq/coredevice/sawg.py
Normal file
@ -0,0 +1,73 @@
|
||||
from artiq.language.core import kernel, now_mu
|
||||
from artiq.coredevice.rtio import rtio_output
|
||||
from artiq.language.types import TInt32, TFloat
|
||||
|
||||
|
||||
class SAWG:
|
||||
"""Smart arbitrary waveform generator channel.
|
||||
|
||||
:param channel_base: RTIO channel number of the first channel (amplitude).
|
||||
Frequency and Phase are then assumed to be successive channels.
|
||||
"""
|
||||
kernel_invariants = {"amplitude_scale", "frequency_scale", "phase_scale",
|
||||
"channel_base"}
|
||||
|
||||
def __init__(self, dmgr, channel_base, parallelism=4, core_device="core"):
|
||||
self.core = dmgr.get(core_device)
|
||||
self.channel_base = channel_base
|
||||
cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain
|
||||
a_width = 16
|
||||
f_width = 32
|
||||
p_width = 16
|
||||
self.amplitude_scale = (1 << a_width) / 2 / cordic_gain
|
||||
self.phase_scale = 1 << p_width
|
||||
self.frequency_scale = ((1 << f_width) * self.core.coarse_ref_period /
|
||||
parallelism)
|
||||
|
||||
@kernel
|
||||
def set_amplitude_mu(self, amplitude: TInt32):
|
||||
"""Set DDS amplitude (machine units).
|
||||
|
||||
:param amplitude: DDS amplitude in machine units.
|
||||
"""
|
||||
rtio_output(now_mu(), self.channel_base, 0, amplitude)
|
||||
|
||||
@kernel
|
||||
def set_amplitude(self, amplitude: TFloat):
|
||||
"""Set DDS amplitude.
|
||||
|
||||
:param amplitude: DDS amplitude relative to full-scale.
|
||||
"""
|
||||
self.set_amplitude_mu(int(amplitude*self.amplitude_scale))
|
||||
|
||||
@kernel
|
||||
def set_frequency_mu(self, frequency: TInt32):
|
||||
"""Set DDS frequency (machine units).
|
||||
|
||||
:param frequency: DDS frequency in machine units.
|
||||
"""
|
||||
rtio_output(now_mu(), self.channel_base + 1, 0, frequency)
|
||||
|
||||
@kernel
|
||||
def set_frequency(self, frequency: TFloat):
|
||||
"""Set DDS frequency.
|
||||
|
||||
:param frequency: DDS frequency in Hz.
|
||||
"""
|
||||
self.set_frequency_mu(int(frequency*self.frequency_scale))
|
||||
|
||||
@kernel
|
||||
def set_phase_mu(self, phase: TInt32):
|
||||
"""Set DDS phase (machine units).
|
||||
|
||||
:param phase: DDS phase in machine units.
|
||||
"""
|
||||
rtio_output(now_mu(), self.channel_base + 2, 0, phase)
|
||||
|
||||
@kernel
|
||||
def set_phase(self, phase: TFloat):
|
||||
"""Set DDS phase.
|
||||
|
||||
:param phase: DDS phase relative in turns.
|
||||
"""
|
||||
self.set_phase_mu(int(phase*self.phase_scale))
|
77
artiq/examples/phaser/device_db.pyon
Normal file
77
artiq/examples/phaser/device_db.pyon
Normal file
@ -0,0 +1,77 @@
|
||||
# The RTIO channel numbers here are for Phaser on KC705.
|
||||
|
||||
{
|
||||
"comm": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.comm_tcp",
|
||||
"class": "Comm",
|
||||
"arguments": {"host": "kc705aux.lab.m-labs.hk"}
|
||||
},
|
||||
"core": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.core",
|
||||
"class": "Core",
|
||||
"arguments": {
|
||||
"ref_period": 1e-9,
|
||||
"external_clock": True
|
||||
}
|
||||
},
|
||||
"core_cache": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.cache",
|
||||
"class": "CoreCache"
|
||||
},
|
||||
"ad9154": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ad9154",
|
||||
"class": "AD9154"
|
||||
},
|
||||
"ttl_sma": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": 0}
|
||||
},
|
||||
"led": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLOut",
|
||||
"arguments": {"channel": 1}
|
||||
},
|
||||
"sysref": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": 2}
|
||||
},
|
||||
"sync": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.ttl",
|
||||
"class": "TTLInOut",
|
||||
"arguments": {"channel": 3}
|
||||
},
|
||||
"sawg0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.sawg",
|
||||
"class": "SAWG",
|
||||
"arguments": {"channel_base": 4, "parallelism": 4}
|
||||
},
|
||||
"sawg1": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.sawg",
|
||||
"class": "SAWG",
|
||||
"arguments": {"channel_base": 7, "parallelism": 4}
|
||||
},
|
||||
"sawg2": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.sawg",
|
||||
"class": "SAWG",
|
||||
"arguments": {"channel_base": 10, "parallelism": 4}
|
||||
},
|
||||
"sawg3": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.sawg",
|
||||
"class": "SAWG",
|
||||
"arguments": {"channel_base": 13, "parallelism": 4}
|
||||
}
|
||||
}
|
21
artiq/examples/phaser/idle_kernel.py
Normal file
21
artiq/examples/phaser/idle_kernel.py
Normal file
@ -0,0 +1,21 @@
|
||||
from artiq.experiment import *
|
||||
|
||||
|
||||
class IdleKernel(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("led")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
start_time = now_mu() + seconds_to_mu(500*ms)
|
||||
while self.core.get_rtio_counter_mu() < start_time:
|
||||
pass
|
||||
self.core.reset()
|
||||
while True:
|
||||
self.led.pulse(250*ms)
|
||||
delay(125*ms)
|
||||
self.led.pulse(125*ms)
|
||||
delay(125*ms)
|
||||
self.led.pulse(125*ms)
|
||||
delay(250*ms)
|
34
artiq/examples/phaser/repository/sawg.py
Normal file
34
artiq/examples/phaser/repository/sawg.py
Normal file
@ -0,0 +1,34 @@
|
||||
from artiq.experiment import *
|
||||
|
||||
|
||||
class SAWGTest(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("led")
|
||||
|
||||
self.setattr_device("sawg0")
|
||||
self.setattr_device("sawg1")
|
||||
self.setattr_device("sawg2")
|
||||
self.setattr_device("sawg3")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.core.reset()
|
||||
|
||||
delay(100*us)
|
||||
self.sawg0.set_amplitude(.1)
|
||||
self.sawg1.set_amplitude(-1.)
|
||||
self.sawg2.set_amplitude(.5)
|
||||
self.sawg3.set_amplitude(.5)
|
||||
self.sawg0.set_frequency(1*MHz)
|
||||
self.sawg1.set_frequency(100*MHz)
|
||||
self.sawg2.set_frequency(200*MHz)
|
||||
self.sawg3.set_frequency(200*MHz)
|
||||
self.sawg0.set_phase(0.)
|
||||
self.sawg1.set_phase(0.)
|
||||
self.sawg2.set_phase(0.)
|
||||
self.sawg3.set_phase(.5)
|
||||
|
||||
for i in range(10):
|
||||
self.led.pulse(100*ms)
|
||||
delay(100*ms)
|
46
artiq/examples/phaser/repository/test_ad9154_prbs.py
Normal file
46
artiq/examples/phaser/repository/test_ad9154_prbs.py
Normal file
@ -0,0 +1,46 @@
|
||||
import time
|
||||
|
||||
from artiq.coredevice.ad9154_reg import *
|
||||
from artiq.experiment import *
|
||||
|
||||
|
||||
class Test(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("ad9154")
|
||||
|
||||
def run(self):
|
||||
self.prbs(2, 100) # prbs31
|
||||
|
||||
def p(self, f, *a):
|
||||
print(f % a)
|
||||
|
||||
def prbs(self, p, t):
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL,
|
||||
AD9154_PHY_PRBS_PAT_SEL_SET(p))
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_EN, 0xff)
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL,
|
||||
AD9154_PHY_PRBS_PAT_SEL_SET(p) | AD9154_PHY_TEST_RESET_SET(1))
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL,
|
||||
AD9154_PHY_PRBS_PAT_SEL_SET(p))
|
||||
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_LOBITS, t)
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS, t >> 8)
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS, t >> 16)
|
||||
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p))
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL,
|
||||
AD9154_PHY_PRBS_PAT_SEL_SET(p) | AD9154_PHY_TEST_START_SET(1))
|
||||
|
||||
time.sleep(.5)
|
||||
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p))
|
||||
|
||||
self.p("prbs status: 0x%02x", self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_STATUS))
|
||||
|
||||
for i in range(8):
|
||||
self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_SRC_ERR_CNT_SET(i))
|
||||
self.p("prbs errors[%d]: 0x%08x", i,
|
||||
self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS) |
|
||||
(self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS) << 8) |
|
||||
(self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS) << 16))
|
126
artiq/examples/phaser/repository/test_ad9154_status.py
Normal file
126
artiq/examples/phaser/repository/test_ad9154_status.py
Normal file
@ -0,0 +1,126 @@
|
||||
from artiq.coredevice.ad9154_reg import *
|
||||
from artiq.experiment import *
|
||||
|
||||
|
||||
class Test(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("ad9154")
|
||||
|
||||
def run(self):
|
||||
self.print_status()
|
||||
self.print_temp()
|
||||
|
||||
def p(self, f, *a):
|
||||
print(f % a)
|
||||
|
||||
def print_temp(self):
|
||||
self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) |
|
||||
AD9154_AUXADC_ENABLE_SET(1))
|
||||
self.ad9154.dac_write(AD9154_DIE_TEMP_UPDATE, 1)
|
||||
self.p("temp_code %d", self.ad9154.dac_read(AD9154_DIE_TEMP0) |
|
||||
(self.ad9154.dac_read(AD9154_DIE_TEMP1) << 8))
|
||||
self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) |
|
||||
AD9154_AUXADC_ENABLE_SET(0))
|
||||
|
||||
def print_status(self):
|
||||
x = self.ad9154.dac_read(AD9154_IRQ_STATUS0)
|
||||
self.p("LANEFIFOERR: %d, SERPLLLOCK: %d, SERPLLLOST: %d, "
|
||||
"DACPLLLOCK: %d, DACPLLLOST: %d",
|
||||
AD9154_LANEFIFOERR_GET(x), AD9154_SERPLLLOCK_GET(x),
|
||||
AD9154_SERPLLLOST_GET(x), AD9154_DACPLLLOCK_GET(x),
|
||||
AD9154_DACPLLLOST_GET(x))
|
||||
x = self.ad9154.dac_read(AD9154_IRQ_STATUS1)
|
||||
self.p("PRBS0: %d, PRBS1: %d, PRBS2: %d, PRBS3: %d",
|
||||
AD9154_PRBS0_GET(x), AD9154_PRBS1_GET(x),
|
||||
AD9154_PRBS2_GET(x), AD9154_PRBS3_GET(x))
|
||||
x = self.ad9154.dac_read(AD9154_IRQ_STATUS2)
|
||||
self.p("SYNC_TRIP0: %d, SYNC_WLIM0: %d, SYNC_ROTATE0: %d, "
|
||||
"SYNC_LOCK0: %d, NCO_ALIGN0: %d, BLNKDONE0: %d, "
|
||||
"PDPERR0: %d",
|
||||
AD9154_SYNC_TRIP0_GET(x), AD9154_SYNC_WLIM0_GET(x),
|
||||
AD9154_SYNC_ROTATE0_GET(x), AD9154_SYNC_LOCK0_GET(x),
|
||||
AD9154_NCO_ALIGN0_GET(x), AD9154_BLNKDONE0_GET(x),
|
||||
AD9154_PDPERR0_GET(x))
|
||||
x = self.ad9154.dac_read(AD9154_IRQ_STATUS3)
|
||||
self.p("SYNC_TRIP1: %d, SYNC_WLIM1: %d, SYNC_ROTATE1: %d, "
|
||||
"SYNC_LOCK1: %d, NCO_ALIGN1: %d, BLNKDONE1: %d, "
|
||||
"PDPERR1: %d",
|
||||
AD9154_SYNC_TRIP1_GET(x), AD9154_SYNC_WLIM1_GET(x),
|
||||
AD9154_SYNC_ROTATE1_GET(x), AD9154_SYNC_LOCK1_GET(x),
|
||||
AD9154_NCO_ALIGN1_GET(x), AD9154_BLNKDONE1_GET(x),
|
||||
AD9154_PDPERR1_GET(x))
|
||||
x = self.ad9154.dac_read(AD9154_JESD_CHECKS)
|
||||
self.p("ERR_INTSUPP: %d, ERR_SUBCLASS: %d, ERR_KUNSUPP: %d, "
|
||||
"ERR_JESDBAD: %d, ERR_WINLIMIT: %d, ERR_DLYOVER: %d",
|
||||
AD9154_ERR_INTSUPP_GET(x), AD9154_ERR_SUBCLASS_GET(x),
|
||||
AD9154_ERR_KUNSUPP_GET(x), AD9154_ERR_JESDBAD_GET(x),
|
||||
AD9154_ERR_WINLIMIT_GET(x), AD9154_ERR_DLYOVER_GET(x))
|
||||
|
||||
x = self.ad9154.dac_read(AD9154_DACPLLSTATUS)
|
||||
self.p("DACPLL_LOCK: %d, VCO_CAL_PROGRESS: %d, CP_CAL_VALID: %d, "
|
||||
"CP_OVERRANGE_L: %d, CP_OVERRANGE_H: %d",
|
||||
AD9154_DACPLL_LOCK_GET(x), AD9154_VCO_CAL_PROGRESS_GET(x),
|
||||
AD9154_CP_CAL_VALID_GET(x), AD9154_CP_OVERRANGE_L_GET(x),
|
||||
AD9154_CP_OVERRANGE_H_GET(x))
|
||||
|
||||
x = self.ad9154.dac_read(AD9154_PLL_STATUS)
|
||||
self.p("PLL_LOCK_RB: %d, CURRENTS_READY_RB: %d, "
|
||||
"VCO_CAL_IN_PROGRESS_RB: %d, PLL_CAL_VALID_RB: %d, "
|
||||
"PLL_OVERRANGE_L_RB: %d, PLL_OVERRANGE_H_RB: %d",
|
||||
AD9154_SERDES_PLL_LOCK_RB_GET(x),
|
||||
AD9154_SERDES_CURRENTS_READY_RB_GET(x),
|
||||
AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x),
|
||||
AD9154_SERDES_PLL_CAL_VALID_RB_GET(x),
|
||||
AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x),
|
||||
AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x))
|
||||
|
||||
self.p("CODEGRPSYNC: 0x%02x", self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG))
|
||||
self.p("FRAMESYNC: 0x%02x", self.ad9154.dac_read(AD9154_FRAMESYNCFLG))
|
||||
self.p("GOODCHECKSUM: 0x%02x", self.ad9154.dac_read(AD9154_GOODCHKSUMFLG))
|
||||
self.p("INITIALLANESYNC: 0x%02x", self.ad9154.dac_read(AD9154_INITLANESYNCFLG))
|
||||
|
||||
x = self.ad9154.dac_read(AD9154_SYNC_LASTERR_H)
|
||||
self.p("SYNC_LASTERR: 0x%04x", self.ad9154.dac_read(AD9154_SYNC_LASTERR_L) |
|
||||
(AD9154_LASTERROR_H_GET(x) << 8))
|
||||
self.p("SYNC_LASTOVER: %d, SYNC_LASTUNDER: %d",
|
||||
AD9154_LASTOVER_GET(x), AD9154_LASTUNDER_GET(x))
|
||||
x = self.ad9154.dac_read(AD9154_SYNC_STATUS)
|
||||
self.p("SYNC_TRIP: %d, SYNC_WLIM: %d, SYNC_ROTATE: %d, "
|
||||
"SYNC_LOCK: %d, SYNC_BUSY: %d",
|
||||
AD9154_SYNC_TRIP_GET(x), AD9154_SYNC_WLIM_GET(x),
|
||||
AD9154_SYNC_ROTATE_GET(x), AD9154_SYNC_LOCK_GET(x),
|
||||
AD9154_SYNC_BUSY_GET(x))
|
||||
|
||||
self.p("LANE_FIFO_FULL: 0x%02x", self.ad9154.dac_read(AD9154_FIFO_STATUS_REG_0))
|
||||
self.p("LANE_FIFO_EMPTY: 0x%02x", self.ad9154.dac_read(AD9154_FIFO_STATUS_REG_1))
|
||||
self.p("DID_REG: 0x%02x", self.ad9154.dac_read(AD9154_DID_REG))
|
||||
self.p("BID_REG: 0x%02x", self.ad9154.dac_read(AD9154_BID_REG))
|
||||
self.p("SCR_L_REG: 0x%02x", self.ad9154.dac_read(AD9154_SCR_L_REG))
|
||||
self.p("F_REG: 0x%02x", self.ad9154.dac_read(AD9154_F_REG))
|
||||
self.p("K_REG: 0x%02x", self.ad9154.dac_read(AD9154_K_REG))
|
||||
self.p("M_REG: 0x%02x", self.ad9154.dac_read(AD9154_M_REG))
|
||||
self.p("CS_N_REG: 0x%02x", self.ad9154.dac_read(AD9154_CS_N_REG))
|
||||
self.p("NP_REG: 0x%02x", self.ad9154.dac_read(AD9154_NP_REG))
|
||||
self.p("S_REG: 0x%02x", self.ad9154.dac_read(AD9154_S_REG))
|
||||
self.p("HD_CF_REG: 0x%02x", self.ad9154.dac_read(AD9154_HD_CF_REG))
|
||||
self.p("RES1_REG: 0x%02x", self.ad9154.dac_read(AD9154_RES1_REG))
|
||||
self.p("RES2_REG: 0x%02x", self.ad9154.dac_read(AD9154_RES2_REG))
|
||||
self.p("LIDx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
|
||||
self.ad9154.dac_read(AD9154_LID0_REG), self.ad9154.dac_read(AD9154_LID1_REG),
|
||||
self.ad9154.dac_read(AD9154_LID2_REG), self.ad9154.dac_read(AD9154_LID3_REG),
|
||||
self.ad9154.dac_read(AD9154_LID4_REG), self.ad9154.dac_read(AD9154_LID5_REG),
|
||||
self.ad9154.dac_read(AD9154_LID6_REG), self.ad9154.dac_read(AD9154_LID7_REG))
|
||||
self.p("CHECKSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
|
||||
self.ad9154.dac_read(AD9154_CHECKSUM0_REG), self.ad9154.dac_read(AD9154_CHECKSUM1_REG),
|
||||
self.ad9154.dac_read(AD9154_CHECKSUM2_REG), self.ad9154.dac_read(AD9154_CHECKSUM3_REG),
|
||||
self.ad9154.dac_read(AD9154_CHECKSUM4_REG), self.ad9154.dac_read(AD9154_CHECKSUM5_REG),
|
||||
self.ad9154.dac_read(AD9154_CHECKSUM6_REG), self.ad9154.dac_read(AD9154_CHECKSUM7_REG))
|
||||
self.p("COMPSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
|
||||
self.ad9154.dac_read(AD9154_COMPSUM0_REG), self.ad9154.dac_read(AD9154_COMPSUM1_REG),
|
||||
self.ad9154.dac_read(AD9154_COMPSUM2_REG), self.ad9154.dac_read(AD9154_COMPSUM3_REG),
|
||||
self.ad9154.dac_read(AD9154_COMPSUM4_REG), self.ad9154.dac_read(AD9154_COMPSUM5_REG),
|
||||
self.ad9154.dac_read(AD9154_COMPSUM6_REG), self.ad9154.dac_read(AD9154_COMPSUM7_REG))
|
||||
self.p("BADDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_BADDISPARITY))
|
||||
self.p("NITDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_NIT_W))
|
||||
self.p("UNEXPECTEDCONTROL: 0x%02x", self.ad9154.dac_read(AD9154_UNEXPECTEDCONTROL_W))
|
306
artiq/examples/phaser/startup_kernel.py
Normal file
306
artiq/examples/phaser/startup_kernel.py
Normal file
@ -0,0 +1,306 @@
|
||||
from artiq.experiment import *
|
||||
from artiq.coredevice.ad9516_reg import *
|
||||
from artiq.coredevice.ad9154_reg import *
|
||||
|
||||
|
||||
class StartupKernel(EnvExperiment):
|
||||
def build(self):
|
||||
self.setattr_device("core")
|
||||
self.setattr_device("led")
|
||||
self.setattr_device("ad9154")
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
# ad9154 mode 2:
|
||||
# M=4 converters
|
||||
# L=4 lanes
|
||||
# S=1 samples/converter and /frame
|
||||
# F=2 octets/lane and /frame
|
||||
# K=16 frames/multiframe (or 32)
|
||||
# HD=0 high density
|
||||
# N=16 bits/converter
|
||||
# NB=16 bits/sample
|
||||
#
|
||||
# external clk=2000MHz
|
||||
# pclock=250MHz
|
||||
# fdata=500MHz
|
||||
# fline=10GHz
|
||||
# deviceclock_fpga=500MHz
|
||||
# deviceclock_dac=2000MHz
|
||||
self.core.reset()
|
||||
self.ad9154.init()
|
||||
self.clock_setup()
|
||||
self.dac_setup()
|
||||
|
||||
@kernel
|
||||
def clock_setup(self):
|
||||
# reset
|
||||
self.ad9154.clock_write(AD9516_SERIAL_PORT_CONFIGURATION,
|
||||
AD9516_SOFT_RESET | AD9516_SOFT_RESET_MIRRORED |
|
||||
AD9516_LONG_INSTRUCTION | AD9516_LONG_INSTRUCTION_MIRRORED |
|
||||
AD9516_SDO_ACTIVE | AD9516_SDO_ACTIVE_MIRRORED)
|
||||
self.ad9154.clock_write(AD9516_SERIAL_PORT_CONFIGURATION,
|
||||
AD9516_LONG_INSTRUCTION | AD9516_LONG_INSTRUCTION_MIRRORED |
|
||||
AD9516_SDO_ACTIVE | AD9516_SDO_ACTIVE_MIRRORED)
|
||||
if self.ad9154.clock_read(AD9516_PART_ID) != 0x41:
|
||||
return
|
||||
|
||||
# use clk input, dclk=clk/4
|
||||
self.ad9154.clock_write(AD9516_PFD_AND_CHARGE_PUMP, 1*AD9516_PLL_POWER_DOWN |
|
||||
0*AD9516_CHARGE_PUMP_MODE)
|
||||
self.ad9154.clock_write(AD9516_VCO_DIVIDER, 2)
|
||||
self.ad9154.clock_write(AD9516_INPUT_CLKS, 0*AD9516_SELECT_VCO_OR_CLK |
|
||||
0*AD9516_BYPASS_VCO_DIVIDER)
|
||||
|
||||
self.ad9154.clock_write(AD9516_OUT0, 2*AD9516_OUT0_POWER_DOWN)
|
||||
self.ad9154.clock_write(AD9516_OUT2, 2*AD9516_OUT2_POWER_DOWN)
|
||||
self.ad9154.clock_write(AD9516_OUT3, 2*AD9516_OUT3_POWER_DOWN)
|
||||
self.ad9154.clock_write(AD9516_OUT4, 2*AD9516_OUT4_POWER_DOWN)
|
||||
self.ad9154.clock_write(AD9516_OUT5, 2*AD9516_OUT5_POWER_DOWN)
|
||||
self.ad9154.clock_write(AD9516_OUT8, 1*AD9516_OUT8_POWER_DOWN)
|
||||
|
||||
# DAC deviceclk, clk/1
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_0_2, AD9516_DIVIDER_0_DIRECT_TO_OUTPUT)
|
||||
self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN |
|
||||
2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE)
|
||||
|
||||
# FPGA deviceclk, dclk/1
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_1 |
|
||||
AD9516_DIVIDER_4_BYPASS_2)
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*AD9516_DIVIDER_4_DCCOFF)
|
||||
self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT |
|
||||
2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY |
|
||||
0*AD9516_OUT9_SELECT_LVDS_CMOS)
|
||||
|
||||
# sysref f_data*S/(K*F), dclk/32
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_3_0, 15*AD9516_DIVIDER_3_HIGH_CYCLES_1 |
|
||||
15*AD9516_DIVIDER_3_LOW_CYCLES_1)
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 |
|
||||
0*AD9516_DIVIDER_3_PHASE_OFFSET_2)
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_3_3, 0*AD9516_DIVIDER_3_NOSYNC |
|
||||
0*AD9516_DIVIDER_3_BYPASS_1 | 1*AD9516_DIVIDER_3_BYPASS_2)
|
||||
self.ad9154.clock_write(AD9516_DIVIDER_3_4, 1*AD9516_DIVIDER_3_DCCOFF)
|
||||
self.ad9154.clock_write(AD9516_OUT6, 1*AD9516_OUT6_LVDS_OUTPUT_CURRENT |
|
||||
2*AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY |
|
||||
0*AD9516_OUT6_SELECT_LVDS_CMOS)
|
||||
self.ad9154.clock_write(AD9516_OUT7, 1*AD9516_OUT7_LVDS_OUTPUT_CURRENT |
|
||||
2*AD9516_OUT7_LVDS_CMOS_OUTPUT_POLARITY |
|
||||
0*AD9516_OUT7_SELECT_LVDS_CMOS)
|
||||
|
||||
self.ad9154.clock_write(AD9516_UPDATE_ALL_REGISTERS, 1)
|
||||
|
||||
@kernel
|
||||
def dac_setup(self):
|
||||
# reset
|
||||
self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) |
|
||||
AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1))
|
||||
self.ad9154.dac_write(AD9154_SPI_INTFCONFA,
|
||||
AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1))
|
||||
if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) |
|
||||
self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154):
|
||||
return
|
||||
|
||||
self.ad9154.dac_write(AD9154_PWRCNTRL0,
|
||||
AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) |
|
||||
AD9154_PD_DAC2_SET(0) | AD9154_PD_DAC3_SET(0) |
|
||||
AD9154_PD_BG_SET(0))
|
||||
self.ad9154.dac_write(AD9154_TXENMASK1, AD9154_DACA_MASK_SET(0) |
|
||||
AD9154_DACB_MASK_SET(0)) # TX not controlled by TXEN pins
|
||||
self.ad9154.dac_write(AD9154_CLKCFG0,
|
||||
AD9154_REF_CLKDIV_EN_SET(0) | AD9154_RF_SYNC_EN_SET(1) |
|
||||
AD9154_DUTY_EN_SET(1) | AD9154_PD_CLK_REC_SET(0) |
|
||||
AD9154_PD_SERDES_PCLK_SET(0) | AD9154_PD_CLK_DIG_SET(0) |
|
||||
AD9154_PD_CLK23_SET(0) | AD9154_PD_CLK01_SET(0))
|
||||
self.ad9154.dac_write(AD9154_DACPLLCNTRL,
|
||||
AD9154_ENABLE_DACPLL_SET(0) | AD9154_RECAL_DACPLL_SET(0))
|
||||
self.ad9154.dac_write(AD9154_SYSREF_ACTRL0, # jesd204b subclass 1
|
||||
AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) |
|
||||
AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0))
|
||||
|
||||
self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic
|
||||
self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic
|
||||
self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic
|
||||
|
||||
self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual
|
||||
|
||||
self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x
|
||||
self.ad9154.dac_write(AD9154_MIX_MODE, 0)
|
||||
self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16
|
||||
self.ad9154.dac_write(AD9154_DATAPATH_CTRL,
|
||||
AD9154_I_TO_Q_SET(0) | AD9154_SEL_SIDEBAND_SET(0) |
|
||||
AD9154_MODULATION_TYPE_SET(0) | AD9154_PHASE_ADJ_ENABLE_SET(0) |
|
||||
AD9154_DIG_GAIN_ENABLE_SET(0) | AD9154_INVSINC_ENABLE_SET(0))
|
||||
self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN0, 0x00)
|
||||
self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN1, 0x8)
|
||||
self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN0, 0x00)
|
||||
self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN1, 0x8)
|
||||
self.ad9154.dac_write(AD9154_DC_OFFSET_CTRL, 0)
|
||||
self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART0, 0x00)
|
||||
self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART1, 0x00)
|
||||
self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_2PART, 0x00)
|
||||
self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART0, 0x00)
|
||||
self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART1, 0x00)
|
||||
self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_2PART, 0x00)
|
||||
self.ad9154.dac_write(AD9154_PHASE_ADJ0, 0)
|
||||
self.ad9154.dac_write(AD9154_PHASE_ADJ1, 0)
|
||||
self.ad9154.dac_write(AD9154_GROUP_DLY, AD9154_COARSE_GROUP_DELAY_SET(0x8) |
|
||||
AD9154_GROUP_DELAY_RESERVED_SET(0x8))
|
||||
self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_BYP,
|
||||
AD9154_GROUPCOMP_BYPQ_SET(1) |
|
||||
AD9154_GROUPCOMP_BYPI_SET(1))
|
||||
self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_I, 0)
|
||||
self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_Q, 0)
|
||||
self.ad9154.dac_write(AD9154_PDP_AVG_TIME, AD9154_PDP_ENABLE_SET(0))
|
||||
|
||||
self.ad9154.dac_write(AD9154_MASTER_PD, 0)
|
||||
self.ad9154.dac_write(AD9154_PHY_PD, 0x0f) # power down lanes 0-3
|
||||
self.ad9154.dac_write(AD9154_GENERIC_PD,
|
||||
AD9154_PD_SYNCOUT0B_SET(0) |
|
||||
AD9154_PD_SYNCOUT1B_SET(1))
|
||||
self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0,
|
||||
AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) |
|
||||
AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0))
|
||||
self.ad9154.dac_write(AD9154_ILS_DID, 0x00) # device id
|
||||
self.ad9154.dac_write(AD9154_ILS_BID, 0x00) # band id
|
||||
self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id
|
||||
self.ad9154.dac_write(AD9154_ILS_SCR_L, AD9154_L_1_SET(4 - 1) | AD9154_SCR_SET(1))
|
||||
self.ad9154.dac_write(AD9154_ILS_F, 2 - 1)
|
||||
self.ad9154.dac_write(AD9154_ILS_K, 16 - 1)
|
||||
self.ad9154.dac_write(AD9154_ILS_M, 4 - 1)
|
||||
self.ad9154.dac_write(AD9154_ILS_CS_N, AD9154_N_1_SET(16 - 1) | AD9154_CS_SET(0))
|
||||
self.ad9154.dac_write(AD9154_ILS_NP, AD9154_NP_1_SET(16 - 1) |
|
||||
AD9154_SUBCLASSV_SET(1))
|
||||
self.ad9154.dac_write(AD9154_ILS_S, AD9154_S_1_SET(1 - 1) | AD9154_JESDV_SET(1))
|
||||
self.ad9154.dac_write(AD9154_ILS_HD_CF, AD9154_HD_SET(0) | AD9154_CF_SET(0))
|
||||
self.ad9154.dac_write(AD9154_ILS_CHECKSUM,
|
||||
0x00 + 0x00 + 0x00 + 1 + (4 - 1) + # DID BID LID SCR L
|
||||
(2 - 1) + (16 - 1) + (4 - 1) + (16 - 1) + # F K M N
|
||||
1 + (16 - 1) + 1 + (1 - 1) + 0 # SUBC NP JESDV S HD
|
||||
)
|
||||
self.ad9154.dac_write(AD9154_LANEDESKEW, 0xf0)
|
||||
for i in range(8):
|
||||
self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_DIS_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_DIS_SET(1) | AD9154_LANE_ADDR_DIS_SET(i))
|
||||
self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_DIS_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_DIS_SET(0) | AD9154_LANE_ADDR_DIS_SET(i))
|
||||
self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_NIT_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_NIT_SET(1) | AD9154_LANE_ADDR_NIT_SET(i))
|
||||
self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_NIT_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_NIT_SET(0) | AD9154_LANE_ADDR_NIT_SET(i))
|
||||
self.ad9154.dac_write(AD9154_UNEXPECTEDCONTROL_W, AD9154_RST_IRQ_UCC_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_UCC_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_UCC_SET(1) | AD9154_LANE_ADDR_UCC_SET(i))
|
||||
self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) |
|
||||
AD9154_DISABLE_ERR_CNTR_UCC_SET(0) |
|
||||
AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i))
|
||||
self.ad9154.dac_write(AD9154_CTRLREG1, 2) # F
|
||||
self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) |
|
||||
AD9154_THRESHOLD_MASK_EN_SET(0))
|
||||
self.ad9154.dac_write(AD9154_KVAL, 1) # 4*K multiframes during ILAS
|
||||
self.ad9154.dac_write(AD9154_LANEENABLE, 0xf0)
|
||||
|
||||
self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1)
|
||||
self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1)
|
||||
self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1)
|
||||
self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0,
|
||||
AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) |
|
||||
AD9154_ENHALFRATE_SET(1))
|
||||
self.ad9154.dac_write(AD9154_CDR_RESET, 0)
|
||||
self.ad9154.dac_write(AD9154_CDR_RESET, 1)
|
||||
self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO,
|
||||
AD9154_SPI_CDR_OVERSAMP_SET(0x0) |
|
||||
AD9154_SPI_LDO_BYPASS_FILT_SET(1) |
|
||||
AD9154_SPI_LDO_REF_SEL_SET(0))
|
||||
self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic
|
||||
self.ad9154.dac_write(AD9154_LDO_FILTER_2, 0xc9) # magic
|
||||
self.ad9154.dac_write(AD9154_LDO_FILTER_3, 0x0e) # magic
|
||||
self.ad9154.dac_write(AD9154_CP_CURRENT_SPI,
|
||||
AD9154_SPI_CP_CURRENT_SET(0x12) |
|
||||
AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(0))
|
||||
self.ad9154.dac_write(AD9154_VCO_LDO, 0x7b) # magic
|
||||
self.ad9154.dac_write(AD9154_PLL_RD_REG,
|
||||
AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(0) |
|
||||
AD9154_SPI_SERDES_LDO_PD_SET(0) | AD9154_SPI_SYN_PD_SET(0) |
|
||||
AD9154_SPI_VCO_PD_ALC_SET(0) | AD9154_SPI_VCO_PD_PTAT_SET(0) |
|
||||
AD9154_SPI_VCO_PD_SET(0))
|
||||
self.ad9154.dac_write(AD9154_ALC_VARACTOR,
|
||||
AD9154_SPI_VCO_VARACTOR_SET(0x9) |
|
||||
AD9154_SPI_INIT_ALC_VALUE_SET(0x8))
|
||||
self.ad9154.dac_write(AD9154_VCO_OUTPUT,
|
||||
AD9154_SPI_VCO_OUTPUT_LEVEL_SET(0xc) |
|
||||
AD9154_SPI_VCO_OUTPUT_RESERVED_SET(0x4))
|
||||
self.ad9154.dac_write(AD9154_CP_CONFIG,
|
||||
AD9154_SPI_CP_TEST_SET(0) |
|
||||
AD9154_SPI_CP_CAL_EN_SET(1) |
|
||||
AD9154_SPI_CP_FORCE_CALBITS_SET(0) |
|
||||
AD9154_SPI_CP_OFFSET_OFF_SET(0) |
|
||||
AD9154_SPI_CP_ENABLE_MACHINE_SET(1) |
|
||||
AD9154_SPI_CP_DITHER_MODE_SET(0) |
|
||||
AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(0))
|
||||
self.ad9154.dac_write(AD9154_VCO_BIAS_1,
|
||||
AD9154_SPI_VCO_BIAS_REF_SET(0x3) |
|
||||
AD9154_SPI_VCO_BIAS_TCF_SET(0x3))
|
||||
self.ad9154.dac_write(AD9154_VCO_BIAS_2,
|
||||
AD9154_SPI_PRESCALE_BIAS_SET(0x1) |
|
||||
AD9154_SPI_LAST_ALC_EN_SET(1) |
|
||||
AD9154_SPI_PRESCALE_BYPASS_R_SET(0x1) |
|
||||
AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(0) |
|
||||
AD9154_SPI_VCO_BYPASS_DAC_R_SET(0))
|
||||
self.ad9154.dac_write(AD9154_VCO_PD_OVERRIDES,
|
||||
AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(0) |
|
||||
AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(1) |
|
||||
AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(0) |
|
||||
AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(0))
|
||||
self.ad9154.dac_write(AD9154_VCO_CAL,
|
||||
AD9154_SPI_FB_CLOCK_ADV_SET(0x2) |
|
||||
AD9154_SPI_VCO_CAL_COUNT_SET(0x3) |
|
||||
AD9154_SPI_VCO_CAL_ALC_WAIT_SET(0) |
|
||||
AD9154_SPI_VCO_CAL_EN_SET(1))
|
||||
self.ad9154.dac_write(AD9154_CP_LEVEL_DETECT,
|
||||
AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(0x2) |
|
||||
AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(0x5) |
|
||||
AD9154_SPI_CP_LEVEL_DET_PD_SET(0))
|
||||
self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_0,
|
||||
AD9154_SPI_VCO_VARACTOR_OFFSET_SET(0xe) |
|
||||
AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(0x7))
|
||||
self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_1,
|
||||
AD9154_SPI_VCO_VARACTOR_REF_SET(0x6))
|
||||
# ensure link is txing
|
||||
self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL,
|
||||
AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1))
|
||||
self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL,
|
||||
AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0))
|
||||
self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) |
|
||||
AD9154_EQ_POWER_MODE_SET(1))
|
||||
|
||||
self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_1, 1) # subclass 1
|
||||
self.ad9154.dac_write(AD9154_LMFC_DELAY_0, 0)
|
||||
self.ad9154.dac_write(AD9154_LMFC_DELAY_1, 0)
|
||||
self.ad9154.dac_write(AD9154_LMFC_VAR_0, 0x0a) # receive buffer delay
|
||||
self.ad9154.dac_write(AD9154_LMFC_VAR_1, 0x0a)
|
||||
self.ad9154.dac_write(AD9154_SYNC_ERRWINDOW, 0) # +- 1/2 DAC clock
|
||||
self.ad9154.dac_write(AD9154_SYNC_CONTROL,
|
||||
AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(0) |
|
||||
AD9154_SYNCARM_SET(0))
|
||||
self.ad9154.dac_write(AD9154_SYNC_CONTROL,
|
||||
AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) |
|
||||
AD9154_SYNCARM_SET(0))
|
||||
self.ad9154.dac_write(AD9154_SYNC_CONTROL,
|
||||
AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) |
|
||||
AD9154_SYNCARM_SET(1))
|
||||
self.ad9154.dac_write(AD9154_XBAR_LN_0_1,
|
||||
AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6))
|
||||
self.ad9154.dac_write(AD9154_XBAR_LN_2_3,
|
||||
AD9154_LOGICAL_LANE2_SRC_SET(5) | AD9154_LOGICAL_LANE3_SRC_SET(4))
|
||||
self.ad9154.dac_write(AD9154_XBAR_LN_4_5,
|
||||
AD9154_LOGICAL_LANE4_SRC_SET(0) | AD9154_LOGICAL_LANE5_SRC_SET(0))
|
||||
self.ad9154.dac_write(AD9154_XBAR_LN_6_7,
|
||||
AD9154_LOGICAL_LANE6_SRC_SET(0) | AD9154_LOGICAL_LANE7_SRC_SET(0))
|
||||
self.ad9154.dac_write(AD9154_JESD_BIT_INVERSE_CTRL, 0x00)
|
||||
self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0,
|
||||
AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) |
|
||||
AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0))
|
0
artiq/gateware/dsp/__init__.py
Normal file
0
artiq/gateware/dsp/__init__.py
Normal file
112
artiq/gateware/dsp/accu.py
Normal file
112
artiq/gateware/dsp/accu.py
Normal file
@ -0,0 +1,112 @@
|
||||
from migen import *
|
||||
from misoc.interconnect.stream import Endpoint
|
||||
|
||||
|
||||
class Accu(Module):
|
||||
def __init__(self, width, meta=[]):
|
||||
self.i = Endpoint([("p", width), ("f", width), ("clr", 1)])
|
||||
self.o = Endpoint([("z", width)])
|
||||
self.latency = 1
|
||||
|
||||
###
|
||||
|
||||
f = Signal.like(self.i.f)
|
||||
p = Signal.like(self.i.p)
|
||||
self.comb += self.i.ack.eq(~self.o.stb | self.o.ack)
|
||||
self.sync += [
|
||||
If(self.o.ack,
|
||||
self.o.stb.eq(0),
|
||||
),
|
||||
If(self.i.ack,
|
||||
self.o.stb.eq(1),
|
||||
If(self.i.stb,
|
||||
self.o.z.eq(self.i.p + Mux(self.i.clr, 0, self.o.z + p)),
|
||||
f.eq(self.i.f),
|
||||
p.eq(self.i.f - self.i.p),
|
||||
).Else(
|
||||
self.o.z.eq(self.o.z + f),
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class MCM(Module):
|
||||
def __init__(self, width, constants):
|
||||
n = len(constants)
|
||||
self.i = i = Signal(width)
|
||||
self.o = o = [Signal.like(self.i) for i in range(n)]
|
||||
|
||||
###
|
||||
|
||||
# TODO: improve MCM
|
||||
assert range(n) == constants
|
||||
assert n <= 9
|
||||
|
||||
if n > 0:
|
||||
self.comb += o[0].eq(0)
|
||||
if n > 1:
|
||||
self.comb += o[1].eq(i)
|
||||
if n > 2:
|
||||
self.comb += o[2].eq(i << 1)
|
||||
if n > 3:
|
||||
self.comb += o[3].eq(i + (i << 1))
|
||||
if n > 4:
|
||||
self.comb += o[4].eq(i << 2)
|
||||
if n > 5:
|
||||
self.comb += o[5].eq(i + (i << 2))
|
||||
if n > 6:
|
||||
self.comb += o[6].eq(o[3] << 1)
|
||||
if n > 7:
|
||||
self.comb += o[7].eq((i << 3) - i)
|
||||
if n > 8:
|
||||
self.comb += o[8].eq(i << 3)
|
||||
|
||||
|
||||
class PhasedAccu(Module):
|
||||
def __init__(self, width, parallelism=8):
|
||||
self.i = Endpoint([("p", width), ("f", width), ("clr", 1)])
|
||||
self.o = Endpoint([("z{}".format(i), width) for i in
|
||||
range(parallelism)])
|
||||
self.parallelism = parallelism
|
||||
self.latency = 2
|
||||
|
||||
###
|
||||
|
||||
a = MCM(width, range(parallelism + 1))
|
||||
self.submodules += a
|
||||
z = [Signal(width) for i in range(parallelism)]
|
||||
o = self.o.payload.flatten()
|
||||
load = Signal()
|
||||
clr = Signal()
|
||||
p = Signal.like(self.i.p)
|
||||
f = Signal.like(self.i.f)
|
||||
fp = Signal.like(self.i.f)
|
||||
self.comb += [
|
||||
self.i.ack.eq(self.o.ack),
|
||||
a.i.eq(self.i.f),
|
||||
]
|
||||
|
||||
self.sync += [
|
||||
If(self.o.ack,
|
||||
self.o.stb.eq(0),
|
||||
),
|
||||
If(~self.o.stb | self.o.ack,
|
||||
self.o.stb.eq(1),
|
||||
If(load,
|
||||
load.eq(0),
|
||||
[oi.eq(Mux(clr, 0, o[0] + fp) + zi)
|
||||
for oi, zi in zip(o, z)],
|
||||
fp.eq(f),
|
||||
).Else(
|
||||
[oi.eq(oi + fp) for oi in o],
|
||||
),
|
||||
),
|
||||
If(self.i.stb & self.i.ack,
|
||||
[zi.eq(self.i.p - Mux(self.i.clr, 0, p) + aoi)
|
||||
for zi, aoi in zip(z, a.o)],
|
||||
clr.eq(self.i.clr),
|
||||
p.eq(self.i.p),
|
||||
f.eq(a.o[parallelism]),
|
||||
load.eq(1),
|
||||
),
|
||||
]
|
358
artiq/gateware/dsp/cordic.py
Normal file
358
artiq/gateware/dsp/cordic.py
Normal file
@ -0,0 +1,358 @@
|
||||
# Copyright 2014-2015 Robert Jordens <jordens@gmail.com>
|
||||
#
|
||||
# This file is part of redpid.
|
||||
#
|
||||
# redpid is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redpid is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redpid. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from math import atan, atanh, log, sqrt, pi
|
||||
|
||||
from migen import *
|
||||
|
||||
|
||||
class TwoQuadrantCordic(Module):
|
||||
"""Coordinate rotation digital computer
|
||||
|
||||
Trigonometric, and arithmetic functions implemented using
|
||||
additions/subtractions and shifts.
|
||||
|
||||
http://eprints.soton.ac.uk/267873/1/tcas1_cordic_review.pdf
|
||||
|
||||
http://www.andraka.com/files/crdcsrvy.pdf
|
||||
|
||||
http://zatto.free.fr/manual/Volder_CORDIC.pdf
|
||||
|
||||
The way the CORDIC is executed is controlled by `eval_mode`.
|
||||
If `"iterative"` the stages are iteratively evaluated, one per clock
|
||||
cycle. This mode uses the least amount of registers, but has the
|
||||
lowest throughput and highest latency. If `"pipelined"` all stages
|
||||
are executed in every clock cycle but separated by registers. This
|
||||
mode has full throughput but uses many registers and has large
|
||||
latency. If `"combinatorial"`, there are no registers, throughput is
|
||||
maximal and latency is zero. `"pipelined"` and `"combinatorial"` use
|
||||
the same number of shifters and adders.
|
||||
|
||||
The type of trigonometric/arithmetic function is determined by
|
||||
`cordic_mode` and `func_mode`. :math:`g` is the gain of the CORDIC.
|
||||
|
||||
* rotate-circular: rotate the vector `(xi, yi)` by an angle `zi`.
|
||||
Used to calculate trigonometric functions, `sin(), cos(),
|
||||
tan() = sin()/cos()`, or to perform polar-to-cartesian coordinate
|
||||
transformation:
|
||||
|
||||
.. math::
|
||||
x_o = g \\cos(z_i) x_i - g \\sin(z_i) y_i
|
||||
|
||||
y_o = g \\sin(z_i) x_i + g \\cos(z_i) y_i
|
||||
|
||||
* vector-circular: determine length and angle of the vector
|
||||
`(xi, yi)`. Used to calculate `arctan(), sqrt()` or
|
||||
to perform cartesian-to-polar transformation:
|
||||
|
||||
.. math::
|
||||
x_o = g\\sqrt{x_i^2 + y_i^2}
|
||||
|
||||
z_o = z_i + \\tan^{-1}(y_i/x_i)
|
||||
|
||||
* rotate-hyperbolic: hyperbolic functions of `zi`. Used to
|
||||
calculate hyperbolic functions, `sinh, cosh, tanh = cosh/sinh,
|
||||
exp = cosh + sinh`:
|
||||
|
||||
.. math::
|
||||
x_o = g \\cosh(z_i) x_i + g \\sinh(z_i) y_i
|
||||
|
||||
y_o = g \\sinh(z_i) x_i + g \\cosh(z_i) z_i
|
||||
|
||||
* vector-hyperbolic: natural logarithm `ln(), arctanh()`, and
|
||||
`sqrt()`. Use `x_i = a + b` and `y_i = a - b` to obtain `2*
|
||||
sqrt(a*b)` and `ln(a/b)/2`:
|
||||
|
||||
.. math::
|
||||
x_o = g\\sqrt{x_i^2 - y_i^2}
|
||||
|
||||
z_o = z_i + \\tanh^{-1}(y_i/x_i)
|
||||
|
||||
* rotate-linear: multiply and accumulate (not a very good
|
||||
multiplier implementation):
|
||||
|
||||
.. math::
|
||||
y_o = g(y_i + x_i z_i)
|
||||
|
||||
* vector-linear: divide and accumulate:
|
||||
|
||||
.. math::
|
||||
z_o = g(z_i + y_i/x_i)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
width : int
|
||||
Bit width of the input and output signals. Defaults to 16. Input
|
||||
and output signals are signed.
|
||||
widthz : int
|
||||
Bit with of `zi` and `zo`. Defaults to the `width`.
|
||||
stages : int or None
|
||||
Number of CORDIC incremental rotation stages. Defaults to
|
||||
`width + min(1, guard)`.
|
||||
guard : int or None
|
||||
Add guard bits to the intermediate signals. If `None`,
|
||||
defaults to `guard = log2(width)` which guarantees accuracy
|
||||
to `width` bits.
|
||||
eval_mode : str, {"iterative", "pipelined", "combinatorial"}
|
||||
cordic_mode : str, {"rotate", "vector"}
|
||||
func_mode : str, {"circular", "linear", "hyperbolic"}
|
||||
Evaluation and arithmetic mode. See above.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
xi, yi, zi : Signal(width), in
|
||||
Input values, signed.
|
||||
xo, yo, zo : Signal(width), out
|
||||
Output values, signed.
|
||||
new_out : Signal(1), out
|
||||
Asserted if output values are freshly updated in the current
|
||||
cycle.
|
||||
new_in : Signal(1), out
|
||||
Asserted if new input values are being read in the next cycle.
|
||||
zmax : float
|
||||
`zi` and `zo` normalization factor. Floating point `zmax`
|
||||
corresponds to `1<<(widthz - 1)`. `x` and `y` are scaled such
|
||||
that floating point `1` corresponds to `1<<(width - 1)`.
|
||||
gain : float
|
||||
Cumulative, intrinsic gain and scaling factor. In circular mode
|
||||
`sqrt(xi**2 + yi**2)` should be no larger than `2**(width - 1)/gain`
|
||||
to prevent overflow. Additionally, in hyperbolic and linear mode,
|
||||
the operation itself can cause overflow.
|
||||
interval : int
|
||||
Output interval in clock cycles. Inverse throughput.
|
||||
latency : int
|
||||
Input-to-output latency. The result corresponding to the inputs
|
||||
appears at the outputs `latency` cycles later.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Each stage `i` in the CORDIC performs the following operation:
|
||||
|
||||
.. math::
|
||||
x_{i+1} = x_i - m d_i y_i r^{-s_{m,i}},
|
||||
|
||||
y_{i+1} = y_i + d_i x_i r^{-s_{m,i}},
|
||||
|
||||
z_{i+1} = z_i - d_i a_{m,i},
|
||||
|
||||
where:
|
||||
|
||||
* :math:`d_i`: clockwise or counterclockwise, determined by
|
||||
`sign(z_i)` in rotate mode or `sign(-y_i)` in vector mode.
|
||||
|
||||
* :math:`r`: radix of the number system (2)
|
||||
|
||||
* :math:`m`: 1: circular, 0: linear, -1: hyperbolic
|
||||
|
||||
* :math:`s_{m,i}`: non decreasing integer shift sequence
|
||||
|
||||
* :math:`a_{m,i}`: elemetary rotation angle: :math:`a_{m,i} =
|
||||
\\tan^{-1}(\\sqrt{m} s_{m,i})/\\sqrt{m}`.
|
||||
"""
|
||||
def __init__(self, width=16, widthz=None, stages=None, guard=0,
|
||||
eval_mode="iterative", cordic_mode="rotate",
|
||||
func_mode="circular"):
|
||||
# validate parameters
|
||||
assert eval_mode in ("combinatorial", "pipelined", "iterative")
|
||||
assert cordic_mode in ("rotate", "vector")
|
||||
assert func_mode in ("circular", "linear", "hyperbolic")
|
||||
self.cordic_mode = cordic_mode
|
||||
self.func_mode = func_mode
|
||||
if guard is None:
|
||||
# guard bits to guarantee "width" accuracy
|
||||
guard = int(log(width)/log(2))
|
||||
if widthz is None:
|
||||
widthz = width
|
||||
if stages is None:
|
||||
stages = width + min(1, guard) # cuts error below LSB
|
||||
|
||||
# input output interface
|
||||
self.xi = Signal((width, True))
|
||||
self.yi = Signal((width, True))
|
||||
self.zi = Signal((widthz, True))
|
||||
self.xo = Signal((width, True))
|
||||
self.yo = Signal((width, True))
|
||||
self.zo = Signal((widthz, True))
|
||||
self.new_in = Signal()
|
||||
self.new_out = Signal()
|
||||
|
||||
###
|
||||
|
||||
a, s, self.zmax, self.gain = self._constants(stages, widthz + guard)
|
||||
stages = len(a) # may have increased due to repetitions
|
||||
|
||||
if eval_mode == "iterative":
|
||||
num_sig = 3
|
||||
self.interval = stages + 1
|
||||
self.latency = stages + 2
|
||||
else:
|
||||
num_sig = stages + 1
|
||||
self.interval = 1
|
||||
if eval_mode == "pipelined":
|
||||
self.latency = stages
|
||||
else: # combinatorial
|
||||
self.latency = 0
|
||||
|
||||
# inter-stage signals
|
||||
x = [Signal((width + guard, True)) for i in range(num_sig)]
|
||||
y = [Signal((width + guard, True)) for i in range(num_sig)]
|
||||
z = [Signal((widthz + guard, True)) for i in range(num_sig)]
|
||||
|
||||
# hook up inputs and outputs to the first and last inter-stage
|
||||
# signals
|
||||
self.comb += [
|
||||
x[0].eq(self.xi << guard),
|
||||
y[0].eq(self.yi << guard),
|
||||
z[0].eq(self.zi << guard),
|
||||
self.xo.eq(x[-1] >> guard),
|
||||
self.yo.eq(y[-1] >> guard),
|
||||
self.zo.eq(z[-1] >> guard),
|
||||
]
|
||||
|
||||
if eval_mode == "iterative":
|
||||
# We afford one additional iteration for in/out.
|
||||
i = Signal(max=stages + 1)
|
||||
self.comb += [
|
||||
self.new_in.eq(i == stages),
|
||||
self.new_out.eq(i == 1),
|
||||
]
|
||||
ai = Signal((widthz + guard, True))
|
||||
self.sync += ai.eq(Array(a)[i])
|
||||
if range(stages) == s:
|
||||
si = i - 1 # shortcut if no stage repetitions
|
||||
else:
|
||||
si = Signal(max=stages + 1)
|
||||
self.sync += si.eq(Array(s)[i])
|
||||
xi, yi, zi = x[1], y[1], z[1]
|
||||
self.sync += [
|
||||
self._stage(xi, yi, zi, xi, yi, zi, si, ai),
|
||||
i.eq(i + 1),
|
||||
If(i == stages,
|
||||
i.eq(0),
|
||||
),
|
||||
If(i == 0,
|
||||
x[2].eq(xi), y[2].eq(yi), z[2].eq(zi),
|
||||
xi.eq(x[0]), yi.eq(y[0]), zi.eq(z[0]),
|
||||
)
|
||||
]
|
||||
else:
|
||||
self.comb += [
|
||||
self.new_out.eq(1),
|
||||
self.new_in.eq(1),
|
||||
]
|
||||
for i, si in enumerate(s):
|
||||
stmt = self._stage(x[i], y[i], z[i],
|
||||
x[i + 1], y[i + 1], z[i + 1],
|
||||
si, a[i])
|
||||
if eval_mode == "pipelined":
|
||||
self.sync += stmt
|
||||
else: # combinatorial
|
||||
self.comb += stmt
|
||||
|
||||
def _constants(self, stages, bits):
|
||||
if self.func_mode == "circular":
|
||||
s = range(stages)
|
||||
a = [atan(2**-i) for i in s]
|
||||
g = [sqrt(1 + 2**(-2*i)) for i in s]
|
||||
#zmax = sum(a)
|
||||
# use pi anyway as the input z can cause overflow
|
||||
# and we need the range for quadrant mapping
|
||||
zmax = pi
|
||||
elif self.func_mode == "linear":
|
||||
s = range(stages)
|
||||
a = [2**-i for i in s]
|
||||
g = [1 for i in s]
|
||||
#zmax = sum(a)
|
||||
# use 2 anyway as this simplifies a and scaling
|
||||
zmax = 2.
|
||||
else: # hyperbolic
|
||||
s = []
|
||||
# need to repeat some stages:
|
||||
j = 4
|
||||
for i in range(stages):
|
||||
if i == j:
|
||||
s.append(j)
|
||||
j = 3*j + 1
|
||||
s.append(i + 1)
|
||||
a = [atanh(2**-i) for i in s]
|
||||
g = [sqrt(1 - 2**(-2*i)) for i in s]
|
||||
zmax = sum(a)*2
|
||||
# round here helps the width=2**i - 1 case but hurts the
|
||||
# important width=2**i case
|
||||
cast = int
|
||||
if log(bits)/log(2) % 1:
|
||||
cast = round
|
||||
a = [cast(ai*2**(bits - 1)/zmax) for ai in a]
|
||||
gain = 1.
|
||||
for gi in g:
|
||||
gain *= gi
|
||||
return a, s, zmax, gain
|
||||
|
||||
def _stage(self, xi, yi, zi, xo, yo, zo, i, ai):
|
||||
dir = Signal()
|
||||
if self.cordic_mode == "rotate":
|
||||
self.comb += dir.eq(zi < 0)
|
||||
else: # vector
|
||||
self.comb += dir.eq(yi >= 0)
|
||||
dx = yi >> i
|
||||
dy = xi >> i
|
||||
dz = ai
|
||||
if self.func_mode == "linear":
|
||||
dx = 0
|
||||
elif self.func_mode == "hyperbolic":
|
||||
dx = -dx
|
||||
stmt = [
|
||||
xo.eq(xi + Mux(dir, dx, -dx)),
|
||||
yo.eq(yi + Mux(dir, -dy, dy)),
|
||||
zo.eq(zi + Mux(dir, dz, -dz))
|
||||
]
|
||||
return stmt
|
||||
|
||||
|
||||
class Cordic(TwoQuadrantCordic):
|
||||
"""Four-quadrant CORDIC
|
||||
|
||||
Same as :class:`TwoQuadrantCordic` but with support and convergence
|
||||
for `abs(zi) > pi/2 in circular rotate mode or `xi < 0` in circular
|
||||
vector mode.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
TwoQuadrantCordic.__init__(self, **kwargs)
|
||||
if self.func_mode != "circular":
|
||||
return # no need to remap quadrants
|
||||
|
||||
cxi, cyi, czi = self.xi, self.yi, self.zi
|
||||
self.xi = xi = Signal.like(cxi)
|
||||
self.yi = yi = Signal.like(cyi)
|
||||
self.zi = zi = Signal.like(czi)
|
||||
|
||||
###
|
||||
|
||||
q = Signal()
|
||||
if self.cordic_mode == "rotate":
|
||||
self.comb += q.eq(zi[-2] ^ zi[-1])
|
||||
else: # vector
|
||||
self.comb += q.eq(xi < 0)
|
||||
self.comb += [
|
||||
If(q,
|
||||
Cat(cxi, cyi, czi).eq(
|
||||
Cat(-xi, -yi, zi + (1 << len(zi) - 1)))
|
||||
).Else(
|
||||
Cat(cxi, cyi, czi).eq(Cat(xi, yi, zi))
|
||||
)
|
||||
]
|
67
artiq/gateware/dsp/sawg.py
Normal file
67
artiq/gateware/dsp/sawg.py
Normal file
@ -0,0 +1,67 @@
|
||||
from migen import *
|
||||
from misoc.interconnect.stream import Endpoint
|
||||
|
||||
from .cordic import Cordic
|
||||
from .accu import PhasedAccu
|
||||
from .tools import eqh
|
||||
|
||||
|
||||
class DDSFast(Module):
|
||||
def __init__(self, width, parallelism=4):
|
||||
a_width = width
|
||||
p_width = width
|
||||
f_width = 2*width
|
||||
|
||||
self.o = [Signal((width, True)) for i in range(parallelism)]
|
||||
|
||||
self.width = width
|
||||
self.parallelism = parallelism
|
||||
self.latency = 1 # will be accumulated
|
||||
|
||||
q = PhasedAccu(f_width, parallelism)
|
||||
self.submodules += q
|
||||
self.latency += q.latency
|
||||
|
||||
self.a = Endpoint([("a", a_width)])
|
||||
self.f = Endpoint([("f", f_width)])
|
||||
self.p = Endpoint([("p", p_width)])
|
||||
self.i = [self.a, self.f, self.p]
|
||||
|
||||
###
|
||||
|
||||
a = Signal.like(self.a.a)
|
||||
self.sync += [
|
||||
If(self.a.stb,
|
||||
a.eq(self.a.a)
|
||||
),
|
||||
If(self.f.stb,
|
||||
eqh(q.i.f, self.f.f)
|
||||
),
|
||||
If(self.p.stb,
|
||||
eqh(q.i.p, self.p.p)
|
||||
),
|
||||
q.i.stb.eq(self.f.stb | self.p.stb),
|
||||
]
|
||||
self.comb += [
|
||||
self.a.ack.eq(1),
|
||||
self.f.ack.eq(1),
|
||||
self.p.ack.eq(1),
|
||||
q.o.ack.eq(1),
|
||||
q.i.clr.eq(0),
|
||||
]
|
||||
|
||||
c = []
|
||||
for i in range(parallelism):
|
||||
ci = Cordic(width=width, widthz=p_width,
|
||||
guard=None, eval_mode="pipelined")
|
||||
self.submodules += ci
|
||||
c.append(ci)
|
||||
qoi = getattr(q.o, "z{}".format(i))
|
||||
self.comb += [
|
||||
eqh(ci.xi, a),
|
||||
ci.yi.eq(0),
|
||||
eqh(ci.zi, qoi),
|
||||
eqh(self.o[i], ci.xo),
|
||||
]
|
||||
self.latency += c[0].latency
|
||||
self.gain = c[0].gain
|
50
artiq/gateware/dsp/tools.py
Normal file
50
artiq/gateware/dsp/tools.py
Normal file
@ -0,0 +1,50 @@
|
||||
from migen import *
|
||||
|
||||
|
||||
def set_dict(e, **k):
|
||||
for k, v in k.items():
|
||||
if isinstance(v, dict):
|
||||
yield from set_dict(getattr(e, k), **v)
|
||||
else:
|
||||
yield getattr(e, k).eq(v)
|
||||
|
||||
|
||||
def xfer(dut, **kw):
|
||||
ep = []
|
||||
for e, v in kw.items():
|
||||
e = getattr(dut, e)
|
||||
yield from set_dict(e, **v)
|
||||
ep.append(e)
|
||||
for e in ep:
|
||||
yield e.stb.eq(1)
|
||||
while ep:
|
||||
yield
|
||||
for e in ep[:]:
|
||||
if hasattr(e, "busy") and (yield e.busy):
|
||||
raise ValueError(e, "busy")
|
||||
if not hasattr(e, "ack") or (yield e.ack):
|
||||
yield e.stb.eq(0)
|
||||
ep.remove(e)
|
||||
|
||||
|
||||
def eqh(a, b):
|
||||
return a[-len(b):].eq(b[-len(a):])
|
||||
|
||||
|
||||
def szip(*iters):
|
||||
active = {it: None for it in iters}
|
||||
while active:
|
||||
for it in list(active):
|
||||
while True:
|
||||
try:
|
||||
val = it.send(active[it])
|
||||
except StopIteration:
|
||||
del active[it]
|
||||
break
|
||||
if val is None:
|
||||
break
|
||||
else:
|
||||
active[it] = (yield val)
|
||||
val = (yield None)
|
||||
for it in active:
|
||||
active[it] = val
|
71
artiq/gateware/phaser.py
Normal file
71
artiq/gateware/phaser.py
Normal file
@ -0,0 +1,71 @@
|
||||
from migen.build.generic_platform import *
|
||||
|
||||
|
||||
fmc_adapter_io = [
|
||||
("ad9154_spi", 0,
|
||||
# AD9154 should give control of SPI to FMC when USB cable is unplugged,
|
||||
# It's the case, but the PIC18F24J50 is introducing noise on SPI SCK
|
||||
# (???) To workaround that, add 2 jumpers:
|
||||
# - on XP1, between pin 5 and 6 (will keep the PIC in reset)
|
||||
# - on JP3 (will force output enable on FXLA108)
|
||||
Subsignal("clk", Pins("HPC:LA03_P")),
|
||||
Subsignal("cs_n", Pins("HPC:LA04_N", "HPC:LA05_P")),
|
||||
Subsignal("mosi", Pins("HPC:LA03_N")),
|
||||
Subsignal("miso", Pins("HPC:LA04_P")),
|
||||
Subsignal("en", Pins("HPC:LA05_N")),
|
||||
IOStandard("LVTTL"),
|
||||
),
|
||||
("ad9154_txen", 0, Pins("HPC:LA07_P"), IOStandard("LVTTL")),
|
||||
("ad9154_txen", 1, Pins("HPC:LA07_N"), IOStandard("LVTTL")),
|
||||
("ad9154_refclk", 0,
|
||||
Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")),
|
||||
Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")),
|
||||
),
|
||||
("ad9154_sysref", 0,
|
||||
Subsignal("p", Pins("HPC:LA00_CC_P")),
|
||||
Subsignal("n", Pins("HPC:LA00_CC_N")),
|
||||
IOStandard("LVDS_25"),
|
||||
),
|
||||
("ad9154_sync", 0,
|
||||
Subsignal("p", Pins("HPC:LA01_CC_P")),
|
||||
Subsignal("n", Pins("HPC:LA01_CC_N")),
|
||||
IOStandard("LVDS_25"),
|
||||
),
|
||||
("ad9154_sync", 1,
|
||||
Subsignal("p", Pins("HPC:LA02_P")),
|
||||
Subsignal("n", Pins("HPC:LA02_N")),
|
||||
IOStandard("LVDS_25"),
|
||||
),
|
||||
("ad9154_jesd", 0, # AD9154's SERIND7
|
||||
Subsignal("txp", Pins("HPC:DP0_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP0_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 1, # AD9154's SERIND6
|
||||
Subsignal("txp", Pins("HPC:DP1_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP1_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 2, # AD9154's SERIND5
|
||||
Subsignal("txp", Pins("HPC:DP2_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP2_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 3, # AD9154's SERIND4
|
||||
Subsignal("txp", Pins("HPC:DP3_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP3_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 4, # AD9154's SERIND2
|
||||
Subsignal("txp", Pins("HPC:DP4_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP4_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 5, # AD9154's SERIND0
|
||||
Subsignal("txp", Pins("HPC:DP5_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP5_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 6, # AD9154's SERIND1
|
||||
Subsignal("txp", Pins("HPC:DP6_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP6_C2M_N"))
|
||||
),
|
||||
("ad9154_jesd", 7, # AD9154's SERIND3
|
||||
Subsignal("txp", Pins("HPC:DP7_C2M_P")),
|
||||
Subsignal("txn", Pins("HPC:DP7_C2M_N"))
|
||||
),
|
||||
]
|
27
artiq/gateware/rtio/phy/sawg.py
Normal file
27
artiq/gateware/rtio/phy/sawg.py
Normal file
@ -0,0 +1,27 @@
|
||||
from collections import namedtuple
|
||||
|
||||
from migen import *
|
||||
from artiq.gateware.rtio import rtlink
|
||||
|
||||
from artiq.gateware.dsp.sawg import DDSFast
|
||||
|
||||
|
||||
_Phy = namedtuple("Phy", "rtlink probes overrides")
|
||||
|
||||
DDSFast_rtio = ClockDomainsRenamer("rio_phy")(DDSFast)
|
||||
|
||||
|
||||
class Channel(DDSFast_rtio):
|
||||
def __init__(self, *args, **kwargs):
|
||||
DDSFast_rtio.__init__(self, *args, **kwargs)
|
||||
self.phys = []
|
||||
for i in self.i:
|
||||
rl = rtlink.Interface(rtlink.OInterface(len(i.payload)))
|
||||
self.comb += [
|
||||
i.stb.eq(rl.o.stb),
|
||||
rl.o.busy.eq(~i.ack),
|
||||
Cat(i.payload.flatten()).eq(rl.o.data),
|
||||
]
|
||||
# no probes, overrides
|
||||
self.phys.append(_Phy(rl, [], []))
|
||||
self.phys_names = dict(zip("afp", self.phys))
|
@ -9,17 +9,20 @@ from migen.build.generic_platform import *
|
||||
from migen.build.xilinx.vivado import XilinxVivadoToolchain
|
||||
from migen.build.xilinx.ise import XilinxISEToolchain
|
||||
from migen.fhdl.specials import Keep
|
||||
from migen.genlib.io import DifferentialInput
|
||||
|
||||
from misoc.interconnect.csr import *
|
||||
from misoc.interconnect import wishbone
|
||||
from misoc.cores import gpio
|
||||
from misoc.cores import spi as spi_csr
|
||||
from misoc.integration.soc_core import mem_decoder
|
||||
from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict
|
||||
from misoc.integration.builder import builder_args, builder_argdict
|
||||
|
||||
from artiq.gateware.soc import AMPSoC, build_artiq_soc
|
||||
from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2
|
||||
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi
|
||||
from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2, phaser
|
||||
from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series,
|
||||
dds, spi, sawg)
|
||||
from artiq import __version__ as artiq_version
|
||||
|
||||
|
||||
@ -138,8 +141,8 @@ class _NIST_Ions(MiniSoC, AMPSoC):
|
||||
self.register_kernel_cpu_csrdevice("i2c")
|
||||
self.config["I2C_BUS_COUNT"] = 1
|
||||
|
||||
def add_rtio(self, rtio_channels):
|
||||
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
|
||||
def add_rtio(self, rtio_channels, crg=_RTIOCRG):
|
||||
self.submodules.rtio_crg = crg(self.platform, self.crg.cd_sys.clk)
|
||||
self.csr_devices.append("rtio_crg")
|
||||
self.submodules.rtio = rtio.RTIO(rtio_channels)
|
||||
self.register_kernel_cpu_csrdevice("rtio")
|
||||
@ -380,6 +383,135 @@ class NIST_QC2(_NIST_Ions):
|
||||
self.config["DDS_RTIO_CLK_RATIO"] = 24 >> self.rtio.fine_ts_width
|
||||
|
||||
|
||||
class _PhaserCRG(Module, AutoCSR):
|
||||
def __init__(self, platform, rtio_internal_clk):
|
||||
rtio_internal_clk = ClockSignal("sys4x")
|
||||
|
||||
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)
|
||||
|
||||
refclk_pads = platform.request("ad9154_refclk")
|
||||
platform.add_period_constraint(refclk_pads.p, 2.)
|
||||
refclk = Signal()
|
||||
refclk = Signal()
|
||||
self.clock_domains.cd_refclk = ClockDomain()
|
||||
self.specials += [
|
||||
Instance("IBUFDS_GTE2", i_CEB=0,
|
||||
i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk),
|
||||
Instance("BUFG", i_I=refclk, o_O=self.cd_refclk.clk),
|
||||
]
|
||||
|
||||
pll_locked = Signal()
|
||||
rtio_clk = Signal()
|
||||
rtiox4_clk = Signal()
|
||||
self.specials += [
|
||||
Instance("PLLE2_ADV",
|
||||
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
|
||||
|
||||
p_REF_JITTER1=0.01, p_REF_JITTER2=0.01,
|
||||
p_CLKIN1_PERIOD=2.0, p_CLKIN2_PERIOD=2.0,
|
||||
i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk,
|
||||
# Warning: CLKINSEL=0 means CLKIN2 is selected
|
||||
i_CLKINSEL=~self._clock_sel.storage,
|
||||
|
||||
# VCO @ 1GHz when using 500MHz input
|
||||
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=4,
|
||||
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,
|
||||
),
|
||||
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
|
||||
Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
|
||||
|
||||
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
|
||||
MultiReg(pll_locked, self._pll_locked.status)
|
||||
]
|
||||
|
||||
|
||||
class Phaser(_NIST_Ions):
|
||||
mem_map = {"ad9154_spi": 0x18000000}
|
||||
mem_map.update(_NIST_Ions.mem_map)
|
||||
|
||||
def __init__(self, cpu_type="or1k", **kwargs):
|
||||
_NIST_Ions.__init__(self, cpu_type, **kwargs)
|
||||
|
||||
platform = self.platform
|
||||
platform.add_extension(phaser.fmc_adapter_io)
|
||||
|
||||
sysref_pads = platform.request("ad9154_sysref")
|
||||
#sysref = Signal()
|
||||
#self.specials += DifferentialInput(
|
||||
# sysref_pads.p, sysref_pads.n, sysref)
|
||||
sync_pads = platform.request("ad9154_sync")
|
||||
#sync = Signal()
|
||||
#self.specials += DifferentialInput(
|
||||
# sync_pads.p, sync_pads.n, sync)
|
||||
|
||||
#for i in range(4):
|
||||
# jesd_pads = platform.request("ad9154_jesd", i)
|
||||
|
||||
rtio_channels = []
|
||||
|
||||
phy = ttl_serdes_7series.Inout_8X(
|
||||
platform.request("user_sma_gpio_n_33"))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=128))
|
||||
|
||||
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||
|
||||
phy = ttl_serdes_7series.Input_8X(sysref_pads.p, sysref_pads.n)
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
||||
ofifo_depth=2))
|
||||
|
||||
phy = ttl_serdes_7series.Input_8X(sync_pads.p, sync_pads.n)
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32,
|
||||
ofifo_depth=2))
|
||||
|
||||
self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels)
|
||||
|
||||
ad9154_spi = self.platform.request("ad9154_spi")
|
||||
self.submodules.ad9154_spi = spi_csr.SPIMaster(ad9154_spi)
|
||||
self.register_kernel_cpu_csrdevice("ad9154_spi")
|
||||
self.config["AD9154_DAC_CS"] = 1 << 0
|
||||
self.config["AD9154_CLK_CS"] = 1 << 1
|
||||
self.comb += [
|
||||
ad9154_spi.en.eq(1),
|
||||
self.platform.request("ad9154_txen", 0).eq(1),
|
||||
self.platform.request("ad9154_txen", 1).eq(1),
|
||||
]
|
||||
|
||||
self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels)
|
||||
sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)]
|
||||
self.submodules += sawgs
|
||||
|
||||
# TODO: dummy, hookup jesd204b phy here
|
||||
o = Signal((16, True))
|
||||
for ch in sawgs: # gather up dangling outputs
|
||||
for oi in ch.o:
|
||||
o0, o = o, Signal.like(o)
|
||||
self.sync += o.eq(o0 + oi)
|
||||
self.sync.rio_phy += platform.request("user_led").eq(o[-1])
|
||||
|
||||
rtio_channels.extend(rtio.Channel.from_phy(phy)
|
||||
for sawg in sawgs
|
||||
for phy in sawg.phys)
|
||||
|
||||
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
|
||||
rtio_channels.append(rtio.LogChannel())
|
||||
self.add_rtio(rtio_channels, _PhaserCRG)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="ARTIQ core device builder / KC705 "
|
||||
@ -388,7 +520,7 @@ def main():
|
||||
soc_kc705_args(parser)
|
||||
parser.add_argument("-H", "--hw-adapter", default="nist_clock",
|
||||
help="hardware adapter type: "
|
||||
"nist_qc1/nist_clock/nist_qc2 "
|
||||
"nist_qc1/nist_clock/nist_qc2/phaser "
|
||||
"(default: %(default)s)")
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -399,6 +531,8 @@ def main():
|
||||
cls = NIST_CLOCK
|
||||
elif hw_adapter == "nist_qc2":
|
||||
cls = NIST_QC2
|
||||
elif hw_adapter == "phaser":
|
||||
cls = Phaser
|
||||
else:
|
||||
raise SystemExit("Invalid hardware adapter string (-H/--hw-adapter)")
|
||||
|
||||
|
@ -7,7 +7,7 @@ OBJECTS := isr.o clock.o rtiocrg.o flash_storage.o mailbox.o \
|
||||
session.o log.o analyzer.o moninj.o net_server.o bridge_ctl.o \
|
||||
ksupport_data.o kloader.o test_mode.o main.o
|
||||
OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \
|
||||
bridge.o rtio.o dds.o i2c.o
|
||||
bridge.o rtio.o dds.o i2c.o ad9154.o
|
||||
|
||||
CFLAGS += -I$(LIBALLOC_DIRECTORY) \
|
||||
-I$(MISOC_DIRECTORY)/software/include/dyld \
|
||||
|
57
artiq/runtime/ad9154.c
Normal file
57
artiq/runtime/ad9154.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include <generated/csr.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "artiq_personality.h"
|
||||
#include "ad9154.h"
|
||||
|
||||
#ifdef CONFIG_AD9154_DAC_CS
|
||||
|
||||
void ad9154_init(void)
|
||||
{
|
||||
ad9154_spi_offline_write(1);
|
||||
ad9154_spi_cs_polarity_write(0);
|
||||
ad9154_spi_clk_polarity_write(0);
|
||||
ad9154_spi_clk_phase_write(0);
|
||||
ad9154_spi_lsb_first_write(0);
|
||||
ad9154_spi_half_duplex_write(0);
|
||||
ad9154_spi_clk_div_write_write(11);
|
||||
ad9154_spi_clk_div_read_write(11);
|
||||
ad9154_spi_xfer_len_write_write(24);
|
||||
ad9154_spi_xfer_len_read_write(0);
|
||||
ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS);
|
||||
ad9154_spi_offline_write(0);
|
||||
}
|
||||
|
||||
#define AD9_READ (1 << 15)
|
||||
#define AD9_XFER(w) ((w) << 13)
|
||||
|
||||
void ad9154_write(uint16_t addr, uint8_t data)
|
||||
{
|
||||
ad9154_spi_data_write_write(
|
||||
((AD9_XFER(0) | addr) << 16) | (data << 8));
|
||||
while (ad9154_spi_pending_read());
|
||||
while (ad9154_spi_active_read());
|
||||
}
|
||||
|
||||
uint8_t ad9154_read(uint16_t addr)
|
||||
{
|
||||
ad9154_write(AD9_READ | addr, 0);
|
||||
return ad9154_spi_data_read_read();
|
||||
}
|
||||
|
||||
void ad9516_write(uint16_t addr, uint8_t data)
|
||||
{
|
||||
ad9154_spi_cs_write(CONFIG_AD9154_CLK_CS);
|
||||
ad9154_write(addr, data);
|
||||
ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS);
|
||||
}
|
||||
|
||||
uint8_t ad9516_read(uint16_t addr)
|
||||
{
|
||||
ad9516_write(AD9_READ | addr, 0);
|
||||
return ad9154_spi_data_read_read();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_AD9154_DAC_CS */
|
14
artiq/runtime/ad9154.h
Normal file
14
artiq/runtime/ad9154.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __AD9154_H
|
||||
#define __AD9154_H
|
||||
|
||||
#ifdef CONFIG_AD9154_DAC_CS
|
||||
|
||||
void ad9154_init(void);
|
||||
void ad9154_write(uint16_t addr, uint8_t data);
|
||||
uint8_t ad9154_read(uint16_t addr);
|
||||
|
||||
void ad9516_write(uint16_t addr, uint8_t data);
|
||||
uint8_t ad9516_read(uint16_t addr);
|
||||
|
||||
#endif
|
||||
#endif
|
@ -17,6 +17,7 @@
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
#include "i2c.h"
|
||||
#include "ad9154.h"
|
||||
|
||||
double round(double x);
|
||||
double sqrt(double x);
|
||||
@ -137,6 +138,14 @@ static const struct symbol runtime_exports[] = {
|
||||
{"cache_get", &cache_get},
|
||||
{"cache_put", &cache_put},
|
||||
|
||||
#ifdef CONFIG_AD9154_DAC_CS
|
||||
{"ad9154_init", &ad9154_init},
|
||||
{"ad9154_write", &ad9154_write},
|
||||
{"ad9154_read", &ad9154_read},
|
||||
{"ad9516_write", &ad9516_write},
|
||||
{"ad9516_read", &ad9516_read},
|
||||
#endif
|
||||
|
||||
/* end */
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "session.h"
|
||||
#include "analyzer.h"
|
||||
#include "moninj.h"
|
||||
#include "ad9154.h"
|
||||
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
|
0
artiq/test/gateware/__init__.py
Normal file
0
artiq/test/gateware/__init__.py
Normal file
46
artiq/test/gateware/test_accu.py
Normal file
46
artiq/test/gateware/test_accu.py
Normal file
@ -0,0 +1,46 @@
|
||||
import numpy as np
|
||||
|
||||
from migen import *
|
||||
from migen.fhdl.verilog import convert
|
||||
|
||||
from artiq.gateware.dsp.accu import Accu, PhasedAccu
|
||||
from artiq.gateware.dsp.tools import xfer
|
||||
|
||||
|
||||
def read(o, n):
|
||||
p = []
|
||||
for i in range(n):
|
||||
p.append((yield from [(yield pi) for pi in o.payload.flatten()]))
|
||||
yield
|
||||
return p
|
||||
|
||||
|
||||
def _test_gen_accu(dut, o):
|
||||
yield dut.o.ack.eq(1)
|
||||
yield from xfer(dut, i=dict(p=0, f=1, clr=1))
|
||||
o.extend((yield from read(dut.o, 8)))
|
||||
yield from xfer(dut, i=dict(p=0, f=2, clr=0))
|
||||
o.extend((yield from read(dut.o, 8)))
|
||||
yield from xfer(dut, i=dict(p=0, f=2, clr=1))
|
||||
o.extend((yield from read(dut.o, 8)))
|
||||
yield from xfer(dut, i=dict(p=8, f=-1, clr=1))
|
||||
o.extend((yield from read(dut.o, 8)))
|
||||
yield from xfer(dut, i=dict(p=0, f=0, clr=1))
|
||||
yield from xfer(dut, i=dict(p=1, f=0, clr=0))
|
||||
o.extend((yield from read(dut.o, 8)))
|
||||
|
||||
|
||||
def _test_accu():
|
||||
dut = PhasedAccu(8, parallelism=8)
|
||||
|
||||
if False:
|
||||
print(convert(dut))
|
||||
else:
|
||||
o = []
|
||||
run_simulation(dut, _test_gen_accu(dut, o), vcd_name="accu.vcd")
|
||||
o = np.array(o)
|
||||
print(o)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test_accu()
|
34
artiq/test/gateware/test_sawg.py
Normal file
34
artiq/test/gateware/test_sawg.py
Normal file
@ -0,0 +1,34 @@
|
||||
import numpy as np
|
||||
|
||||
from migen import *
|
||||
from migen.fhdl.verilog import convert
|
||||
|
||||
from artiq.gateware.dsp.sawg import DDSFast
|
||||
from artiq.gateware.dsp.tools import xfer
|
||||
|
||||
|
||||
def _test_gen_dds(dut, o):
|
||||
yield from xfer(dut,
|
||||
a=dict(a=10),
|
||||
p=dict(p=0),
|
||||
f=dict(f=1 << 8),
|
||||
)
|
||||
for i in range(256//dut.parallelism):
|
||||
yield
|
||||
o.append((yield from [(yield _) for _ in dut.o]))
|
||||
|
||||
|
||||
def _test_channel():
|
||||
dut = DDSFast(width=8, parallelism=2)
|
||||
|
||||
if False:
|
||||
print(convert(dut))
|
||||
else:
|
||||
o = []
|
||||
run_simulation(dut, _test_gen_dds(dut, o), vcd_name="dds.vcd")
|
||||
o = np.array(o)
|
||||
print(o[:, :])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test_channel()
|
61
artiq/test/gateware/test_sawg_phy.py
Normal file
61
artiq/test/gateware/test_sawg_phy.py
Normal file
@ -0,0 +1,61 @@
|
||||
import numpy as np
|
||||
|
||||
from migen import *
|
||||
from migen.fhdl.verilog import convert
|
||||
|
||||
from artiq.gateware.rtio.phy.sawg import Channel
|
||||
from artiq.gateware.dsp.tools import xfer, szip
|
||||
|
||||
|
||||
def rtio_xfer(dut, **kwargs):
|
||||
yield from szip(*(
|
||||
xfer(dut.phys_names[k].rtlink, o={"data": v})
|
||||
for k, v in kwargs.items()))
|
||||
|
||||
|
||||
def gen_rtio(dut):
|
||||
width = dut.width
|
||||
yield
|
||||
yield from rtio_xfer(
|
||||
dut, a=int(.1 * (1 << width)),
|
||||
f=int(.01234567 * (1 << 2*width)),
|
||||
p=0)
|
||||
|
||||
|
||||
def gen_log(dut, o, n):
|
||||
for i in range(3 + dut.latency):
|
||||
yield
|
||||
for i in range(n):
|
||||
yield
|
||||
o.append((yield from [(yield _) for _ in dut.o]))
|
||||
|
||||
|
||||
def _test_channel():
|
||||
width = 16
|
||||
dut = ClockDomainsRenamer({"rio_phy": "sys"})(
|
||||
Channel(width=width, parallelism=4)
|
||||
)
|
||||
|
||||
if False:
|
||||
print(convert(dut))
|
||||
return
|
||||
|
||||
o = []
|
||||
run_simulation(
|
||||
dut,
|
||||
[gen_rtio(dut), gen_log(dut, o, 256 * 2)],
|
||||
) # vcd_name="dds.vcd")
|
||||
o = np.array(o)/(1 << (width - 1))
|
||||
o = o.ravel()
|
||||
np.savez_compressed("dds.npz", o=o)
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
fig, ax = plt.subplots(2)
|
||||
ax[0].step(np.arange(o.size), o)
|
||||
ax[1].psd(o, 1 << 10, Fs=1, noverlap=1 << 9, scale_by_freq=False)
|
||||
fig.savefig("dds.pdf")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_test_channel()
|
14
conda/artiq-kc705-phaser/build.sh
Normal file
14
conda/artiq-kc705-phaser/build.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh
|
||||
[ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE
|
||||
|
||||
SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-phaser
|
||||
mkdir -p $SOC_PREFIX
|
||||
|
||||
$PYTHON -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE
|
||||
cp misoc_phaser_kc705/gateware/top.bit $SOC_PREFIX
|
||||
cp misoc_phaser_kc705/software/bios/bios.bin $SOC_PREFIX
|
||||
cp misoc_phaser_kc705/software/runtime/runtime.fbi $SOC_PREFIX
|
||||
|
||||
wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc7k325t.bit
|
27
conda/artiq-kc705-phaser/meta.yaml
Normal file
27
conda/artiq-kc705-phaser/meta.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
package:
|
||||
name: artiq-kc705-phaser
|
||||
version: {{ environ.get("GIT_DESCRIBE_TAG", "") }}
|
||||
|
||||
source:
|
||||
git_url: ../..
|
||||
|
||||
build:
|
||||
noarch_python: true
|
||||
number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}
|
||||
string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_DESCRIBE_HASH", "")[1:] }}
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- migen 0.4
|
||||
- misoc 0.3
|
||||
- llvm-or1k
|
||||
- binutils-or1k-linux >=2.27
|
||||
- rust-core-or1k
|
||||
- cargo
|
||||
run:
|
||||
- artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_DESCRIBE_HASH")[1:]) if "GIT_DESCRIBE_TAG" in environ else "" }}
|
||||
|
||||
about:
|
||||
home: https://m-labs.hk/artiq
|
||||
license: GPL
|
||||
summary: 'Bitstream, BIOS and runtime for Phaser on the KC705 board'
|
@ -155,6 +155,38 @@ To avoid I/O contention, the startup kernel should first program the TCA6424A ex
|
||||
|
||||
See :mod:`artiq.coredevice.i2c` for more details.
|
||||
|
||||
|
||||
Phaser
|
||||
++++++
|
||||
|
||||
The Phaser adapter is an AD9154-FMC-EBZ, a 4 channel 2.4 GHz DAC on an FMC HPC card.
|
||||
|
||||
+--------------+------------+--------------+
|
||||
| RTIO channel | TTL line | Capability |
|
||||
+==============+============+==============+
|
||||
| 0 | SMA_GPIO_N | Input+Output |
|
||||
+--------------+------------+--------------+
|
||||
| 1 | LED | Output |
|
||||
+--------------+------------+--------------+
|
||||
| 2 | SYSREF | Input |
|
||||
+--------------+------------+--------------+
|
||||
| 3 | SYNC | Input |
|
||||
+--------------+------------+--------------+
|
||||
|
||||
The SAWG channels start with RTIO channel number 4, each occupying 3 channels.
|
||||
|
||||
The board has one non-RTIO SPI bus that is accessible through
|
||||
:mod:`artiq.coredevice.ad9154`.
|
||||
|
||||
* Setup the KC705 observing the notes above and as laid out in :ref:`configuring-core-device`.
|
||||
* A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1.
|
||||
The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal.
|
||||
* The ``startup_clock`` needs to be set to internal (``i``) for bootstrapping the clock distribution tree.
|
||||
See :ref:`configuring-core-device`.
|
||||
* Compile and flash the startup kernel in ``artiq/examples/phaser/startup_kernel.py``.
|
||||
* An example ``device_db.pyon`` is provided in ``artiq/examples/phaser/device_db.pyon``.
|
||||
|
||||
|
||||
Pipistrello
|
||||
-----------
|
||||
|
||||
|
@ -53,3 +53,15 @@ These drivers are for the core device and the peripherals closely integrated int
|
||||
|
||||
.. automodule:: artiq.coredevice.exceptions
|
||||
:members:
|
||||
|
||||
:mod:`artiq.coredevice.sawg` module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: artiq.coredevice.sawg
|
||||
:members:
|
||||
|
||||
:mod:`artiq.coredevice.ad9154` module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: artiq.coredevice.ad9154
|
||||
:members:
|
||||
|
@ -142,6 +142,7 @@ Then, you can flash the board:
|
||||
|
||||
For the KC705, the next step is to flash the MAC and IP addresses to the board. See :ref:`those instructions <flash-mac-ip-addr>`.
|
||||
|
||||
.. _configuring-core-device:
|
||||
|
||||
Configuring the core device
|
||||
---------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user