Add PA control logic

This commit is contained in:
Sergey Kostanbaev
2014-12-21 13:07:20 +03:00
parent 90b619f4b9
commit e08b40758a
9 changed files with 248 additions and 9 deletions

View File

@@ -227,6 +227,13 @@ NET "AUX_XX" LOC = AA6; // empty awhile
NET "AUX_SCL" LOC = AB7;// I2C clock (teperature sensor etc.)
NET "AUX_SDA" LOC = AB10;// I2C data (teperature sensor etc.)
## PA control
NET "ENPA2" LOC = AB21;
NET "ENPA1" LOC = AA21;
NET "LOWPA" LOC = Y12;
#NET "DC_SYNC" LOC = AA6;
## LEDS
NET "leds[1]" LOC = Y3;
NET "leds[2]" LOC = W4;
@@ -234,7 +241,7 @@ NET "leds[3]" LOC = AB2;
NET "leds[4]" LOC = Y4;
NET "leds[5]" LOC = AA2;
NET "led_stat" LOC = AB3; // output for clock status (or something else) front panel LED !!!
// was stupid "master clock" LED indicator
// was stupid "master clock" LED indicator
### Debug // a lot changes !!!
NET "debug[0]" LOC = D22;
@@ -314,6 +321,11 @@ NET "TXD[1]" IOSTANDARD = LVCMOS33;// FPGA input <- FTDI input !!! in v1a was o
NET "TXD[2]" IOSTANDARD = LVCMOS33;// FPGA input <- GPS input !!! in v1a was output !!!
NET "TXD[3]" IOSTANDARD = LVCMOS33;
NET "enpa2" IOSTANDARD = LVCMOS33;
NET "enpa1" IOSTANDARD = LVCMOS33;
NET "lowpa" IOSTANDARD = LVCMOS33;
#NET "DC_SYNC" IOSTANDARD = LVCMOS33;
NET "DivSw1_N" IOSTANDARD = LVCMOS25;
NET "DivSw1_P" IOSTANDARD = LVCMOS25;
NET "DivSw2_N" IOSTANDARD = LVCMOS25;

View File

@@ -77,6 +77,11 @@ module u2plus_umtrx_v2
inout AUX_SCL,
inout AUX_SDA,
//PA control
output ENPA2,
output ENPA1,
output LOWPA,
// PPS
input PPS_IN,
output GPS_ON,
@@ -305,6 +310,10 @@ wire DivSw1, DivSw2;
assign GPS_ON = 1'b1;
assign pps = PPS_IN;
wire enpa2_o, enpa1_o, lowpa_o;
OBUF enpa2_pin (.I(enpa2_o),.O(ENPA2));
OBUF enpa1_pin (.I(enpa1_o),.O(ENPA1));
OBUF lowpa_pin (.I(lowpa_o),.O(LOWPA));
umtrx_core u2p_c(
.sys_clk (dsp_clk),
@@ -370,6 +379,10 @@ wire DivSw1, DivSw2;
//Diversity switches
.DivSw1(DivSw1),
.DivSw2(DivSw2),
//PA control
.enpa2(enpa2_o),
.enpa1(enpa1_o),
.lowpa(lowpa_o),
`ifndef NO_EXT_FIFO
.RAM_D_po (RAM_D_po),
.RAM_D_pi (RAM_D_pi),

View File

@@ -107,6 +107,11 @@ module umtrx_core
input aux_ld1,
input aux_ld2,
//PA control
output enpa2,
output enpa1,
output lowpa,
`ifndef NO_EXT_FIFO
// External RAM
input [35:0] RAM_D_pi,
@@ -549,7 +554,7 @@ module umtrx_core
assign PHY_RESETn = ~phy_reset;
setting_reg #(.my_addr(SR_MISC+0),.width(2)) sr_lms_res
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(lms_res),.changed());
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out({enpa2, enpa1, lowpa, lms_res}),.changed());
setting_reg #(.my_addr(SR_MISC+1),.width(1)) sr_clear_sfc
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),.changed(sfc_clear));

View File

