Merge branch 'umtrx_gains' into umtrx_update

This commit is contained in:
Josh Blum
2015-04-06 12:32:21 -07:00
5 changed files with 181 additions and 33 deletions

View File

@@ -164,11 +164,18 @@ void lms6002d_dev::init()
write_reg(0x09, 0x00); // RXOUTSW (disabled), CLK_EN (all disabled)
write_reg(0x17, 0xE0);
write_reg(0x27, 0xE3);
write_reg(0x64, 0x32);
write_reg(0x70, 0x01);
write_reg(0x79, 0x37);
write_reg(0x59, 0x09);
write_reg(0x47, 0x40);
// FAQ v1.0r12, 5.27:
write_reg(0x47, 0x40); // Improving Tx spurious emission performance
write_reg(0x59, 0x29); // Improving ADCs performance
write_reg(0x64, 0x36); // Common Mode Voltage For ADCs
write_reg(0x79, 0x37); // Higher LNA Gain
// Power down DC comparators to improve the receiver linearity
// (see FAQ v1.0r12, 5.26)
lms_set_bits(0x6E, (0x3 << 6));
lms_set_bits(0x5F, (0x1 << 7));
// Disable AUX PA
// PA_EN[0]:AUXPA = 0 (powered up) - for mask set v1
@@ -241,6 +248,10 @@ int lms6002d_dev::general_dc_calibration_loop(uint8_t dc_addr, uint8_t calibrati
int lms6002d_dev::general_dc_calibration(uint8_t dc_addr, uint8_t calibration_reg_base)
{
// Power up DC comparators
lms_clear_bits(0x6E, (0x3 << 6));
lms_clear_bits(0x5F, (0x1 << 7));
// Set DC_REGVAL to 31
write_reg(calibration_reg_base+0x00, 31);
// Run the calibration first time
@@ -264,6 +275,11 @@ int lms6002d_dev::general_dc_calibration(uint8_t dc_addr, uint8_t calibration_re
}
}
// Power down DC comparators to improve the receiver linearity
// (see FAQ v1.0r12, 5.26)
lms_set_bits(0x6E, (0x3 << 6));
lms_set_bits(0x5F, (0x1 << 7));
if (verbosity > 0) printf("Successful DC Offset Calibration for register bank 0x%X, DC addr %d. Result: 0x%X\n",
calibration_reg_base, dc_addr, DC_REGVAL);
return DC_REGVAL;

View File

@@ -121,9 +121,9 @@ public:
gain is in [-4 .. -35] dB range
Returns the old gain value */
int8_t set_tx_vga1gain(int8_t gain) {
/* Safety check */
if (not(-35 <= gain and gain <= -4))
gain = -35;
//clip
if (gain < -35) gain = -35;
if (gain > -4) gain = -4;
int8_t old_bits = lms_write_bits(0x41, 0x1f, 35 + gain);
return (old_bits & 0x1f) - 35;
}
@@ -155,9 +155,9 @@ public:
gain is in dB [0 .. 25]
Returns the old gain value */
int8_t set_tx_vga2gain(int8_t gain) {
/* Safety check */
if (not(0 <= gain and gain <= 25))
gain = 0;
//clip
if (gain < 0) gain = 0;
if (gain > 25) gain = 25;
int8_t old_bits = lms_write_bits(0x45, (0x1f << 3), (gain << 3));
return old_bits >> 3;
}
@@ -175,9 +175,9 @@ public:
gain is in dB [0 .. 60]
Returns the old gain value */
int8_t set_rx_vga2gain(int8_t gain) {
/* Safety check */
if (not (0 <= gain and gain <= 60))
gain = 0;
//clip
if (gain < 0) gain = 0;
if (gain > 60) gain = 60;
int8_t old_bits = lms_write_bits(0x65, 0x1f, gain/3);
return (old_bits & 0x1f) * 3;
}

View File

@@ -61,10 +61,11 @@ static const std::vector<std::string> lms_tx_antennas = list_of("TX0")("TX1")("T
static const std::vector<std::string> lms_rx_antennas = list_of("RX0")("RX1")("RX2")("RX3")("CAL");
static const uhd::dict<std::string, gain_range_t> lms_tx_gain_ranges = map_list_of
// ("VGA1", gain_range_t(-35, -4, double(1.0)))
// ("VGA2", gain_range_t(0, 25, double(1.0)))
//listing VGA2 first means that overall gain is first distributed to VGA2
("VGA2", gain_range_t(0, 25, double(1.0)))
("VGA1", gain_range_t(-35, -4, double(1.0)))
// Use a single control to manually control how VGA1/VGA2 are set
("VGA", gain_range_t(-35+0, -4+25, double(1.0)))
// ("VGA", gain_range_t(-35+0, -4+25, double(1.0)))
;
static const uhd::dict<std::string, gain_range_t> lms_rx_gain_ranges = map_list_of
@@ -235,8 +236,10 @@ public:
assert_has(lms_rx_gain_ranges.keys(), name, "LMS6002D rx gain name");
if(name == "VGA1"){
lms.set_rx_vga1gain(gain);
return lms.get_rx_vga1gain();
} else if(name == "VGA2"){
lms.set_rx_vga2gain(gain);
return lms.get_rx_vga2gain();
} else UHD_THROW_INVALID_CODE_PATH();
return gain;
}
@@ -290,23 +293,14 @@ public:
//validate input
assert_has(lms_tx_gain_ranges.keys(), name, "LMS6002D tx gain name");
if (name == "VGA") {
// Calculate the best combination of VGA1 and VGA2 gains.
// For simplicity we just try to use VGA2 as much as possible
// and only then engage VGA1.
int desired_vga2 = int(gain) - tx_vga1gain;
if (desired_vga2 < 0)
tx_vga2gain = 0;
else if (desired_vga2 > 25)
tx_vga2gain = 25;
else
tx_vga2gain = desired_vga2;
tx_vga1gain = int(gain) - tx_vga2gain;
// Set the gains in hardware
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);
if (name == "VGA1") {
if (verbosity>1) printf("db_lms6002d::set_tx_gain() VGA1=%d\n", int(gain));
lms.set_tx_vga1gain(int(gain));
return lms.get_tx_vga1gain();
} else if (name == "VGA2") {
if (verbosity>1) printf("db_lms6002d::set_tx_gain() VGA2=%d\n", int(gain));
lms.set_tx_vga2gain(int(gain));
return lms.get_tx_vga2gain();
} else {
UHD_THROW_INVALID_CODE_PATH();
}

View File

@@ -10,6 +10,10 @@ add_executable(umtrx_test_chains umtrx_test_chains.cpp)
target_link_libraries(umtrx_test_chains ${UMTRX_LIBRARIES})
install(TARGETS umtrx_test_chains DESTINATION bin)
add_executable(umtrx_test_gains umtrx_test_gains.cpp)
target_link_libraries(umtrx_test_gains ${UMTRX_LIBRARIES})
install(TARGETS umtrx_test_gains DESTINATION bin)
add_executable(umtrx_cal_tx_dc_offset umtrx_cal_tx_dc_offset.cpp)
target_link_libraries(umtrx_cal_tx_dc_offset ${UMTRX_LIBRARIES})
install(TARGETS umtrx_cal_tx_dc_offset DESTINATION bin)

View File

@@ -0,0 +1,134 @@
//
// Copyright 2015 Fairwaves 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 <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/sensors.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/random.hpp>
#include <iostream>
#include <complex>
#include <cmath>
#include <ctime>
namespace po = boost::program_options;
static size_t failCount = 0;
#define CHECK(expr, expected) { \
const double actual = expr; \
const bool ok = (actual == expected); \
if (not ok) failCount++; \
std::cout << "Check: " << #expr << " == " << #expected << "\t\t\t" << ((ok)?"OK":"FAIL") << std::endl; \
if (not ok) std::cout << "\t FAIL: actual = " << actual << std::endl; }
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[])
{
std::string args;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "help message")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << desc << std::endl;
return ~0;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path mb_path = "/mboards/0";
//get the spi-interface to check gain values
uhd::spi_iface::sptr spiface = tree->access<uhd::spi_iface::sptr>(mb_path / "spi_iface").get();
for (size_t ch = 0; ch <= 1; ch++)
{
std::cout << std::endl << "==== Testing channel: " << ch << std::endl;
std::cout << std::endl << "Check RX gain ranges:" << std::endl;
CHECK(usrp->get_rx_gain_range("VGA1", ch).start(), 0);
CHECK(usrp->get_rx_gain_range("VGA1", ch).stop(), 126);
CHECK(usrp->get_rx_gain_range("VGA2", ch).start(), 0);
CHECK(usrp->get_rx_gain_range("VGA2", ch).stop(), 30);
CHECK(usrp->get_rx_gain_range(ch).start(), 0);
CHECK(usrp->get_rx_gain_range(ch).stop(), 156);
std::cout << std::endl << "Check TX gain ranges:" << std::endl;
CHECK(usrp->get_tx_gain_range("VGA1", ch).start(), -35);
CHECK(usrp->get_tx_gain_range("VGA1", ch).stop(), -4);
CHECK(usrp->get_tx_gain_range("VGA2", ch).start(), 0);
CHECK(usrp->get_tx_gain_range("VGA2", ch).stop(), 25);
CHECK(usrp->get_tx_gain_range(ch).start(), -35);
CHECK(usrp->get_tx_gain_range(ch).stop(), 21);
std::cout << std::endl << "Test RX gain distribution:" << std::endl;
usrp->set_rx_gain(0, ch);
CHECK(usrp->get_rx_gain(ch), 0);
CHECK(usrp->get_rx_gain("VGA1", ch), 0);
CHECK(usrp->get_rx_gain("VGA2", ch), 0);
usrp->set_rx_gain(15, ch);
CHECK(usrp->get_rx_gain(ch), 15);
CHECK(usrp->get_rx_gain("VGA1", ch), 15);
CHECK(usrp->get_rx_gain("VGA2", ch), 0);
usrp->set_rx_gain(129, ch);
CHECK(usrp->get_rx_gain(ch), 129);
CHECK(usrp->get_rx_gain("VGA1", ch), 126);
CHECK(usrp->get_rx_gain("VGA2", ch), 3);
std::cout << std::endl << "Test TX gain distribution:" << std::endl;
usrp->set_tx_gain(-35, ch);
CHECK(usrp->get_tx_gain(ch), -35);
CHECK(usrp->get_tx_gain("VGA2", ch), 0);
CHECK(usrp->get_tx_gain("VGA1", ch), -35);
usrp->set_tx_gain(-10, ch);
CHECK(usrp->get_tx_gain(ch), -10);
CHECK(usrp->get_tx_gain("VGA2", ch), 0);
CHECK(usrp->get_tx_gain("VGA1", ch), -10);
usrp->set_tx_gain(10, ch);
CHECK(usrp->get_tx_gain(ch), 10);
CHECK(usrp->get_tx_gain("VGA2", ch), 14);
CHECK(usrp->get_tx_gain("VGA1", ch), -4);
}
//print status
std::cout << std::endl;
const bool fail = failCount > 0;
if (fail) std::cerr << std::endl << failCount << " TESTS FAILED!!!" << std::endl;
else std::cout << std::endl << "ALL TESTS PASSED" << std::endl;
std::cout << "Done!" << std::endl;
return fail?EXIT_FAILURE:EXIT_SUCCESS;
}