umtrx: created control interface for lms6002d

This commit is contained in:
Josh Blum
2014-04-06 21:24:36 -07:00
parent 9435b695c4
commit 07f4fb19a0
5 changed files with 621 additions and 176 deletions

View File

@@ -30,6 +30,8 @@ list(APPEND UMTRX_SOURCES
umtrx_find.cpp
umtrx_iface.cpp
umtrx_eeprom.cpp
lms6002d.cpp
lms6002d_ctrl.cpp
missing/platform.cpp #not properly exported from uhd, so we had to copy it
cores/rx_frontend_core_200.cpp
cores/tx_frontend_core_200.cpp

View File

@@ -0,0 +1,424 @@
/***********************************************************************
* This file was generated by /home/jblum/src/umtrx/uhd/host/lib/ic_reg_maps/gen_adf4350_regs.py on Mon Mar 31 20:02:28 2014
**********************************************************************/
#ifndef INCLUDED_ADF4350_REGS_HPP
#define INCLUDED_ADF4350_REGS_HPP
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
#include <boost/cstdint.hpp>
#include <set>
class adf4350_regs_t{
public:
boost::uint16_t frac_12_bit;
boost::uint16_t int_16_bit;
boost::uint16_t mod_12_bit;
boost::uint16_t phase_12_bit;
enum prescaler_t{
PRESCALER_4_5 = 0,
PRESCALER_8_9 = 1
};
prescaler_t prescaler;
enum counter_reset_t{
COUNTER_RESET_DISABLED = 0,
COUNTER_RESET_ENABLED = 1
};
counter_reset_t counter_reset;
enum cp_three_state_t{
CP_THREE_STATE_DISABLED = 0,
CP_THREE_STATE_ENABLED = 1
};
cp_three_state_t cp_three_state;
enum power_down_t{
POWER_DOWN_DISABLED = 0,
POWER_DOWN_ENABLED = 1
};
power_down_t power_down;
enum pd_polarity_t{
PD_POLARITY_NEGATIVE = 0,
PD_POLARITY_POSITIVE = 1
};
pd_polarity_t pd_polarity;
enum ldp_t{
LDP_10NS = 0,
LDP_6NS = 1
};
ldp_t ldp;
enum ldf_t{
LDF_FRAC_N = 0,
LDF_INT_N = 1
};
ldf_t ldf;
enum charge_pump_current_t{
CHARGE_PUMP_CURRENT_0_31MA = 0,
CHARGE_PUMP_CURRENT_0_63MA = 1,
CHARGE_PUMP_CURRENT_0_94MA = 2,
CHARGE_PUMP_CURRENT_1_25MA = 3,
CHARGE_PUMP_CURRENT_1_56MA = 4,
CHARGE_PUMP_CURRENT_1_88MA = 5,
CHARGE_PUMP_CURRENT_2_19MA = 6,
CHARGE_PUMP_CURRENT_2_50MA = 7,
CHARGE_PUMP_CURRENT_2_81MA = 8,
CHARGE_PUMP_CURRENT_3_13MA = 9,
CHARGE_PUMP_CURRENT_3_44MA = 10,
CHARGE_PUMP_CURRENT_3_75MA = 11,
CHARGE_PUMP_CURRENT_4_07MA = 12,
CHARGE_PUMP_CURRENT_4_38MA = 13,
CHARGE_PUMP_CURRENT_4_69MA = 14,
CHARGE_PUMP_CURRENT_5_00MA = 15
};
charge_pump_current_t charge_pump_current;
enum double_buffer_t{
DOUBLE_BUFFER_DISABLED = 0,
DOUBLE_BUFFER_ENABLED = 1
};
double_buffer_t double_buffer;
boost::uint16_t r_counter_10_bit;
enum reference_divide_by_2_t{
REFERENCE_DIVIDE_BY_2_DISABLED = 0,
REFERENCE_DIVIDE_BY_2_ENABLED = 1
};
reference_divide_by_2_t reference_divide_by_2;
enum reference_doubler_t{
REFERENCE_DOUBLER_DISABLED = 0,
REFERENCE_DOUBLER_ENABLED = 1
};
reference_doubler_t reference_doubler;
enum muxout_t{
MUXOUT_3STATE = 0,
MUXOUT_DVDD = 1,
MUXOUT_DGND = 2,
MUXOUT_RDIV = 3,
MUXOUT_NDIV = 4,
MUXOUT_ANALOG_LD = 5,
MUXOUT_DLD = 6,
MUXOUT_RESERVED = 7
};
muxout_t muxout;
enum low_noise_and_spur_t{
LOW_NOISE_AND_SPUR_LOW_NOISE = 0,
LOW_NOISE_AND_SPUR_RESERVED0 = 1,
LOW_NOISE_AND_SPUR_RESERVED1 = 2,
LOW_NOISE_AND_SPUR_LOW_SPUR = 3
};
low_noise_and_spur_t low_noise_and_spur;
boost::uint16_t clock_divider_12_bit;
enum clock_div_mode_t{
CLOCK_DIV_MODE_CLOCK_DIVIDER_OFF = 0,
CLOCK_DIV_MODE_FAST_LOCK = 1,
CLOCK_DIV_MODE_RESYNC_ENABLE = 2,
CLOCK_DIV_MODE_RESERVED = 3
};
clock_div_mode_t clock_div_mode;
enum cycle_slip_reduction_t{
CYCLE_SLIP_REDUCTION_DISABLED = 0,
CYCLE_SLIP_REDUCTION_ENABLED = 1
};
cycle_slip_reduction_t cycle_slip_reduction;
enum output_power_t{
OUTPUT_POWER_M4DBM = 0,
OUTPUT_POWER_M1DBM = 1,
OUTPUT_POWER_2DBM = 2,
OUTPUT_POWER_5DBM = 3
};
output_power_t output_power;
enum rf_output_enable_t{
RF_OUTPUT_ENABLE_DISABLED = 0,
RF_OUTPUT_ENABLE_ENABLED = 1
};
rf_output_enable_t rf_output_enable;
enum aux_output_power_t{
AUX_OUTPUT_POWER_M4DBM = 0,
AUX_OUTPUT_POWER_M1DBM = 1,
AUX_OUTPUT_POWER_2DBM = 2,
AUX_OUTPUT_POWER_5DBM = 3
};
aux_output_power_t aux_output_power;
enum aux_output_enable_t{
AUX_OUTPUT_ENABLE_DISABLED = 0,
AUX_OUTPUT_ENABLE_ENABLED = 1
};
aux_output_enable_t aux_output_enable;
enum aux_output_select_t{
AUX_OUTPUT_SELECT_DIVIDED = 0,
AUX_OUTPUT_SELECT_FUNDAMENTAL = 1
};
aux_output_select_t aux_output_select;
enum mute_till_lock_detect_t{
MUTE_TILL_LOCK_DETECT_MUTE_DISABLED = 0,
MUTE_TILL_LOCK_DETECT_MUTE_ENABLED = 1
};
mute_till_lock_detect_t mute_till_lock_detect;
enum vco_power_down_t{
VCO_POWER_DOWN_VCO_POWERED_UP = 0,
VCO_POWER_DOWN_VCO_POWERED_DOWN = 1
};
vco_power_down_t vco_power_down;
boost::uint8_t band_select_clock_div;
enum rf_divider_select_t{
RF_DIVIDER_SELECT_DIV1 = 0,
RF_DIVIDER_SELECT_DIV2 = 1,
RF_DIVIDER_SELECT_DIV4 = 2,
RF_DIVIDER_SELECT_DIV8 = 3,
RF_DIVIDER_SELECT_DIV16 = 4
};
rf_divider_select_t rf_divider_select;
enum feedback_select_t{
FEEDBACK_SELECT_DIVIDED = 0,
FEEDBACK_SELECT_FUNDAMENTAL = 1
};
feedback_select_t feedback_select;
enum ld_pin_mode_t{
LD_PIN_MODE_LOW0 = 0,
LD_PIN_MODE_DLD = 1,
LD_PIN_MODE_LOW = 2,
LD_PIN_MODE_HIGH = 3
};
ld_pin_mode_t ld_pin_mode;
adf4350_regs_t(void){
_state = NULL;
frac_12_bit = 0;
int_16_bit = 35;
mod_12_bit = 4095;
phase_12_bit = 0;
prescaler = PRESCALER_4_5;
counter_reset = COUNTER_RESET_DISABLED;
cp_three_state = CP_THREE_STATE_DISABLED;
power_down = POWER_DOWN_DISABLED;
pd_polarity = PD_POLARITY_POSITIVE;
ldp = LDP_10NS;
ldf = LDF_FRAC_N;
charge_pump_current = CHARGE_PUMP_CURRENT_1_88MA;
double_buffer = DOUBLE_BUFFER_DISABLED;
r_counter_10_bit = 0;
reference_divide_by_2 = REFERENCE_DIVIDE_BY_2_ENABLED;
reference_doubler = REFERENCE_DOUBLER_DISABLED;
muxout = MUXOUT_DVDD;
low_noise_and_spur = LOW_NOISE_AND_SPUR_LOW_SPUR;
clock_divider_12_bit = 0;
clock_div_mode = CLOCK_DIV_MODE_FAST_LOCK;
cycle_slip_reduction = CYCLE_SLIP_REDUCTION_DISABLED;
output_power = OUTPUT_POWER_5DBM;
rf_output_enable = RF_OUTPUT_ENABLE_ENABLED;
aux_output_power = AUX_OUTPUT_POWER_M4DBM;
aux_output_enable = AUX_OUTPUT_ENABLE_DISABLED;
aux_output_select = AUX_OUTPUT_SELECT_FUNDAMENTAL;
mute_till_lock_detect = MUTE_TILL_LOCK_DETECT_MUTE_DISABLED;
vco_power_down = VCO_POWER_DOWN_VCO_POWERED_UP;
band_select_clock_div = 0;
rf_divider_select = RF_DIVIDER_SELECT_DIV1;
feedback_select = FEEDBACK_SELECT_FUNDAMENTAL;
ld_pin_mode = LD_PIN_MODE_DLD;
}
~adf4350_regs_t(void){
delete _state;
}
enum addr_t{
ADDR_R0 = 0,
ADDR_R1 = 1,
ADDR_R2 = 2,
ADDR_R3 = 3,
ADDR_R4 = 4,
ADDR_R5 = 5
};
boost::uint32_t get_reg(boost::uint8_t addr){
boost::uint32_t reg = addr & 0x7;
switch(addr){
case 0:
reg |= (boost::uint32_t(frac_12_bit) & 0xfff) << 3;
reg |= (boost::uint32_t(int_16_bit) & 0xffff) << 15;
break;
case 1:
reg |= (boost::uint32_t(mod_12_bit) & 0xfff) << 3;
reg |= (boost::uint32_t(phase_12_bit) & 0xfff) << 15;
reg |= (boost::uint32_t(prescaler) & 0x1) << 27;
break;
case 2:
reg |= (boost::uint32_t(counter_reset) & 0x1) << 3;
reg |= (boost::uint32_t(cp_three_state) & 0x1) << 4;
reg |= (boost::uint32_t(power_down) & 0x1) << 5;
reg |= (boost::uint32_t(pd_polarity) & 0x1) << 6;
reg |= (boost::uint32_t(ldp) & 0x1) << 7;
reg |= (boost::uint32_t(ldf) & 0x1) << 8;
reg |= (boost::uint32_t(charge_pump_current) & 0xf) << 9;
reg |= (boost::uint32_t(double_buffer) & 0x1) << 13;
reg |= (boost::uint32_t(r_counter_10_bit) & 0x3ff) << 14;
reg |= (boost::uint32_t(reference_divide_by_2) & 0x1) << 24;
reg |= (boost::uint32_t(reference_doubler) & 0x1) << 25;
reg |= (boost::uint32_t(muxout) & 0x7) << 26;
reg |= (boost::uint32_t(low_noise_and_spur) & 0x3) << 29;
break;
case 3:
reg |= (boost::uint32_t(clock_divider_12_bit) & 0xfff) << 3;
reg |= (boost::uint32_t(clock_div_mode) & 0x3) << 15;
reg |= (boost::uint32_t(cycle_slip_reduction) & 0x1) << 18;
break;
case 4:
reg |= (boost::uint32_t(output_power) & 0x3) << 3;
reg |= (boost::uint32_t(rf_output_enable) & 0x1) << 5;
reg |= (boost::uint32_t(aux_output_power) & 0x3) << 6;
reg |= (boost::uint32_t(aux_output_enable) & 0x1) << 8;
reg |= (boost::uint32_t(aux_output_select) & 0x1) << 9;
reg |= (boost::uint32_t(mute_till_lock_detect) & 0x1) << 10;
reg |= (boost::uint32_t(vco_power_down) & 0x1) << 11;
reg |= (boost::uint32_t(band_select_clock_div) & 0xff) << 12;
reg |= (boost::uint32_t(rf_divider_select) & 0x7) << 20;
reg |= (boost::uint32_t(feedback_select) & 0x1) << 23;
break;
case 5:
reg |= (boost::uint32_t(ld_pin_mode) & 0x3) << 22;
break;
}
return reg;
}
void save_state(void){
if (_state == NULL) _state = new adf4350_regs_t();
_state->frac_12_bit = this->frac_12_bit;
_state->int_16_bit = this->int_16_bit;
_state->mod_12_bit = this->mod_12_bit;
_state->phase_12_bit = this->phase_12_bit;
_state->prescaler = this->prescaler;
_state->counter_reset = this->counter_reset;
_state->cp_three_state = this->cp_three_state;
_state->power_down = this->power_down;
_state->pd_polarity = this->pd_polarity;
_state->ldp = this->ldp;
_state->ldf = this->ldf;
_state->charge_pump_current = this->charge_pump_current;
_state->double_buffer = this->double_buffer;
_state->r_counter_10_bit = this->r_counter_10_bit;
_state->reference_divide_by_2 = this->reference_divide_by_2;
_state->reference_doubler = this->reference_doubler;
_state->muxout = this->muxout;
_state->low_noise_and_spur = this->low_noise_and_spur;
_state->clock_divider_12_bit = this->clock_divider_12_bit;
_state->clock_div_mode = this->clock_div_mode;
_state->cycle_slip_reduction = this->cycle_slip_reduction;
_state->output_power = this->output_power;
_state->rf_output_enable = this->rf_output_enable;
_state->aux_output_power = this->aux_output_power;
_state->aux_output_enable = this->aux_output_enable;
_state->aux_output_select = this->aux_output_select;
_state->mute_till_lock_detect = this->mute_till_lock_detect;
_state->vco_power_down = this->vco_power_down;
_state->band_select_clock_div = this->band_select_clock_div;
_state->rf_divider_select = this->rf_divider_select;
_state->feedback_select = this->feedback_select;
_state->ld_pin_mode = this->ld_pin_mode;
}
template<typename T> std::set<T> get_changed_addrs(void){
if (_state == NULL) throw uhd::runtime_error("no saved state");
//check each register for changes
std::set<T> addrs;
if(_state->frac_12_bit != this->frac_12_bit){
addrs.insert(0);
}
if(_state->int_16_bit != this->int_16_bit){
addrs.insert(0);
}
if(_state->mod_12_bit != this->mod_12_bit){
addrs.insert(1);
}
if(_state->phase_12_bit != this->phase_12_bit){
addrs.insert(1);
}
if(_state->prescaler != this->prescaler){
addrs.insert(1);
}
if(_state->counter_reset != this->counter_reset){
addrs.insert(2);
}
if(_state->cp_three_state != this->cp_three_state){
addrs.insert(2);
}
if(_state->power_down != this->power_down){
addrs.insert(2);
}
if(_state->pd_polarity != this->pd_polarity){
addrs.insert(2);
}
if(_state->ldp != this->ldp){
addrs.insert(2);
}
if(_state->ldf != this->ldf){
addrs.insert(2);
}
if(_state->charge_pump_current != this->charge_pump_current){
addrs.insert(2);
}
if(_state->double_buffer != this->double_buffer){
addrs.insert(2);
}
if(_state->r_counter_10_bit != this->r_counter_10_bit){
addrs.insert(2);
}
if(_state->reference_divide_by_2 != this->reference_divide_by_2){
addrs.insert(2);
}
if(_state->reference_doubler != this->reference_doubler){
addrs.insert(2);
}
if(_state->muxout != this->muxout){
addrs.insert(2);
}
if(_state->low_noise_and_spur != this->low_noise_and_spur){
addrs.insert(2);
}
if(_state->clock_divider_12_bit != this->clock_divider_12_bit){
addrs.insert(3);
}
if(_state->clock_div_mode != this->clock_div_mode){
addrs.insert(3);
}
if(_state->cycle_slip_reduction != this->cycle_slip_reduction){
addrs.insert(3);
}
if(_state->output_power != this->output_power){
addrs.insert(4);
}
if(_state->rf_output_enable != this->rf_output_enable){
addrs.insert(4);
}
if(_state->aux_output_power != this->aux_output_power){
addrs.insert(4);
}
if(_state->aux_output_enable != this->aux_output_enable){
addrs.insert(4);
}
if(_state->aux_output_select != this->aux_output_select){
addrs.insert(4);
}
if(_state->mute_till_lock_detect != this->mute_till_lock_detect){
addrs.insert(4);
}
if(_state->vco_power_down != this->vco_power_down){
addrs.insert(4);
}
if(_state->band_select_clock_div != this->band_select_clock_div){
addrs.insert(4);
}
if(_state->rf_divider_select != this->rf_divider_select){
addrs.insert(4);
}
if(_state->feedback_select != this->feedback_select){
addrs.insert(4);
}
if(_state->ld_pin_mode != this->ld_pin_mode){
addrs.insert(5);
}
return addrs;
}
private:
adf4350_regs_t *_state;
};
#endif /* INCLUDED_ADF4350_REGS_HPP */

View File

@@ -1,111 +0,0 @@
//
// Copyright 2012 Fairwaves
// Copyright 2010-2011 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 "gpio_core_200.hpp"
#include "umtrx_regs.hpp" //wishbone address constants?
#include <uhd/usrp/dboard_iface.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/asio.hpp> //htonl and ntohl
#include <boost/math/special_functions/round.hpp>
#include "usrp2_iface.hpp"
#include <cstdio>
using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
class umtrx_dboard_iface : public dboard_iface {
usrp2_iface::sptr _iface;
const std::string _dboard;
double _ref_clk;
int _lms_spi_number;
int _adf4350_spi_number;
void _write_aux_dac(unit_t) {}
public:
umtrx_dboard_iface(usrp2_iface::sptr iface, const std::string board, double ref_clk)
: _iface(iface), _dboard(board),
_ref_clk(ref_clk),
_lms_spi_number(board=="A"?SPI_SS_LMS1:SPI_SS_LMS2),
_adf4350_spi_number(board=="A"?SPI_SS_AUX1:SPI_SS_AUX2)
{}
~umtrx_dboard_iface(void) {}
special_props_t get_special_props(void) {
special_props_t props;
props.soft_clock_divider = false;
props.mangle_i2c_addrs = false;
return props;
}
void write_aux_dac(unit_t, aux_dac_t, double) {}
double read_aux_adc(unit_t, aux_adc_t) { return 0; }
void _set_pin_ctrl(unit_t, boost::uint16_t) {}
void _set_gpio_ddr(unit_t, boost::uint16_t) {}
void _set_gpio_out(unit_t, boost::uint16_t) {}
boost::uint16_t read_gpio(unit_t) { return 0; }
void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t) {}
void set_gpio_debug(unit_t, int) {}
void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes) { return _iface->write_i2c(addr, bytes); }
byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes) { return _iface->read_i2c(addr, num_bytes); }
void set_clock_rate(unit_t, double) { /* The clock rate is fixed */ }
double get_clock_rate(unit_t) { return _ref_clk; }
std::vector<double> get_clock_rates(unit_t) { assert(!"umtrx_dboard_iface::get_clock_rates() is not implemented"); std::vector<double> FIXME; return FIXME; }
void set_clock_enabled(unit_t, bool) { /* It's always enabled. */ }
double get_codec_rate(unit_t) { assert(!"umtrx_dboard_iface::get_codec_rate() is not implemented"); return 0; }
void write_spi(unit_t spi_device, const spi_config_t &config, boost::uint32_t data, size_t num_bits) {
if (spi_device == uhd::usrp::dboard_iface::UNIT_LMS) {
// Access LMS
_iface->write_spi(_lms_spi_number, config, data, num_bits);
} else if (spi_device == uhd::usrp::dboard_iface::UNIT_SYNT) {
// Access ADF4350 synthetiser
// _iface->write_spi(_adf4350_spi_number, config, data, num_bits);
_iface->write_spi(SPI_SS_AUX1, config, data, num_bits);
_iface->write_spi(SPI_SS_AUX2, config, data, num_bits);
} else {
assert(!"Wrong unit_t pased to umtrx_dboard_iface::write_spi.");
}
}
boost::uint32_t read_write_spi(unit_t spi_device, const spi_config_t &config, boost::uint32_t data, size_t num_bits) {
if (spi_device == uhd::usrp::dboard_iface::UNIT_LMS) {
// Access LMS
return _iface->read_spi(_lms_spi_number, config, data, num_bits);
} else if (spi_device == uhd::usrp::dboard_iface::UNIT_SYNT) {
// Access ADF4350 synthetiser
// return _iface->read_spi(_adf4350_spi_number, config, data, num_bits);
return _iface->read_spi(SPI_SS_AUX1, config, data, num_bits);
return _iface->read_spi(SPI_SS_AUX2, config, data, num_bits);
}
assert(!"Wrong unit_t pased to umtrx_dboard_iface::write_spi.");
return 0; // FIXME: propagate error for non-assert builds
}
};
/**********************************
* Make Function
**********************************/
dboard_iface::sptr make_umtrx_dboard_iface(usrp2_iface::sptr iface, const std::string dboard, double ref_clk) {
return dboard_iface::sptr(new umtrx_dboard_iface(iface, dboard, ref_clk));
}

