2 // Copyright 2010 Free Software Foundation, Inc.
4 // This file is part of GNU Radio
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)
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.
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.
25 #include <usrp/db_bitshark_rx.h>
26 #include <db_base_impl.h>
32 /* Note: Thie general structure of this file is based on the db_dbsrx.cc
33 codebase for the dbsrx daughterboard. */
35 /* The following defines specify the address map provided by the
36 Bitshark card. These registers are all accessed over I2C. */
37 #define RF_CENTER_FREQ_REG 0x00
38 #define RF_CHAN_FILTER_BW_REG 0x01
39 #define RF_GAIN_REG 0x02
40 #define BB_GAIN_REG 0x03
41 #define ADF4350_REG 0x10
42 #define SKY73202_REG 0x11
43 #define CLOCK_SCHEME_REG 0x20
45 /* The following table lists the registers provided by the BURX board that
46 are accessible over I2C:
47 --------------------------------------------------------
48 |RegAddr: 0x00-RF Center Freq register |
50 |4-byte unsigned RF center freq (in KHz)|
51 |RegAddr: 0x01-RF channel filter bandwidth register |
53 |4-byte unsigned RF channel filter bw (in KHz)|
54 |RegAddr: 0x02-RF gain register |
56 |1-byte signed RF gain (in dB)|
57 |RegAddr: 0x03-Baseband gain register |
59 |4-byte signed baseband filter gain (in dB)|
60 |RegAddr: 0x10-ADF4350 register |
62 |4-byte ADF4350 register value (actual ADF4350 reg addr embedded
64 |RegAddr: 0x11-SKY73202 register |
66 |1-byte reg 0 of SKY73202 |
67 |1-byte reg 1 of SKY73202 |
68 |1-byte reg 2 of SKY73202 |
69 |RegAddr: 0x20-Clock Scheme |
71 |1-byte indicating clocking scheme:
72 -0x00 -> BURX local TCXO off, BURX accepts ref clock from
73 USRP (freq of USRP's ref clock specified in bytes 2-5)
74 -0x01 -> BURX local TCXO on, BURX uses its local TCXO as its ref
75 clock, TCXO signal output for use by USRP |
76 |4-byte USRP ref clock freq in hz (only needed if byte 1 set to 0x00) |
78 ---------------------------------------------------------------------------
80 As an example, lets say the client wants to set an RF center freq of
81 1000 MHz. In KHz, this translates to 1000000 (resolution is only down to
82 steps of 1 KHz), which is 0x000F4240 in hex. So the complete 9-byte I2C
83 sequence that the client should send is as follows:
84 byte 0: 0x00-register 0x00 is the target of the write operation
85 bytes 1-4: 0x00 (padding)
86 byte 5: 0x40 (LSB of the 1000000 KHz value, in hex)
89 byte 8: 0x00 (MSB of the 1000000 KHz value, in hex)
91 If using the usrper cmd-line application on a PC, this sequence would
92 be sent as follows (assuming that the BURX is in slot A):
94 # usrper i2c_write 0x47 000000000040420F00
96 How about another example...lets say the client wants to setup the clock
97 scheme to use scheme #1 where the 26 MHz TCXO on the BURX board is enabled,
98 and is provided to the USRP. 26 MHz (i.e. 26 million), in hex, is 0x18CBA80.
99 So the complete 9-byte I2C sequence that the client should send is as follows:
100 byte 0: 0x20-register 0x20 is the target of the write operation
101 bytes 1-3: 0x00 (padding)
102 byte 4: 0x01 (indicating that clock scheme #1 is wanted)
103 byte 5: 0x80 (LSB of the BURX ref clk freq)
106 byte 8: 0x01 (MSB of the BURX ref clk freq)
108 To enable the BURX local ref clk, which will also make it available on the
109 on-board U.FL connector as a source for the USRP, a user can also use
110 the usrper cmd-line application on a PC. The following sequence would
111 be sent (assuming that the BURX is in slot A):
113 # usrper i2c_write 0x47 200000000180BA8C01
117 #define NUM_BYTES_IN_I2C_CMD 9
119 /*****************************************************************************/
121 db_bitshark_rx::db_bitshark_rx(usrp_basic_sptr _usrp, int which)
122 : db_base(_usrp, which)
124 // Control Bitshark receiver USRP daughterboard.
126 // @param usrp: instance of usrp.source_c
127 // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively
129 // turn off all outputs
130 usrp()->_write_oe(d_which, 0, 0xffff);
142 set_gain((gain_min() + gain_max()) / 2.0);
144 // by default, assume we're using the USRPs clock as the ref clk,
145 // so setup the clock scheme and frequency. If the user wants
146 // to use the Bitshark's TCXO, the clock scheme should be set
147 // to 1, the freq should be set to 26000000, and a top-level
148 // 'make' and 'make install' needs to be executed. In addition,
149 // a U.FL to SMA cable needs to connect J6 on the Bitshark to
150 // the external clk input on the USRP
151 set_clock_scheme(0,64000000);
153 bypass_adc_buffers(true);
156 db_bitshark_rx::~db_bitshark_rx()
161 /************ Private Functions **********************/
164 db_bitshark_rx::_set_pga(int pga_gain)
166 assert(pga_gain>=0 && pga_gain<=20);
169 usrp()->set_pga (0, pga_gain);
170 usrp()->set_pga (1, pga_gain);
174 usrp()->set_pga (2, pga_gain);
175 usrp()->set_pga (3, pga_gain);
179 /************ Public Functions **********************/
181 db_bitshark_rx::shutdown()
185 d_is_shutdown = true;
190 db_bitshark_rx::set_bw (float bw)
192 std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
193 uint16_t rf_bw_in_khz = (uint16_t)(bw/1000.0);
196 uint8_t try_count = 0;
199 if (rf_bw_in_khz < 660 || rf_bw_in_khz > 56000)
201 fprintf(stderr, "db_bitshark_rx::set_bw: bw (=%d) must be between 660 KHz and 56 MHz inclusive\n", rf_bw_in_khz);
204 //fprintf(stdout,"Setting bw: requested bw in khz is %d\r\n",rf_bw_in_khz);
205 memcpy(val,&rf_bw_in_khz,4);
206 args[0] = RF_CHAN_FILTER_BW_REG;
211 while ((result != true) && (try_count < 3))
213 result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
219 fprintf(stderr, "db_bitshark_rx:set_bw: giving up after 3 tries without success\n");
225 /* The gain referenced below is RF gain only. There are two independent
226 gain settings at RF: a digital step attenuator (providing 0, -6, -12, and
227 -18 dB of attenuation), and a second LNA (LNA2) that provides ~25 dB of
228 gain (roughly...it actually depends on the RF freq). So combining these
229 two stages can provide an overall gain range from 0 (which is mapped
230 to -18 dB on the step attenuator + LNA2 turned off) to 42 (which is
231 mapped to 0 dB on the step attenuator + LNA2 turned on).
233 There could be better ways to map these, but this is sufficient for
236 db_bitshark_rx::gain_min()
242 db_bitshark_rx::gain_max()
248 db_bitshark_rx::gain_db_per_step()
254 db_bitshark_rx::set_gain(float gain)
258 // @param gain: RF gain in decibels, range of 0-42
259 // @returns True/False
261 std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
262 uint8_t final_gain = (uint8_t)gain;
264 uint8_t try_count = 0;
266 if (gain < gain_min() || gain > gain_max())
268 fprintf(stderr,"db_bitshark_rx::set_gain: gain (=%f) must be between %f and %f inclusive\n", gain,gain_min(),gain_max());
271 //fprintf(stdout,"db_bitshark_rx::set_gain: requested gain of %f\r\n",gain);
272 args[0] = RF_GAIN_REG;
275 while ((result != true) && (try_count < 3))
277 result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
283 fprintf(stderr, "db_bitshark_rx:set_gain: giving up after 3 tries without success\n");
291 db_bitshark_rx::set_clock_scheme(uint8_t clock_scheme, uint32_t ref_clk_freq)
293 // Set the clock scheme for determining how the BURX
294 // dboard receives its clock. Note: Ideally, the constructor for the
295 // BURX board could simply call this method to set how it wants the
296 // clock scheme configured. However, depending on the application
297 // using the daughterboard, the constructor may run _after_ some
298 // other portion of the application needs the FPGA. And if the
299 // the clock source for the FPGA was the BURX's 26 MHz TCXO, we're in
300 // a chicken-before-the-egg dilemna. So the solution is to leave
301 // this function here for reference in case an app wants to use it,
302 // and also give the user the ability to set the clock scheme through
303 // the usrper cmd-line application (see example at the top of this
306 // @param clock_scheme
307 // @param ref_clk_freq in Hz
308 // @returns True/False
310 std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
312 uint8_t try_count = 0;
315 if (clock_scheme > 1)
317 fprintf(stderr,"db_bitshark_rx::set_clock_scheme: invalid scheme %d\n",clock_scheme);
320 //fprintf(stdout,"db_bitshark_rx::set_clock_scheme: requested clock schem of %d with freq %d Hz \n",clock_scheme,ref_clk_freq);
321 memcpy(val,&ref_clk_freq,4);
322 args[0] = CLOCK_SCHEME_REG;
323 args[4] = (int)clock_scheme;
329 while ((result != true) && (try_count < 3))
331 result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
337 fprintf(stderr, "db_bitshark_rx:set_clock_scheme: giving up after 3 tries without success\n");
343 db_bitshark_rx::freq_min()
349 db_bitshark_rx::freq_max()
355 db_bitshark_rx::set_freq(double freq)
357 // Set the frequency.
359 // @param freq: target RF frequency in Hz
360 // @type freq: double
362 // @returns (ok, actual_baseband_freq) where:
363 // ok is True or False and indicates success or failure,
364 // actual_baseband_freq is RF frequency that corresponds to DC in the IF.
366 std::vector<int> args(NUM_BYTES_IN_I2C_CMD,0);
367 std::vector<int> bytes(2);
369 freq_result_t act_freq = {false, 0};
370 uint32_t freq_in_khz = (uint32_t)(freq/1000.0);
372 uint8_t try_count = 0;
375 if(!(freq>=freq_min() && freq<=freq_max()))
380 //fprintf(stdout,"db_bitshark_rx::set_freq: requested freq is %d KHz\n",freq_in_khz);
381 memcpy(val,&freq_in_khz,4);
382 args[0] = RF_CENTER_FREQ_REG;
388 while ((result != true) && (try_count < 3))
390 result=usrp()->write_i2c (d_i2c_addr, int_seq_to_str (args));
396 fprintf(stderr, "db_bitshark_rx:set_freq: giving up after 3 tries without success\n");
399 act_freq.ok = result;
400 act_freq.baseband_freq = (double)freq;
405 db_bitshark_rx::is_quadrature()
407 // Return True if this board requires both I & Q analog channels.
412 db_bitshark_rx::i_and_q_swapped()
414 // Returns True since our I and Q channels are swapped