Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp1 / mboard_impl.cpp @ b96088b6

History | View | Annotate | Download (13.5 kB)

1
//
2
// Copyright 2010 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include "usrp1_impl.hpp"
19
#include "usrp_commands.h"
20
#include "fpga_regs_standard.h"
21
#include "fpga_regs_common.h"
22
#include <uhd/usrp/misc_utils.hpp>
23
#include <uhd/usrp/mboard_props.hpp>
24
#include <uhd/usrp/dboard_props.hpp>
25
#include <uhd/usrp/subdev_props.hpp>
26
#include <uhd/utils/warning.hpp>
27
#include <uhd/utils/assert.hpp>
28
#include <uhd/utils/images.hpp>
29
#include <boost/assign/list_of.hpp>
30
#include <boost/foreach.hpp>
31
#include <boost/bind.hpp>
32
#include <iostream>
33

    
34
using namespace uhd;
35
using namespace uhd::usrp;
36

    
37
/***********************************************************************
38
 * Calculate the RX mux value:
39
 *    The I and Q mux values are intentionally reversed to flip I and Q
40
 *    to account for the reversal in the type conversion routines.
41
 **********************************************************************/
42
static int calc_rx_mux_pair(int adc_for_i, int adc_for_q){
43
    return (adc_for_i << 2) | (adc_for_q << 0); //shift reversal here
44
}
45

    
46
/*!
47
 *    3                   2                   1                   0
48
 *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
49
 * +-----------------------+-------+-------+-------+-------+-+-----+
50
 * |      must be zero     | Q3| I3| Q2| I2| Q1| I1| Q0| I0|Z| NCH |
51
 * +-----------------------+-------+-------+-------+-------+-+-----+
52
 */
53
static boost::uint32_t calc_rx_mux(
54
    const subdev_spec_t &subdev_spec, wax::obj mboard
55
){
56
    //create look-up-table for mapping dboard name and connection type to ADC flags
57
    static const int ADC0 = 0, ADC1 = 1, ADC2 = 2, ADC3 = 3;
58
    static const uhd::dict<std::string, uhd::dict<subdev_conn_t, int> > name_to_conn_to_flag = boost::assign::map_list_of
59
        ("A", boost::assign::map_list_of
60
            (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC0, ADC1)) //I and Q
61
            (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC1, ADC0)) //I and Q
62
            (SUBDEV_CONN_REAL_I,     calc_rx_mux_pair(ADC0, ADC0)) //I and Q (Q identical but ignored Z=1)
63
            (SUBDEV_CONN_REAL_Q,     calc_rx_mux_pair(ADC1, ADC1)) //I and Q (Q identical but ignored Z=1)
64
        )
65
        ("B", boost::assign::map_list_of
66
            (SUBDEV_CONN_COMPLEX_IQ, calc_rx_mux_pair(ADC2, ADC3)) //I and Q
67
            (SUBDEV_CONN_COMPLEX_QI, calc_rx_mux_pair(ADC3, ADC2)) //I and Q
68
            (SUBDEV_CONN_REAL_I,     calc_rx_mux_pair(ADC2, ADC2)) //I and Q (Q identical but ignored Z=1)
69
            (SUBDEV_CONN_REAL_Q,     calc_rx_mux_pair(ADC3, ADC3)) //I and Q (Q identical but ignored Z=1)
70
        )
71
    ;
72

    
73
    //extract the number of channels
74
    size_t nchan = subdev_spec.size();
75

    
76
    //calculate the channel flags
77
    int channel_flags = 0;
78
    size_t num_reals = 0, num_quads = 0;
79
    BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
80
        wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_RX_DBOARD, pair.db_name)];
81
        wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
82
        subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>();
83
        switch(conn){
84
        case SUBDEV_CONN_COMPLEX_IQ:
85
        case SUBDEV_CONN_COMPLEX_QI: num_quads++; break;
86
        case SUBDEV_CONN_REAL_I:
87
        case SUBDEV_CONN_REAL_Q:     num_reals++; break;
88
        }
89
        channel_flags = (channel_flags << 4) | name_to_conn_to_flag[pair.db_name][conn];
