Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / cores / rx_dsp_core_200.cpp @ 861e6684

History | View | Annotate | Download (8.75 KB)

1
//
2
// Copyright 2011 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 "rx_dsp_core_200.hpp"
19
#include <uhd/types/dict.hpp>
20
#include <uhd/exception.hpp>
21
#include <uhd/utils/algorithm.hpp>
22
#include <boost/assign/list_of.hpp>
23
#include <boost/math/special_functions/round.hpp>
24
#include <boost/math/special_functions/sign.hpp>
25
#include <algorithm>
26
#include <cmath>
27

    
28
#define REG_DSP_RX_FREQ       _dsp_base + 0
29
//skip one right here
30
#define REG_DSP_RX_DECIM      _dsp_base + 8
31
#define REG_DSP_RX_MUX        _dsp_base + 12
32

    
33
#define FLAG_DSP_RX_MUX_SWAP_IQ   (1 << 0)
34
#define FLAG_DSP_RX_MUX_REAL_MODE (1 << 1)
35

    
36
#define REG_RX_CTRL_STREAM_CMD     _ctrl_base + 0
37
#define REG_RX_CTRL_TIME_SECS      _ctrl_base + 4
38
#define REG_RX_CTRL_TIME_TICKS     _ctrl_base + 8
39
#define REG_RX_CTRL_CLEAR          _ctrl_base + 12
40
#define REG_RX_CTRL_VRT_HDR        _ctrl_base + 16
41
#define REG_RX_CTRL_VRT_SID        _ctrl_base + 20
42
#define REG_RX_CTRL_VRT_TLR        _ctrl_base + 24
43
#define REG_RX_CTRL_NSAMPS_PP      _ctrl_base + 28
44
#define REG_RX_CTRL_NCHANNELS      _ctrl_base + 32
45
#define REG_RX_CTRL_FORMAT         _ctrl_base + 36
46

    
47
template <class T> T ceil_log2(T num){
48
    return std::ceil(std::log(num)/std::log(T(2)));
49
}
50

    
51
using namespace uhd;
52

    
53
class rx_dsp_core_200_impl : public rx_dsp_core_200{
54
public:
55
    rx_dsp_core_200_impl(
56
        wb_iface::sptr iface,
57
        const size_t dsp_base, const size_t ctrl_base,
58
        const boost::uint32_t sid, const bool lingering_packet
59
    ):
60
        _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base)
61
    {
62
        //This is a hack/fix for the lingering packet problem.
63
        //The caller should also flush the recv transports
64
        if (lingering_packet){
65
            stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
66
            stream_cmd.num_samps = 1;
67
            issue_stream_command(stream_cmd);
68
        }
69

    
70
        _iface->poke32(REG_RX_CTRL_CLEAR, 1); //reset
71
        _iface->poke32(REG_RX_CTRL_NCHANNELS, 1);
72
        _iface->poke32(REG_RX_CTRL_VRT_HDR, 0
73
            | (0x1 << 28) //if data with stream id
74
            | (0x1 << 26) //has trailer
75
            | (0x3 << 22) //integer time other
76
            | (0x1 << 20) //fractional time sample count
77
        );
78
        _iface->poke32(REG_RX_CTRL_VRT_SID, sid);
79
        _iface->poke32(REG_RX_CTRL_VRT_TLR, 0);
80
    }
81

    
82
    void set_nsamps_per_packet(const size_t nsamps){
83
        _iface->poke32(REG_RX_CTRL_NSAMPS_PP, nsamps);
84
    }
85

    
86
    void issue_stream_command(const stream_cmd_t &stream_cmd){
87
        UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff);
88
        _continuous_streaming = stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS;
89

    
90
        //setup the mode to instruction flags
91
        typedef boost::tuple<bool, bool, bool, bool> inst_t;
92
        static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of
93
                                                                //reload, chain, samps, stop
94
            (stream_cmd_t::STREAM_MODE_START_CONTINUOUS,   inst_t(true,  true,  false, false))
95
            (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS,    inst_t(false, false, false, true))
96
            (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true,  false))
97
            (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true,  true,  false))
98
        ;
99

    
100
        //setup the instruction flag values
101
        bool inst_reload, inst_chain, inst_samps, inst_stop;
102
        boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode];
103

    
104
        //calculate the word from flags and length
105
        boost::uint32_t cmd_word = 0;
106
        cmd_word |= boost::uint32_t((stream_cmd.stream_now)? 1 : 0) << 31;
107
        cmd_word |= boost::uint32_t((inst_chain)?            1 : 0) << 30;
108
        cmd_word |= boost::uint32_t((inst_reload)?           1 : 0) << 29;
109
        cmd_word |= boost::uint32_t((inst_stop)?             1 : 0) << 28;
