Source code for rfblocks.hmc833

# `hmc833` - Encapsulates control for the HMC833 frequency synthesizer device.
#
#    Copyright (C) 2020 Dyadic Pty Ltd
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.

from typing import (
    List, Tuple, Optional
)
import math
from enum import IntFlag


[docs]class FrequencyRangeException(Exception): """Raised when a requested output frequency is out of range. """ pass
class UnknownGainSettingException(Exception): """Raised when an invalid gain setting is specified. """ pass
[docs]class hmc833(object): """Encapsulates control for the HMC833 frequency synthesizer device. Documentation for the HMC833 frequency synthesizer rfblocks module can be found here: `An HMC833 Frequency Synthesizer <../boards/HMC833-Synth.html>`_ """ MIN_FUNDAMENTAL: float = 1500.0 "The minimum VCO fundamental frequency" MAX_FUNDAMENTAL: float = 3000.0 "The maximum VCO fundamental frequency" MIN_FREQUENCY: float = 25.0 "The minimum synthesizer output frequency" MAX_FREQUENCY: float = 6000.0 "The maximum synthesizer output frequency" MIN_CP_GAIN: int = 0 MAX_CP_GAIN: int = 127
[docs] class ReferenceSource(IntFlag): """An `enum` containing the possible settings for the reference source. (``hmc833.ReferenceSource.INTERNAL``, ``hmc833.ReferenceSource.EXTERNAL``) """ INTERNAL = 0b00 EXTERNAL = 0b01
[docs] class OutputBufferGain(IntFlag): """An `enum` containing possible gain settings for the device output buffer. (``ad9552.OutputBufferGain.MAXGAIN_MINUS_9DB``, ``ad9552.OutputBufferGain.MAXGAIN_MINUS_6DB``, ``ad9552.OutputBufferGain.MAXGAIN_MINUS_3DB``, ``ad9552.OutputBufferGain.MAXGAIN``) """ MAXGAIN_MINUS_9DB = 0b00 MAXGAIN_MINUS_6DB = 0b01 MAXGAIN_MINUS_3DB = 0b10 MAXGAIN = 0b11 @classmethod def has_value(cls, value): return value in cls._value2member_map_
[docs] class DividerGain(IntFlag): """An `enum` containing possible gain settings for the divider output stage. (``ad9552.DividerGain.MAXGAIN_MINUS_3DB``, ``ad9552.DividerGain.MAXGAIN``) """ MAXGAIN_MINUS_3DB = 0b0 MAXGAIN = 0b1 @classmethod def has_value(cls, value): return value in cls._value2member_map_
DEFAULT_REFSRC: ReferenceSource = ReferenceSource.INTERNAL DEFAULT_REF_FREQ: float = 50.0 DEFAULT_CP_GAIN: int = 100 CP_GAIN_STEP: float = 20e-6 MAX_DIVIDER: int = 62 "Maximum RF output divider value" DIVIDER_VALUES: List[int] = list(range(2, MAX_DIVIDER+1, 2)) "Legal RF output divider values" def __init__( self, sen: str = None, ld_sdo: str = None, ref: str = None, fref: float = DEFAULT_REF_FREQ, refdiv: int = 1, refsrc: ReferenceSource = ReferenceSource.INTERNAL, cp_gain: int = DEFAULT_CP_GAIN) -> None: """ :param sen: The HMC833 serial port enable (`SEN`) controller pin. :type sen: str :param ld_sdo: The HMC833 lock detect and GPO serial output controller pin. :type ld_sdo: str :param ref: The PLO board reference select controller pin. :type ref: str :param fref: The input reference frequency in MHz. Default: 50 MHz. :type fref: float :param refdiv: The input reference divider value (1..16,383), default 1. :type refdiv: int :param refsrc: The PLO reference source. :param type: hmc833.ReferenceSource """ self.sen = sen.upper() if sen else sen self.ld_sdo = ld_sdo.upper() if ld_sdo else ld_sdo self.ref = ref.upper() if ref else ref self._fref = fref self._refdiv = refdiv self._refsrc = refsrc self._cp_gain = cp_gain self._buf_gain = hmc833.OutputBufferGain.MAXGAIN_MINUS_9DB self._div_gain = hmc833.DividerGain.MAXGAIN_MINUS_3DB self._mute_vco = False # We keep track of the currently configured values of # the integer and fractional dividers so that we can determine # when it's necessary to change the SD fractional modulator # state (via self.init_registers). self.__nfrac: Optional[int] = None self.__nint: Optional[int] = None # We also keep track of the output RF divider ratio. # This is configured in VCO_Reg_02h which is also used # to configure the output buffer and divider buffer gains. # Therefore, in order to set gain values we also need to # ensure that the divider value remains correct. self.__divide_ratio: Optional[int] = None self.__doubler: Optional[bool] = None def __repr__(self) -> str: return "{}({!r})".format(self.__class__.__name__, vars(self)) @property def mute_vco(self) -> bool: """The synthesizer output mute setting. Set to ``False`` to enable RF output, ``True`` to mute the output. Note that this will set the value of the :py:attr:`mute_vco` property only. Updating the PLO hardware should be done separately. See, for example, :py:meth:`config_vco_mute`. """ return self._mute_vco @mute_vco.setter def mute_vco(self, mute: bool) -> None: self._mute_vco = mute @property def fref(self) -> float: """The current input reference frequency in MHz. Note that this will set the value of the :py:attr:`fref` property only. Updating the PLO hardware should be done separately. See, for example, :py:meth:`config_reference_divider`. Note also that if :py:attr:`fref` or :py:attr:`refdiv` are changed then the PLO output frequency tuning must also be updated. This can be done by calling: .. code:: python plo.config_frequency(fout, full_reg_update=True) .. seealso:: :meth:`.HMC833Controller.configure_refdiv` and :meth:`.HMC833Controller.configure_refsrc`. """ return self._fref @fref.setter def fref(self, fref: float) -> None: self._fref = fref @property def refdiv(self) -> int: """The current reference frequency divider value. Note that this will set the value of the :py:attr:`refdiv` property only. Updating the PLO hardware should be done separately. See, for example, :py:meth:`config_reference_divider`. Note also that if :py:attr:`fref` or :py:attr:`refdiv` are changed then the PLO output frequency tuning must also be updated. This can be done by calling: .. code:: python plo.config_frequency(fout, full_reg_update=True) .. seealso:: :meth:`.HMC833Controller.configure_refdiv` and :meth:`.HMC833Controller.configure_refsrc`. """ return self._refdiv @refdiv.setter def refdiv(self, refdiv: int) -> None: self._refdiv = refdiv @property def refsrc(self) -> ReferenceSource: """The current reference source. """ return self._refsrc @refsrc.setter def refsrc(self, src: ReferenceSource) -> None: self._refsrc = src @property def cp_gain(self) -> int: """The charge pump gain setting. """ return self._cp_gain @cp_gain.setter def cp_gain(self, gain: int) -> None: if gain < hmc833.MIN_CP_GAIN: self._cp_gain = hmc833.MIN_CP_GAIN if gain > hmc833.MAX_CP_GAIN: self._cp_gain = hmc833.MAX_CP_GAIN else: self._cp_gain = gain @property def buf_gain(self) -> OutputBufferGain: """The output buffer gain setting. """ return self._buf_gain @buf_gain.setter def buf_gain(self, gain: OutputBufferGain) -> None: if hmc833.OutputBufferGain.has_value(gain): self._buf_gain = gain else: raise UnknownGainSettingException @property def div_gain(self) -> DividerGain: """The divider output stage gain setting. """ return self._div_gain @div_gain.setter def div_gain(self, gain: DividerGain) -> None: if hmc833.DividerGain.has_value(gain): self._div_gain = gain else: raise UnknownGainSettingException
[docs] def auto_gain(self, fout: float) -> None: """Set the ``buf_gain`` and ``div_gain`` based on the specified output frequency. This method will adjust the output buffer and divider output buffer gains for optimal power flatness across all output frequencies (from 25 to 6000 MHz). :param fout: The device output frequency in MHz. :type fout: float .. note:: Invoking this method will set appropriate values for ``buf_gain`` and ``div_gain``. The ``config_gain`` method should then be called in order to generate a command which can be used to configure the gain settings on the actual device. .. seealso:: :py:meth:`buf_gain` :py:meth:`div_gain` :py:meth:`config_gain` >>> plo1 = hmc833('d1', 'c5') >>> plo1.auto_gain(560) >>> plo1.buf_gain <OutputBufferGain.MAXGAIN_MINUS_9DB: 0> >>> plo1.div_gain <DividerGain.MAXGAIN: 1> >>> plo1.auto_gain(1560) >>> plo1.buf_gain <OutputBufferGain.MAXGAIN_MINUS_9DB: 0> >>> plo1.div_gain <DividerGain.MAXGAIN_MINUS_3DB: 0> >>> plo1.auto_gain(2560) >>> plo1.buf_gain <OutputBufferGain.MAXGAIN_MINUS_3DB: 2> >>> plo1.div_gain <DividerGain.MAXGAIN_MINUS_3DB: 0> >>> plo1.auto_gain(3560) >>> plo1.buf_gain <OutputBufferGain.MAXGAIN_MINUS_3DB: 2> >>> plo1.div_gain <DividerGain.MAXGAIN_MINUS_3DB: 0> >>> plo1.auto_gain(4560) >>> plo1.buf_gain <OutputBufferGain.MAXGAIN: 3> >>> plo1.div_gain <DividerGain.MAXGAIN_MINUS_3DB: 0> """ if fout < 1500.0: self.div_gain = hmc833.DividerGain.MAXGAIN self.buf_gain = hmc833.OutputBufferGain.MAXGAIN_MINUS_9DB elif fout < 2500.0: self.div_gain = hmc833.DividerGain.MAXGAIN_MINUS_3DB self.buf_gain = hmc833.OutputBufferGain.MAXGAIN_MINUS_9DB elif fout <= 4300.0: self.div_gain = hmc833.DividerGain.MAXGAIN_MINUS_3DB self.buf_gain = hmc833.OutputBufferGain.MAXGAIN_MINUS_3DB else: self.div_gain = hmc833.DividerGain.MAXGAIN_MINUS_3DB self.buf_gain = hmc833.OutputBufferGain.MAXGAIN
[docs] def pin_config(self) -> str: """Initialize controller pin configuration. :return: A string specifying the commands required to initialize the connected controller pins. >>> plo1 = hmc833('d1', 'c5', fref=50.0) >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.pin_config() 'OD1:LD1:IC5:W00:' >>> plo2.pin_config() 'OD2:LD2:IC6:OB5:LB5:W00:' """ cmd = '' if self.sen: cmd += 'O{}:L{}:'.format(self.sen, self.sen) if self.ld_sdo: cmd += 'I{}:'.format(self.ld_sdo) if self.ref: cmd += 'O{}:'.format(self.ref) cmd += self.config_refsrc() # Toggle the SCK line. This will put the connected HMC833 into # 'open' mode. (See Section 1.17.2 of the HMC833 data sheet.) cmd += 'W00:' return cmd
[docs] def chip_reset(self) -> str: """Reset the chip internal logic to default states. :return: The command for reseting the PLL subsystem SPI registers. From Section 1.13 of the HMC833 data sheet: The HMC833LP6GE features a hardware Power on Reset (``POR``). All chip registers will be reset to default states approximately 250 us after power up. The PLL subsystem SPI registers may also be soft reset by an SPI write to register ``rst_swrst`` (``Reg_00h``). Note that the soft reset does not clear the SPI mode of operation referred to in section 1.17.2. The soft reset is applied by writing ``Reg_00h[5]=1``. The reset is a one time event that occurs immediately. The reset bit does not have to be returned to 0 after a reset. It should be noted that the VCO subsystem is not affected by the PLL soft reset. The VCO subsystem registers can only be reset by removing the power supply. >>> plo1 = hmc833('d1', 'c5') >>> plo1.chip_reset() 'W00,00,20,00:HD1:LD1:' """ return 'W00,00,20,00:H{}:L{}:'.format(self.sen, self.sen)
[docs] def divider_values(self, fout: float) -> Tuple[int, int, bool, int]: """Calculate the N divider values. :param fout: The desired output frequency in MHz. :type fout: float :returns: A tuple containing the parameters for the fractional frequency tuning: ``(n_int, n_frac, doubler, divider)`` where: ``n_int``: is the integer division ratio, a number between 20 and 524,284. ``n_frac`` : is the fractional part, from 0 to 2^24. ``doubler`` : is True if the frequency doubler must be enabled, False if the frequency doubler should be disabled. ``divider`` : the required setting for the output frequency divider. If this is 1 then the divider is not used. :raises: FrequencyRangeException If the specified output frequency is out of range. >>> plo1 = hmc833('d1', 'c5') >>> plo1.divider_values(762) (30, 8053064, False, 2) >>> plo1.divider_values(1762) (35, 4026532, False, 1) >>> plo1.divider_values(3762) (37, 10401874, True, 1) >>> plo1.divider_values(5762) (57, 10401874, True, 1) >>> plo1.divider_values(6762) Traceback (most recent call last): ... FrequencyRangeException >>> plo1.divider_values(20) Traceback (most recent call last): ... FrequencyRangeException """ doubler = False divider = 1 fund = fout if fout > hmc833.MAX_FUNDAMENTAL: doubler = True fund = fout/2 if fund > hmc833.MAX_FUNDAMENTAL: # The specified fout is out of range raise FrequencyRangeException elif fout < hmc833.MIN_FUNDAMENTAL: # If fout < 1500 MHz we need an output dividing factor. # Use the greatest dividing factor such that # fout*divider is between hmc833.MIN_FUNDAMENTAL and # hmc833.MAX_FUNDAMENTAL try: divider = [d for d in hmc833.DIVIDER_VALUES if fout*d >= hmc833.MIN_FUNDAMENTAL and fout*d <= hmc833.MAX_FUNDAMENTAL][-1] except IndexError: # The specified fout is out of range raise FrequencyRangeException from None fund = fout * divider nf_f, nf_i = math.modf((self.refdiv/self.fref) * fund) n_int = int(nf_i) n_frac = round(nf_f * (1 << 24)) return n_int, n_frac, doubler, divider
[docs] def config_refsrc(self) -> str: """Configure the reference source. :returns: The command string required to set the reference source switch. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.config_refsrc() '' >>> plo2.config_refsrc() 'LB5:' """ cmd = "" if self.ref is not None: if self.refsrc == hmc833.ReferenceSource.INTERNAL: cmd = "H{}:".format(self.ref) else: cmd = "L{}:".format(self.ref) return cmd
[docs] def config_reference_divider(self) -> str: """Configure the reference divider value. :returns: The command string required to set the reference divider value. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.config_reference_divider() 'W00,00,01,10:HD1:LD1:' >>> plo2.config_reference_divider() 'W00,00,04,10:HD2:LD2:' """ ref_str = '{:04x}'.format(self.refdiv & 0x3fff) return 'W00,{},{},10:H{}:L{}:'.format(ref_str[0:2], ref_str[2:4], self.sen, self.sen)
[docs] def config_spi_chipen(self) -> str: """Configure device to accept the SPI power down command. :returns: The command required to reset the device via the SPI. .. note:: From the HMC833 data sheet: It is possible to ignore the CEN pin, by clearing ``rst_chipen_pin_select`` (``Reg_01h[0]=0``). Control of Power Down Mode then comes from the serial port register ``rst_chipen_from_spi``, ``Reg_01h[1]``. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.config_spi_chipen() 'W00,00,02,08:HD1:LD1:' >>> plo2.config_spi_chipen() 'W00,00,02,08:HD2:LD2:' """ return 'W00,00,02,08:H{}:L{}:'.format(self.sen, self.sen)
[docs] def config_frequency_registers(self, nint: int, nfrac: int) -> str: """Configure the device registers for the specified fractional divide ratio :param nint: The integer part of the frequency tuning. :type nint: 19-bit int (20 to 524,284) :param nfrac: The fractional part of the frequency tuning. :type nfrac: 24-bit int (0 to 2^24) :return: The command string required to set the necessary device register values. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(1000.0) >>> plo1.config_frequency_registers(n_int, n_frac) 'W00,00,28,18:HD1:LD1:W00,00,00,20:HD1:LD1:' >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(1004.0) >>> plo1.config_frequency_registers(n_int, n_frac) 'W00,00,28,18:HD1:LD1:W28,f5,c3,20:HD1:LD1:' >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(4207.0) >>> plo1.config_frequency_registers(n_int, n_frac) 'W00,00,2a,18:HD1:LD1:W11,eb,85,20:HD1:LD1:' >>> n_int, n_frac, doubler, divide_ratio = plo2.divider_values(4207.0) >>> plo2.config_frequency_registers(n_int, n_frac) 'W00,00,21,18:HD2:LD2:Wa7,ef,9e,20:HD2:LD2:' """ cmd = '' reg_03h = '{:08x}'.format(((nint & 0x7ffff) << 8) | 0x18) cmd += 'W{},{},{},{}:H{}:L{}:'.format(reg_03h[0:2], reg_03h[2:4], reg_03h[4:6], reg_03h[6:8], self.sen, self.sen) self.__nint = nint if (self.__nfrac is None) or (self.__nfrac != nfrac): reg_04h = '{:08x}'.format(((nfrac & 0xffffff) << 8) | 0x20) cmd += 'W{},{},{},{}:H{}:L{}:'.format(reg_04h[0:2], reg_04h[2:4], reg_04h[4:6], reg_04h[6:8], self.sen, self.sen) self.__nfrac = nfrac return cmd
[docs] def init_vco_registers(self) -> str: """Initialize VCO registers 4 and 5. This initialization can be done once at device power up or reset. :return: The command required to initialize ``VCO_Reg_04h`` and ``VCO_Reg_05h``. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.init_vco_registers() 'W00,01,88,28:HD1:LD1:W00,16,28,28:HD1:LD1:W00,60,A0,28:HD1:LD1:' >>> plo2.init_vco_registers() 'W00,01,88,28:HD2:LD2:W00,16,28,28:HD2:LD2:W00,60,A0,28:HD2:LD2:' """ # VCO_Reg_01h # # 8 7 6 5 4 3 2 1 0 # | | # | Master Enable VCO Subsystem # Manual Mode PLL buffer enable vco_reg_01h = 0b0000_0011 reg_05h = '{:06X}'.format((((vco_reg_01h << 7) | 0b0001_000) << 8) | 0b0101_000) cmd = 'W00,{},{},{}:H{}:L{}:'.format(reg_05h[0:2], reg_05h[2:4], reg_05h[4:6], self.sen, self.sen) # - Configure the VCO subsystem via Reg_05h # * As per the HMC833 data sheet (Section 3.6), VCO_Reg_05h # is configured with: # # 0001_0110_0010_1000 = 0x1628 # \/\_/\/\_/\___/\_/ # | | | | | VCO subsystem addr # | | | | VCO_Reg_05h # | | | CF L = 0b00 # | | CF ML = 0b11 # | CF MH = 0b10 # CF H = 0b00 # # * As per the HMC833 data sheet (Section 3.5), VCO_Reg_04h # is configured with: # # 0110_0000_1010_0000 = 0x60A0 # \/\/ \/\__/\___/\_/ # | | | | | VCO subsystem addr # | | | | VCO_Reg_04h # | | | VCO bias = 0b001 # | | PLL buffer bias = 0b00 # | FndLmtr bias = 0b10 # Preset cal 0 = 0b01 # cmd += 'W00,16,28,28:H{}:L{}:'.format(self.sen, self.sen) cmd += 'W00,60,A0,28:H{}:L{}:'.format(self.sen, self.sen) return cmd
[docs] def config_vco_divider(self, out_div: int) -> str: """Configure the VCO output divider. :param out_div: The required VCO divider value. :type out_div: int :return: The command string required to configure the specified VCO divide value. .. note:: This method may also be used to configure the VCO divider and output buffer gains. The gain values must have been previously set using :py:meth:`buf_gain` and/or :py:meth:`div_gain`. The ``out_div`` parameter should be set to the currently configured VCO divide value (available internally as ``self.__divide_ratio``). """ # VCO_Reg_02h # # 8 7 6 5 4 3 2 1 0 # | \_/ \_________/ # | | RF divide ratio # | RF output buf. gain control # divider gain control vco_reg_02h = ((self.div_gain & 0x1) << 8) \ | ((self.buf_gain & 0x3) << 6) \ | out_div & 0x3f reg_05h = '{:06X}'.format((((vco_reg_02h << 7) | 0b0010_000) << 8) | 0b0101_000) cmd = 'W00,{},{},{}:H{}:L{}:'.format(reg_05h[0:2], reg_05h[2:4], reg_05h[4:6], self.sen, self.sen) return cmd
[docs] def config_vco_doubler(self, doubler: bool) -> str: """Configure the VCO output frequency doubler. :param doubler: True to activate the frequency doubler, False to deactivate it. :type doubler: bool :return: The command string required to configure the specified VCO frequency doubler state. .. note:: This method may also be used to mute the VCO output. The VCO mute state must have been previously set using :py:meth:`mute_vco`. The ``doubler`` parameter should be set to the currently configured VCO frequency doubler state (available internally as ``self.__doubler``). """ # VCO_Reg_03h # # 0000_0000_0 # \/| | # || fund./doubler: 0 = enable doubler, 1 = fundamental # |manual RFO mode: 0 = autoRFO (recommended) # RF buf. bias: 0b10 for fout <= 3000MHz (VCO_Reg_03h[0] = 1) # 0b00 for fout > 3000MHz (VCO_Reg_03h[0] = 0) if doubler: if self.mute_vco: vco_reg_03h = 0b0000_0010_0 else: vco_reg_03h = 0b0000_0000_0 else: if self.mute_vco: vco_reg_03h = 0b0000_1010_1 else: vco_reg_03h = 0b0000_1000_1 reg_05h = '{:06X}'.format((((vco_reg_03h << 7) | 0b0011_000) << 8) | 0b0101_000) cmd = 'W00,{},{},{}:H{}:L{}:'.format(reg_05h[0:2], reg_05h[2:4], reg_05h[4:6], self.sen, self.sen) return cmd
[docs] def config_vco_registers(self, out_div: int, doubler: bool) -> str: """Configure VCO registers for the specified divide ratio/doubler. :param out_div: The specified output divide ratio. This should be in the range 1..62 although only the values in `[1] + hmc833.DIVIDER_VALUES` are legal. :type out_div: int :param doubler: True if the output frequency doubler should be enabled, False if the doubler should be disabled. :type doubler: bool :return: The commands required to set the necessary VCO register values. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(1000.0) >>> plo1.config_vco_registers(divide_ratio, doubler) 'W00,01,10,28:HD1:LD1:W00,08,98,28:HD1:LD1:W00,00,00,28:HD1:LD1:' >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(1004.0) >>> plo1.config_vco_registers(divide_ratio, doubler) '' >>> n_int, n_frac, doubler, divide_ratio = plo1.divider_values(4207.0) >>> plo1.config_vco_registers(divide_ratio, doubler) 'W00,00,90,28:HD1:LD1:W00,00,18,28:HD1:LD1:W00,00,00,28:HD1:LD1:' >>> n_int, n_frac, doubler, divide_ratio = plo2.divider_values(4207.0) >>> plo2.config_vco_registers(divide_ratio, doubler) 'W00,00,90,28:HD2:LD2:W00,00,18,28:HD2:LD2:W00,00,00,28:HD2:LD2:' """ cmd = '' if (self.__divide_ratio is None) or (self.__divide_ratio != out_div): cmd += self.config_vco_divider(out_div) self.__divide_ratio = out_div if (self.__doubler is None) or (self.__doubler != doubler): cmd += self.config_vco_doubler(doubler) self.__doubler = doubler if len(cmd): # Close out VCO register programming by writing reg_05h = 0 cmd += self.close_vco_config() return cmd
[docs] def config_chargepump(self, sd_mod_en: bool) -> str: """Configure the PLO sigma/delta modulator. :param en: True for enabling the SD modulator. False to disable. :type en: bool :return: The command string required to effect the register initialization. """ f_pd = self._fref/self._refdiv * 1e6 i_cp = self.cp_gain * hmc833.CP_GAIN_STEP cp_offset = round(min(4.3e-9 * f_pd * i_cp, 0.25 * i_cp) * 1e6) if sd_mod_en: cp_conf = 0x400000 else: cp_conf = 0x000000 cp_conf |= ((int(cp_offset/5) << 14) | (self.cp_gain << 7) | self.cp_gain) reg_09h = '{:08X}'.format((cp_conf << 8) | 0x48) cmd = 'W{},{},{},{}:H{}:L{}:'.format(reg_09h[0:2], reg_09h[2:4], reg_09h[4:6], reg_09h[6:8], self.sen, self.sen) return cmd
[docs] def enable_sd_modulator(self, en: bool) -> str: """Configure the PLO sigma/delta modulator. :param en: True for enabling the SD modulator. False to disable. :type en: bool :return: The command string required to effect the register initialization. """ if en: # - Enable the SD modulator, Reg_06h[11] = 1 # - Connect modulator in circuit, Reg_06h[7] = 0 # # 0000_0011_0000_1111_0100_1010_0011_0000 # | || | \/\/ \____/ # | || | | | Reg_06h # | || | | fractional seed (B29D08h seed) # | || | modulator type (mode B) # | || 0 = use modulator (fractional mode) # | |1 = auto seed # | 1 = modulator uses VCO divider clock # 1 = enable SD modulator cmd = 'W03,0F,4A,30:H{}:L{}:'.format(self.sen, self.sen) # reg_09h = '{:08X}'.format((0x1CBFFF << 8) | 0x48) # Icp = 2mA: # reg_09h = '{:08X}'.format((0x15B264 << 8) | 0x48) # Icp = 1mA # reg_09h = '{:08X}'.format((0x0AD932 << 8) | 0x48) else: # - Disable the SD modulator, Reg_06h[11] = 0 # - Bypass the modulator, Reg_06h[7] = 1 # # 0000_0011_0000_0111_1100_1010_0011_0000 # | || | \/\/ \____/ # | || | | | Reg_06h # | || | | fractional seed (B29D08h seed) # | || | modulator type (mode B) # | || 1 = bypass modulator (integer mode) # | |1 = auto seed # | 1 = modulator uses VCO divider clock # 0 = disable SD modulator # # Note: SD modulator mode B is recommended. The max. PD freq. # in this mode is 100 MHz. (max. PD freq. for mode A # is 80 MHz.) cmd = 'W03,07,CA,30:H{}:L{}:'.format(self.sen, self.sen) # reg_09h = '{:08X}'.format((0x5CBFFF << 8) | 0x48) # Icp = 2mA: # reg_09h = '{:08X}'.format((0x55B264 << 8) | 0x48) # Icp = 1mA # reg_09h = '{:08X}'.format((0x4AD932 << 8) | 0x48) #cmd += 'W{},{},{},{}:H{}:L{}:'.format(reg_09h[0:2], reg_09h[2:4], # reg_09h[4:6], reg_09h[6:8], # self.sen, self.sen) cmd += self.config_chargepump(en) return cmd
[docs] def init_registers(self, nint: int, nfrac: int, out_div: int, doubler: bool = False) -> str: """Initialize the frequency, SD modulator and VCO subsystem registers. :param nint: The integer part of the frequency tuning. :type nint: 19-bit int :param nfrac: The fractional part of the frequency tuning. :type nfrac: 24-bit int :param out_div: The RF output divider value. :type out_div: 5-bit int :param doubler: Enables or disables the output frequency doubler. :type doubler: bool :return: The command string required to effect the register initialization. .. note:: The synthesizer output frequency is controlled by the following registers: - Frequency register, integer part, ``Reg_03h[18:0]`` - Frequency register, fractional part, ``Reg_04h[23:0]`` The SD modulator is configured by the following: - Fractional bypass, ``Reg_06h[7]`` - SD enable, ``Reg_06h[11]`` The VCO subsystem registers are accessed via ``Reg_05h``. ``Reg_05h`` is a special register used for indirect addressing of the VCO subsystem. Writes to ``Reg_05h`` are automatically forwarded to the VCO subsystem by the VCO SPI state machine controller. - ``Reg_05h[2:0]`` holds the VCO subsystem address: 0b000 - ``Reg_05h[6:3]`` is the VCO subsystem register address - ``Reg_05h[15:7]`` is the data to be written to the VCO register The VCO subsystem registers control the following: - RF divide ratio, ``VCO_Reg_02h[5:0]`` - RF output buffer gain control, ``VCO_Reg_02h[7:6]`` - Divider output stage gain control, ``VCO_Reg_02h[8]`` - Fundamental/doubler mode selection, ``VCO_Reg_03h[0]`` - RF buffer bias, ``VCO_Reg_03h[4:3]`` >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.init_registers(*plo1.divider_values(1000.0)) 'W03,07,CA,30:HD1:LD1:W15,B2,64,48:HD1:LD1:W00,21,4d,38:HD1:LD1:WC1,BE,FF,40:HD1:LD1:W00,20,46,50:HD1:LD1:W07,C0,61,58:HD1:LD1:W00,00,C1,78:HD1:LD1:' >>> plo2.init_registers(*plo2.divider_values(4207.0)) 'W03,0F,4A,30:HD2:LD2:W59,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:' """ cmd = '' # Setting nfrac to 0 indicates that integer mode should be used. if nfrac == 0: cmd += self.enable_sd_modulator(False) else: cmd += self.enable_sd_modulator(True) # - Configure lock detect and auto-relock via Reg_07h # # 0000_0000_0010_0001_0100_1101_0011_1000 # | \__/| |\_/ \____/ # | | | | | Reg_07h # | | | | lock detect window (2048) # | | | enable lock detect # | | lock detect window type (digital) # | | # | digital window duration (2 cycles) # auto-relock cmd += 'W00,21,4D,38:H{}:L{}:'.format(self.sen, self.sen) cmd += self.config_analog_enables() cmd += self.config_autocal() # - Configure phase detect via Reg_0Bh # # 0000_0111_1100_0000_0110_0001_0101_1000 # \_/|| \_/ \____/ # | || | Reg_0Bh # | || PD reset path delay # | |enable PD UP output # | enable PD DN output # cycle slip prevention disabled cmd += 'W07,C0,61,58:H{}:L{}:'.format(self.sen, self.sen) # - Configure GPO and LD_SDO via Reg_0Fh # We want LD_SDO to always provide the lock detect signal # # 0000_0000_0000_0000_1100_0001_0111_1000 # || \____/ \____/ # || | Reg_0Fh # || GPO select: lock detect output # |Prevent SDO automux. 1 = output GPO data only # LD_SDO pin driver always on cmd += 'W00,00,C1,78:H{}:L{}:'.format(self.sen, self.sen) return cmd
[docs] def device_initialize(self, fout: float) -> str: """Configure the PLL after power up. :param fout: The initial output frequency in MHz. :type fout: float :return: The command string required to effect the device initialization. To configure the PLL after power up: 1. Configure the reference divider (write to ``Reg_02h``), if required. 2. Configure the delta-sigma modulator (write to ``Reg_06h``). - Configuration involves selecting the mode of the delta-sigma modulator (Mode A or Mode B), selection of the delta-sigma modulator seed value, and configuration of the delta-sigma modulator clock scheme. It is recommended to use the values found in the Hittite PLL evaluation board control software register files. 3. Configure the charge pump current and charge pump offset current (write to ``Reg_09h``) 4. Configure the VCO Subsystem (write to ``Reg_05h``, for more information see section 1.19, and *3.0 VCO Subsystem Register Map*. Detailed writes to the VCO subsystem via PLL ``Reg_05h`` at start-up are available in the Register Setting Files found in the Hittite PLL Evaluation Software 5. Configure the VCO output divider/doubler, if needed in the VCO subsystem via PLL ``Reg_05h``. 6. Program the frequency of operation - Program the integer part (write to ``Reg_03h``) - Program the fractional part (write to ``Reg_04h``) Once the HMC833LP6GE is configured after startup, in most cases the user only needs to change frequencies by writing to ``Reg_03h`` integer register, ``Reg_04h`` fractional register, and ``Reg_05h`` to change the VCO output divider or doubler setting if needed, and possibly adjust the charge pump settings by writing to ``Reg_09h``. >>> plo1 = hmc833('d6', 'd7') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.device_initialize(1000.0) 'W00,00,20,00:HD6:LD6:W00,00,02,08:HD6:LD6:W00,00,01,10:HD6:LD6:W00,01,88,28:HD6:LD6:W00,16,28,28:HD6:LD6:W00,60,A0,28:HD6:LD6:W00,01,10,28:HD6:LD6:W00,08,98,28:HD6:LD6:W00,00,00,28:HD6:LD6:W03,07,CA,30:HD6:LD6:W15,B2,64,48:HD6:LD6:W00,21,4d,38:HD6:LD6:WC1,BE,FF,40:HD6:LD6:W00,20,46,50:HD6:LD6:W07,C0,61,58:HD6:LD6:W00,00,C1,78:HD6:LD6:W00,00,28,18:HD6:LD6:W00,00,00,20:HD6:LD6:' >>> plo1.device_initialize(3409.0) 'W00,00,20,00:HD6:LD6:W00,00,02,08:HD6:LD6:W00,00,01,10:HD6:LD6:W00,01,88,28:HD6:LD6:W00,16,28,28:HD6:LD6:W00,60,A0,28:HD6:LD6:W00,00,90,28:HD6:LD6:W00,00,18,28:HD6:LD6:W00,00,00,28:HD6:LD6:W03,0F,4A,30:HD6:LD6:W55,B2,64,48:HD6:LD6:W00,21,4d,38:HD6:LD6:WC1,BE,FF,40:HD6:LD6:W00,20,46,50:HD6:LD6:W07,C0,61,58:HD6:LD6:W00,00,C1,78:HD6:LD6:W00,00,22,18:HD6:LD6:W17,0a,3d,20:HD6:LD6:' >>> plo2.device_initialize(1000.0) 'W00,00,20,00:HD2:LD2:LB5:W00,00,02,08:HD2:LD2:W00,00,04,10:HD2:LD2:W00,01,88,28:HD2:LD2:W00,16,28,28:HD2:LD2:W00,60,A0,28:HD2:LD2:W00,01,10,28:HD2:LD2:W00,08,98,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,07,CA,30:HD2:LD2:W19,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,20,18:HD2:LD2:W00,00,00,20:HD2:LD2:' >>> plo2.device_initialize(2791.0) 'W00,00,20,00:HD2:LD2:LB5:W00,00,02,08:HD2:LD2:W00,00,04,10:HD2:LD2:W00,01,88,28:HD2:LD2:W00,16,28,28:HD2:LD2:W00,60,A0,28:HD2:LD2:W00,00,90,28:HD2:LD2:W00,08,98,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,0F,4A,30:HD2:LD2:W59,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,2c,18:HD2:LD2:Wa7,ef,9e,20:HD2:LD2:' """ self.__divide_ratio = None self.__doubler = None self.__nint = None self.__nfrac = None n_int, n_frac, doubler, divide_ratio = self.divider_values(fout) cmd = self.chip_reset() cmd += self.config_refsrc() cmd += self.config_spi_chipen() cmd += self.config_reference_divider() cmd += self.init_vco_registers() cmd += self.config_vco_registers(divide_ratio, doubler) cmd += self.init_registers(n_int, n_frac, divide_ratio, doubler) cmd += self.config_frequency_registers(n_int, n_frac) return cmd
[docs] def config_device_state(self) -> None: """Configure the device state. Set ``Reg_01h[0]`` (``rst_chipen_pin_select``) to 0 in order to control PLL enable via SPI. PLL enable is then controlled using ``Reg_01h[1]`` (``rst_chipen_from_spi``) subject to masking using the bits in ``Reg_01h[2:7]``. If ``AutoRFO`` mode is enabled (via ``VCO_Reg_03h[2]`` = 0) as recommended in the HMC833 datasheet, then the VCO subsystem is powered up/down by setting ``VCO_Reg_01h[0]`` (Master enable VCO subsystem) to 0b1 and 0b0 respectively. If ``AutoRFO`` mode is disabled (via ``VCO_Reg_03h`` = 1) then the VCO subsystem is powered down by setting ``VCO_Reg_01h[0]`` = 0 and setting ``VCO_Reg_01h[0]`` = 1 will power up the various VCO subsystem components subject to the setting of the associated bit in ``VCO_Reg_01h``. In short, it's best to go with the recommended ``AutoRFO`` enabled setting in ``VCO_Reg_03h`` .. note:: Not currently implemented. """ pass
[docs] def config_analog_enables(self): """Configure the 'analog enables register' (Reg_08h). :return: The command string required to set PLO Reg_08h. """ # - Configure analog enables via Reg_08h # # 1100_0001_1011_1110_1111_1111_0100_0000 # | || || |||| \____/ # | || || |||| Reg_08h # | || || |||bias ref. enable # | || || ||charge pump enable # | || || |phase det. enable # | || || ref. buffer enable # | || |VCO buffer enable # | || GPO enable # | |prescaler clk enable # | VCO buf. and prescaler bias enable # high freq. ref. 1 = >=200MHz, 0 = <200MHz # # Note: setting Reg_08h[21] to 1 appears to cause the # PLO to have lock problems. # In any case, for reference input powers of # about -5dBm leaving Reg_08h[21] set to 0 does # not cause any issues even with ref. freqs >350MHz. cmd = 'WC1,BE,FF,40:H{}:L{}:'.format(self.sen, self.sen) return cmd
[docs] def config_autocal(self): """Configure the 'autocal register' (Reg_0Ah). :return: The command string required to set PLO Reg_0Ah. """ # - Configure VCO autocal via Reg_0Ah # # 0000_0000_0010_0000_0100_0110_0101_0000 # \/ \/ \/\__/\_/ \____/ # | | | | | Reg_0Ah # | | | | vtune resolution (128) # | | | vco curve adjust: disabled # | | wait state setup # | number of SAR bits in VCO # FM/VSPI clk select, max. 50MHz (input ref/4) # Note that if fref is over 200 MHz then Reg_0Ah[14:13] # (FM/VSPI clk select) needs to be set to an appropriate # value (see Section 2.12 of the HMC833 datasheet). if self.fref > 200.0: cmd = 'W00,40,46,50:H{}:L{}:'.format(self.sen, self.sen) else: cmd = 'W00,20,46,50:H{}:L{}:'.format(self.sen, self.sen) return cmd
[docs] def config_frequency(self, fout: float, full_reg_update: bool = False) -> str: """Configure for a specified output frequency When configuring the PLO registers for a specified frequency we try to minimize the number of register updates in order to reduce the time taken to effect the changes. This optimization process produces incorrect results in some circumstances, for example when the PLO reference divider is changed. In cases such as this the ~full_reg_update~ should be set to ~True~ in order to update all relevant PLO registers when configuring the output frequency. :param fout: The required output frequency in MHz. :type fout: float :param reset_state: Force an update of the relevant device registers. :type reset_state: bool :return: The command string required to effect the specified frequency output. >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo2.device_initialize(1000.0) 'W00,00,20,00:HD2:LD2:LB5:W00,00,02,08:HD2:LD2:W00,00,04,10:HD2:LD2:W00,01,88,28:HD2:LD2:W00,16,28,28:HD2:LD2:W00,60,A0,28:HD2:LD2:W00,01,10,28:HD2:LD2:W00,08,98,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,07,CA,30:HD2:LD2:W19,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,20,18:HD2:LD2:W00,00,00,20:HD2:LD2:' >>> plo2.config_frequency(512.0) 'W00,02,10,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,0F,4A,30:HD2:LD2:W59,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,20,18:HD2:LD2:Wc4,9b,a6,20:HD2:LD2:' >>> plo2.config_frequency(764.0) 'W00,01,10,28:HD2:LD2:W00,00,00,28:HD2:LD2:W00,00,18,18:HD2:LD2:W72,b0,21,20:HD2:LD2:' >>> plo2.config_frequency(500.0) 'W00,03,10,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,07,CA,30:HD2:LD2:W19,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,30,18:HD2:LD2:W00,00,00,20:HD2:LD2:' >>> plo2.config_frequency(1000.0) 'W00,01,10,28:HD2:LD2:W00,00,00,28:HD2:LD2:W00,00,20,18:HD2:LD2:' """ if full_reg_update: self.__doubler = self.__divide_ratio = None self.__nint = self.__nfrac = None n_int, n_frac, doubler, divide_ratio = self.divider_values(fout) cmd = '' cmd += self.config_vco_registers(divide_ratio, doubler) if full_reg_update: cmd += self.init_registers(n_int, n_frac, divide_ratio, doubler) elif (n_frac == 0 and self.__nfrac != 0) or \ (self.__nfrac == 0 and n_frac != 0): # Then the SD fractional modulator state needs to change. cmd += self.init_registers(n_int, n_frac, divide_ratio, doubler) cmd += self.config_frequency_registers(n_int, n_frac) return cmd
[docs] def config_gain(self) -> str: """Configure current ``buf_gain`` and ``div_gain`` settings. :return: A command string to configure the device gain settings. .. seealso:: :py:meth:`config_vco_registers` >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.device_initialize(1000.0) 'W00,00,20,00:HD1:LD1:W00,00,02,08:HD1:LD1:W00,00,01,10:HD1:LD1:W00,01,88,28:HD1:LD1:W00,16,28,28:HD1:LD1:W00,60,A0,28:HD1:LD1:W00,01,10,28:HD1:LD1:W00,08,98,28:HD1:LD1:W00,00,00,28:HD1:LD1:W03,07,CA,30:HD1:LD1:W15,B2,64,48:HD1:LD1:W00,21,4d,38:HD1:LD1:WC1,BE,FF,40:HD1:LD1:W00,20,46,50:HD1:LD1:W07,C0,61,58:HD1:LD1:W00,00,C1,78:HD1:LD1:W00,00,28,18:HD1:LD1:W00,00,00,20:HD1:LD1:' >>> plo2.device_initialize(1000.0) 'W00,00,20,00:HD2:LD2:LB5:W00,00,02,08:HD2:LD2:W00,00,04,10:HD2:LD2:W00,01,88,28:HD2:LD2:W00,16,28,28:HD2:LD2:W00,60,A0,28:HD2:LD2:W00,01,10,28:HD2:LD2:W00,08,98,28:HD2:LD2:W00,00,00,28:HD2:LD2:W03,07,CA,30:HD2:LD2:W19,32,64,48:HD2:LD2:W00,21,4d,38:HD2:LD2:WC1,BE,FF,40:HD2:LD2:W00,40,46,50:HD2:LD2:W07,C0,61,58:HD2:LD2:W00,00,C1,78:HD2:LD2:W00,00,20,18:HD2:LD2:W00,00,00,20:HD2:LD2:' >>> plo1.auto_gain(1000.0) >>> plo2.auto_gain(1000.0) >>> plo1.config_gain() 'W00,81,10,28:HD1:LD1:' >>> plo2.config_gain() 'W00,81,10,28:HD2:LD2:' >>> plo2.auto_gain(3817.0) >>> plo2.config_gain() 'W00,41,10,28:HD2:LD2:' >>> plo2.buf_gain = hmc833.OutputBufferGain.MAXGAIN >>> plo2.config_gain() 'W00,61,10,28:HD2:LD2:' >>> plo2.buf_gain = hmc833.OutputBufferGain.MAXGAIN_MINUS_3DB >>> plo2.config_gain() 'W00,41,10,28:HD2:LD2:' """ # It's easiest just to invoke config_vco_divider. # This will also (re)set VCO_Reg_03h. cmd = self.config_vco_divider(self.__divide_ratio) return cmd
[docs] def config_vco_mute(self) -> str: """Enable or disable VCO output while maintaining PLL/VCO lock. The mute function provides over 40 dB of isolation throughout the operating range of the HMC833LP6GE. :return: The command string to effect the currently set mute state. >>> plo1 = hmc833('d1', 'c5') >>> plo2 = hmc833('d2', 'c6', 'b5', fref=250.0, refdiv=4, ... refsrc=hmc833.ReferenceSource.EXTERNAL) >>> plo1.device_initialize(1000.0) 'W00,00,20,00:HD1:LD1:W00,00,02,08:HD1:LD1:W00,00,01,10:HD1:LD1:W00,01,88,28:HD1:LD1:W00,16,28,28:HD1:LD1:W00,60,A0,28:HD1:LD1:W00,01,10,28:HD1:LD1:W00,08,98,28:HD1:LD1:W00,00,00,28:HD1:LD1:W03,07,CA,30:HD1:LD1:W15,B2,64,48:HD1:LD1:W00,21,4d,38:HD1:LD1:WC1,BE,FF,40:HD1:LD1:W00,20,46,50:HD1:LD1:W07,C0,61,58:HD1:LD1:W00,00,C1,78:HD1:LD1:W00,00,28,18:HD1:LD1:W00,00,00,20:HD1:LD1:' >>> plo1.config_vco_mute() 'W00,01,88,28:HD1:LD1:W00,08,98,28:HD1:LD1:' """ # VCO_Reg_01h # # 8 7 6 5 4 3 2 1 0 # | | # | Master Enable VCO Subsystem # Manual Mode PLL buffer enable vco_reg_01h = 0b0000_0011 reg_05h = '{:06X}'.format((((vco_reg_01h << 7) | 0b0001_000) << 8) | 0b0101_000) cmd = 'W00,{},{},{}:H{}:L{}:'.format(reg_05h[0:2], reg_05h[2:4], reg_05h[4:6], self.sen, self.sen) cmd += self.config_vco_doubler(self.__doubler) return cmd
def close_vco_config(self): return 'W00,00,00,28:H{}:L{}:'.format(self.sen, self.sen)
[docs] def check_is_locked(self) -> str: """Check if the device PLL is locked. :return: The command string for checking the device PLL lock status. """ return 'P{}:'.format(self.ld_sdo)
if __name__ == '__main__': import doctest doctest.testmod()