View File

@@ -1,3 +1,11 @@
/***********************************************************************
* The interface to lms6002d that get registered into the property tree
**********************************************************************/
#include "lms6002d_ctrl.hpp"
#include "lms6002d.hpp"
#include "cores/adf4350_regs.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/assert_has.hpp>
@@ -18,9 +26,6 @@
#include <cfloat>
#include <limits>
#include "../umtrx/lms6002d.hpp"
#include "adf4350_regs.hpp"
using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
@@ -75,34 +80,103 @@ static int verbosity = 0;
// LMS6002D interface class for UmTRX
class umtrx_lms6002d_dev: public lms6002d_dev {
dboard_iface::sptr _db_iface;
uhd::spi_iface::sptr _spiface;
const int _slaveno;
public:
umtrx_lms6002d_dev(dboard_iface::sptr db_iface) : _db_iface(db_iface) {};
umtrx_lms6002d_dev(uhd::spi_iface::sptr spiface, const int slaveno) : _spiface(spiface), _slaveno(slaveno) {};
virtual void write_reg(uint8_t addr, uint8_t data) {
if (verbosity>2) printf("db_lms6002d::write_reg(addr=0x%x, data=0x%x)\n", addr, data);
if (verbosity>2) printf("lms6002d_ctrl_impl::write_reg(addr=0x%x, data=0x%x)\n", addr, data);
uint16_t command = (((uint16_t)0x80 | (uint16_t)addr) << 8) | (uint16_t)data;
_db_iface->write_spi(uhd::usrp::dboard_iface::UNIT_LMS,
spi_config_t::EDGE_RISE, command, 16);
_spiface->write_spi(_slaveno, spi_config_t::EDGE_RISE, command, 16);
}
virtual uint8_t read_reg(uint8_t addr) {
if(addr > 127) return 0; // incorrect address, 7 bit long expected
uint8_t data = _db_iface->read_write_spi(uhd::usrp::dboard_iface::UNIT_LMS,
spi_config_t::EDGE_RISE, addr << 8, 16);
if (verbosity>2) printf("db_lms6002d::read_reg(addr=0x%x) data=0x%x\n", addr, data);
uint8_t data = _spiface->read_spi(_slaveno, spi_config_t::EDGE_RISE, addr << 8, 16);
if (verbosity>2) printf("lms6002d_ctrl_impl::read_reg(addr=0x%x) data=0x%x\n", addr, data);
return data;
}
};
// LMS6002D virtual daughter board for UmTRX
class db_lms6002d : public xcvr_dboard_base {
class lms6002d_ctrl_impl : public lms6002d_ctrl {
public:
db_lms6002d(ctor_args_t args);
lms6002d_ctrl_impl(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate);
double set_rx_freq(const double freq)
{
return this->set_freq(dboard_iface::UNIT_RX, freq);
}
double set_tx_freq(const double freq)
{
return this->set_freq(dboard_iface::UNIT_TX, freq);
}
bool set_rx_enabled(const bool enb)
{
return this->set_enabled(dboard_iface::UNIT_RX, enb);
}
bool set_tx_enabled(const bool enb)
{
return this->set_enabled(dboard_iface::UNIT_RX, enb);
}
uhd::freq_range_t get_rx_bw_range(void)
{
return lms_bandwidth_range;
}
uhd::freq_range_t get_tx_bw_range(void)
{
return lms_bandwidth_range;
}
uhd::freq_range_t get_rx_freq_range(void)
{
return lms_freq_range;
}
uhd::freq_range_t get_tx_freq_range(void)
{
return lms_freq_range;
}
std::vector<std::string> get_tx_antennas(void)
{
return lms_tx_antennas;
}
std::vector<std::string> get_rx_antennas(void)
{
return lms_rx_antennas;
}
std::vector<std::string> get_tx_gains(void)
{
return lms_tx_gain_ranges.keys();
}
std::vector<std::string> get_rx_gains(void)
{
return lms_rx_gain_ranges.keys();
}
uhd::gain_range_t get_rx_gain_range(const std::string &name)
{
return lms_rx_gain_ranges[name];
}
uhd::gain_range_t get_tx_gain_range(const std::string &name)
{
return lms_tx_gain_ranges[name];
}
double set_freq(dboard_iface::unit_t unit, double f) {
if (verbosity>0) printf("db_lms6002d::set_freq(%f)\n", f);
unsigned ref_freq = get_iface()->get_clock_rate(dboard_iface::UNIT_LMS);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq(%f)\n", f);
unsigned ref_freq = _clock_rate;
double actual_freq = 0;
if (unit==dboard_iface::UNIT_TX) {
actual_freq = lms.tx_pll_tune(ref_freq, f);
@@ -113,24 +187,24 @@ public:
// New beta version of the code for UmSEL support.
const double umsel_if = 359.5e6;
double actual_lms_freq = lms.rx_pll_tune(ref_freq, umsel_if);
if (verbosity>0) printf("db_lms6002d::set_freq() actual_lms_freq=%f\n", actual_lms_freq);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq() actual_lms_freq=%f\n", actual_lms_freq);
double adf4350_freq = f - actual_lms_freq;
actual_freq = tune_adf4350(adf4350_freq);
if (verbosity>0) printf("db_lms6002d::set_freq() adf4350 freq=%f\n", actual_freq);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq() adf4350 freq=%f\n", actual_freq);
actual_freq += actual_lms_freq;
if (verbosity>0) printf("db_lms6002d::set_freq() actual_freq=%f\n", actual_freq);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq() actual_freq=%f\n", actual_freq);
#endif
} else {
assert(!"Wrong units_t value passed to db_lms6002d::set_freq()");
assert(!"Wrong units_t value passed to lms6002d_ctrl_impl::set_freq()");
}
if (actual_freq<0)
actual_freq = 0;
if (verbosity>0) printf("db_lms6002d::set_freq() actual_freq=%f\n", actual_freq);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq() actual_freq=%f\n", actual_freq);
return actual_freq;
}
bool set_enabled(dboard_iface::unit_t unit, bool en) {
if (verbosity>0) printf("db_lms6002d::set_enabled(%d)\n", en);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_enabled(%d)\n", en);
if (unit==dboard_iface::UNIT_RX) {
if (en)
lms.rx_enable();
@@ -147,7 +221,7 @@ public:
}
double set_rx_gain(double gain, const std::string &name) {
if (verbosity>0) printf("db_lms6002d::set_rx_gain(%f, %s)\n", gain, name.c_str());
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_gain(%f, %s)\n", gain, name.c_str());
assert_has(lms_rx_gain_ranges.keys(), name, "LMS6002D rx gain name");
if(name == "VGA1"){
lms.set_rx_vga1gain(gain);
@@ -158,14 +232,14 @@ public:
}
void set_rx_ant(const std::string &ant) {
if (verbosity>0) printf("db_lms6002d::set_rx_ant(%s)\n", ant.c_str());
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_ant(%s)\n", ant.c_str());
//validate input
assert_has(lms_rx_antennas, ant, "LMS6002D rx antenna name");
if (ant == "CAL") {
// Enable RF loopback if disabled
if (!rf_loopback_enabled) {
if (verbosity>0) printf("db_lms6002d::set_rx_ant(%s) enabling RF loopback for LNA%d\n", ant.c_str(), lms.get_rx_lna());
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_ant(%s) enabling RF loopback for LNA%d\n", ant.c_str(), lms.get_rx_lna());
lms.rf_loopback_enable(lms.get_rx_lna());
rf_loopback_enabled = true;
}
@@ -191,7 +265,7 @@ public:
}
double set_rx_bandwidth(double bandwidth) {
if (verbosity>0) printf("db_lms6002d::set_rx_bandwidth(%f)\n", bandwidth);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_bandwidth(%f)\n", bandwidth);
// Get the closest available bandwidth
bandwidth = lms_bandwidth_range.clip(bandwidth);
@@ -202,7 +276,7 @@ public:
}
double set_tx_gain(double gain, const std::string &name) {
if (verbosity>0) printf("db_lms6002d::set_tx_gain(%f, %s)\n", gain, name.c_str());
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_gain(%f, %s)\n", gain, name.c_str());
//validate input
assert_has(lms_tx_gain_ranges.keys(), name, "LMS6002D tx gain name");
@@ -220,7 +294,7 @@ public:
tx_vga1gain = int(gain) - tx_vga2gain;
// Set the gains in hardware
if (verbosity>1) printf("db_lms6002d::set_tx_gain() VGA1=%d VGA2=%d\n", tx_vga1gain, tx_vga2gain);
if (verbosity>1) printf("lms6002d_ctrl_impl::set_tx_gain() VGA1=%d VGA2=%d\n", tx_vga1gain, tx_vga2gain);
lms.set_tx_vga1gain(tx_vga1gain);
lms.set_tx_vga2gain(tx_vga2gain);
} else {
@@ -232,7 +306,7 @@ public:
}
void set_tx_ant(const std::string &ant) {
if (verbosity>0) printf("db_lms6002d::set_tx_ant(%s)\n", ant.c_str());
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_ant(%s)\n", ant.c_str());
//validate input
assert_has(lms_tx_antennas, ant, "LMS6002D tx antenna ant");
@@ -251,7 +325,7 @@ public:
}
double set_tx_bandwidth(double bandwidth) {
if (verbosity>0) printf("db_lms6002d::set_tx_bandwidth(%f)\n", bandwidth);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_bandwidth(%f)\n", bandwidth);
// Get the closest available bandwidth
bandwidth = lms_bandwidth_range.clip(bandwidth);
@@ -262,13 +336,13 @@ public:
}
uint8_t _set_tx_vga1dc_i_int(uint8_t offset) {
if (verbosity>0) printf("db_lms6002d::set_tx_vga1dc_i_int(%d)\n", offset);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_i_int(%d)\n", offset);
lms.set_tx_vga1dc_i_int(offset);
return offset;
}
uint8_t _set_tx_vga1dc_q_int(uint8_t offset) {
if (verbosity>0) printf("db_lms6002d::set_tx_vga1dc_q_int(%d)\n", offset);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_q_int(%d)\n", offset);
lms.set_tx_vga1dc_q_int(offset);
return offset;
}
@@ -280,12 +354,22 @@ private:
// Tune ADF4350 on an UmSEL
double tune_adf4350(double target_freq);
uhd::spi_iface::sptr _spiface;
const int _lms_spi_number;
const int _adf4350_spi_number;
const double _clock_rate;
};
lms6002d_ctrl::sptr lms6002d_ctrl::make(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate)
{
return sptr(new lms6002d_ctrl_impl(spiface, lms_spi_number, adf4350_spi_number, clock_rate));
}
/***********************************************************************
* Tuning
**********************************************************************/
double db_lms6002d::tune_adf4350(double target_freq) {
double lms6002d_ctrl_impl::tune_adf4350(double target_freq) {
UHD_LOGV(often) << boost::format(
"UmSEL tune: target frequency %f Mhz"
) % (target_freq/1e6) << std::endl;
@@ -311,7 +395,7 @@ double db_lms6002d::tune_adf4350(double target_freq) {
double actual_freq, pfd_freq;
// TODO:: May be *2? Check
double ref_freq = get_iface()->get_clock_rate(dboard_iface::UNIT_LMS) * 2;
double ref_freq = _clock_rate * 2;
int R=0, BS=0, N=0, FRAC=0, MOD=0;
int RFdiv = 1;
adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
@@ -436,12 +520,12 @@ double db_lms6002d::tune_adf4350(double target_freq) {
);
}
#else
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, 0x0580000|5, 32);
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, 0x0BFF4F8|4, 32);
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, 0x0040000|3, 32);
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, 0x1006E40|2, 32);
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, 0x8008208|1, 32);
this->get_iface()->write_spi(uhd::usrp::dboard_iface::UNIT_SYNT, spi_config_t::EDGE_RISE, (325<<15)|(1<<3)|0, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, 0x0580000|5, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, 0x0BFF4F8|4, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, 0x0040000|3, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, 0x1006E40|2, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, 0x8008208|1, 32);
_spiface->write_spi(_adf4350_spi_number, spi_config_t::EDGE_RISE, (325<<15)|(1<<3)|0, 32);
#endif
//return the actual frequency
@@ -452,23 +536,17 @@ double db_lms6002d::tune_adf4350(double target_freq) {
return actual_freq;
}
// Register the LMS dboards
static dboard_base::sptr make_lms6002d(dboard_base::ctor_args_t args) {
return dboard_base::sptr(new db_lms6002d(args));
}
UHD_STATIC_BLOCK(reg_lms_dboards){
dboard_manager::register_dboard(0xfa07, 0xfa09, &make_lms6002d, "LMS6002D");
}
// LMS RX dboard configuration
db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
lms(get_iface()),
lms6002d_ctrl_impl::lms6002d_ctrl_impl(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate) :
lms(umtrx_lms6002d_dev(spiface, lms_spi_number)),
tx_vga1gain(lms.get_tx_vga1gain()),
tx_vga2gain(lms.get_tx_vga2gain()),
rf_loopback_enabled(false)
rf_loopback_enabled(false),
_spiface(spiface),
_lms_spi_number(lms_spi_number),
_adf4350_spi_number(adf4350_spi_number),
_clock_rate(clock_rate)
{
////////////////////////////////////////////////////////////////////
// LMS6002D initialization
@@ -484,8 +562,9 @@ db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
lms.set_tx_vga1gain(-10);
// Perform autocalibration
lms.auto_calibration(get_iface()->get_clock_rate(dboard_iface::UNIT_LMS), 0xf);
lms.auto_calibration(_clock_rate, 0xf);
/*
////////////////////////////////////////////////////////////////////
// Register RX properties
////////////////////////////////////////////////////////////////////
@@ -494,19 +573,19 @@ db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
BOOST_FOREACH(const std::string &name, lms_rx_gain_ranges.keys()){
this->get_rx_subtree()->create<double>("gains/"+name+"/value")
.coerce(boost::bind(&db_lms6002d::set_rx_gain, this, _1, name))
.coerce(boost::bind(&lms6002d_ctrl_impl::set_rx_gain, this, _1, name))
.set((lms_rx_gain_ranges[name].start()+lms_rx_gain_ranges[name].stop())/2.0);
this->get_rx_subtree()->create<meta_range_t>("gains/"+name+"/range")
.set(lms_rx_gain_ranges[name]);
}
this->get_rx_subtree()->create<double>("freq/value")
.coerce(boost::bind(&db_lms6002d::set_freq, this, dboard_iface::UNIT_RX, _1));
.coerce(boost::bind(&lms6002d_ctrl_impl::set_freq, this, dboard_iface::UNIT_RX, _1));
this->get_rx_subtree()->create<meta_range_t>("freq/range")
.set(lms_freq_range);
this->get_rx_subtree()->create<std::string>("antenna/value")
.subscribe(boost::bind(&db_lms6002d::set_rx_ant, this, _1))
.subscribe(boost::bind(&lms6002d_ctrl_impl::set_rx_ant, this, _1))
.set("RX1");
this->get_rx_subtree()->create<std::vector<std::string> >("antenna/options")
.set(lms_rx_antennas);
@@ -515,11 +594,11 @@ db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
.set(sensor_value_t("LO", true, "locked", "unlocked"));
this->get_rx_subtree()->create<std::string>("connection").set("IQ");
this->get_rx_subtree()->create<bool>("enabled")
.coerce(boost::bind(&db_lms6002d::set_enabled, this, dboard_iface::UNIT_RX, _1));
.coerce(boost::bind(&lms6002d_ctrl_impl::set_enabled, this, dboard_iface::UNIT_RX, _1));
this->get_rx_subtree()->create<bool>("use_lo_offset").set(false);
this->get_rx_subtree()->create<double>("bandwidth/value")
.coerce(boost::bind(&db_lms6002d::set_rx_bandwidth, this, _1))
.coerce(boost::bind(&lms6002d_ctrl_impl::set_rx_bandwidth, this, _1))
.set(double(2*0.75e6));
this->get_rx_subtree()->create<meta_range_t>("bandwidth/range")
.set(lms_bandwidth_range);
@@ -532,19 +611,19 @@ db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
BOOST_FOREACH(const std::string &name, lms_tx_gain_ranges.keys()){
this->get_tx_subtree()->create<double>("gains/"+name+"/value")
.coerce(boost::bind(&db_lms6002d::set_tx_gain, this, _1, name))
.coerce(boost::bind(&lms6002d_ctrl_impl::set_tx_gain, this, _1, name))
.set((lms_tx_gain_ranges[name].start()+lms_tx_gain_ranges[name].stop())/2.0);
this->get_tx_subtree()->create<meta_range_t>("gains/"+name+"/range")
.set(lms_tx_gain_ranges[name]);
}
this->get_tx_subtree()->create<double>("freq/value")
.coerce(boost::bind(&db_lms6002d::set_freq, this, dboard_iface::UNIT_TX, _1));
.coerce(boost::bind(&lms6002d_ctrl_impl::set_freq, this, dboard_iface::UNIT_TX, _1));
this->get_tx_subtree()->create<meta_range_t>("freq/range")
.set(lms_freq_range);
this->get_tx_subtree()->create<std::string>("antenna/value")
.subscribe(boost::bind(&db_lms6002d::set_tx_ant, this, _1))
.subscribe(boost::bind(&lms6002d_ctrl_impl::set_tx_ant, this, _1))
.set("TX2");
this->get_tx_subtree()->create<std::vector<std::string> >("antenna/options")
.set(lms_tx_antennas);
@@ -553,21 +632,22 @@ db_lms6002d::db_lms6002d(ctor_args_t args) : xcvr_dboard_base(args),
.set(sensor_value_t("LO", true, "locked", "unlocked"));
this->get_tx_subtree()->create<std::string>("connection").set("IQ");
this->get_tx_subtree()->create<bool>("enabled")
.coerce(boost::bind(&db_lms6002d::set_enabled, this, dboard_iface::UNIT_TX, _1));
.coerce(boost::bind(&lms6002d_ctrl_impl::set_enabled, this, dboard_iface::UNIT_TX, _1));
this->get_tx_subtree()->create<bool>("use_lo_offset").set(false);
this->get_tx_subtree()->create<double>("bandwidth/value")
.coerce(boost::bind(&db_lms6002d::set_tx_bandwidth, this, _1))
.coerce(boost::bind(&lms6002d_ctrl_impl::set_tx_bandwidth, this, _1))
.set(double(2*0.75e6));
this->get_tx_subtree()->create<meta_range_t>("bandwidth/range")
.set(lms_bandwidth_range);
// UmTRX specific calibration
this->get_tx_subtree()->create<uint8_t>("lms6002d/tx_dc_i/value")
.subscribe(boost::bind(&db_lms6002d::_set_tx_vga1dc_i_int, this, _1))
.subscribe(boost::bind(&lms6002d_ctrl_impl::_set_tx_vga1dc_i_int, this, _1))
.publish(boost::bind(&umtrx_lms6002d_dev::get_tx_vga1dc_i_int, &lms));
this->get_tx_subtree()->create<uint8_t>("lms6002d/tx_dc_q/value")
.subscribe(boost::bind(&db_lms6002d::_set_tx_vga1dc_q_int, this, _1))
.subscribe(boost::bind(&lms6002d_ctrl_impl::_set_tx_vga1dc_q_int, this, _1))
.publish(boost::bind(&umtrx_lms6002d_dev::get_tx_vga1dc_q_int, &lms));
*/
}

View File

@@ -0,0 +1,50 @@
#ifndef INCLUDED_LMS6002D_CTRL_HPP
#define INCLUDED_LMS6002D_CTRL_HPP
#include <uhd/types/ranges.hpp>
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
/***********************************************************************
* The interface to lms6002d that get registered into the property tree
**********************************************************************/
class lms6002d_ctrl
{
public:
typedef boost::shared_ptr<lms6002d_ctrl> sptr;
static sptr make(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate);
virtual double set_rx_freq(const double freq) = 0;
virtual double set_tx_freq(const double freq) = 0;
virtual bool set_rx_enabled(const bool enb) = 0;
virtual bool set_tx_enabled(const bool enb) = 0;
virtual double set_rx_gain(const double gain, const std::string &name) = 0;
virtual double set_tx_gain(const double gain, const std::string &name) = 0;
virtual void set_rx_ant(const std::string &ant) = 0;
virtual void set_tx_ant(const std::string &ant) = 0;
virtual double set_rx_bandwidth(const double bandwidth) = 0;
virtual double set_tx_bandwidth(const double bandwidth) = 0;
virtual uhd::freq_range_t get_rx_bw_range(void) = 0;
virtual uhd::freq_range_t get_tx_bw_range(void) = 0;
virtual uhd::freq_range_t get_rx_freq_range(void) = 0;
virtual uhd::freq_range_t get_tx_freq_range(void) = 0;
virtual std::vector<std::string> get_tx_antennas(void) = 0;
virtual std::vector<std::string> get_rx_antennas(void) = 0;
virtual std::vector<std::string> get_tx_gains(void) = 0;
virtual std::vector<std::string> get_rx_gains(void) = 0;
virtual uhd::gain_range_t get_rx_gain_range(const std::string &name) = 0;
virtual uhd::gain_range_t get_tx_gain_range(const std::string &name) = 0;
};
#endif /* INCLUDED_LMS6002D_CTRL_HPP */