1
0
forked from M-Labs/artiq

ad9834: port to nac3

This commit is contained in:
Sébastien Bourdeauducq 2024-12-17 17:29:11 +08:00
parent 62faca81e9
commit 7c93a69e6f

View File

@ -5,10 +5,12 @@ 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/data-sheets/AD9834.pdf
# https://www.analog.com/media/en/technical-documentation/app-notes/an-1070.pdf # https://www.analog.com/media/en/technical-documentation/app-notes/an-1070.pdf
from artiq.coredevice import spi2 as spi from numpy import int32
from artiq.coredevice.core import Core
from artiq.coredevice.spi2 import *
from artiq.experiment import * from artiq.experiment import *
from artiq.language.core import * from artiq.language.core import *
from artiq.language.types import *
from artiq.language.units import * from artiq.language.units import *
AD9834_B28 = 1 << 13 AD9834_B28 = 1 << 13
@ -34,6 +36,7 @@ AD9834_PHASE_REG_1 = AD9834_PHASE_REG | (1 << 13)
PHASE_REGS = [AD9834_PHASE_REG_0, AD9834_PHASE_REG_1] PHASE_REGS = [AD9834_PHASE_REG_0, AD9834_PHASE_REG_1]
@nac3
class AD9834: class AD9834:
""" """
AD9834 DDS driver. AD9834 DDS driver.
@ -51,14 +54,18 @@ class AD9834:
:param core_device: Core device name (default: "core"). :param core_device: Core device name (default: "core").
""" """
kernel_invariants = {"core", "bus", "spi_freq", "clk_freq"} core: KernelInvariant[Core]
bus: KernelInvariant[SPIMaster]
spi_freq: KernelInvariant[float]
clk_freq: KernelInvariant[float]
ctrl_reg: Kernel[int32]
def __init__( def __init__(
self, dmgr, spi_device, spi_freq=10 * MHz, clk_freq=75 * MHz, core_device="core" self, dmgr, spi_device, spi_freq=10. * MHz, clk_freq=75. * MHz, core_device="core"
): ):
self.core = dmgr.get(core_device) self.core = dmgr.get(core_device)
self.bus = dmgr.get(spi_device) self.bus = dmgr.get(spi_device)
assert spi_freq <= 40 * MHz, "SPI frequency exceeds maximum value of 40 MHz" assert spi_freq <= 40. * MHz, "SPI frequency exceeds maximum value of 40 MHz"
self.spi_freq = spi_freq self.spi_freq = spi_freq
self.clk_freq = clk_freq self.clk_freq = clk_freq
self.ctrl_reg = 0x0000 # Reset control register self.ctrl_reg = 0x0000 # Reset control register
@ -81,11 +88,11 @@ class AD9834:
This method should be called before any other operations are performed This method should be called before any other operations are performed
on the AD9834 to ensure that the device is in a known state. 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.bus.set_config(SPI_CLK_POLARITY | SPI_END, 16, self.spi_freq, 1)
self.enable_reset() self.enable_reset()
@kernel @kernel
def set_frequency_reg(self, freq_reg, frequency: TFloat): def set_frequency_reg(self, freq_reg: int32, frequency: float):
""" """
Set the frequency for the specified frequency register. Set the frequency for the specified frequency register.
@ -107,10 +114,11 @@ class AD9834:
then sends the fourteen least significant bits LSBs and fourteen most significant then sends the fourteen least significant bits LSBs and fourteen most significant
bits MSBs in two consecutive writes to the specified frequency register. bits MSBs in two consecutive writes to the specified frequency register.
""" """
if freq_reg not in FREQ_REGS: # NAC3TODO
raise ValueError("Invalid 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" assert frequency <= 37.5 * MHz, "Frequency exceeds maximum value of 37.5 MHz"
freq_word = int((frequency * (1 << 28)) / self.clk_freq) & 0x0FFFFFFF freq_word = int32((frequency * float(1 << 28)) / self.clk_freq) & 0x0FFFFFFF
self.ctrl_reg |= AD9834_B28 self.ctrl_reg |= AD9834_B28
self.write(self.ctrl_reg) self.write(self.ctrl_reg)
lsb = freq_word & 0x3FFF lsb = freq_word & 0x3FFF
@ -119,7 +127,7 @@ class AD9834:
self.write(freq_reg | msb) self.write(freq_reg | msb)
@kernel @kernel
def set_frequency_reg_msb(self, freq_reg, word: TInt32): def set_frequency_reg_msb(self, freq_reg: int32, word: int32):
""" """
Set the fourteen most significant bits MSBs of the specified frequency register. Set the fourteen most significant bits MSBs of the specified frequency register.
@ -134,15 +142,16 @@ class AD9834:
indicate that the MSB is being sent, and then writes the updated control register indicate that the MSB is being sent, and then writes the updated control register
followed by the MSB value to the specified frequency register. followed by the MSB value to the specified frequency register.
""" """
if freq_reg not in FREQ_REGS: # NAC3TODO
raise ValueError("Invalid frequency register") #if freq_reg not in FREQ_REGS:
# raise ValueError("Invalid frequency register")
self.ctrl_reg &= ~AD9834_B28 self.ctrl_reg &= ~AD9834_B28
self.ctrl_reg |= AD9834_HLB self.ctrl_reg |= AD9834_HLB
self.write(self.ctrl_reg) self.write(self.ctrl_reg)
self.write(freq_reg | (word & 0x3FFF)) self.write(freq_reg | (word & 0x3FFF))
@kernel @kernel
def set_frequency_reg_lsb(self, freq_reg, word: TInt32): def set_frequency_reg_lsb(self, freq_reg: int32, word: int32):
""" """
Set the fourteen least significant bits LSBs of the specified frequency register. Set the fourteen least significant bits LSBs of the specified frequency register.
@ -156,15 +165,16 @@ class AD9834:
The method first clears the appropriate control bits and writes the updated control The method first clears the appropriate control bits and writes the updated control
register followed by the LSB value to the specified frequency register. register followed by the LSB value to the specified frequency register.
""" """
if freq_reg not in FREQ_REGS: # NAC3TODO
raise ValueError("Invalid frequency register") #if freq_reg not in FREQ_REGS:
# raise ValueError("Invalid frequency register")
self.ctrl_reg &= ~AD9834_B28 self.ctrl_reg &= ~AD9834_B28
self.ctrl_reg &= ~AD9834_HLB self.ctrl_reg &= ~AD9834_HLB
self.write(self.ctrl_reg) self.write(self.ctrl_reg)
self.write(freq_reg | (word & 0x3FFF)) self.write(freq_reg | (word & 0x3FFF))
@kernel @kernel
def select_frequency_reg(self, freq_reg): def select_frequency_reg(self, freq_reg: int32):
""" """
Select the active frequency register for the phase accumulator. Select the active frequency register for the phase accumulator.
@ -175,8 +185,9 @@ class AD9834:
:param freq_reg: The frequency register to select. Must be one of :param freq_reg: The frequency register to select. Must be one of
:const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`. :const:`AD9834_FREQ_REG_0` or :const:`AD9834_FREQ_REG_1`.
""" """
if freq_reg not in FREQ_REGS: # NAC3TODO
raise ValueError("Invalid frequency register") #if freq_reg not in FREQ_REGS:
# raise ValueError("Invalid frequency register")
if freq_reg == FREQ_REGS[0]: if freq_reg == FREQ_REGS[0]:
self.ctrl_reg &= ~AD9834_FSEL self.ctrl_reg &= ~AD9834_FSEL
else: else:
@ -186,7 +197,7 @@ class AD9834:
self.write(self.ctrl_reg) self.write(self.ctrl_reg)
@kernel @kernel
def set_phase_reg(self, phase_reg, phase: TInt32): def set_phase_reg(self, phase_reg: int32, phase: int32):
""" """
Set the phase for the specified phase register. Set the phase for the specified phase register.
@ -199,13 +210,14 @@ class AD9834:
The method masks the phase value to ensure it fits within the 12-bit limit The method masks the phase value to ensure it fits within the 12-bit limit
and writes it to the specified phase register. and writes it to the specified phase register.
""" """
if phase_reg not in PHASE_REGS: # NAC3TODO
raise ValueError("Invalid phase register") #if phase_reg not in PHASE_REGS:
# raise ValueError("Invalid phase register")
phase_word = phase & 0x0FFF phase_word = phase & 0x0FFF
self.write(phase_reg | phase_word) self.write(phase_reg | phase_word)
@kernel @kernel
def select_phase_reg(self, phase_reg): def select_phase_reg(self, phase_reg: int32):
""" """
Select the active phase register for the phase accumulator. Select the active phase register for the phase accumulator.
@ -216,8 +228,9 @@ class AD9834:
:param phase_reg: The phase register to select. Must be one of :param phase_reg: The phase register to select. Must be one of
:const:`AD9834_PHASE_REG_0` or :const:`AD9834_PHASE_REG_1`. :const:`AD9834_PHASE_REG_0` or :const:`AD9834_PHASE_REG_1`.
""" """
if phase_reg not in PHASE_REGS: # NAC3TODO
raise ValueError("Invalid phase register") #if phase_reg not in PHASE_REGS:
# raise ValueError("Invalid phase register")
if phase_reg == PHASE_REGS[0]: if phase_reg == PHASE_REGS[0]:
self.ctrl_reg &= ~AD9834_PSEL self.ctrl_reg &= ~AD9834_PSEL
else: else:
@ -380,7 +393,7 @@ class AD9834:
self.write(self.ctrl_reg) self.write(self.ctrl_reg)
@kernel @kernel
def write(self, data: TInt32): def write(self, data: int32):
""" """
Write a 16-bit word to the AD9834. Write a 16-bit word to the AD9834.