sampler: fix reference voltage of recent hardware

This commit is contained in:
Egor Savkin 2022-12-02 10:45:40 +08:00 committed by GitHub
parent 261dc6b933
commit c591e7e305
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 16 deletions

View File

@ -12,6 +12,9 @@ Highlights:
* Implemented Phaser-MIQRO support. This requires the Phaser MIQRO gateware * Implemented Phaser-MIQRO support. This requires the Phaser MIQRO gateware
variant. variant.
* MSYS2 packaging for Windows. * MSYS2 packaging for Windows.
* Sampler: adjusted ADC MU to Volt conversion base for Sampler since v2.2.
For earlier version please explicitly define it as an argument in the device database file
(e.g. ``"hw_rev": "v2.1"``).
ARTIQ-7 ARTIQ-7
------- -------

View File

@ -376,6 +376,9 @@
"minItems": 2, "minItems": 2,
"maxItems": 2 "maxItems": 2
}, },
"sampler_hw_rev": {
"type": "string"
},
"urukul0_ports": { "urukul0_ports": {
"type": "array", "type": "array",
"items": { "items": {

View File

@ -15,24 +15,26 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK
@portable @portable
def adc_mu_to_volt(data, gain=0): def adc_mu_to_volt(data, gain=0, corrected_fs=True):
"""Convert ADC data in machine units to Volts. """Convert ADC data in machine units to Volts.
:param data: 16 bit signed ADC word :param data: 16 bit signed ADC word
:param gain: PGIA gain setting (0: 1, ..., 3: 1000) :param gain: PGIA gain setting (0: 1, ..., 3: 1000)
:param corrected_fs: use corrected ADC FS reference.
Should be True for Samplers' revisions after v2.1. False for v2.1 and earlier.
:return: Voltage in Volts :return: Voltage in Volts
""" """
if gain == 0: if gain == 0:
volt_per_lsb = 20./(1 << 16) volt_per_lsb = 20.48 / (1 << 16) if corrected_fs else 20. / (1 << 16)
elif gain == 1: elif gain == 1:
volt_per_lsb = 2./(1 << 16) volt_per_lsb = 2.048 / (1 << 16) if corrected_fs else 2. / (1 << 16)
elif gain == 2: elif gain == 2:
volt_per_lsb = .2/(1 << 16) volt_per_lsb = .2048 / (1 << 16) if corrected_fs else .2 / (1 << 16)
elif gain == 3: elif gain == 3:
volt_per_lsb = .02/(1 << 16) volt_per_lsb = 0.02048 / (1 << 16) if corrected_fs else .02 / (1 << 16)
else: else:
raise ValueError("invalid gain") raise ValueError("invalid gain")
return data*volt_per_lsb return data * volt_per_lsb
class Sampler: class Sampler:
@ -48,12 +50,13 @@ class Sampler:
:param gains: Initial value for PGIA gains shift register :param gains: Initial value for PGIA gains shift register
(default: 0x0000). Knowledge of this state is not transferred (default: 0x0000). Knowledge of this state is not transferred
between experiments. between experiments.
:param hw_rev: Sampler's hardware revision string (default 'v2.2')
:param core_device: Core device name :param core_device: Core device name
""" """
kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div", "corrected_fs"}
def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device,
div=8, gains=0x0000, core_device="core"): div=8, gains=0x0000, hw_rev="v2.2", core_device="core"):
self.bus_adc = dmgr.get(spi_adc_device) self.bus_adc = dmgr.get(spi_adc_device)
self.bus_adc.update_xfer_duration_mu(div, 32) self.bus_adc.update_xfer_duration_mu(div, 32)
self.bus_pgia = dmgr.get(spi_pgia_device) self.bus_pgia = dmgr.get(spi_pgia_device)
@ -62,6 +65,11 @@ class Sampler:
self.cnv = dmgr.get(cnv_device) self.cnv = dmgr.get(cnv_device)
self.div = div self.div = div
self.gains = gains self.gains = gains
self.corrected_fs = self.use_corrected_fs(hw_rev)
@staticmethod
def use_corrected_fs(hw_rev):
return hw_rev != "v2.1"
@kernel @kernel
def init(self): def init(self):
@ -144,4 +152,4 @@ class Sampler:
for i in range(n): for i in range(n):
channel = i + 8 - len(data) channel = i + 8 - len(data)
gain = (self.gains >> (channel*2)) & 0b11 gain = (self.gains >> (channel*2)) & 0b11
data[i] = adc_mu_to_volt(adc_data[i], gain) data[i] = adc_mu_to_volt(adc_data[i], gain, self.revision)

View File

@ -23,12 +23,12 @@ def y_mu_to_full_scale(y):
@portable @portable
def adc_mu_to_volts(x, gain): def adc_mu_to_volts(x, gain, corrected_fs=True):
"""Convert servo ADC data from machine units to Volt.""" """Convert servo ADC data from machine units to Volt."""
val = (x >> 1) & 0xffff val = (x >> 1) & 0xffff
mask = 1 << 15 mask = 1 << 15
val = -(val & mask) + (val & ~mask) val = -(val & mask) + (val & ~mask)
return sampler.adc_mu_to_volt(val, gain) return sampler.adc_mu_to_volt(val, gain, corrected_fs)
class SUServo: class SUServo:
@ -62,14 +62,15 @@ class SUServo:
:param gains: Initial value for PGIA gains shift register :param gains: Initial value for PGIA gains shift register
(default: 0x0000). Knowledge of this state is not transferred (default: 0x0000). Knowledge of this state is not transferred
between experiments. between experiments.
:param sampler_hw_rev: Sampler's revision string
:param core_device: Core device name :param core_device: Core device name
""" """
kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses", kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses",
"ref_period_mu"} "ref_period_mu", "corrected_fs"}
def __init__(self, dmgr, channel, pgia_device, def __init__(self, dmgr, channel, pgia_device,
cpld_devices, dds_devices, cpld_devices, dds_devices,
gains=0x0000, core_device="core"): gains=0x0000, sampler_hw_rev="v2.2", core_device="core"):
self.core = dmgr.get(core_device) self.core = dmgr.get(core_device)
self.pgia = dmgr.get(pgia_device) self.pgia = dmgr.get(pgia_device)
@ -81,6 +82,7 @@ class SUServo:
self.gains = gains self.gains = gains
self.ref_period_mu = self.core.seconds_to_mu( self.ref_period_mu = self.core.seconds_to_mu(
self.core.coarse_ref_period) self.core.coarse_ref_period)
self.corrected_fs = sampler.Sampler.use_corrected_fs(sampler_hw_rev)
assert self.ref_period_mu == self.core.ref_multiplier assert self.ref_period_mu == self.core.ref_multiplier
@kernel @kernel
@ -234,7 +236,7 @@ class SUServo:
""" """
val = self.get_adc_mu(channel) val = self.get_adc_mu(channel)
gain = (self.gains >> (channel*2)) & 0b11 gain = (self.gains >> (channel*2)) & 0b11
return adc_mu_to_volts(val, gain) return adc_mu_to_volts(val, gain, self.corrected_fs)
class Channel: class Channel:

