forked from M-Labs/artiq
1
0
Fork 0

phaser: SI methods

This commit is contained in:
Robert Jördens 2020-09-12 11:02:37 +00:00
parent 4e24700205
commit fdd2d6f2fb
2 changed files with 75 additions and 10 deletions

View File

@ -270,6 +270,18 @@ class Phaser:
""" """
self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw) self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw)
@kernel
def set_duc_frequency(self, ch, frequency):
"""Set the DUC frequency.
:param ch: DAC channel pair (0 or 1)
:param frequency: DUC frequency in Hz
"""
if ch < 0 or ch > 1:
raise ValueError("invalid channel index")
ftw = int32(round(frequency*((1 << 32)/500e6)))
self.set_duc_frequency_mu(ch, ftw)
@kernel @kernel
def set_duc_phase_mu(self, ch, pow): def set_duc_phase_mu(self, ch, pow):
"""Set the DUC phase offset """Set the DUC phase offset
@ -279,6 +291,18 @@ class Phaser:
""" """
self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow) self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow)
@kernel
def set_duc_phase(self, ch, phase):
"""Set the DUC phase.
:param ch: DAC channel pair (0 or 1)
:param phase: DUC phase in turns
"""
if ch < 0 or ch > 1:
raise ValueError("invalid channel index")
pow = int32(round(phase*(1 << 16))) & 0xffff
self.set_duc_phase_mu(ch, pow)
@kernel @kernel
def duc_stb(self): def duc_stb(self):
"""Strobe the DUC configuration register update. """Strobe the DUC configuration register update.
@ -303,12 +327,16 @@ class Phaser:
:param offline: Put the SPI interfaces offline and don't drive voltages :param offline: Put the SPI interfaces offline and don't drive voltages
:param length: SPI transfer length (1 to 8 bits) :param length: SPI transfer length (1 to 8 bits)
""" """
if div < 2 or div > 257:
raise ValueError("invalid divider")
if length < 0 or length > 8:
raise ValueError("invalid length")
self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_SEL, select)
self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5))
self.write8(PHASER_ADDR_SPI_CFG, self.write8(PHASER_ADDR_SPI_CFG,
(offline << 0) | (end << 1) | (clk_phase << 2) | ((offline & 1) << 0) | ((end & 1) << 1) |
(clk_polarity << 3) | (half_duplex << 4) | ((clk_phase & 1) << 2) | ((clk_polarity & 1) << 3) |
(lsb_first << 5)) ((half_duplex & 1) << 4) | ((lsb_first & 1) << 5))
@kernel @kernel
def spi_write(self, data): def spi_write(self, data):
@ -328,7 +356,7 @@ class Phaser:
:param addr: Register address :param addr: Register address
:param data: Register data to write :param data: Register data to write
""" """
div = 32 # 100 ns min period div = 34 # 100 ns min period
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0)
self.spi_write(addr) self.spi_write(addr)
@ -340,7 +368,7 @@ class Phaser:
delay_mu(t_xfer) delay_mu(t_xfer)
@kernel @kernel
def dac_read(self, addr, div=32) -> TInt32: def dac_read(self, addr, div=34) -> TInt32:
"""Read from a DAC register. """Read from a DAC register.
:param addr: Register address to read from :param addr: Register address to read from
@ -368,7 +396,7 @@ class Phaser:
:param ch: RF channel (0 or 1) :param ch: RF channel (0 or 1)
:param data: Attenuator data :param data: Attenuator data
""" """
div = 32 # 30 ns min period div = 34 # 30 ns min period
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1)
self.spi_write(data) self.spi_write(data)
@ -383,7 +411,7 @@ class Phaser:
:param ch: RF channel (0 or 1) :param ch: RF channel (0 or 1)
:return: Current attenuation :return: Current attenuation
""" """
div = 32 div = 34
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0)
self.spi_write(0) self.spi_write(0)
@ -403,7 +431,7 @@ class Phaser:
:param data: Register data (32 bit) :param data: Register data (32 bit)
:param readback: Whether to return the read back MISO data :param readback: Whether to return the read back MISO data
""" """
div = 32 # 50 ns min period div = 34 # 50 ns min period
t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns)
read = 0 read = 0
end = 0 end = 0
@ -437,7 +465,7 @@ class Phaser:
""" """
self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27))
# single clk pulse with ~LE to start readback # single clk pulse with ~LE to start readback
self.spi_cfg(select=0, div=32, end=1, length=1) self.spi_cfg(select=0, div=34, end=1, length=1)
self.spi_write(0) self.spi_write(0)
delay((1 + 1)*32*4*ns) delay((1 + 1)*32*4*ns)
return self.trf_write(ch, 0x00000008, readback=True) return self.trf_write(ch, 0x00000008, readback=True)
@ -453,6 +481,22 @@ class Phaser:
addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1)
rtio_output(addr, ftw) rtio_output(addr, ftw)
@kernel
def set_frequency(self, ch, osc, frequency):
"""Set Phaser MultiDDS frequency.
:param ch: RF channel (0 or 1)
:param osc: Oscillator number (0 to 4)
:param frequency: Frequency in Hz
"""
if ch < 0 or ch > 1:
raise ValueError("invalid channel index")
if osc < 0 or osc > 4:
raise ValueError("invalid oscillator index")
ftw = int32(round(frequency*((1 << 32)/125e6)))
self.set_frequency_mu(ch, osc, ftw)
@kernel @kernel
def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0): def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0):
"""Set Phaser MultiDDS amplitude, phase offset and accumulator clear. """Set Phaser MultiDDS amplitude, phase offset and accumulator clear.
@ -464,5 +508,25 @@ class Phaser:
:param clr: Clear the phase accumulator (persistent) :param clr: Clear the phase accumulator (persistent)
""" """
addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1 addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1
data = (asf & 0x7fff) | (clr << 15) | (pow << 16) data = (asf & 0x7fff) | ((clr & 1) << 15) | ((pow & 0xffff) << 16)
rtio_output(addr, data) rtio_output(addr, data)
@kernel
def set_amplitude_phase(self, ch, osc, amplitude, phase=0., clr=0):
"""Set Phaser MultiDDS amplitude and phase.
:param ch: RF channel (0 or 1)
:param osc: Oscillator number (0 to 4)
:param amplitude: Amplitude in units of full scale
:param phase: Phase in turns
:param clr: Clear the phase accumulator (persistent)
"""
if ch < 0 or ch > 1:
raise ValueError("invalid channel index")
if osc < 0 or osc > 4:
raise ValueError("invalid oscillator index")
asf = int32(round(amplitude*0x7fff))
if asf < 0 or asf > 0x7fff:
raise ValueError("invalid amplitude")
pow = int32(round(phase*(1 << 16)))
self.set_amplitude_phase_mu(ch, osc, asf, pow, clr)

View File

@ -87,6 +87,7 @@ class SerDes(Module):
self.crcb.last.eq(self.crca.next), self.crcb.last.eq(self.crca.next),
miso_sr_next.eq(Cat(self.data[-1], miso_sr)), miso_sr_next.eq(Cat(self.data[-1], miso_sr)),
# unload miso # unload miso
# TODO: align to marker
self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk]
for i in range(n_frame)])), for i in range(n_frame)])),
] ]