@@ -55,9 +55,11 @@ static const uhd::dict<std::string, boost::uint8_t> UMTRX_OFFSETS = boost::assig
("tcxo-dac", 0xFF-3) // 2 bytes
("tx2-vga1-dc-i", 0xFF-4) // 1 byte
("tx2-vga1-dc-q", 0xFF-5) // 1 byte
("pa_dcdc_r", 0xFF-6) // 1 byte
("pa_low", 0xFF-7) // 1 byte
;
#if 0x18 + SERIAL_LEN + NAME_MAX_LEN >= 0xFF-5
#if 0x18 + SERIAL_LEN + NAME_MAX_LEN >= 0xFF-7
# error EEPROM address overlap! Get a bigger EEPROM.
#endif
@@ -87,6 +89,14 @@ void load_umtrx_eeprom(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
mb_eeprom["tcxo-dac"] = uint16_bytes_to_string(
iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["tcxo-dac"], 2)
);
mb_eeprom["pa_dcdc_r"] =
boost::lexical_cast<std::string>(unsigned(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_dcdc_r"], 1).at(0)));
{
uint8_t val = int(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_low"], 1).at(0));
mb_eeprom["pa_low"] = (val==255)?"":boost::lexical_cast<std::string>(int(val));
}
}
void store_umtrx_eeprom(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
@@ -115,4 +125,14 @@ void store_umtrx_eeprom(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
N100_EEPROM_ADDR, UMTRX_OFFSETS["tcxo-dac"],
string_to_uint16_bytes(mb_eeprom["tcxo-dac"])
);
if (mb_eeprom.has_key("pa_dcdc_r")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_dcdc_r"],
byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["pa_dcdc_r"]))
);
if (mb_eeprom.has_key("pa_low")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_dcdc_r"],
byte_vector_t(1, boost::lexical_cast<int>(mb_eeprom["pa_low"]))
);
}

View File

@@ -558,6 +558,13 @@ umtrx_impl::~umtrx_impl(void)
}
}
void umtrx_impl::set_pa_dcdc_r(uint8_t val)
{
// AD5245 control
if (_hw_rev >= UMTRX_VER_2_3_1)
_iface->write_i2c(BOOST_BINARY(0101100), boost::assign::list_of(0)(val));
}
void umtrx_impl::set_mb_eeprom(const uhd::i2c_iface::sptr &iface, const uhd::usrp::mboard_eeprom_t &eeprom)
{
store_umtrx_eeprom(eeprom, *iface);
@@ -693,8 +700,60 @@ void umtrx_impl::detect_hw_rev(const fs_path& mb_path)
UHD_MSG(status) << this->read_dc_v(dc_sensors[i]).to_pp_string() << std::endl;
}
_hw_rev = UMTRX_VER_2_3_1;
_tree->create<uint8_t>(mb_path / "pa_dcdc_r")
.subscribe(boost::bind(&umtrx_impl::set_pa_dcdc_r, this, _1));
const std::string pa_dcdc_r = _iface->mb_eeprom.get("pa_low", "");
if (pa_dcdc_r.empty())
set_pa_dcdc_r(0);
else
set_pa_dcdc_r(boost::lexical_cast<unsigned>(pa_dcdc_r));
_pa_en1 = false;
_pa_en2 = false;
const std::string pa_low = _iface->mb_eeprom.get("pa_low", "");
if (pa_low.empty())
_pa_nlow = false;
else
_pa_nlow = (boost::lexical_cast<int>(pa_low) == 0);
_tree->create<bool>(mb_path / "pa_en1")
.subscribe(boost::bind(&umtrx_impl::set_enpa1, this, _1));
_tree->create<bool>(mb_path / "pa_en2")
.subscribe(boost::bind(&umtrx_impl::set_enpa2, this, _1));
_tree->create<bool>(mb_path / "pa_nlow")
.subscribe(boost::bind(&umtrx_impl::set_nlow, this, _1));
commit_pa_state();
UHD_MSG(status) << "PA low=`" << pa_low.c_str()
<< "` PA dcdc_r=`" << pa_dcdc_r.c_str()
<< "`" << std::endl;
}
void umtrx_impl::commit_pa_state()
{
if (_hw_rev >= UMTRX_VER_2_3_1)
_iface->poke32(U2_REG_MISC_LMS_RES, LMS1_RESET | LMS2_RESET
| ((_pa_nlow) ? PAREG_NLOW_PA : 0)
| ((_pa_en1) ? PAREG_ENPA1 : 0)
| ((_pa_en2) ? PAREG_ENPA2 : 0));
}
void umtrx_impl::set_enpa1(bool en)
{
_pa_en1 = en; commit_pa_state();
}
void umtrx_impl::set_enpa2(bool en)
{
_pa_en2 = en; commit_pa_state();
}
void umtrx_impl::set_nlow(bool en)
{
_pa_nlow = en; commit_pa_state();
}
const char* umtrx_impl::get_hw_rev() const

