"""
Set the LO on the radar frontend board to the correct frequency. The LO is
controlled via SPI.
"""
import os
import struct
import time
[docs]class HMC807(object):
REG_ID = 0x0
REG_RST = 0x1
REG_REFDIV = 0x2
REG_FREQ_INT = 0x3
REG_FREQ_FRAC = 0x4
REG_SEED = 0x5
REG_SD_CFG = 0x6
REG_LKD_CSP = 0x7 # lock detect / cycle slip prevention
REG_ANALOG_EN = 0x8
REG_CP = 0x9 # charge pump
REG_CP_OPAMP = 0xA # Charge Pump Internal Op-Amp bias
REG_PFD = 0xB # phase frequency detector
REG_VCO = 0xC # Voltage controlled oscillator
REG_GPO = 0xD # General purpose output register (multiplexer select)
REG_LD_STATE = 0xF # Lock detect state
def __init__(self, bus, device):
import spidev
self._frequency_mult = None
self.spi = spidev.SpiDev(bus, device)
self.spi.mode = 0
@classmethod
def _format_read(cls, reg):
"""Return the bytes that need to be sent to read a register."""
tx = [0] * 4
tx[0] = (0x80 | ((0x3F & reg) << 1)) & 0xFE
return tx
[docs] @classmethod
def from_chardev(cls, path):
"""Instantiate an HMC807 device given a path to SPI device in /dev"""
basename = os.path.basename(path)
bus, dev = basename.split('.')
bus = int(bus[len('spidev'):])
dev = int(dev)
return cls(bus, dev)
@classmethod
def _format_write(cls, reg, val):
"""Return the bytes that need to be sent to write `val` to `reg`"""
tx = [None] * 4
data = [None] * 3
data[0] = val >> 16
data[1] = (val >> 8) & 0xFF
data[2] = val & 0xFF
# the hmc is the worst and has one 7-bit word at the beginning.
# so everything else has to be bitshifted lots.
tx[0] = (0x00 | ((0x3F & reg) << 1)) | ((data[0] >> 7) & 0x01)
tx[1] = ((data[0] << 1) & 0xFE) | ((data[1] >> 7) & 0x01);
tx[2] = ((data[1] << 1) & 0xFE) | ((data[2] >> 7) & 0x01);
tx[3] = ((data[2] << 1) & 0xFE);
return tx
[docs] def read_reg(self, reg):
tx = self._format_read(reg)
rx = self.spi.xfer(tx)
b = bytearray(rx)
value, = struct.unpack('>I', b)
# The first seven bits are not part of the value.
# _Probably_ we should count the first bit as well, but we're not going to.
# This means that the MSB won't get counted, I think.
value = value & 0xFFFFFF
return value
[docs] def write_reg(self, reg, data):
tx = self._format_write(reg, data)
self.spi.writebytes(tx)
def _display_registers(self):
"""Displays the registers in self.default_addr"""
for addr in range(0x10):
val = self.read_reg(addr)
print("HMC Reg 0x%02X: 0x%06X" % (addr, val))
[docs] def init_registers(self):
"""Initialize the registers with values we like."""
self.reset()
self.write_reg(self.REG_RST, 1) # enable external CE
self.write_reg(self.REG_REFDIV, 1) # bypass reference clk divider
self.frequency_mult = 125 # multiply reference clk by 125
self.write_reg(self.REG_FREQ_FRAC, 0) # no fractional part
self.write_reg(self.REG_SEED , 0x50894C)
self.write_reg(self.REG_SD_CFG , 0x703387)
self.write_reg(self.REG_LKD_CSP, 0x04FA) # Disable CSP
self.write_reg(self.REG_ANALOG_EN, 0x31DF)
self.write_reg(self.REG_CP, 0x900000)
self.write_reg(self.REG_PFD, 0x72)
self.write_reg(self.REG_GPO, 0xD)
@property
def id(self):
return '{:x}'.format(self.read_reg(0))
@property
def frequency_mult(self):
"""Get and set the reference frequency multiplier."""
return self._frequency_mult
return self.read_reg(self.REG_FREQ_INT)
@frequency_mult.setter
def frequency_mult(self, value):
self._frequency_mult = value
self.write_reg(self.REG_FREQ_INT, value)
[docs] def reset(self):
"""Reset all registers to default values."""
self.write_reg(0, 1)