# HG changeset patch # Parent 4fa55f1cd74ede8ca83e5c099bec2dcf442e7042 Control the si570 frequency directly via registers diff -r 4fa55f1cd74e quisk_conf_defaults.py --- a/quisk_conf_defaults.py Wed Feb 16 17:11:15 2011 -0500 +++ b/quisk_conf_defaults.py Wed Feb 16 17:14:54 2011 -0500 @@ -196,6 +196,15 @@ # name_of_sound_play = "hw:0" # Play back on this soundcard # playback_rate = 48000 # Radio sound play rate, default 48000 +# If you are using a DG8SAQ interface to set a Si570 clock directly, set +# this to True. Complex controllers which have their own internal +# crystal calibration do not require this. +si570_direct_control = False +# This is the Si570 startup frequency in Hz. 114.285MHz is the typical +# value from the data sheet; you can use 'usbsoftrock calibrate' to find +# the value for your device. +si570_xtal_freq = 114285000 + # This is the received radio sound playback rate. The default will # be 48 kHz for the SDR-IQ and UDP port samples, and sample_rate for sound # card capture. Set it yourself for other rates or hardware. diff -r 4fa55f1cd74e softrock/hardware_usb.py --- a/softrock/hardware_usb.py Wed Feb 16 17:11:15 2011 -0500 +++ b/softrock/hardware_usb.py Wed Feb 16 17:14:54 2011 -0500 @@ -1,7 +1,7 @@ # Please do not change this hardware control module for Quisk. # It provides USB control of SoftRock hardware. -import struct, threading, time, traceback +import struct, threading, time, traceback, math from quisk_hardware_model import Hardware as BaseHardware import _quisk as QS @@ -16,6 +16,16 @@ # I2C-address of the SI570; Thanks to Joachim Schneider, DB6QS si570_i2c_address = 0x55 +# Thanks to Ethan Blanton, KB8OJH, for this patch for the Si570 (many SoftRocks): +# These are used by SetFreqByDirect(); see below. +# The Si570 DCO must be clamped between these values +SI570_MIN_DCO = 4.85e9 +SI570_MAX_DCO = 5.67e9 +# The Si570 has 6 valid HSDIV values. Subtract 4 from HSDIV before +# stuffing it. We want to find the highest HSDIV first, so start +# from 11. +SI570_HSDIV_VALUES = [11, 9, 7, 6, 5, 4] + IN = usb.util.build_request_type(usb.util.CTRL_IN, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) OUT = usb.util.build_request_type(usb.util.CTRL_OUT, usb.util.CTRL_TYPE_VENDOR, usb.util.CTRL_RECIPIENT_DEVICE) @@ -69,8 +79,11 @@ self.key_thread = None def ChangeFrequency(self, tune, vfo, source='', band='', event=None): if self.usb_dev and self.vfo != vfo: - if self.SetFreqByValue(vfo): - self.vfo = vfo + if self.conf.si570_direct_control: + if self.SetFreqByDirect(vfo): + self.vfo = vfo + elif self.SetFreqByValue(vfo): + self.vfo = vfo if DEBUG: print 'Change to', vfo print 'Run freq', self.GetFreq() @@ -123,6 +136,52 @@ if DEBUG: traceback.print_exc() else: return True + def SetFreqByDirect(self, freq): # Thanks to Ethan Blanton, KB8OJH + # For now, find the minimum DCO speed that will give us the + # desired frequency; if we're slewing in the future, we want this + # to additionally yield an RFREQ ~= 512. + freq = int(freq * 4) + if freq == 0: + return False + dco_new = None + hsdiv_new = 0 + n1_new = 0 + for hsdiv in SI570_HSDIV_VALUES: + n1 = int(math.ceil(SI570_MIN_DCO / (freq * hsdiv))) + if n1 < 1: + n1 = 1 + else: + n1 = ((n1 + 1) / 2) * 2 + dco = (freq * 1.0) * hsdiv * n1 + # Since we're starting with max hsdiv, this can only happen if + # freq was larger than we can handle + if n1 > 128: + continue + if dco < SI570_MIN_DCO or dco > SI570_MAX_DCO: + # This really shouldn't happen + continue + if not dco_new or dco < dco_new: + dco_new = dco + hsdiv_new = hsdiv + n1_new = n1 + if not dco_new: + # For some reason, we were unable to calculate a frequency. + # Probably because the frequency requested is outside the range + # of our device. + return False # Failure + rfreq = dco_new / self.conf.si570_xtal_freq + rfreq_int = int(rfreq) + rfreq_frac = int(round((rfreq - rfreq_int) * 2**28)) + # It looks like the DG8SAQ protocol just passes r7-r12 straight + # To the Si570 when given command 0x30. Easy enough. + # n1 is stuffed as n1 - 1, hsdiv is stuffed as hsdiv - 4. + hsdiv_new = hsdiv_new - 4 + n1_new = n1_new - 1 + s = struct.Struct('>BBL').pack((hsdiv_new << 5) + (n1_new >> 2), + ((n1_new & 0x3) << 6) + (rfreq_int >> 4), + ((rfreq_int & 0xf) << 28) + rfreq_frac) + self.usb_dev.ctrl_transfer(OUT, 0x30, si570_i2c_address + 0x700, 0, s) + return True # Success class KeyThread(threading.Thread): """Create a thread to monitor the key state."""