View File

@@ -129,6 +129,11 @@ private:
tmp102_ctrl _temp_side_a;
tmp102_ctrl _temp_side_b;
//PA control
bool _pa_nlow;
bool _pa_en1;
bool _pa_en2;
//controls for perifs
uhd::dict<std::string, lms6002d_ctrl::sptr> _lms_ctrl;
@@ -140,6 +145,7 @@ private:
time64_core_200::sptr _time64;
//helper routines
void set_pa_dcdc_r(uint8_t val);
void set_mb_eeprom(const uhd::i2c_iface::sptr &, const uhd::usrp::mboard_eeprom_t &);
double get_master_clock_rate(void) const { return 26e6; }
double get_master_dsp_rate(void) const { return get_master_clock_rate()/2; }
@@ -155,6 +161,10 @@ private:
void set_tx_fe_corrections(const std::string &mb, const std::string &board, const double);
void set_tcxo_dac(const umtrx_iface::sptr &, const uint16_t val);
void detect_hw_rev(const uhd::fs_path &mb_path);
void commit_pa_state();
void set_enpa1(bool en);
void set_enpa2(bool en);
void set_nlow(bool en);
uint16_t get_tcxo_dac(const umtrx_iface::sptr &);
uhd::transport::zero_copy_if::sptr make_xport(const size_t which, const uhd::device_addr_t &args);

View File

@@ -39,7 +39,7 @@
////////////////////////////////////////////////////////////////////////
// Setting register offsets
////////////////////////////////////////////////////////////////////////
localparam SR_MISC = 0; // 7 regs
localparam SR_MISC = 0; // 9 regs
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
@@ -123,4 +123,9 @@ localparam SR_SPI_CORE = 185; // 3
#define LMS1_RESET (1<<0)
#define LMS2_RESET (1<<1)
// Defined for the U2_REG_MISC_LMS_RES register
#define PAREG_NLOW_PA (1<<2)
#define PAREG_ENPA1 (1<<3)
#define PAREG_ENPA2 (1<<4)
#endif

View File

@@ -13,3 +13,8 @@ install(TARGETS umtrx_test_chains 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)
add_executable(umtrx_pa_ctrl umtrx_pa_ctrl.cpp)
target_link_libraries(umtrx_pa_ctrl ${UMTRX_LIBRARIES})
install(TARGETS umtrx_pa_ctrl DESTINATION bin)

View File

@@ -0,0 +1,110 @@
//
// Copyright 2014 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;
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
unsigned pa_dcdc_r = 0;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "help message")
("verbose", "enable some verbose")
("debug_raw_data", "save raw captured signals to files")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("dcdc_cal,C", "Calibrate DC/DC")
("paen1", "Enable PA1")
("paen2", "Enable PA2")
("padis1", "Disable PA1")
("padis2", "Disable PA2")
("palow", "Turn off internal DC/DC")
("pa_dcdc_r", po::value<unsigned>(&pa_dcdc_r),"Turn on internal DC/DC")
;
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";
if (vm.count("paen1")) {
tree->access<bool>(mb_path / "pa_en1").set(true);
}
if (vm.count("paen2")) {
tree->access<bool>(mb_path / "pa_en2").set(true);
}
if (vm.count("palow")) {
tree->access<bool>(mb_path / "pa_nlow").set(false);
}
if (vm.count("padis1")) {
tree->access<bool>(mb_path / "pa_en1").set(false);
}
if (vm.count("padis2")) {
tree->access<bool>(mb_path / "pa_en2").set(false);
}
if (vm.count("pa_dcdc_r")) {
tree->access<bool>(mb_path / "pa_nlow").set(true);
tree->access<uint8_t>(mb_path / "pa_dcdc_r").set(pa_dcdc_r);
}
if (vm.count("dcdc_cal")) {
tree->access<bool>(mb_path / "pa_nlow").set(true);
unsigned i;
for (i = 0; i < 256; i++) {
tree->access<uint8_t>(mb_path / "pa_dcdc_r").set(i);
usleep(100 * 1000); // Wait for value to settle
std::cout << "[" << std::setw(3) << i << "]="
<< tree->access<uhd::sensor_value_t>(mb_path / "sensors" / "voltageDCOUT").get().to_pp_string().c_str()
<< std::endl;
}
}
return 0;
}