Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp2 / dboard_iface.cpp @ f73a3688

History | View | Annotate | Download (9.8 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 <boost/assign/list_of.hpp>
25
#include <boost/asio.hpp> //htonl and ntohl
26
#include <boost/math/special_functions/round.hpp>
27
#include "ad7922_regs.hpp" //aux adc
28
#include "ad5623_regs.hpp" //aux dac
29

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

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

    
39
    void write_aux_dac(unit_t, int, float);
40
    float read_aux_adc(unit_t, int);
41

    
42
    void set_pin_ctrl(unit_t, boost::uint16_t);
43
    void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t);
44
    void set_gpio_ddr(unit_t, boost::uint16_t);
45
    void write_gpio(unit_t, boost::uint16_t);
46
    boost::uint16_t read_gpio(unit_t);
47

    
48
    void write_i2c(boost::uint8_t, const byte_vector_t &);
49
    byte_vector_t read_i2c(boost::uint8_t, size_t);
50

    
51
    double get_clock_rate(unit_t);
52
    void set_clock_enabled(unit_t, bool);
53
    bool get_clock_enabled(unit_t);
54

    
55
    void write_spi(
56
        unit_t unit,
57
        const spi_config_t &config,
58
        boost::uint32_t data,
59
        size_t num_bits
60
    );
61

    
62
    boost::uint32_t read_write_spi(
63
        unit_t unit,
64
        const spi_config_t &config,
65
        boost::uint32_t data,
66
        size_t num_bits
67
    );
68

    
69
private:
70
    usrp2_iface::sptr _iface;
71
    usrp2_clock_ctrl::sptr _clock_ctrl;
72
    boost::uint32_t _ddr_shadow;
73
    boost::uint32_t _gpio_shadow;
74

    
75
    uhd::dict<unit_t, ad5623_regs_t> _dac_regs;
76
    void _write_aux_dac(unit_t);
77
};
78

    
79
/***********************************************************************
80
 * Make Function
81
 **********************************************************************/
82
dboard_iface::sptr make_usrp2_dboard_iface(
83
    usrp2_iface::sptr iface,
84
    usrp2_clock_ctrl::sptr clock_ctrl
85
){
86
    return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl));
87
}
88

    
89
/***********************************************************************
90
 * Structors
91
 **********************************************************************/
92
usrp2_dboard_iface::usrp2_dboard_iface(
93
    usrp2_iface::sptr iface,
94
    usrp2_clock_ctrl::sptr clock_ctrl
95
){
96
    _iface = iface;
97
    _clock_ctrl = clock_ctrl;
98
    _ddr_shadow = 0;
99
    _gpio_shadow = 0;
100

    
101
    //reset the aux dacs
102
    _dac_regs[UNIT_RX] = ad5623_regs_t();
103
    _dac_regs[UNIT_TX] = ad5623_regs_t();
104
    BOOST_FOREACH(unit_t unit, _dac_regs.keys()){
105
        _dac_regs[unit].data = 1;
106
        _dac_regs[unit].addr = ad5623_regs_t::ADDR_ALL;
107
        _dac_regs[unit].cmd  = ad5623_regs_t::CMD_RESET;
108
        this->_write_aux_dac(unit);
109
    }
110
}
111

    
112
usrp2_dboard_iface::~usrp2_dboard_iface(void){
113
    /* NOP */
114
}
115

    
116
/***********************************************************************
117
 * Clocks
118
 **********************************************************************/
119
double usrp2_dboard_iface::get_clock_rate(unit_t){
120
    return _clock_ctrl->get_master_clock_rate();
121
}
122

    
123
void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){
124
    switch(unit){
125
    case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return;
126
    case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return;
127
    }
128
}
129

    
130
/***********************************************************************
131
 * GPIO
132
 **********************************************************************/
133
static const uhd::dict<dboard_iface::unit_t, int> unit_to_shift = map_list_of
134
    (dboard_iface::UNIT_RX, 0)
135
    (dboard_iface::UNIT_TX, 16)
136
;
137

    
138
void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){
139
    //calculate the new selection mux setting
140
    boost::uint32_t new_sels = 0x0;
141
    for(size_t i = 0; i < 16; i++){
142
        bool is_bit_set = (value & (0x1 << i)) != 0;
143
        new_sels |= ((is_bit_set)? U2_FLAG_GPIO_SEL_ATR : U2_FLAG_GPIO_SEL_GPIO) << (i*2);
144
    }
145

    
146
    //write the selection mux value to register
147
    switch(unit){
148
    case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
149
    case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
150
    }
151
}
152

    
153
void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
154
    _ddr_shadow = \
155
        (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
156
        (boost::uint32_t(value) << unit_to_shift[unit]);
157
    _iface->poke32(U2_REG_GPIO_DDR, _ddr_shadow);
158
}
159

    
160
void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){
161
    _gpio_shadow = \
162
        (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) |
163
        (boost::uint32_t(value) << unit_to_shift[unit]);
164
    _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow);
165
}
166

    
167
boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
168
    return boost::uint16_t(_iface->peek32(U2_REG_GPIO_IO) >> unit_to_shift[unit]);
169
}
170

    
171
void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
172
    //define mapping of unit to atr regs to register address
173
    static const uhd::dict<
174
        unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
175
    > unit_to_atr_to_addr = map_list_of
