sayma_amc: add option to generate a 9MHz sq wave on the MCXs

This commit is contained in:
Harry Ho 2021-04-09 13:31:15 +08:00 committed by Sébastien Bourdeauducq
parent 86fcd97416
commit f49f1fcbfc
3 changed files with 109 additions and 3 deletions

View File

@ -0,0 +1,77 @@
from migen import *
from migen.genlib.coding import PriorityEncoder
from artiq.gateware.rtio import rtlink
def _mk_edges(w, direction):
l = [(1 << i) - 1 for i in range(w)]
if direction == "rising":
l = [((1 << w) - 1) ^ x for x in l]
elif direction == "falling":
pass
else:
raise ValueError
return l
class _SerdesSquareWaveDriver(Module):
def __init__(self, serdes_o, rtio_freq, wave_freq):
assert wave_freq <= rtio_freq
serdes_width = len(serdes_o)
assert serdes_width & (serdes_width-1) == 0 # serdes_width must be 2**n
edges = Array(_mk_edges(serdes_width, "rising"))
edges_n = Array(_mk_edges(serdes_width, "falling"))
phase_accumulator = Signal(32)
tuning_word = int((wave_freq/rtio_freq) * 2**32)
fine_ts = Signal() # indicates which rtiox period within the
# current rtio period should the edge be changed
logic_level = Signal(reset=1)
logic_level_d = Signal(reset=1)
self.comb += [
fine_ts.eq(phase_accumulator[-log2_int(serdes_width):]),
logic_level.eq(~phase_accumulator[-1]),
]
# Using CD rio such that RtioInitRequest
# resets the phase accumulator and logic level registers
# (Refer to :class:`artiq.gateware.rtio.core.Core`)
self.sync.rio += [
logic_level_d.eq(logic_level),
If(~logic_level_d & logic_level,
serdes_o.eq(edges[fine_ts]),
).Elif(logic_level_d & ~logic_level,
serdes_o.eq(edges_n[fine_ts]),
).Else(
serdes_o.eq(Replicate(logic_level_d, serdes_width)),
),
phase_accumulator.eq(phase_accumulator + tuning_word),
]
SEDRES_DRIVER_TYPES = {
"square_wave": _SerdesSquareWaveDriver,
}
class Output(Module):
def __init__(self, serdes, driver_type, **kwargs):
assert driver_type in SEDRES_DRIVER_TYPES.keys()
# Include an unused, dummy rtlink interface just to consume an RTIO channel
self.rtlink = rtlink.Interface(
rtlink.OInterface(1, fine_ts_width=log2_int(len(serdes.o))))
self.probes = [Signal()]
self.overrides = [Signal(), Signal()]
# # #
self.submodules += SEDRES_DRIVER_TYPES[driver_type](
serdes.o, **kwargs)
class InOut(Module):
def __init__(self, serdes):
raise NotImplementedError()

View File

@ -1,6 +1,6 @@
from migen import * from migen import *
from artiq.gateware.rtio.phy import ttl_serdes_generic from artiq.gateware.rtio.phy import ttl_serdes_generic, ttl_serdes_nortio
class _OSERDESE3(Module): class _OSERDESE3(Module):
@ -99,3 +99,23 @@ class InOut(ttl_serdes_generic.InOut):
i_INTERMDISABLE=~serdes.t_out, i_INTERMDISABLE=~serdes.t_out,
i_I=serdes.ser_out, o_O=serdes.ser_in, i_T=serdes.t_out, i_I=serdes.ser_out, o_O=serdes.ser_in, i_T=serdes.t_out,
io_IO=pad, io_IOB=pad_n) io_IO=pad, io_IOB=pad_n)
class CustomOutput(ttl_serdes_nortio.Output):
def __init__(self, dw, pad, pad_n=None, dci=False, **kwargs):
serdes = _OSERDESE3(dw)
self.submodules += serdes
ttl_serdes_nortio.Output.__init__(self, serdes, **kwargs)
if pad_n is None:
self.comb += pad.eq(serdes.ser_out)
else:
self.specials += Instance("IOBUFDS",
i_I=serdes.ser_out,
i_T=serdes.t_out,
io_IO=pad, io_IOB=pad_n)
class CustomInOut(ttl_serdes_nortio.InOut):
def __init__(self, dw, pad, pad_n=None, dci=False, **kwargs):
raise NotImplementedError()

View File

@ -294,7 +294,7 @@ class Satellite(SatelliteBase):
""" """
DRTIO satellite with local DAC/SAWG channels, as well as TTL channels via FMC and VHDCI carrier. DRTIO satellite with local DAC/SAWG channels, as well as TTL channels via FMC and VHDCI carrier.
""" """
def __init__(self, jdcg_type, ttlout=False, **kwargs): def __init__(self, jdcg_type, ttlout=False, mcx_sqwave=False, **kwargs):
SatelliteBase.__init__(self, identifier_suffix="." + jdcg_type, **kwargs) SatelliteBase.__init__(self, identifier_suffix="." + jdcg_type, **kwargs)
platform = self.platform platform = self.platform
@ -320,7 +320,13 @@ class Satellite(SatelliteBase):
rtio_channels.append(rtio.Channel.from_phy(phy)) rtio_channels.append(rtio.Channel.from_phy(phy))
for i in range(2): for i in range(2):
mcx_io = platform.request("mcx_io", i) mcx_io = platform.request("mcx_io", i)
if ttlout: if mcx_sqwave:
phy = ttl_serdes_ultrascale.CustomOutput(4, mcx_io.level,
driver_type="square_wave",
rtio_freq=self.rtio_clk_freq,
wave_freq=9e6)
self.comb += mcx_io.direction.eq(1)
elif ttlout:
phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) phy = ttl_serdes_ultrascale.Output(4, mcx_io.level)
self.comb += mcx_io.direction.eq(1) self.comb += mcx_io.direction.eq(1)
else: else:
@ -433,6 +439,8 @@ def main():
"development and debugging.") "development and debugging.")
parser.add_argument("--ttlout", default=False, action="store_true", parser.add_argument("--ttlout", default=False, action="store_true",
help="force only outputs on the MCX TTL IOs") help="force only outputs on the MCX TTL IOs")
parser.add_argument("--mcx-sqwave", default=False, action="store_true",
help="generate a square wave on the MCX TTL IOs")
parser.add_argument("--gateware-identifier-str", default=None, parser.add_argument("--gateware-identifier-str", default=None,
help="Override ROM identifier") help="Override ROM identifier")
args = parser.parse_args() args = parser.parse_args()
@ -443,6 +451,7 @@ def main():
with_sfp=args.sfp, with_sfp=args.sfp,
jdcg_type=args.jdcg_type, jdcg_type=args.jdcg_type,
ttlout=args.ttlout, ttlout=args.ttlout,
mcx_sqwave=args.mcx_sqwave,
gateware_identifier_str=args.gateware_identifier_str, gateware_identifier_str=args.gateware_identifier_str,
**soc_sayma_amc_argdict(args)) **soc_sayma_amc_argdict(args))
elif variant == "simplesatellite": elif variant == "simplesatellite":