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
pull/1017/head
Robert Jördens 2018-05-21 18:28:19 +02:00
parent 4e5fe672e7
commit 4e863b32a1
6 changed files with 74 additions and 17 deletions

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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.

View File

@ -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

View File

@ -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,