1
0
forked from M-Labs/artiq

Update AD9834 coredevice driver

This commit is contained in:
newell 2024-12-29 21:40:13 -08:00 committed by GitHub
parent 7669cfce3d
commit 7534a8fe04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 425 additions and 281 deletions

View File

@ -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)

View File

@ -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")