From ba658f4d2cac9fb0f9d22060da989c9078cc4d1e Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 21 Sep 2010 10:41:05 -0700 Subject: added db_tvrx, regmap gen_dtt75403_regs.py --- host/lib/usrp/dboard/db_tvrx.cpp | 316 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 host/lib/usrp/dboard/db_tvrx.cpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp new file mode 100644 index 000000000..5582dbe33 --- /dev/null +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -0,0 +1,316 @@ +// +// Copyright 2010 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 . +// + +// No RX IO Pins Used + +// RX IO Functions + +//ADC/DAC functions: +//DAC 1: RF AGC +//DAC 2: IF AGC + +//min freq: 50e6 +//max freq: 860e6 +//gain range: [0:1dB:115dB] + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The tvrx constants + **********************************************************************/ +static const bool tvrx_debug = true; + +static const freq_range_t tvrx_freq_range(50e6, 860e6); + +static const prop_names_t tvrx_antennas = ""; //only got one + +static const uhd::dict tvrx_gain_ranges = map_list_of + ("RF", gain_range_t(0, 60, float(60.0/4096))) //both gains are analog and controlled by DAC + ("IF", gain_range_t(0, 35, float(35.0/4096))) //the old driver used 1dB for both; i don't think that's right? +; + +static const uhd::dict tvrx_freq_ranges = map_list_of + ("VHFLO", freq_range_t(50e6, 158e6)) //this isn't used outside this driver. just for us. + ("VHFHI", freq_range_t(158e6, 454e6)) + ("UHF" , freq_range_t(454e6, 860e6)) +; + +//we might need to spec the various bands for band selection. + +static const double tvrx_lo_freq = 36e6; //LO freq of TVRX module + +/*********************************************************************** + * The tvrx dboard class + **********************************************************************/ +class tvrx : public rx_dboard_base{ +public: + tvrx(ctor_args_t args); + ~tvrx(void); + + void rx_get(const wax::obj &key, wax::obj &val); + void rx_set(const wax::obj &key, const wax::obj &val); + +private: + uhd::dict _gains; + dtt75403_regs_t _dtt75403_regs; + boost::uint8_t _dtt75403_addr(void){ + return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call + }; + + void set_gain(float gain, const std::string &name); + + void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ + //why is this an inline anyway? bring this out + start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); + stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5)); + + for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ + int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; + + //create buffer for register data (+1 for start address) + byte_vector_t regs_vector(num_bytes + 1); + + //first byte is the address of first register + regs_vector[0] = start_addr; + + //get the register data + for(int i=0; iget_iface()->write_i2c( + _max2118_addr(), regs_vector + ); + } + } + +}; + +/*********************************************************************** + * Register the tvrx dboard + **********************************************************************/ +static dboard_base::sptr make_tvrx(dboard_base::ctor_args_t args){ + return dboard_base::sptr(new tvrx(args)); +} + +UHD_STATIC_BLOCK(reg_tvrx_dboard){ + //register the factory function for the rx dbid + dboard_manager::register_dboard(0x0003, &make_tvrx, "tvrx"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ + //enable only the clocks we need + + //TODO: YOU GOT SOME CLOCK SETUP TO DO HERE, DOGGGG + + this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); + + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr + if (this->get_iface()->get_special_props().soft_clock_divider){ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock + } + else{ + this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs + } + + //send initial register settings + //HAAAAY GUYYYYYSSS + + //set default gains + BOOST_FOREACH(const std::string &name, tvrx_gain_ranges.keys()){ + set_gain(tvrx_gain_ranges[name].min, name); + } +} + +tvrx::~tvrx(void){ +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +/*! + * Convert a requested gain for the GC2 vga into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return 5 bit the register value + */ + +//yo this should look the same as the below one for the IF, dogg +static int gain_to_gc2_vga_reg(float &gain){ + int reg = 0; + gain = std::clip(float(boost::math::iround(gain)), tvrx_gain_ranges["GC2"].min, tvrx_gain_ranges["GC2"].max); + + // Half dB steps from 0-5dB, 1dB steps from 5-24dB + if (gain < 5) { + reg = boost::math::iround(31.0 - gain/0.5); + gain = float(boost::math::iround(gain) * 0.5); + } else { + reg = boost::math::iround(22.0 - (gain - 4.0)); + gain = float(boost::math::iround(gain)); + } + + if (tvrx_debug) std::cerr << boost::format( + "tvrx GC2 Gain: %f dB, reg: %d" + ) % gain % reg << std::endl; + + return reg; +} + +/*! + * Convert a requested gain for the RF gain into the dac_volts value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return dac voltage value + */ + +//yo what about the 1.22 opamp gain of the USRP1 -- is this replicated on U2? +static float gain_to_rfgain_dac(float &gain){ + //clip the input + gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + + //voltage level constants + static const float max_volts = float(0), min_volts = float(3.3); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + + //calculate the voltage for the aux dac + float dac_volts = gain*slope + min_volts; + + if (tvrx_debug) std::cerr << boost::format( + "tvrx RFAGC Gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; + + //the actual gain setting + gain = (dac_volts - min_volts)/slope; + + return dac_volts; +} + +void tvrx::set_gain(float gain, const std::string &name){ + assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); + if (name == "RF"){ +//should look the same as below + } + else if(name == "IF"){ + //write the new voltage to the aux dac CHECK THIS + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); + } + else UHD_THROW_INVALID_CODE_PATH(); + _gains[name] = gain; +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_NAME: + val = get_rx_id().to_pp_string(); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + assert_has(_gains.keys(), key.name, "tvrx gain name"); + val = _gains[key.name]; + return; + + case SUBDEV_PROP_GAIN_RANGE: + assert_has(tvrx_gain_ranges.keys(), key.name, "tvrx gain name"); + val = tvrx_gain_ranges[key.name]; + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(tvrx_gain_ranges.keys()); + return; + + case SUBDEV_PROP_FREQ: + val = tvrx_lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = tvrx_freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string(tvrx_antennas); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = tvrx_antennas; + return; + + case SUBDEV_PROP_CONNECTION: + val = SUBDEV_CONN_COMPLEX_IQ; + return; + + case SUBDEV_PROP_USE_LO_OFFSET: + val = false; + return; + + case SUBDEV_PROP_LO_LOCKED: + val = true; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +//for smaaht kids to use to set advanced props +void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_GAIN: + this->set_gain(val.as(), key.name); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + -- cgit v1.2.3 From 017e7202468a8800335c05afd4a85cb52c6171e6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 26 Sep 2010 21:07:43 -0700 Subject: usrp1: add print out messages when loading images --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 1dc6e6e25..76e8ce368 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -38,6 +38,8 @@ enum firmware_code { #define FX2_FIRMWARE_LOAD 0xa0 +static const bool load_img_msg = true; + /*********************************************************************** * Helper Functions **********************************************************************/ @@ -178,6 +180,7 @@ public: unsigned char reset_n = 0; //hit the reset line + if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush; usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); @@ -213,7 +216,7 @@ public: //wait for things to settle boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - + if (load_img_msg) std::cout << " done" << std::endl; return USRP_FIRMWARE_LOAD_SUCCESS; } //type anything else is unhandled @@ -249,6 +252,7 @@ public: unsigned char buf[ep0_size]; int ret; + if (load_img_msg) std::cout << "Loading FPGA image: " << filestring << "..." << std::flush; std::ifstream file; file.open(filename, std::ios::in | std::ios::binary); if (not file.good()) { @@ -282,6 +286,7 @@ public: usrp_set_fpga_hash(hash); file.close(); + if (load_img_msg) std::cout << " done" << std::endl; return 0; } -- cgit v1.2.3 From 2f62c39b7135728ed06faa06db46004323b1c70f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 27 Sep 2010 11:35:28 -0700 Subject: uhd: fix warning by adding brackets for while(cond){}; --- host/examples/test_async_messages.cpp | 2 +- host/lib/transport/libusb1_zero_copy.cpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/examples/test_async_messages.cpp b/host/examples/test_async_messages.cpp index 4c9d18121..0a5c076ea 100644 --- a/host/examples/test_async_messages.cpp +++ b/host/examples/test_async_messages.cpp @@ -58,7 +58,7 @@ void test_no_async_message(uhd::usrp::single_usrp::sptr sdev){ " Got unexpected event code 0x%x.\n" ) % async_md.event_code << std::endl; //clear the async messages - while (dev->recv_async_msg(async_md, 0)); + while (dev->recv_async_msg(async_md, 0)){}; } else{ std::cout << boost::format( diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index d3888240b..b089d11e0 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -184,7 +184,7 @@ usb_endpoint::~usb_endpoint(void){ } //collect canceled transfers (drain the queue) - while (this->get_lut_with_wait() != NULL); + while (this->get_lut_with_wait() != NULL){}; //free all transfers BOOST_FOREACH(libusb_transfer *lut, _all_luts){ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 91a1b2344..65411801d 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -150,7 +150,7 @@ void usrp2_impl::io_init(void){ std::memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->commit(sizeof(data)); //drain the recv buffers (may have junk) - while (data_transport->get_recv_buff().get()); + while (data_transport->get_recv_buff().get()){}; } //the number of recv frames is the number for the first transport -- cgit v1.2.3 From fd15965442d5a8805a4730022f8d500841f8448d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 27 Sep 2010 16:04:04 -0700 Subject: usrp1: filter the discovery routine on the serial --- host/lib/usrp/usrp1/usrp1_impl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 627180b11..80ea49e9d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -96,7 +96,10 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); - usrp1_addrs.push_back(new_addr); + //this is a found usrp1 when a hint serial is not specified or it matches + if (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]){ + usrp1_addrs.push_back(new_addr); + } } return usrp1_addrs; -- cgit v1.2.3 From a6f60ab4911fa756656a62ebe3a1093d52836a6e Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Mon, 27 Sep 2010 19:19:55 -0700 Subject: TVRX: not done yet but getting there. gain linearization framework in place. --- host/lib/ic_reg_maps/CMakeLists.txt | 4 +- host/lib/ic_reg_maps/gen_dtt75403_regs.py | 85 ---------- host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py | 75 +++++++++ host/lib/usrp/dboard/db_tvrx.cpp | 218 +++++++++++++++++-------- 4 files changed, 225 insertions(+), 157 deletions(-) delete mode 100755 host/lib/ic_reg_maps/gen_dtt75403_regs.py create mode 100644 host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py (limited to 'host/lib/usrp') diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt index b396db4ca..25f34a280 100644 --- a/host/lib/ic_reg_maps/CMakeLists.txt +++ b/host/lib/ic_reg_maps/CMakeLists.txt @@ -70,6 +70,6 @@ LIBUHD_PYTHON_GEN_SOURCE( ) LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_dtt75403_regs.py - ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/dtt75403_regs.py + ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_tuner_4937di5_regs.py + ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/tuner_4937di5_regs.hpp ) diff --git a/host/lib/ic_reg_maps/gen_dtt75403_regs.py b/host/lib/ic_reg_maps/gen_dtt75403_regs.py deleted file mode 100755 index fe64bd92a..000000000 --- a/host/lib/ic_reg_maps/gen_dtt75403_regs.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2010 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 . -# - -######################################################################## -# Template for raw text data describing registers -# name addr[bit range inclusive] default optional enums -######################################################################## -REGS_TMPL="""\ -######################################################################## -## Note: offsets given from perspective of data bits (excludes address) -######################################################################## -## -######################################################################## -## Address byte -######################################################################## -adb 0[1:2] 0 -######################################################################## -## Divider byte 1 -######################################################################## -db1 1[0:6] 0x00 -######################################################################## -## Divider byte 2 -######################################################################## -db2 2[0:7] 0x00 -######################################################################## -## Control byte 1 -######################################################################## -atp 3[3:5] 0 112, 109, 106, 103, 100, 94, 94, disable -refdiv 3[0:2] 0 166.667khz, 142.857khz, 80khz, 62.5khz, 31.25khz, 50khz -######################################################################## -## Band switch byte -######################################################################## -cpsel 4[6:7] 0 -filterbw 4[4] 0 8mhz, 7mhz -bandsel 4[0:3] 0 -######################################################################## -## Control byte 2 -######################################################################## -atc 5[5] 0 low, high -stby 5[4] 0 standby, on -xto 5[0] 0 disable, enable -""" - -######################################################################## -# Template for methods in the body of the struct -######################################################################## -BODY_TMPL="""\ -boost::uint8_t get_reg(boost::uint8_t addr){ - boost::uint8_t reg = 0; - switch(addr){ - #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) - case $addr: - #for $reg in filter(lambda r: r.get_addr() == addr, $regs) - reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); - #end for - break; - #end for - } - return boost::uint8_t(reg); -} - -""" - -if __name__ == '__main__': - import common; common.generate( - name='dtt75403_regs', - regs_tmpl=REGS_TMPL, - body_tmpl=BODY_TMPL, - file=__file__, - ) diff --git a/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py new file mode 100644 index 000000000..73f7aa3db --- /dev/null +++ b/host/lib/ic_reg_maps/gen_tuner_4937di5_regs.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# Copyright 2010 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 . +# + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_TMPL="""\ +######################################################################## +## Note: offsets given from perspective of data bits (excludes address) +######################################################################## +## Divider byte 1 +######################################################################## +db1 0[0:6] 0x00 +######################################################################## +## Divider byte 2 +######################################################################## +db2 1[0:7] 0x00 +######################################################################## +## Control byte 1 +######################################################################## +cb7 2[7] 0x01 +cp 2[6] 0x00 low,high +os 2[0] 0x00 on,off +rs 2[1:2] 0x00 d512=3,d640=0,d1024=1 +test 2[3:5] 0x01 normal=0x01,cpoff=0x02,cpsink=0x06,cpsrc=0x07,cptest1=0x04,cptest2=0x05 +######################################################################## +## Control byte 2 +######################################################################## +bandsel 3[4:7] 0x03 uhf=0x03,vhfhi=0x09,vhflo=0x0a +power 3[3] 0x00 on,off +""" + +######################################################################## +# Template for methods in the body of the struct +######################################################################## +BODY_TMPL="""\ +boost::uint8_t get_reg(boost::uint8_t addr){ + boost::uint8_t reg = 0; + switch(addr){ + #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) + case $addr: + #for $reg in filter(lambda r: r.get_addr() == addr, $regs) + reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); + #end for + break; + #end for + } + return boost::uint8_t(reg); +} + +""" + +if __name__ == '__main__': + import common; common.generate( + name='tuner_4937di5_regs', + regs_tmpl=REGS_TMPL, + body_tmpl=BODY_TMPL, + file=__file__, + ) diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 5582dbe33..ed6025433 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -42,6 +42,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -57,19 +58,73 @@ static const freq_range_t tvrx_freq_range(50e6, 860e6); static const prop_names_t tvrx_antennas = ""; //only got one static const uhd::dict tvrx_gain_ranges = map_list_of - ("RF", gain_range_t(0, 60, float(60.0/4096))) //both gains are analog and controlled by DAC - ("IF", gain_range_t(0, 35, float(35.0/4096))) //the old driver used 1dB for both; i don't think that's right? + ("RF", gain_range_t(-13.3, 50.3, float(50.3/4096))) //both gains are analog and controlled by DAC + ("IF", gain_range_t(-1.5, 32.5, float(32.5/4096))) //the old driver used 1dB for both; i don't think that's right? ; static const uhd::dict tvrx_freq_ranges = map_list_of - ("VHFLO", freq_range_t(50e6, 158e6)) //this isn't used outside this driver. just for us. + ("VHFLO", freq_range_t(50e6, 158e6)) ("VHFHI", freq_range_t(158e6, 454e6)) ("UHF" , freq_range_t(454e6, 860e6)) ; -//we might need to spec the various bands for band selection. +//gain linearization data +//this is from the datasheet and is dB vs. volts (below) +//i tried to curve fit this, but it's really just so nonlinear that you'd +//need dang near as many coefficients as to just map it like this and interp. +//these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate +//but if it's better than the old linear fit i'm happy +static const uhd::dict > tvrx_rf_gains_db = map_list_of + ("VHFLO", std::vector(-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, + 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, + 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, + 50.30000, 50.30000)) + ("VHFHI", std::vector(-13.3000, -13.3000, -13.3000, -1.0000, 7.7000, + 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, + 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, + 48.2000, 48.2000)) + ("UHF" , std::vector(-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, + 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, + 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, + 43.2000, 43.8000)) +; + +static const std::vector tvrx_if_gains_db = + std::vector(-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, + 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, + 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, + 32.50000, 32.50000) +; + +//sample voltages for the above points +static const std::vector tvrx_rf_gains_volts = + std::vector(0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0); -static const double tvrx_lo_freq = 36e6; //LO freq of TVRX module + +/*! + * Execute a linear interpolation to find the voltage corresponding to a desired gain + * \param gain the desired gain in dB + * \param db_vector the vector of dB readings + * \param volts_vector the corresponding vector of voltages db_vector was sampled at + * \return a voltage to feed the TVRX analog gain + */ + +static float gain_interp(float gain, std::vector db_vector, std::vector volts_vector) { + float volts; + gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here + + boost::uint8_t gain_step = 0; + for(int i = 0; i < db_vector.size()-1; i++) { + if(gain > db_vector[i] && gain < db_vector.[i+1]) gain_step = i; + } + + + return volts; +} + +static const double opamp_gain = 1.22; //onboard DAC opamp gain +static const double tvrx_lo_freq = 43.75e6; //LO freq of TVRX module +static const boost::uint16_t reference_divider = 640; //clock reference divider to use /*********************************************************************** * The tvrx dboard class @@ -84,40 +139,28 @@ public: private: uhd::dict _gains; - dtt75403_regs_t _dtt75403_regs; - boost::uint8_t _dtt75403_addr(void){ + tuner_4937di5_regs_t _tuner_4937di5_regs; + boost::uint8_t _tuner_4937di5_addr(void){ return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); - void send_reg(boost::uint8_t start_reg, boost::uint8_t stop_reg){ - //why is this an inline anyway? bring this out - start_reg = boost::uint8_t(std::clip(int(start_reg), 0x0, 0x5)); - stop_reg = boost::uint8_t(std::clip(int(stop_reg), 0x0, 0x5)); - - for(boost::uint8_t start_addr=start_reg; start_addr <= stop_reg; start_addr += sizeof(boost::uint32_t) - 1){ - int num_bytes = int(stop_reg - start_addr + 1) > int(sizeof(boost::uint32_t)) - 1 ? sizeof(boost::uint32_t) - 1 : stop_reg - start_addr + 1; - - //create buffer for register data (+1 for start address) - byte_vector_t regs_vector(num_bytes + 1); + void update_regs(void){ + byte_vector_t regs_vector(4); - //first byte is the address of first register - regs_vector[0] = start_addr; - - //get the register data - for(int i=0; iget_iface()->write_i2c( - _max2118_addr(), regs_vector - ); + //get the register data + for(int i=0; i<4; i++){ + regs_vector[i] = _tuner_4937di5_regs.get_reg(i); + if(tvrx_debug) std::cerr << boost::format( + "tvrx: send reg 0x%02x, value 0x%04x" + ) % int(i) % int(regs_vector[i]) << std::endl; } + + //send the data + this->get_iface()->write_i2c( + _tuner_4937di5_addr(), regs_vector + ); } }; @@ -138,10 +181,6 @@ UHD_STATIC_BLOCK(reg_tvrx_dboard){ * Structors **********************************************************************/ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ - //enable only the clocks we need - - //TODO: YOU GOT SOME CLOCK SETUP TO DO HERE, DOGGGG - this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); //set the gpio directions and atr controls (identically) @@ -165,77 +204,114 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ tvrx::~tvrx(void){ } +/*! Return a string corresponding to the relevant band + * \param freq the frequency of interest + * \return a string corresponding to the band + */ + +static std::string get_band(double freq) { + BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { + if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) + return name; + } + UHD_THROW_INVALID_CODE_PATH(); +} + /*********************************************************************** * Gain Handling **********************************************************************/ +/* + * Gain accuracy on this thing is basically a crap shoot. In other words, there is none. + * The old driver basically picked a linear approximation of the median gain, but the actual + * gain slope is heavily nonlinear and varies both with gain and with frequency. + * It also probably varies markedly over temperature, but there's only so much we can do. + * The best approximation to the RF gain data is fifth-order. If we ignore the curve portions + * below 0dB (yes, it's a pad below a certain gain value) and if we ignore the curve portions + * near the max-gain asymptotes, it looks pretty close to third-order. This is less insane to + * approximate. + */ + /*! - * Convert a requested gain for the GC2 vga into the integer register value. + * Convert a requested gain for the RF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. * \param gain the requested gain in dB - * \return 5 bit the register value + * \return dac voltage value */ -//yo this should look the same as the below one for the IF, dogg -static int gain_to_gc2_vga_reg(float &gain){ - int reg = 0; - gain = std::clip(float(boost::math::iround(gain)), tvrx_gain_ranges["GC2"].min, tvrx_gain_ranges["GC2"].max); - - // Half dB steps from 0-5dB, 1dB steps from 5-24dB - if (gain < 5) { - reg = boost::math::iround(31.0 - gain/0.5); - gain = float(boost::math::iround(gain) * 0.5); - } else { - reg = boost::math::iround(22.0 - (gain - 4.0)); - gain = float(boost::math::iround(gain)); - } +static float rf_gain_to_voltage(float &gain){ + //clip the input + gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + + //voltage level constants + static const float max_volts = float(4.0), min_volts = float(0.6); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + + //this is the voltage at the TVRX gain input + float gain_volts = gain*slope + min_volts + //this is the voltage at the USRP DAC output + float dac_volts = gain_volts / opamp_gain; + + //the actual gain setting + gain = (dac_volts - min_volts)/slope; if (tvrx_debug) std::cerr << boost::format( - "tvrx GC2 Gain: %f dB, reg: %d" - ) % gain % reg << std::endl; + "tvrx RF AGC gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; - return reg; + return dac_volts; } /*! - * Convert a requested gain for the RF gain into the dac_volts value. + * Convert a requested gain for the IF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. * \param gain the requested gain in dB * \return dac voltage value */ -//yo what about the 1.22 opamp gain of the USRP1 -- is this replicated on U2? -static float gain_to_rfgain_dac(float &gain){ +static float if_gain_to_voltage(float &gain){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + gain = std::clip(gain, tvrx_gain_ranges["IF"].min, tvrx_gain_ranges["IF"].max); //voltage level constants - static const float max_volts = float(0), min_volts = float(3.3); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + static const float max_volts = float(4.0), min_volts = float(0.0); + static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["IF"].max; - //calculate the voltage for the aux dac - float dac_volts = gain*slope + min_volts; - - if (tvrx_debug) std::cerr << boost::format( - "tvrx RFAGC Gain: %f dB, dac_volts: %f V" - ) % gain % dac_volts << std::endl; + //this is the voltage at the TVRX gain input + float gain_volts = gain*slope + 1.25; + //this is the voltage at the USRP DAC output + float dac_volts = gain_volts / opamp_gain; //the actual gain setting gain = (dac_volts - min_volts)/slope; + if (tvrx_debug) std::cerr << boost::format( + "tvrx IF AGC gain: %f dB, dac_volts: %f V" + ) % gain % dac_volts << std::endl; + return dac_volts; } void tvrx::set_gain(float gain, const std::string &name){ assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); if (name == "RF"){ -//should look the same as below + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain)); } else if(name == "IF"){ - //write the new voltage to the aux dac CHECK THIS - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, gain_to_gc1_rfvga_dac(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); } else UHD_THROW_INVALID_CODE_PATH(); _gains[name] = gain; +} + +/*! + * Set the tuner to center the desired frequency at 43.75MHz + * \param freq the requested frequency + */ + +void tvrx::set_freq(double freq) { + + + } /*********************************************************************** @@ -300,7 +376,6 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ } } -//for smaaht kids to use to set advanced props void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); @@ -309,6 +384,9 @@ void tvrx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_GAIN: this->set_gain(val.as(), key.name); return; + case SUBDEV_PROP_FREQ: + this->set_freq(val.as()); + return; default: UHD_THROW_PROP_SET_ERROR(); } -- cgit v1.2.3 From 852f5c5f7b31bfb2e7561a86ca9f5380bd53d130 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 10:21:11 -0700 Subject: dboard: better warnings for invalid IDs and invalid ID combinations --- host/lib/usrp/dboard_manager.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index ab80875f5..181f843a0 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,6 +18,7 @@ #include "dboard_ctor_args.hpp" #include #include +#include #include #include #include @@ -176,10 +177,6 @@ static args_t get_dboard_args( ){ //special case, the none id was provided, use the following ids if (dboard_id == dboard_id_t::none() or force_to_unknown){ - std::cerr << boost::format( - "Warning: unknown dboard-id or dboard-id combination: %s\n" - " -> defaulting to the unknown board type" - ) % dboard_id.to_pp_string() << std::endl; UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff1)); UHD_ASSERT_THROW(get_id_to_args_map().has_key(0xfff0)); switch(unit){ @@ -191,6 +188,9 @@ static args_t get_dboard_args( //verify that there is a registered constructor for this id if (not get_id_to_args_map().has_key(dboard_id)){ + uhd::print_warning(str(boost::format( + "Unknown dboard ID: %s.\n" + ) % dboard_id.to_pp_string())); return get_dboard_args(unit, dboard_id, true); } @@ -214,12 +214,25 @@ dboard_manager_impl::dboard_manager_impl( (get_xcvr_id_to_id_map()[tx_dboard_id] == rx_dboard_id) ); + //warn for invalid dboard id xcvr combinations + if (rx_dboard_is_xcvr != this_dboard_is_xcvr or tx_dboard_is_xcvr != this_dboard_is_xcvr){ + uhd::print_warning(str(boost::format( + "Unknown transceiver board ID combination...\n" + "RX dboard ID: %s\n" + "TX dboard ID: %s\n" + ) % rx_dboard_id.to_pp_string() % tx_dboard_id.to_pp_string())); + } + //extract dboard constructor and settings (force to unknown for messed up xcvr status) dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs; - boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr); + boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args( + dboard_iface::UNIT_RX, rx_dboard_id, rx_dboard_is_xcvr != this_dboard_is_xcvr + ); dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs; - boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr); + boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args( + dboard_iface::UNIT_TX, tx_dboard_id, tx_dboard_is_xcvr != this_dboard_is_xcvr + ); //initialize the gpio pins before creating subdevs set_nice_dboard_if(); -- cgit v1.2.3 From 137aa0ab1ed0b8f7f31a6c484fcf5a845682db80 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 10:24:53 -0700 Subject: usrp1: modify fpga file load to use read (readsome seems to not work here in windows land) --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 76e8ce368..2e1bd85cd 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -267,8 +267,9 @@ public: return -1; } - ssize_t n; - while ((n = file.readsome((char *)buf, sizeof(buf))) > 0) { + while (not file.eof()) { + file.read((char *)buf, sizeof(buf)); + size_t n = file.gcount(); ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); if (ret != n) { -- cgit v1.2.3 From f5bdb7ccb39ef23d4b2c0872fe410e9d5d031958 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 11:08:41 -0700 Subject: usrp1: move the get handles call into the for loop scope to facilitate decontruction --- host/lib/usrp/usrp1/usrp1_impl.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 627180b11..a56649305 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -74,14 +74,14 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) boost::uint16_t vid = hint.has_key("uninit") ? FX2_VENDOR_ID : USRP1_VENDOR_ID; boost::uint16_t pid = hint.has_key("uninit") ? FX2_PRODUCT_ID : USRP1_PRODUCT_ID; - //see what we got on the USB bus - std::vector device_list = - usb_device_handle::get_device_list(vid, pid); - - if(device_list.size() == 0) return usrp1_addrs; //return nothing if no USRPs found + // Important note: + // The get device list calls are nested inside the for loop. + // This allows the usb guts to decontruct when not in use, + // so that re-enumeration after fw load can occur successfully. + // This requirement is a courtesy of libusb1.0 on windows. //find the usrps and load firmware - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { usb_control::sptr ctrl_transport = usb_control::make(handle); usrp_ctrl::sptr usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_firmware(usrp1_fw_image); @@ -90,9 +90,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) //get descriptors again with serial number, but using the initialized VID/PID now since we have firmware vid = USRP1_VENDOR_ID; pid = USRP1_PRODUCT_ID; - device_list = usb_device_handle::get_device_list(vid, pid); - BOOST_FOREACH(usb_device_handle::sptr handle, device_list) { + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { device_addr_t new_addr; new_addr["type"] = "usrp1"; new_addr["serial"] = handle->get_serial(); -- cgit v1.2.3 From 15eacbd920a0527ec16c24baeb1d6b87f29d9110 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 13:52:09 -0700 Subject: TVRX: Don't have mboard impl modified for ADC buffer disable. The rest of TVRX should be in there. Not debugged. --- host/lib/usrp/dboard/CMakeLists.txt | 1 + host/lib/usrp/dboard/db_tvrx.cpp | 219 +++++++++++++++++++++--------------- host/lib/usrp/usrp1/codec_ctrl.cpp | 13 +++ host/lib/usrp/usrp1/codec_ctrl.hpp | 3 + 4 files changed, 147 insertions(+), 89 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 3e995009e..8d3d11530 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -24,5 +24,6 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_tvrx.cpp ) diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index ed6025433..2988367e2 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -39,9 +39,11 @@ #include #include #include +#include #include #include #include +#include #include using namespace uhd; @@ -55,12 +57,11 @@ static const bool tvrx_debug = true; static const freq_range_t tvrx_freq_range(50e6, 860e6); -static const prop_names_t tvrx_antennas = ""; //only got one +static const std::string tvrx_antennas = std::string(""); //only got one -static const uhd::dict tvrx_gain_ranges = map_list_of - ("RF", gain_range_t(-13.3, 50.3, float(50.3/4096))) //both gains are analog and controlled by DAC - ("IF", gain_range_t(-1.5, 32.5, float(32.5/4096))) //the old driver used 1dB for both; i don't think that's right? -; +//a note on these: the gain of the TVRX varies over frequency. the gain ranges +//below correspond to the maximum and minimum gains over the entire frequency range. +//specifying a gain higher or lower than the TVRX can accomplish will of course just clip. static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) @@ -68,63 +69,68 @@ static const uhd::dict tvrx_freq_ranges = map_list_of ("UHF" , freq_range_t(454e6, 860e6)) ; +static const boost::array vhflo_gains_db = + {{-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, + 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, + 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, + 50.30000, 50.30000}}; + +static const boost::array vhfhi_gains_db = + {{13.3000, -13.3000, -13.3000, -1.0000, 7.7000, + 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, + 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, + 48.2000, 48.2000}}; + +static const boost::array uhf_gains_db = + {{-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, + 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, + 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, + 43.2000, 43.8000}}; + +static const boost::array tvrx_if_gains_db = + {{-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, + 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, + 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, + 32.50000, 32.50000}}; + //gain linearization data //this is from the datasheet and is dB vs. volts (below) //i tried to curve fit this, but it's really just so nonlinear that you'd //need dang near as many coefficients as to just map it like this and interp. //these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate //but if it's better than the old linear fit i'm happy -static const uhd::dict > tvrx_rf_gains_db = map_list_of - ("VHFLO", std::vector(-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, - 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, - 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, - 50.30000, 50.30000)) - ("VHFHI", std::vector(-13.3000, -13.3000, -13.3000, -1.0000, 7.7000, - 11.0000, 14.7000, 19.3000, 26.1000, 36.0000, - 42.7000, 46.0000, 47.0000, 47.8000, 48.2000, - 48.2000, 48.2000)) - ("UHF" , std::vector(-8.0000, -8.0000, -7.0000, 4.0000, 10.2000, - 14.5000, 17.5000, 20.0000, 24.5000, 30.8000, - 37.0000, 39.8000, 40.7000, 41.6000, 42.6000, - 43.2000, 43.8000)) -; - -static const std::vector tvrx_if_gains_db = - std::vector(-1.50000, -1.50000, -1.50000, -1.00000, 0.20000, - 2.10000, 4.30000, 6.40000, 9.00000, 12.00000, - 14.80000, 18.20000, 26.10000, 32.50000, 32.50000, - 32.50000, 32.50000) +static const uhd::dict > tvrx_rf_gains_db = map_list_of + ("VHFLO", vhflo_gains_db) + ("VHFHI", vhfhi_gains_db) + ("UHF" , uhf_gains_db) ; //sample voltages for the above points -static const std::vector tvrx_rf_gains_volts = - std::vector(0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0); - - -/*! - * Execute a linear interpolation to find the voltage corresponding to a desired gain - * \param gain the desired gain in dB - * \param db_vector the vector of dB readings - * \param volts_vector the corresponding vector of voltages db_vector was sampled at - * \return a voltage to feed the TVRX analog gain - */ - -static float gain_interp(float gain, std::vector db_vector, std::vector volts_vector) { - float volts; - gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here - - boost::uint8_t gain_step = 0; - for(int i = 0; i < db_vector.size()-1; i++) { - if(gain > db_vector[i] && gain < db_vector.[i+1]) gain_step = i; +static const boost::array tvrx_gains_volts = + {{0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0}}; + +static uhd::dict get_tvrx_gain_ranges(void) { + float rfmax = 0.0, rfmin = FLT_MAX; + BOOST_FOREACH(const std::string range, tvrx_rf_gains_db.keys()) { + float my_max = tvrx_rf_gains_db[range].back(); //we're assuming it's monotonic + float my_min = tvrx_rf_gains_db[range].front(); //if it's not this is wrong wrong wrong + if(my_max > rfmax) rfmax = my_max; + if(my_min < rfmin) rfmin = my_min; } - - return volts; + float ifmin = tvrx_if_gains_db.front(); + float ifmax = tvrx_if_gains_db.back(); + + return map_list_of + ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0)) + ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0)) + ; } static const double opamp_gain = 1.22; //onboard DAC opamp gain -static const double tvrx_lo_freq = 43.75e6; //LO freq of TVRX module +static const double tvrx_if_freq = 43.75e6; //IF freq of TVRX module static const boost::uint16_t reference_divider = 640; //clock reference divider to use +static const double reference_freq = 4.0e6; /*********************************************************************** * The tvrx dboard class @@ -139,12 +145,14 @@ public: private: uhd::dict _gains; + double _lo_freq; tuner_4937di5_regs_t _tuner_4937di5_regs; boost::uint8_t _tuner_4937di5_addr(void){ return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); + void set_freq(double freq); void update_regs(void){ byte_vector_t regs_vector(4); @@ -192,12 +200,14 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs } - //send initial register settings - //HAAAAY GUYYYYYSSS + //send initial register settings if necessary + + //set default freq + set_freq(tvrx_freq_range.min); //set default gains - BOOST_FOREACH(const std::string &name, tvrx_gain_ranges.keys()){ - set_gain(tvrx_gain_ranges[name].min, name); + BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){ + set_gain(get_tvrx_gain_ranges()[name].min, name); } } @@ -212,7 +222,7 @@ tvrx::~tvrx(void){ static std::string get_band(double freq) { BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) - return name; + return band; } UHD_THROW_INVALID_CODE_PATH(); } @@ -220,17 +230,34 @@ static std::string get_band(double freq) { /*********************************************************************** * Gain Handling **********************************************************************/ -/* - * Gain accuracy on this thing is basically a crap shoot. In other words, there is none. - * The old driver basically picked a linear approximation of the median gain, but the actual - * gain slope is heavily nonlinear and varies both with gain and with frequency. - * It also probably varies markedly over temperature, but there's only so much we can do. - * The best approximation to the RF gain data is fifth-order. If we ignore the curve portions - * below 0dB (yes, it's a pad below a certain gain value) and if we ignore the curve portions - * near the max-gain asymptotes, it looks pretty close to third-order. This is less insane to - * approximate. +/*! + * Execute a linear interpolation to find the voltage corresponding to a desired gain + * \param gain the desired gain in dB + * \param db_vector the vector of dB readings + * \param volts_vector the corresponding vector of voltages db_vector was sampled at + * \return a voltage to feed the TVRX analog gain */ +static float gain_interp(float gain, boost::array db_vector, boost::array volts_vector) { + float volts; + gain = std::clip(gain, db_vector.front(), db_vector.back()); //let's not get carried away here + + boost::uint8_t gain_step = 0; + //find which bin we're in + for(size_t i = 0; i < db_vector.size()-1; i++) { + if(gain > db_vector[i] && gain < db_vector[i+1]) gain_step = i; + } + + //find the current slope for linear interpolation + float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) + / (db_vector[gain_step + 1] - db_vector[gain_step]); + + //use the volts per dB slope to find the final interpolated voltage + volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); + + return volts; +} + /*! * Convert a requested gain for the RF gain into a DAC voltage. * The gain passed into the function will be set to the actual value. @@ -238,22 +265,18 @@ static std::string get_band(double freq) { * \return dac voltage value */ -static float rf_gain_to_voltage(float &gain){ +static float rf_gain_to_voltage(float gain, double lo_freq){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); + gain = std::clip(gain, get_tvrx_gain_ranges()["RF"].min, get_tvrx_gain_ranges()["RF"].max); - //voltage level constants - static const float max_volts = float(4.0), min_volts = float(0.6); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; + //first we need to find out what band we're in, because gains are different across different bands + std::string band = get_band(lo_freq + tvrx_if_freq); //this is the voltage at the TVRX gain input - float gain_volts = gain*slope + min_volts + float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); //this is the voltage at the USRP DAC output float dac_volts = gain_volts / opamp_gain; - //the actual gain setting - gain = (dac_volts - min_volts)/slope; - if (tvrx_debug) std::cerr << boost::format( "tvrx RF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; @@ -268,22 +291,13 @@ static float rf_gain_to_voltage(float &gain){ * \return dac voltage value */ -static float if_gain_to_voltage(float &gain){ +static float if_gain_to_voltage(float gain){ //clip the input - gain = std::clip(gain, tvrx_gain_ranges["IF"].min, tvrx_gain_ranges["IF"].max); - - //voltage level constants - static const float max_volts = float(4.0), min_volts = float(0.0); - static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["IF"].max; - - //this is the voltage at the TVRX gain input - float gain_volts = gain*slope + 1.25; - //this is the voltage at the USRP DAC output + gain = std::clip(gain, get_tvrx_gain_ranges()["IF"].min, get_tvrx_gain_ranges()["IF"].max); + + float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); float dac_volts = gain_volts / opamp_gain; - //the actual gain setting - gain = (dac_volts - min_volts)/slope; - if (tvrx_debug) std::cerr << boost::format( "tvrx IF AGC gain: %f dB, dac_volts: %f V" ) % gain % dac_volts << std::endl; @@ -292,9 +306,9 @@ static float if_gain_to_voltage(float &gain){ } void tvrx::set_gain(float gain, const std::string &name){ - assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); + assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name"); if (name == "RF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain, _lo_freq)); } else if(name == "IF"){ this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); @@ -309,9 +323,36 @@ void tvrx::set_gain(float gain, const std::string &name){ */ void tvrx::set_freq(double freq) { + freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); + std::string prev_band = get_band(_lo_freq + tvrx_if_freq); + std::string new_band = get_band(freq); + double lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing + double f_ref = reference_freq / double(reference_divider); //your tuning step size + int divisor = int(lo_freq + (f_ref * 4.0)) / (f_ref * 8); //the divisor we'll use + double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get + + if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH(); + + //now we update the registers + _tuner_4937di5_regs.db1 = (divisor >> 8) & 0xff; + _tuner_4937di5_regs.db2 = divisor & 0xff; + + if(new_band == "VHFLO") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFLO; + else if(new_band == "VHFHI") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFHI; + else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF; + else UHD_THROW_INVALID_CODE_PATH(); + + _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_ON; + update_regs(); + + //ok don't forget to reset RF gain here if the new band != the old band + //we do this because the gains are different for different band settings + //not FAR off, but we do this to be consistent + if(prev_band != new_band) set_gain(_gains["RF"], "RF"); + _lo_freq = actual_lo_freq; //for rx props } /*********************************************************************** @@ -336,16 +377,16 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN_RANGE: - assert_has(tvrx_gain_ranges.keys(), key.name, "tvrx gain name"); - val = tvrx_gain_ranges[key.name]; + assert_has(get_tvrx_gain_ranges().keys(), key.name, "tvrx gain name"); + val = get_tvrx_gain_ranges()[key.name]; return; case SUBDEV_PROP_GAIN_NAMES: - val = prop_names_t(tvrx_gain_ranges.keys()); + val = prop_names_t(get_tvrx_gain_ranges().keys()); return; case SUBDEV_PROP_FREQ: - val = tvrx_lo_freq; + val = _lo_freq - tvrx_if_freq; return; case SUBDEV_PROP_FREQ_RANGE: diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 08f2d2a8e..3ab02eeeb 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -61,6 +61,9 @@ public: float get_tx_pga_gain(void); void set_rx_pga_gain(float, char); float get_rx_pga_gain(char); + + //rx adc buffer control + void bypass_adc_buffers(bool bypass); private: usrp1_iface::sptr _iface; @@ -418,6 +421,16 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq) this->send_reg(23); } +/*********************************************************************** + * Codec Control ADC buffer bypass + * Enable this for DC-coupled daughterboards (TVRX) + **********************************************************************/ +void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { + _ad9862_regs.byp_buffer_a = bypass; + _ad9862_regs.byp_buffer_b = bypass; + this->send_reg(2); +} + /*********************************************************************** * Codec Control Make **********************************************************************/ diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 259d10ef4..e2e8a010d 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -92,6 +92,9 @@ public: //! Set the TX modulator frequency virtual void set_duc_freq(double freq) = 0; + + //! Enable or disable ADC buffer bypass + virtual void bypass_adc_buffers(bool bypass) = 0; }; #endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ -- cgit v1.2.3 From b70d4430d4a898fe99b54740a1c4821ed9a1077b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 15:31:38 -0700 Subject: wbx: fix for id swap typo --- host/lib/usrp/dboard/db_wbx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index ccd897674..e473ce41e 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -154,7 +154,7 @@ static dboard_base::sptr make_wbx(dboard_base::ctor_args_t args){ } UHD_STATIC_BLOCK(reg_wbx_dboards){ - dboard_manager::register_dboard(0x0052, 0x0053, &make_wbx, "WBX"); + dboard_manager::register_dboard(0x0053, 0x0052, &make_wbx, "WBX"); } /*********************************************************************** -- cgit v1.2.3 From e4c6f42ff30aeaedf2d1eb426a221b85236fb74e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 28 Sep 2010 16:53:52 -0700 Subject: usb: submit should return ssize_t, usrp1: set hash before reset after fw load --- host/include/uhd/transport/usb_control.hpp | 4 ++-- host/lib/transport/libusb1_control.cpp | 2 +- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6137ecf84..f9829c3ec 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -50,9 +50,9 @@ public: * \param index 2-byte (wIndex) * \param buff buffer to hold send or receive data * \param length 2-byte (wLength) - * \return number of bytes submitted + * \return number of bytes submitted or error code */ - virtual size_t submit(boost::uint8_t request_type, + virtual ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index c989a788c..f903907d0 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -33,7 +33,7 @@ public: _handle->claim_interface(0 /* control interface */); } - size_t submit(boost::uint8_t request_type, + ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 2e1bd85cd..5d73e6dd9 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -209,9 +209,9 @@ public: } //type 0x01 is end else if (type == 0x01) { + usrp_set_firmware_hash(hash); //set hash before reset usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_n, 1); - usrp_set_firmware_hash(hash); file.close(); //wait for things to settle -- cgit v1.2.3 From 7cb95203f8d7173e3d7070d24f68358be67d0b29 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 17:45:07 -0700 Subject: TVRX: First version that works. The gain linearity is still borked. I'll probably give up on the complicated linearizing stuff and just use the values from the old driver. The tuner's gain-vs-voltage is nothing like the datasheet. --- host/lib/usrp/dboard/db_tvrx.cpp | 44 ++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 2988367e2..f5b544c18 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include using namespace uhd; @@ -59,10 +60,6 @@ static const freq_range_t tvrx_freq_range(50e6, 860e6); static const std::string tvrx_antennas = std::string(""); //only got one -//a note on these: the gain of the TVRX varies over frequency. the gain ranges -//below correspond to the maximum and minimum gains over the entire frequency range. -//specifying a gain higher or lower than the TVRX can accomplish will of course just clip. - static const uhd::dict tvrx_freq_ranges = map_list_of ("VHFLO", freq_range_t(50e6, 158e6)) ("VHFHI", freq_range_t(158e6, 454e6)) @@ -148,7 +145,7 @@ private: double _lo_freq; tuner_4937di5_regs_t _tuner_4937di5_regs; boost::uint8_t _tuner_4937di5_addr(void){ - return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call + return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x61 : 0x60; //ok really? we could rename that call }; void set_gain(float gain, const std::string &name); @@ -182,7 +179,7 @@ static dboard_base::sptr make_tvrx(dboard_base::ctor_args_t args){ UHD_STATIC_BLOCK(reg_tvrx_dboard){ //register the factory function for the rx dbid - dboard_manager::register_dboard(0x0003, &make_tvrx, "tvrx"); + dboard_manager::register_dboard(0x0040, &make_tvrx, "tvrx"); } /*********************************************************************** @@ -203,6 +200,7 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){ //send initial register settings if necessary //set default freq + _lo_freq = tvrx_freq_range.min + tvrx_if_freq; //init _lo_freq to a sane default set_freq(tvrx_freq_range.min); //set default gains @@ -220,9 +218,12 @@ tvrx::~tvrx(void){ */ static std::string get_band(double freq) { + std::cout << "get_band called with freq " << freq << std::endl; BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { - if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) + if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max){ + std::cout << "Holy poop you're in band " << band << std::endl; return band; + } } UHD_THROW_INVALID_CODE_PATH(); } @@ -245,15 +246,25 @@ static float gain_interp(float gain, boost::array db_vector, boost::a boost::uint8_t gain_step = 0; //find which bin we're in for(size_t i = 0; i < db_vector.size()-1; i++) { - if(gain > db_vector[i] && gain < db_vector[i+1]) gain_step = i; + if(gain >= db_vector[i] && gain <= db_vector[i+1]) gain_step = i; } //find the current slope for linear interpolation float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step]) / (db_vector[gain_step + 1] - db_vector[gain_step]); + + //the problem here is that for gains approaching the maximum, the voltage slope becomes infinite + //i.e., a small change in gain requires an infinite change in voltage + //to cope, we limit the slope + + if(slope == std::numeric_limits::infinity()) + return volts_vector[gain_step]; //use the volts per dB slope to find the final interpolated voltage volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); + + if(tvrx_debug) + std::cout << "Gain interp: gain: " << gain << ", gain_step: " << int(gain_step) << ", slope: " << slope << ", volts: " << volts << std::endl; return volts; } @@ -276,6 +287,8 @@ static float rf_gain_to_voltage(float gain, double lo_freq){ float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts); //this is the voltage at the USRP DAC output float dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx RF AGC gain: %f dB, dac_volts: %f V" @@ -297,6 +310,8 @@ static float if_gain_to_voltage(float gain){ float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts); float dac_volts = gain_volts / opamp_gain; + + dac_volts = std::clip(dac_volts, 0.0, 3.3); if (tvrx_debug) std::cerr << boost::format( "tvrx IF AGC gain: %f dB, dac_volts: %f V" @@ -324,13 +339,13 @@ void tvrx::set_gain(float gain, const std::string &name){ void tvrx::set_freq(double freq) { freq = std::clip(freq, tvrx_freq_range.min, tvrx_freq_range.max); - std::string prev_band = get_band(_lo_freq + tvrx_if_freq); + std::string prev_band = get_band(_lo_freq - tvrx_if_freq); std::string new_band = get_band(freq); - double lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing + double target_lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing double f_ref = reference_freq / double(reference_divider); //your tuning step size - int divisor = int(lo_freq + (f_ref * 4.0)) / (f_ref * 8); //the divisor we'll use + int divisor = int((target_lo_freq + (f_ref * 4.0)) / (f_ref * 8)); //the divisor we'll use double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH(); @@ -344,7 +359,7 @@ void tvrx::set_freq(double freq) { else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF; else UHD_THROW_INVALID_CODE_PATH(); - _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_ON; + _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_OFF; update_regs(); //ok don't forget to reset RF gain here if the new band != the old band @@ -352,6 +367,9 @@ void tvrx::set_freq(double freq) { //not FAR off, but we do this to be consistent if(prev_band != new_band) set_gain(_gains["RF"], "RF"); + if(tvrx_debug) + std::cout << boost::format("set_freq: target LO: %f f_ref: %f divisor: %i actual LO: %f") % target_lo_freq % f_ref % divisor % actual_lo_freq << std::endl; + _lo_freq = actual_lo_freq; //for rx props } @@ -386,7 +404,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq - tvrx_if_freq; + val = _lo_freq - 2*tvrx_if_freq; return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 560cbf9a2900a02391f025a3fd50a1616893c8c7 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 18:04:35 -0700 Subject: TVRX: Fixed spectrum inversion (derp derp derp). Removed debug printing. --- host/lib/usrp/dboard/db_tvrx.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index f5b544c18..83a638810 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -54,7 +54,7 @@ using namespace boost::assign; /*********************************************************************** * The tvrx constants **********************************************************************/ -static const bool tvrx_debug = true; +static const bool tvrx_debug = false; static const freq_range_t tvrx_freq_range(50e6, 860e6); @@ -218,10 +218,9 @@ tvrx::~tvrx(void){ */ static std::string get_band(double freq) { - std::cout << "get_band called with freq " << freq << std::endl; BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) { if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max){ - std::cout << "Holy poop you're in band " << band << std::endl; + if(tvrx_debug) std::cout << "Band: " << band << std::endl; return band; } } @@ -404,7 +403,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq - 2*tvrx_if_freq; + val = _lo_freq; return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 6fe533e19a29ea6cd241b70c38081499a8f3ba55 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Tue, 28 Sep 2010 18:09:04 -0700 Subject: TVRX: Mixed up DAC channels. Gain is much more linear now. --- host/lib/usrp/dboard/db_tvrx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 83a638810..71aff1680 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -322,10 +322,10 @@ static float if_gain_to_voltage(float gain){ void tvrx::set_gain(float gain, const std::string &name){ assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name"); if (name == "RF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain, _lo_freq)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, rf_gain_to_voltage(gain, _lo_freq)); } else if(name == "IF"){ - this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); + this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, if_gain_to_voltage(gain)); } else UHD_THROW_INVALID_CODE_PATH(); _gains[name] = gain; -- cgit v1.2.3 From 302078474312ad87db69a9c06b63e3f8a0c19cd5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 09:51:41 -0700 Subject: usrp1: fixed compile time warning, tweaked fw load message --- host/lib/usrp/usrp1/usrp1_ctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_ctrl.cpp b/host/lib/usrp/usrp1/usrp1_ctrl.cpp index 5d73e6dd9..5043aed7d 100644 --- a/host/lib/usrp/usrp1/usrp1_ctrl.cpp +++ b/host/lib/usrp/usrp1/usrp1_ctrl.cpp @@ -180,7 +180,7 @@ public: unsigned char reset_n = 0; //hit the reset line - if (load_img_msg) std::cout << "Loading firmware image " << filestring << "..." << std::flush; + if (load_img_msg) std::cout << "Loading firmware image: " << filestring << "..." << std::flush; usrp_control_write(FX2_FIRMWARE_LOAD, 0xe600, 0, &reset_y, 1); @@ -272,7 +272,7 @@ public: size_t n = file.gcount(); ret = usrp_control_write(VRQ_FPGA_LOAD, 0, FL_XFER, buf, n); - if (ret != n) { + if (ret < 0 or size_t(ret) != n) { std::cerr << "fpga load error " << ret << std::endl; file.close(); return -1; -- cgit v1.2.3 From 543a63648f11d0e502e897f3cd98667005580c9e Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 15:35:54 -0700 Subject: usrp: transfer resize options and documentation --- host/docs/usrp1.rst | 27 ++++++ host/include/uhd/transport/usb_zero_copy.hpp | 24 +++-- host/lib/transport/libusb1_zero_copy.cpp | 140 ++++++++++++++------------- host/lib/usrp/usrp1/usrp1_impl.cpp | 26 +++-- 4 files changed, 137 insertions(+), 80 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/docs/usrp1.rst b/host/docs/usrp1.rst index 3c1431d30..7cf447719 100644 --- a/host/docs/usrp1.rst +++ b/host/docs/usrp1.rst @@ -95,6 +95,27 @@ Notice that the subdevice name is always specified in the 3 possible cases. B:B + +------------------------------------------------------------------------ +Change USB transfer parameters +------------------------------------------------------------------------ +The advanced user may manipulate parameters of the usb bulk transfers +for various reasons, such as lowering latency or increasing buffer size. +By default, the UHD will use values for these parameters +that are known to perform well on a variety of systems. + +The following device address can be used to manipulate USB bulk transfers: + +* **recv_xfer_size:** the size of each receive bulk transfer in bytes +* **recv_num_xfers:** the number of simultaneous receive bulk transfers +* **send_xfer_size:** the size of each send bulk transfer in bytes +* **send_num_xfers:** the number of simultaneous send bulk transfers + +Example, set the args string to the following: +:: + + serial=12345678, recv_num_xfers=16 + ------------------------------------------------------------------------ OS Specific Notes ------------------------------------------------------------------------ @@ -113,3 +134,9 @@ so that non-root users may access the device: sudo mv tmpfile /etc/udev/rules.d/10-usrp.rules sudo udevadm control --reload-rules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install libusb driver on Windows +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +On Windows, a driver must be installed the first time the USRP1 is attached to the host computer. +A download link for this driver can be found on the Ettus Research UHD wiki page. +Download and unpack the driver, and direct the Windows driver install wizard to the *.inf file. diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 75232c22a..61bf380ba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -45,16 +45,22 @@ public: * The underlying implementation may be platform specific. * * \param handle a device handle that uniquely identifying the device - * \param rx_endpoint an integer specifiying an IN endpoint number - * \param tx_endpoint an integer specifiying an OUT endpoint number - * \param buff_size total number of bytes of buffer space to allocate - * \param block_size number of bytes allocated for each I/O transaction + * \param recv_endpoint an integer specifiying an IN endpoint number + * \param send_endpoint an integer specifiying an OUT endpoint number + * \param recv_xfer_size the number of bytes for each receive transfer + * \param recv_num_xfers the number of simultaneous receive transfers + * \param send_xfer_size the number of bytes for each send transfer + * \param send_num_xfers the number of simultaneous send transfers */ - static sptr make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size = 0, - size_t block_size = 0); + static sptr make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, + unsigned int send_endpoint, + size_t recv_xfer_size = 0, + size_t recv_num_xfers = 0, + size_t send_xfer_size = 0, + size_t send_num_xfers = 0 + ); }; }} //namespace diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index b089d11e0..f2dcff6b5 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -30,6 +30,9 @@ using namespace uhd::transport; const int libusb_timeout = 0; +static const size_t DEFAULT_NUM_XFERS = 16; //num xfers +static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes + /*********************************************************************** * Helper functions ***********************************************************************/ @@ -56,7 +59,7 @@ void pp_transfer(libusb_transfer *lut) * create a bidirectional interface. It is a zero copy implementation * with respect to libusb, however, each send and recv requires a copy * operation from kernel to userspace; this is due to the usbfs - * interface provided by the kernel. + * interface provided by the kernel. **********************************************************************/ class usb_endpoint { public: @@ -107,7 +110,7 @@ private: //! a list of shared arrays for the transfer buffers std::vector > _buffers; - // Calls for processing asynchronous I/O + // Calls for processing asynchronous I/O libusb_transfer *allocate_transfer(int buff_len); void print_transfer_status(libusb_transfer *lut); }; @@ -142,7 +145,7 @@ void usb_endpoint::callback_handle_transfer(libusb_transfer *lut){ * Constructor * Allocate libusb transfers and mark as free. For IN endpoints, * submit the transfers so that they're ready to return when - * data is available. + * data is available. */ usb_endpoint::usb_endpoint( libusb::device_handle::sptr handle, @@ -194,7 +197,7 @@ usb_endpoint::~usb_endpoint(void){ /* - * Allocate a libusb transfer + * Allocate a libusb transfer * The allocated transfer - and buffer it contains - is repeatedly * submitted, reaped, and reused and should not be freed until shutdown. * \param buff_len size of the individual buffer held by each transfer @@ -225,7 +228,7 @@ libusb_transfer *usb_endpoint::allocate_transfer(int buff_len){ * Asynchonous transfer submission * Submit a libusb transfer to libusb add pending status * \param lut pointer to libusb_transfer - * \return true on success or false on error + * \return true on success or false on error */ void usb_endpoint::submit(libusb_transfer *lut){ UHD_ASSERT_THROW(libusb_submit_transfer(lut) == 0); @@ -281,14 +284,14 @@ libusb_transfer *usb_endpoint::get_lut_with_wait(size_t timeout_ms){ } /*********************************************************************** - * Managed buffers + * Managed buffers **********************************************************************/ /* * Libusb managed receive buffer * Construct a recv buffer from a libusb transfer. The memory held by * the libusb transfer is exposed through the managed buffer interface. * Upon destruction, the transfer and buffer are resubmitted to the - * endpoint for further use. + * endpoint for further use. */ class libusb_managed_recv_buffer_impl : public managed_recv_buffer { public: @@ -307,7 +310,7 @@ public: private: const boost::asio::const_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; @@ -327,9 +330,8 @@ private: class libusb_managed_send_buffer_impl : public managed_send_buffer { public: libusb_managed_send_buffer_impl(libusb_transfer *lut, - usb_endpoint::sptr endpoint, - size_t buff_size) - : _buff(lut->buffer, buff_size), _committed(false) + usb_endpoint::sptr endpoint) + : _buff(lut->buffer, lut->length), _committed(false) { _lut = lut; _endpoint = endpoint; @@ -349,7 +351,7 @@ public: std::cerr << "UHD: send buffer already committed" << std::endl; return 0; } - + UHD_ASSERT_THROW(num_bytes <= boost::asio::buffer_size(_buff)); _lut->length = num_bytes; @@ -369,7 +371,7 @@ public: private: const boost::asio::mutable_buffer &get() const { - return _buff; + return _buff; } libusb_transfer *_lut; @@ -385,61 +387,71 @@ private: class libusb_zero_copy_impl : public usb_zero_copy { private: - usb_endpoint::sptr _rx_ep, _tx_ep; - libusb::device_handle::sptr _handle; - - size_t _recv_buff_size; - size_t _send_buff_size; - size_t _num_frames; + size_t _recv_num_frames, _send_num_frames; + usb_endpoint::sptr _recv_ep, _send_ep; public: typedef boost::shared_ptr sptr; - libusb_zero_copy_impl(libusb::device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t recv_buff_size, - size_t send_buff_size); + libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); managed_recv_buffer::sptr get_recv_buff(void); managed_send_buffer::sptr get_send_buff(void); - size_t get_num_recv_frames(void) const { return _num_frames; } - size_t get_num_send_frames(void) const { return _num_frames; } + size_t get_num_recv_frames(void) const { return _recv_num_frames; } + size_t get_num_send_frames(void) const { return _send_num_frames; } }; /* * Constructor * Initializes libusb, opens devices, and sets up interfaces for I/O. - * Finally, creates endpoints for asynchronous I/O. + * Finally, creates endpoints for asynchronous I/O. */ -libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size, - size_t block_size) - : _handle(handle), - _recv_buff_size(block_size), _send_buff_size(block_size), - _num_frames(buff_size / block_size) -{ - _handle->claim_interface(2 /*in interface*/); +libusb_zero_copy_impl::libusb_zero_copy_impl( + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ + _handle = handle; + + //if the sizes are left at 0 (automatic) -> use the defaults + if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; + if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; + if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; + if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; + + //sanity check the transfer sizes + UHD_ASSERT_THROW(recv_xfer_size % 512 == 0); + UHD_ASSERT_THROW(send_xfer_size % 512 == 0); + + //store the num xfers for the num frames count + _recv_num_frames = recv_num_xfers; + _send_num_frames = send_num_xfers; + + _handle->claim_interface(2 /*in interface*/); _handle->claim_interface(1 /*out interface*/); - _rx_ep = usb_endpoint::sptr(new usb_endpoint( + _recv_ep = usb_endpoint::sptr(new usb_endpoint( _handle, // libusb device_handle - rx_endpoint, // USB endpoint number + recv_endpoint, // USB endpoint number true, // IN endpoint - _recv_buff_size, // buffer size per transfer - _num_frames // number of libusb transfers + recv_xfer_size, // buffer size per transfer + recv_num_xfers // number of libusb transfers )); - _tx_ep = usb_endpoint::sptr(new usb_endpoint( + _send_ep = usb_endpoint::sptr(new usb_endpoint( _handle, // libusb device_handle - tx_endpoint, // USB endpoint number + send_endpoint, // USB endpoint number false, // OUT endpoint - _send_buff_size, // buffer size per transfer - _num_frames // number of libusb transfers + send_xfer_size, // buffer size per transfer + send_num_xfers // number of libusb transfers )); } @@ -447,17 +459,17 @@ libusb_zero_copy_impl::libusb_zero_copy_impl(libusb::device_handle::sptr handle, * Construct a managed receive buffer from a completed libusb transfer * (happy with buffer full of data) obtained from the receive endpoint. * Return empty pointer if no transfer is available (timeout or error). - * \return pointer to a managed receive buffer + * \return pointer to a managed receive buffer */ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ - libusb_transfer *lut = _rx_ep->get_lut_with_wait(/* TODO timeout API */); + libusb_transfer *lut = _recv_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_recv_buffer::sptr(); } else { return managed_recv_buffer::sptr( new libusb_managed_recv_buffer_impl(lut, - _rx_ep)); + _recv_ep)); } } @@ -466,38 +478,36 @@ managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ * Construct a managed send buffer from a free libusb transfer (with * empty buffer). Return empty pointer of no transfer is available * (timeout or error). - * \return pointer to a managed send buffer + * \return pointer to a managed send buffer */ managed_send_buffer::sptr libusb_zero_copy_impl::get_send_buff(void){ - libusb_transfer *lut = _tx_ep->get_lut_with_wait(/* TODO timeout API */); + libusb_transfer *lut = _send_ep->get_lut_with_wait(/* TODO timeout API */); if (lut == NULL) { return managed_send_buffer::sptr(); } else { return managed_send_buffer::sptr( new libusb_managed_send_buffer_impl(lut, - _tx_ep, - _send_buff_size)); + _send_ep)); } } - /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size, - size_t block_size) - -{ +usb_zero_copy::sptr usb_zero_copy::make( + usb_device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers +){ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( boost::static_pointer_cast(handle)->get_device() )); - return sptr(new libusb_zero_copy_impl(dev_handle, - rx_endpoint, - tx_endpoint, - buff_size, - block_size)); + return sptr(new libusb_zero_copy_impl( + dev_handle, + recv_endpoint, send_endpoint, + recv_xfer_size, recv_num_xfers, + send_xfer_size, send_num_xfers + )); } diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index b4c23bf12..793e3027d 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include using namespace uhd; @@ -107,6 +108,15 @@ static device_addrs_t usrp1_find(const device_addr_t &hint) /*********************************************************************** * Make **********************************************************************/ +template static output_type cast_from_dev_addr( + const device_addr_t &device_addr, + const std::string &key, + output_type def_val +){ + return (device_addr.has_key(key))? + boost::lexical_cast(device_addr[key]) : def_val; +} + static device::sptr usrp1_make(const device_addr_t &device_addr) { //extract the FPGA path for the USRP1 @@ -130,11 +140,15 @@ static device::sptr usrp1_make(const device_addr_t &device_addr) usrp_ctrl = usrp_ctrl::make(ctrl_transport); usrp_ctrl->usrp_load_fpga(usrp1_fpga_image); - data_transport = usb_zero_copy::make(handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - 2 * (1 << 20), // buffer size - 16384); // transfer size + data_transport = usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + size_t(cast_from_dev_addr(device_addr, "recv_xfer_size", 0)), + size_t(cast_from_dev_addr(device_addr, "recv_num_xfers", 0)), + size_t(cast_from_dev_addr(device_addr, "send_xfer_size", 0)), + size_t(cast_from_dev_addr(device_addr, "send_num_xfers", 0)) + ); break; } } @@ -173,7 +187,7 @@ usrp1_impl::usrp1_impl(uhd::transport::usb_zero_copy::sptr data_transport, //initialize the mboard mboard_init(); - //initialize the dboards + //initialize the dboards dboard_init(); //initialize the dsps -- cgit v1.2.3 From 83596f1feb73a15a1ef8741c1c520e8cae46c2a6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 29 Sep 2010 17:43:26 -0700 Subject: usrp: added get codec rate to dboard iface --- host/include/uhd/usrp/dboard_iface.hpp | 9 +++++++++ host/lib/usrp/usrp1/dboard_iface.cpp | 5 +++++ host/lib/usrp/usrp2/dboard_iface.cpp | 4 ++++ 3 files changed, 18 insertions(+) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index c7db244f2..c430ecd3f 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -242,6 +242,15 @@ public: * \param enb true for enabled */ virtual void set_clock_enabled(unit_t unit, bool enb) = 0; + + /*! + * Get the rate of the codec. + * For rx, this is the rate the ADC feeds the DSP. + * For tx, this is the rate the DSP feeds the DAC. + * \param unit which unit rx or tx + * \return the codec rate in Hz + */ + virtual double get_codec_rate(unit_t unit) = 0; }; }} //namespace diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4791b55ce..4f0549a37 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -93,6 +93,7 @@ public: std::vector get_clock_rates(unit_t); double get_clock_rate(unit_t); void set_clock_enabled(unit_t, bool); + double get_codec_rate(unit_t); private: usrp1_iface::sptr _iface; @@ -170,6 +171,10 @@ void usrp1_dboard_iface::set_clock_enabled(unit_t, bool) //TODO we can only enable for special case anyway... } +double usrp1_dboard_iface::get_codec_rate(unit_t){ + return _clock->get_master_clock_freq(); +} + /*********************************************************************** * GPIO **********************************************************************/ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index f6d2b718a..fdfbf0d17 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -61,6 +61,7 @@ public: double get_clock_rate(unit_t); std::vector get_clock_rates(unit_t); void set_clock_enabled(unit_t, bool); + double get_codec_rate(unit_t); void write_spi( unit_t unit, @@ -158,6 +159,9 @@ void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ } } +double usrp2_dboard_iface::get_codec_rate(unit_t){ + return _clock_ctrl->get_master_clock_rate(); +} /*********************************************************************** * GPIO **********************************************************************/ -- cgit v1.2.3 From 56751efbe6e0751a2b8cd0f7a31d5dfd07fec5dd Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Wed, 29 Sep 2010 18:27:08 -0700 Subject: TVRX: works for USRP and USRP2. --- host/lib/usrp/dboard/db_tvrx.cpp | 11 ++++++++++- host/lib/usrp/usrp1/codec_ctrl.cpp | 3 ++- host/lib/usrp/usrp1/dboard_iface.cpp | 6 ++++++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 71aff1680..6b71a3c6e 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -377,6 +377,7 @@ void tvrx::set_freq(double freq) { **********************************************************************/ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); + int codec_rate; //handle the get request conditioned on the key switch(key.as()){ @@ -403,7 +404,15 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_FREQ: - val = _lo_freq; + /* + * so here we have to do some magic. because the TVRX uses a relatively high IF, + * we have to watch the sample rate to see if the IF will be aliased + * or if it will fall within Nyquist. + */ + codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX); + if(codec_rate/2 > tvrx_if_freq) val = _lo_freq; + //ok take a deep breath i am positive there is an easier way to get this number + else val = _lo_freq - tvrx_if_freq - (tvrx_if_freq-codec_rate)*int(tvrx_if_freq / (codec_rate/2)); return; case SUBDEV_PROP_FREQ_RANGE: diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 33b18b196..4aa730573 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -423,7 +423,8 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq) /*********************************************************************** * Codec Control ADC buffer bypass - * Enable this for DC-coupled daughterboards (TVRX) + * Disable this for AC-coupled daughterboards (TVRX) + * By default it is initialized TRUE. **********************************************************************/ void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { _ad9862_regs.byp_buffer_a = bypass; diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4f0549a37..1ac15a46a 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -32,6 +32,8 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; +static const dboard_id_t tvrx_id(0x0040); + class usrp1_dboard_iface : public dboard_iface { public: @@ -51,6 +53,10 @@ public: //init the clock rate shadows this->set_clock_rate(UNIT_RX, this->get_clock_rates(UNIT_RX).front()); this->set_clock_rate(UNIT_TX, this->get_clock_rates(UNIT_TX).front()); + + //yes this is evil but it's necessary for TVRX to work on USRP1 + if(_rx_dboard_id == tvrx_id) _codec->bypass_adc_buffers(false); + //else _codec->bypass_adc_buffers(false); //don't think this is necessary } ~usrp1_dboard_iface() -- cgit v1.2.3 From 04c74a3c74907e55e339f1568a1d5b4cdf190daf Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 10:07:13 -0700 Subject: usrp1: replace byteswap with htonx (it was wrong to just swap) also removed unused poke and peek 16 bit calls --- host/lib/usrp/usrp1/usrp1_iface.cpp | 16 ++-------------- host/lib/usrp/usrp1/usrp1_iface.hpp | 14 -------------- 2 files changed, 2 insertions(+), 28 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp index 5fd3987d5..64ced2905 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.cpp +++ b/host/lib/usrp/usrp1/usrp1_iface.cpp @@ -49,7 +49,7 @@ public: ******************************************************************/ void poke32(boost::uint32_t addr, boost::uint32_t value) { - boost::uint32_t swapped = byteswap(value); + boost::uint32_t swapped = uhd::htonx(value); if (iface_debug) { std::cout.fill('0'); @@ -72,12 +72,6 @@ public: std::cerr << "USRP: failed memory write: " << ret << std::endl; } - void poke16(boost::uint32_t, boost::uint16_t) - { - //fpga only handles 32 bit writes - std::cerr << "USRP: unsupported operation: poke16()" << std::endl; - } - boost::uint32_t peek32(boost::uint32_t addr) { boost::uint32_t value_out; @@ -95,13 +89,7 @@ public: if (ret < 0) std::cerr << "USRP: failed memory read: " << ret << std::endl; - return byteswap(value_out); - } - - boost::uint16_t peek16(boost::uint32_t addr) - { - boost::uint32_t val = peek32(addr); - return boost::uint16_t(val & 0xff); + return uhd::ntohx(value_out); } /******************************************************************* diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp index 9a3fdd6bc..3f608584a 100644 --- a/host/lib/usrp/usrp1/usrp1_iface.hpp +++ b/host/lib/usrp/usrp1/usrp1_iface.hpp @@ -53,20 +53,6 @@ public: */ virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; - /*! - * Write a register (16 bits) - * \param addr the address - * \param data the 16bit data - */ - virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; - - /*! - * read a register (16 bits) - * \param addr the address - * \return the 16bit data - */ - virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; - /*! * Perform an spi transaction. * \param which_slave the slave device number -- cgit v1.2.3 From 046d8a9a5a5b0addb7e6c8bfde7973f3051d48b1 Mon Sep 17 00:00:00 2001 From: Nick Foster Date: Thu, 30 Sep 2010 11:57:40 -0700 Subject: TVRX: Fixed to properly calculate alias frequencies. --- host/lib/usrp/dboard/db_tvrx.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index 6b71a3c6e..1cb74c5ae 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -372,12 +372,30 @@ void tvrx::set_freq(double freq) { _lo_freq = actual_lo_freq; //for rx props } +/*********************************************************************** + * Get the alias frequency of frequency freq when sampled at fs. + * \param freq the frequency of interest + * \param fs the sample rate + * \return the alias frequency + **********************************************************************/ + +static double get_alias(double freq, double fs) { + double alias; + freq = fmod(freq, fs); + if(freq >= (fs/2)) { + alias = fs - freq; + } else { + alias = freq; + } + return alias; +} + /*********************************************************************** * RX Get and Set **********************************************************************/ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ named_prop_t key = named_prop_t::extract(key_); - int codec_rate; + double codec_rate; //handle the get request conditioned on the key switch(key.as()){ @@ -410,9 +428,7 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){ * or if it will fall within Nyquist. */ codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX); - if(codec_rate/2 > tvrx_if_freq) val = _lo_freq; - //ok take a deep breath i am positive there is an easier way to get this number - else val = _lo_freq - tvrx_if_freq - (tvrx_if_freq-codec_rate)*int(tvrx_if_freq / (codec_rate/2)); + val = (_lo_freq - tvrx_if_freq) + get_alias(tvrx_if_freq, codec_rate); return; case SUBDEV_PROP_FREQ_RANGE: -- cgit v1.2.3 From 2c8a7c7debf19d92065661cc1d258f97bd38e224 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 30 Sep 2010 14:36:24 -0700 Subject: uhd: implemented recv timeout for zero copy interface --- host/include/uhd/transport/zero_copy.hpp | 11 +++++--- host/lib/transport/libusb1_zero_copy.cpp | 42 +++++++++++++++---------------- host/lib/transport/udp_zero_copy_asio.cpp | 5 ++-- host/lib/transport/zero_copy.cpp | 4 +-- host/lib/usrp/usrp1/io_impl.cpp | 8 +++--- host/lib/usrp/usrp2/io_impl.cpp | 5 ++-- 6 files changed, 39 insertions(+), 36 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 513291b63..8ecafd3fb 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -122,9 +122,10 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. + * \param timeout_ms the timeout to get the buffer in ms * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_recv_buffer::sptr get_recv_buff(void) = 0; + virtual managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms) = 0; /*! * Get the maximum number of receive frames: @@ -171,16 +172,19 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. + * \param timeout_ms the timeout to get the buffer in ms + * \return a managed buffer, or null sptr on timeout/error */ - managed_recv_buffer::sptr get_recv_buff(void); + managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); private: /*! * Perform a private copying recv. * \param buff the buffer to write data into + * \param timeout_ms the timeout to get the buffer in ms * \return the number of bytes written to buff, 0 for timeout, negative for error */ - virtual ssize_t recv(const boost::asio::mutable_buffer &buff) = 0; + virtual ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms) = 0; UHD_PIMPL_DECL(impl) _impl; }; @@ -204,6 +208,7 @@ namespace uhd{ namespace transport{ /*! * Get a new send buffer from this transport object. + * \return a managed buffer, or null sptr on timeout/error */ managed_send_buffer::sptr get_send_buff(void); diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f2dcff6b5..f9beb0b4c 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -308,8 +308,7 @@ public: } private: - const boost::asio::const_buffer &get() const - { + const boost::asio::const_buffer &get(void) const{ return _buff; } @@ -369,8 +368,7 @@ public: } private: - const boost::asio::mutable_buffer &get() const - { + const boost::asio::mutable_buffer &get(void) const{ return _buff; } @@ -395,13 +393,13 @@ public: typedef boost::shared_ptr sptr; libusb_zero_copy_impl( - libusb::device_handle::sptr handle, - unsigned int recv_endpoint, unsigned int send_endpoint, - size_t recv_xfer_size, size_t recv_num_xfers, - size_t send_xfer_size, size_t send_num_xfers - ); + libusb::device_handle::sptr handle, + unsigned int recv_endpoint, unsigned int send_endpoint, + size_t recv_xfer_size, size_t recv_num_xfers, + size_t send_xfer_size, size_t send_num_xfers + ); - managed_recv_buffer::sptr get_recv_buff(void); + managed_recv_buffer::sptr get_recv_buff(size_t timeout_ms); managed_send_buffer::sptr get_send_buff(void); size_t get_num_recv_frames(void) const { return _recv_num_frames; } @@ -419,23 +417,23 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( size_t recv_xfer_size, size_t recv_num_xfers, size_t send_xfer_size, size_t send_num_xfers ){ - _handle = handle; + _handle = handle; - //if the sizes are left at 0 (automatic) -> use the defaults - if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; - if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; - if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; - if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; + //if the sizes are left at 0 (automatic) -> use the defaults + if (recv_xfer_size == 0) recv_xfer_size = DEFAULT_XFER_SIZE; + if (recv_num_xfers == 0) recv_num_xfers = DEFAULT_NUM_XFERS; + if (send_xfer_size == 0) send_xfer_size = DEFAULT_XFER_SIZE; + if (send_num_xfers == 0) send_num_xfers = DEFAULT_NUM_XFERS; //sanity check the transfer sizes UHD_ASSERT_THROW(recv_xfer_size % 512 == 0); UHD_ASSERT_THROW(send_xfer_size % 512 == 0); - //store the num xfers for the num frames count - _recv_num_frames = recv_num_xfers; - _send_num_frames = send_num_xfers; + //store the num xfers for the num frames count + _recv_num_frames = recv_num_xfers; + _send_num_frames = send_num_xfers; - _handle->claim_interface(2 /*in interface*/); + _handle->claim_interface(2 /*in interface*/); _handle->claim_interface(1 /*out interface*/); _recv_ep = usb_endpoint::sptr(new usb_endpoint( @@ -461,8 +459,8 @@ libusb_zero_copy_impl::libusb_zero_copy_impl( * Return empty pointer if no transfer is available (timeout or error). * \return pointer to a managed receive buffer */ -managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(void){ - libusb_transfer *lut = _recv_ep->get_lut_with_wait(/* TODO timeout API */); +managed_recv_buffer::sptr libusb_zero_copy_impl::get_recv_buff(size_t timeout_ms){ + libusb_transfer *lut = _recv_ep->get_lut_with_wait(timeout_ms); if (lut == NULL) { return managed_recv_buffer::sptr(); } diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee989ee2b..0a6c9f2af 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -35,7 +35,6 @@ static const size_t MIN_RECV_SOCK_BUFF_SIZE = size_t(sizeof(boost::uint32_t) * 2 //Perhaps this is due to the kernel scheduling, //but may change with host-based flow control. static const size_t MIN_SEND_SOCK_BUFF_SIZE = size_t(10e3); -static const double RECV_TIMEOUT = 0.1; //100 ms /*********************************************************************** * Zero Copy UDP implementation with ASIO: @@ -110,11 +109,11 @@ private: boost::asio::io_service _io_service; int _sock_fd; - ssize_t recv(const boost::asio::mutable_buffer &buff){ + ssize_t recv(const boost::asio::mutable_buffer &buff, size_t timeout_ms){ //setup timeval for timeout timeval tv; tv.tv_sec = 0; - tv.tv_usec = int(RECV_TIMEOUT*1e6); + tv.tv_usec = timeout_ms*1000; //setup rset for timeout fd_set rset; diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp index 8a1cde694..1fcf846a0 100644 --- a/host/lib/transport/zero_copy.cpp +++ b/host/lib/transport/zero_copy.cpp @@ -68,12 +68,12 @@ phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ /* NOP */ } -managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(void){ +managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(size_t timeout_ms){ //allocate memory boost::uint8_t *recv_mem = new boost::uint8_t[_impl->max_buff_size]; //call recv() with timeout option - ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size)); + ssize_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size), timeout_ms); if (num_bytes <= 0) return managed_recv_buffer::sptr(); //NULL sptr diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp index 73974f2d6..aee760a83 100644 --- a/host/lib/usrp/usrp1/io_impl.cpp +++ b/host/lib/usrp/usrp1/io_impl.cpp @@ -272,18 +272,18 @@ static void usrp1_bs_vrt_unpacker( } static bool get_recv_buffs( - zero_copy_if::sptr zc_if, + zero_copy_if::sptr zc_if, size_t timeout_ms, vrt_packet_handler::managed_recv_buffs_t &buffs ){ UHD_ASSERT_THROW(buffs.size() == 1); - buffs[0] = zc_if->get_recv_buff(); + buffs[0] = zc_if->get_recv_buff(timeout_ms); return buffs[0].get() != NULL; } size_t usrp1_impl::recv( const std::vector &buffs, size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, size_t /*timeout_ms TODO*/ + recv_mode_t recv_mode, size_t timeout_ms ){ size_t num_samps_recvd = vrt_packet_handler::recv( _io_impl->packet_handler_recv_state, //last state of the recv handler @@ -292,7 +292,7 @@ size_t usrp1_impl::recv( io_type, _rx_otw_type, //input and output types to convert _clock_ctrl->get_master_clock_freq(), //master clock tick rate &usrp1_bs_vrt_unpacker, - boost::bind(&get_recv_buffs, _data_transport, _1), + boost::bind(&get_recv_buffs, _data_transport, timeout_ms, _1), &vrt_packet_handler::handle_overflow_nop, 0, //vrt header offset _rx_subdev_spec.size() //num channels diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 65411801d..3395f94e2 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -33,6 +33,7 @@ using namespace uhd::transport; namespace asio = boost::asio; static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; +static const double RECV_TIMEOUT_MS = 100; /*********************************************************************** * io impl details (internal to this file) @@ -90,7 +91,7 @@ void usrp2_impl::io_impl::recv_pirate_loop( size_t next_packet_seq = 0; while(recv_pirate_crew_raiding){ - managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); + managed_recv_buffer::sptr buff = zc_if->get_recv_buff(RECV_TIMEOUT_MS); if (not buff.get()) continue; //ignore timeout/error buffers try{ @@ -150,7 +151,7 @@ void usrp2_impl::io_init(void){ std::memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->commit(sizeof(data)); //drain the recv buffers (may have junk) - while (data_transport->get_recv_buff().get()){}; + while (data_transport->get_recv_buff(RECV_TIMEOUT_MS).get()){}; } //the number of recv frames is the number for the first transport -- cgit v1.2.3