Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp2 / dsp_impl.cpp @ 51a9c2d4

History | View | Annotate | Download (7.25 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_impl.hpp"
19
#include "usrp2_regs.hpp"
20
#include <uhd/usrp/dsp_props.hpp>
21
#include <uhd/utils/assert.hpp>
22
#include <boost/format.hpp>
23
#include <boost/bind.hpp>
24
#include <boost/assign/list_of.hpp>
25
#include <boost/math/special_functions/round.hpp>
26

    
27
using namespace uhd;
28
using namespace uhd::usrp;
29

    
30
static const size_t default_decim = 16;
31
static const size_t default_interp = 16;
32

    
33
#define rint boost::math::iround
34

    
35
template <class T> T log2(T num){
36
    return std::log(num)/std::log(T(2));
37
}
38

    
39
/***********************************************************************
40
 * DDC Helper Methods
41
 **********************************************************************/
42
static boost::uint32_t calculate_freq_word_and_update_actual_freq(double &freq, double clock_freq){
43
    double scale_factor = std::pow(2.0, 32);
44

    
45
    //calculate the freq register word
46
    boost::uint32_t freq_word = rint((freq / clock_freq) * scale_factor);
47

    
48
    //update the actual frequency
49
    freq = (double(freq_word) / scale_factor) * clock_freq;
50

    
51
    return freq_word;
52
}
53

    
54
static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t q){
55
    return (boost::uint16_t(i) << 16) | (boost::uint16_t(q) << 0);
56
}
57

    
58
template <class rate_t> static rate_t
59
pick_closest_rate(double exact_rate, const std::vector<rate_t> &rates){
60
    rate_t closest_match = rates.at(0);
61
    BOOST_FOREACH(rate_t possible_rate, rates){
62
        if(std::abs(exact_rate - possible_rate) < std::abs(exact_rate - closest_match))
63
            closest_match = possible_rate;
64
    }
65
    return closest_match;
66
}
67

    
68
void usrp2_impl::init_ddc_config(void){
69
    //create the ddc in the rx dsp dict
70
    _rx_dsp_proxy = wax_obj_proxy::make(
71
        boost::bind(&usrp2_impl::ddc_get, this, _1, _2),
72
        boost::bind(&usrp2_impl::ddc_set, this, _1, _2)
73
    );
74

    
75
    //initial config and update
76
    _ddc_decim = default_decim;
77
    _ddc_freq = 0;
78
    update_ddc_config();
79

    
80
    //initial command that kills streaming (in case if was left on)
81
    issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
82
}
83

    
84
void usrp2_impl::update_ddc_config(void){
85
    //set the decimation
86
    _iface->poke32(FR_DSP_RX_DECIM_RATE, _ddc_decim);
87

    
88
    //set the scaling
89
    static const boost::int16_t default_rx_scale_iq = 1024;
90
    _iface->poke32(FR_DSP_RX_SCALE_IQ,
91
        calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
92
    );
93
}
94

    
95
/***********************************************************************
96
 * DDC Properties
97
 **********************************************************************/
98
void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){
99
    switch(key.as<dsp_prop_t>()){
100
    case DSP_PROP_NAME:
101
        val = std::string("usrp2 ddc0");
102
        return;
103

    
104
    case DSP_PROP_OTHERS:
105
        val = prop_names_t(); //empty
106
        return;
107

    
108
    case DSP_PROP_FREQ_SHIFT:
109
        val = _ddc_freq;
110
        return;
111

    
112
    case DSP_PROP_CODEC_RATE:
113
        val = get_master_clock_freq();
114
        return;
115

    
116
    case DSP_PROP_HOST_RATE:
117
        val = get_master_clock_freq()/_ddc_decim;
118
        return;
119
    }
120
}
121

    
122
void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){
123
    switch(key.as<dsp_prop_t>()){
124

    
125
    case DSP_PROP_FREQ_SHIFT:{
126
            double new_freq = val.as<double>();
127
            ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
128
            ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
129
            _ddc_freq = new_freq; //shadow
130
            _iface->poke32(FR_DSP_RX_FREQ,
131
                calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq())
132
            );
133
        }
134
        return;
135

    
136
    case DSP_PROP_HOST_RATE:{
137
            double extact_rate = get_master_clock_freq()/val.as<double>();
138
            _ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
139
            update_ddc_config();
140
        }
141
        return;
142

    
143
    default:
144
        throw std::runtime_error("Error: trying to set read-only property on usrp2 ddc0");
145
    }
146
}
147

    
148
/***********************************************************************
149
 * DUC Helper Methods
150
 **********************************************************************/
151
void usrp2_impl::init_duc_config(void){
152
    //create the duc in the tx dsp dict
153
    _tx_dsp_proxy = wax_obj_proxy::make(
154
        boost::bind(&usrp2_impl::duc_get, this, _1, _2),
155
        boost::bind(&usrp2_impl::duc_set, this, _1, _2)
156
    );
157

    
158
    //initial config and update
159
    _duc_interp = default_interp;
160
    _duc_freq = 0;
161
    update_duc_config();
162
}
163

    
164
void usrp2_impl::update_duc_config(void){
165
    // Calculate CIC interpolation (i.e., without halfband interpolators)
166
    size_t tmp_interp = _duc_interp;
167
    while(tmp_interp > 128) tmp_interp /= 2;
168

    
169
    // Calculate closest multiplier constant to reverse gain absent scale multipliers
170
    double interp_cubed = std::pow(double(tmp_interp), 3);
171
    boost::int16_t scale = rint((4096*std::pow(2, ceil(log2(interp_cubed))))/(1.65*interp_cubed));
172

    
173
    //set the interpolation
174
    _iface->poke32(FR_DSP_TX_INTERP_RATE, _ddc_decim);
175

    
176
    //set the scaling
177
    _iface->poke32(FR_DSP_TX_SCALE_IQ, calculate_iq_scale_word(scale, scale));
178
}
179

    
180
/***********************************************************************
181
 * DUC Properties
182
 **********************************************************************/
183
void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){
184
    switch(key.as<dsp_prop_t>()){
185
    case DSP_PROP_NAME:
186
        val = std::string("usrp2 duc0");
187
        return;
188

    
189
    case DSP_PROP_OTHERS:
190
        val = prop_names_t(); //empty
191
        return;
192

    
193
    case DSP_PROP_FREQ_SHIFT:
194
        val = _duc_freq;
195
        return;
196

    
197
    case DSP_PROP_CODEC_RATE:
198
        val = get_master_clock_freq();
199
        return;
200

    
201
    case DSP_PROP_HOST_RATE:
202
        val = get_master_clock_freq()/_duc_interp;
203
        return;
204
    }
205
}
206

    
207
void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){
208
    switch(key.as<dsp_prop_t>()){
209

    
210
    case DSP_PROP_FREQ_SHIFT:{
211
            double new_freq = val.as<double>();
212
            ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0);
213
            ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0);
214
            _duc_freq = new_freq; //shadow
215
            _iface->poke32(FR_DSP_TX_FREQ,
216
                calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq())
217
            );
218
        }
219
        return;
220

    
221
    case DSP_PROP_HOST_RATE:{
222
            double extact_rate = get_master_clock_freq()/val.as<double>();
223
            _duc_interp = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
224
            update_duc_config();
225
        }
226
        return;
227

    
228
    default:
229
        throw std::runtime_error("Error: trying to set read-only property on usrp2 duc0");
230
    }
231
}