forked from M-Labs/artiq
1
0
Fork 0

urukul: use spi2

* switch kc705 and kasli targets to spi2 gateware on urukul
* rewrite urukul, ad9912, ad9910
* update example experiments, device_dbs
This commit is contained in:
Robert Jördens 2018-02-21 15:00:28 +00:00
parent 37a0d6580b
commit a63fd306af
10 changed files with 256 additions and 193 deletions

View File

@ -1,9 +1,12 @@
from artiq.language.core import kernel, delay_mu, delay, portable
from artiq.language.units import us, ns, ms
from artiq.coredevice.urukul import urukul_sta_pll_lock
from numpy import int32, int64 from numpy import int32, int64
from artiq.language.core import kernel, delay, portable
from artiq.language.units import us, ns, ms
from artiq.coredevice import spi2 as spi
from artiq.coredevice import urukul
urukul_sta_pll_lock = urukul.urukul_sta_pll_lock
_AD9910_REG_CFR1 = 0x00 _AD9910_REG_CFR1 = 0x00
_AD9910_REG_CFR2 = 0x01 _AD9910_REG_CFR2 = 0x01
@ -47,7 +50,7 @@ class AD9910:
:param pll_vco: DDS PLL VCO range selection. :param pll_vco: DDS PLL VCO range selection.
""" """
kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw",
"ftw_per_hz", "sysclk", "pll_n", "pll_cp", "pll_vco"} "ftw_per_hz", "pll_n", "pll_cp", "pll_vco"}
def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, def __init__(self, dmgr, chip_select, cpld_device, sw_device=None,
pll_n=40, pll_cp=7, pll_vco=5): pll_n=40, pll_cp=7, pll_vco=5):
@ -60,14 +63,14 @@ class AD9910:
self.sw = dmgr.get(sw_device) self.sw = dmgr.get(sw_device)
assert 12 <= pll_n <= 127 assert 12 <= pll_n <= 127
self.pll_n = pll_n self.pll_n = pll_n
assert self.cpld.refclk < 60e6 assert self.cpld.refclk/4 <= 60e6
self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider
assert self.sysclk <= 1e9 assert sysclk <= 1e9
self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32) self.ftw_per_hz = 1./sysclk*(int64(1) << 32)
assert 0 <= pll_vco <= 5 assert 0 <= pll_vco <= 5
vco_min, vco_max = [(370, 510), (420, 590), (500, 700), vco_min, vco_max = [(370, 510), (420, 590), (500, 700),
(600, 880), (700, 950), (820, 1150)][pll_vco] (600, 880), (700, 950), (820, 1150)][pll_vco]
assert vco_min <= self.sysclk/1e6 <= vco_max assert vco_min <= sysclk/1e6 <= vco_max
self.pll_vco = pll_vco self.pll_vco = pll_vco
assert 0 <= pll_cp <= 7 assert 0 <= pll_cp <= 7
self.pll_cp = pll_cp self.pll_cp = pll_cp
@ -79,12 +82,27 @@ class AD9910:
:param addr: Register address :param addr: Register address
:param data: Data to be written :param data: Data to be written
""" """
self.bus.set_xfer(self.chip_select, 8, 0) self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(addr << 24) self.bus.write(addr << 24)
delay_mu(-self.bus.xfer_period_mu + 8) self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
self.bus.set_xfer(self.chip_select, 32, 0) urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data) self.bus.write(data)
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
@kernel
def read32(self, addr):
"""Read from 32 bit register.
:param addr: Register address
"""
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END
| spi.SPI_INPUT, 32,
urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
return self.bus.read()
@kernel @kernel
def write64(self, addr, data_high, data_low): def write64(self, addr, data_high, data_low):
@ -94,68 +112,58 @@ class AD9910:
:param data_high: High (MSB) 32 bits of the data :param data_high: High (MSB) 32 bits of the data
:param data_low: Low (LSB) 32 data bits :param data_low: Low (LSB) 32 data bits
""" """
self.bus.set_xfer(self.chip_select, 8, 0) self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(addr << 24) self.bus.write(addr << 24)
t = self.bus.xfer_period_mu self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
delay_mu(-t + 8) urukul.SPIT_DDS_WR, self.chip_select)
self.bus.set_xfer(self.chip_select, 32, 0)
self.bus.write(data_high) self.bus.write(data_high)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data_low) self.bus.write(data_low)
delay_mu(t - 2*self.bus.write_period_mu)
@kernel
def read32(self, addr):
"""Read from 32 bit register.
:param addr: Register address
"""
self.bus.set_xfer(self.chip_select, 8, 0)
self.bus.write((addr | 0x80) << 24)
delay_mu(-self.bus.xfer_period_mu + 8)
self.bus.set_xfer(self.chip_select, 0, 32)
self.bus.write(0)
delay_mu(2*self.bus.xfer_period_mu)
data = self.bus.read_sync()
return data
@kernel @kernel
def init(self): def init(self):
"""Initialize and configure the DDS.""" """Initialize and configure the DDS.
Sets up SPI mode, confirms chip presence, powers down unused blocks,
configures the PLL, waits for PLL lock. Uses the
IO_UPDATE signal multiple times.
"""
# Set SPI mode # Set SPI mode
self.write32(_AD9910_REG_CFR1, 0x00000002) self.write32(_AD9910_REG_CFR1, 0x00000002)
delay(100*us) self.cpld.io_update.pulse(1*us)
self.cpld.io_update.pulse(100*ns)
# Use the AUX DAC setting to identify and confirm presence # Use the AUX DAC setting to identify and confirm presence
aux_dac = self.read32(_AD9910_REG_AUX_DAC) aux_dac = self.read32(_AD9910_REG_AUX_DAC)
if aux_dac & 0xff != 0x7f: if aux_dac & 0xff != 0x7f:
raise ValueError("Urukul AD9910 AUX_DAC mismatch") raise ValueError("Urukul AD9910 AUX_DAC mismatch")
delay(100*us) delay(20*us) # slack
# Configure PLL settings and bring up PLL # Configure PLL settings and bring up PLL
self.write32(_AD9910_REG_CFR2, 0x01400020) self.write32(_AD9910_REG_CFR2, 0x01400020)
self.cpld.io_update.pulse(1*us)
cfr3 = (0x0807c100 | (self.pll_vco << 24) | cfr3 = (0x0807c100 | (self.pll_vco << 24) |
(self.pll_cp << 19) | (self.pll_n << 1)) (self.pll_cp << 19) | (self.pll_n << 1))
self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset
delay(100*us) self.cpld.io_update.pulse(100*us)
self.cpld.io_update.pulse(100*ns)
self.write32(_AD9910_REG_CFR3, cfr3) self.write32(_AD9910_REG_CFR3, cfr3)
delay(100*us) self.cpld.io_update.pulse(100*us)
self.cpld.io_update.pulse(100*ns)
# Wait for PLL lock, up to 100 ms # Wait for PLL lock, up to 100 ms
for i in range(100): for i in range(100):
lock = urukul_sta_pll_lock(self.cpld.sta_read()) sta = self.cpld.sta_read()
lock = urukul_sta_pll_lock(sta)
delay(1*ms) delay(1*ms)
if lock & (1 << self.chip_select - 4) != 0: if lock & (1 << self.chip_select - 4):
return return
raise ValueError("PLL failed to lock") raise ValueError("PLL lock timeout")
@kernel @kernel
def set_mu(self, ftw=int32(0), pow=int32(0), asf=int32(0x3fff)): def set_mu(self, ftw, pow=0, asf=0x3fff):
"""Set profile 0 data in machine units. """Set profile 0 data in machine units.
After the SPI transfer, the shared IO update pin is pulsed to After the SPI transfer, the shared IO update pin is pulsed to
activate the data. activate the data.
:param ftw: Frequency tuning word: 32 bit unsigned. :param ftw: Frequency tuning word: 32 bit.
:param pow: Phase tuning word: 16 bit unsigned. :param pow: Phase tuning word: 16 bit unsigned.
:param asf: Amplitude scale factor: 14 bit unsigned. :param asf: Amplitude scale factor: 14 bit unsigned.
""" """
@ -195,7 +203,7 @@ class AD9910:
self.amplitude_to_asf(amplitude)) self.amplitude_to_asf(amplitude))
@kernel @kernel
def set_att_mu(self, att=int32(0)): def set_att_mu(self, att):
"""Set digital step attenuator in machine units. """Set digital step attenuator in machine units.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`

View File

@ -1,8 +1,11 @@
from artiq.language.core import kernel, delay_mu, delay, portable from numpy import int32, int64
from artiq.language.core import kernel, delay, portable
from artiq.language.units import us, ns from artiq.language.units import us, ns
from artiq.coredevice.ad9912_reg import * from artiq.coredevice.ad9912_reg import *
from numpy import int32, int64 from artiq.coredevice import spi2 as spi
from artiq.coredevice import urukul
class AD9912: class AD9912:
@ -39,8 +42,9 @@ class AD9912:
self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48)
@kernel @kernel
def write(self, addr=int32(0), data=int32(0), length=int32(1)): def write(self, addr, data, length):
"""Variable length write to a register. Up to 32 bits. """Variable length write to a register.
Up to 4 bytes.
:param addr: Register address :param addr: Register address
:param data: Data to be written: int32 :param data: Data to be written: int32
@ -48,51 +52,60 @@ class AD9912:
""" """
assert length > 0 assert length > 0
assert length <= 4 assert length <= 4
self.bus.set_xfer(self.chip_select, 16, 0) self.bus.set_config_mu(urukul.SPI_CONFIG, 16,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | ((length - 1) << 13)) << 16) self.bus.write((addr | ((length - 1) << 13)) << 16)
delay_mu(-self.bus.xfer_period_mu) self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, length*8,
self.bus.set_xfer(self.chip_select, length*8, 0) urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data << (32 - length*8)) self.bus.write(data << (32 - length*8))
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
@kernel @kernel
def read(self, addr=int32(0), length=int32(1)): def read(self, addr, length):
"""Variable length read from a register. Up to 32 bits. """Variable length read from a register.
Up to 4 bytes.
:param addr: Register address :param addr: Register address
:param length: Length in bytes (1-4) :param length: Length in bytes (1-4)
:return: Data read
""" """
assert length > 0 assert length > 0
assert length <= 4 assert length <= 4
self.bus.set_xfer(self.chip_select, 16, 0) self.bus.set_config_mu(urukul.SPI_CONFIG, 16,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16) self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16)
delay_mu(-self.bus.xfer_period_mu) self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END
self.bus.set_xfer(self.chip_select, 0, length*8) | spi.SPI_INPUT, length*8,
urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0) self.bus.write(0)
delay_mu(2*self.bus.xfer_period_mu) data = self.bus.read()
data = self.bus.read_sync()
if length < 4: if length < 4:
data &= (1 << (length*8)) - 1 data &= (1 << (length*8)) - 1
return data return data
@kernel @kernel
def init(self): def init(self):
"""Initialize and configure the DDS.""" """Initialize and configure the DDS.
t = now_mu()
Sets up SPI mode, confirms chip presence, powers down unused blocks,
and configures the PLL. Does not wait for PLL lock. Uses the
IO_UPDATE signal multiple times.
"""
# SPI mode # SPI mode
self.write(AD9912_SER_CONF, 0x99) self.write(AD9912_SER_CONF, 0x99, length=1)
self.cpld.io_update.pulse(1*us)
# Verify chip ID and presence # Verify chip ID and presence
prodid = self.read(AD9912_PRODIDH, length=2) prodid = self.read(AD9912_PRODIDH, length=2)
if (prodid != 0x1982) and (prodid != 0x1902): if (prodid != 0x1982) and (prodid != 0x1902):
raise ValueError("Urukul AD9912 product id mismatch") raise ValueError("Urukul AD9912 product id mismatch")
delay(10*us) delay(20*us)
# HSTL power down, CMOS power down # HSTL power down, CMOS power down
self.write(AD9912_PWRCNTRL1, 0x80) self.write(AD9912_PWRCNTRL1, 0x80, length=1)
delay(10*us) self.cpld.io_update.pulse(1*us)
self.write(AD9912_N_DIV, self.pll_n//2 - 2) self.write(AD9912_N_DIV, self.pll_n//2 - 2, length=1)
delay(10*us) self.cpld.io_update.pulse(1*us)
# I_cp = 375 µA, VCO high range # I_cp = 375 µA, VCO high range
self.write(AD9912_PLLCFG, 0b00000101) self.write(AD9912_PLLCFG, 0b00000101, length=1)
self.cpld.io_update.pulse(1*us)
@kernel @kernel
def set_att_mu(self, att): def set_att_mu(self, att):
@ -110,12 +123,12 @@ class AD9912:
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
:param att: Attenuation in dB. :param att: Attenuation in dB. Higher values mean more attenuation.
""" """
self.cpld.set_att(self.chip_select - 4, att) self.cpld.set_att(self.chip_select - 4, att)
@kernel @kernel
def set_mu(self, ftw=int64(0), pow=int32(0)): def set_mu(self, ftw, pow):
"""Set profile 0 data in machine units. """Set profile 0 data in machine units.
After the SPI transfer, the shared IO update pin is pulsed to After the SPI transfer, the shared IO update pin is pulsed to
@ -125,13 +138,15 @@ class AD9912:
:param pow: Phase tuning word: 16 bit unsigned. :param pow: Phase tuning word: 16 bit unsigned.
""" """
# streaming transfer of FTW and POW # streaming transfer of FTW and POW
self.bus.set_xfer(self.chip_select, 16, 0) self.bus.set_config_mu(urukul.SPI_CONFIG, 16,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((AD9912_POW1 << 16) | (3 << 29)) self.bus.write((AD9912_POW1 << 16) | (3 << 29))
delay_mu(-self.bus.xfer_period_mu) self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
self.bus.set_xfer(self.chip_select, 32, 0) urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((pow << 16) | int32(ftw >> 32)) self.bus.write((pow << 16) | (int32(ftw >> 32) & 0xffff))
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(int32(ftw)) self.bus.write(int32(ftw))
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
self.cpld.io_update.pulse(10*ns) self.cpld.io_update.pulse(10*ns)
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})

View File

@ -1,6 +1,8 @@
""" """
Driver for generic SPI on RTIO. Driver for generic SPI on RTIO.
This ARTIQ coredevice driver corresponds to the legacy MiSoC SPI core (v1).
Output event replacement is not supported and issuing commands at the same Output event replacement is not supported and issuing commands at the same
time is an error. time is an error.
""" """

View File

@ -1,22 +1,23 @@
from artiq.language.core import kernel, delay_mu, delay, now_mu, at_mu from artiq.language.core import kernel, delay, portable
from artiq.language.units import us, ms from artiq.language.units import us, ms
from numpy import int32, int64 from numpy import int32, int64
from artiq.coredevice import spi from artiq.coredevice import spi2 as spi
_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_CS_POLARITY | SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END |
0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY |
0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE |
0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
# SPI clock write and read dividers # SPI clock write and read dividers
_SPIT_CFG_WR = 2 SPIT_CFG_WR = 2
_SPIT_CFG_RD = 16 SPIT_CFG_RD = 16
_SPIT_ATT_WR = 2 SPIT_ATT_WR = 2
_SPIT_ATT_RD = 16 SPIT_ATT_RD = 16
_SPIT_DDS_WR = 3 SPIT_DDS_WR = 2
_SPIT_DDS_RD = 16 SPIT_DDS_RD = 16
# CFG configuration register bit offsets # CFG configuration register bit offsets
CFG_RF_SW = 0 CFG_RF_SW = 0
@ -29,17 +30,6 @@ CFG_SYNC_SEL = 18
CFG_RST = 19 CFG_RST = 19
CFG_IO_RST = 20 CFG_IO_RST = 20
@kernel
def urukul_cfg(rf_sw, led, profile, io_update, mask_nu,
clk_sel, sync_sel, rst, io_rst):
return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) |
(profile << CFG_PROFILE) |
(io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) |
(clk_sel << CFG_CLK_SEL) | (sync_sel << CFG_SYNC_SEL) |
(rst << CFG_RST) | (io_rst << CFG_IO_RST))
# STA status register bit offsets # STA status register bit offsets
STA_RF_SW = 0 STA_RF_SW = 0
STA_SMP_ERR = 4 STA_SMP_ERR = 4
@ -47,32 +37,6 @@ STA_PLL_LOCK = 8
STA_IFC_MODE = 12 STA_IFC_MODE = 12
STA_PROTO_REV = 16 STA_PROTO_REV = 16
@kernel
def urukul_sta_rf_sw(sta):
return (sta >> STA_RF_SW) & 0xf
@kernel
def urukul_sta_smp_err(sta):
return (sta >> STA_SMP_ERR) & 0xf
@kernel
def urukul_sta_pll_lock(sta):
return (sta >> STA_PLL_LOCK) & 0xf
@kernel
def urukul_sta_ifc_mode(sta):
return (sta >> STA_IFC_MODE) & 0xf
@kernel
def urukul_sta_proto_rev(sta):
return (sta >> STA_PROTO_REV) & 0x7f
# supported hardware and CPLD code version # supported hardware and CPLD code version
STA_PROTO_REV_MATCH = 0x08 STA_PROTO_REV_MATCH = 0x08
@ -86,6 +50,51 @@ CS_DDS_CH2 = 6
CS_DDS_CH3 = 7 CS_DDS_CH3 = 7
@portable
def urukul_cfg(rf_sw, led, profile, io_update, mask_nu,
clk_sel, sync_sel, rst, io_rst):
"""Build Urukul CPLD configuration register"""
return ((rf_sw << CFG_RF_SW) |
(led << CFG_LED) |
(profile << CFG_PROFILE) |
(io_update << CFG_IO_UPDATE) |
(mask_nu << CFG_MASK_NU) |
(clk_sel << CFG_CLK_SEL) |
(sync_sel << CFG_SYNC_SEL) |
(rst << CFG_RST) |
(io_rst << CFG_IO_RST))
@portable
def urukul_sta_rf_sw(sta):
"""Return the RF switch status from Urukul status register value."""
return (sta >> STA_RF_SW) & 0xf
@portable
def urukul_sta_smp_err(sta):
"""Return the SMP_ERR status from Urukul status register value."""
return (sta >> STA_SMP_ERR) & 0xf
@portable
def urukul_sta_pll_lock(sta):
"""Return the PLL_LOCK status from Urukul status register value."""
return (sta >> STA_PLL_LOCK) & 0xf
@portable
def urukul_sta_ifc_mode(sta):
"""Return the IFC_MODE status from Urukul status register value."""
return (sta >> STA_IFC_MODE) & 0xf
@portable
def urukul_sta_proto_rev(sta):
"""Return the PROTO_REV value from Urukul status register value."""
return (sta >> STA_PROTO_REV) & 0x7f
class CPLD: class CPLD:
"""Urukul CPLD SPI router and configuration interface. """Urukul CPLD SPI router and configuration interface.
@ -94,11 +103,18 @@ class CPLD:
:param dds_reset_device: DDS reset RTIO TTLOut channel name :param dds_reset_device: DDS reset RTIO TTLOut channel name
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
frequency in Hz frequency in Hz
:param clk_sel: Reference clock selection. 0 corresponds to the internal
MMCX or ob-board XO clock. 1 corresponds to the front panel SMA.
:param sync_sel: SYNC clock selection. 0 corresponds to SYNC clock over EEM
from FPGA. 1 corresponds to SYNC clock from DDS0.
:param core_device: Core device name :param core_device: Core device name
""" """
kernel_invariants = {"refclk", "bus", "core", "io_update"}
def __init__(self, dmgr, spi_device, io_update_device, def __init__(self, dmgr, spi_device, io_update_device,
dds_reset_device=None, dds_reset_device=None,
refclk=100e6, core_device="core"): sync_sel=0, clk_sel=0,
refclk=125e6, core_device="core"):
self.core = dmgr.get(core_device) self.core = dmgr.get(core_device)
self.refclk = refclk self.refclk = refclk
@ -108,63 +124,83 @@ class CPLD:
if dds_reset_device is not None: if dds_reset_device is not None:
self.dds_reset = dmgr.get(dds_reset_device) self.dds_reset = dmgr.get(dds_reset_device)
self.cfg_reg = int32(0) self.cfg_reg = urukul_cfg(rf_sw=0, led=0, profile=0,
self.att_reg = int32(0) io_update=0, mask_nu=0, clk_sel=clk_sel,
sync_sel=sync_sel, rst=0, io_rst=0)
self.att_reg = 0
@kernel @kernel
def cfg_write(self, data=int32(0)): def cfg_write(self, cfg):
"""Write to the configuration register. """Write to the configuration register.
See :func:`urukul_cfg` for possible flags.
:param data: 24 bit data to be written. Will be stored at :param data: 24 bit data to be written. Will be stored at
:attr:`cfg_reg`. :attr:`cfg_reg`.
""" """
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24,
self.bus.set_xfer(CS_CFG, 24, 0) SPIT_CFG_WR, CS_CFG)
self.bus.write(data << 8) self.bus.write(cfg << 8)
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) self.cfg_reg = cfg
self.cfg_reg = data
@kernel @kernel
def sta_read(self): def sta_read(self):
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) """Read the status register.
self.bus.set_xfer(CS_CFG, 0, 24)
Use any of the following functions to extract values:
* :func:`urukul_sta_rf_sw`
* :func:`urukul_sta_smp_err`
* :func:`urukul_sta_pll_lock`
* :func:`urukul_sta_ifc_mode`
* :func:`urukul_sta_proto_rev`
:return: The status register value.
"""
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 24,
SPIT_CFG_RD, CS_CFG)
self.bus.write(self.cfg_reg << 8) self.bus.write(self.cfg_reg << 8)
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) return self.bus.read()
return self.bus.read_sync()
@kernel @kernel
def init(self, clk_sel=0, sync_sel=0): def init(self):
cfg = urukul_cfg(rf_sw=0, led=0, profile=0, """Initialize and detect Urukul.
io_update=0, mask_nu=0, clk_sel=clk_sel,
sync_sel=sync_sel, rst=0, io_rst=0) Resets the DDS and verifies correct CPLD gateware version.
self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)) """
delay(1*ms) cfg = self.cfg_reg
self.cfg_write(cfg) self.cfg_reg = cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)
delay(10*ms) # DDS wake up
proto_rev = urukul_sta_proto_rev(self.sta_read()) proto_rev = urukul_sta_proto_rev(self.sta_read())
if proto_rev != STA_PROTO_REV_MATCH: if proto_rev != STA_PROTO_REV_MATCH:
raise ValueError("Urukul proto_rev mismatch") raise ValueError("Urukul proto_rev mismatch")
delay(100*us) delay(20*us) # slack, reset
self.cfg_write(cfg)
delay(1*ms) # DDS wake up
@kernel @kernel
def io_rst(self): def io_rst(self):
delay(1*us) """Pulse IO_RST"""
self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST)) self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST))
delay(1*us)
self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST)) self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST))
delay(1*us)
@kernel @kernel
def cfg_sw(self, sw, on): def cfg_sw(self, channel, on):
"""Configure the RF switches through the configuration register.
These values are logically OR-ed with the LVDS lines on EEM1.
:param channel: Channel index (0-3)
:param on: Switch value
"""
c = self.cfg_reg c = self.cfg_reg
if on: if on:
c |= 1 << sw c |= 1 << channel
else: else:
c &= ~(1 << sw) c &= ~(1 << channel)
self.cfg_write(c) self.cfg_write(c)
@kernel @kernel
def set_att_mu(self, channel=int32(0), att=int32(0)): def set_att_mu(self, channel, att):
"""Set digital step attenuator in machine units. """Set digital step attenuator in machine units.
:param channel: Attenuator channel (0-3). :param channel: Attenuator channel (0-3).
@ -173,16 +209,28 @@ class CPLD:
""" """
a = self.att_reg & ~(0xff << (channel * 8)) a = self.att_reg & ~(0xff << (channel * 8))
a |= att << (channel * 8) a |= att << (channel * 8)
self.att_reg = a self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) SPIT_ATT_WR, CS_ATT)
self.bus.set_xfer(CS_ATT, 32, 0)
self.bus.write(a) self.bus.write(a)
self.att_reg = a
@kernel @kernel
def set_att(self, channel, att): def set_att(self, channel, att):
"""Set digital step attenuator in SI units. """Set digital step attenuator in SI units.
:param channel: Attenuator channel (0-3). :param channel: Attenuator channel (0-3).
:param att: Attenuation in dB. :param att: Attenuation setting in dB. Higher value is more
attenuation.
""" """
self.set_att_mu(channel, 255 - int32(round(att*8))) self.set_att_mu(channel, 255 - int32(round(att*8)))
@kernel
def get_att_mu(self):
"""Return the digital step attenuator settings in machine units.
:return: 32 bit attenuator settings
"""
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32,
SPIT_ATT_RD, CS_ATT)
self.bus.write(self.att_reg)
return self.bus.read()

View File

@ -188,7 +188,7 @@ device_db = {
"spi_novogorny0": { "spi_novogorny0": {
"type": "local", "type": "local",
"module": "artiq.coredevice.spi", "module": "artiq.coredevice.spi2",
"class": "SPIMaster", "class": "SPIMaster",
"arguments": {"channel": 24} "arguments": {"channel": 24}
}, },
@ -201,7 +201,7 @@ device_db = {
"spi_urukul0": { "spi_urukul0": {
"type": "local", "type": "local",
"module": "artiq.coredevice.spi", "module": "artiq.coredevice.spi2",
"class": "SPIMaster", "class": "SPIMaster",
"arguments": {"channel": 26} "arguments": {"channel": 26}
}, },
@ -242,7 +242,8 @@ device_db = {
"arguments": { "arguments": {
"spi_device": "spi_urukul0", "spi_device": "spi_urukul0",
"io_update_device": "ttl_urukul0_io_update", "io_update_device": "ttl_urukul0_io_update",
"refclk": 100e6 "refclk": 100e6,
"clk_sel": 1
} }
}, },
"urukul0_ch0": { "urukul0_ch0": {

View File

@ -11,9 +11,6 @@ class UrukulTest(EnvExperiment):
self.setattr_device("urukul0_ch3") self.setattr_device("urukul0_ch3")
self.setattr_device("led0") self.setattr_device("led0")
def p(self, f, *a):
print(f % a)
@kernel @kernel
def run(self): def run(self):
self.core.reset() self.core.reset()
@ -21,7 +18,7 @@ class UrukulTest(EnvExperiment):
delay(5*ms) delay(5*ms)
self.led0.off() self.led0.off()
self.urukul0_cpld.init(clk_sel=0) self.urukul0_cpld.init()
self.urukul0_ch0.init() self.urukul0_ch0.init()
self.urukul0_ch1.init() self.urukul0_ch1.init()
self.urukul0_ch2.init() self.urukul0_ch2.init()

View File

@ -192,7 +192,7 @@ device_db = {
"spi_urukul": { "spi_urukul": {
"type": "local", "type": "local",
"module": "artiq.coredevice.spi", "module": "artiq.coredevice.spi2",
"class": "SPIMaster", "class": "SPIMaster",
"arguments": {"channel": 32} "arguments": {"channel": 32}
}, },

View File

@ -16,9 +16,6 @@ class UrukulTest(EnvExperiment):
self.setattr_device("urukul_ch3b") self.setattr_device("urukul_ch3b")
self.setattr_device("led") self.setattr_device("led")
def p(self, f, *a):
print(f % a)
@kernel @kernel
def run(self): def run(self):
self.core.reset() self.core.reset()
@ -28,7 +25,7 @@ class UrukulTest(EnvExperiment):
self.fmcdio_dirctl.set(0x0A008800) self.fmcdio_dirctl.set(0x0A008800)
self.led.off() self.led.off()
self.urukul_cpld.init(clk_sel=0) self.urukul_cpld.init()
self.urukul_ch0b.init() self.urukul_ch0b.init()
self.urukul_ch1b.init() self.urukul_ch1b.init()
self.urukul_ch2b.init() self.urukul_ch2b.init()
@ -54,24 +51,19 @@ class UrukulTest(EnvExperiment):
self.urukul_ch3b.sw.on() self.urukul_ch3b.sw.on()
self.urukul_ch3b.set_att(20.) self.urukul_ch3b.set_att(20.)
i = 0 data = 0
j = 0 errors = 0
while True:
delay(13*us)
self.urukul_ch0b.write32(0x07, i)
self.urukul_cpld.io_update.pulse(10*ns)
k = self.urukul_ch0b.read32(0x07)
delay(100*us) delay(100*us)
if k != i: while data != -1:
#print(i) self.urukul_ch0b.write32(0x07, data)
#print(k) read = self.urukul_ch0b.read32(0x07)
#if j > 20: if read != data:
# return errors += 1
j += 1 if errors > 20:
#delay(20*ms) return
i += 1 data += 1
while True: while False:
self.urukul_ch0b.sw.pulse(5*ms) self.urukul_ch0b.sw.pulse(5*ms)
delay(5*ms) delay(5*ms)

View File

@ -19,7 +19,7 @@ from misoc.integration.builder import builder_args, builder_argdict
from artiq.gateware.amp import AMPSoC from artiq.gateware.amp import AMPSoC
from artiq.gateware import rtio from artiq.gateware import rtio
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2
from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.transceiver import gtp_7series
from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite
from artiq.build_soc import build_artiq_soc from artiq.build_soc import build_artiq_soc
@ -265,7 +265,7 @@ class Opticlock(_StandaloneBase):
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
phy = spi.SPIMaster(self.platform.request("eem3_spi_p"), phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"),
self.platform.request("eem3_spi_n")) self.platform.request("eem3_spi_n"))
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
@ -276,7 +276,7 @@ class Opticlock(_StandaloneBase):
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
phy = spi.SPIMaster(self.platform.request("eem5_spi_p"), phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"),
self.platform.request("eem5_spi_n")) self.platform.request("eem5_spi_n"))
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))

View File

@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict
from artiq.gateware.amp import AMPSoC from artiq.gateware.amp import AMPSoC
from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware import rtio, nist_clock, nist_qc2
from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series,
dds, spi, ad5360_monitor) dds, spi, spi2, ad5360_monitor)
from artiq.build_soc import build_artiq_soc from artiq.build_soc import build_artiq_soc
from artiq import __version__ as artiq_version from artiq import __version__ as artiq_version
@ -355,7 +355,7 @@ class NIST_CLOCK(_StandaloneBase):
self.submodules += dac_monitor self.submodules += dac_monitor
sdac_phy.probes.extend(dac_monitor.probes) sdac_phy.probes.extend(dac_monitor.probes)
phy = spi.SPIMaster(self.platform.request("urukul_spi_p"), phy = spi2.SPIMaster(self.platform.request("urukul_spi_p"),
self.platform.request("urukul_spi_n")) self.platform.request("urukul_spi_n"))
self.submodules += phy self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))