Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp2 / dboard_iface.cpp @ 48ad3b73

History | View | Annotate | Download (11.6 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 "usrp2_iface.hpp"
19
#include "clock_ctrl.hpp"
20
#include "usrp2_regs.hpp" //wishbone address constants
21
#include <uhd/usrp/dboard_iface.hpp>
22
#include <uhd/types/dict.hpp>
23
#include <uhd/utils/assert.hpp>
24
#include <uhd/utils/algorithm.hpp>
25
#include <boost/assign/list_of.hpp>
26
#include <boost/asio.hpp> //htonl and ntohl
27
#include <boost/math/special_functions/round.hpp>
28
#include "ad7922_regs.hpp" //aux adc
29
#include "ad5623_regs.hpp" //aux dac
30

    
31
using namespace uhd;
32
using namespace uhd::usrp;
33
using namespace boost::assign;
34

    
35
class usrp2_dboard_iface : public dboard_iface{
36
public:
37
    usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl);
38
    ~usrp2_dboard_iface(void);
39

    
40
    special_props_t get_special_props(void){
41
        special_props_t props;
42
        props.soft_clock_divider = false;
43
        props.mangle_i2c_addrs = false;
44
        return props;
45
    }
46

    
47
    void write_aux_dac(unit_t, aux_dac_t, float);
48
    float read_aux_adc(unit_t, aux_adc_t);
49

    
50
    void set_pin_ctrl(unit_t, boost::uint16_t);
51
    void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
52
    void set_gpio_ddr(unit_t, boost::uint16_t);
53
    void write_gpio(unit_t, boost::uint16_t);
54
    void set_gpio_debug(unit_t, int);
55
    boost::uint16_t read_gpio(unit_t);
56

    
57
    void write_i2c(boost::uint8_t, const byte_vector_t &);
58
    byte_vector_t read_i2c(boost::uint8_t, size_t);
59

    
60
    void set_clock_rate(unit_t, double);
61
    double get_clock_rate(unit_t);
62
    std::vector<double> get_clock_rates(unit_t);
63
    void set_clock_enabled(unit_t, bool);
64

    
65
    void write_spi(
66
        unit_t unit,
67
        const spi_config_t &config,
68
        boost::uint32_t data,
69
        size_t num_bits
70
    );
71

    
72
    boost::uint32_t read_write_spi(
73
        unit_t unit,
74
        const spi_config_t &config,
75
        boost::uint32_t data,
76
        size_t num_bits
77
    );
78

    
79
private:
80
    usrp2_iface::sptr _iface;
81
    usrp2_clock_ctrl::sptr _clock_ctrl;
82
    boost::uint32_t _ddr_shadow;
83
    boost::uint32_t _gpio_shadow;
84

    
85
    uhd::dict<unit_t, ad5623_regs_t> _dac_regs;
86
    uhd::dict<unit_t, double> _clock_rates;
87
    void _write_aux_dac(unit_t);
88
};
89

    
90
/***********************************************************************
91
 * Make Function
92
 **********************************************************************/
93
dboard_iface::sptr make_usrp2_dboard_iface(
94
    usrp2_iface::sptr iface,
95
    usrp2_clock_ctrl::sptr clock_ctrl
96
){
97
    return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
98
}
99

    
100
/***********************************************************************
101
 * Structors
102
 **********************************************************************/
103
usrp2_dboard_iface::usrp2_dboard_iface(
104
    usrp2_iface::sptr iface,
105
    usrp2_clock_ctrl::sptr clock_ctrl
106
){
107
    _iface = iface;
108
    _clock_ctrl = clock_ctrl;
109
    _ddr_shadow = 0;
110
    _gpio_shadow = 0;
111

    
112
    //reset the aux dacs
113
    _dac_regs[UNIT_RX] = ad5623_regs_t();
114
    _dac_regs[UNIT_TX] = ad5623_regs_t();
115
    BOOST_FOREACH(unit_t unit, _dac_regs.keys()){
116
        _dac_regs[unit].data = 1;
117
        _dac_regs[unit].addr = ad5623_regs_t::ADDR_ALL;
118
        _dac_regs[unit].cmd  = ad5623_regs_t::CMD_RESET;
119
        this->_write_aux_dac(unit);
120
    }
121

    
122
    //init the clock rate shadows with max rate clock
123
    this->set_clock_rate(UNIT_RX, sorted(this->get_clock_rates(UNIT_RX)).back());
124
    this->set_clock_rate(UNIT_TX, sorted(this->get_clock_rates(UNIT_TX)).back());
125
}
126

    
127
usrp2_dboard_iface::~usrp2_dboard_iface(void){
128
    /* NOP */
129
}
130

    
131
/***********************************************************************
132
 * Clocks
133
 **********************************************************************/