90
    }
91

    
92
    //calculate Z:
93
    //    for all real sources: Z = 1
94
    //    for all quadrature sources: Z = 0
95
    //    for mixed sources: warning + Z = 0
96
    int Z = (num_quads > 0)? 0 : 1;
97
    if (num_quads != 0 and num_reals != 0) uhd::print_warning(
98
        "Mixing real and quadrature rx subdevices is not supported.\n"
99
        "The Q input to the real source(s) will be non-zero.\n"
100
    );
101

    
102
    //calculate the rx mux value
103
    return ((channel_flags & 0xffff) << 4) | ((Z & 0x1) << 3) | ((nchan & 0x7) << 0);
104
}
105

    
106
/***********************************************************************
107
 * Calculate the TX mux value:
108
 *    The I and Q mux values are intentionally reversed to flip I and Q
109
 *    to account for the reversal in the type conversion routines.
110
 **********************************************************************/
111
static int calc_tx_mux_pair(int chn_for_i, int chn_for_q){
112
    return (chn_for_i << 4) | (chn_for_q << 0); //shift reversal here
113
}
114

    
115
/*!
116
 *    3                   2                   1                   0
117
 *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
118
 * +-----------------------+-------+-------+-------+-------+-+-----+
119
 * |                       | DAC1Q | DAC1I | DAC0Q | DAC0I |0| NCH |
120
 * +-----------------------------------------------+-------+-+-----+
121
 */
122
static boost::uint32_t calc_tx_mux(
123
    const subdev_spec_t &subdev_spec, wax::obj mboard
124
){
125
    //create look-up-table for mapping channel number and connection type to flags
126
    static const int ENB = 1 << 3, CHAN_I0 = 0, CHAN_Q0 = 1, CHAN_I1 = 2, CHAN_Q1 = 3;
127
    static const uhd::dict<size_t, uhd::dict<subdev_conn_t, int> > chan_to_conn_to_flag = boost::assign::map_list_of
128
        (0, boost::assign::map_list_of
129
            (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I0 | ENB, CHAN_Q0 | ENB))
130
            (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q0 | ENB, CHAN_I0 | ENB))
131
            (SUBDEV_CONN_REAL_I,     calc_tx_mux_pair(CHAN_I0 | ENB, 0            ))
132
            (SUBDEV_CONN_REAL_Q,     calc_tx_mux_pair(0,             CHAN_I0 | ENB))
133
        )
134
        (1, boost::assign::map_list_of
135
            (SUBDEV_CONN_COMPLEX_IQ, calc_tx_mux_pair(CHAN_I1 | ENB, CHAN_Q1 | ENB))
136
            (SUBDEV_CONN_COMPLEX_QI, calc_tx_mux_pair(CHAN_Q1 | ENB, CHAN_I1 | ENB))
137
            (SUBDEV_CONN_REAL_I,     calc_tx_mux_pair(CHAN_I1 | ENB, 0            ))
138
            (SUBDEV_CONN_REAL_Q,     calc_tx_mux_pair(0,             CHAN_I1 | ENB))
139
        )
140
    ;
141

    
142
    //extract the number of channels
143
    size_t nchan = subdev_spec.size();
144

    
145
    //calculate the channel flags
146
    int channel_flags = 0, chan = 0;
147
    BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
148
        wax::obj dboard = mboard[named_prop_t(MBOARD_PROP_TX_DBOARD, pair.db_name)];
149
        wax::obj subdev = dboard[named_prop_t(DBOARD_PROP_SUBDEV, pair.sd_name)];
150
        subdev_conn_t conn = subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>();
151

    
152
        //combine the channel flags: shift for slot A vs B
153
        if (pair.db_name == "A") channel_flags |= chan_to_conn_to_flag[chan][conn] << 0;
154
        if (pair.db_name == "B") channel_flags |= chan_to_conn_to_flag[chan][conn] << 8;
155

    
156
        //increment for the next channel
157
        chan++;
158
    }
159

    
160
    //calculate the tx mux value
161
    return ((channel_flags & 0xffff) << 4) | ((nchan & 0x7) << 0);