110
        cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1);
111

    
112
        //issue the stream command
113
        _iface->poke32(REG_RX_CTRL_STREAM_CMD, cmd_word);
114
        _iface->poke32(REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
115
        _iface->poke32(REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(_tick_rate)); //latches the command
116
    }
117

    
118
    void set_mux(const std::string &mode, const bool fe_swapped){
119
        static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of
120
            ("IQ", 0)
121
            ("QI", FLAG_DSP_RX_MUX_SWAP_IQ)
122
            ("I", FLAG_DSP_RX_MUX_REAL_MODE)
123
            ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE)
124
        ;
125
        _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] ^ (fe_swapped? FLAG_DSP_RX_MUX_SWAP_IQ : 0));
126
    }
127

    
128
    void set_tick_rate(const double rate){
129
        _tick_rate = rate;
130
    }
131

    
132
    void set_link_rate(const double rate){
133
        _link_rate = rate/sizeof(boost::uint32_t); //in samps/s
134
    }
135

    
136
    double set_host_rate(const double rate){
137
        size_t decim_rate = uhd::clip<size_t>(
138
            boost::math::iround(_tick_rate/rate), size_t(std::ceil(_tick_rate/_link_rate)), 512
139
        );
140
        if (decim_rate > 128) decim_rate &= ~0x1; //CIC up to 128, have to use 1 HB
141
        if (decim_rate > 256) decim_rate &= ~0x3; //CIC up to 128, have to use 2 HB
142
        size_t decim = decim_rate;
143

    
144
        //determine which half-band filters are activated
145
        int hb0 = 0, hb1 = 0;
146
        if (decim % 2 == 0){
147
            hb0 = 1;
148
            decim /= 2;
149
        }
150
        if (decim % 2 == 0){
151
            hb1 = 1;
152
            decim /= 2;
153
        }
154

    
155
        _iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
156

    
157
        // Calculate CIC decimation (i.e., without halfband decimators)
158
        // Calculate closest multiplier constant to reverse gain absent scale multipliers
159
        const double rate_pow = std::pow(double(decim & 0xff), 4);
160
        _scaling_adjustment = std::pow(2, ceil_log2(rate_pow))/(1.65*rate_pow);
161

    
162
        return _tick_rate/decim_rate;
163
    }
164

    
165
    double get_scaling_adjustment(void){
166
        return _scaling_adjustment/_fxpt_scale_adj;
167
    }
168

    
169
    double set_freq(const double freq_){
170
        //correct for outside of rate (wrap around)
171
        double freq = std::fmod(freq_, _tick_rate);
172
        if (std::abs(freq) > _tick_rate/2.0)
173
            freq -= boost::math::sign(freq)*_tick_rate;
174

    
175
        //calculate the freq register word (signed)
176
        UHD_ASSERT_THROW(std::abs(freq) <= _tick_rate/2.0);
177
        static const double scale_factor = std::pow(2.0, 32);
178
        const boost::int32_t freq_word = boost::int32_t(boost::math::round((freq / _tick_rate) * scale_factor));
179

    
180
        //update the actual frequency
181
        const double actual_freq = (double(freq_word) / scale_factor) * _tick_rate;
182

    
183
        _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word));
184

    
185
        return actual_freq;
186
    }
187

    
188
    uhd::meta_range_t get_freq_range(void){
189
        return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32));
190
    }
191

    
192
    void handle_overflow(void){
193
        if (_continuous_streaming) issue_stream_command(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
194
    }
195

    
196
    void set_format(const std::string &format, const unsigned scale){
197
        unsigned format_word = 0;
198
        if (format == "sc16"){
199
            format_word = 0;
200
            _fxpt_scale_adj = 32767.;
201
        }
202
        else if (format == "sc8"){
203
            format_word = (1 << 18);
204
            _fxpt_scale_adj = 32767./scale;
205
        }
206
        else throw uhd::value_error("USRP RX cannot handle requested wire format: " + format);
207

    
208
        const unsigned scale_word = scale & 0x3ffff; //18 bits;
209
        _iface->poke32(REG_RX_CTRL_FORMAT, format_word | scale_word);
210
    }
211

    
212
private:
213
    wb_iface::sptr _iface;
214
    const size_t _dsp_base, _ctrl_base;
215
    double _tick_rate, _link_rate;
216
    bool _continuous_streaming;
217
    double _scaling_adjustment, _fxpt_scale_adj;
218
};
219

    
220
rx_dsp_core_200::sptr rx_dsp_core_200::make(wb_iface::sptr iface, const size_t dsp_base, const size_t ctrl_base, const boost::uint32_t sid, const bool lingering_packet){
221
    return sptr(new rx_dsp_core_200_impl(iface, dsp_base, ctrl_base, sid, lingering_packet));
222
}