134
void usrp2_dboard_iface::set_clock_rate(unit_t unit, double rate){
135
    _clock_rates[unit] = rate; //set to shadow
136
    switch(unit){
137
    case UNIT_RX: _clock_ctrl->set_rate_rx_dboard_clock(rate); return;
138
    case UNIT_TX: _clock_ctrl->set_rate_tx_dboard_clock(rate); return;
139
    }
140
}
141

    
142
double usrp2_dboard_iface::get_clock_rate(unit_t unit){
143
    return _clock_rates[unit]; //get from shadow
144
}
145

    
146
std::vector<double> usrp2_dboard_iface::get_clock_rates(unit_t unit){
147
    switch(unit){
148
    case UNIT_RX: return _clock_ctrl->get_rates_rx_dboard_clock();
149
    case UNIT_TX: return _clock_ctrl->get_rates_tx_dboard_clock();
150
    default: UHD_THROW_INVALID_CODE_PATH();
151
    }
152
}
153

    
154
void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
155
    switch(unit){
156
    case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return;
157
    case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return;
158
    }
159
}
160

    
161
/***********************************************************************
162
 * GPIO
163
 **********************************************************************/
164
static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
165
    (dboard_iface::UNIT_RX, 0)
166
    (dboard_iface::UNIT_TX, 16)
167
;
168

    
169
void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){
170
    //calculate the new selection mux setting
171
    boost::uint32_t new_sels = 0x0;
172
    for(size_t i = 0; i < 16; i++){
173
        bool is_bit_set = (value & (0x1 << i)) != 0;
174
        new_sels |= ((is_bit_set)? U2_FLAG_GPIO_SEL_ATR : U2_FLAG_GPIO_SEL_GPIO) << (i*2);
175
    }
176

    
177
    //write the selection mux value to register
178
    switch(unit){
179
    case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
180
    case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
181
    }
182
}
183

    
184
void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
185
    _ddr_shadow = \
186
        (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
187
        (boost::uint32_t(value) << unit_to_shift[unit]);
188
    _iface->poke32(U2_REG_GPIO_DDR, _ddr_shadow);
189
}
190

    
191
void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){
192
    _gpio_shadow = \
193
        (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) |
194
        (boost::uint32_t(value) << unit_to_shift[unit]);
195
    _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow);
196
}
197

    
198
boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
199
    return boost::uint16_t(_iface->peek32(U2_REG_GPIO_IO) >> unit_to_shift[unit]);
200
}
201

    
202
void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
203
    //define mapping of unit to atr regs to register address
204
    static const uhd::dict<
205
        unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
206
    > unit_to_atr_to_addr = map_list_of
207
        (UNIT_RX, map_list_of
208
            (ATR_REG_IDLE,        U2_REG_ATR_IDLE_RXSIDE)
209
            (ATR_REG_TX_ONLY,     U2_REG_ATR_INTX_RXSIDE)
210
            (ATR_REG_RX_ONLY,     U2_REG_ATR_INRX_RXSIDE)
211
            (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE)
212
        )
213
        (UNIT_TX, map_list_of
214
            (ATR_REG_IDLE,        U2_REG_ATR_IDLE_TXSIDE)
215
            (ATR_REG_TX_ONLY,     U2_REG_ATR_INTX_TXSIDE)
216
            (ATR_REG_RX_ONLY,     U2_REG_ATR_INRX_TXSIDE)
217
            (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE)
218
        )
219
    ;
220
    _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
221
}
222

    
223
void usrp2_dboard_iface::set_gpio_debug(unit_t unit, int which){
224
    this->set_gpio_ddr(unit, 0xffff); //all outputs
225

    
226
    //calculate the new selection mux setting
227
    boost::uint32_t new_sels = 0x0;
228
    int sel = (which == 0)?
229
        U2_FLAG_GPIO_SEL_DEBUG_0:
230
        U2_FLAG_GPIO_SEL_DEBUG_1;
231
    for(size_t i = 0; i < 16; i++){
232
        new_sels |= sel << (i*2);
233
    }
234

    
235
    //write the selection mux value to register
236
    switch(unit){
237
    case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
238
    case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
239
    }
240
}
241

    
242
/***********************************************************************
243
 * SPI
244
 **********************************************************************/
