forked from M-Labs/artiq
Update AD9834 coredevice driver
This commit is contained in:
parent
7669cfce3d
commit
7534a8fe04
@ -5,6 +5,8 @@ RTIO Driver for the Analog Devices AD9834 DDS via 3-wire SPI interface.
|
||||
# https://www.analog.com/media/en/technical-documentation/data-sheets/AD9834.pdf
|
||||
# https://www.analog.com/media/en/technical-documentation/app-notes/an-1070.pdf
|
||||
|
||||
from numpy import int32
|
||||
|
||||
from artiq.coredevice import spi2 as spi
|
||||
from artiq.experiment import *
|
||||
from artiq.language.core import *
|
||||
@ -64,167 +66,21 @@ class AD9834:
|
||||
self.ctrl_reg = 0x0000 # Reset control register
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
def write(self, data: TInt32):
|
||||
"""
|
||||
Initialize the AD9834: configure the SPI bus and reset the DDS.
|
||||
Write a 16-bit word to the AD9834.
|
||||
|
||||
This method performs the necessary setup for the AD9834 device, including:
|
||||
- Configuring the SPI bus parameters (clock polarity, data width, and frequency).
|
||||
- Putting the AD9834 into a reset state to ensure proper initialization.
|
||||
This method sends a 16-bit data word to the AD9834 via the SPI bus. The input
|
||||
data is left-shifted by 16 bits to ensure proper alignment for the SPI controller,
|
||||
allowing for accurate processing of the command by the AD9834.
|
||||
|
||||
The SPI bus is configured to use 16 bits of data width with the clock frequency
|
||||
provided as a parameter when creating the AD9834 instance. After configuring
|
||||
the SPI bus, the method invokes :meth:`enable_reset()` to reset the AD9834.
|
||||
This is an essential step to prepare the device for subsequent configuration
|
||||
of frequency and phase.
|
||||
This method is used internally by other methods to update the control registers
|
||||
and frequency settings of the AD9834. It should not be called directly unless
|
||||
low-level register manipulation is required.
|
||||
|
||||
This method should be called before any other operations are performed
|
||||
on the AD9834 to ensure that the device is in a known state.
|
||||
:param data: The 16-bit word to be sent to the AD9834.
|
||||
"""
|
||||
self.bus.set_config(spi.SPI_CLK_POLARITY | spi.SPI_END, 16, self.spi_freq, 1)
|
||||
self.enable_reset()
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg(self, freq_reg, frequency: TFloat):
|
||||
"""
|
||||
Set the frequency for the specified frequency register.
|
||||
|
||||
This method calculates the frequency word based on the provided frequency in Hz
|
||||
and writes it to the specified frequency register.
|
||||
|
||||
:param freq_reg: The frequency register to write to, must be one of
|
||||
:const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`.
|
||||
:param frequency: The desired frequency in Hz, which will be converted to a
|
||||
frequency word suitable for the AD9834.
|
||||
|
||||
The frequency word is calculated using the formula:
|
||||
|
||||
``freq_word = (frequency * (1 << 28)) / clk_freq``
|
||||
|
||||
The result is limited to the lower 28 bits for compatibility with the AD9834.
|
||||
|
||||
The method first sets the control register to enable the appropriate settings,
|
||||
then sends the fourteen least significant bits LSBs and fourteen most significant
|
||||
bits MSBs in two consecutive writes to the specified frequency register.
|
||||
"""
|
||||
if freq_reg not in FREQ_REGS:
|
||||
raise ValueError("Invalid frequency register")
|
||||
assert frequency <= 37.5 * MHz, "Frequency exceeds maximum value of 37.5 MHz"
|
||||
freq_word = int((frequency * (1 << 28)) / self.clk_freq) & 0x0FFFFFFF
|
||||
self.ctrl_reg |= AD9834_B28
|
||||
self.write(self.ctrl_reg)
|
||||
lsb = freq_word & 0x3FFF
|
||||
msb = (freq_word >> 14) & 0x3FFF
|
||||
self.write(freq_reg | lsb)
|
||||
self.write(freq_reg | msb)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_msb(self, freq_reg, word: TInt32):
|
||||
"""
|
||||
Set the fourteen most significant bits MSBs of the specified frequency register.
|
||||
|
||||
This method updates the specified frequency register with the provided MSB value.
|
||||
It configures the control register to indicate that the MSB is being set.
|
||||
|
||||
:param freq_reg: The frequency register to update, must be one of
|
||||
:const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`.
|
||||
:param word: The value to be written to the fourteen MSBs of the frequency register.
|
||||
|
||||
The method first clears the appropriate control bits, sets :const:`AD9834_HLB` to
|
||||
indicate that the MSB is being sent, and then writes the updated control register
|
||||
followed by the MSB value to the specified frequency register.
|
||||
"""
|
||||
if freq_reg not in FREQ_REGS:
|
||||
raise ValueError("Invalid frequency register")
|
||||
self.ctrl_reg &= ~AD9834_B28
|
||||
self.ctrl_reg |= AD9834_HLB
|
||||
self.write(self.ctrl_reg)
|
||||
self.write(freq_reg | (word & 0x3FFF))
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_lsb(self, freq_reg, word: TInt32):
|
||||
"""
|
||||
Set the fourteen least significant bits LSBs of the specified frequency register.
|
||||
|
||||
This method updates the specified frequency register with the provided LSB value.
|
||||
It configures the control register to indicate that the LSB is being set.
|
||||
|
||||
:param freq_reg: The frequency register to update, must be one of
|
||||
:const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`.
|
||||
:param word: The value to be written to the fourteen LSBs of the frequency register.
|
||||
|
||||
The method first clears the appropriate control bits and writes the updated control
|
||||
register followed by the LSB value to the specified frequency register.
|
||||
"""
|
||||
if freq_reg not in FREQ_REGS:
|
||||
raise ValueError("Invalid frequency register")
|
||||
self.ctrl_reg &= ~AD9834_B28
|
||||
self.ctrl_reg &= ~AD9834_HLB
|
||||
self.write(self.ctrl_reg)
|
||||
self.write(freq_reg | (word & 0x3FFF))
|
||||
|
||||
@kernel
|
||||
def select_frequency_reg(self, freq_reg):
|
||||
"""
|
||||
Select the active frequency register for the phase accumulator.
|
||||
|
||||
This method chooses between the two available frequency registers in the AD9834 to
|
||||
control the frequency of the output waveform. The control register is updated
|
||||
to reflect the selected frequency register.
|
||||
|
||||
:param freq_reg: The frequency register to select. Must be one of
|
||||
:const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`.
|
||||
"""
|
||||
if freq_reg not in FREQ_REGS:
|
||||
raise ValueError("Invalid frequency register")
|
||||
if freq_reg == FREQ_REGS[0]:
|
||||
self.ctrl_reg &= ~AD9834_FSEL
|
||||
else:
|
||||
self.ctrl_reg |= AD9834_FSEL
|
||||
|
||||
self.ctrl_reg &= ~AD9834_PIN_SW
|
||||
self.write(self.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def set_phase_reg(self, phase_reg, phase: TInt32):
|
||||
"""
|
||||
Set the phase for the specified phase register.
|
||||
|
||||
This method updates the specified phase register with the provided phase value.
|
||||
|
||||
:param phase_reg: The phase register to update, must be one of
|
||||
:const:`AD9834_PHASE_REG_0` or :const:`AD9834_PHASE_REG_1`.
|
||||
:param phase: The value to be written to the phase register.
|
||||
|
||||
The method masks the phase value to ensure it fits within the 12-bit limit
|
||||
and writes it to the specified phase register.
|
||||
"""
|
||||
if phase_reg not in PHASE_REGS:
|
||||
raise ValueError("Invalid phase register")
|
||||
phase_word = phase & 0x0FFF
|
||||
self.write(phase_reg | phase_word)
|
||||
|
||||
@kernel
|
||||
def select_phase_reg(self, phase_reg):
|
||||
"""
|
||||
Select the active phase register for the phase accumulator.
|
||||
|
||||
This method chooses between the two available phase registers in the AD9834 to
|
||||
control the phase of the output waveform. The control register is updated
|
||||
to reflect the selected phase register.
|
||||
|
||||
:param phase_reg: The phase register to select. Must be one of
|
||||
:const:`AD9834_PHASE_REG_0` or :const:`AD9834_PHASE_REG_1`.
|
||||
"""
|
||||
if phase_reg not in PHASE_REGS:
|
||||
raise ValueError("Invalid phase register")
|
||||
if phase_reg == PHASE_REGS[0]:
|
||||
self.ctrl_reg &= ~AD9834_PSEL
|
||||
else:
|
||||
self.ctrl_reg |= AD9834_PSEL
|
||||
|
||||
self.ctrl_reg &= ~AD9834_PIN_SW
|
||||
self.write(self.ctrl_reg)
|
||||
self.bus.write(data << 16)
|
||||
|
||||
@kernel
|
||||
def enable_reset(self):
|
||||
@ -255,6 +111,158 @@ class AD9834:
|
||||
self.ctrl_reg &= ~AD9834_RESET
|
||||
self.write(self.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
"""
|
||||
Initialize the AD9834: configure the SPI bus and reset the DDS.
|
||||
|
||||
This method performs the necessary setup for the AD9834 device, including:
|
||||
- Configuring the SPI bus parameters (clock polarity, data width, and frequency).
|
||||
- Putting the AD9834 into a reset state to ensure proper initialization.
|
||||
|
||||
The SPI bus is configured to use 16 bits of data width with the clock frequency
|
||||
provided as a parameter when creating the AD9834 instance. After configuring
|
||||
the SPI bus, the method invokes :meth:`enable_reset()` to reset the AD9834.
|
||||
This is an essential step to prepare the device for subsequent configuration
|
||||
of frequency and phase.
|
||||
|
||||
This method should be called before any other operations are performed
|
||||
on the AD9834 to ensure that the device is in a known state.
|
||||
"""
|
||||
self.bus.set_config(spi.SPI_CLK_POLARITY | spi.SPI_END, 16, self.spi_freq, 1)
|
||||
self.enable_reset()
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_msb(self, freq_reg: TInt32, word: TInt32):
|
||||
"""
|
||||
Set the fourteen most significant bits MSBs of the specified frequency register.
|
||||
|
||||
This method updates the specified frequency register with the provided MSB value.
|
||||
It configures the control register to indicate that the MSB is being set.
|
||||
|
||||
:param freq_reg: The frequency register to write to (0-1).
|
||||
:param word: The value to be written to the fourteen MSBs of the frequency register.
|
||||
|
||||
The method first clears the appropriate control bits, sets :const:`AD9834_HLB` to
|
||||
indicate that the MSB is being sent, and then writes the updated control register
|
||||
followed by the MSB value to the specified frequency register.
|
||||
"""
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
self.ctrl_reg &= ~AD9834_B28
|
||||
self.ctrl_reg |= AD9834_HLB
|
||||
self.write(self.ctrl_reg)
|
||||
self.write(FREQ_REGS[freq_reg] | (word & 0x3FFF))
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_lsb(self, freq_reg: TInt32, word: TInt32):
|
||||
"""
|
||||
Set the fourteen least significant bits LSBs of the specified frequency register.
|
||||
|
||||
This method updates the specified frequency register with the provided LSB value.
|
||||
It configures the control register to indicate that the LSB is being set.
|
||||
|
||||
:param freq_reg: The frequency register to write to (0-1).
|
||||
:param word: The value to be written to the fourteen LSBs of the frequency register.
|
||||
|
||||
The method first clears the appropriate control bits and writes the updated control
|
||||
register followed by the LSB value to the specified frequency register.
|
||||
"""
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
self.ctrl_reg &= ~AD9834_B28
|
||||
self.ctrl_reg &= ~AD9834_HLB
|
||||
self.write(self.ctrl_reg)
|
||||
self.write(FREQ_REGS[freq_reg] | (word & 0x3FFF))
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg(self, freq_reg: TInt32, freq_word: TInt32):
|
||||
"""
|
||||
Set the frequency for the specified frequency register using a precomputed frequency word.
|
||||
|
||||
This writes to the 28-bit frequency register in one transfer.
|
||||
|
||||
:param freq_reg: The frequency register to write to (0-1).
|
||||
:param freq_word: The precomputed frequency word.
|
||||
"""
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
self.ctrl_reg |= AD9834_B28
|
||||
self.write(self.ctrl_reg)
|
||||
lsb = freq_word & 0x3FFF
|
||||
msb = (freq_word >> 14) & 0x3FFF
|
||||
self.write(FREQ_REGS[freq_reg] | lsb)
|
||||
self.write(FREQ_REGS[freq_reg] | msb)
|
||||
|
||||
@portable(flags={"fast-math"})
|
||||
def frequency_to_ftw(self, frequency: TFloat) -> TInt32:
|
||||
"""Return the 28-bit frequency tuning word corresponding to the given
|
||||
frequency.
|
||||
"""
|
||||
assert frequency <= 37.5 * MHz, "Frequency exceeds maximum value of 37.5 MHz"
|
||||
return int((frequency * (1 << 28)) / self.clk_freq) & 0x0FFFFFFF
|
||||
|
||||
@portable(flags={"fast-math"})
|
||||
def turns_to_pow(self, turns: TFloat) -> TInt32:
|
||||
"""Return the 12-bit phase offset word corresponding to the given phase
|
||||
in turns."""
|
||||
assert 0.0 <= turns <= 1.0, "Turns exceeds range 0.0 - 1.0"
|
||||
return int32(round(turns * 0x1000)) & int32(0x0FFF)
|
||||
|
||||
@kernel
|
||||
def select_frequency_reg(self, freq_reg: TInt32):
|
||||
"""
|
||||
Select the active frequency register for the phase accumulator.
|
||||
|
||||
This method chooses between the two available frequency registers in the AD9834 to
|
||||
control the frequency of the output waveform. The control register is updated
|
||||
to reflect the selected frequency register.
|
||||
|
||||
:param freq_reg: The frequency register to write to (0-1).
|
||||
"""
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
if freq_reg:
|
||||
self.ctrl_reg |= AD9834_FSEL
|
||||
else:
|
||||
self.ctrl_reg &= ~AD9834_FSEL
|
||||
|
||||
self.ctrl_reg &= ~AD9834_PIN_SW
|
||||
self.write(self.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def set_phase_reg(self, phase_reg: TInt32, phase: TInt32):
|
||||
"""
|
||||
Set the phase for the specified phase register.
|
||||
|
||||
This method updates the specified phase register with the provided phase value.
|
||||
|
||||
:param phase_reg: The phase register to write to (0-1).
|
||||
:param phase: The value to be written to the phase register.
|
||||
|
||||
The method masks the phase value to ensure it fits within the 12-bit limit
|
||||
and writes it to the specified phase register.
|
||||
"""
|
||||
assert 0 <= phase_reg <= 1, "Invalid phase register index"
|
||||
phase_word = phase & 0x0FFF
|
||||
self.write(PHASE_REGS[phase_reg] | phase_word)
|
||||
|
||||
@kernel
|
||||
def select_phase_reg(self, phase_reg: TInt32):
|
||||
"""
|
||||
Select the active phase register for the phase accumulator.
|
||||
|
||||
This method chooses between the two available phase registers in the AD9834 to
|
||||
control the phase of the output waveform. The control register is updated
|
||||
to reflect the selected phase register.
|
||||
|
||||
:param phase_reg: The phase register to write to (0-1).
|
||||
"""
|
||||
assert 0 <= phase_reg <= 1, "Invalid phase register index"
|
||||
if phase_reg:
|
||||
self.ctrl_reg |= AD9834_PSEL
|
||||
else:
|
||||
self.ctrl_reg &= ~AD9834_PSEL
|
||||
|
||||
self.ctrl_reg &= ~AD9834_PIN_SW
|
||||
self.write(self.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def sleep(self, dac_pd: bool = False, clk_dis: bool = False):
|
||||
"""
|
||||
@ -329,19 +337,13 @@ class AD9834:
|
||||
self.ctrl_reg &= ~AD9834_OPBITEN
|
||||
elif msb_2:
|
||||
self.ctrl_reg |= AD9834_OPBITEN
|
||||
self.ctrl_reg &= ~AD9834_MODE
|
||||
self.ctrl_reg &= ~AD9834_SIGN_PIB
|
||||
self.ctrl_reg &= ~AD9834_DIV2
|
||||
self.ctrl_reg &= ~(AD9834_MODE | AD9834_SIGN_PIB | AD9834_DIV2)
|
||||
elif msb:
|
||||
self.ctrl_reg |= AD9834_OPBITEN
|
||||
self.ctrl_reg &= ~AD9834_MODE
|
||||
self.ctrl_reg &= ~AD9834_SIGN_PIB
|
||||
self.ctrl_reg |= AD9834_DIV2
|
||||
self.ctrl_reg |= AD9834_OPBITEN | AD9834_DIV2
|
||||
self.ctrl_reg &= ~(AD9834_MODE | AD9834_SIGN_PIB)
|
||||
elif comp_out:
|
||||
self.ctrl_reg |= AD9834_OPBITEN
|
||||
self.ctrl_reg |= AD9834_OPBITEN | AD9834_SIGN_PIB | AD9834_DIV2
|
||||
self.ctrl_reg &= ~AD9834_MODE
|
||||
self.ctrl_reg |= AD9834_SIGN_PIB
|
||||
self.ctrl_reg |= AD9834_DIV2
|
||||
else:
|
||||
self.ctrl_reg &= ~AD9834_OPBITEN
|
||||
|
||||
@ -380,18 +382,56 @@ class AD9834:
|
||||
self.write(self.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def write(self, data: TInt32):
|
||||
def set_mu(
|
||||
self,
|
||||
freq_word: TInt32 = 0,
|
||||
phase_word: TInt32 = 0,
|
||||
freq_reg: TInt32 = 0,
|
||||
phase_reg: TInt32 = 0,
|
||||
):
|
||||
"""
|
||||
Write a 16-bit word to the AD9834.
|
||||
Set DDS frequency and phase in machine units.
|
||||
|
||||
This method sends a 16-bit data word to the AD9834 via the SPI bus. The input
|
||||
data is left-shifted by 16 bits to ensure proper alignment for the SPI controller,
|
||||
allowing for accurate processing of the command by the AD9834.
|
||||
This method updates the specified frequency and phase registers with the provided
|
||||
machine units, selects the corresponding registers, and enables the output.
|
||||
|
||||
This method is used internally by other methods to update the control registers
|
||||
and frequency settings of the AD9834. It should not be called directly unless
|
||||
low-level register manipulation is required.
|
||||
|
||||
:param data: The 16-bit word to be sent to the AD9834.
|
||||
:param freq_word: Frequency tuning word (28-bit).
|
||||
:param phase_word: Phase tuning word (12-bit).
|
||||
:param freq_reg: Frequency register to write to (0 or 1).
|
||||
:param phase_reg: Phase register to write to (0 or 1).
|
||||
"""
|
||||
self.bus.write(data << 16)
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
assert 0 <= phase_reg <= 1, "Invalid phase register index"
|
||||
|
||||
self.set_frequency_reg_lsb(freq_reg, freq_word & 0x3FFF)
|
||||
self.set_frequency_reg_msb(freq_reg, (freq_word >> 14) & 0x3FFF)
|
||||
self.set_phase_reg(phase_reg, phase_word)
|
||||
self.select_frequency_reg(freq_reg)
|
||||
self.select_phase_reg(phase_reg)
|
||||
self.output_enable()
|
||||
|
||||
@kernel
|
||||
def set(
|
||||
self,
|
||||
frequency: TFloat = 0.0,
|
||||
phase: TFloat = 0.0,
|
||||
freq_reg: TInt32 = 0,
|
||||
phase_reg: TInt32 = 0,
|
||||
):
|
||||
"""
|
||||
Set DDS frequency in Hz and phase using fractional turns.
|
||||
|
||||
This method converts the specified frequency and phase to their corresponding
|
||||
machine units, updates the selected registers, and enables the output.
|
||||
|
||||
:param frequency: Frequency in Hz.
|
||||
:param phase: Phase in fractional turns (e.g., 0.5 for 180 degrees).
|
||||
:param freq_reg: Frequency register to write to (0 or 1).
|
||||
:param phase_reg: Phase register to write to (0 or 1).
|
||||
"""
|
||||
assert 0 <= freq_reg <= 1, "Invalid frequency register index"
|
||||
assert 0 <= phase_reg <= 1, "Invalid phase register index"
|
||||
|
||||
freq_word = self.frequency_to_ftw(frequency)
|
||||
phase_word = self.turns_to_pow(phase)
|
||||
self.set_mu(freq_word, phase_word, freq_reg, phase_reg)
|
||||
|
@ -11,8 +11,6 @@ from artiq.coredevice.ad9834 import (
|
||||
AD9834_SIGN_PIB,
|
||||
AD9834_SLEEP1,
|
||||
AD9834_SLEEP12,
|
||||
FREQ_REGS,
|
||||
PHASE_REGS,
|
||||
)
|
||||
from artiq.experiment import *
|
||||
from artiq.language.units import MHz
|
||||
@ -34,165 +32,251 @@ class AD9834Exp(EnvExperiment):
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.set_dataset("spi_freq", self.dev.spi_freq)
|
||||
self.set_dataset("clk_freq", self.dev.clk_freq)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_fail1(self):
|
||||
self.core.break_realtime()
|
||||
frequency = 10 * MHz
|
||||
self.dev.set_frequency_reg(19, frequency)
|
||||
def frequency_to_ftw_fail(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.frequency_to_ftw(37.6 * MHz)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_fail2(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.set_frequency_reg(FREQ_REGS[0], 37.6 * MHz)
|
||||
def turns_to_phase_fail(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.turns_to_phase(1.1)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_fail(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_frequency_reg(19, self.dev.frequency_to_ftw(10 * MHz))
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_frequency_reg(FREQ_REGS[1], 19 * MHz)
|
||||
self.dev.set_frequency_reg(1, self.dev.frequency_to_ftw(19 * MHz))
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_msb(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.ctrl_reg |= AD9834_B28
|
||||
self.dev.set_frequency_reg_msb(FREQ_REGS[0], 0x1111)
|
||||
self.dev.set_frequency_reg_msb(0, 0x1111)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def set_frequency_reg_lsb(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.ctrl_reg |= AD9834_B28 | AD9834_HLB
|
||||
self.dev.set_frequency_reg_lsb(FREQ_REGS[1], 0xFFFF)
|
||||
self.dev.set_frequency_reg_lsb(1, 0xFFFF)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def select_frequency_reg_0(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_FSEL | AD9834_PIN_SW
|
||||
self.dev.select_frequency_reg(FREQ_REGS[0])
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.select_frequency_reg(0)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg & ~(AD9834_FSEL | AD9834_PIN_SW))
|
||||
|
||||
@kernel
|
||||
def select_frequency_reg_1(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_PIN_SW
|
||||
self.dev.select_frequency_reg(FREQ_REGS[1])
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.select_frequency_reg(1)
|
||||
self.set_dataset("ctrl_reg", (self.dev.ctrl_reg | AD9834_FSEL) & ~AD9834_PIN_SW)
|
||||
|
||||
@kernel
|
||||
def set_phase_reg_fail(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_phase_reg(19, 0x123)
|
||||
|
||||
@kernel
|
||||
def set_phase_reg(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_phase_reg(PHASE_REGS[0], 0x123)
|
||||
self.dev.set_phase_reg(0, 0x123)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def select_phase_reg_0(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_PSEL | AD9834_PIN_SW
|
||||
self.dev.select_phase_reg(PHASE_REGS[0])
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.select_phase_reg(0)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg & ~(AD9834_PSEL | AD9834_PIN_SW))
|
||||
|
||||
@kernel
|
||||
def select_phase_reg_1(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_PIN_SW
|
||||
self.dev.select_phase_reg(PHASE_REGS[1])
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def enable_reset(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.enable_reset()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def output_enable(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_RESET
|
||||
self.dev.output_enable()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.select_phase_reg(1)
|
||||
self.set_dataset("ctrl_reg", (self.dev.ctrl_reg | AD9834_PSEL) & ~AD9834_PIN_SW)
|
||||
|
||||
@kernel
|
||||
def sleep_dac_powerdown(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.sleep(dac_pd=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def sleep_internal_clk_disable(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.sleep(clk_dis=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def sleep(self):
|
||||
self.core.break_realtime()
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.sleep(dac_pd=True, clk_dis=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
|
||||
@kernel
|
||||
def awake(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_SLEEP1 | AD9834_SLEEP12
|
||||
self.dev.sleep()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.awake()
|
||||
self.set_dataset(
|
||||
"ctrl_reg", self.dev.ctrl_reg & ~(AD9834_SLEEP1 | AD9834_SLEEP12)
|
||||
)
|
||||
|
||||
@kernel
|
||||
def sign_bit_high_z(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_OPBITEN
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.config_sign_bit_out()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg & ~AD9834_OPBITEN)
|
||||
|
||||
@kernel
|
||||
def sign_bit_msb_2(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_MODE | AD9834_SIGN_PIB | AD9834_DIV2
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.config_sign_bit_out(msb_2=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset(
|
||||
"ctrl_reg",
|
||||
(self.dev.ctrl_reg | AD9834_OPBITEN)
|
||||
& ~(AD9834_MODE | AD9834_SIGN_PIB | AD9834_DIV2),
|
||||
)
|
||||
|
||||
@kernel
|
||||
def sign_bit_msb(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_MODE | AD9834_SIGN_PIB
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.config_sign_bit_out(msb=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset(
|
||||
"ctrl_reg",
|
||||
(self.dev.ctrl_reg | AD9834_MODE | AD9834_SIGN_PIB)
|
||||
& ~(AD9834_MODE | AD9834_SIGN_PIB),
|
||||
)
|
||||
|
||||
@kernel
|
||||
def sign_bit_comp_out(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_MODE
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.config_sign_bit_out(comp_out=True)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset(
|
||||
"ctrl_reg",
|
||||
(self.dev.ctrl_reg | AD9834_OPBITEN | AD9834_SIGN_PIB | AD9834_DIV2)
|
||||
& ~AD9834_MODE,
|
||||
)
|
||||
|
||||
@kernel
|
||||
def enable_triangular_waveform(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_OPBITEN
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.enable_triangular_waveform()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg | AD9834_MODE)
|
||||
|
||||
@kernel
|
||||
def disable_triangular_waveform(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.ctrl_reg |= AD9834_MODE
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.disable_triangular_waveform()
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg)
|
||||
self.set_dataset("ctrl_reg", self.dev.ctrl_reg & ~AD9834_MODE)
|
||||
|
||||
## The following tests should be hooked up to an oscilloscope
|
||||
## to monitor the waveforms
|
||||
@kernel
|
||||
def single_tone(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_frequency_reg(0, self.dev.frequency_to_ftw(1 * MHz))
|
||||
self.dev.select_frequency_reg(0)
|
||||
self.dev.output_enable()
|
||||
delay(5 * s)
|
||||
self.dev.enable_reset()
|
||||
self.core.wait_until_mu(now_mu())
|
||||
|
||||
@kernel
|
||||
def toggle_frequency(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_frequency_reg(0, self.dev.frequency_to_ftw(1 * MHz))
|
||||
self.dev.set_frequency_reg(1, self.dev.frequency_to_ftw(2 * MHz))
|
||||
self.dev.select_frequency_reg(0)
|
||||
self.dev.output_enable()
|
||||
|
||||
for _ in range(6):
|
||||
self.dev.select_frequency_reg(0)
|
||||
delay(1 * s)
|
||||
self.dev.select_frequency_reg(1)
|
||||
delay(1 * s)
|
||||
|
||||
self.dev.enable_reset()
|
||||
self.core.wait_until_mu(now_mu())
|
||||
|
||||
@kernel
|
||||
def toggle_phase(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set_frequency_reg(0, self.dev.frequency_to_ftw(1 * MHz))
|
||||
self.dev.select_frequency_reg(0)
|
||||
self.dev.set_phase_reg(0, 0x0)
|
||||
self.dev.set_phase_reg(1, 0x7FF)
|
||||
self.dev.output_enable()
|
||||
|
||||
for _ in range(300000):
|
||||
self.dev.select_phase_reg(0)
|
||||
delay(10 * us)
|
||||
self.dev.select_phase_reg(1)
|
||||
delay(10 * us)
|
||||
|
||||
self.dev.enable_reset()
|
||||
self.core.wait_until_mu(now_mu())
|
||||
|
||||
@kernel
|
||||
def set_mu(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
freq_word = self.dev.frequency_to_ftw(1 * MHz)
|
||||
phase_word = self.dev.turns_to_phase(0.5)
|
||||
self.dev.set_mu(freq_word, phase_word, 0, 1)
|
||||
|
||||
delay(5 * s)
|
||||
|
||||
self.dev.enable_reset()
|
||||
self.core.wait_until_mu(now_mu())
|
||||
|
||||
@kernel
|
||||
def set(self):
|
||||
self.core.reset()
|
||||
self.dev.init()
|
||||
self.dev.set(2 * MHz, 0.5, 1, 0)
|
||||
|
||||
delay(5 * s)
|
||||
|
||||
self.dev.enable_reset()
|
||||
self.core.wait_until_mu(now_mu())
|
||||
|
||||
|
||||
class AD9834Test(ExperimentCase):
|
||||
@ -208,21 +292,27 @@ class AD9834Test(ExperimentCase):
|
||||
self.assertEqual(clk_freq, 75 * MHz)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_set_frequency_reg_fail(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.execute(AD9834Exp, "set_frequency_reg_fail1")
|
||||
def test_frequency_to_ftw_fail(self):
|
||||
with self.assertRaises(AssertionError):
|
||||
self.execute(AD9834Exp, "set_frequency_reg_fail2")
|
||||
self.execute(AD9834Exp, "frequency_to_ftw_fail")
|
||||
|
||||
def test_turns_to_phase_fail(self):
|
||||
with self.assertRaises(AssertionError):
|
||||
self.execute(AD9834Exp, "turns_to_phase_fail")
|
||||
|
||||
def test_set_frequency_reg_fail(self):
|
||||
with self.assertRaises(AssertionError):
|
||||
self.execute(AD9834Exp, "set_frequency_reg_fail")
|
||||
|
||||
def test_set_frequency_reg(self):
|
||||
self.execute(AD9834Exp, "set_frequency_reg")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET | AD9834_B28)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_B28 | AD9834_RESET)
|
||||
|
||||
def test_set_frequency_reg_msb(self):
|
||||
self.execute(AD9834Exp, "set_frequency_reg_msb")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET | AD9834_HLB)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_HLB | AD9834_RESET)
|
||||
|
||||
def test_set_frequency_reg_lsb(self):
|
||||
self.execute(AD9834Exp, "set_frequency_reg_lsb")
|
||||
@ -232,15 +322,15 @@ class AD9834Test(ExperimentCase):
|
||||
def test_select_frequency_reg_0(self):
|
||||
self.execute(AD9834Exp, "select_frequency_reg_0")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_select_frequency_reg_1(self):
|
||||
self.execute(AD9834Exp, "select_frequency_reg_1")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_FSEL)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_FSEL | AD9834_RESET)
|
||||
|
||||
def test_set_phase_reg_fail(self):
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(AssertionError):
|
||||
self.execute(AD9834Exp, "set_phase_reg_fail")
|
||||
|
||||
def test_set_phase_reg(self):
|
||||
@ -251,71 +341,85 @@ class AD9834Test(ExperimentCase):
|
||||
def test_select_phase_reg_0(self):
|
||||
self.execute(AD9834Exp, "select_phase_reg_0")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_select_phase_reg_1(self):
|
||||
self.execute(AD9834Exp, "select_phase_reg_1")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_PSEL)
|
||||
|
||||
def test_enable_reset(self):
|
||||
self.execute(AD9834Exp, "enable_reset")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_output_enable(self):
|
||||
self.execute(AD9834Exp, "output_enable")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_PSEL | AD9834_RESET)
|
||||
|
||||
def test_sleep_dac_powerdown(self):
|
||||
self.execute(AD9834Exp, "sleep_dac_powerdown")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_SLEEP12)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_SLEEP12 | AD9834_RESET)
|
||||
|
||||
def test_sleep_internal_clk_disable(self):
|
||||
self.execute(AD9834Exp, "sleep_internal_clk_disable")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_SLEEP1)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_SLEEP1 | AD9834_RESET)
|
||||
|
||||
def test_sleep(self):
|
||||
self.execute(AD9834Exp, "sleep")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_SLEEP1 | AD9834_SLEEP12)
|
||||
self.assertEqual(
|
||||
ctrl_reg, 0x0000 | AD9834_SLEEP1 | AD9834_SLEEP12 | AD9834_RESET
|
||||
)
|
||||
|
||||
def test_awake(self):
|
||||
self.execute(AD9834Exp, "awake")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_sign_bit_high_z(self):
|
||||
self.execute(AD9834Exp, "sign_bit_high_z")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
def test_sign_bit_msb_2(self):
|
||||
self.execute(AD9834Exp, "sign_bit_msb_2")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_OPBITEN)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_OPBITEN | AD9834_RESET)
|
||||
|
||||
def test_sign_bit_msb(self):
|
||||
self.execute(AD9834Exp, "sign_bit_msb")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_OPBITEN | AD9834_DIV2)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_OPBITEN | AD9834_DIV2 | AD9834_RESET)
|
||||
|
||||
def test_sign_bit_comp_out(self):
|
||||
self.execute(AD9834Exp, "sign_bit_comp_out")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(
|
||||
ctrl_reg, 0x0000 | AD9834_OPBITEN | AD9834_SIGN_PIB | AD9834_DIV2
|
||||
ctrl_reg,
|
||||
0x0000 | AD9834_OPBITEN | AD9834_SIGN_PIB | AD9834_DIV2 | AD9834_RESET,
|
||||
)
|
||||
|
||||
def test_enble_triangular_waveform(self):
|
||||
self.execute(AD9834Exp, "enable_triangular_waveform")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_MODE)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_MODE | AD9834_RESET)
|
||||
|
||||
def test_disble_triangular_waveform(self):
|
||||
self.execute(AD9834Exp, "disable_triangular_waveform")
|
||||
ctrl_reg = self.dataset_mgr.get("ctrl_reg")
|
||||
self.assertEqual(ctrl_reg, 0x0000)
|
||||
self.assertEqual(ctrl_reg, 0x0000 | AD9834_RESET)
|
||||
|
||||
## Waveform Tests
|
||||
def test_single_tone(self):
|
||||
print("Running waveform test:", self._testMethodName)
|
||||
self.execute(AD9834Exp, "single_tone")
|
||||
|
||||
def test_toggle_frequency(self):
|
||||
print("Running waveform test:", self._testMethodName)
|
||||
self.execute(AD9834Exp, "toggle_frequency")
|
||||
|
||||
def test_toggle_phase(self):
|
||||
print("Running waveform test:", self._testMethodName)
|
||||
self.execute(AD9834Exp, "toggle_phase")
|
||||
|
||||
def test_set_mu(self):
|
||||
print("Running waveform test:", self._testMethodName)
|
||||
self.execute(AD9834Exp, "set_mu")
|
||||
|
||||
def test_set(self):
|
||||
print("Running waveform test:", self._testMethodName)
|
||||
self.execute(AD9834Exp, "set")
|
||||
|
Loading…
Reference in New Issue
Block a user