forked from M-Labs/artiq
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:
parent
37a0d6580b
commit
a63fd306af
|
@ -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 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_CFR2 = 0x01
|
||||
|
@ -47,7 +50,7 @@ class AD9910:
|
|||
:param pll_vco: DDS PLL VCO range selection.
|
||||
"""
|
||||
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,
|
||||
pll_n=40, pll_cp=7, pll_vco=5):
|
||||
|
@ -60,14 +63,14 @@ class AD9910:
|
|||
self.sw = dmgr.get(sw_device)
|
||||
assert 12 <= pll_n <= 127
|
||||
self.pll_n = pll_n
|
||||
assert self.cpld.refclk < 60e6
|
||||
self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider
|
||||
assert self.sysclk <= 1e9
|
||||
self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32)
|
||||
assert self.cpld.refclk/4 <= 60e6
|
||||
sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider
|
||||
assert sysclk <= 1e9
|
||||
self.ftw_per_hz = 1./sysclk*(int64(1) << 32)
|
||||
assert 0 <= pll_vco <= 5
|
||||
vco_min, vco_max = [(370, 510), (420, 590), (500, 700),
|
||||
(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
|
||||
assert 0 <= pll_cp <= 7
|
||||
self.pll_cp = pll_cp
|
||||
|
@ -79,12 +82,27 @@ class AD9910:
|
|||
:param addr: Register address
|
||||
: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)
|
||||
delay_mu(-self.bus.xfer_period_mu + 8)
|
||||
self.bus.set_xfer(self.chip_select, 32, 0)
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
|
||||
urukul.SPIT_DDS_WR, self.chip_select)
|
||||
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
|
||||
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_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)
|
||||
t = self.bus.xfer_period_mu
|
||||
delay_mu(-t + 8)
|
||||
self.bus.set_xfer(self.chip_select, 32, 0)
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
|
||||
urukul.SPIT_DDS_WR, self.chip_select)
|
||||
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)
|
||||
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
|
||||
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
|
||||
self.write32(_AD9910_REG_CFR1, 0x00000002)
|
||||
delay(100*us)
|
||||
self.cpld.io_update.pulse(100*ns)
|
||||
self.cpld.io_update.pulse(1*us)
|
||||
# Use the AUX DAC setting to identify and confirm presence
|
||||
aux_dac = self.read32(_AD9910_REG_AUX_DAC)
|
||||
if aux_dac & 0xff != 0x7f:
|
||||
raise ValueError("Urukul AD9910 AUX_DAC mismatch")
|
||||
delay(100*us)
|
||||
delay(20*us) # slack
|
||||
# Configure PLL settings and bring up PLL
|
||||
self.write32(_AD9910_REG_CFR2, 0x01400020)
|
||||
self.cpld.io_update.pulse(1*us)
|
||||
cfr3 = (0x0807c100 | (self.pll_vco << 24) |
|
||||
(self.pll_cp << 19) | (self.pll_n << 1))
|
||||
self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset
|
||||
delay(100*us)
|
||||
self.cpld.io_update.pulse(100*ns)
|
||||
self.cpld.io_update.pulse(100*us)
|
||||
self.write32(_AD9910_REG_CFR3, cfr3)
|
||||
delay(100*us)
|
||||
self.cpld.io_update.pulse(100*ns)
|
||||
self.cpld.io_update.pulse(100*us)
|
||||
# Wait for PLL lock, up to 100 ms
|
||||
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)
|
||||
if lock & (1 << self.chip_select - 4) != 0:
|
||||
if lock & (1 << self.chip_select - 4):
|
||||
return
|
||||
raise ValueError("PLL failed to lock")
|
||||
raise ValueError("PLL lock timeout")
|
||||
|
||||
@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.
|
||||
|
||||
After the SPI transfer, the shared IO update pin is pulsed to
|
||||
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 asf: Amplitude scale factor: 14 bit unsigned.
|
||||
"""
|
||||
|
@ -195,7 +203,7 @@ class AD9910:
|
|||
self.amplitude_to_asf(amplitude))
|
||||
|
||||
@kernel
|
||||
def set_att_mu(self, att=int32(0)):
|
||||
def set_att_mu(self, att):
|
||||
"""Set digital step attenuator in machine units.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`
|
||||
|
|
|
@ -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.coredevice.ad9912_reg import *
|
||||
|
||||
from numpy import int32, int64
|
||||
from artiq.coredevice import spi2 as spi
|
||||
from artiq.coredevice import urukul
|
||||
|
||||
|
||||
class AD9912:
|
||||
|
@ -39,8 +42,9 @@ class AD9912:
|
|||
self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48)
|
||||
|
||||
@kernel
|
||||
def write(self, addr=int32(0), data=int32(0), length=int32(1)):
|
||||
"""Variable length write to a register. Up to 32 bits.
|
||||
def write(self, addr, data, length):
|
||||
"""Variable length write to a register.
|
||||
Up to 4 bytes.
|
||||
|
||||
:param addr: Register address
|
||||
:param data: Data to be written: int32
|
||||
|
@ -48,51 +52,60 @@ class AD9912:
|
|||
"""
|
||||
assert length > 0
|
||||
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)
|
||||
delay_mu(-self.bus.xfer_period_mu)
|
||||
self.bus.set_xfer(self.chip_select, length*8, 0)
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, length*8,
|
||||
urukul.SPIT_DDS_WR, self.chip_select)
|
||||
self.bus.write(data << (32 - length*8))
|
||||
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
|
||||
|
||||
@kernel
|
||||
def read(self, addr=int32(0), length=int32(1)):
|
||||
"""Variable length read from a register. Up to 32 bits.
|
||||
def read(self, addr, length):
|
||||
"""Variable length read from a register.
|
||||
Up to 4 bytes.
|
||||
|
||||
:param addr: Register address
|
||||
:param length: Length in bytes (1-4)
|
||||
:return: Data read
|
||||
"""
|
||||
assert length > 0
|
||||
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)
|
||||
delay_mu(-self.bus.xfer_period_mu)
|
||||
self.bus.set_xfer(self.chip_select, 0, length*8)
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END
|
||||
| spi.SPI_INPUT, length*8,
|
||||
urukul.SPIT_DDS_RD, self.chip_select)
|
||||
self.bus.write(0)
|
||||
delay_mu(2*self.bus.xfer_period_mu)
|
||||
data = self.bus.read_sync()
|
||||
data = self.bus.read()
|
||||
if length < 4:
|
||||
data &= (1 << (length*8)) - 1
|
||||
return data
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
"""Initialize and configure the DDS."""
|
||||
t = now_mu()
|
||||
"""Initialize and configure the DDS.
|
||||
|
||||
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
|
||||
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
|
||||
prodid = self.read(AD9912_PRODIDH, length=2)
|
||||
if (prodid != 0x1982) and (prodid != 0x1902):
|
||||
raise ValueError("Urukul AD9912 product id mismatch")
|
||||
delay(10*us)
|
||||
delay(20*us)
|
||||
# HSTL power down, CMOS power down
|
||||
self.write(AD9912_PWRCNTRL1, 0x80)
|
||||
delay(10*us)
|
||||
self.write(AD9912_N_DIV, self.pll_n//2 - 2)
|
||||
delay(10*us)
|
||||
self.write(AD9912_PWRCNTRL1, 0x80, length=1)
|
||||
self.cpld.io_update.pulse(1*us)
|
||||
self.write(AD9912_N_DIV, self.pll_n//2 - 2, length=1)
|
||||
self.cpld.io_update.pulse(1*us)
|
||||
# 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
|
||||
def set_att_mu(self, att):
|
||||
|
@ -110,12 +123,12 @@ class AD9912:
|
|||
|
||||
.. 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)
|
||||
|
||||
@kernel
|
||||
def set_mu(self, ftw=int64(0), pow=int32(0)):
|
||||
def set_mu(self, ftw, pow):
|
||||
"""Set profile 0 data in machine units.
|
||||
|
||||
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.
|
||||
"""
|
||||
# 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))
|
||||
delay_mu(-self.bus.xfer_period_mu)
|
||||
self.bus.set_xfer(self.chip_select, 32, 0)
|
||||
self.bus.write((pow << 16) | int32(ftw >> 32))
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
|
||||
urukul.SPIT_DDS_WR, self.chip_select)
|
||||
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))
|
||||
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
|
||||
self.cpld.io_update.pulse(10*ns)
|
||||
|
||||
@portable(flags={"fast-math"})
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""
|
||||
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
|
||||
time is an error.
|
||||
"""
|
||||
|
|
|
@ -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 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_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
|
||||
|
||||
# SPI clock write and read dividers
|
||||
_SPIT_CFG_WR = 2
|
||||
_SPIT_CFG_RD = 16
|
||||
_SPIT_ATT_WR = 2
|
||||
_SPIT_ATT_RD = 16
|
||||
_SPIT_DDS_WR = 3
|
||||
_SPIT_DDS_RD = 16
|
||||
SPIT_CFG_WR = 2
|
||||
SPIT_CFG_RD = 16
|
||||
SPIT_ATT_WR = 2
|
||||
SPIT_ATT_RD = 16
|
||||
SPIT_DDS_WR = 2
|
||||
SPIT_DDS_RD = 16
|
||||
|
||||
# CFG configuration register bit offsets
|
||||
CFG_RF_SW = 0
|
||||
|
@ -29,17 +30,6 @@ CFG_SYNC_SEL = 18
|
|||
CFG_RST = 19
|
||||
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_RF_SW = 0
|
||||
STA_SMP_ERR = 4
|
||||
|
@ -47,32 +37,6 @@ STA_PLL_LOCK = 8
|
|||
STA_IFC_MODE = 12
|
||||
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
|
||||
STA_PROTO_REV_MATCH = 0x08
|
||||
|
||||
|
@ -86,6 +50,51 @@ CS_DDS_CH2 = 6
|
|||
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:
|
||||
"""Urukul CPLD SPI router and configuration interface.
|
||||
|
||||
|
@ -94,11 +103,18 @@ class CPLD:
|
|||
:param dds_reset_device: DDS reset RTIO TTLOut channel name
|
||||
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
|
||||
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
|
||||
"""
|
||||
kernel_invariants = {"refclk", "bus", "core", "io_update"}
|
||||
|
||||
def __init__(self, dmgr, spi_device, io_update_device,
|
||||
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.refclk = refclk
|
||||
|
@ -108,63 +124,83 @@ class CPLD:
|
|||
if dds_reset_device is not None:
|
||||
self.dds_reset = dmgr.get(dds_reset_device)
|
||||
|
||||
self.cfg_reg = int32(0)
|
||||
self.att_reg = int32(0)
|
||||
self.cfg_reg = urukul_cfg(rf_sw=0, led=0, profile=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
|
||||
def cfg_write(self, data=int32(0)):
|
||||
def cfg_write(self, cfg):
|
||||
"""Write to the configuration register.
|
||||
|
||||
See :func:`urukul_cfg` for possible flags.
|
||||
|
||||
:param data: 24 bit data to be written. Will be stored at
|
||||
:attr:`cfg_reg`.
|
||||
"""
|
||||
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD)
|
||||
self.bus.set_xfer(CS_CFG, 24, 0)
|
||||
self.bus.write(data << 8)
|
||||
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD)
|
||||
self.cfg_reg = data
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24,
|
||||
SPIT_CFG_WR, CS_CFG)
|
||||
self.bus.write(cfg << 8)
|
||||
self.cfg_reg = cfg
|
||||
|
||||
@kernel
|
||||
def sta_read(self):
|
||||
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD)
|
||||
self.bus.set_xfer(CS_CFG, 0, 24)
|
||||
"""Read the status register.
|
||||
|
||||
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.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD)
|
||||
return self.bus.read_sync()
|
||||
return self.bus.read()
|
||||
|
||||
@kernel
|
||||
def init(self, clk_sel=0, sync_sel=0):
|
||||
cfg = urukul_cfg(rf_sw=0, led=0, profile=0,
|
||||
io_update=0, mask_nu=0, clk_sel=clk_sel,
|
||||
sync_sel=sync_sel, rst=0, io_rst=0)
|
||||
self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST))
|
||||
delay(1*ms)
|
||||
self.cfg_write(cfg)
|
||||
delay(10*ms) # DDS wake up
|
||||
def init(self):
|
||||
"""Initialize and detect Urukul.
|
||||
|
||||
Resets the DDS and verifies correct CPLD gateware version.
|
||||
"""
|
||||
cfg = self.cfg_reg
|
||||
self.cfg_reg = cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)
|
||||
proto_rev = urukul_sta_proto_rev(self.sta_read())
|
||||
if proto_rev != STA_PROTO_REV_MATCH:
|
||||
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
|
||||
def io_rst(self):
|
||||
delay(1*us)
|
||||
"""Pulse 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))
|
||||
delay(1*us)
|
||||
|
||||
@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
|
||||
if on:
|
||||
c |= 1 << sw
|
||||
c |= 1 << channel
|
||||
else:
|
||||
c &= ~(1 << sw)
|
||||
c &= ~(1 << channel)
|
||||
self.cfg_write(c)
|
||||
|
||||
@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.
|
||||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
|
@ -173,16 +209,28 @@ class CPLD:
|
|||
"""
|
||||
a = self.att_reg & ~(0xff << (channel * 8))
|
||||
a |= att << (channel * 8)
|
||||
self.att_reg = a
|
||||
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD)
|
||||
self.bus.set_xfer(CS_ATT, 32, 0)
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
|
||||
SPIT_ATT_WR, CS_ATT)
|
||||
self.bus.write(a)
|
||||
self.att_reg = a
|
||||
|
||||
@kernel
|
||||
def set_att(self, channel, att):
|
||||
"""Set digital step attenuator in SI units.
|
||||
|
||||
: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)))
|
||||
|
||||
@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()
|
||||
|
|
|
@ -188,7 +188,7 @@ device_db = {
|
|||
|
||||
"spi_novogorny0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
"arguments": {"channel": 24}
|
||||
},
|
||||
|
@ -201,7 +201,7 @@ device_db = {
|
|||
|
||||
"spi_urukul0": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
"arguments": {"channel": 26}
|
||||
},
|
||||
|
@ -242,7 +242,8 @@ device_db = {
|
|||
"arguments": {
|
||||
"spi_device": "spi_urukul0",
|
||||
"io_update_device": "ttl_urukul0_io_update",
|
||||
"refclk": 100e6
|
||||
"refclk": 100e6,
|
||||
"clk_sel": 1
|
||||
}
|
||||
},
|
||||
"urukul0_ch0": {
|
||||
|
|
|
@ -11,9 +11,6 @@ class UrukulTest(EnvExperiment):
|
|||
self.setattr_device("urukul0_ch3")
|
||||
self.setattr_device("led0")
|
||||
|
||||
def p(self, f, *a):
|
||||
print(f % a)
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.core.reset()
|
||||
|
@ -21,7 +18,7 @@ class UrukulTest(EnvExperiment):
|
|||
delay(5*ms)
|
||||
self.led0.off()
|
||||
|
||||
self.urukul0_cpld.init(clk_sel=0)
|
||||
self.urukul0_cpld.init()
|
||||
self.urukul0_ch0.init()
|
||||
self.urukul0_ch1.init()
|
||||
self.urukul0_ch2.init()
|
||||
|
|
|
@ -192,7 +192,7 @@ device_db = {
|
|||
|
||||
"spi_urukul": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.spi",
|
||||
"module": "artiq.coredevice.spi2",
|
||||
"class": "SPIMaster",
|
||||
"arguments": {"channel": 32}
|
||||
},
|
||||
|
|
|
@ -16,9 +16,6 @@ class UrukulTest(EnvExperiment):
|
|||
self.setattr_device("urukul_ch3b")
|
||||
self.setattr_device("led")
|
||||
|
||||
def p(self, f, *a):
|
||||
print(f % a)
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.core.reset()
|
||||
|
@ -28,7 +25,7 @@ class UrukulTest(EnvExperiment):
|
|||
self.fmcdio_dirctl.set(0x0A008800)
|
||||
self.led.off()
|
||||
|
||||
self.urukul_cpld.init(clk_sel=0)
|
||||
self.urukul_cpld.init()
|
||||
self.urukul_ch0b.init()
|
||||
self.urukul_ch1b.init()
|
||||
self.urukul_ch2b.init()
|
||||
|
@ -54,24 +51,19 @@ class UrukulTest(EnvExperiment):
|
|||
self.urukul_ch3b.sw.on()
|
||||
self.urukul_ch3b.set_att(20.)
|
||||
|
||||
i = 0
|
||||
j = 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)
|
||||
data = 0
|
||||
errors = 0
|
||||
delay(100*us)
|
||||
if k != i:
|
||||
#print(i)
|
||||
#print(k)
|
||||
#if j > 20:
|
||||
# return
|
||||
j += 1
|
||||
#delay(20*ms)
|
||||
i += 1
|
||||
while data != -1:
|
||||
self.urukul_ch0b.write32(0x07, data)
|
||||
read = self.urukul_ch0b.read32(0x07)
|
||||
if read != data:
|
||||
errors += 1
|
||||
if errors > 20:
|
||||
return
|
||||
data += 1
|
||||
|
||||
while True:
|
||||
while False:
|
||||
self.urukul_ch0b.sw.pulse(5*ms)
|
||||
delay(5*ms)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from misoc.integration.builder import builder_args, builder_argdict
|
|||
|
||||
from artiq.gateware.amp import AMPSoC
|
||||
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 import DRTIOMaster, DRTIOSatellite
|
||||
from artiq.build_soc import build_artiq_soc
|
||||
|
@ -265,7 +265,7 @@ class Opticlock(_StandaloneBase):
|
|||
self.submodules += 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.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
@ -276,7 +276,7 @@ class Opticlock(_StandaloneBase):
|
|||
self.submodules += 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.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
|
|
@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict
|
|||
from artiq.gateware.amp import AMPSoC
|
||||
from artiq.gateware import rtio, nist_clock, nist_qc2
|
||||
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 import __version__ as artiq_version
|
||||
|
||||
|
@ -355,7 +355,7 @@ class NIST_CLOCK(_StandaloneBase):
|
|||
self.submodules += dac_monitor
|
||||
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.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
|
Loading…
Reference in New Issue