Clean up for work-in-progress
[debian/gnuradio] / usrp / host / lib / db_wbxng_adf4350.cc
1 //
2 // Copyright 2009 Free Software Foundation, Inc.
3 //
4 // This file is part of GNU Radio
5 //
6 // GNU Radio is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either asversion 3, or (at your option)
9 // any later version.
10 //
11 // GNU Radio is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with GNU Radio; see the file COPYING.  If not, write to
18 // the Free Software Foundation, Inc., 51 Franklin Street,
19 // Boston, MA 02110-1301, USA.
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include "db_wbxng_adf4350.h"
26 #include <db_base_impl.h>
27 #include <stdio.h>
28
29 #define INPUT_REF_FREQ FREQ_C(64e6)
30 #define DIV_ROUND(num, denom) (((num) + ((denom)/2))/(denom))
31 #define FREQ_C(freq) uint64_t(freq)
32 #define INPUT_REF_FREQ_2X (2*INPUT_REF_FREQ)                            /* input ref freq with doubler turned on */
33 #define MIN_INT_DIV uint16_t(23)                                        /* minimum int divider, prescaler 4/5 only */
34 #define MAX_RF_DIV uint8_t(16)                                          /* max rf divider, divides rf output */
35 #define MIN_VCO_FREQ FREQ_C(2.2e9)                                      /* minimum vco freq */
36 #define MAX_VCO_FREQ FREQ_C(4.4e9)                                      /* minimum vco freq */
37 #define MAX_FREQ MAX_VCO_FREQ                                           /* upper bound freq (rf div = 1) */
38 #define MIN_FREQ DIV_ROUND(MIN_VCO_FREQ, MAX_RF_DIV)                    /* calculated lower bound freq */
39
40 #define CE_PIN        (1 << 3)
41 #define PDB_RF_PIN    (1 << 2)
42 #define MUX_PIN       (1 << 1)
43 #define LD_PIN        (1 << 0)
44
45 adf4350::adf4350(usrp_basic_sptr _usrp, int _which, int _spi_enable)
46 {
47     /* Initialize the pin directions. */
48
49     d_usrp = _usrp;
50     d_which = _which;
51     d_spi_enable = _spi_enable;
52     d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
53
54     d_regs = new adf4350_regs(this);
55
56     /* Outputs */
57     d_usrp->_write_oe(d_which, (CE_PIN | PDB_RF_PIN), (CE_PIN | PDB_RF_PIN));
58     d_usrp->write_io(d_which, (0), (CE_PIN | PDB_RF_PIN));
59
60     /* Initialize the pin levels. */
61     _enable(true);
62     /* Initialize the registers. */
63     d_regs->_load_register(5);
64     d_regs->_load_register(4);
65     d_regs->_load_register(3);
66     d_regs->_load_register(2);
67     d_regs->_load_register(1);
68     d_regs->_load_register(0);
69 }
70
71 adf4350::~adf4350()
72 {
73     delete d_regs;
74 }
75
76 freq_t
77 adf4350::_get_max_freq(void)
78 {
79     return MAX_FREQ;
80 }
81
82 freq_t
83 adf4350::_get_min_freq(void)
84 {
85     return MIN_FREQ;
86 }
87
88 bool
89 adf4350::_get_locked(void)
90 {
91     return d_usrp->read_io(d_which) & LD_PIN;
92 }
93
94 void
95 adf4350::_enable(bool enable)
96 {
97     if (enable){ /* chip enable */
98         d_usrp->write_io(d_which, (CE_PIN | PDB_RF_PIN), (CE_PIN | PDB_RF_PIN));
99     }else{
100         d_usrp->write_io(d_which, 0, (CE_PIN | PDB_RF_PIN));
101     }
102 }
103
104 void
105 adf4350::_write(uint8_t addr, uint32_t data)
106 {
107     data |= addr;
108
109     // create str from data here
110     char s[4];
111     s[0] = (char)((data >> 24) & 0xff);
112     s[1] = (char)((data >> 16) & 0xff);
113     s[2] = (char)((data >>  8) & 0xff);
114     s[3] = (char)(data & 0xff);
115     std::string str(s, 4);
116
117     timespec t;
118     t.tv_sec = 0;
119     t.tv_nsec = 5e6;
120
121     nanosleep(&t, NULL);
122     d_usrp->_write_spi(0, d_spi_enable, d_spi_format, str);
123     nanosleep(&t, NULL);
124
125     //fprintf(stderr, "Wrote to WBXNG SPI address %d with data %8x\n", addr, data);
126     /* pulse latch */
127     //d_usrp->write_io(d_which, 1, LE_PIN);
128     //d_usrp->write_io(d_which, 0, LE_PIN);
129 }
130
131 bool
132 adf4350::_set_freq(freq_t freq)
133 {
134     /* Set the frequency by setting int, frac, mod, r, div */
135     if (freq > MAX_FREQ || freq < MIN_FREQ) return false;
136     /* Ramp up the RF divider until the VCO is within range. */
137     d_regs->d_divider_select = 0;
138     while (freq < MIN_VCO_FREQ){
139         freq <<= 1; //double the freq
140         d_regs->d_divider_select++; //double the divider
141     }
142     /* Ramp up the R divider until the N divider is at least the minimum. */
143     //d_regs->d_10_bit_r_counter = INPUT_REF_FREQ*MIN_INT_DIV/freq;
144     d_regs->d_10_bit_r_counter = 2;
145     uint64_t n_mod;
146     do{
147         d_regs->d_10_bit_r_counter++;
148         n_mod = freq;
149         n_mod *= d_regs->d_10_bit_r_counter;
150         n_mod *= d_regs->d_mod;
151         n_mod /= INPUT_REF_FREQ;
152         /* calculate int and frac */
153         d_regs->d_int = n_mod/d_regs->d_mod;
154         d_regs->d_frac = (n_mod - (freq_t)d_regs->d_int*d_regs->d_mod) & uint16_t(0xfff);
155         /*
156         fprintf(stderr,
157             "VCO %lu KHz, Int %u, Frac %u, Mod %u, R %u, Div %u\n",
158             freq, d_regs->d_int, d_regs->d_frac,
159             d_regs->d_mod, d_regs->d_10_bit_r_counter, (1 << d_regs->d_divider_select)
160         );
161         */
162     }while(d_regs->d_int < MIN_INT_DIV);
163     /* calculate the band select so PFD is under 125 KHz */
164     d_regs->d_8_bit_band_select_clock_divider_value = \
165         INPUT_REF_FREQ/(FREQ_C(30e3)*d_regs->d_10_bit_r_counter) + 1;
166     /*
167     fprintf(stderr, "Band Selection: Div %u, Freq %lu\n",
168         d_regs->d_8_bit_band_select_clock_divider_value,
169         INPUT_REF_FREQ/(d_regs->d_8_bit_band_select_clock_divider_value * d_regs->d_10_bit_r_counter) + 1
170     );
171     */
172     d_regs->_load_register(5);
173     d_regs->_load_register(3);
174     d_regs->_load_register(1);
175     /* load involved registers */
176     d_regs->_load_register(2);
177     d_regs->_load_register(4);
178     d_regs->_load_register(0); /* register 0 must be last */
179     return true;
180 }
181
182 freq_t
183 adf4350::_get_freq(void)
184 {
185     /* Calculate the freq from int, frac, mod, ref, r, div:
186      *  freq = (int + frac/mod) * (ref/r)
187      * Keep precision by doing multiplies first:
188      *  freq = (((((((int)*mod) + frac)*ref)/mod)/r)/div)
189      */
190     uint64_t temp;
191     temp = d_regs->d_int;
192     temp *= d_regs->d_mod;
193     temp += d_regs->d_frac;
194     temp *= INPUT_REF_FREQ;
195     temp /= d_regs->d_mod;
196     temp /= d_regs->d_10_bit_r_counter;
197     temp /= (1 << d_regs->d_divider_select);
198     return temp;
199 }