162
}
163

    
164
/*!
165
 * Capabilities Register
166
 *
167
 *    3                   2                   1                   0
168
 *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
169
 * +-----------------------------------------------+-+-----+-+-----+
170
 * |               Reserved                        |T|DUCs |R|DDCs |
171
 * +-----------------------------------------------+-+-----+-+-----+
172
 */
173
static int num_ddcs(boost::uint32_t regval)
174
{
175
    return (regval >> 0) & 0x0007;
176
}
177

    
178
static int num_ducs(boost::uint32_t regval)
179
{
180
    return (regval >> 4) & 0x0007;
181
}
182

    
183
static bool has_rx_halfband(boost::uint32_t regval)
184
{
185
    return (regval >> 3) & 0x0001;
186
}
187

    
188
static bool has_tx_halfband(boost::uint32_t regval)
189
{
190
    return (regval >> 7) & 0x0001;
191
}
192

    
193
/***********************************************************************
194
 * Mboard Initialization
195
 **********************************************************************/
196
void usrp1_impl::mboard_init(void)
197
{
198
    _mboard_proxy = wax_obj_proxy::make(
199
                     boost::bind(&usrp1_impl::mboard_get, this, _1, _2),
200
                     boost::bind(&usrp1_impl::mboard_set, this, _1, _2));
201

    
202
    // Normal mode with no loopback or Rx counting
203
    _iface->poke32(FR_MODE, 0x00000000);
204
    _iface->poke32(FR_DEBUG_EN, 0x00000000);
205
    _iface->poke32(FR_RX_SAMPLE_RATE_DIV, 0x00000001);
206
    _iface->poke32(FR_TX_SAMPLE_RATE_DIV, 0x00000003);
207
    _iface->poke32(FR_DC_OFFSET_CL_EN, 0x0000000f);
208

    
209
    // Reset offset correction registers
210
    _iface->poke32(FR_ADC_OFFSET_0, 0x00000000);
211
    _iface->poke32(FR_ADC_OFFSET_1, 0x00000000);
212
    _iface->poke32(FR_ADC_OFFSET_2, 0x00000000);
213
    _iface->poke32(FR_ADC_OFFSET_3, 0x00000000);
214

    
215
    // Set default for RX format to 16-bit I&Q and no half-band filter bypass
216
    _iface->poke32(FR_RX_FORMAT, 0x00000300);
217

    
218
    // Set default for TX format to 16-bit I&Q
219
    _iface->poke32(FR_TX_FORMAT, 0x00000000);
220

    
221
    // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 
222
    // 
223
    // Do something useful with the capabilities register
224
    //
225
    boost::uint32_t regval = _iface->peek32(FR_RB_CAPS);
226
    std::cout << "USRP1 Capabilities" << std::endl;
227
    std::cout << "    number of duc's: " << num_ddcs(regval) << std::endl;
228
    std::cout << "    number of ddc's: " << num_ducs(regval) << std::endl;
229
    std::cout << "    rx halfband:     " << has_rx_halfband(regval) << std::endl;
230
    std::cout << "    tx halfband:     " << has_tx_halfband(regval) << std::endl;
231
}
232

    
233
void usrp1_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd)
234
{
235
    if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) {
236
        _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, true, 0, 0, 0);
237
    }
238

    
239
    if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) {
240
        _iface->write_firmware_cmd(VRQ_FPGA_SET_RX_ENABLE, false, 0, 0, 0);
241
    }
242
}
243

    
244
/***********************************************************************
245
 * Mboard Get
246
 **********************************************************************/
