diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index dfc347fbc..0b10b3388 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -110,7 +110,8 @@ class AD53xx: valid) :param vref: DAC reference voltage (default: 5.) :param offset_dacs: Initial register value for the two offset DACs, device - dependent and must be set correctly for correct voltage to mu conversions + dependent and must be set correctly for correct voltage to mu conversions. + Knowledge of his state is not transferred between experiments. (default: 8192) :param core_device: Core device name (default: "core") """ @@ -121,6 +122,7 @@ class AD53xx: chip_select=1, div_write=4, div_read=16, vref=5., offset_dacs=8192, core="core"): self.bus = dmgr.get(spi_device) + self.bus.update_xfer_duration_mu(div_write, 24) if ldac_device is None: self.ldac = _DummyTTL() else: diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index f92b00e25..49bb9a22c 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -69,17 +69,20 @@ class Novogorny: :param spi_device: SPI bus device name :param cnv_device: CNV RTIO TTLOut channel name :param div: SPI clock divider (default: 8) + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"bus", "core", "cnv", "div", "v_ref"} - def __init__(self, dmgr, spi_device, cnv_device, div=8, + def __init__(self, dmgr, spi_device, cnv_device, div=8, gains=0x0000, core_device="core"): self.bus = dmgr.get(spi_device) self.core = dmgr.get(core_device) self.cnv = dmgr.get(cnv_device) self.div = div - self.gains = 0x0000 + self.gains = gains self.v_ref = 5. # 5 Volt reference @kernel diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 8cf80f071..8679ad93c 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -45,18 +45,23 @@ class Sampler: :param spi_pgia_device: PGIA SPI bus device name :param cnv_device: CNV RTIO TTLOut channel name :param div: SPI clock divider (default: 8) + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, - div=8, core_device="core"): + div=8, gains=0x0000, core_device="core"): self.bus_adc = dmgr.get(spi_adc_device) + self.bus_adc.update_xfer_duration_mu(div, 32) self.bus_pgia = dmgr.get(spi_pgia_device) + self.bus_pgia.update_xfer_duration_mu(div, 16) self.core = dmgr.get(core_device) self.cnv = dmgr.get(cnv_device) self.div = div - self.gains = 0x0000 + self.gains = gains @kernel def init(self): diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index d64f1ad17..c8749b082 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -57,16 +57,20 @@ class SPIMaster: register. :param channel: RTIO channel number of the SPI bus to control. + :param div: Initial CLK divider, see also: :meth:`update_xfer_duration_mu` + :param length: Initial transfer length, see also: + :meth:`update_xfer_duration_mu` + :param core_device: Core device name """ kernel_invariants = {"core", "ref_period_mu", "channel"} - def __init__(self, dmgr, channel, core_device="core"): + def __init__(self, dmgr, channel, div=0, length=0, core_device="core"): self.core = dmgr.get(core_device) self.ref_period_mu = self.core.seconds_to_mu( self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier self.channel = channel - self.xfer_duration_mu = 2*self.ref_period_mu + self.update_xfer_duration_mu(div, length) @portable def frequency_to_div(self, f): @@ -162,11 +166,31 @@ class SPIMaster: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") - self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) + self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu) + @portable + def update_xfer_duration_mu(self, div, length): + """Calculate and set the transfer duration. + + This method updates the SPI transfer duration which is used + in :meth:`write` to advance the timeline. + + Use this method (and avoid having to call :meth:`set_config_mu`) + when the divider and transfer length have been configured + (using :meth:`set_config` or :meth:`set_config_mu`) by previous + experiments and are known. + + This method is portable and can also be called from e.g. + ``__init__``. + + :param div: SPI clock divider (see: :meth:`set_config_mu`) + :param length: SPI transfer length (see: :meth:`set_config_mu`) + """ + self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu + @kernel def write(self, data): """Write SPI data to shift register register and start transfer. diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 5bd4860c1..20ca966cc 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -26,6 +26,9 @@ class SUServo: Urukul :param dds1_device: Name of the AD9910 device for the DDS on the second Urukul + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"channel", "core", "pgia", "cpld0", "cpld1", @@ -34,16 +37,17 @@ class SUServo: def __init__(self, dmgr, channel, pgia_device, cpld0_device, cpld1_device, dds0_device, dds1_device, - core_device="core"): + gains=0x0000, core_device="core"): self.core = dmgr.get(core_device) self.pgia = dmgr.get(pgia_device) + self.pgia.update_xfer_duration_mu(div=4, length=16) self.dds0 = dmgr.get(dds0_device) self.dds1 = dmgr.get(dds1_device) self.cpld0 = dmgr.get(cpld0_device) self.cpld1 = dmgr.get(cpld1_device) self.channel = channel - self.gains = 0x0000 + self.gains = gains self.ref_period_mu = self.core.seconds_to_mu( self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 59dcceb5a..f3d34b93f 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -119,14 +119,18 @@ class CPLD: 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 rf_sw: Initial CPLD RF switch register setting (default: 0x0). + Knowledge of this state is not transferred between experiments. + :param att: Initial attenuator setting shift register (default: + 0x00000000). See also: :meth:`set_all_att_mu`. Knowledge of this state + is not transferred between experiments. :param core_device: Core device name """ kernel_invariants = {"refclk", "bus", "core", "io_update"} def __init__(self, dmgr, spi_device, io_update_device=None, - dds_reset_device=None, - sync_sel=0, clk_sel=0, - refclk=125e6, core_device="core"): + dds_reset_device=None, sync_sel=0, clk_sel=0, rf_sw=0, + refclk=125e6, att=0x00000000, core_device="core"): self.core = dmgr.get(core_device) self.refclk = refclk @@ -139,10 +143,10 @@ class CPLD: if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) - self.cfg_reg = urukul_cfg(rf_sw=0, led=0, profile=0, + self.cfg_reg = urukul_cfg(rf_sw=rf_sw, 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 + self.att_reg = att @kernel def cfg_write(self, cfg): @@ -226,16 +230,28 @@ class CPLD: def set_att_mu(self, channel, att): """Set digital step attenuator in machine units. + This method will write the attenuator settings of all four channels. + :param channel: Attenuator channel (0-3). :param att: Digital attenuation setting: 255 minimum attenuation, 0 maximum attenuation (31.5 dB) """ a = self.att_reg & ~(0xff << (channel * 8)) a |= att << (channel * 8) + self.set_all_att_mu(a) + + @kernel + def set_all_att_mu(self, att_reg): + """Set all four digital step attenuators (in machine units). + + .. seealso:: :meth:`set_att_mu` + + :param att_reg: Attenuator setting string (32 bit) + """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, SPIT_ATT_WR, CS_ATT) - self.bus.write(a) - self.att_reg = a + self.bus.write(att_reg) + self.att_reg = att_reg @kernel def set_att(self, channel, att): @@ -251,6 +267,9 @@ class CPLD: def get_att_mu(self): """Return the digital step attenuator settings in machine units. + This method will also (as a side effect) write the attenuator + settings of all four channels. + :return: 32 bit attenuator settings """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32,