1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
//
// Copyright 2010-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include "x300_adc_ctrl.hpp"
#include "ads62p48_regs.hpp"
#include <uhd/types/ranges.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/exception.hpp>
#include <boost/foreach.hpp>
using namespace uhd;
x300_adc_ctrl::~x300_adc_ctrl(void){
/* NOP */
}
/*!
* A X300 codec control specific to the ads62p48 ic.
*/
class x300_adc_ctrl_impl : public x300_adc_ctrl
{
public:
x300_adc_ctrl_impl(uhd::spi_iface::sptr iface, const size_t slaveno):
_iface(iface), _slaveno(slaveno)
{
init();
}
void init()
{
//power-up adc
_ads62p48_regs.reset = 1;
this->send_ads62p48_reg(0x00); //issue a reset to the ADC
_ads62p48_regs.reset = 0;
_ads62p48_regs.enable_low_speed_mode = 0;
_ads62p48_regs.ref = ads62p48_regs_t::REF_INTERNAL;
_ads62p48_regs.standby = ads62p48_regs_t::STANDBY_NORMAL;
_ads62p48_regs.power_down = ads62p48_regs_t::POWER_DOWN_NORMAL;
_ads62p48_regs.lvds_cmos = ads62p48_regs_t::LVDS_CMOS_DDR_LVDS;
_ads62p48_regs.channel_control = ads62p48_regs_t::CHANNEL_CONTROL_INDEPENDENT;
_ads62p48_regs.data_format = ads62p48_regs_t::DATA_FORMAT_2S_COMPLIMENT;
_ads62p48_regs.clk_out_pos_edge = ads62p48_regs_t::CLK_OUT_POS_EDGE_MINUS4_26;
_ads62p48_regs.clk_out_neg_edge = ads62p48_regs_t::CLK_OUT_NEG_EDGE_MINUS4_26;
this->send_ads62p48_reg(0);
this->send_ads62p48_reg(0x20);
this->send_ads62p48_reg(0x3f);
this->send_ads62p48_reg(0x40);
this->send_ads62p48_reg(0x41);
this->send_ads62p48_reg(0x44);
this->send_ads62p48_reg(0x50);
this->send_ads62p48_reg(0x51);
this->send_ads62p48_reg(0x52);
this->send_ads62p48_reg(0x53);
this->send_ads62p48_reg(0x55);
this->send_ads62p48_reg(0x57);
this->send_ads62p48_reg(0x62);
this->send_ads62p48_reg(0x63);
this->send_ads62p48_reg(0x66);
this->send_ads62p48_reg(0x68);
this->send_ads62p48_reg(0x6a);
this->send_ads62p48_reg(0x75);
this->send_ads62p48_reg(0x76);
}
void reset()
{
init();
}
double set_gain(const double &gain)
{
const meta_range_t gain_range = meta_range_t(0, 6.0, 0.5);
const int gain_bits = int((gain_range.clip(gain)*2.0) + 0.5);
_ads62p48_regs.gain_chA = gain_bits;
_ads62p48_regs.gain_chB = gain_bits;
this->send_ads62p48_reg(0x55);
this->send_ads62p48_reg(0x68);
return gain_bits/2;
}
void set_test_word(const std::string &patterna, const std::string &patternb, const uint32_t num)
{
_ads62p48_regs.custom_pattern_low = num & 0xff;
_ads62p48_regs.custom_pattern_high = num >> 8;
if (patterna == "ones") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_ONES;
if (patterna == "zeros") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_ZEROS;
if (patterna == "custom") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_CUSTOM;
if (patterna == "ramp") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_RAMP;
if (patterna == "normal") _ads62p48_regs.test_patterns_chA = ads62p48_regs_t::TEST_PATTERNS_CHA_NORMAL;
if (patternb == "ones") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_ONES;
if (patternb == "zeros") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_ZEROS;
if (patternb == "custom") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_CUSTOM;
if (patterna == "ramp") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_RAMP;
if (patterna == "normal") _ads62p48_regs.test_patterns_chB = ads62p48_regs_t::TEST_PATTERNS_CHB_NORMAL;
this->send_ads62p48_reg(0x51);
this->send_ads62p48_reg(0x52);
this->send_ads62p48_reg(0x62);
this->send_ads62p48_reg(0x75);
}
~x300_adc_ctrl_impl(void)
{
_ads62p48_regs.power_down = ads62p48_regs_t::POWER_DOWN_GLOBAL;
UHD_SAFE_CALL
(
this->send_ads62p48_reg(0x40);
)
}
private:
ads62p48_regs_t _ads62p48_regs;
uhd::spi_iface::sptr _iface;
const size_t _slaveno;
void send_ads62p48_reg(uint8_t addr)
{
uint16_t reg = _ads62p48_regs.get_write_reg(addr);
_iface->write_spi(_slaveno, spi_config_t::EDGE_FALL, reg, 16);
}
};
/***********************************************************************
* Public make function for the ADC control
**********************************************************************/
x300_adc_ctrl::sptr x300_adc_ctrl::make(uhd::spi_iface::sptr iface, const size_t slaveno)
{
return sptr(new x300_adc_ctrl_impl(iface, slaveno));
}
|