245
static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of
246
    (dboard_iface::UNIT_TX, SPI_SS_TX_DB)
247
    (dboard_iface::UNIT_RX, SPI_SS_RX_DB)
248
;
249

    
250
void usrp2_dboard_iface::write_spi(
251
    unit_t unit,
252
    const spi_config_t &config,
253
    boost::uint32_t data,
254
    size_t num_bits
255
){
256
    _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, false /*no rb*/);
257
}
258

    
259
boost::uint32_t usrp2_dboard_iface::read_write_spi(
260
    unit_t unit,
261
    const spi_config_t &config,
262
    boost::uint32_t data,
263
    size_t num_bits
264
){
265
    return _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, true /*rb*/);
266
}
267

    
268
/***********************************************************************
269
 * I2C
270
 **********************************************************************/
271
void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
272
    return _iface->write_i2c(addr, bytes);
273
}
274

    
275
byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
276
    return _iface->read_i2c(addr, num_bytes);
277
}
278

    
279
/***********************************************************************
280
 * Aux DAX/ADC
281
 **********************************************************************/
282
void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
283
    static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of
284
        (UNIT_RX, SPI_SS_RX_DAC)
285
        (UNIT_TX, SPI_SS_TX_DAC)
286
    ;
287
    _iface->transact_spi(
288
        unit_to_spi_dac[unit], spi_config_t::EDGE_FALL, 
289
        _dac_regs[unit].get_reg(), 24, false /*no rb*/
290
    );
291
}
292

    
293
void usrp2_dboard_iface::write_aux_dac(unit_t unit, aux_dac_t which, float value){
294
    _dac_regs[unit].data = boost::math::iround(4095*value/3.3);
295
    _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N;
296

    
297
    typedef uhd::dict<aux_dac_t, ad5623_regs_t::addr_t> aux_dac_to_addr;
298
    static const uhd::dict<unit_t, aux_dac_to_addr> unit_to_which_to_addr = map_list_of
299
        (UNIT_RX, map_list_of
300
            (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_B)
301
            (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_A)
302
            (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_A)
303
            (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_B)
304
        )
305
        (UNIT_TX, map_list_of
306
            (AUX_DAC_A, ad5623_regs_t::ADDR_DAC_A)
307
            (AUX_DAC_B, ad5623_regs_t::ADDR_DAC_B)
308
            (AUX_DAC_C, ad5623_regs_t::ADDR_DAC_B)
309
            (AUX_DAC_D, ad5623_regs_t::ADDR_DAC_A)
310
        )
311
    ;
312
    _dac_regs[unit].addr = unit_to_which_to_addr[unit][which];
313
    this->_write_aux_dac(unit);
314
}
315

    
316
float usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){
317
    static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
318
        (UNIT_RX, SPI_SS_RX_ADC)
319
        (UNIT_TX, SPI_SS_TX_ADC)
320
    ;
321

    
322
    //setup spi config args
323
    spi_config_t config;
324
    config.mosi_edge = spi_config_t::EDGE_FALL;
325
    config.miso_edge = spi_config_t::EDGE_RISE;
326

    
327
    //setup the spi registers
328
    ad7922_regs_t ad7922_regs;
329
    switch(which){
330
    case AUX_ADC_A: ad7922_regs.mod = 0; break;
331
    case AUX_ADC_B: ad7922_regs.mod = 1; break;
332
    } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn
333

    
334
    //write and read spi
335
    _iface->transact_spi(
336
        unit_to_spi_adc[unit], config,
337
        ad7922_regs.get_reg(), 16, false /*no rb*/
338
    );
339
    ad7922_regs.set_reg(boost::uint16_t(_iface->transact_spi(
340
        unit_to_spi_adc[unit], config,
341
        ad7922_regs.get_reg(), 16, true /*rb*/
342
    )));
343

    
344
    //convert to voltage and return
345
    return float(3.3*ad7922_regs.result/4095);
346
}