forked from M-Labs/artiq
coredevice: configurable initial backing state
Several core device drivers maintain a copy of some device state. Since this copy is not transferred between experiments this backing state can be different from device state when a new experiment is started. This commit adds support for injecting initial backing state into experiments via the device database and sets initial backing state where known. ad53xx (zotino): spi2 xfer_duration novogorny: pgia gains sampler: pgia gains, spi2 pgia and adc xfer_duration suservo: pgia gains, spi2 pgia xfer_duration urukul: cpld cfg (partial: rf_sw), attenuator register spi2: div/length for xfer_duration close #1003
This commit is contained in:
parent
4e5fe672e7
commit
4e863b32a1
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue