ad9910: avoid unnecessary write/param

Credit: Solution proposed by @pmldrmota in https://github.com/m-labs/artiq/pull/1584#issuecomment-987774353
This commit is contained in:
occheung 2021-12-08 11:21:57 +08:00
parent 1064fdff2e
commit 158a7be74c
1 changed files with 25 additions and 13 deletions

View File

@ -516,9 +516,10 @@ 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 = 7) -> TInt32: ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 7,
ram_destination: TInt32 = -1) -> TInt32:
"""Set DDS data in machine units. """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
@ -543,8 +544,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: 7), or -1 to write :param profile: Single tone profile number to set (0-7, default: 7).
parameters to the ASF, FTW and POW registers instead. 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.
@ -567,13 +573,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 profile < 0: if ram_destination == -1:
self.set_asf(asf)
self.set_ftw(ftw)
self.set_pow(pow_)
else:
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
@ -832,9 +842,10 @@ 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 = 7) -> TFloat: ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 7,
ram_destination: TInt32 = -1) -> TFloat:
"""Set DDS data in SI units. """Set DDS data in SI units.
.. seealso:: :meth:`set_mu` .. seealso:: :meth:`set_mu`
@ -844,13 +855,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: Registers 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]):