3 # Copyright 2004 Free Software Foundation, Inc.
5 # This file is part of GNU Radio
7 # GNU Radio is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3, or (at your option)
12 # GNU Radio is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Radio; see the file COPYING. If not, write to
19 # the Free Software Foundation, Inc., 51 Franklin Street,
20 # Boston, MA 02110-1301, USA.
23 '''Control National LMX2306 based frequency synthesizer'''
25 from gnuradio import gr
26 from gnuradio import eng_notation
27 from gnuradio.eng_option import eng_option
28 from optparse import OptionParser
30 # bottom two bits of 21 bit word select which register to program
36 F_counter_reset = (1 << 2)
37 F_phase_detector_polarity = (1 << 7)
39 F_LD_tri_state = (0 << 4)
40 F_LD_R_divider_output = (4 << 4)
41 F_LD_N_divider_output = (2 << 4)
42 F_LD_serial_data_output = (6 << 4)
43 F_LD_digital_lock_detect = (1 << 4)
44 F_LD_open_drain = (5 << 4)
48 # F_default = F_LD_digital_lock_detect | F_phase_detector_polarity
49 F_default = F_LD_open_drain | F_phase_detector_polarity
54 # LE load enable. When LE goes high, data stored in the shift register
55 # is loaded into one of the three registers
56 # CLK data is clocked in on the rising edge
57 # DATA single data bit. Entered MSB first
64 class lmx2306 (object):
65 '''Control the National LMX2306 PLL'''
66 __slots__ = ['pp', 'shadow', 'fosc', 'r', 'step_size', 'verbose']
67 def __init__ (self, fosc, step_size, which_pp = 0):
68 '''FOSC is the frequency of the reference oscillator,
69 STEP_SIZE is the step between valid frequencies,
70 WHICH_PP specifies which parallel port to use
72 self.pp = gr.make_ppio (which_pp)
75 self.pp.write_data (self.shadow)
79 self._set_step (step_size)
82 def program (self, r, a, b):
84 print "lmx2306: r = %d a = %d b = %d" % (r, a, b)
86 self._write_word (F_REG | F_default | F_counter_reset)
87 self._write_word (R_REG | ((r & 0x3fff) << 2))
88 self._write_word (AB_REG | ((a & 0x1f) << 2) | ((b & 0x1fff) << 7))
89 self._write_word (F_REG | F_default)
92 def set_freq (self, freq):
93 '''Set the PLL frequency to FREQ
95 Return the actual freq value set. It will be rounded down to a
98 divisor = int (freq / self.step_size)
99 actual = divisor * self.step_size
100 (a, b) = self._compute_ab (divisor)
101 self.program (self.r, a, b)
104 # ----------------------------------------------------------------
106 def _set_fosc (self, ref_oscillator_freq):
107 self.fosc = ref_oscillator_freq
109 def _set_step (self, step_size):
110 r = int (self.fosc / step_size)
111 if r * step_size != self.fosc:
112 raise ValueError, "step_size is not a factor of self.fosc"
113 if r < 3 or r > 16383:
114 raise ValueError, "r is out of range"
116 self.step_size = step_size
118 def _compute_ab (self, divisor):
120 a = divisor - (b * 8)
121 if b < 3 or b > 8191 or a > b:
122 raise ValueError, "Invalid divisor"
125 def _write_word (self, w):
131 w = (w << 1) & 0x0ffffff
137 def _set_LE_0 (self):
138 self.shadow = self.shadow & ~DB_LE
139 self.pp.write_data (self.shadow)
141 def _set_LE_1 (self):
142 self.shadow = self.shadow | DB_LE
143 self.pp.write_data (self.shadow)
145 def _set_CLK_0 (self):
146 self.shadow = self.shadow & ~DB_CLK
147 self.pp.write_data (self.shadow)
149 def _set_CLK_1 (self):
150 self.shadow = self.shadow | DB_CLK
151 self.pp.write_data (self.shadow)
153 def _set_DATA_0 (self):
154 self.shadow = self.shadow & ~DB_DATA
155 self.pp.write_data (self.shadow)
157 def _set_DATA_1 (self):
158 self.shadow = self.shadow | DB_DATA
159 self.pp.write_data (self.shadow)
161 if __name__ == '__main__':
162 parser = OptionParser (option_class=eng_option)
163 parser.add_option ("-o", "--fosc", type="eng_float", default=32e6,
164 help="set reference oscillator freq to FREQ", metavar="FREQ")
165 parser.add_option ("-s", "--step-size", type="eng_float", default=10e3,
166 help="set the frequency step size to STEP_SIZE")
167 parser.add_option ("-f", "--freq", type="eng_float", default=430e6,
168 help="set VCO frequency to FREQ")
169 parser.add_option ("-v", "--verbose", action="store_true", default=False)
170 (options, args) = parser.parse_args ()
173 print "fosc = %s step = %s fvco = %s" % (
174 eng_notation.num_to_str (options.fosc),
175 eng_notation.num_to_str (options.step_size),
176 eng_notation.num_to_str (options.freq))
178 lmx = lmx2306 (options.fosc, options.step_size)
179 lmx.verbose = options.verbose
181 actual = lmx.set_freq (options.freq)
184 print "fvco_actual = %s delta = %s" % (
185 eng_notation.num_to_str (actual),
186 eng_notation.num_to_str (options.freq - actual))