mirror of https://github.com/m-labs/artiq.git
Simplified use of the AD9910 RAM feature (#1584)
* coredevice: Change Urukul default single-tone profile to 7 This allows using the internal profile control in RAM modulation mode (which always starts to play back at profile 0) without competing for the content of the profile 0 register used in single tone mode. Signed-off-by: Peter Drmota <peter.drmota@physics.ox.ac.uk> * ad9910/set_mu: comment on caveats when setting register * ad9910: avoid unnecessary write/param Credit: Solution proposed by @pmldrmota in https://github.com/m-labs/artiq/pull/1584#issuecomment-987774353 * revert1064fdff
(`set_mu()` comments)158a7be7
had addressed this issue. Co-authored-by: occheung <dc@m-labs.hk>
This commit is contained in:
parent
33a9ca2684
commit
7c664142a5
|
@ -84,8 +84,11 @@ Highlights:
|
||||||
- Improved performance for kernel RPC involving list and array.
|
- Improved performance for kernel RPC involving list and array.
|
||||||
* Coredevice SI to mu conversions now always return valid codes, or raise a ``ValueError``.
|
* Coredevice SI to mu conversions now always return valid codes, or raise a ``ValueError``.
|
||||||
* Zotino now exposes ``voltage_to_mu()``
|
* Zotino now exposes ``voltage_to_mu()``
|
||||||
* ``ad9910``: The maximum amplitude scale factor is now ``0x3fff`` (was ``0x3ffe``
|
* ``ad9910``:
|
||||||
before).
|
- The maximum amplitude scale factor is now ``0x3fff`` (was ``0x3ffe`` before).
|
||||||
|
- The default single-tone profile is now 7 (was 0).
|
||||||
|
- Added option to ``set_mu()`` that affects the ASF, FTW and POW registers
|
||||||
|
instead of the single-tone profile register.
|
||||||
* Mirny now supports HW revision independent, human readable ``clk_sel`` parameters:
|
* Mirny now supports HW revision independent, human readable ``clk_sel`` parameters:
|
||||||
"XO", "SMA", and "MMCX". Passing an integer is backwards compatible.
|
"XO", "SMA", and "MMCX". Passing an integer is backwards compatible.
|
||||||
* Dashboard:
|
* Dashboard:
|
||||||
|
|
|
@ -236,7 +236,7 @@ class AD9910:
|
||||||
"""
|
"""
|
||||||
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24,
|
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24,
|
||||||
urukul.SPIT_DDS_WR, self.chip_select)
|
urukul.SPIT_DDS_WR, self.chip_select)
|
||||||
self.bus.write((addr << 24) | (data << 8))
|
self.bus.write((addr << 24) | ((data & 0xffff) << 8))
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def write32(self, addr: TInt32, data: TInt32):
|
def write32(self, addr: TInt32, data: TInt32):
|
||||||
|
@ -516,10 +516,11 @@ class AD9910:
|
||||||
self.cpld.io_update.pulse(1 * us)
|
self.cpld.io_update.pulse(1 * us)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_mu(self, ftw: TInt32, pow_: TInt32 = 0, asf: TInt32 = 0x3fff,
|
def set_mu(self, ftw: TInt32 = 0, pow_: TInt32 = 0, asf: TInt32 = 0x3fff,
|
||||||
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
||||||
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0) -> TInt32:
|
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 7,
|
||||||
"""Set profile 0 data in machine units.
|
ram_destination: TInt32 = -1) -> TInt32:
|
||||||
|
"""Set DDS data in machine units.
|
||||||
|
|
||||||
This uses machine units (FTW, POW, ASF). The frequency tuning word
|
This uses machine units (FTW, POW, ASF). The frequency tuning word
|
||||||
width is 32, the phase offset word width is 16, and the amplitude
|
width is 32, the phase offset word width is 16, and the amplitude
|
||||||
|
@ -538,7 +539,13 @@ class AD9910:
|
||||||
by :meth:`set_phase_mode` for this call.
|
by :meth:`set_phase_mode` for this call.
|
||||||
:param ref_time_mu: Fiducial time used to compute absolute or tracking
|
:param ref_time_mu: Fiducial time used to compute absolute or tracking
|
||||||
phase updates. In machine units as obtained by `now_mu()`.
|
phase updates. In machine units as obtained by `now_mu()`.
|
||||||
:param profile: Profile number to set (0-7, default: 0).
|
:param profile: Single tone profile number to set (0-7, default: 7).
|
||||||
|
Ineffective if `ram_destination` is specified.
|
||||||
|
:param ram_destination: RAM destination (:const:`RAM_DEST_FTW`,
|
||||||
|
:const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`,
|
||||||
|
:const:`RAM_DEST_POWASF`). If specified, write free DDS parameters
|
||||||
|
to the ASF/FTW/POW registers instead of to the single tone profile
|
||||||
|
register (default behaviour, see `profile`).
|
||||||
:return: Resulting phase offset word after application of phase
|
:return: Resulting phase offset word after application of phase
|
||||||
tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
|
tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
|
||||||
subsequent calls, use this value as the "current" phase.
|
subsequent calls, use this value as the "current" phase.
|
||||||
|
@ -561,8 +568,17 @@ class AD9910:
|
||||||
# is equivalent to an output pipeline latency.
|
# is equivalent to an output pipeline latency.
|
||||||
dt = int32(now_mu()) - int32(ref_time_mu)
|
dt = int32(now_mu()) - int32(ref_time_mu)
|
||||||
pow_ += dt * ftw * self.sysclk_per_mu >> 16
|
pow_ += dt * ftw * self.sysclk_per_mu >> 16
|
||||||
|
if ram_destination == -1:
|
||||||
self.write64(_AD9910_REG_PROFILE0 + profile,
|
self.write64(_AD9910_REG_PROFILE0 + profile,
|
||||||
(asf << 16) | (pow_ & 0xffff), ftw)
|
(asf << 16) | (pow_ & 0xffff), ftw)
|
||||||
|
else:
|
||||||
|
if not ram_destination == RAM_DEST_FTW:
|
||||||
|
self.set_ftw(ftw)
|
||||||
|
if not ram_destination == RAM_DEST_POWASF:
|
||||||
|
if not ram_destination == RAM_DEST_ASF:
|
||||||
|
self.set_asf(asf)
|
||||||
|
if not ram_destination == RAM_DEST_POW:
|
||||||
|
self.set_pow(pow_)
|
||||||
delay_mu(int64(self.sync_data.io_update_delay))
|
delay_mu(int64(self.sync_data.io_update_delay))
|
||||||
self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK
|
self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK
|
||||||
at_mu(now_mu() & ~7) # clear fine TSC again
|
at_mu(now_mu() & ~7) # clear fine TSC again
|
||||||
|
@ -821,10 +837,11 @@ class AD9910:
|
||||||
return self.pow_to_turns(self.get_pow())
|
return self.pow_to_turns(self.get_pow())
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, frequency: TFloat, phase: TFloat = 0.0,
|
def set(self, frequency: TFloat = 0.0, phase: TFloat = 0.0,
|
||||||
amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
||||||
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0) -> TFloat:
|
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 7,
|
||||||
"""Set profile 0 data in SI units.
|
ram_destination: TInt32 = -1) -> TFloat:
|
||||||
|
"""Set DDS data in SI units.
|
||||||
|
|
||||||
.. seealso:: :meth:`set_mu`
|
.. seealso:: :meth:`set_mu`
|
||||||
|
|
||||||
|
@ -833,13 +850,14 @@ class AD9910:
|
||||||
:param amplitude: Amplitude in units of full scale
|
:param amplitude: Amplitude in units of full scale
|
||||||
:param phase_mode: Phase mode constant
|
:param phase_mode: Phase mode constant
|
||||||
:param ref_time_mu: Fiducial time stamp in machine units
|
:param ref_time_mu: Fiducial time stamp in machine units
|
||||||
:param profile: Profile to affect
|
:param profile: Single tone profile to affect.
|
||||||
|
:param ram_destination: RAM destination.
|
||||||
:return: Resulting phase offset in turns
|
:return: Resulting phase offset in turns
|
||||||
"""
|
"""
|
||||||
return self.pow_to_turns(self.set_mu(
|
return self.pow_to_turns(self.set_mu(
|
||||||
self.frequency_to_ftw(frequency), self.turns_to_pow(phase),
|
self.frequency_to_ftw(frequency), self.turns_to_pow(phase),
|
||||||
self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu,
|
self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu,
|
||||||
profile))
|
profile, ram_destination))
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def get(self, profile: TInt32 = 0) -> TTuple([TFloat, TFloat, TFloat]):
|
def get(self, profile: TInt32 = 0) -> TTuple([TFloat, TFloat, TFloat]):
|
||||||
|
|
|
@ -188,7 +188,7 @@ class CPLD:
|
||||||
assert sync_div is None
|
assert sync_div is None
|
||||||
sync_div = 0
|
sync_div = 0
|
||||||
|
|
||||||
self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0,
|
self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=7,
|
||||||
io_update=0, mask_nu=0, clk_sel=clk_sel,
|
io_update=0, mask_nu=0, clk_sel=clk_sel,
|
||||||
sync_sel=sync_sel,
|
sync_sel=sync_sel,
|
||||||
rst=0, io_rst=0, clk_div=clk_div)
|
rst=0, io_rst=0, clk_div=clk_div)
|
||||||
|
|
Loading…
Reference in New Issue