mirny: add

* This targets unrelease CPLD gateware (https://github.com/quartiq/mirny/issues/1)
* includes initial coredevice driver, eem shims, and kasli_generic tooling
* addresses the ARTIQ side of #1130
* Register abstraction to be written

Signed-off-by: Robert Jördens <rj@quartiq.de>
This commit is contained in:
Robert Jördens 2019-06-16 17:17:42 +00:00
parent ec03767dcf
commit 01a6e77d89
4 changed files with 187 additions and 0 deletions

View File

@ -0,0 +1,68 @@
""""RTIO driver for the Analog Devices ADF[45]35[56] family of GHz PLLs
on Mirny-style prefixed SPI buses
"""
# https://github.com/analogdevicesinc/linux/blob/master/Documentation/devicetree/bindings/iio/frequency/adf5355.txt
# https://github.com/analogdevicesinc/linux/blob/master/drivers/iio/frequency/adf5355.c
# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5356.pdf
# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5355.pdf
# https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf
from numpy import int32
from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu,
at_mu)
from artiq.language.units import ns, us
from artiq.coredevice import spi2 as spi, mirny
SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END |
0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY |
0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE |
0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
class ADF5355:
"""Analog Devices AD[45]35[56] family of GHz PLLs.
:param cpld_device: Mirny CPLD device name
:param sw_device: Mirny RF switch device name
:param channel: Mirny RF channel index
:param core_device: Core device name (default: "core")
"""
kernel_invariants = {"cpld", "sw", "channel", "core"}
def __init__(self, dmgr, cpld_device, sw_device, channel,
core="core"):
self.cpld = dmgr.get(cpld_device)
self.sw = dmgr.get(sw_device)
self.channel = channel
self.core = dmgr.get(core)
@kernel
def set_att_mu(self, att):
"""Set digital step attenuator in machine units.
:param att: Attenuation setting, 8 bit digital.
"""
self.cpld.set_att_mu(self.channel, att)
@kernel
def write(self, data):
self.cpld.write_ext(self.channel | 4, 32, data)
@kernel
def read_muxout(self):
return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8)))
@kernel
def init(self):
self.write((1 << 27) | 4)
if not self.read_muxout():
raise ValueError("MUXOUT not high")
delay(100*us)
self.write((2 << 27) | 4)
if self.read_muxout():
raise ValueError("MUXOUT not low")
delay(100*us)
self.write((6 << 27) | 4)

66
artiq/coredevice/mirny.py Normal file
View File

@ -0,0 +1,66 @@
from artiq.language.core import kernel, delay
from artiq.language.units import us
from numpy import int32
from artiq.coredevice import spi2 as spi
SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END |
0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY |
0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE |
0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
# SPI clock write and read dividers
SPIT_WR = 4
SPIT_RD = 16
SPI_CS = 1
class Mirny:
WE = 1 << 24
kernel_invariants = {"bus", "core", "WE"}
def __init__(self, dmgr, spi_device, core_device="core"):
self.core = dmgr.get(core_device)
self.bus = dmgr.get(spi_device)
@kernel
def read_reg(self, addr):
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24,
SPIT_RD, SPI_CS)
self.bus.write((addr << 25))
return self.bus.read() & int32(0xffff)
@kernel
def write_reg(self, addr, data):
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS)
self.bus.write((addr << 25) | self.WE | ((data & 0xffff) << 8))
@kernel
def init(self):
reg0 = self.read_reg(0)
if reg0 & 0b11 != 0b11:
raise ValueError("Mirny HW_REV mismatch")
if (reg0 >> 2) & 0b11 != 0b00:
raise ValueError("Mirny PROTO_REV mismatch")
delay(100*us) # slack
@kernel
def set_att_mu(self, channel, att):
"""Set digital step attenuator in machine units.
:param att: Attenuation setting, 8 bit digital.
"""
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, SPIT_WR, SPI_CS)
self.bus.write(((channel | 8) << 25) | (att << 16))
@kernel
def write_ext(self, addr, length, data):
self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS)
self.bus.write(addr << 25)
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length,
SPIT_WR, SPI_CS)
if length < 32:
data <<= 32 - length
self.bus.write(data)

View File

@ -558,3 +558,48 @@ class SUServo(_EEM):
pads = target.platform.request("{}_{}".format(eem_urukuli, signal)) pads = target.platform.request("{}_{}".format(eem_urukuli, signal))
target.specials += DifferentialOutput( target.specials += DifferentialOutput(
su.iir.ctrl[j*4 + i].en_out, pads.p, pads.n) su.iir.ctrl[j*4 + i].en_out, pads.p, pads.n)
class Mirny(_EEM):
@staticmethod
def io(eem, iostandard="LVDS_25"):
ios = [
("mirny{}_spi_p".format(eem), 0,
Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))),
Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))),
Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))),
Subsignal("cs_n", Pins(_eem_pin(eem, 3, "p"))),
IOStandard(iostandard),
),
("mirny{}_spi_n".format(eem), 0,
Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))),
Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))),
Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))),
Subsignal("cs_n", Pins(_eem_pin(eem, 3, "n"))),
IOStandard(iostandard),
),
]
for i in range(4):
ios.append(
("mirny{}_io{}".format(eem, i), 0,
Subsignal("p", Pins(_eem_pin(eem, 4 + i, "p"))),
Subsignal("n", Pins(_eem_pin(eem, 4 + i, "n"))),
IOStandard(iostandard)
))
return ios
@classmethod
def add_std(cls, target, eem, ttl_out_cls, iostandard="LVDS_25"):
cls.add_extension(target, eem, iostandard=iostandard)
phy = spi2.SPIMaster(
target.platform.request("mirny{}_spi_p".format(eem)),
target.platform.request("mirny{}_spi_n".format(eem)))
target.submodules += phy
target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
for i in range(4):
pads = target.platform.request("mirny{}_io{}".format(eem, i))
phy = ttl_out_cls(pads.p, pads.n)
target.submodules += phy
target.rtio_channels.append(rtio.Channel.from_phy(phy))

View File

@ -99,6 +99,13 @@ def peripheral_grabber(module, peripheral):
eem.Grabber.add_std(module, port, port_aux, port_aux2) eem.Grabber.add_std(module, port, port_aux, port_aux2)
def peripheral_mirny(module, peripheral):
if len(peripheral["ports"]) != 1:
raise ValueError("wrong number of ports")
eem.Mirny.add_std(module, peripheral["ports"][0],
ttl_serdes_7series.Output_8X)
peripheral_processors = { peripheral_processors = {
"dio": peripheral_dio, "dio": peripheral_dio,
"urukul": peripheral_urukul, "urukul": peripheral_urukul,
@ -107,6 +114,7 @@ peripheral_processors = {
"suservo": peripheral_suservo, "suservo": peripheral_suservo,
"zotino": peripheral_zotino, "zotino": peripheral_zotino,
"grabber": peripheral_grabber, "grabber": peripheral_grabber,
"mirny": peripheral_mirny,
} }