176
        (UNIT_RX, map_list_of
177
            (ATR_REG_IDLE,        U2_REG_ATR_IDLE_RXSIDE)
178
            (ATR_REG_TX_ONLY,     U2_REG_ATR_INTX_RXSIDE)
179
            (ATR_REG_RX_ONLY,     U2_REG_ATR_INRX_RXSIDE)
180
            (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE)
181
        )
182
        (UNIT_TX, map_list_of
183
            (ATR_REG_IDLE,        U2_REG_ATR_IDLE_TXSIDE)
184
            (ATR_REG_TX_ONLY,     U2_REG_ATR_INTX_TXSIDE)
185
            (ATR_REG_RX_ONLY,     U2_REG_ATR_INRX_TXSIDE)
186
            (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE)
187
        )
188
    ;
189
    _iface->poke16(unit_to_atr_to_addr[unit][atr], value);
190
}
191

    
192
/***********************************************************************
193
 * SPI
194
 **********************************************************************/
195
static const uhd::dict<dboard_iface::unit_t, int> unit_to_spi_dev = map_list_of
196
    (dboard_iface::UNIT_TX, SPI_SS_TX_DB)
197
    (dboard_iface::UNIT_RX, SPI_SS_RX_DB)
198
;
199

    
200
void usrp2_dboard_iface::write_spi(
201
    unit_t unit,
202
    const spi_config_t &config,
203
    boost::uint32_t data,
204
    size_t num_bits
205
){
206
    _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, false /*no rb*/);
207
}
208

    
209
boost::uint32_t usrp2_dboard_iface::read_write_spi(
210
    unit_t unit,
211
    const spi_config_t &config,
212
    boost::uint32_t data,
213
    size_t num_bits
214
){
215
    return _iface->transact_spi(unit_to_spi_dev[unit], config, data, num_bits, true /*rb*/);
216
}
217

    
218
/***********************************************************************
219
 * I2C
220
 **********************************************************************/
221
void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){
222
    return _iface->write_i2c(addr, bytes);
223
}
224

    
225
byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){
226
    return _iface->read_i2c(addr, num_bytes);
227
}
228

    
229
/***********************************************************************
230
 * Aux DAX/ADC
231
 **********************************************************************/
232
void usrp2_dboard_iface::_write_aux_dac(unit_t unit){
233
    static const uhd::dict<unit_t, int> unit_to_spi_dac = map_list_of
234
        (UNIT_RX, SPI_SS_RX_DAC)
235
        (UNIT_TX, SPI_SS_TX_DAC)
236
    ;
237
    _iface->transact_spi(
238
        unit_to_spi_dac[unit], spi_config_t::EDGE_FALL, 
239
        _dac_regs[unit].get_reg(), 24, false /*no rb*/
240
    );
241
}
242

    
243
void usrp2_dboard_iface::write_aux_dac(unit_t unit, int which, float value){
244
    _dac_regs[unit].data = boost::math::iround(4095*value/3.3);
245
    _dac_regs[unit].cmd = ad5623_regs_t::CMD_WR_UP_DAC_CHAN_N;
246
    //standardize on USRP1 interface, A=0, B=1, C=2, D=3
247
    //FIXME josh reccommends the use of a nested dictionary
248
    switch(which){
249
    case 0: _dac_regs[unit].addr = unit == dboard_iface::UNIT_RX ? ad5623_regs_t::ADDR_DAC_B : ad5623_regs_t::ADDR_DAC_A; break;
250
    case 1: _dac_regs[unit].addr = unit == dboard_iface::UNIT_RX ? ad5623_regs_t::ADDR_DAC_A : ad5623_regs_t::ADDR_DAC_B; break;
251
    case 2: _dac_regs[unit].addr = unit == dboard_iface::UNIT_RX ? ad5623_regs_t::ADDR_DAC_A : ad5623_regs_t::ADDR_DAC_B; break;
252
    case 3: _dac_regs[unit].addr = unit == dboard_iface::UNIT_RX ? ad5623_regs_t::ADDR_DAC_B : ad5623_regs_t::ADDR_DAC_A; break;
253
    default: throw std::runtime_error("not a possible aux dac, must be 0, 1, 2, or 3");
254
    }
255
    this->_write_aux_dac(unit);
256
}
257

    
258
float usrp2_dboard_iface::read_aux_adc(unit_t unit, int which){
259
    static const uhd::dict<unit_t, int> unit_to_spi_adc = map_list_of
260
        (UNIT_RX, SPI_SS_RX_ADC)
261
        (UNIT_TX, SPI_SS_TX_ADC)
262
    ;
263

    
264
    //setup spi config args
265
    spi_config_t config;
266
    config.mosi_edge = spi_config_t::EDGE_FALL;
267
    config.miso_edge = spi_config_t::EDGE_RISE;
268

    
269
    //setup the spi registers
270
    ad7922_regs_t ad7922_regs;
271
    ad7922_regs.mod = which; //normal mode: mod == chn
272
    ad7922_regs.chn = which;
273

    
274
    //write and read spi
275
    _iface->transact_spi(
276
        unit_to_spi_adc[unit], config,
277
        ad7922_regs.get_reg(), 16, false /*no rb*/
278
    );
279
    ad7922_regs.set_reg(boost::uint16_t(_iface->transact_spi(
280
        unit_to_spi_adc[unit], config,
281
        ad7922_regs.get_reg(), 16, true /*rb*/
282
    )));
283

    
284
    //convert to voltage and return
285
    return float(3.3*ad7922_regs.result/4095);
286
}