Revision 898adebb host/lib/usrp/dboard/db_dbsrx.cpp
| b/host/lib/usrp/dboard/db_dbsrx.cpp | ||
|---|---|---|
| 23 | 23 |
#include <uhd/utils/static.hpp> |
| 24 | 24 |
#include <uhd/utils/assert.hpp> |
| 25 | 25 |
#include <uhd/utils/algorithm.hpp> |
| 26 |
#include <uhd/utils/warning.hpp> |
|
| 26 | 27 |
#include <uhd/types/ranges.hpp> |
| 27 | 28 |
#include <uhd/types/dict.hpp> |
| 28 | 29 |
#include <uhd/usrp/subdev_props.hpp> |
| ... | ... | |
| 41 | 42 |
/*********************************************************************** |
| 42 | 43 |
* The DBSRX constants |
| 43 | 44 |
**********************************************************************/ |
| 44 |
static const bool dbsrx_debug = true;
|
|
| 45 |
static const bool dbsrx_debug = false;
|
|
| 45 | 46 |
|
| 46 | 47 |
static const freq_range_t dbsrx_freq_range(0.8e9, 2.4e9); |
| 47 | 48 |
|
| ... | ... | |
| 113 | 114 |
for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t)){
|
| 114 | 115 |
int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) ? sizeof(boost::uint32_t) : stop_reg - start_addr + 1; |
| 115 | 116 |
|
| 116 |
//create address to start reading register data |
|
| 117 |
byte_vector_t address_vector(1); |
|
| 118 |
address_vector[0] = start_addr; |
|
| 119 |
|
|
| 120 |
/* |
|
| 121 |
//send the address |
|
| 122 |
this->get_iface()->write_i2c( |
|
| 123 |
_max2118_addr, address_vector |
|
| 124 |
); |
|
| 125 |
*/ |
|
| 126 |
|
|
| 127 | 117 |
//create buffer for register data |
| 128 | 118 |
byte_vector_t regs_vector(num_bytes); |
| 129 | 119 |
|
| ... | ... | |
| 135 | 125 |
for(boost::uint8_t i=0; i < num_bytes; i++){
|
| 136 | 126 |
if (i + start_addr >= status_addr){
|
| 137 | 127 |
_max2118_read_regs.set_reg(i + start_addr, regs_vector[i]); |
| 138 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 139 |
"DBSRX: set reg 0x%02x, value 0x%04x" |
|
| 140 |
) % int(i + start_addr) % int(_max2118_read_regs.get_reg(i + start_addr)) << std::endl; |
|
| 141 | 128 |
} |
| 142 | 129 |
if(dbsrx_debug) std::cerr << boost::format( |
| 143 | 130 |
"DBSRX: read reg 0x%02x, value 0x%04x, start_addr = 0x%04x, num_bytes %d" |
| ... | ... | |
| 151 | 138 |
* \return true for locked |
| 152 | 139 |
*/ |
| 153 | 140 |
bool get_locked(void){
|
| 154 |
read_reg(0x0, 0x1);
|
|
| 141 |
read_reg(0x0, 0x0);
|
|
| 155 | 142 |
|
| 156 | 143 |
//mask and return lock detect |
| 157 | 144 |
bool locked = 5 >= _max2118_read_regs.adc && _max2118_read_regs.adc >= 2; |
| ... | ... | |
| 174 | 161 |
return dboard_base::sptr(new dbsrx(args, 0x67)); |
| 175 | 162 |
} |
| 176 | 163 |
|
| 177 |
//FIXME different dbid for USRP1 also
|
|
| 164 |
//dbid for USRP2 version
|
|
| 178 | 165 |
UHD_STATIC_BLOCK(reg_dbsrx_dboard){
|
| 179 | 166 |
//register the factory function for the rx dbid |
| 180 | 167 |
dboard_manager::register_dboard(0x000D, &make_dbsrx, "DBSRX"); |
| 181 | 168 |
} |
| 182 | 169 |
|
| 170 |
//dbid for USRP1 version |
|
| 171 |
UHD_STATIC_BLOCK(reg_dbsrx_on_usrp1_dboard){
|
|
| 172 |
//register the factory function for the rx dbid |
|
| 173 |
dboard_manager::register_dboard(0x0002, &make_dbsrx, "DBSRX"); |
|
| 174 |
} |
|
| 175 |
|
|
| 183 | 176 |
/*********************************************************************** |
| 184 | 177 |
* Structors |
| 185 | 178 |
**********************************************************************/ |
| 186 | 179 |
dbsrx::dbsrx(ctor_args_t args, boost::uint8_t max2118_addr) : rx_dboard_base(args){
|
| 180 |
//warn user about incorrect DBID on USRP1, requires R193 populated |
|
| 181 |
if (this->get_iface()->get_mboard_name() == "usrp1" and this->get_rx_id() == 0x000D) |
|
| 182 |
uhd::print_warning( |
|
| 183 |
str(boost::format( |
|
| 184 |
"DBSRX: incorrect dbid\n" |
|
| 185 |
"%s expects dbid 0x0002 and R193\n" |
|
| 186 |
"found dbid == %d\n" |
|
| 187 |
"Please see the daughterboard app notes" |
|
| 188 |
) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) |
|
| 189 |
); |
|
| 190 |
|
|
| 191 |
//warn user about incorrect DBID on non-USRP1, requires R194 populated |
|
| 192 |
if (this->get_iface()->get_mboard_name() != "usrp1" and this->get_rx_id() == 0x0002) |
|
| 193 |
uhd::print_warning( |
|
| 194 |
str(boost::format( |
|
| 195 |
"DBSRX: incorrect dbid\n" |
|
| 196 |
"%s expects dbid 0x000D and R194\n" |
|
| 197 |
"found dbid == %d\n" |
|
| 198 |
"Please see the daughterboard app notes" |
|
| 199 |
) % (this->get_iface()->get_mboard_name()) % (this->get_rx_id().to_pp_string())) |
|
| 200 |
); |
|
| 201 |
|
|
| 187 | 202 |
//enable only the clocks we need |
| 188 | 203 |
this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); |
| 189 | 204 |
|
| ... | ... | |
| 197 | 212 |
//send initial register settings |
| 198 | 213 |
this->send_reg(0x0, 0x5); |
| 199 | 214 |
|
| 200 |
//set defaults for LO, gains |
|
| 215 |
//set defaults for LO, gains, and filter bandwidth |
|
| 216 |
_bandwidth = 33e6; |
|
| 201 | 217 |
set_lo_freq(dbsrx_freq_range.min); |
| 218 |
|
|
| 202 | 219 |
BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){
|
| 203 | 220 |
set_gain(dbsrx_gain_ranges[name].min, name); |
| 204 | 221 |
} |
| 205 | 222 |
|
| 206 |
set_bandwidth(22.27e6); // default bandwidth from datasheet |
|
| 207 |
|
|
| 208 |
get_locked(); |
|
| 223 |
set_bandwidth(33e6); // default bandwidth from datasheet |
|
| 209 | 224 |
} |
| 210 | 225 |
|
| 211 | 226 |
dbsrx::~dbsrx(void){
|
| ... | ... | |
| 219 | 234 |
target_freq = std::clip(target_freq, dbsrx_freq_range.min, dbsrx_freq_range.max); |
| 220 | 235 |
|
| 221 | 236 |
double actual_freq=0.0, pfd_freq=0.0, ref_clock=0.0; |
| 222 |
int R=0, N=0, r=0; |
|
| 237 |
int R=0, N=0, r=0, m=0; |
|
| 238 |
bool update_filter_settings = false; |
|
| 223 | 239 |
|
| 224 | 240 |
//choose refclock |
| 225 | 241 |
std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX); |
| 226 | 242 |
BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){
|
| 227 |
if (ref_clock != 4e6) continue; |
|
| 243 |
if (ref_clock > 27.0e6) continue; |
|
| 244 |
|
|
| 245 |
//choose m_divider such that filter tuning constraint is met |
|
| 246 |
m = 31; |
|
| 247 |
while ((ref_clock/m < 1e6 or ref_clock/m > 2.5e6) and m > 0){ m--; }
|
|
| 248 |
|
|
| 249 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 250 |
"DBSRX: trying ref_clock %f and m_divider %d" |
|
| 251 |
) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; |
|
| 252 |
|
|
| 253 |
if (m >= 32) continue; |
|
| 228 | 254 |
|
| 229 | 255 |
//choose R |
| 230 | 256 |
for(r = 0; r <= 6; r += 1) {
|
| ... | ... | |
| 249 | 275 |
} |
| 250 | 276 |
|
| 251 | 277 |
//Assert because we failed to find a suitable combination of ref_clock, R and N |
| 278 |
UHD_ASSERT_THROW(ref_clock/(1 << m) < 1e6 or ref_clock/(1 << m) > 2.5e6); |
|
| 252 | 279 |
UHD_ASSERT_THROW((pfd_freq < dbsrx_pfd_freq_range.min) or (pfd_freq > dbsrx_pfd_freq_range.max)); |
| 253 | 280 |
UHD_ASSERT_THROW((N < 256) or (N > 32768)); |
| 254 | 281 |
done_loop: |
| 255 | 282 |
|
| 283 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 284 |
"DBSRX: choose ref_clock %f and m_divider %d" |
|
| 285 |
) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % m << std::endl; |
|
| 286 |
|
|
| 287 |
//if ref_clock or m divider changed, we need to update the filter settings |
|
| 288 |
if (ref_clock != this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) or m != _max2118_write_regs.m_divider) update_filter_settings = true; |
|
| 289 |
|
|
| 256 | 290 |
//compute resulting output frequency |
| 257 | 291 |
actual_freq = pfd_freq * N; |
| 258 | 292 |
|
| 259 | 293 |
//apply ref_clock, R, and N settings |
| 260 | 294 |
this->get_iface()->set_clock_rate(dboard_iface::UNIT_RX, ref_clock); |
| 261 | 295 |
ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); |
| 296 |
_max2118_write_regs.m_divider = m; |
|
| 262 | 297 |
_max2118_write_regs.r_divider = (max2118_write_regs_t::r_divider_t) r; |
| 263 | 298 |
_max2118_write_regs.set_n_divider(N); |
| 264 | 299 |
_max2118_write_regs.ade_vco_ade_read = max2118_write_regs_t::ADE_VCO_ADE_READ_ENABLED; |
| 265 |
send_reg(0x4,0x4); |
|
| 266 |
send_reg(0x0,0x2); |
|
| 267 | 300 |
|
| 268 | 301 |
//compute prescaler variables |
| 269 | 302 |
int scaler = actual_freq > 1125e6 ? 2 : 4; |
| 270 | 303 |
_max2118_write_regs.div2 = scaler == 4 ? max2118_write_regs_t::DIV2_DIV4 : max2118_write_regs_t::DIV2_DIV2; |
| 271 | 304 |
|
| 305 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 306 |
"DBSRX: scaler %d, actual_freq %f MHz, register bit: %d" |
|
| 307 |
) % scaler % (actual_freq/1e6) % int(_max2118_write_regs.div2) << std::endl; |
|
| 308 |
|
|
| 272 | 309 |
//compute vco frequency and select vco |
| 273 | 310 |
double vco_freq = actual_freq * scaler; |
| 274 |
int vco; |
|
| 275 | 311 |
if (vco_freq < 2433e6) |
| 276 |
vco = 0;
|
|
| 312 |
_max2118_write_regs.osc_band = 0;
|
|
| 277 | 313 |
else if (vco_freq < 2711e6) |
| 278 |
vco=1;
|
|
| 314 |
_max2118_write_regs.osc_band = 1;
|
|
| 279 | 315 |
else if (vco_freq < 3025e6) |
| 280 |
vco=2;
|
|
| 316 |
_max2118_write_regs.osc_band = 2;
|
|
| 281 | 317 |
else if (vco_freq < 3341e6) |
| 282 |
vco=3;
|
|
| 318 |
_max2118_write_regs.osc_band = 3;
|
|
| 283 | 319 |
else if (vco_freq < 3727e6) |
| 284 |
vco=4;
|
|
| 320 |
_max2118_write_regs.osc_band = 4;
|
|
| 285 | 321 |
else if (vco_freq < 4143e6) |
| 286 |
vco=5;
|
|
| 322 |
_max2118_write_regs.osc_band = 5;
|
|
| 287 | 323 |
else if (vco_freq < 4493e6) |
| 288 |
vco=6;
|
|
| 324 |
_max2118_write_regs.osc_band = 6;
|
|
| 289 | 325 |
else |
| 290 |
vco=7;
|
|
| 326 |
_max2118_write_regs.osc_band = 7;
|
|
| 291 | 327 |
|
| 292 |
//apply vco selection |
|
| 293 |
_max2118_write_regs.osc_band = vco; |
|
| 294 |
send_reg(0x2, 0x2); |
|
| 328 |
//send settings over i2c |
|
| 329 |
send_reg(0x0, 0x4); |
|
| 295 | 330 |
|
| 296 | 331 |
//check vtune for lock condition |
| 297 |
read_reg(0x0, 0x1); |
|
| 332 |
read_reg(0x0, 0x0); |
|
| 333 |
|
|
| 334 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 335 |
"DBSRX: initial guess for vco %d, vtune adc %d" |
|
| 336 |
) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; |
|
| 298 | 337 |
|
| 299 | 338 |
//if we are out of lock for chosen vco, change vco |
| 300 | 339 |
while ((_max2118_read_regs.adc == 0) or (_max2118_read_regs.adc == 7)){
|
| 340 |
|
|
| 301 | 341 |
//vtune is too low, try lower frequency vco |
| 302 | 342 |
if (_max2118_read_regs.adc == 0){
|
| 303 |
UHD_ASSERT_THROW(_max2118_write_regs.osc_band <= 0); |
|
| 343 |
if (_max2118_write_regs.osc_band == 0){
|
|
| 344 |
uhd::print_warning( |
|
| 345 |
str(boost::format( |
|
| 346 |
"DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" |
|
| 347 |
) % int(_max2118_write_regs.osc_band)) |
|
| 348 |
); |
|
| 349 |
UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); |
|
| 350 |
} |
|
| 351 |
if (_max2118_write_regs.osc_band <= 0) break; |
|
| 304 | 352 |
_max2118_write_regs.osc_band -= 1; |
| 305 | 353 |
} |
| 306 | 354 |
|
| 307 | 355 |
//vtune is too high, try higher frequency vco |
| 308 | 356 |
if (_max2118_read_regs.adc == 7){
|
| 309 |
UHD_ASSERT_THROW(_max2118_write_regs.osc_band >= 7); |
|
| 357 |
if (_max2118_write_regs.osc_band == 7){
|
|
| 358 |
uhd::print_warning( |
|
| 359 |
str(boost::format( |
|
| 360 |
"DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" |
|
| 361 |
) % int(_max2118_write_regs.osc_band)) |
|
| 362 |
); |
|
| 363 |
UHD_ASSERT_THROW(_max2118_read_regs.adc == 0); |
|
| 364 |
} |
|
| 365 |
if (_max2118_write_regs.osc_band >= 7) break; |
|
| 310 | 366 |
_max2118_write_regs.osc_band += 1; |
| 311 | 367 |
} |
| 312 | 368 |
|
| 369 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 370 |
"DBSRX: trying vco %d, vtune adc %d" |
|
| 371 |
) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; |
|
| 372 |
|
|
| 313 | 373 |
//update vco selection and check vtune |
| 314 | 374 |
send_reg(0x2, 0x2); |
| 315 | 375 |
read_reg(0x0, 0x0); |
| 316 | 376 |
} |
| 317 | 377 |
|
| 378 |
if(dbsrx_debug) std::cerr << boost::format( |
|
| 379 |
"DBSRX: final vco %d, vtune adc %d" |
|
| 380 |
) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl; |
|
| 381 |
|
|
| 318 | 382 |
//select charge pump bias current |
| 319 | 383 |
if (_max2118_read_regs.adc <= 2) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_100UA; |
| 320 | 384 |
else if (_max2118_read_regs.adc >= 5) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_400UA; |
| ... | ... | |
| 335 | 399 |
<< boost::format(" Target Freq=%fMHz\n") % (target_freq/1e6)
|
| 336 | 400 |
<< boost::format(" Actual Freq=%fMHz\n") % (_lo_freq/1e6)
|
| 337 | 401 |
<< std::endl; |
| 402 |
|
|
| 403 |
if (update_filter_settings) set_bandwidth(_bandwidth); |
|
| 404 |
get_locked(); |
|
| 338 | 405 |
} |
| 339 | 406 |
|
| 340 | 407 |
/*********************************************************************** |
| ... | ... | |
| 377 | 444 |
gain = std::clip<float>(gain, dbsrx_gain_ranges["GC1"].min, dbsrx_gain_ranges["GC1"].max); |
| 378 | 445 |
|
| 379 | 446 |
//voltage level constants |
| 380 |
static const float max_volts = float(2.7), min_volts = float(1.2);
|
|
| 447 |
static const float max_volts = float(1.2), min_volts = float(2.7);
|
|
| 381 | 448 |
static const float slope = (max_volts-min_volts)/dbsrx_gain_ranges["GC1"].max; |
| 382 | 449 |
|
| 383 | 450 |
//calculate the voltage for the aux dac |
| ... | ... | |
| 413 | 480 |
void dbsrx::set_bandwidth(float bandwidth){
|
| 414 | 481 |
//clip the input |
| 415 | 482 |
bandwidth = std::clip<float>(bandwidth, 4e6, 33e6); |
| 416 |
|
|
| 417 |
//calculate ref_freq |
|
| 418 |
float ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); |
|
| 419 | 483 |
|
| 420 |
//FIXME this contraint needs to be in the set_freq and needs to assert if it can't hit the range |
|
| 421 |
//calculate acceptable m_divider for filter tuning |
|
| 422 |
int m = 1; |
|
| 423 |
while (ref_freq/m < 1e6 or ref_freq/m > 2.5e6){ m++; }
|
|
| 424 |
_max2118_write_regs.m_divider = m; |
|
| 484 |
double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX); |
|
| 485 |
|
|
| 486 |
//NOTE: _max2118_write_regs.m_divider set in set_lo_freq |
|
| 425 | 487 |
|
| 426 |
_bandwidth = float((ref_freq/1e6/_max2118_write_regs.m_divider)*(4+0.145*_max2118_write_regs.f_dac)*1e6); |
|
| 488 |
//compute f_dac setting |
|
| 489 |
_max2118_write_regs.f_dac = std::clip<int>(int((((bandwidth*_max2118_write_regs.m_divider)/ref_clock) - 4)/0.145),0,127); |
|
| 427 | 490 |
|
| 428 |
_max2118_write_regs.f_dac = int(((bandwidth*_max2118_write_regs.m_divider/ref_freq) - 4)/0.145); |
|
| 491 |
//determine actual bandwidth |
|
| 492 |
_bandwidth = float((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac)); |
|
| 429 | 493 |
|
| 430 | 494 |
if (dbsrx_debug) std::cerr << boost::format( |
| 431 | 495 |
"DBSRX Filter Bandwidth: %f MHz, m: %d, f_dac: %d\n" |
| 432 |
) % (_bandwidth/1e6) % m % int(_max2118_write_regs.f_dac) << std::endl;
|
|
| 496 |
) % (_bandwidth/1e6) % int(_max2118_write_regs.m_divider) % int(_max2118_write_regs.f_dac) << std::endl;
|
|
| 433 | 497 |
|
| 434 |
this->send_reg(0x3, 0x5);
|
|
| 498 |
this->send_reg(0x3, 0x4);
|
|
| 435 | 499 |
} |
| 436 | 500 |
|
| 437 | 501 |
/*********************************************************************** |
Also available in: Unified diff