artiq_sinara_tester: port to NAC3

This commit is contained in:
Sebastien Bourdeauducq 2022-03-03 17:07:27 +08:00
parent ba106de24f
commit 9d82f968f9
1 changed files with 106 additions and 87 deletions

View File

@ -6,8 +6,21 @@ import os
import select import select
import sys import sys
from numpy import int32
from artiq.experiment import * from artiq.experiment import *
from artiq.coredevice.core import Core
from artiq.coredevice.ttl import TTLOut, TTLInOut
from artiq.coredevice.urukul import CPLD as UrukulCPLD
from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom
from artiq.coredevice.mirny import Mirny, Almazny
from artiq.coredevice.adf5356 import ADF5356
from artiq.coredevice.sampler import Sampler
from artiq.coredevice.zotino import Zotino
from artiq.coredevice.fastino import Fastino
from artiq.coredevice.phaser import Phaser
from artiq.coredevice.grabber import Grabber
from artiq.coredevice.suservo import SUServo, Channel as SUServoChannel
from artiq.master.databases import DeviceDB from artiq.master.databases import DeviceDB
from artiq.master.worker_db import DeviceManager from artiq.master.worker_db import DeviceManager
@ -27,7 +40,8 @@ def chunker(seq, size):
yield res yield res
def is_enter_pressed() -> TBool: @rpc
def is_enter_pressed() -> bool:
if os.name == "nt": if os.name == "nt":
if msvcrt.kbhit() and msvcrt.getch() == b"\r": if msvcrt.kbhit() and msvcrt.getch() == b"\r":
return True return True
@ -41,7 +55,10 @@ def is_enter_pressed() -> TBool:
return False return False
@nac3
class SinaraTester(EnvExperiment): class SinaraTester(EnvExperiment):
core: KernelInvariant[Core]
def build(self): def build(self):
self.setattr_device("core") self.setattr_device("core")
@ -149,7 +166,7 @@ class SinaraTester(EnvExperiment):
self.suschannels = sorted(self.suschannels.items(), key=lambda x: x[1].channel) self.suschannels = sorted(self.suschannels.items(), key=lambda x: x[1].channel)
@kernel @kernel
def test_led(self, led): def test_led(self, led: TTLOut):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -157,8 +174,8 @@ class SinaraTester(EnvExperiment):
while self.core.get_rtio_counter_mu() < t: while self.core.get_rtio_counter_mu() < t:
pass pass
for i in range(3): for i in range(3):
led.pulse(100*ms) led.pulse(100.*ms)
delay(100*ms) self.core.delay(100.*ms)
def test_leds(self): def test_leds(self):
print("*** Testing LEDs.") print("*** Testing LEDs.")
@ -169,7 +186,7 @@ class SinaraTester(EnvExperiment):
self.test_led(led_dev) self.test_led(led_dev)
@kernel @kernel
def test_ttl_out_chunk(self, ttl_chunk): def test_ttl_out_chunk(self, ttl_chunk: list[TTLOut]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
for _ in range(50000): for _ in range(50000):
@ -177,9 +194,9 @@ class SinaraTester(EnvExperiment):
for ttl in ttl_chunk: for ttl in ttl_chunk:
i += 1 i += 1
for _ in range(i): for _ in range(i):
ttl.pulse(1*us) ttl.pulse(1.*us)
delay(1*us) self.core.delay(1.*us)
delay(10*us) self.core.delay(10.*us)
def test_ttl_outs(self): def test_ttl_outs(self):
print("*** Testing TTL outputs.") print("*** Testing TTL outputs.")
@ -193,16 +210,16 @@ class SinaraTester(EnvExperiment):
self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) self.test_ttl_out_chunk([dev for name, dev in ttl_chunk])
@kernel @kernel
def test_ttl_in(self, ttl_out, ttl_in): def test_ttl_in(self, ttl_out: TTLOut, ttl_in: TTLInOut) -> bool:
n = 42 n = 42
self.core.break_realtime() self.core.break_realtime()
with parallel: with parallel:
ttl_in.gate_rising(1*ms) ttl_in.gate_rising(1.*ms)
with sequential: with sequential:
delay(50*us) self.core.delay(50.*us)
for _ in range(n): for _ in range(n):
ttl_out.pulse(2*us) ttl_out.pulse(2.*us)
delay(2*us) self.core.delay(2.*us)
return ttl_in.count(now_mu()) == n return ttl_in.count(now_mu()) == n
def test_ttl_ins(self): def test_ttl_ins(self):
@ -227,23 +244,25 @@ class SinaraTester(EnvExperiment):
print("FAILED") print("FAILED")
@kernel @kernel
def init_urukul(self, cpld): def init_urukul(self, cpld: UrukulCPLD):
self.core.break_realtime() self.core.break_realtime()
cpld.init() cpld.init()
@kernel @kernel
def test_urukul_att(self, cpld): def test_urukul_att(self, cpld: UrukulCPLD):
self.core.break_realtime() self.core.break_realtime()
for i in range(32): for i in range(32):
test_word = 1 << i test_word = 1 << i
cpld.set_all_att_mu(test_word) cpld.set_all_att_mu(test_word)
readback_word = cpld.get_att_mu() readback_word = cpld.get_att_mu()
if readback_word != test_word: if readback_word != test_word:
print(readback_word, test_word) # NAC3TODO print(readback_word, test_word)
raise ValueError # NAC3TODO raise ValueError
pass
# NAC3TODO: AD9912 support
@kernel @kernel
def calibrate_urukul(self, channel): def calibrate_urukul(self, channel: AD9910) -> tuple[int32, int32]:
self.core.break_realtime() self.core.break_realtime()
channel.init() channel.init()
self.core.break_realtime() self.core.break_realtime()
@ -253,7 +272,7 @@ class SinaraTester(EnvExperiment):
return sync_delay_seed, io_update_delay return sync_delay_seed, io_update_delay
@kernel @kernel
def setup_urukul(self, channel, frequency): def setup_urukul(self, channel: AD9910, frequency: float):
self.core.break_realtime() self.core.break_realtime()
channel.init() channel.init()
channel.set(frequency*MHz) channel.set(frequency*MHz)
@ -261,12 +280,12 @@ class SinaraTester(EnvExperiment):
channel.set_att(6.) channel.set_att(6.)
@kernel @kernel
def cfg_sw_off_urukul(self, channel): def cfg_sw_off_urukul(self, channel: AD9910):
self.core.break_realtime() self.core.break_realtime()
channel.cfg_sw(False) channel.cfg_sw(False)
@kernel @kernel
def rf_switch_wave(self, channels): def rf_switch_wave(self, channels: list[TTLOut]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -274,8 +293,8 @@ class SinaraTester(EnvExperiment):
while self.core.get_rtio_counter_mu() < t: while self.core.get_rtio_counter_mu() < t:
pass pass
for channel in channels: for channel in channels:
channel.pulse(100*ms) channel.pulse(100.*ms)
delay(100*ms) self.core.delay(100.*ms)
# We assume that RTIO channels for switches are grouped by card. # We assume that RTIO channels for switches are grouped by card.
def test_urukuls(self): def test_urukuls(self):
@ -322,12 +341,12 @@ class SinaraTester(EnvExperiment):
self.rf_switch_wave([swi.sw for swi in sw]) self.rf_switch_wave([swi.sw for swi in sw])
@kernel @kernel
def init_mirny(self, cpld): def init_mirny(self, cpld: Mirny):
self.core.break_realtime() self.core.break_realtime()
cpld.init() cpld.init()
@kernel @kernel
def setup_mirny(self, channel, frequency): def setup_mirny(self, channel: ADF5356, frequency: float):
self.core.break_realtime() self.core.break_realtime()
channel.init() channel.init()
@ -336,15 +355,15 @@ class SinaraTester(EnvExperiment):
self.core.break_realtime() self.core.break_realtime()
channel.set_frequency(frequency*MHz) channel.set_frequency(frequency*MHz)
delay(5*ms) self.core.delay(5.*ms)
@kernel @kernel
def sw_off_mirny(self, channel): def sw_off_mirny(self, channel: ADF5356):
self.core.break_realtime() self.core.break_realtime()
channel.sw.off() channel.sw.off()
@kernel @kernel
def mirny_rf_switch_wave(self, channels): def mirny_rf_switch_wave(self, channels: list[TTLOut]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -352,26 +371,26 @@ class SinaraTester(EnvExperiment):
while self.core.get_rtio_counter_mu() < t: while self.core.get_rtio_counter_mu() < t:
pass pass
for channel in channels: for channel in channels:
channel.pulse(100*ms) channel.pulse(100.*ms)
delay(100*ms) self.core.delay(100.*ms)
@kernel @kernel
def init_almazny(self, almazny): def init_almazny(self, almazny: Almazny):
self.core.break_realtime() self.core.break_realtime()
almazny.init() almazny.init()
almazny.output_toggle(True) almazny.output_toggle(True)
@kernel @kernel
def almazny_set_attenuators_mu(self, almazny, ch, atts): def almazny_set_attenuators_mu(self, almazny: Almazny, ch: int32, atts: int32):
self.core.break_realtime() self.core.break_realtime()
almazny.set_att_mu(ch, atts) almazny.set_att_mu(ch, atts)
@kernel @kernel
def almazny_set_attenuators(self, almazny, ch, atts): def almazny_set_attenuators(self, almazny: Almazny, ch: int32, atts: float):
self.core.break_realtime() self.core.break_realtime()
almazny.set_att(ch, atts) almazny.set_att(ch, atts)
@kernel @kernel
def almazny_toggle_output(self, almazny, rf_on): def almazny_toggle_output(self, almazny: Almazny, rf_on: bool):
self.core.break_realtime() self.core.break_realtime()
almazny.output_toggle(rf_on) almazny.output_toggle(rf_on)
@ -445,17 +464,21 @@ class SinaraTester(EnvExperiment):
self.sw_off_mirny(swi) self.sw_off_mirny(swi)
self.mirny_rf_switch_wave([swi.sw for swi in sw]) self.mirny_rf_switch_wave([swi.sw for swi in sw])
@rpc
def update_sampler_voltages(self, voltages: list[float]):
self.sampler_voltages = voltages
@kernel @kernel
def get_sampler_voltages(self, sampler, cb): def get_sampler_voltages(self, sampler: Sampler):
self.core.break_realtime() self.core.break_realtime()
sampler.init() sampler.init()
delay(5*ms) self.core.delay(5.*ms)
for i in range(8): for i in range(8):
sampler.set_gain_mu(i, 0) sampler.set_gain_mu(i, 0)
delay(100*us) self.core.delay(100.*us)
smp = [0.0]*8 smp = [0. for _ in range(8)]
sampler.sample(smp) sampler.sample(smp)
cb(smp) self.update_sampler_voltages(smp)
def test_samplers(self): def test_samplers(self):
print("*** Testing Sampler ADCs.") print("*** Testing Sampler ADCs.")
@ -466,14 +489,10 @@ class SinaraTester(EnvExperiment):
print("Apply 1.5V to channel {}. Press ENTER when done.".format(channel)) print("Apply 1.5V to channel {}. Press ENTER when done.".format(channel))
input() input()
voltages = [] self.get_sampler_voltages(card_dev)
def setv(x):
nonlocal voltages
voltages = x
self.get_sampler_voltages(card_dev, setv)
passed = True passed = True
for n, voltage in enumerate(voltages): for n, voltage in enumerate(self.sampler_voltages):
if n == channel: if n == channel:
if abs(voltage - 1.5) > 0.2: if abs(voltage - 1.5) > 0.2:
passed = False passed = False
@ -484,22 +503,22 @@ class SinaraTester(EnvExperiment):
print("PASSED") print("PASSED")
else: else:
print("FAILED") print("FAILED")
print(" ".join(["{:.1f}".format(x) for x in voltages])) print(" ".join(["{:.1f}".format(x) for x in self.sampler_voltages]))
@kernel @kernel
def set_zotino_voltages(self, zotino, voltages): def set_zotino_voltages(self, zotino: Zotino, voltages: list[float]):
self.core.break_realtime() self.core.break_realtime()
zotino.init() zotino.init()
delay(200*us) self.core.delay(200.*us)
i = 0 i = 0
for voltage in voltages: for voltage in voltages:
zotino.write_dac(i, voltage) zotino.write_dac(i, voltage)
delay(100*us) self.core.delay(100.*us)
i += 1 i += 1
zotino.load() zotino.load()
@kernel @kernel
def zotinos_led_wave(self, zotinos): def zotinos_led_wave(self, zotinos: list[Zotino]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -509,9 +528,9 @@ class SinaraTester(EnvExperiment):
for zotino in zotinos: for zotino in zotinos:
for i in range(8): for i in range(8):
zotino.set_leds(1 << i) zotino.set_leds(1 << i)
delay(100*ms) self.core.delay(100.*ms)
zotino.set_leds(0) zotino.set_leds(0)
delay(100*ms) self.core.delay(100.*ms)
def test_zotinos(self): def test_zotinos(self):
print("*** Testing Zotino DACs and USER LEDs.") print("*** Testing Zotino DACs and USER LEDs.")
@ -527,18 +546,18 @@ class SinaraTester(EnvExperiment):
) )
@kernel @kernel
def set_fastino_voltages(self, fastino, voltages): def set_fastino_voltages(self, fastino: Fastino, voltages: list[float]):
self.core.break_realtime() self.core.break_realtime()
fastino.init() fastino.init()
delay(200*us) self.core.delay(200.*us)
i = 0 i = 0
for voltage in voltages: for voltage in voltages:
fastino.set_dac(i, voltage) fastino.set_dac(i, voltage)
delay(100*us) self.core.delay(100.*us)
i += 1 i += 1
@kernel @kernel
def fastinos_led_wave(self, fastinos): def fastinos_led_wave(self, fastinos: list[Fastino]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -548,9 +567,9 @@ class SinaraTester(EnvExperiment):
for fastino in fastinos: for fastino in fastinos:
for i in range(8): for i in range(8):
fastino.set_leds(1 << i) fastino.set_leds(1 << i)
delay(100*ms) self.core.delay(100.*ms)
fastino.set_leds(0) fastino.set_leds(0)
delay(100*ms) self.core.delay(100.*ms)
def test_fastinos(self): def test_fastinos(self):
print("*** Testing Fastino DACs and USER LEDs.") print("*** Testing Fastino DACs and USER LEDs.")
@ -566,27 +585,27 @@ class SinaraTester(EnvExperiment):
) )
@kernel @kernel
def set_phaser_frequencies(self, phaser, duc, osc): def set_phaser_frequencies(self, phaser: Phaser, duc: float, osc: list[float]):
self.core.break_realtime() self.core.break_realtime()
phaser.init() phaser.init()
delay(1*ms) self.core.delay(1.*ms)
phaser.channel[0].set_duc_frequency(duc) phaser.channel[0].set_duc_frequency(duc)
phaser.channel[0].set_duc_cfg() phaser.channel[0].set_duc_cfg()
phaser.channel[0].set_att(6*dB) phaser.channel[0].set_att(6.*dB)
phaser.channel[1].set_duc_frequency(-duc) phaser.channel[1].set_duc_frequency(-duc)
phaser.channel[1].set_duc_cfg() phaser.channel[1].set_duc_cfg()
phaser.channel[1].set_att(6*dB) phaser.channel[1].set_att(6.*dB)
phaser.duc_stb() phaser.duc_stb()
delay(1*ms) self.core.delay(1.*ms)
for i in range(len(osc)): for i in range(len(osc)):
phaser.channel[0].oscillator[i].set_frequency(osc[i]) phaser.channel[0].oscillator[i].set_frequency(osc[i])
phaser.channel[0].oscillator[i].set_amplitude_phase(.2) phaser.channel[0].oscillator[i].set_amplitude_phase(.2)
phaser.channel[1].oscillator[i].set_frequency(-osc[i]) phaser.channel[1].oscillator[i].set_frequency(-osc[i])
phaser.channel[1].oscillator[i].set_amplitude_phase(.2) phaser.channel[1].oscillator[i].set_amplitude_phase(.2)
delay(1*ms) self.core.delay(1.*ms)
@kernel @kernel
def phaser_led_wave(self, phasers): def phaser_led_wave(self, phasers: list[Phaser]):
while not is_enter_pressed(): while not is_enter_pressed():
self.core.break_realtime() self.core.break_realtime()
# do not fill the FIFOs too much to avoid long response times # do not fill the FIFOs too much to avoid long response times
@ -596,9 +615,9 @@ class SinaraTester(EnvExperiment):
for phaser in phasers: for phaser in phasers:
for i in range(6): for i in range(6):
phaser.set_leds(1 << i) phaser.set_leds(1 << i)
delay(100*ms) self.core.delay(100.*ms)
phaser.set_leds(0) phaser.set_leds(0)
delay(100*ms) self.core.delay(100.*ms)
def test_phasers(self): def test_phasers(self):
print("*** Testing Phaser DACs and 6 USER LEDs.") print("*** Testing Phaser DACs and 6 USER LEDs.")
@ -617,9 +636,9 @@ class SinaraTester(EnvExperiment):
) )
@kernel @kernel
def grabber_capture(self, card_dev, rois): def grabber_capture(self, card_dev: Grabber, rois: list[list[int32]]):
self.core.break_realtime() self.core.break_realtime()
delay(100*us) self.core.delay(100.*us)
mask = 0 mask = 0
for i in range(len(rois)): for i in range(len(rois)):
i = rois[i][0] i = rois[i][0]
@ -630,11 +649,11 @@ class SinaraTester(EnvExperiment):
mask |= 1 << i mask |= 1 << i
card_dev.setup_roi(i, x0, y0, x1, y1) card_dev.setup_roi(i, x0, y0, x1, y1)
card_dev.gate_roi(mask) card_dev.gate_roi(mask)
n = [0]*len(rois) n = [0 for _ in range(len(rois))]
card_dev.input_mu(n) card_dev.input_mu(n)
self.core.break_realtime() self.core.break_realtime()
card_dev.gate_roi(0) card_dev.gate_roi(0)
print("ROI sums:", n) # NAC3TODO print("ROI sums:", n)
def test_grabbers(self): def test_grabbers(self):
print("*** Testing Grabber Frame Grabbers.") print("*** Testing Grabber Frame Grabbers.")
@ -651,25 +670,25 @@ class SinaraTester(EnvExperiment):
self.grabber_capture(card_dev, rois) self.grabber_capture(card_dev, rois)
@kernel @kernel
def setup_suservo(self, channel): def setup_suservo(self, channel: SUServo):
self.core.break_realtime() self.core.break_realtime()
channel.init() channel.init()
delay(1*us) self.core.delay(1.*us)
# ADC PGIA gain 0 # ADC PGIA gain 0
for i in range(8): for i in range(8):
channel.set_pgia_mu(i, 0) channel.set_pgia_mu(i, 0)
delay(10*us) self.core.delay(10.*us)
# DDS attenuator 10dB # DDS attenuator 10dB
for i in range(4): for i in range(4):
for cpld in channel.cplds: for cpld in channel.cplds:
cpld.set_att(i, 10.) cpld.set_att(i, 10.)
delay(1*us) self.core.delay(1.*us)
# Servo is done and disabled # Servo is done and disabled
assert channel.get_status() & 0xff == 2 # NAC3TODO assert channel.get_status() & 0xff == 2
delay(10*us) self.core.delay(10.*us)
@kernel @kernel
def setup_suservo_loop(self, channel, loop_nr): def setup_suservo_loop(self, channel: SUServoChannel, loop_nr: int32):
self.core.break_realtime() self.core.break_realtime()
channel.set_y( channel.set_y(
profile=loop_nr, profile=loop_nr,
@ -684,24 +703,24 @@ class SinaraTester(EnvExperiment):
delay=0. # no IIR update delay after enabling delay=0. # no IIR update delay after enabling
) )
# setpoint 0.5 (5 V with above PGIA gain setting) # setpoint 0.5 (5 V with above PGIA gain setting)
delay(100*us) self.core.delay(100.*us)
channel.set_dds( channel.set_dds(
profile=loop_nr, profile=loop_nr,
offset=-.3, # 3 V with above PGIA settings offset=-.3, # 3 V with above PGIA settings
frequency=10*MHz, frequency=10.*MHz,
phase=0.) phase=0.)
# enable RF, IIR updates and set profile # enable RF, IIR updates and set profile
delay(10*us) self.core.delay(10.*us)
channel.set(en_out=1, en_iir=1, profile=loop_nr) channel.set(en_out=True, en_iir=True, profile=loop_nr)
@kernel @kernel
def setup_start_suservo(self, channel): def setup_start_suservo(self, channel: SUServo):
self.core.break_realtime() self.core.break_realtime()
channel.set_config(enable=1) channel.set_config(enable=True)
delay(10*us) self.core.delay(10.*us)
# check servo enabled # check servo enabled
assert channel.get_status() & 0x01 == 1 # NAC3TODO assert channel.get_status() & 0x01 == 1
delay(10*us) self.core.delay(10.*us)
def test_suservos(self): def test_suservos(self):
print("*** Testing SUServos.") print("*** Testing SUServos.")