View File

@ -410,10 +410,12 @@ class PeripheralManager:
"arguments": {{ "arguments": {{
"spi_adc_device": "spi_{name}_adc", "spi_adc_device": "spi_{name}_adc",
"spi_pgia_device": "spi_{name}_pgia", "spi_pgia_device": "spi_{name}_pgia",
"cnv_device": "ttl_{name}_cnv" "cnv_device": "ttl_{name}_cnv",
"hw_rev": "{hw_rev}"
}} }}
}}""", }}""",
name=self.get_name("sampler"), name=self.get_name("sampler"),
hw_rev=peripheral.get("hw_rev", "v2.2"),
adc_channel=rtio_offset, adc_channel=rtio_offset,
pgia_channel=rtio_offset + 1, pgia_channel=rtio_offset + 1,
cnv_channel=rtio_offset + 2) cnv_channel=rtio_offset + 2)
@ -444,11 +446,13 @@ class PeripheralManager:
"channel": 0x{suservo_channel:06x}, "channel": 0x{suservo_channel:06x},
"pgia_device": "spi_{sampler_name}_pgia", "pgia_device": "spi_{sampler_name}_pgia",
"cpld_devices": {cpld_names_list}, "cpld_devices": {cpld_names_list},
"dds_devices": {dds_names_list} "dds_devices": {dds_names_list},
"sampler_hw_rev": "{sampler_hw_rev}"
}} }}
}}""", }}""",
suservo_name=suservo_name, suservo_name=suservo_name,
sampler_name=sampler_name, sampler_name=sampler_name,
sampler_hw_rev=peripheral.get("sampler_hw_rev", "v2.2"),
cpld_names_list=[urukul_name + "_cpld" for urukul_name in urukul_names], cpld_names_list=[urukul_name + "_cpld" for urukul_name in urukul_names],
dds_names_list=[urukul_name + "_dds" for urukul_name in urukul_names], dds_names_list=[urukul_name + "_dds" for urukul_name in urukul_names],
suservo_channel=rtio_offset+next(channel)) suservo_channel=rtio_offset+next(channel))