forked from M-Labs/artiq
add Almazny support (#1780)
This commit is contained in:
parent
4e3e0d129c
commit
095fb9e333
|
@ -11,6 +11,7 @@ Highlights:
|
||||||
* New hardware support:
|
* New hardware support:
|
||||||
- Kasli-SoC, a new EEM carrier based on a Zynq SoC, enabling much faster kernel execution.
|
- Kasli-SoC, a new EEM carrier based on a Zynq SoC, enabling much faster kernel execution.
|
||||||
- HVAMP_8CH 8 channel HV amplifier for Fastino / Zotinos
|
- HVAMP_8CH 8 channel HV amplifier for Fastino / Zotinos
|
||||||
|
- Almazny mezzanine board for Mirny
|
||||||
* Softcore targets now use the RISC-V architecture (VexRiscv) instead of OR1K (mor1kx).
|
* Softcore targets now use the RISC-V architecture (VexRiscv) instead of OR1K (mor1kx).
|
||||||
* Faster compilation for large arrays/lists.
|
* Faster compilation for large arrays/lists.
|
||||||
* Phaser:
|
* Phaser:
|
||||||
|
|
|
@ -409,6 +409,10 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": 0
|
"default": 0
|
||||||
|
},
|
||||||
|
"almazny": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["ports"]
|
"required": ["ports"]
|
||||||
|
|
|
@ -31,6 +31,16 @@ WE = 1 << 24
|
||||||
# supported CPLD code version
|
# supported CPLD code version
|
||||||
PROTO_REV_MATCH = 0x0
|
PROTO_REV_MATCH = 0x0
|
||||||
|
|
||||||
|
# almazny-specific data
|
||||||
|
ALMAZNY_REG_BASE = 0x0C
|
||||||
|
ALMAZNY_OE_SHIFT = 12
|
||||||
|
|
||||||
|
# higher SPI write divider to match almazny shift register timing
|
||||||
|
# min SER time before SRCLK rise = 125ns
|
||||||
|
# -> div=32 gives 125ns for data before clock rise
|
||||||
|
# works at faster dividers too but could be less reliable
|
||||||
|
ALMAZNY_SPIT_WR = 32
|
||||||
|
|
||||||
|
|
||||||
class Mirny:
|
class Mirny:
|
||||||
"""
|
"""
|
||||||
|
@ -132,11 +142,114 @@ class Mirny:
|
||||||
self.bus.write(((channel | 8) << 25) | (att << 16))
|
self.bus.write(((channel | 8) << 25) | (att << 16))
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def write_ext(self, addr, length, data):
|
def write_ext(self, addr, length, data, ext_div=SPIT_WR):
|
||||||
"""Perform SPI write to a prefixed address"""
|
"""Perform SPI write to a prefixed address"""
|
||||||
self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS)
|
self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS)
|
||||||
self.bus.write(addr << 25)
|
self.bus.write(addr << 25)
|
||||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, SPIT_WR, SPI_CS)
|
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, ext_div, SPI_CS)
|
||||||
if length < 32:
|
if length < 32:
|
||||||
data <<= 32 - length
|
data <<= 32 - length
|
||||||
self.bus.write(data)
|
self.bus.write(data)
|
||||||
|
|
||||||
|
|
||||||
|
class Almazny:
|
||||||
|
"""
|
||||||
|
Almazny (High frequency mezzanine board for Mirny)
|
||||||
|
|
||||||
|
:param host_mirny - Mirny device Almazny is connected to
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, dmgr, host_mirny):
|
||||||
|
self.mirny_cpld = dmgr.get(host_mirny)
|
||||||
|
self.att_mu = [0x3f] * 4
|
||||||
|
self.channel_sw = [0] * 4
|
||||||
|
self.output_enable = False
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def init(self):
|
||||||
|
self.output_toggle(self.output_enable)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def att_to_mu(self, att):
|
||||||
|
"""
|
||||||
|
Convert an attenuator setting in dB to machine units.
|
||||||
|
|
||||||
|
:param att: attenuator setting in dB [0-31.5]
|
||||||
|
:return: attenuator setting in machine units
|
||||||
|
"""
|
||||||
|
mu = round(att * 2.0)
|
||||||
|
if mu > 63 or mu < 0:
|
||||||
|
raise ValueError("Invalid Almazny attenuator settings!")
|
||||||
|
return mu
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def mu_to_att(self, att_mu):
|
||||||
|
"""
|
||||||
|
Convert a digital attenuator setting to dB.
|
||||||
|
|
||||||
|
:param att_mu: attenuator setting in machine units
|
||||||
|
:return: attenuator setting in dB
|
||||||
|
"""
|
||||||
|
return att_mu / 2
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_att(self, channel, att, rf_switch=True):
|
||||||
|
"""
|
||||||
|
Sets attenuators on chosen shift register (channel).
|
||||||
|
:param channel - index of the register [0-3]
|
||||||
|
:param att_mu - attenuation setting in dBm [0-31.5]
|
||||||
|
:param rf_switch - rf switch (bool)
|
||||||
|
"""
|
||||||
|
self.set_att_mu(channel, self.att_to_mu(att), rf_switch)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_att_mu(self, channel, att_mu, rf_switch=True):
|
||||||
|
"""
|
||||||
|
Sets attenuators on chosen shift register (channel).
|
||||||
|
:param channel - index of the register [0-3]
|
||||||
|
:param att_mu - attenuation setting in machine units [0-63]
|
||||||
|
:param rf_switch - rf switch (bool)
|
||||||
|
"""
|
||||||
|
self.channel_sw[channel] = 1 if rf_switch else 0
|
||||||
|
self.att_mu[channel] = att_mu
|
||||||
|
self._update_register(channel)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def output_toggle(self, oe):
|
||||||
|
"""
|
||||||
|
Toggles output on all shift registers on or off.
|
||||||
|
:param oe - toggle output enable (bool)
|
||||||
|
"""
|
||||||
|
self.output_enable = oe
|
||||||
|
cfg_reg = self.mirny_cpld.read_reg(1)
|
||||||
|
en = 1 if self.output_enable else 0
|
||||||
|
delay(100 * us)
|
||||||
|
new_reg = (en << ALMAZNY_OE_SHIFT) | (cfg_reg & 0x3FF)
|
||||||
|
self.mirny_cpld.write_reg(1, new_reg)
|
||||||
|
delay(100 * us)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _flip_mu_bits(self, mu):
|
||||||
|
# in this form MSB is actually 0.5dB attenuator
|
||||||
|
# unnatural for users, so we flip the six bits
|
||||||
|
return (((mu & 0x01) << 5)
|
||||||
|
| ((mu & 0x02) << 3)
|
||||||
|
| ((mu & 0x04) << 1)
|
||||||
|
| ((mu & 0x08) >> 1)
|
||||||
|
| ((mu & 0x10) >> 3)
|
||||||
|
| ((mu & 0x20) >> 5))
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _update_register(self, ch):
|
||||||
|
self.mirny_cpld.write_ext(
|
||||||
|
ALMAZNY_REG_BASE + ch,
|
||||||
|
8,
|
||||||
|
self._flip_mu_bits(self.att_mu[ch]) | (self.channel_sw[ch] << 6),
|
||||||
|
ALMAZNY_SPIT_WR
|
||||||
|
)
|
||||||
|
delay(100 * us)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _update_all_registers(self):
|
||||||
|
for i in range(4):
|
||||||
|
self._update_register(i)
|
|
@ -294,6 +294,18 @@ class PeripheralManager:
|
||||||
name=mirny_name,
|
name=mirny_name,
|
||||||
refclk=peripheral["refclk"],
|
refclk=peripheral["refclk"],
|
||||||
clk_sel=clk_sel)
|
clk_sel=clk_sel)
|
||||||
|
almazny = peripheral.get("almazny", False)
|
||||||
|
if almazny:
|
||||||
|
self.gen("""
|
||||||
|
device_db["{name}_almazny"] = {{
|
||||||
|
"type": "local",
|
||||||
|
"module": "artiq.coredevice.mirny",
|
||||||
|
"class": "Almazny",
|
||||||
|
"arguments": {{
|
||||||
|
"host_mirny": "{name}_cpld",
|
||||||
|
}},
|
||||||
|
}}""",
|
||||||
|
name=mirny_name)
|
||||||
|
|
||||||
return next(channel)
|
return next(channel)
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ class SinaraTester(EnvExperiment):
|
||||||
self.mirnies = dict()
|
self.mirnies = dict()
|
||||||
self.suservos = dict()
|
self.suservos = dict()
|
||||||
self.suschannels = dict()
|
self.suschannels = dict()
|
||||||
|
self.almaznys = dict()
|
||||||
|
|
||||||
ddb = self.get_device_db()
|
ddb = self.get_device_db()
|
||||||
for name, desc in ddb.items():
|
for name, desc in ddb.items():
|
||||||
|
@ -96,6 +97,8 @@ class SinaraTester(EnvExperiment):
|
||||||
self.suservos[name] = self.get_device(name)
|
self.suservos[name] = self.get_device(name)
|
||||||
elif (module, cls) == ("artiq.coredevice.suservo", "Channel"):
|
elif (module, cls) == ("artiq.coredevice.suservo", "Channel"):
|
||||||
self.suschannels[name] = self.get_device(name)
|
self.suschannels[name] = self.get_device(name)
|
||||||
|
elif (module, cls) == ("artiq.coredevice.mirny", "Almazny"):
|
||||||
|
self.almaznys[name] = self.get_device(name)
|
||||||
|
|
||||||
# Remove Urukul, Sampler, Zotino and Mirny control signals
|
# Remove Urukul, Sampler, Zotino and Mirny control signals
|
||||||
# from TTL outs (tested separately) and remove Urukuls covered by
|
# from TTL outs (tested separately) and remove Urukuls covered by
|
||||||
|
@ -351,6 +354,68 @@ class SinaraTester(EnvExperiment):
|
||||||
for channel in channels:
|
for channel in channels:
|
||||||
channel.pulse(100*ms)
|
channel.pulse(100*ms)
|
||||||
delay(100*ms)
|
delay(100*ms)
|
||||||
|
@kernel
|
||||||
|
def init_almazny(self, almazny):
|
||||||
|
self.core.break_realtime()
|
||||||
|
almazny.init()
|
||||||
|
almazny.output_toggle(True)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def almazny_set_attenuators_mu(self, almazny, ch, atts):
|
||||||
|
self.core.break_realtime()
|
||||||
|
almazny.set_att_mu(ch, atts)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def almazny_set_attenuators(self, almazny, ch, atts):
|
||||||
|
self.core.break_realtime()
|
||||||
|
almazny.set_att(ch, atts)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def almazny_toggle_output(self, almazny, rf_on):
|
||||||
|
self.core.break_realtime()
|
||||||
|
almazny.output_toggle(rf_on)
|
||||||
|
|
||||||
|
def test_almaznys(self):
|
||||||
|
print("*** Testing Almaznys.")
|
||||||
|
for name, almazny in sorted(self.almaznys.items(), key=lambda x: x[0]):
|
||||||
|
print(name + "...")
|
||||||
|
print("Initializing Mirny CPLDs...")
|
||||||
|
for name, cpld in sorted(self.mirny_cplds.items(), key=lambda x: x[0]):
|
||||||
|
print(name + "...")
|
||||||
|
self.init_mirny(cpld)
|
||||||
|
print("...done")
|
||||||
|
|
||||||
|
print("Testing attenuators. Frequencies:")
|
||||||
|
for card_n, channels in enumerate(chunker(self.mirnies, 4)):
|
||||||
|
for channel_n, (channel_name, channel_dev) in enumerate(channels):
|
||||||
|
frequency = 2000 + card_n * 250 + channel_n * 50
|
||||||
|
print("{}\t{}MHz".format(channel_name, frequency*2))
|
||||||
|
self.setup_mirny(channel_dev, frequency)
|
||||||
|
print("{} info: {}".format(channel_name, channel_dev.info()))
|
||||||
|
self.init_almazny(almazny)
|
||||||
|
print("RF ON, all attenuators ON. Press ENTER when done.")
|
||||||
|
for i in range(4):
|
||||||
|
self.almazny_set_attenuators_mu(almazny, i, 63)
|
||||||
|
input()
|
||||||
|
print("RF ON, half power attenuators ON. Press ENTER when done.")
|
||||||
|
for i in range(4):
|
||||||
|
self.almazny_set_attenuators(almazny, i, 15.5)
|
||||||
|
input()
|
||||||
|
print("RF ON, all attenuators OFF. Press ENTER when done.")
|
||||||
|
for i in range(4):
|
||||||
|
self.almazny_set_attenuators(almazny, i, 0)
|
||||||
|
input()
|
||||||
|
print("SR outputs are OFF. Press ENTER when done.")
|
||||||
|
self.almazny_toggle_output(almazny, False)
|
||||||
|
input()
|
||||||
|
print("RF ON, all attenuators are ON. Press ENTER when done.")
|
||||||
|
for i in range(4):
|
||||||
|
self.almazny_set_attenuators(almazny, i, 31.5)
|
||||||
|
self.almazny_toggle_output(almazny, True)
|
||||||
|
input()
|
||||||
|
print("RF OFF. Press ENTER when done.")
|
||||||
|
self.almazny_toggle_output(almazny, False)
|
||||||
|
input()
|
||||||
|
|
||||||
def test_mirnies(self):
|
def test_mirnies(self):
|
||||||
print("*** Testing Mirny PLLs.")
|
print("*** Testing Mirny PLLs.")
|
||||||
|
@ -365,7 +430,7 @@ class SinaraTester(EnvExperiment):
|
||||||
print("Frequencies:")
|
print("Frequencies:")
|
||||||
for card_n, channels in enumerate(chunker(self.mirnies, 4)):
|
for card_n, channels in enumerate(chunker(self.mirnies, 4)):
|
||||||
for channel_n, (channel_name, channel_dev) in enumerate(channels):
|
for channel_n, (channel_name, channel_dev) in enumerate(channels):
|
||||||
frequency = 1000*(card_n + 1) + channel_n * 100 + 8 # Extra 8 Hz for easier observation
|
frequency = 1000*(card_n + 1) + channel_n * 100
|
||||||
print("{}\t{}MHz".format(channel_name, frequency))
|
print("{}\t{}MHz".format(channel_name, frequency))
|
||||||
self.setup_mirny(channel_dev, frequency)
|
self.setup_mirny(channel_dev, frequency)
|
||||||
print("{} info: {}".format(channel_name, channel_dev.info()))
|
print("{} info: {}".format(channel_name, channel_dev.info()))
|
||||||
|
|
Loading…
Reference in New Issue