247
static prop_names_t dboard_names = boost::assign::list_of("A")("B");
248

    
249
void usrp1_impl::mboard_get(const wax::obj &key_, wax::obj &val)
250
{
251
    named_prop_t key = named_prop_t::extract(key_);
252

    
253
    //handle the get request conditioned on the key
254
    switch(key.as<mboard_prop_t>()){
255
    case MBOARD_PROP_NAME:
256
        val = std::string("usrp1 mboard");
257
        return;
258

    
259
    case MBOARD_PROP_OTHERS:
260
        val = prop_names_t();
261
        return;
262

    
263
    case MBOARD_PROP_RX_DBOARD:
264
        uhd::assert_has(dboard_names, key.name, "dboard name");
265
        if (key.name == "A") val = _rx_dboard_proxies[DBOARD_SLOT_A]->get_link();
266
        if (key.name == "B") val = _rx_dboard_proxies[DBOARD_SLOT_B]->get_link();
267
        return;
268

    
269
    case MBOARD_PROP_RX_DBOARD_NAMES:
270
        val = dboard_names;
271
        return;
272

    
273
    case MBOARD_PROP_TX_DBOARD:
274
        uhd::assert_has(dboard_names, key.name, "dboard name");
275
        if (key.name == "A") val = _tx_dboard_proxies[DBOARD_SLOT_A]->get_link();
276
        if (key.name == "B") val = _tx_dboard_proxies[DBOARD_SLOT_B]->get_link();
277
        return;
278

    
279
    case MBOARD_PROP_TX_DBOARD_NAMES:
280
        val = dboard_names;
281
        return;
282

    
283
    case MBOARD_PROP_RX_DSP:
284
        UHD_ASSERT_THROW(key.name == "");
285
        val = _rx_dsp_proxy->get_link();
286
        return;
287

    
288
    case MBOARD_PROP_RX_DSP_NAMES:
289
        val = prop_names_t(1, "");
290
        return;
291

    
292
    case MBOARD_PROP_TX_DSP:
293
        UHD_ASSERT_THROW(key.name == "");
294
        val = _tx_dsp_proxy->get_link();
295
        return;
296

    
297
    case MBOARD_PROP_TX_DSP_NAMES:
298
        val = prop_names_t(1, "");
299
        return;
300

    
301
    case MBOARD_PROP_CLOCK_CONFIG:
302
        val = _clock_config;
303
        return;
304

    
305
    case MBOARD_PROP_RX_SUBDEV_SPEC:
306
        val = _rx_subdev_spec;
307
        return;
308

    
309
    case MBOARD_PROP_TX_SUBDEV_SPEC:
310
        val = _tx_subdev_spec;
311
        return;
312

    
313
    default: UHD_THROW_PROP_GET_ERROR();
314
    }
315
}
316

    
317
/***********************************************************************
318
 * Mboard Set
319
 **********************************************************************/
320
void usrp1_impl::mboard_set(const wax::obj &key, const wax::obj &val)
321
{
322
    if(key.type() == typeid(std::string)) {
323
      if(key.as<std::string>() == "load_eeprom") {
324
        std::string usrp1_fpga_image = val.as<std::string>();
325
        std::cout << "USRP1 EEPROM image: " << usrp1_fpga_image << std::endl;
326
        _ctrl_transport->usrp_load_eeprom(val.as<std::string>());
327
      }
328

    
329
      return;
330
           }
331

    
332
    //handle the get request conditioned on the key
333
    switch(key.as<mboard_prop_t>()){
334

    
335
    case MBOARD_PROP_STREAM_CMD:
336
        issue_stream_cmd(val.as<stream_cmd_t>());
337
        return;
338

    
339
    case MBOARD_PROP_RX_SUBDEV_SPEC:
340
        _rx_subdev_spec = val.as<subdev_spec_t>();
341
        verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link());
342
        //sanity check
343
        UHD_ASSERT_THROW(_rx_subdev_spec.size() <= 2);
344
        //set the mux and set the number of rx channels
345
        _iface->poke32(FR_RX_MUX, calc_rx_mux(_rx_subdev_spec, _mboard_proxy->get_link()));
346
        return;
347

    
348
    case MBOARD_PROP_TX_SUBDEV_SPEC:
349
        _tx_subdev_spec = val.as<subdev_spec_t>();
350
        verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link());
351
        //sanity check
352
        UHD_ASSERT_THROW(_tx_subdev_spec.size() <= 2);
353
        //set the mux and set the number of tx channels
354
        _iface->poke32(FR_TX_MUX, calc_tx_mux(_tx_subdev_spec, _mboard_proxy->get_link()));
355
        return;
356

    
357
    default: UHD_THROW_PROP_SET_ERROR();
358
    }
359
}