sampler: fix reference voltage of recent hardware

pull/2016/head
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
variant.
* 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
-------

View File

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

View File

@ -15,24 +15,26 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK
@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.
:param data: 16 bit signed ADC word
: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
"""
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:
volt_per_lsb = 2./(1 << 16)
volt_per_lsb = 2.048 / (1 << 16) if corrected_fs else 2. / (1 << 16)
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:
volt_per_lsb = .02/(1 << 16)
volt_per_lsb = 0.02048 / (1 << 16) if corrected_fs else .02 / (1 << 16)
else:
raise ValueError("invalid gain")
return data*volt_per_lsb
return data * volt_per_lsb
class Sampler:
@ -48,12 +50,13 @@ class Sampler:
:param gains: Initial value for PGIA gains shift register
(default: 0x0000). Knowledge of this state is not transferred
between experiments.
:param hw_rev: Sampler's hardware revision string (default 'v2.2')
: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,
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.update_xfer_duration_mu(div, 32)
self.bus_pgia = dmgr.get(spi_pgia_device)
@ -62,6 +65,11 @@ class Sampler:
self.cnv = dmgr.get(cnv_device)
self.div = div
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
def init(self):
@ -144,4 +152,4 @@ class Sampler:
for i in range(n):
channel = i + 8 - len(data)
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
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."""
val = (x >> 1) & 0xffff
mask = 1 << 15
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:
@ -62,14 +62,15 @@ class SUServo:
:param gains: Initial value for PGIA gains shift register
(default: 0x0000). Knowledge of this state is not transferred
between experiments.
:param sampler_hw_rev: Sampler's revision string
:param core_device: Core device name
"""
kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses",
"ref_period_mu"}
"ref_period_mu", "corrected_fs"}
def __init__(self, dmgr, channel, pgia_device,
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.pgia = dmgr.get(pgia_device)
@ -81,6 +82,7 @@ class SUServo:
self.gains = gains
self.ref_period_mu = self.core.seconds_to_mu(
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
@kernel
@ -234,7 +236,7 @@ class SUServo:
"""
val = self.get_adc_mu(channel)
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:

View File

@ -410,10 +410,12 @@ class PeripheralManager:
"arguments": {{
"spi_adc_device": "spi_{name}_adc",
"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"),
hw_rev=peripheral.get("hw_rev", "v2.2"),
adc_channel=rtio_offset,
pgia_channel=rtio_offset + 1,
cnv_channel=rtio_offset + 2)
@ -444,11 +446,13 @@ class PeripheralManager:
"channel": 0x{suservo_channel:06x},
"pgia_device": "spi_{sampler_name}_pgia",
"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,
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],
dds_names_list=[urukul_name + "_dds" for urukul_name in urukul_names],
suservo_channel=rtio_offset+next(channel))