From 2e401993b5b3e8920017729f4325ff5a51790fa5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 17 Jun 2011 15:37:30 -0700 Subject: e100: removed usrp from directory prefix --- host/lib/usrp/CMakeLists.txt | 2 +- host/lib/usrp/b100/b100_ctrl.cpp | 17 +- host/lib/usrp/e100/CMakeLists.txt | 49 ++ host/lib/usrp/e100/clock_ctrl.cpp | 512 +++++++++++++++++++++ host/lib/usrp/e100/clock_ctrl.hpp | 123 +++++ host/lib/usrp/e100/codec_ctrl.cpp | 280 +++++++++++ host/lib/usrp/e100/codec_ctrl.hpp | 90 ++++ host/lib/usrp/e100/codec_impl.cpp | 149 ++++++ host/lib/usrp/e100/dboard_iface.cpp | 300 ++++++++++++ host/lib/usrp/e100/dboard_impl.cpp | 185 ++++++++ host/lib/usrp/e100/dsp_impl.cpp | 217 +++++++++ host/lib/usrp/e100/e100_iface.cpp | 393 ++++++++++++++++ host/lib/usrp/e100/e100_iface.hpp | 90 ++++ host/lib/usrp/e100/e100_impl.cpp | 227 +++++++++ host/lib/usrp/e100/e100_impl.hpp | 183 ++++++++ host/lib/usrp/e100/e100_mmap_zero_copy.cpp | 269 +++++++++++ host/lib/usrp/e100/e100_regs.hpp | 242 ++++++++++ host/lib/usrp/e100/fpga_downloader.cpp | 272 +++++++++++ host/lib/usrp/e100/include/linux/usrp_e.h | 91 ++++ host/lib/usrp/e100/io_impl.cpp | 297 ++++++++++++ host/lib/usrp/e100/mboard_impl.cpp | 256 +++++++++++ host/lib/usrp/usrp_e100/CMakeLists.txt | 49 -- host/lib/usrp/usrp_e100/clock_ctrl.cpp | 512 --------------------- host/lib/usrp/usrp_e100/clock_ctrl.hpp | 123 ----- host/lib/usrp/usrp_e100/codec_ctrl.cpp | 280 ----------- host/lib/usrp/usrp_e100/codec_ctrl.hpp | 90 ---- host/lib/usrp/usrp_e100/codec_impl.cpp | 149 ------ host/lib/usrp/usrp_e100/dboard_iface.cpp | 300 ------------ host/lib/usrp/usrp_e100/dboard_impl.cpp | 185 -------- host/lib/usrp/usrp_e100/dsp_impl.cpp | 217 --------- host/lib/usrp/usrp_e100/fpga_downloader.cpp | 272 ----------- host/lib/usrp/usrp_e100/include/linux/usrp_e.h | 91 ---- host/lib/usrp/usrp_e100/io_impl.cpp | 297 ------------ host/lib/usrp/usrp_e100/mboard_impl.cpp | 256 ----------- host/lib/usrp/usrp_e100/usrp_e100_iface.cpp | 393 ---------------- host/lib/usrp/usrp_e100/usrp_e100_iface.hpp | 90 ---- host/lib/usrp/usrp_e100/usrp_e100_impl.cpp | 227 --------- host/lib/usrp/usrp_e100/usrp_e100_impl.hpp | 183 -------- .../usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp | 269 ----------- host/lib/usrp/usrp_e100/usrp_e100_regs.hpp | 242 ---------- 40 files changed, 4233 insertions(+), 4236 deletions(-) create mode 100644 host/lib/usrp/e100/CMakeLists.txt create mode 100644 host/lib/usrp/e100/clock_ctrl.cpp create mode 100644 host/lib/usrp/e100/clock_ctrl.hpp create mode 100644 host/lib/usrp/e100/codec_ctrl.cpp create mode 100644 host/lib/usrp/e100/codec_ctrl.hpp create mode 100644 host/lib/usrp/e100/codec_impl.cpp create mode 100644 host/lib/usrp/e100/dboard_iface.cpp create mode 100644 host/lib/usrp/e100/dboard_impl.cpp create mode 100644 host/lib/usrp/e100/dsp_impl.cpp create mode 100644 host/lib/usrp/e100/e100_iface.cpp create mode 100644 host/lib/usrp/e100/e100_iface.hpp create mode 100644 host/lib/usrp/e100/e100_impl.cpp create mode 100644 host/lib/usrp/e100/e100_impl.hpp create mode 100644 host/lib/usrp/e100/e100_mmap_zero_copy.cpp create mode 100644 host/lib/usrp/e100/e100_regs.hpp create mode 100644 host/lib/usrp/e100/fpga_downloader.cpp create mode 100644 host/lib/usrp/e100/include/linux/usrp_e.h create mode 100644 host/lib/usrp/e100/io_impl.cpp create mode 100644 host/lib/usrp/e100/mboard_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/CMakeLists.txt delete mode 100644 host/lib/usrp/usrp_e100/clock_ctrl.cpp delete mode 100644 host/lib/usrp/usrp_e100/clock_ctrl.hpp delete mode 100644 host/lib/usrp/usrp_e100/codec_ctrl.cpp delete mode 100644 host/lib/usrp/usrp_e100/codec_ctrl.hpp delete mode 100644 host/lib/usrp/usrp_e100/codec_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/dboard_iface.cpp delete mode 100644 host/lib/usrp/usrp_e100/dboard_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/dsp_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/fpga_downloader.cpp delete mode 100644 host/lib/usrp/usrp_e100/include/linux/usrp_e.h delete mode 100644 host/lib/usrp/usrp_e100/io_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/mboard_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_iface.cpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_iface.hpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_impl.cpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_impl.hpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp delete mode 100644 host/lib/usrp/usrp_e100/usrp_e100_regs.hpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 80f4bf45e..45498e3b4 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -38,4 +38,4 @@ INCLUDE_SUBDIRECTORY(fx2) INCLUDE_SUBDIRECTORY(usrp1) INCLUDE_SUBDIRECTORY(usrp2) INCLUDE_SUBDIRECTORY(b100) -INCLUDE_SUBDIRECTORY(usrp_e100) +INCLUDE_SUBDIRECTORY(e100) diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp index 2a87703f7..6d415facc 100644 --- a/host/lib/usrp/b100/b100_ctrl.cpp +++ b/host/lib/usrp/b100/b100_ctrl.cpp @@ -205,18 +205,15 @@ void b100_ctrl_impl::viking_marauder_loop(boost::barrier &spawn_barrier) { time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), 64e6 //FIXME get from clock_ctrl ); metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & + async_msg_fifo.push_with_pop_on_full(metadata); + if (metadata.event_code & ( async_metadata_t::EVENT_CODE_UNDERFLOW - | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) ) - UHD_MSG(fastpath) << "U"; - - if (metadata.event_code & + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & ( async_metadata_t::EVENT_CODE_SEQ_ERROR - | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) ) - UHD_MSG(fastpath) << "S"; - - async_msg_fifo.push_with_pop_on_full(metadata); + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; continue; } UHD_MSG(error) << "Control: unknown async response" << std::endl; diff --git a/host/lib/usrp/e100/CMakeLists.txt b/host/lib/usrp/e100/CMakeLists.txt new file mode 100644 index 000000000..15133ad5e --- /dev/null +++ b/host/lib/usrp/e100/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# Copyright 2010-2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +######################################################################## +# This file included, use CMake directory variables +######################################################################## + +######################################################################## +# Conditionally configure the USRP-E100 support +######################################################################## +LIBUHD_REGISTER_COMPONENT("USRP-E100" ENABLE_E100 OFF "ENABLE_LIBUHD;LINUX" OFF) + +IF(ENABLE_E100) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + + LIBUHD_APPEND_SOURCES( + ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_impl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_iface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_iface.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_mmap_zero_copy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e100_regs.hpp + ) +ENDIF(ENABLE_E100) diff --git a/host/lib/usrp/e100/clock_ctrl.cpp b/host/lib/usrp/e100/clock_ctrl.cpp new file mode 100644 index 000000000..ff64d9ca7 --- /dev/null +++ b/host/lib/usrp/e100/clock_ctrl.cpp @@ -0,0 +1,512 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "clock_ctrl.hpp" +#include "ad9522_regs.hpp" +#include +#include +#include +#include +#include "e100_regs.hpp" //spi slave constants +#include +#include +#include +#include +#include //gcd +#include +#include + +using namespace uhd; + +/*********************************************************************** + * Constants + **********************************************************************/ +static const bool ENABLE_THE_TEST_OUT = true; +static const double REFERENCE_INPUT_RATE = 10e6; + +/*********************************************************************** + * Helpers + **********************************************************************/ +template static void set_clock_divider( + size_t divider, div_type &low, div_type &high, bypass_type &bypass +){ + high = divider/2 - 1; + low = divider - high - 2; + bypass = (divider == 1)? 1 : 0; +} + +/*********************************************************************** + * Clock rate calculation stuff: + * Using the internal VCO between 1400 and 1800 MHz + **********************************************************************/ +struct clock_settings_type{ + size_t ref_clock_doubler, r_counter, a_counter, b_counter, prescaler, vco_divider, chan_divider; + size_t get_n_counter(void) const{return prescaler * b_counter + a_counter;} + double get_ref_rate(void) const{return REFERENCE_INPUT_RATE * ref_clock_doubler;} + double get_vco_rate(void) const{return get_ref_rate()/r_counter * get_n_counter();} + double get_chan_rate(void) const{return get_vco_rate()/vco_divider;} + double get_out_rate(void) const{return get_chan_rate()/chan_divider;} + std::string to_pp_string(void) const{ + return str(boost::format( + " r_counter: %d\n" + " a_counter: %d\n" + " b_counter: %d\n" + " prescaler: %d\n" + " vco_divider: %d\n" + " chan_divider: %d\n" + " vco_rate: %fMHz\n" + " chan_rate: %fMHz\n" + " out_rate: %fMHz\n" + ) + % r_counter + % a_counter + % b_counter + % prescaler + % vco_divider + % chan_divider + % (get_vco_rate()/1e6) + % (get_chan_rate()/1e6) + % (get_out_rate()/1e6) + ); + } +}; + +//! gives the greatest divisor of num between 1 and max inclusive +template static inline T greatest_divisor(T num, T max){ + for (T i = max; i > 1; i--) if (num%i == 0) return i; return 1; +} + +//! gives the least divisor of num between min and num exclusive +template static inline T least_divisor(T num, T min){ + for (T i = min; i < num; i++) if (num%i == 0) return i; return 1; +} + +static clock_settings_type get_clock_settings(double rate){ + clock_settings_type cs; + cs.ref_clock_doubler = 2; //always doubling + cs.prescaler = 8; //set to 8 when input is under 2400 MHz + + //basic formulas used below: + //out_rate*X = ref_rate*Y + //X = i*ref_rate/gcd + //Y = i*out_rate/gcd + //X = chan_div * vco_div * R + //Y = P*B + A + + const boost::uint64_t out_rate = boost::uint64_t(rate); + const boost::uint64_t ref_rate = boost::uint64_t(cs.get_ref_rate()); + const size_t gcd = size_t(boost::math::gcd(ref_rate, out_rate)); + + for (size_t i = 1; i <= 100; i++){ + const size_t X = i*ref_rate/gcd; + const size_t Y = i*out_rate/gcd; + + //determine A and B (P is fixed) + cs.b_counter = Y/cs.prescaler; + cs.a_counter = Y - cs.b_counter*cs.prescaler; + + static const double vco_bound_pad = 100e6; + for ( //calculate an r divider that fits into the bounds of the vco + cs.r_counter = size_t(cs.get_n_counter()*cs.get_ref_rate()/(1800e6 - vco_bound_pad)); + cs.r_counter <= size_t(cs.get_n_counter()*cs.get_ref_rate()/(1400e6 + vco_bound_pad)) + and cs.r_counter > 0; cs.r_counter++ + ){ + + //determine chan_div and vco_div + //and fill in that order of preference + cs.chan_divider = greatest_divisor(X/cs.r_counter, 32); + cs.vco_divider = greatest_divisor(X/cs.chan_divider/cs.r_counter, 6); + + //avoid a vco divider of 1 (if possible) + if (cs.vco_divider == 1){ + cs.vco_divider = least_divisor(cs.chan_divider, 2); + cs.chan_divider /= cs.vco_divider; + } + + UHD_LOGV(always) + << "gcd " << gcd << std::endl + << "X " << X << std::endl + << "Y " << Y << std::endl + << cs.to_pp_string() << std::endl + ; + + //filter limits on the counters + if (cs.vco_divider == 1) continue; + if (cs.r_counter >= (1<<14)) continue; + if (cs.b_counter == 2) continue; + if (cs.b_counter == 1 and cs.a_counter != 0) continue; + if (cs.b_counter >= (1<<13)) continue; + if (cs.a_counter >= (1<<6)) continue; + + UHD_MSG(status) << "USRP-E100 clock control: " << i << std::endl << cs.to_pp_string() << std::endl; + return cs; + } + } + + throw uhd::value_error(str(boost::format( + "USRP-E100 clock control: could not calculate settings for clock rate %fMHz" + ) % (rate/1e6))); +} + +/*********************************************************************** + * Clock Control Implementation + **********************************************************************/ +class e100_clock_ctrl_impl : public e100_clock_ctrl{ +public: + e100_clock_ctrl_impl(e100_iface::sptr iface, double master_clock_rate){ + _iface = iface; + _chan_rate = 0.0; + _out_rate = 0.0; + + //perform soft-reset + _ad9522_regs.soft_reset = 1; + this->send_reg(0x000); + this->latch_regs(); + _ad9522_regs.soft_reset = 0; + + //init the clock gen registers + //Note: out0 should already be clocking the FPGA or this isnt going to work + _ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO; + _ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin + _ad9522_regs.status_pin_control = 0x1; //n divider + _ad9522_regs.ld_pin_control = 0x00; //dld + _ad9522_regs.refmon_pin_control = 0x12; //show ref2 + _ad9522_regs.lock_detect_counter = ad9522_regs_t::LOCK_DETECT_COUNTER_16CYC; + + this->use_internal_ref(); + + //initialize the FPGA clock rate + UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl; + this->set_fpga_clock_rate(master_clock_rate); + + this->enable_test_clock(ENABLE_THE_TEST_OUT); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + } + + ~e100_clock_ctrl_impl(void){ + this->enable_test_clock(ENABLE_THE_TEST_OUT); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + } + + /*********************************************************************** + * Clock rate control: + * - set clock rate w/ internal VCO + * - set clock rate w/ external VCXO + **********************************************************************/ + void set_clock_settings_with_internal_vco(double rate){ + const clock_settings_type cs = get_clock_settings(rate); + + //set the rates to private variables so the implementation knows! + _chan_rate = cs.get_chan_rate(); + _out_rate = cs.get_out_rate(); + + _ad9522_regs.enable_clock_doubler = (cs.ref_clock_doubler == 2)? 1 : 0; + + _ad9522_regs.set_r_counter(cs.r_counter); + _ad9522_regs.a_counter = cs.a_counter; + _ad9522_regs.set_b_counter(cs.b_counter); + UHD_ASSERT_THROW(cs.prescaler == 8); //assumes this below: + _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV8_9; + + _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; + _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA; + + _ad9522_regs.bypass_vco_divider = 0; + switch(cs.vco_divider){ + case 1: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV1; break; + case 2: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV2; break; + case 3: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV3; break; + case 4: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV4; break; + case 5: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; break; + case 6: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV6; break; + } + _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO; + + //setup fpga master clock + _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; + set_clock_divider(cs.chan_divider, + _ad9522_regs.divider0_low_cycles, + _ad9522_regs.divider0_high_cycles, + _ad9522_regs.divider0_bypass + ); + + //setup codec clock + _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; + set_clock_divider(cs.chan_divider, + _ad9522_regs.divider1_low_cycles, + _ad9522_regs.divider1_high_cycles, + _ad9522_regs.divider1_bypass + ); + + this->send_all_regs(); + calibrate_now(); + } + + void set_clock_settings_with_external_vcxo(double rate){ + //set the rates to private variables so the implementation knows! + _chan_rate = rate; + _out_rate = rate; + + _ad9522_regs.enable_clock_doubler = 1; //doubler always on + const double ref_rate = REFERENCE_INPUT_RATE*2; + + //bypass prescaler such that N = B + long gcd = boost::math::gcd(long(ref_rate), long(rate)); + _ad9522_regs.set_r_counter(int(ref_rate/gcd)); + _ad9522_regs.a_counter = 0; + _ad9522_regs.set_b_counter(int(rate/gcd)); + _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV1; + + //setup external vcxo + _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; + _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA; + _ad9522_regs.bypass_vco_divider = 1; + _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_EXTERNAL; + + //setup fpga master clock + _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; + _ad9522_regs.divider0_bypass = 1; + + //setup codec clock + _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; + _ad9522_regs.divider1_bypass = 1; + + this->send_all_regs(); + } + + void set_fpga_clock_rate(double rate){ + if (_out_rate == rate) return; + if (rate == 61.44e6) set_clock_settings_with_external_vcxo(rate); + else set_clock_settings_with_internal_vco(rate); + //clock rate changed! update dboard clocks and FPGA ticks per second + set_rx_dboard_clock_rate(rate); + set_tx_dboard_clock_rate(rate); + _iface->poke32(E100_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate())); + } + + double get_fpga_clock_rate(void){ + return this->_out_rate; + } + + /*********************************************************************** + * Special test clock output + **********************************************************************/ + void enable_test_clock(bool enb){ + //setup test clock (same divider as codec clock) + _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS; + _ad9522_regs.out4_cmos_configuration = (enb)? + ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON : + ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF; + this->send_reg(0x0F4); + this->latch_regs(); + } + + /*********************************************************************** + * RX Dboard Clock Control (output 9, divider 3) + **********************************************************************/ + void enable_rx_dboard_clock(bool enb){ + _ad9522_regs.out9_format = ad9522_regs_t::OUT9_FORMAT_CMOS; + _ad9522_regs.out9_cmos_configuration = (enb)? + ad9522_regs_t::OUT9_CMOS_CONFIGURATION_B_ON : + ad9522_regs_t::OUT9_CMOS_CONFIGURATION_OFF; + this->send_reg(0x0F9); + this->latch_regs(); + } + + std::vector get_rx_dboard_clock_rates(void){ + std::vector rates; + for(size_t div = 1; div <= 16+16; div++) + rates.push_back(this->_chan_rate/div); + return rates; + } + + void set_rx_dboard_clock_rate(double rate){ + assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate"); + _rx_clock_rate = rate; + size_t divider = size_t(this->_chan_rate/rate); + //set the divider registers + set_clock_divider(divider, + _ad9522_regs.divider3_low_cycles, + _ad9522_regs.divider3_high_cycles, + _ad9522_regs.divider3_bypass + ); + this->send_reg(0x199); + this->send_reg(0x19a); + this->soft_sync(); + } + + double get_rx_clock_rate(void){ + return _rx_clock_rate; + } + + /*********************************************************************** + * TX Dboard Clock Control (output 6, divider 2) + **********************************************************************/ + void enable_tx_dboard_clock(bool enb){ + _ad9522_regs.out6_format = ad9522_regs_t::OUT6_FORMAT_CMOS; + _ad9522_regs.out6_cmos_configuration = (enb)? + ad9522_regs_t::OUT6_CMOS_CONFIGURATION_B_ON : + ad9522_regs_t::OUT6_CMOS_CONFIGURATION_OFF; + this->send_reg(0x0F6); + this->latch_regs(); + } + + std::vector get_tx_dboard_clock_rates(void){ + return get_rx_dboard_clock_rates(); //same master clock, same dividers... + } + + void set_tx_dboard_clock_rate(double rate){ + assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate"); + _tx_clock_rate = rate; + size_t divider = size_t(this->_chan_rate/rate); + //set the divider registers + set_clock_divider(divider, + _ad9522_regs.divider2_low_cycles, + _ad9522_regs.divider2_high_cycles, + _ad9522_regs.divider2_bypass + ); + this->send_reg(0x196); + this->send_reg(0x197); + this->soft_sync(); + } + + double get_tx_clock_rate(void){ + return _tx_clock_rate; + } + + /*********************************************************************** + * Clock reference control + **********************************************************************/ + void use_internal_ref(void) { + _ad9522_regs.enable_ref2 = 1; + _ad9522_regs.enable_ref1 = 0; + _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; + _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL; + this->send_reg(0x01C); + this->latch_regs(); + } + + void use_external_ref(void) { + _ad9522_regs.enable_ref2 = 0; + _ad9522_regs.enable_ref1 = 1; + _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1; + _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL; + this->send_reg(0x01C); + this->latch_regs(); + } + + void use_auto_ref(void) { + _ad9522_regs.enable_ref2 = 1; + _ad9522_regs.enable_ref1 = 1; + _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1; + _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_AUTO; + this->send_reg(0x01C); + this->latch_regs(); + } + +private: + e100_iface::sptr _iface; + ad9522_regs_t _ad9522_regs; + double _out_rate; //rate at the fpga and codec + double _chan_rate; //rate before final dividers + double _rx_clock_rate, _tx_clock_rate; + + void latch_regs(void){ + _ad9522_regs.io_update = 1; + this->send_reg(0x232); + } + + void send_reg(boost::uint16_t addr){ + boost::uint32_t reg = _ad9522_regs.get_write_reg(addr); + UHD_LOGV(often) << "clock control write reg: " << std::hex << reg << std::endl; + _iface->write_spi( + UE_SPI_SS_AD9522, + spi_config_t::EDGE_RISE, + reg, 24 + ); + } + + void calibrate_now(void){ + //vco calibration routine: + _ad9522_regs.vco_calibration_now = 0; + this->send_reg(0x18); + this->latch_regs(); + _ad9522_regs.vco_calibration_now = 1; + this->send_reg(0x18); + this->latch_regs(); + //wait for calibration done: + static const boost::uint8_t addr = 0x01F; + for (size_t ms10 = 0; ms10 < 100; ms10++){ + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + boost::uint32_t reg = _iface->read_spi( + UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, + _ad9522_regs.get_read_reg(addr), 24 + ); + _ad9522_regs.set_reg(addr, reg); + if (_ad9522_regs.vco_calibration_finished) goto wait_for_ld; + } + UHD_MSG(error) << "USRP-E100 clock control: VCO calibration timeout" << std::endl; + wait_for_ld: + //wait for digital lock detect: + for (size_t ms10 = 0; ms10 < 100; ms10++){ + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + boost::uint32_t reg = _iface->read_spi( + UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, + _ad9522_regs.get_read_reg(addr), 24 + ); + _ad9522_regs.set_reg(addr, reg); + if (_ad9522_regs.digital_lock_detect) return; + } + UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl; + } + + void soft_sync(void){ + _ad9522_regs.soft_sync = 1; + this->send_reg(0x230); + this->latch_regs(); + _ad9522_regs.soft_sync = 0; + this->send_reg(0x230); + this->latch_regs(); + } + + void send_all_regs(void){ + //setup a list of register ranges to write + typedef std::pair range_t; + static const std::vector ranges = boost::assign::list_of + (range_t(0x000, 0x000)) (range_t(0x010, 0x01F)) + (range_t(0x0F0, 0x0FD)) (range_t(0x190, 0x19B)) + (range_t(0x1E0, 0x1E1)) (range_t(0x230, 0x230)) + ; + + //write initial register values and latch/update + BOOST_FOREACH(const range_t &range, ranges){ + for(boost::uint16_t addr = range.first; addr <= range.second; addr++){ + this->send_reg(addr); + } + } + this->latch_regs(); + } +}; + +/*********************************************************************** + * Clock Control Make + **********************************************************************/ +e100_clock_ctrl::sptr e100_clock_ctrl::make(e100_iface::sptr iface, double master_clock_rate){ + return sptr(new e100_clock_ctrl_impl(iface, master_clock_rate)); +} diff --git a/host/lib/usrp/e100/clock_ctrl.hpp b/host/lib/usrp/e100/clock_ctrl.hpp new file mode 100644 index 000000000..f3a6de0fa --- /dev/null +++ b/host/lib/usrp/e100/clock_ctrl.hpp @@ -0,0 +1,123 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_USRP_E100_CLOCK_CTRL_HPP +#define INCLUDED_USRP_E100_CLOCK_CTRL_HPP + +#include "e100_iface.hpp" +#include +#include +#include + +/*! + * The usrp-e clock control: + * - Setup system clocks. + * - Disable/enable clock lines. + */ +class e100_clock_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new clock control object. + * \param iface the usrp_e100 iface object + * \param master clock rate the FPGA rate + * \return the clock control object + */ + static sptr make(e100_iface::sptr iface, double master_clock_rate); + + /*! + * Set the rate of the fpga clock line. + * Throws if rate is not valid. + * \param rate the new rate in Hz + */ + virtual void set_fpga_clock_rate(double rate) = 0; + + /*! + * Get the rate of the fpga clock line. + * \return the fpga clock rate in Hz + */ + virtual double get_fpga_clock_rate(void) = 0; + + /*! + * Get the possible rates of the rx dboard clock. + * \return a vector of clock rates in Hz + */ + virtual std::vector get_rx_dboard_clock_rates(void) = 0; + + /*! + * Get the possible rates of the tx dboard clock. + * \return a vector of clock rates in Hz + */ + virtual std::vector get_tx_dboard_clock_rates(void) = 0; + + /*! + * Set the rx dboard clock rate to a possible rate. + * \param rate the new clock rate in Hz + * \throw exception when rate cannot be achieved + */ + virtual void set_rx_dboard_clock_rate(double rate) = 0; + + /*! + * Set the tx dboard clock rate to a possible rate. + * \param rate the new clock rate in Hz + * \throw exception when rate cannot be achieved + */ + virtual void set_tx_dboard_clock_rate(double rate) = 0; + + /*! + * Get the current rx dboard clock rate. + * \return the clock rate in Hz + */ + virtual double get_rx_clock_rate(void) = 0; + + /*! + * Get the current tx dboard clock rate. + * \return the clock rate in Hz + */ + virtual double get_tx_clock_rate(void) = 0; + + /*! + * Enable/disable the rx dboard clock. + * \param enb true to enable + */ + virtual void enable_rx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable the tx dboard clock. + * \param enb true to enable + */ + virtual void enable_tx_dboard_clock(bool enb) = 0; + + /*! + * Use the internal TCXO reference + */ + virtual void use_internal_ref(void) = 0; + + /*! + * Use the external SMA reference + */ + virtual void use_external_ref(void) = 0; + + /*! + * Use external if available, internal otherwise + */ + virtual void use_auto_ref(void) = 0; + +}; + +#endif /* INCLUDED_USRP_E100_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/e100/codec_ctrl.cpp b/host/lib/usrp/e100/codec_ctrl.cpp new file mode 100644 index 000000000..a796d5cc5 --- /dev/null +++ b/host/lib/usrp/e100/codec_ctrl.cpp @@ -0,0 +1,280 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "codec_ctrl.hpp" +#include "ad9862_regs.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "e100_regs.hpp" //spi slave constants +#include + +using namespace uhd; + +const gain_range_t e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1)); +const gain_range_t e100_codec_ctrl::rx_pga_gain_range(0, 20, 1); + +/*********************************************************************** + * Codec Control Implementation + **********************************************************************/ +class e100_codec_ctrl_impl : public e100_codec_ctrl{ +public: + //structors + e100_codec_ctrl_impl(e100_iface::sptr iface); + ~e100_codec_ctrl_impl(void); + + //aux adc and dac control + double read_aux_adc(aux_adc_t which); + void write_aux_dac(aux_dac_t which, double volts); + + //pga gain control + void set_tx_pga_gain(double); + double get_tx_pga_gain(void); + void set_rx_pga_gain(double, char); + double get_rx_pga_gain(char); + +private: + e100_iface::sptr _iface; + ad9862_regs_t _ad9862_regs; + void send_reg(boost::uint8_t addr); + void recv_reg(boost::uint8_t addr); +}; + +/*********************************************************************** + * Codec Control Structors + **********************************************************************/ +e100_codec_ctrl_impl::e100_codec_ctrl_impl(e100_iface::sptr iface){ + _iface = iface; + + //soft reset + _ad9862_regs.soft_reset = 1; + this->send_reg(0); + + //initialize the codec register settings + _ad9862_regs.sdio_bidir = ad9862_regs_t::SDIO_BIDIR_SDIO_SDO; + _ad9862_regs.lsb_first = ad9862_regs_t::LSB_FIRST_MSB; + _ad9862_regs.soft_reset = 0; + + //setup rx side of codec + _ad9862_regs.byp_buffer_a = 1; + _ad9862_regs.byp_buffer_b = 1; + _ad9862_regs.buffer_a_pd = 1; + _ad9862_regs.buffer_b_pd = 1; + _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control + _ad9862_regs.rx_twos_comp = 1; + _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; + + //setup tx side of codec + _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; + _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; + _ad9862_regs.tx_retime = ad9862_regs_t::TX_RETIME_CLKOUT2; + _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control + _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; + _ad9862_regs.interp = ad9862_regs_t::INTERP_2; + _ad9862_regs.tx_twos_comp = 1; + _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_BYPASS; + _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; + _ad9862_regs.dac_a_coarse_gain = 0x3; + _ad9862_regs.dac_b_coarse_gain = 0x3; + _ad9862_regs.edges = ad9862_regs_t::EDGES_NORMAL; + + //setup the dll + _ad9862_regs.input_clk_ctrl = ad9862_regs_t::INPUT_CLK_CTRL_EXTERNAL; + _ad9862_regs.dll_mult = ad9862_regs_t::DLL_MULT_2; + _ad9862_regs.dll_mode = ad9862_regs_t::DLL_MODE_FAST; + + //write the register settings to the codec + for (uint8_t addr = 0; addr <= 25; addr++){ + this->send_reg(addr); + } + + //always start conversions for aux ADC + _ad9862_regs.start_a = 1; + _ad9862_regs.start_b = 1; + + //aux adc clock + _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; + this->send_reg(34); +} + +e100_codec_ctrl_impl::~e100_codec_ctrl_impl(void){ + //set aux dacs to zero + this->write_aux_dac(AUX_DAC_A, 0); + this->write_aux_dac(AUX_DAC_B, 0); + this->write_aux_dac(AUX_DAC_C, 0); + this->write_aux_dac(AUX_DAC_D, 0); + + //power down + _ad9862_regs.all_rx_pd = 1; + this->send_reg(1); + _ad9862_regs.tx_digital_pd = 1; + _ad9862_regs.tx_analog_pd = ad9862_regs_t::TX_ANALOG_PD_BOTH; + this->send_reg(8); +} + +/*********************************************************************** + * Codec Control Gain Control Methods + **********************************************************************/ +static const int mtpgw = 255; //maximum tx pga gain word + +void e100_codec_ctrl_impl::set_tx_pga_gain(double gain){ + int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start())); + _ad9862_regs.tx_pga_gain = uhd::clip(gain_word, 0, mtpgw); + this->send_reg(16); +} + +double e100_codec_ctrl_impl::get_tx_pga_gain(void){ + return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start(); +} + +static const int mrpgw = 0x14; //maximum rx pga gain word + +void e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){ + int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start())); + gain_word = uhd::clip(gain_word, 0, mrpgw); + switch(which){ + case 'A': + _ad9862_regs.rx_pga_a = gain_word; + this->send_reg(2); + return; + case 'B': + _ad9862_regs.rx_pga_b = gain_word; + this->send_reg(3); + return; + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +double e100_codec_ctrl_impl::get_rx_pga_gain(char which){ + int gain_word; + switch(which){ + case 'A': gain_word = _ad9862_regs.rx_pga_a; break; + case 'B': gain_word = _ad9862_regs.rx_pga_b; break; + default: UHD_THROW_INVALID_CODE_PATH(); + } + return (gain_word*(rx_pga_gain_range.stop() - rx_pga_gain_range.start())/mrpgw) + rx_pga_gain_range.start(); +} + +/*********************************************************************** + * Codec Control AUX ADC Methods + **********************************************************************/ +static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ + return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +} + +double e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ + switch(which){ + case AUX_ADC_A1: + _ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1; + this->send_reg(34); //start conversion and select mux + this->recv_reg(28); //read the value (2 bytes, 2 reads) + this->recv_reg(29); + return aux_adc_to_volts(_ad9862_regs.aux_adc_a1_9_2, _ad9862_regs.aux_adc_a1_1_0); + + case AUX_ADC_A2: + _ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC2; + this->send_reg(34); //start conversion and select mux + this->recv_reg(26); //read the value (2 bytes, 2 reads) + this->recv_reg(27); + return aux_adc_to_volts(_ad9862_regs.aux_adc_a2_9_2, _ad9862_regs.aux_adc_a2_1_0); + + case AUX_ADC_B1: + _ad9862_regs.select_b = ad9862_regs_t::SELECT_B_AUX_ADC1; + this->send_reg(34); //start conversion and select mux + this->recv_reg(32); //read the value (2 bytes, 2 reads) + this->recv_reg(33); + return aux_adc_to_volts(_ad9862_regs.aux_adc_b1_9_2, _ad9862_regs.aux_adc_b1_1_0); + + case AUX_ADC_B2: + _ad9862_regs.select_b = ad9862_regs_t::SELECT_B_AUX_ADC2; + this->send_reg(34); //start conversion and select mux + this->recv_reg(30); //read the value (2 bytes, 2 reads) + this->recv_reg(31); + return aux_adc_to_volts(_ad9862_regs.aux_adc_b2_9_2, _ad9862_regs.aux_adc_b2_1_0); + } + UHD_THROW_INVALID_CODE_PATH(); +} + +/*********************************************************************** + * Codec Control AUX DAC Methods + **********************************************************************/ +void e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){ + //special case for aux dac d (aka sigma delta word) + if (which == AUX_DAC_D){ + boost::uint16_t dac_word = uhd::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); + _ad9862_regs.sig_delt_11_4 = boost::uint8_t(dac_word >> 4); + _ad9862_regs.sig_delt_3_0 = boost::uint8_t(dac_word & 0xf); + this->send_reg(42); + this->send_reg(43); + return; + } + + //calculate the dac word for aux dac a, b, c + boost::uint8_t dac_word = uhd::clip(boost::math::iround(volts*0xff/3.3), 0, 0xff); + + //setup a lookup table for the aux dac params (reg ref, reg addr) + typedef boost::tuple dac_params_t; + uhd::dict aux_dac_to_params = boost::assign::map_list_of + (AUX_DAC_A, dac_params_t(&_ad9862_regs.aux_dac_a, 36)) + (AUX_DAC_B, dac_params_t(&_ad9862_regs.aux_dac_b, 37)) + (AUX_DAC_C, dac_params_t(&_ad9862_regs.aux_dac_c, 38)) + ; + + //set the aux dac register + UHD_ASSERT_THROW(aux_dac_to_params.has_key(which)); + boost::uint8_t *reg_ref, reg_addr; + boost::tie(reg_ref, reg_addr) = aux_dac_to_params[which]; + *reg_ref = dac_word; + this->send_reg(reg_addr); +} + +/*********************************************************************** + * Codec Control SPI Methods + **********************************************************************/ +void e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){ + boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); + UHD_LOGV(often) << "codec control write reg: " << std::hex << reg << std::endl; + _iface->write_spi( + UE_SPI_SS_AD9862, + spi_config_t::EDGE_RISE, + reg, 16 + ); +} + +void e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ + boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); + UHD_LOGV(often) << "codec control read reg: " << std::hex << reg << std::endl; + boost::uint32_t ret = _iface->read_spi( + UE_SPI_SS_AD9862, + spi_config_t::EDGE_RISE, + reg, 16 + ); + UHD_LOGV(often) << "codec control read ret: " << std::hex << ret << std::endl; + _ad9862_regs.set_reg(addr, boost::uint16_t(ret)); +} + +/*********************************************************************** + * Codec Control Make + **********************************************************************/ +e100_codec_ctrl::sptr e100_codec_ctrl::make(e100_iface::sptr iface){ + return sptr(new e100_codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/e100/codec_ctrl.hpp b/host/lib/usrp/e100/codec_ctrl.hpp new file mode 100644 index 000000000..22d0390f5 --- /dev/null +++ b/host/lib/usrp/e100/codec_ctrl.hpp @@ -0,0 +1,90 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_USRP_E100_CODEC_CTRL_HPP +#define INCLUDED_USRP_E100_CODEC_CTRL_HPP + +#include "e100_iface.hpp" +#include +#include +#include + +/*! + * The usrp-e codec control: + * - Init/power down codec. + * - Read aux adc, write aux dac. + */ +class e100_codec_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + static const uhd::gain_range_t tx_pga_gain_range; + static const uhd::gain_range_t rx_pga_gain_range; + + /*! + * Make a new codec control object. + * \param iface the usrp_e100 iface object + * \return the codec control object + */ + static sptr make(e100_iface::sptr iface); + + //! aux adc identifier constants + enum aux_adc_t{ + AUX_ADC_A2 = 0xA2, + AUX_ADC_A1 = 0xA1, + AUX_ADC_B2 = 0xB2, + AUX_ADC_B1 = 0xB1 + }; + + /*! + * Read an auxiliary adc: + * The internals remember which aux adc was read last. + * Therefore, the aux adc switch is only changed as needed. + * \param which which of the 4 adcs + * \return a value in volts + */ + virtual double read_aux_adc(aux_adc_t which) = 0; + + //! aux dac identifier constants + enum aux_dac_t{ + AUX_DAC_A = 0xA, + AUX_DAC_B = 0xB, + AUX_DAC_C = 0xC, + AUX_DAC_D = 0xD //really the sigma delta output + }; + + /*! + * Write an auxiliary dac. + * \param which which of the 4 dacs + * \param volts the level in in volts + */ + virtual void write_aux_dac(aux_dac_t which, double volts) = 0; + + //! Set the TX PGA gain + virtual void set_tx_pga_gain(double gain) = 0; + + //! Get the TX PGA gain + virtual double get_tx_pga_gain(void) = 0; + + //! Set the RX PGA gain ('A' or 'B') + virtual void set_rx_pga_gain(double gain, char which) = 0; + + //! Get the RX PGA gain ('A' or 'B') + virtual double get_rx_pga_gain(char which) = 0; +}; + +#endif /* INCLUDED_USRP_E100_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/e100/codec_impl.cpp b/host/lib/usrp/e100/codec_impl.cpp new file mode 100644 index 000000000..26743d173 --- /dev/null +++ b/host/lib/usrp/e100/codec_impl.cpp @@ -0,0 +1,149 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_impl.hpp" +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void e100_impl::codec_init(void){ + //make proxies + _rx_codec_proxy = wax_obj_proxy::make( + boost::bind(&e100_impl::rx_codec_get, this, _1, _2), + boost::bind(&e100_impl::rx_codec_set, this, _1, _2) + ); + _tx_codec_proxy = wax_obj_proxy::make( + boost::bind(&e100_impl::tx_codec_get, this, _1, _2), + boost::bind(&e100_impl::tx_codec_set, this, _1, _2) + ); +} + +/*********************************************************************** + * RX Codec Properties + **********************************************************************/ +static const std::string ad9862_pga_gain_name = "ad9862 pga"; + +void e100_impl::rx_codec_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 CODEC_PROP_NAME: + val = std::string("usrp-e adc - ad9522"); + return; + + case CODEC_PROP_OTHERS: + val = prop_names_t(); + return; + + case CODEC_PROP_GAIN_NAMES: + val = prop_names_t(1, ad9862_pga_gain_name); + return; + + case CODEC_PROP_GAIN_RANGE: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + val = e100_codec_ctrl::rx_pga_gain_range; + return; + + case CODEC_PROP_GAIN_I: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + val = _codec_ctrl->get_rx_pga_gain('A'); + return; + + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + val = _codec_ctrl->get_rx_pga_gain('B'); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +void e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the set request conditioned on the key + switch(key.as()){ + case CODEC_PROP_GAIN_I: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); + return; + + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + +/*********************************************************************** + * TX Codec Properties + **********************************************************************/ +void e100_impl::tx_codec_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 CODEC_PROP_NAME: + val = std::string("usrp-e dac - ad9522"); + return; + + case CODEC_PROP_OTHERS: + val = prop_names_t(); + return; + + case CODEC_PROP_GAIN_NAMES: + val = prop_names_t(1, ad9862_pga_gain_name); + return; + + case CODEC_PROP_GAIN_RANGE: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + val = e100_codec_ctrl::tx_pga_gain_range; + return; + + case CODEC_PROP_GAIN_I: //only one gain for I and Q + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + val = _codec_ctrl->get_tx_pga_gain(); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +void e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + + //handle the set request conditioned on the key + switch(key.as()){ + case CODEC_PROP_GAIN_I: //only one gain for I and Q + case CODEC_PROP_GAIN_Q: + UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); + _codec_ctrl->set_tx_pga_gain(val.as()); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/e100/dboard_iface.cpp b/host/lib/usrp/e100/dboard_iface.cpp new file mode 100644 index 000000000..43e05aa57 --- /dev/null +++ b/host/lib/usrp/e100/dboard_iface.cpp @@ -0,0 +1,300 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_iface.hpp" +#include "e100_regs.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include +#include +#include +#include +#include //i2c and spi constants + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +class usrp_e100_dboard_iface : public dboard_iface{ +public: + + usrp_e100_dboard_iface( + e100_iface::sptr iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec + ){ + _iface = iface; + _clock = clock; + _codec = codec; + + //init the clock rate shadows + this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); + this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate()); + + _iface->poke16(E100_REG_GPIO_RX_DBG, 0); + _iface->poke16(E100_REG_GPIO_TX_DBG, 0); + } + + ~usrp_e100_dboard_iface(void){ + /* NOP */ + } + + special_props_t get_special_props(void){ + special_props_t props; + props.soft_clock_divider = false; + props.mangle_i2c_addrs = false; + return props; + } + + void write_aux_dac(unit_t, aux_dac_t, double); + double read_aux_adc(unit_t, aux_adc_t); + + void _set_pin_ctrl(unit_t, boost::uint16_t); + void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); + void _set_gpio_ddr(unit_t, boost::uint16_t); + void _set_gpio_out(unit_t, boost::uint16_t); + void set_gpio_debug(unit_t, int); + boost::uint16_t read_gpio(unit_t); + + void write_i2c(boost::uint8_t, const byte_vector_t &); + byte_vector_t read_i2c(boost::uint8_t, size_t); + + void write_spi( + unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ); + + boost::uint32_t read_write_spi( + unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ); + + void set_clock_rate(unit_t, double); + 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: + e100_iface::sptr _iface; + e100_clock_ctrl::sptr _clock; + e100_codec_ctrl::sptr _codec; +}; + +/*********************************************************************** + * Make Function + **********************************************************************/ +dboard_iface::sptr make_usrp_e100_dboard_iface( + e100_iface::sptr iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec +){ + return dboard_iface::sptr(new usrp_e100_dboard_iface(iface, clock, codec)); +} + +/*********************************************************************** + * Clock Rates + **********************************************************************/ +void usrp_e100_dboard_iface::set_clock_rate(unit_t unit, double rate){ + switch(unit){ + case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); + case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate); + } +} + +std::vector usrp_e100_dboard_iface::get_clock_rates(unit_t unit){ + switch(unit){ + case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); + case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){ + switch(unit){ + case UNIT_RX: return _clock->get_rx_clock_rate(); + case UNIT_TX: return _clock->get_tx_clock_rate(); + } + UHD_THROW_INVALID_CODE_PATH(); +} + +void usrp_e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ + switch(unit){ + case UNIT_RX: return _clock->enable_rx_dboard_clock(enb); + case UNIT_TX: return _clock->enable_tx_dboard_clock(enb); + } +} + +double usrp_e100_dboard_iface::get_codec_rate(unit_t){ + return _clock->get_fpga_clock_rate(); +} + +/*********************************************************************** + * GPIO + **********************************************************************/ +void usrp_e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ + UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption + switch(unit){ + case UNIT_RX: _iface->poke16(E100_REG_GPIO_RX_SEL, value); return; + case UNIT_TX: _iface->poke16(E100_REG_GPIO_TX_SEL, value); return; + } +} + +void usrp_e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ + switch(unit){ + case UNIT_RX: _iface->poke16(E100_REG_GPIO_RX_DDR, value); return; + case UNIT_TX: _iface->poke16(E100_REG_GPIO_TX_DDR, value); return; + } +} + +void usrp_e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ + switch(unit){ + case UNIT_RX: _iface->poke16(E100_REG_GPIO_RX_IO, value); return; + case UNIT_TX: _iface->poke16(E100_REG_GPIO_TX_IO, value); return; + } +} + +boost::uint16_t usrp_e100_dboard_iface::read_gpio(unit_t unit){ + switch(unit){ + case UNIT_RX: return _iface->peek16(E100_REG_GPIO_RX_IO); + case UNIT_TX: return _iface->peek16(E100_REG_GPIO_TX_IO); + default: UHD_THROW_INVALID_CODE_PATH(); + } +} + +void usrp_e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ + //define mapping of unit to atr regs to register address + static const uhd::dict< + unit_t, uhd::dict + > unit_to_atr_to_addr = map_list_of + (UNIT_RX, map_list_of + (ATR_REG_IDLE, E100_REG_ATR_IDLE_RXSIDE) + (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_RXSIDE) + (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_RXSIDE) + (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_RXSIDE) + ) + (UNIT_TX, map_list_of + (ATR_REG_IDLE, E100_REG_ATR_IDLE_TXSIDE) + (ATR_REG_TX_ONLY, E100_REG_ATR_INTX_TXSIDE) + (ATR_REG_RX_ONLY, E100_REG_ATR_INRX_TXSIDE) + (ATR_REG_FULL_DUPLEX, E100_REG_ATR_FULL_TXSIDE) + ) + ; + _iface->poke16(unit_to_atr_to_addr[unit][atr], value); +} + +void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){ + //set this unit to all outputs + this->set_gpio_ddr(unit, 0xffff); + + //calculate the debug selections + boost::uint32_t dbg_sels = 0x0; + int sel = (which == 0)? GPIO_SEL_DEBUG_0 : GPIO_SEL_DEBUG_1; + for(size_t i = 0; i < 16; i++) dbg_sels |= sel << i; + + //set the debug on and which debug selection + switch(unit){ + case UNIT_RX: + _iface->poke16(E100_REG_GPIO_RX_DBG, 0xffff); + _iface->poke16(E100_REG_GPIO_RX_SEL, dbg_sels); + return; + + case UNIT_TX: + _iface->poke16(E100_REG_GPIO_TX_DBG, 0xffff); + _iface->poke16(E100_REG_GPIO_TX_SEL, dbg_sels); + return; + } +} + +/*********************************************************************** + * SPI + **********************************************************************/ +/*! + * Static function to convert a unit type to a spi slave device number. + * \param unit the dboard interface unit type enum + * \return the slave device number + */ +static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){ + switch(unit){ + case dboard_iface::UNIT_TX: return UE_SPI_SS_TX_DB; + case dboard_iface::UNIT_RX: return UE_SPI_SS_RX_DB; + } + UHD_THROW_INVALID_CODE_PATH(); +} + +void usrp_e100_dboard_iface::write_spi( + unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits +){ + _iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); +} + +boost::uint32_t usrp_e100_dboard_iface::read_write_spi( + unit_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits +){ + return _iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); +} + +/*********************************************************************** + * I2C + **********************************************************************/ +void usrp_e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ + return _iface->write_i2c(addr, bytes); +} + +byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ + return _iface->read_i2c(addr, num_bytes); +} + +/*********************************************************************** + * Aux DAX/ADC + **********************************************************************/ +void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){ + //same aux dacs for each unit + static const uhd::dict which_to_aux_dac = map_list_of + (AUX_DAC_A, e100_codec_ctrl::AUX_DAC_A) + (AUX_DAC_B, e100_codec_ctrl::AUX_DAC_B) + (AUX_DAC_C, e100_codec_ctrl::AUX_DAC_C) + (AUX_DAC_D, e100_codec_ctrl::AUX_DAC_D) + ; + _codec->write_aux_dac(which_to_aux_dac[which], value); +} + +double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){ + static const uhd::dict< + unit_t, uhd::dict + > unit_to_which_to_aux_adc = map_list_of + (UNIT_RX, map_list_of + (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A1) + (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B1) + ) + (UNIT_TX, map_list_of + (AUX_ADC_A, e100_codec_ctrl::AUX_ADC_A2) + (AUX_ADC_B, e100_codec_ctrl::AUX_ADC_B2) + ) + ; + return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]); +} diff --git a/host/lib/usrp/e100/dboard_impl.cpp b/host/lib/usrp/e100/dboard_impl.cpp new file mode 100644 index 000000000..86481e70a --- /dev/null +++ b/host/lib/usrp/e100/dboard_impl.cpp @@ -0,0 +1,185 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Dboard Initialization + **********************************************************************/ +void e100_impl::dboard_init(void){ + //read the dboard eeprom to extract the dboard ids + _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB); + _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB); + _gdb_eeprom.load(*_iface, I2C_ADDR_TX_DB ^ 5); + + //create a new dboard interface and manager + _dboard_iface = make_usrp_e100_dboard_iface( + _iface, _clock_ctrl, _codec_ctrl + ); + _dboard_manager = dboard_manager::make( + _rx_db_eeprom.id, + ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, + _dboard_iface + ); + + //setup the dboard proxies + _rx_dboard_proxy = wax_obj_proxy::make( + boost::bind(&e100_impl::rx_dboard_get, this, _1, _2), + boost::bind(&e100_impl::rx_dboard_set, this, _1, _2) + ); + _tx_dboard_proxy = wax_obj_proxy::make( + boost::bind(&e100_impl::tx_dboard_get, this, _1, _2), + boost::bind(&e100_impl::tx_dboard_set, this, _1, _2) + ); +} + +/*********************************************************************** + * RX Dboard Get + **********************************************************************/ +void e100_impl::rx_dboard_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 DBOARD_PROP_NAME: + val = std::string("usrp-e dboard (rx unit)"); + return; + + case DBOARD_PROP_SUBDEV: + val = _dboard_manager->get_rx_subdev(key.name); + return; + + case DBOARD_PROP_SUBDEV_NAMES: + val = _dboard_manager->get_rx_subdev_names(); + return; + + case DBOARD_PROP_DBOARD_EEPROM: + val = _rx_db_eeprom; + return; + + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + + case DBOARD_PROP_CODEC: + val = _rx_codec_proxy->get_link(); + return; + + case DBOARD_PROP_GAIN_GROUP: + val = make_gain_group( + _rx_db_eeprom.id, + _dboard_manager->get_rx_subdev(key.name), + _rx_codec_proxy->get_link(), + GAIN_GROUP_POLICY_RX + ); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * RX Dboard Set + **********************************************************************/ +void e100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ + switch(key.as()){ + case DBOARD_PROP_DBOARD_EEPROM: + _rx_db_eeprom = val.as(); + _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_DB); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + +/*********************************************************************** + * TX Dboard Get + **********************************************************************/ +void e100_impl::tx_dboard_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 DBOARD_PROP_NAME: + val = std::string("usrp-e dboard (tx unit)"); + return; + + case DBOARD_PROP_SUBDEV: + val = _dboard_manager->get_tx_subdev(key.name); + return; + + case DBOARD_PROP_SUBDEV_NAMES: + val = _dboard_manager->get_tx_subdev_names(); + return; + + case DBOARD_PROP_DBOARD_EEPROM: + val = _tx_db_eeprom; + return; + + case DBOARD_PROP_GBOARD_EEPROM: + val = _gdb_eeprom; + return; + + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + + case DBOARD_PROP_CODEC: + val = _tx_codec_proxy->get_link(); + return; + + case DBOARD_PROP_GAIN_GROUP: + val = make_gain_group( + _tx_db_eeprom.id, + _dboard_manager->get_tx_subdev(key.name), + _tx_codec_proxy->get_link(), + GAIN_GROUP_POLICY_TX + ); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * TX Dboard Set + **********************************************************************/ +void e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ + switch(key.as()){ + case DBOARD_PROP_DBOARD_EEPROM: + _tx_db_eeprom = val.as(); + _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB); + return; + + case DBOARD_PROP_GBOARD_EEPROM: + _gdb_eeprom = val.as(); + _gdb_eeprom.store(*_iface, I2C_ADDR_TX_DB ^ 5); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/e100/dsp_impl.cpp b/host/lib/usrp/e100/dsp_impl.cpp new file mode 100644 index 000000000..fc65609a0 --- /dev/null +++ b/host/lib/usrp/e100/dsp_impl.cpp @@ -0,0 +1,217 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * DSP impl and methods + **********************************************************************/ +struct e100_impl::dsp_impl{ + uhd::dict ddc_decim; + uhd::dict ddc_freq; + uhd::dict duc_interp; + uhd::dict duc_freq; +}; + +/*********************************************************************** + * RX DDC Initialization + **********************************************************************/ +void e100_impl::dsp_init(void){ + //create new dsp impl + _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); + + //bind and initialize the rx dsps + for (size_t i = 0; i < E100_NUM_RX_DSPS; i++){ + _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&e100_impl::ddc_get, this, _1, _2, i), + boost::bind(&e100_impl::ddc_set, this, _1, _2, i) + ); + + //initial config and update + ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); + ddc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); + + //setup the rx control registers + _iface->poke32(E100_REG_RX_CTRL_CLEAR(i), 1); //reset + _iface->poke32(E100_REG_RX_CTRL_NSAMPS_PP(i), this->get_max_recv_samps_per_packet()); + _iface->poke32(E100_REG_RX_CTRL_NCHANNELS(i), 1); + _iface->poke32(E100_REG_RX_CTRL_VRT_HDR(i), 0 + | (0x1 << 28) //if data with stream id + | (0x1 << 26) //has trailer + | (0x3 << 22) //integer time other + | (0x1 << 20) //fractional time sample count + ); + _iface->poke32(E100_REG_RX_CTRL_VRT_SID(i), E100_DSP_SID_BASE + i); + _iface->poke32(E100_REG_RX_CTRL_VRT_TLR(i), 0); + _iface->poke32(E100_REG_TIME64_TPS, size_t(_clock_ctrl->get_fpga_clock_rate())); + } + + //bind and initialize the tx dsps + for (size_t i = 0; i < E100_NUM_TX_DSPS; i++){ + _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( + boost::bind(&e100_impl::duc_get, this, _1, _2, i), + boost::bind(&e100_impl::duc_set, this, _1, _2, i) + ); + + //initial config and update + duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); + duc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); + + //init the tx control registers + _iface->poke32(E100_REG_TX_CTRL_CLEAR_STATE, 1); //reset + _iface->poke32(E100_REG_TX_CTRL_NUM_CHAN, 0); //1 channel + _iface->poke32(E100_REG_TX_CTRL_REPORT_SID, E100_ASYNC_SID); + _iface->poke32(E100_REG_TX_CTRL_POLICY, E100_FLAG_TX_CTRL_POLICY_NEXT_PACKET); + } +} + +/*********************************************************************** + * RX DDC Get + **********************************************************************/ +void e100_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ + named_prop_t key = named_prop_t::extract(key_); + + switch(key.as()){ + case DSP_PROP_NAME: + val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); + return; + + case DSP_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case DSP_PROP_FREQ_SHIFT: + val = _dsp_impl->ddc_freq[which_dsp]; + return; + + case DSP_PROP_CODEC_RATE: + val = _clock_ctrl->get_fpga_clock_rate(); + return; + + case DSP_PROP_HOST_RATE: + val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->ddc_decim[which_dsp]; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * RX DDC Set + **********************************************************************/ +void e100_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ + named_prop_t key = named_prop_t::extract(key_); + + switch(key.as()){ + + case DSP_PROP_STREAM_CMD: + issue_ddc_stream_cmd(val.as(), which_dsp); + return; + + case DSP_PROP_FREQ_SHIFT:{ + double new_freq = val.as(); + _iface->poke32(E100_REG_DSP_RX_FREQ(which_dsp), + dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) + ); + _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow + } + return; + + case DSP_PROP_HOST_RATE:{ + _dsp_impl->ddc_decim[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as()); + + //set the decimation + _iface->poke32(E100_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); + } + this->update_xport_channel_mapping(); //rate changed -> update + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} + +/*********************************************************************** + * TX DUC Get + **********************************************************************/ +void e100_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ + named_prop_t key = named_prop_t::extract(key_); + + switch(key.as()){ + case DSP_PROP_NAME: + val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); + return; + + case DSP_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case DSP_PROP_FREQ_SHIFT: + val = _dsp_impl->duc_freq[which_dsp]; + return; + + case DSP_PROP_CODEC_RATE: + val = _clock_ctrl->get_fpga_clock_rate(); + return; + + case DSP_PROP_HOST_RATE: + val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->duc_interp[which_dsp]; + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * TX DUC Set + **********************************************************************/ +void e100_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ + named_prop_t key = named_prop_t::extract(key_); + + switch(key.as()){ + + case DSP_PROP_FREQ_SHIFT:{ + double new_freq = val.as(); + _iface->poke32(E100_REG_DSP_TX_FREQ, + dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) + ); + _dsp_impl->duc_freq[which_dsp] = new_freq; //shadow + } + return; + + case DSP_PROP_HOST_RATE:{ + _dsp_impl->duc_interp[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as()); + + //set the interpolation + _iface->poke32(E100_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); + + //set the scaling + _iface->poke32(E100_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); + } + this->update_xport_channel_mapping(); //rate changed -> update + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/e100/e100_iface.cpp b/host/lib/usrp/e100/e100_iface.cpp new file mode 100644 index 000000000..d61ef42ad --- /dev/null +++ b/host/lib/usrp/e100/e100_iface.cpp @@ -0,0 +1,393 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_iface.hpp" +#include "e100_regs.hpp" +#include +#include +#include //ioctl +#include //open, close +#include //ioctl structures and constants +#include //sleep +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * I2C device node implementation wrapper + **********************************************************************/ +class i2c_dev_iface : public i2c_iface{ +public: + i2c_dev_iface(const std::string &node){ + if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ + throw uhd::io_error("Failed to open " + node); + } + } + + ~i2c_dev_iface(void){ + ::close(_node_fd); + } + + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ + byte_vector_t rw_bytes(bytes); + + //setup the message + i2c_msg msg; + msg.addr = addr; + msg.flags = 0; + msg.len = bytes.size(); + msg.buf = &rw_bytes.front(); + + //setup the data + i2c_rdwr_ioctl_data data; + data.msgs = &msg; + data.nmsgs = 1; + + //call the ioctl + UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0); + } + + byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ + byte_vector_t bytes(num_bytes); + + //setup the message + i2c_msg msg; + msg.addr = addr; + msg.flags = I2C_M_RD; + msg.len = bytes.size(); + msg.buf = &bytes.front(); + + //setup the data + i2c_rdwr_ioctl_data data; + data.msgs = &msg; + data.nmsgs = 1; + + //call the ioctl + UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0); + + return bytes; + } + +private: int _node_fd; +}; + +/*********************************************************************** + * USRP-E100 interface implementation + **********************************************************************/ +class e100_iface_impl : public e100_iface{ +public: + + int get_file_descriptor(void){ + return _node_fd; + } + + void open(const std::string &node){ + UHD_MSG(status) << "Opening device node " << node << "..." << std::endl; + + //open the device node and check file descriptor + if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ + throw uhd::io_error("Failed to open " + node); + } + + //check the module compatibility number + int module_compat_num = ::ioctl(_node_fd, USRP_E_GET_COMPAT_NUMBER, NULL); + if (module_compat_num != USRP_E_COMPAT_NUMBER){ + throw uhd::runtime_error(str(boost::format( + "Expected module compatibility number 0x%x, but got 0x%x:\n" + "The module build is not compatible with the host code build." + ) % USRP_E_COMPAT_NUMBER % module_compat_num)); + } + } + + void close(void){ + ::close(_node_fd); + _node_fd = -1; + } + + /******************************************************************* + * Structors + ******************************************************************/ + e100_iface_impl(void): + _node_fd(-1), + _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3")) + { + mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); + } + + ~e100_iface_impl(void){ + if (_node_fd >= 0) this->close(); + } + + /******************************************************************* + * IOCTL: provides the communication base for all other calls + ******************************************************************/ + void ioctl(int request, void *mem){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + + if (::ioctl(_node_fd, request, mem) < 0){ + throw uhd::os_error(str( + boost::format("ioctl failed with request %d") % request + )); + } + } + + /******************************************************************* + * I2C device node interface + ******************************************************************/ + i2c_iface &get_i2c_dev_iface(void){ + return _i2c_dev_iface; + } + + /******************************************************************* + * Peek and Poke + ******************************************************************/ + void poke32(boost::uint32_t addr, boost::uint32_t value){ + //load the data struct + usrp_e_ctl32 data; + data.offset = addr; + data.count = 1; + data.buf[0] = value; + + //call the ioctl + this->ioctl(USRP_E_WRITE_CTL32, &data); + } + + void poke16(boost::uint32_t addr, boost::uint16_t value){ + //load the data struct + usrp_e_ctl16 data; + data.offset = addr; + data.count = 1; + data.buf[0] = value; + + //call the ioctl + this->ioctl(USRP_E_WRITE_CTL16, &data); + } + + boost::uint32_t peek32(boost::uint32_t addr){ + //load the data struct + usrp_e_ctl32 data; + data.offset = addr; + data.count = 1; + + //call the ioctl + this->ioctl(USRP_E_READ_CTL32, &data); + + return data.buf[0]; + } + + boost::uint16_t peek16(boost::uint32_t addr){ + //load the data struct + usrp_e_ctl16 data; + data.offset = addr; + data.count = 1; + + //call the ioctl + this->ioctl(USRP_E_READ_CTL16, &data); + + return data.buf[0]; + } + + /******************************************************************* + * I2C + ******************************************************************/ + static const size_t max_i2c_data_bytes = 10; + + void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ + //allocate some memory for this transaction + UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes); + boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; + + //load the data struct + usrp_e_i2c *data = reinterpret_cast(mem); + data->addr = addr; + data->len = bytes.size(); + std::copy(bytes.begin(), bytes.end(), data->data); + + //call the spi ioctl + this->ioctl(USRP_E_I2C_WRITE, data); + } + + byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ + //allocate some memory for this transaction + UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes); + boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; + + //load the data struct + usrp_e_i2c *data = reinterpret_cast(mem); + data->addr = addr; + data->len = num_bytes; + + //call the spi ioctl + this->ioctl(USRP_E_I2C_READ, data); + + //unload the data + byte_vector_t bytes(data->len); + UHD_ASSERT_THROW(bytes.size() == num_bytes); + std::copy(data->data, data->data+bytes.size(), bytes.begin()); + return bytes; + } + + /******************************************************************* + * SPI + ******************************************************************/ + boost::uint32_t transact_spi( + int which_slave, + const spi_config_t &config, + boost::uint32_t bits, + size_t num_bits, + bool readback + ){ + if (which_slave == UE_SPI_SS_AD9522) return bitbang_spi( + bits, num_bits, readback + ); + + //load data struct + usrp_e_spi data; + data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY; + data.slave = which_slave; + data.length = num_bits; + data.data = bits; + + //load the flags + data.flags = 0; + data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; + data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL : UE_SPI_PUSH_RISE; + + //call the spi ioctl + this->ioctl(USRP_E_SPI, &data); + + //unload the data + return data.data; + } + + boost::uint32_t bitbang_spi( + boost::uint32_t bits, + size_t num_bits, + bool readback + ){ + boost::uint32_t rb_bits = 0; + + _spi_bitbanger.spi_sen_gpio_write(0); + + for (size_t i = 0; i < num_bits; i++){ + _spi_bitbanger.spi_sclk_gpio_write(0); + _spi_bitbanger.spi_mosi_gpio_write((bits >> (num_bits-i-1)) & 0x1); + boost::this_thread::sleep(boost::posix_time::microseconds(10)); + if (readback) rb_bits = (rb_bits << 1) | _spi_bitbanger.spi_miso_gpio_read(); + _spi_bitbanger.spi_sclk_gpio_write(1); + boost::this_thread::sleep(boost::posix_time::microseconds(10)); + } + + _spi_bitbanger.spi_sen_gpio_write(1); + boost::this_thread::sleep(boost::posix_time::microseconds(100)); + + return rb_bits; + } + + class bitbang_spi_guts{ + public: + bitbang_spi_guts(void){ + //setup gpio pin directions + this->set_gpio_direction(spi_sclk_gpio, "out"); + this->set_gpio_direction(spi_sen_gpio, "out"); + this->set_gpio_direction(spi_mosi_gpio, "out"); + this->set_gpio_direction(spi_miso_gpio, "in"); + + //open the gpio pin values + _spi_sclk_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sclk_gpio).c_str()); + _spi_sen_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sen_gpio).c_str()); + _spi_mosi_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_mosi_gpio).c_str()); + _spi_miso_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_miso_gpio).c_str()); + } + + ~bitbang_spi_guts(void){ + this->set_gpio_direction(spi_sclk_gpio, "in"); + this->set_gpio_direction(spi_sen_gpio, "in"); + this->set_gpio_direction(spi_mosi_gpio, "in"); + } + + void spi_sclk_gpio_write(int val){ + _spi_sclk_gpio_value << val << std::endl << std::flush; + } + + void spi_sen_gpio_write(int val){ + _spi_sen_gpio_value << val << std::endl << std::flush; + } + + void spi_mosi_gpio_write(int val){ + _spi_mosi_gpio_value << val << std::endl << std::flush; + } + + int spi_miso_gpio_read(void){ + std::string val; + std::getline(_spi_miso_gpio_value, val); + _spi_miso_gpio_value.seekg(0); + return int(val.at(0) - '0') & 0x1; + } + + private: + enum{ + spi_sclk_gpio = 65, + spi_sen_gpio = 186, + spi_mosi_gpio = 145, + spi_miso_gpio = 147, + }; + + void set_gpio_direction(int gpio_num, const std::string &dir){ + std::ofstream export_file("/sys/class/gpio/export"); + export_file << gpio_num << std::endl << std::flush; + export_file.close(); + + std::ofstream dir_file(str(boost::format("/sys/class/gpio/gpio%d/direction") % gpio_num).c_str()); + dir_file << dir << std::endl << std::flush; + dir_file.close(); + } + + std::ofstream _spi_sclk_gpio_value, _spi_sen_gpio_value, _spi_mosi_gpio_value; + std::ifstream _spi_miso_gpio_value; + }; + + /******************************************************************* + * UART + ******************************************************************/ + void write_uart(boost::uint8_t, const std::string &) { + throw uhd::not_implemented_error("Unhandled command write_uart()"); + } + + std::string read_uart(boost::uint8_t) { + throw uhd::not_implemented_error("Unhandled command read_uart()"); + } + +private: + int _node_fd; + i2c_dev_iface _i2c_dev_iface; + boost::mutex _ctrl_mutex; + bitbang_spi_guts _spi_bitbanger; +}; + +/*********************************************************************** + * Public Make Function + **********************************************************************/ +e100_iface::sptr e100_iface::make(void){ + return sptr(new e100_iface_impl()); +} diff --git a/host/lib/usrp/e100/e100_iface.hpp b/host/lib/usrp/e100/e100_iface.hpp new file mode 100644 index 000000000..a0135a468 --- /dev/null +++ b/host/lib/usrp/e100/e100_iface.hpp @@ -0,0 +1,90 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_E100_IFACE_HPP +#define INCLUDED_E100_IFACE_HPP + +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////// +// I2C addresses +//////////////////////////////////////////////////////////////////////// +#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx +#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) +#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) +#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) +//////////////////////////////////////////////////////////////////////// + +/*! + * The usrp-e interface class: + * Provides a set of functions to implementation layer. + * Including spi, peek, poke, control... + */ +class e100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new usrp-e interface with the control transport. + * \return a new usrp-e interface object + */ + static sptr make(void); + + //! TODO implement this for multiple hardwares revs in the future + std::string get_cname(void){ + return "USRP-E100"; + } + + /*! + * Get the underlying file descriptor. + * \return the file descriptor + */ + virtual int get_file_descriptor(void) = 0; + + /*! + * Open a device node into this iface. + * \param node the device node name + */ + virtual void open(const std::string &node) = 0; + + /*! + * Close the open device node in this iface. + */ + virtual void close(void) = 0; + + /*! + * Perform an ioctl call on the device node file descriptor. + * This will throw when the internal ioctl call fails. + * \param request the control word + * \param mem pointer to some memory + */ + virtual void ioctl(int request, void *mem) = 0; + + //! Get the I2C interface for the I2C device node + virtual uhd::i2c_iface &get_i2c_dev_iface(void) = 0; + + //motherboard eeprom map structure + uhd::usrp::mboard_eeprom_t mb_eeprom; +}; + +#endif /* INCLUDED_E100_IFACE_HPP */ diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp new file mode 100644 index 000000000..5485388f9 --- /dev/null +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -0,0 +1,227 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +namespace fs = boost::filesystem; + +/*********************************************************************** + * Discovery + **********************************************************************/ +static device_addrs_t e100_find(const device_addr_t &hint){ + device_addrs_t e100_addrs; + + //return an empty list of addresses when type is set to non-usrp-e + if (hint.has_key("type") and hint["type"] != "e100") return e100_addrs; + + //device node not provided, assume its 0 + if (not hint.has_key("node")){ + device_addr_t new_addr = hint; + new_addr["node"] = "/dev/usrp_e0"; + return e100_find(new_addr); + } + + //use the given device node name + if (fs::exists(hint["node"])){ + device_addr_t new_addr; + new_addr["type"] = "e100"; + new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); + try{ + e100_iface::sptr iface = e100_iface::make(); + new_addr["name"] = iface->mb_eeprom["name"]; + new_addr["serial"] = iface->mb_eeprom["serial"]; + } + catch(const std::exception &e){ + new_addr["name"] = ""; + new_addr["serial"] = ""; + } + if ( + (not hint.has_key("name") or hint["name"] == new_addr["name"]) and + (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) + ){ + e100_addrs.push_back(new_addr); + } + } + + return e100_addrs; +} + +/*********************************************************************** + * Make + **********************************************************************/ +static size_t hash_fpga_file(const std::string &file_path){ + size_t hash = 0; + std::ifstream file(file_path.c_str()); + if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); + while (file.good()) boost::hash_combine(hash, file.get()); + file.close(); + return hash; +} + +static device::sptr e100_make(const device_addr_t &device_addr){ + + //setup the main interface into fpga + const std::string node = device_addr["node"]; + e100_iface::sptr iface = e100_iface::make(); + iface->open(node); + + //setup clock control here to ensure that the FPGA has a good clock before we continue + const double master_clock_rate = device_addr.cast("master_clock_rate", E100_DEFAULT_CLOCK_RATE); + e100_clock_ctrl::sptr clock_ctrl = e100_clock_ctrl::make(iface, master_clock_rate); + + //extract the fpga path for usrp-e and compute hash + const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", E100_FPGA_FILE_NAME)); + const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(e100_fpga_image)); + + //When the hash does not match: + // - close the device node + // - load the fpga bin file + // - re-open the device node + if (iface->peek32(E100_REG_RB_MISC_TEST32) != file_hash){ + iface->close(); + e100_load_fpga(e100_fpga_image); + iface->open(node); + } + + //Perform wishbone readback tests, these tests also write the hash + bool test_fail = false; + UHD_MSG(status) << "Performing wishbone readback test... " << std::flush; + for (size_t i = 0; i < 100; i++){ + iface->poke32(E100_REG_SR_MISC_TEST32, file_hash); + test_fail = iface->peek32(E100_REG_RB_MISC_TEST32) != file_hash; + if (test_fail) break; //exit loop on any failure + } + UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; + + if (test_fail) UHD_MSG(error) << boost::format( + "The FPGA is either clocked improperly\n" + "or the FPGA build is not compatible.\n" + "Subsequent errors may follow...\n" + ); + + //check that the compatibility is correct + const boost::uint16_t fpga_compat_num = iface->peek16(E100_REG_MISC_COMPAT); + if (fpga_compat_num != E100_FPGA_COMPAT_NUM){ + throw uhd::runtime_error(str(boost::format( + "\nPlease update the FPGA image for your device.\n" + "See the application notes for USRP E-Series for instructions.\n" + "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" + "The FPGA build is not compatible with the host code build." + ) % E100_FPGA_COMPAT_NUM % fpga_compat_num)); + } + + return device::sptr(new e100_impl(device_addr, iface, clock_ctrl)); +} + +UHD_STATIC_BLOCK(register_e100_device){ + device::register_device(&e100_find, &e100_make); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +e100_impl::e100_impl( + const uhd::device_addr_t &device_addr, + e100_iface::sptr iface, + e100_clock_ctrl::sptr clock_ctrl +): + _iface(iface), + _clock_ctrl(clock_ctrl), + _codec_ctrl(e100_codec_ctrl::make(_iface)), + _data_xport(e100_make_mmap_zero_copy(_iface)), + _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast("recv_frame_size", 1e9)))), + _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast("send_frame_size", 1e9)))) +{ + + //setup otw types + _send_otw_type.width = 16; + _send_otw_type.shift = 0; + _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + + _recv_otw_type.width = 16; + _recv_otw_type.shift = 0; + _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; + + //initialize the mboard + mboard_init(); + + //initialize the dboards + dboard_init(); + + //initialize the dsps + dsp_init(); + + //init the codec properties + codec_init(); + + //set default subdev specs + this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); + this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); + + //init the io send/recv + io_init(); + +} + +e100_impl::~e100_impl(void){ + /* NOP */ +} + +/*********************************************************************** + * Device Get + **********************************************************************/ +void e100_impl::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 DEVICE_PROP_NAME: + val = std::string("usrp-e device"); + return; + + case DEVICE_PROP_MBOARD: + UHD_ASSERT_THROW(key.name == ""); + val = _mboard_proxy->get_link(); + return; + + case DEVICE_PROP_MBOARD_NAMES: + val = prop_names_t(1, ""); //vector of size 1 with empty string + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * Device Set + **********************************************************************/ +void e100_impl::set(const wax::obj &, const wax::obj &){ + UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp new file mode 100644 index 000000000..1390559a0 --- /dev/null +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -0,0 +1,183 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_iface.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef INCLUDED_E100_IMPL_HPP +#define INCLUDED_E100_IMPL_HPP + +uhd::transport::zero_copy_if::sptr e100_make_mmap_zero_copy(e100_iface::sptr iface); + +static const std::string E100_FPGA_FILE_NAME = "usrp_e100_fpga5.bin"; +static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x05; +static const double E100_DEFAULT_CLOCK_RATE = 64e6; +static const size_t E100_NUM_RX_DSPS = 2; +static const size_t E100_NUM_TX_DSPS = 1; +static const boost::uint32_t E100_DSP_SID_BASE = 2; //leave room for other dsp (increments by 1) +static const boost::uint32_t E100_ASYNC_SID = 1; + +//! load an fpga image from a bin file into the usrp-e fpga +extern void e100_load_fpga(const std::string &bin_file); + +/*! + * Make a usrp-e dboard interface. + * \param iface the usrp-e interface object + * \param clock the clock control interface + * \param codec the codec control interface + * \return a sptr to a new dboard interface + */ +uhd::usrp::dboard_iface::sptr make_usrp_e100_dboard_iface( + e100_iface::sptr iface, + e100_clock_ctrl::sptr clock, + e100_codec_ctrl::sptr codec +); + +/*! + * Simple wax obj proxy class: + * Provides a wax obj interface for a set and a get function. + * This allows us to create nested properties structures + * while maintaining flattened code within the implementation. + */ +class wax_obj_proxy : public wax::obj{ +public: + typedef boost::function get_t; + typedef boost::function set_t; + typedef boost::shared_ptr sptr; + + static sptr make(const get_t &get, const set_t &set){ + return sptr(new wax_obj_proxy(get, set)); + } + +private: + get_t _get; set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; + void get(const wax::obj &key, wax::obj &val){return _get(key, val);} + void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} +}; + +/*! + * USRP-E100 implementation guts: + * The implementation details are encapsulated here. + * Handles properties on the mboard, dboard, dsps... + */ +class e100_impl : public uhd::device{ +public: + //structors + e100_impl( + const uhd::device_addr_t &, + e100_iface::sptr, + e100_clock_ctrl::sptr + ); + ~e100_impl(void); + + //the io interface + size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); + size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); + bool recv_async_msg(uhd::async_metadata_t &, double); + size_t get_max_send_samps_per_packet(void) const; + size_t get_max_recv_samps_per_packet(void) const; + +private: + //interface to ioctls and file descriptor + e100_iface::sptr _iface; + + //ad9522 clock control + e100_clock_ctrl::sptr _clock_ctrl; + + //ad9862 codec control + e100_codec_ctrl::sptr _codec_ctrl; + + //handle io stuff + uhd::transport::zero_copy_if::sptr _data_xport; + UHD_PIMPL_DECL(io_impl) _io_impl; + size_t _recv_frame_size, _send_frame_size; + uhd::otw_type_t _send_otw_type, _recv_otw_type; + void io_init(void); + void handle_overrun(size_t); + void update_xport_channel_mapping(void); + + //configuration shadows + uhd::clock_config_t _clock_config; + + //device functions and settings + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //mboard functions and settings + void mboard_init(void); + void mboard_get(const wax::obj &, wax::obj &); + void mboard_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _mboard_proxy; + uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; + + //xx dboard functions and settings + void dboard_init(void); + uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; + + //rx dboard functions and settings + uhd::usrp::dboard_eeprom_t _rx_db_eeprom; + void rx_dboard_get(const wax::obj &, wax::obj &); + void rx_dboard_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _rx_dboard_proxy; + + //tx dboard functions and settings + uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; + void tx_dboard_get(const wax::obj &, wax::obj &); + void tx_dboard_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _tx_dboard_proxy; + + //methods and shadows for the dsps + UHD_PIMPL_DECL(dsp_impl) _dsp_impl; + void dsp_init(void); + void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); + + //properties interface for ddc + void ddc_get(const wax::obj &, wax::obj &, size_t); + void ddc_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict _rx_dsp_proxies; + + //properties interface for duc + void duc_get(const wax::obj &, wax::obj &, size_t); + void duc_set(const wax::obj &, const wax::obj &, size_t); + uhd::dict _tx_dsp_proxies; + + //codec functions and settings + void codec_init(void); + void rx_codec_get(const wax::obj &, wax::obj &); + void rx_codec_set(const wax::obj &, const wax::obj &); + void tx_codec_get(const wax::obj &, wax::obj &); + void tx_codec_set(const wax::obj &, const wax::obj &); + wax_obj_proxy::sptr _rx_codec_proxy, _tx_codec_proxy; + + //clock control functions and settings + void init_clock_config(void); + void update_clock_config(void); +}; + +#endif /* INCLUDED_E100_IMPL_HPP */ diff --git a/host/lib/usrp/e100/e100_mmap_zero_copy.cpp b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp new file mode 100644 index 000000000..5370b7594 --- /dev/null +++ b/host/lib/usrp/e100/e100_mmap_zero_copy.cpp @@ -0,0 +1,269 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_iface.hpp" +#include +#include +#include +#include +#include //mmap +#include //getpagesize +#include //poll +#include + +using namespace uhd; +using namespace uhd::transport; + +#define fp_verbose false //fast-path verbose +static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout + +/*********************************************************************** + * Reusable managed receiver buffer: + * - The buffer knows how to claim and release a frame. + **********************************************************************/ +class e100_mmap_zero_copy_mrb : public managed_recv_buffer{ +public: + e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info): + _mem(mem), _info(info) { /* NOP */ } + + void release(void){ + if (_info->flags != RB_USER_PROCESS) return; + if (fp_verbose) UHD_LOGV(always) << "recv buff: release" << std::endl; + _info->flags = RB_KERNEL; //release the frame + } + + bool ready(void){return _info->flags & RB_USER;} + + sptr get_new(void){ + if (fp_verbose) UHD_LOGV(always) << " make_recv_buff: " << get_size() << std::endl; + _info->flags = RB_USER_PROCESS; //claim the frame + return make_managed_buffer(this); + } + +private: + const void *get_buff(void) const{return _mem;} + size_t get_size(void) const{return _info->len;} + + void *_mem; + ring_buffer_info *_info; +}; + +/*********************************************************************** + * Reusable managed send buffer: + * - The buffer knows how to claim and release a frame. + **********************************************************************/ +class e100_mmap_zero_copy_msb : public managed_send_buffer{ +public: + e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd): + _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ } + + void commit(size_t len){ + if (_info->flags != RB_USER_PROCESS) return; + if (fp_verbose) UHD_LOGV(always) << "send buff: commit " << len << std::endl; + _info->len = len; + _info->flags = RB_USER; //release the frame + if (::write(_fd, NULL, 0) < 0){ //notifies the kernel + UHD_LOGV(rarely) << UHD_THROW_SITE_INFO("write error") << std::endl; + } + } + + bool ready(void){return _info->flags & RB_KERNEL;} + + sptr get_new(void){ + if (fp_verbose) UHD_LOGV(always) << " make_send_buff: " << get_size() << std::endl; + _info->flags = RB_USER_PROCESS; //claim the frame + return make_managed_buffer(this); + } + +private: + void *get_buff(void) const{return _mem;} + size_t get_size(void) const{return _len;} + + void *_mem; + ring_buffer_info *_info; + size_t _len; + int _fd; +}; + +/*********************************************************************** + * The zero copy interface implementation + **********************************************************************/ +class e100_mmap_zero_copy_impl : public zero_copy_if{ +public: + e100_mmap_zero_copy_impl(e100_iface::sptr iface): + _fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0) + { + //get system sizes + iface->ioctl(USRP_E_GET_RB_INFO, &_rb_size); + size_t page_size = getpagesize(); + _frame_size = page_size/2; + + //calculate the memory size + _map_size = + (_rb_size.num_pages_rx_flags + _rb_size.num_pages_tx_flags) * page_size + + (_rb_size.num_rx_frames + _rb_size.num_tx_frames) * _frame_size; + + //print sizes summary + UHD_LOG + << "page_size: " << page_size << std::endl + << "frame_size: " << _frame_size << std::endl + << "num_pages_rx_flags: " << _rb_size.num_pages_rx_flags << std::endl + << "num_rx_frames: " << _rb_size.num_rx_frames << std::endl + << "num_pages_tx_flags: " << _rb_size.num_pages_tx_flags << std::endl + << "num_tx_frames: " << _rb_size.num_tx_frames << std::endl + << "map_size: " << _map_size << std::endl + ; + + //call mmap to get the memory + _mapped_mem = ::mmap( + NULL, _map_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0 + ); + UHD_ASSERT_THROW(_mapped_mem != MAP_FAILED); + + //calculate the memory offsets for info and buffers + size_t recv_info_off = 0; + size_t recv_buff_off = recv_info_off + (_rb_size.num_pages_rx_flags * page_size); + size_t send_info_off = recv_buff_off + (_rb_size.num_rx_frames * _frame_size); + size_t send_buff_off = send_info_off + (_rb_size.num_pages_tx_flags * page_size); + + //print offset summary + UHD_LOG + << "recv_info_off: " << recv_info_off << std::endl + << "recv_buff_off: " << recv_buff_off << std::endl + << "send_info_off: " << send_info_off << std::endl + << "send_buff_off: " << send_buff_off << std::endl + ; + + //pointers to sections in the mapped memory + ring_buffer_info (*recv_info)[], (*send_info)[]; + char *recv_buff, *send_buff; + + //set the internal pointers for info and buffers + typedef ring_buffer_info (*rbi_pta)[]; + char *rb_ptr = reinterpret_cast(_mapped_mem); + recv_info = reinterpret_cast(rb_ptr + recv_info_off); + recv_buff = rb_ptr + recv_buff_off; + send_info = reinterpret_cast(rb_ptr + send_info_off); + send_buff = rb_ptr + send_buff_off; + + //initialize the managed receive buffers + for (size_t i = 0; i < get_num_recv_frames(); i++){ + _mrb_pool.push_back(e100_mmap_zero_copy_mrb( + recv_buff + get_recv_frame_size()*i, (*recv_info) + i + )); + } + + //initialize the managed send buffers + for (size_t i = 0; i < get_num_recv_frames(); i++){ + _msb_pool.push_back(e100_mmap_zero_copy_msb( + send_buff + get_send_frame_size()*i, (*send_info) + i, + get_send_frame_size(), _fd + )); + } + } + + ~e100_mmap_zero_copy_impl(void){ + UHD_LOG << "cleanup: munmap" << std::endl; + ::munmap(_mapped_mem, _map_size); + } + + managed_recv_buffer::sptr get_recv_buff(double timeout){ + if (fp_verbose) UHD_LOGV(always) << "get_recv_buff: " << _recv_index << std::endl; + e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index]; + + //poll/wait for a ready frame + if (not mrb.ready()){ + for (size_t i = 0; i < poll_breakout; i++){ + pollfd pfd; + pfd.fd = _fd; + pfd.events = POLLIN; + ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3/poll_breakout)); + if (fp_verbose) UHD_LOGV(always) << " POLLIN: " << poll_ret << std::endl; + if (poll_ret > 0) goto found_user_frame; //good poll, continue on + } + return managed_recv_buffer::sptr(); //timed-out for real + } found_user_frame: + + //increment the index for the next call + if (++_recv_index == get_num_recv_frames()) _recv_index = 0; + + //return the managed buffer for this frame + return mrb.get_new(); + } + + size_t get_num_recv_frames(void) const{ + return _rb_size.num_rx_frames; + } + + size_t get_recv_frame_size(void) const{ + return _frame_size; + } + + managed_send_buffer::sptr get_send_buff(double timeout){ + if (fp_verbose) UHD_LOGV(always) << "get_send_buff: " << _send_index << std::endl; + e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index]; + + //poll/wait for a ready frame + if (not msb.ready()){ + pollfd pfd; + pfd.fd = _fd; + pfd.events = POLLOUT; + ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3)); + if (fp_verbose) UHD_LOGV(always) << " POLLOUT: " << poll_ret << std::endl; + if (poll_ret <= 0) return managed_send_buffer::sptr(); + } + + //increment the index for the next call + if (++_send_index == get_num_send_frames()) _send_index = 0; + + //return the managed buffer for this frame + return msb.get_new(); + } + + size_t get_num_send_frames(void) const{ + return _rb_size.num_tx_frames; + } + + size_t get_send_frame_size(void) const{ + return _frame_size; + } + +private: + //file descriptor for mmap + int _fd; + + //the mapped memory itself + void *_mapped_mem; + + //mapped memory sizes + usrp_e_ring_buffer_size_t _rb_size; + size_t _frame_size, _map_size; + + //re-usable managed buffers + std::vector _mrb_pool; + std::vector _msb_pool; + + //indexes into sub-sections of mapped memory + size_t _recv_index, _send_index; +}; + +/*********************************************************************** + * The zero copy interface make function + **********************************************************************/ +zero_copy_if::sptr e100_make_mmap_zero_copy(e100_iface::sptr iface){ + return zero_copy_if::sptr(new e100_mmap_zero_copy_impl(iface)); +} diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp new file mode 100644 index 000000000..5be607389 --- /dev/null +++ b/host/lib/usrp/e100/e100_regs.hpp @@ -0,0 +1,242 @@ + + +//////////////////////////////////////////////////////////////// +// +// Memory map for embedded wishbone bus +// +//////////////////////////////////////////////////////////////// + +// All addresses are byte addresses. All accesses are word (16-bit) accesses. +// This means that address bit 0 is usually 0. +// There are 11 bits of address for the control. + +#ifndef INCLUDED_E100_REGS_HPP +#define INCLUDED_E100_REGS_HPP + +///////////////////////////////////////////////////// +// Slave pointers + +#define E100_REG_SLAVE(n) ((n)<<7) + +///////////////////////////////////////////////////// +// Slave 0 -- Misc Regs + +#define E100_REG_MISC_BASE E100_REG_SLAVE(0) + +#define E100_REG_MISC_LED E100_REG_MISC_BASE + 0 +#define E100_REG_MISC_SW E100_REG_MISC_BASE + 2 +#define E100_REG_MISC_CGEN_CTRL E100_REG_MISC_BASE + 4 +#define E100_REG_MISC_CGEN_ST E100_REG_MISC_BASE + 6 +#define E100_REG_MISC_TEST E100_REG_MISC_BASE + 8 +#define E100_REG_MISC_RX_LEN E100_REG_MISC_BASE + 10 +#define E100_REG_MISC_TX_LEN E100_REG_MISC_BASE + 12 +#define E100_REG_MISC_XFER_RATE E100_REG_MISC_BASE + 14 +#define E100_REG_MISC_COMPAT E100_REG_MISC_BASE + 16 + +///////////////////////////////////////////////////// +// Slave 1 -- UART +// CLKDIV is 16 bits, others are only 8 + +#define E100_REG_UART_BASE E100_REG_SLAVE(1) + +#define E100_REG_UART_CLKDIV E100_REG_UART_BASE + 0 +#define E100_REG_UART_TXLEVEL E100_REG_UART_BASE + 2 +#define E100_REG_UART_RXLEVEL E100_REG_UART_BASE + 4 +#define E100_REG_UART_TXCHAR E100_REG_UART_BASE + 6 +#define E100_REG_UART_RXCHAR E100_REG_UART_BASE + 8 + +///////////////////////////////////////////////////// +// Slave 2 -- SPI Core +// This should be accessed through the IOCTL +// Users should not touch directly + +#define E100_REG_SPI_BASE E100_REG_SLAVE(2) + +//spi slave constants +#define UE_SPI_SS_AD9522 (1 << 3) +#define UE_SPI_SS_AD9862 (1 << 2) +#define UE_SPI_SS_TX_DB (1 << 1) +#define UE_SPI_SS_RX_DB (1 << 0) + +//////////////////////////////////////////////// +// Slave 3 -- I2C Core +// This should be accessed through the IOCTL +// Users should not touch directly + +#define E100_REG_I2C_BASE E100_REG_SLAVE(3) + + +//////////////////////////////////////////////// +// Slave 4 -- GPIO + +#define E100_REG_GPIO_BASE E100_REG_SLAVE(4) + +#define E100_REG_GPIO_RX_IO E100_REG_GPIO_BASE + 0 +#define E100_REG_GPIO_TX_IO E100_REG_GPIO_BASE + 2 +#define E100_REG_GPIO_RX_DDR E100_REG_GPIO_BASE + 4 +#define E100_REG_GPIO_TX_DDR E100_REG_GPIO_BASE + 6 +#define E100_REG_GPIO_RX_SEL E100_REG_GPIO_BASE + 8 +#define E100_REG_GPIO_TX_SEL E100_REG_GPIO_BASE + 10 +#define E100_REG_GPIO_RX_DBG E100_REG_GPIO_BASE + 12 +#define E100_REG_GPIO_TX_DBG E100_REG_GPIO_BASE + 14 + +//possible bit values for sel when dbg is 0: +#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg +#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic + +//possible bit values for sel when dbg is 1: +#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric +#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric + +/////////////////////////////////////////////////// +// Slave 6 -- ATR Controller +// 16 regs + +#define E100_REG_ATR_BASE E100_REG_SLAVE(6) + +#define E100_REG_ATR_IDLE_RXSIDE E100_REG_ATR_BASE + 0 +#define E100_REG_ATR_IDLE_TXSIDE E100_REG_ATR_BASE + 2 +#define E100_REG_ATR_INTX_RXSIDE E100_REG_ATR_BASE + 4 +#define E100_REG_ATR_INTX_TXSIDE E100_REG_ATR_BASE + 6 +#define E100_REG_ATR_INRX_RXSIDE E100_REG_ATR_BASE + 8 +#define E100_REG_ATR_INRX_TXSIDE E100_REG_ATR_BASE + 10 +#define E100_REG_ATR_FULL_RXSIDE E100_REG_ATR_BASE + 12 +#define E100_REG_ATR_FULL_TXSIDE E100_REG_ATR_BASE + 14 + +/////////////////////////////////////////////////// +// Slave 7 -- Readback Mux 32 + +#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7) + +#define E100_REG_RB_TIME_NOW_SECS E100_REG_RB_MUX_32_BASE + 0 +#define E100_REG_RB_TIME_NOW_TICKS E100_REG_RB_MUX_32_BASE + 4 +#define E100_REG_RB_TIME_PPS_SECS E100_REG_RB_MUX_32_BASE + 8 +#define E100_REG_RB_TIME_PPS_TICKS E100_REG_RB_MUX_32_BASE + 12 +#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16 + +//////////////////////////////////////////////////// +// Slave 8 -- Settings Bus +// +// Output-only, no readback, 64 registers total +// Each register must be written 64 bits at a time +// First the address xxx_xx00 and then xxx_xx10 + +// 64 total regs in address space +#define UE_SR_RX_CTRL0 0 // 9 regs (+0 to +8) +#define UE_SR_RX_DSP0 10 // 4 regs (+0 to +3) +#define UE_SR_RX_CTRL1 16 // 9 regs (+0 to +8) +#define UE_SR_RX_DSP1 26 // 4 regs (+0 to +3) +#define UE_SR_TX_CTRL 32 // 4 regs (+0 to +3) +#define UE_SR_TX_DSP 38 // 3 regs (+0 to +2) + +#define UE_SR_TIME64 42 // 6 regs (+0 to +5) +#define UE_SR_RX_FRONT 48 // 5 regs (+0 to +4) +#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4) + +#define UE_SR_REG_TEST32 60 // 1 reg +#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg +#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg +#define UE_SR_GLOBAL_RESET 63 // 1 reg + +#define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n))) + +#define E100_REG_SR_MISC_TEST32 E100_REG_SR_ADDR(UE_SR_REG_TEST32) + +///////////////////////////////////////////////// +// Magic reset regs +//////////////////////////////////////////////// +#define E100_REG_CLEAR_RX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) +#define E100_REG_CLEAR_TX E100_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) +#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET) + +///////////////////////////////////////////////// +// DSP RX Regs +//////////////////////////////////////////////// +#define E100_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \ + (E100_REG_SR_ADDR(UE_SR_RX_DSP0 + offset)) : \ + (E100_REG_SR_ADDR(UE_SR_RX_DSP1 + offset))) + +#define E100_REG_DSP_RX_FREQ(which) E100_REG_DSP_RX_HELPER(which, 0) +#define E100_REG_DSP_RX_DECIM(which) E100_REG_DSP_RX_HELPER(which, 2) +#define E100_REG_DSP_RX_MUX(which) E100_REG_DSP_RX_HELPER(which, 3) + +#define E100_FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) +#define E100_FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) + +/////////////////////////////////////////////////// +// RX CTRL regs +/////////////////////////////////////////////////// +#define E100_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \ + (E100_REG_SR_ADDR(UE_SR_RX_CTRL0 + offset)) : \ + (E100_REG_SR_ADDR(UE_SR_RX_CTRL1 + offset))) + +#define E100_REG_RX_CTRL_STREAM_CMD(which) E100_REG_RX_CTRL_HELPER(which, 0) +#define E100_REG_RX_CTRL_TIME_SECS(which) E100_REG_RX_CTRL_HELPER(which, 1) +#define E100_REG_RX_CTRL_TIME_TICKS(which) E100_REG_RX_CTRL_HELPER(which, 2) +#define E100_REG_RX_CTRL_CLEAR(which) E100_REG_RX_CTRL_HELPER(which, 3) +#define E100_REG_RX_CTRL_VRT_HDR(which) E100_REG_RX_CTRL_HELPER(which, 4) +#define E100_REG_RX_CTRL_VRT_SID(which) E100_REG_RX_CTRL_HELPER(which, 5) +#define E100_REG_RX_CTRL_VRT_TLR(which) E100_REG_RX_CTRL_HELPER(which, 6) +#define E100_REG_RX_CTRL_NSAMPS_PP(which) E100_REG_RX_CTRL_HELPER(which, 7) +#define E100_REG_RX_CTRL_NCHANNELS(which) E100_REG_RX_CTRL_HELPER(which, 8) + +///////////////////////////////////////////////// +// RX FE +//////////////////////////////////////////////// +#define E100_REG_RX_FE_SWAP_IQ E100_REG_SR_ADDR(UE_SR_RX_FRONT + 0) //lower bit +#define E100_REG_RX_FE_MAG_CORRECTION E100_REG_SR_ADDR(UE_SR_RX_FRONT + 1) //18 bits +#define E100_REG_RX_FE_PHASE_CORRECTION E100_REG_SR_ADDR(UE_SR_RX_FRONT + 2) //18 bits +#define E100_REG_RX_FE_OFFSET_I E100_REG_SR_ADDR(UE_SR_RX_FRONT + 3) //18 bits +#define E100_REG_RX_FE_OFFSET_Q E100_REG_SR_ADDR(UE_SR_RX_FRONT + 4) //18 bits + +///////////////////////////////////////////////// +// DSP TX Regs +//////////////////////////////////////////////// +#define E100_REG_DSP_TX_FREQ E100_REG_SR_ADDR(UE_SR_TX_DSP + 0) +#define E100_REG_DSP_TX_SCALE_IQ E100_REG_SR_ADDR(UE_SR_TX_DSP + 1) +#define E100_REG_DSP_TX_INTERP_RATE E100_REG_SR_ADDR(UE_SR_TX_DSP + 2) + +/////////////////////////////////////////////////// +// TX CTRL regs +/////////////////////////////////////////////////// +#define E100_REG_TX_CTRL_NUM_CHAN E100_REG_SR_ADDR(UE_SR_TX_CTRL + 0) +#define E100_REG_TX_CTRL_CLEAR_STATE E100_REG_SR_ADDR(UE_SR_TX_CTRL + 1) +#define E100_REG_TX_CTRL_REPORT_SID E100_REG_SR_ADDR(UE_SR_TX_CTRL + 2) +#define E100_REG_TX_CTRL_POLICY E100_REG_SR_ADDR(UE_SR_TX_CTRL + 3) +#define E100_REG_TX_CTRL_CYCLES_PER_UP E100_REG_SR_ADDR(UE_SR_TX_CTRL + 4) +#define E100_REG_TX_CTRL_PACKETS_PER_UP E100_REG_SR_ADDR(UE_SR_TX_CTRL + 5) + +#define E100_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) +#define E100_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) +#define E100_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) + +///////////////////////////////////////////////// +// TX FE +//////////////////////////////////////////////// +#define E100_REG_TX_FE_DC_OFFSET_I E100_REG_SR_ADDR(UE_SR_TX_FRONT + 0) //24 bits +#define E100_REG_TX_FE_DC_OFFSET_Q E100_REG_SR_ADDR(UE_SR_TX_FRONT + 1) //24 bits +#define E100_REG_TX_FE_MAC_CORRECTION E100_REG_SR_ADDR(UE_SR_TX_FRONT + 2) //18 bits +#define E100_REG_TX_FE_PHASE_CORRECTION E100_REG_SR_ADDR(UE_SR_TX_FRONT + 3) //18 bits +#define E100_REG_TX_FE_MUX E100_REG_SR_ADDR(UE_SR_TX_FRONT + 4) //8 bits (std output = 0x10, reversed = 0x01) + +///////////////////////////////////////////////// +// VITA49 64 bit time (write only) +//////////////////////////////////////////////// +#define E100_REG_TIME64_SECS E100_REG_SR_ADDR(UE_SR_TIME64 + 0) +#define E100_REG_TIME64_TICKS E100_REG_SR_ADDR(UE_SR_TIME64 + 1) +#define E100_REG_TIME64_FLAGS E100_REG_SR_ADDR(UE_SR_TIME64 + 2) +#define E100_REG_TIME64_IMM E100_REG_SR_ADDR(UE_SR_TIME64 + 3) +#define E100_REG_TIME64_TPS E100_REG_SR_ADDR(UE_SR_TIME64 + 4) +#define E100_REG_TIME64_MIMO_SYNC E100_REG_SR_ADDR(UE_SR_TIME64 + 5) + +//pps flags (see above) +#define E100_FLAG_TIME64_PPS_NEGEDGE (0 << 0) +#define E100_FLAG_TIME64_PPS_POSEDGE (1 << 0) +#define E100_FLAG_TIME64_PPS_SMA (0 << 1) +#define E100_FLAG_TIME64_PPS_MIMO (1 << 1) + +#define E100_FLAG_TIME64_LATCH_NOW 1 +#define E100_FLAG_TIME64_LATCH_NEXT_PPS 0 + +#endif + diff --git a/host/lib/usrp/e100/fpga_downloader.cpp b/host/lib/usrp/e100/fpga_downloader.cpp new file mode 100644 index 000000000..7074c8299 --- /dev/null +++ b/host/lib/usrp/e100/fpga_downloader.cpp @@ -0,0 +1,272 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#ifdef UHD_DLL_EXPORTS +#include +#include +#else //special case when this file is externally included +#include +#include +#define UHD_MSG(type) std::cout +namespace uhd{ + typedef std::runtime_error os_error; + typedef std::runtime_error io_error; +} +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * Configuration connections + * + * CCK - MCSPI1_CLK + * DIN - MCSPI1_MOSI + * PROG_B - GPIO_175 - output (change mux) + * DONE - GPIO_173 - input (change mux) + * INIT_B - GPIO_114 - input (change mux) + * +*/ + +namespace usrp_e_fpga_downloader_utility{ + +const unsigned int PROG_B = 175; +const unsigned int DONE = 173; +const unsigned int INIT_B = 114; + +//static std::string bit_file = "safe_u1e.bin"; + +const int BUF_SIZE = 4096; + +enum gpio_direction {IN, OUT}; + +class gpio { + public: + + gpio(unsigned int gpio_num, gpio_direction pin_direction); + + bool get_value(); + void set_value(bool state); + + private: + + std::stringstream base_path; + std::fstream value_file; +}; + +class spidev { + public: + + spidev(std::string dev_name); + ~spidev(); + + void send(char *wbuf, char *rbuf, unsigned int nbytes); + + private: + + int fd; + +}; + +gpio::gpio(unsigned int gpio_num, gpio_direction pin_direction) +{ + std::fstream export_file; + + export_file.open("/sys/class/gpio/export", std::ios::out); + if (not export_file.is_open()) throw uhd::os_error( + "Failed to open gpio export file." + ); + + export_file << gpio_num << std::endl; + + base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush; + + std::fstream direction_file; + std::string direction_file_name; + + if (gpio_num != 114) { + direction_file_name = base_path.str() + "/direction"; + + direction_file.open(direction_file_name.c_str()); + if (!direction_file.is_open()) throw uhd::os_error( + "Failed to open direction file." + ); + if (pin_direction == OUT) + direction_file << "out" << std::endl; + else + direction_file << "in" << std::endl; + } + + std::string value_file_name; + + value_file_name = base_path.str() + "/value"; + + value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out); + if (!value_file.is_open()) throw uhd::os_error( + "Failed to open value file." + ); +} + +bool gpio::get_value() +{ + + std::string val; + + std::getline(value_file, val); + value_file.seekg(0); + + if (val == "0") + return false; + else if (val == "1") + return true; + else + throw uhd::os_error("Data read from value file|" + val + "|"); + + return false; +} + +void gpio::set_value(bool state) +{ + + if (state) + value_file << "1" << std::endl; + else + value_file << "0" << std::endl; +} + +static void prepare_fpga_for_configuration(gpio &prog, gpio &)//init) +{ + + prog.set_value(true); + prog.set_value(false); + prog.set_value(true); + +#if 0 + bool ready_to_program(false); + unsigned int count(0); + do { + ready_to_program = init.get_value(); + count++; + + sleep(1); + } while (count < 10 && !ready_to_program); + + if (count == 10) { + throw uhd::os_error("FPGA not ready for programming."); + } +#endif +} + +spidev::spidev(std::string fname) +{ + int ret; + int mode = 0; + int speed = 12000000; + int bits = 8; + + fd = open(fname.c_str(), O_RDWR); + + ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); + ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); +} + + +spidev::~spidev() +{ + close(fd); +} + +void spidev::send(char *buf, char *rbuf, unsigned int nbytes) +{ + int ret; + + struct spi_ioc_transfer tr; + tr.tx_buf = (unsigned long) buf; + tr.rx_buf = (unsigned long) rbuf; + tr.len = nbytes; + tr.delay_usecs = 0; + tr.speed_hz = 48000000; + tr.bits_per_word = 8; + + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); + +} + +static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &done) +{ + std::ifstream bitstream; + + bitstream.open(file_name.c_str(), std::ios::binary); + if (!bitstream.is_open()) throw uhd::os_error( + "Coult not open the file: " + file_name + ); + + spidev spi("/dev/spidev1.0"); + char buf[BUF_SIZE]; + char rbuf[BUF_SIZE]; + + do { + bitstream.read(buf, BUF_SIZE); + spi.send(buf, rbuf, bitstream.gcount()); + + if (error.get_value()) + throw uhd::os_error("INIT_B went high, error occured."); + + if (!done.get_value()) + UHD_MSG(status) << "Configuration complete." << std::endl; + + } while (bitstream.gcount() == BUF_SIZE); +} + +}//namespace usrp_e_fpga_downloader_utility + +void e100_load_fpga(const std::string &bin_file){ + using namespace usrp_e_fpga_downloader_utility; + + gpio gpio_prog_b(PROG_B, OUT); + gpio gpio_init_b(INIT_B, IN); + gpio gpio_done (DONE, IN); + + UHD_MSG(status) << "Loading FPGA image: " << bin_file << "... " << std::flush; + +// if(std::system("/sbin/rmmod usrp_e") != 0){ +// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl; +// } + + prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); + + UHD_MSG(status) << "done = " << gpio_done.get_value() << std::endl; + + send_file_to_fpga(bin_file, gpio_init_b, gpio_done); + +// if(std::system("/sbin/modprobe usrp_e") != 0){ +// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl; +// } + +} + diff --git a/host/lib/usrp/e100/include/linux/usrp_e.h b/host/lib/usrp/e100/include/linux/usrp_e.h new file mode 100644 index 000000000..4c6a5dd89 --- /dev/null +++ b/host/lib/usrp/e100/include/linux/usrp_e.h @@ -0,0 +1,91 @@ + +/* + * Copyright (C) 2010 Ettus Research, LLC + * + * Written by Philip Balister + * + * 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 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __USRP_E_H +#define __USRP_E_H + +#include +#include + +struct usrp_e_ctl16 { + __u32 offset; + __u32 count; + __u16 buf[20]; +}; + +struct usrp_e_ctl32 { + __u32 offset; + __u32 count; + __u32 buf[10]; +}; + +/* SPI interface */ + +#define UE_SPI_TXONLY 0 +#define UE_SPI_TXRX 1 + +/* Defines for spi ctrl register */ +#define UE_SPI_CTRL_TXNEG (1<<10) +#define UE_SPI_CTRL_RXNEG (1<<9) + +#define UE_SPI_PUSH_RISE 0 +#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG +#define UE_SPI_LATCH_RISE 0 +#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG + +struct usrp_e_spi { + __u8 readback; + __u32 slave; + __u32 data; + __u32 length; + __u32 flags; +}; + +struct usrp_e_i2c { + __u8 addr; + __u32 len; + __u8 data[]; +}; + +#define USRP_E_IOC_MAGIC 'u' +#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16) +#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16) +#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32) +#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32) +#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi) +#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c) +#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c) +#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) +#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) + +#define USRP_E_COMPAT_NUMBER 1 + +/* Flag defines */ +#define RB_USER (1<<0) +#define RB_KERNEL (1<<1) +#define RB_OVERRUN (1<<2) +#define RB_DMA_ACTIVE (1<<3) +#define RB_USER_PROCESS (1<<4) + +struct ring_buffer_info { + int flags; + int len; +}; + +struct usrp_e_ring_buffer_size_t { + int num_pages_rx_flags; + int num_rx_frames; + int num_pages_tx_flags; + int num_tx_frames; +}; + +#endif diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp new file mode 100644 index 000000000..dc0d959fa --- /dev/null +++ b/host/lib/usrp/e100/io_impl.cpp @@ -0,0 +1,297 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "../../transport/super_recv_packet_handler.hpp" +#include "../../transport/super_send_packet_handler.hpp" +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +/*********************************************************************** + * Helpers + **********************************************************************/ +#if 1 +# define debug_print_buff(...) +#else +static void debug_print_buff(const std::string &what, managed_recv_buffer::sptr buff){ + std::ostringstream ss; + ss << boost::format( + "This is a %s packet, %u bytes.\n" + ) % what % buff->size(); + for (size_t i = 0; i < 9; i++){ + ss << boost::format(" buff[%u] = 0x%08x\n") % i % buff->cast()[i]; + } + ss << std::endl << std::endl; + UHD_MSG(status) << ss.str(); +} +#endif + +/*********************************************************************** + * io impl details (internal to this file) + * - pirate crew of 1 + * - bounded buffer + * - thread loop + * - vrt packet handler states + **********************************************************************/ +struct e100_impl::io_impl{ + io_impl(zero_copy_if::sptr &xport): + data_xport(xport), + async_msg_fifo(100/*messages deep*/) + { + for (size_t i = 0; i < E100_NUM_RX_DSPS; i++){ + typedef bounded_buffer booty_type; + recv_pirate_booty.push_back(new booty_type(data_xport->get_num_recv_frames())); + } + } + + ~io_impl(void){ + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); + for (size_t i = 0; i < recv_pirate_booty.size(); i++){ + delete recv_pirate_booty[i]; + } + } + + managed_recv_buffer::sptr get_recv_buff(const size_t index, double timeout){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + managed_recv_buffer::sptr buff; + recv_pirate_booty[index]->pop_with_timed_wait(buff, timeout); + return buff; //ASSUME buff == NULL when pop times-out + } + + //The data transport is listed first so that it is deconstructed last, + //which is after the states and booty which may hold managed buffers. + //This comment is invalid because its now a reference and not stored here. + zero_copy_if::sptr &data_xport; + + //state management for the vrt packet handler code + sph::recv_packet_handler recv_handler; + sph::send_packet_handler send_handler; + bool continuous_streaming; + + //a pirate's life is the life for me! + void recv_pirate_loop(boost::barrier &, e100_clock_ctrl::sptr); + std::vector *> recv_pirate_booty; + bounded_buffer async_msg_fifo; + boost::thread_group recv_pirate_crew; +}; + +/*********************************************************************** + * Receive Pirate Loop + * - while raiding, loot for recv buffers + * - put booty into the alignment buffer + **********************************************************************/ +void e100_impl::io_impl::recv_pirate_loop( + boost::barrier &spawn_barrier, e100_clock_ctrl::sptr clock_ctrl +){ + spawn_barrier.wait(); + set_thread_priority_safe(); + + while (not boost::this_thread::interruption_requested()){ + managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(); + if (buff.get() == NULL) continue; //ignore timeout buffers + + //handle an rx data packet or inline message + const boost::uint32_t *vrt_hdr = buff->cast(); + const size_t rx_index = uhd::wtohx(vrt_hdr[1]) - E100_DSP_SID_BASE; + if (rx_index < E100_NUM_RX_DSPS){ + debug_print_buff("data", buff); + recv_pirate_booty[rx_index]->push_with_wait(buff); + continue; + } + + //otherwise, unpack the vrt header and process below... + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); + try{vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);} + catch(const std::exception &e){ + UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl; + continue; + } + + //handle a tx async report message + if (if_packet_info.sid == E100_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + debug_print_buff("async", buff); + + //fill in the async metadata + async_metadata_t metadata; + metadata.channel = 0; + metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; + metadata.time_spec = time_spec_t( + time_t(if_packet_info.tsi), long(if_packet_info.tsf), clock_ctrl->get_fpga_clock_rate() + ); + metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); + async_msg_fifo.push_with_pop_on_full(metadata); + if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_UNDERFLOW + | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET) + ) UHD_MSG(fastpath) << "U"; + else if (metadata.event_code & + ( async_metadata_t::EVENT_CODE_SEQ_ERROR + | async_metadata_t::EVENT_CODE_SEQ_ERROR_IN_BURST) + ) UHD_MSG(fastpath) << "S"; + continue; + } + + debug_print_buff("unknown", buff); + } +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +void e100_impl::io_init(void){ + + //setup before the registers (transport called to calculate max spp) + _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport)); + + //clear state machines + _iface->poke32(E100_REG_CLEAR_RX, 0); + _iface->poke32(E100_REG_CLEAR_TX, 0); + + //spawn a pirate, yarrr! + boost::barrier spawn_barrier(2); + _io_impl->recv_pirate_crew.create_thread(boost::bind( + &e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), + boost::ref(spawn_barrier), _clock_ctrl + )); + spawn_barrier.wait(); + //update mapping here since it didnt b4 when io init not called first + update_xport_channel_mapping(); +} + +void e100_impl::update_xport_channel_mapping(void){ + if (_io_impl.get() == NULL) return; //not inited yet + + //set all of the relevant properties on the handler + boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); + _io_impl->recv_handler.resize(_rx_subdev_spec.size()); + _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); + _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); + //FIXME assumes homogeneous rates across all dsp + _io_impl->recv_handler.set_samp_rate(_rx_dsp_proxies[_rx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as()); + for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ + _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( + &e100_impl::io_impl::get_recv_buff, _io_impl.get(), chan, _1 + )); + _io_impl->recv_handler.set_overflow_handler(chan, boost::bind( + &e100_impl::handle_overrun, this, chan + )); + } + _io_impl->recv_handler.set_converter(_recv_otw_type); + + //set all of the relevant properties on the handler + boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); + _io_impl->send_handler.resize(_tx_subdev_spec.size()); + _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); + _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); + //FIXME assumes homogeneous rates across all dsp + _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as()); + for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ + _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( + &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_xport, _1 + )); + } + _io_impl->send_handler.set_converter(_send_otw_type); + _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); +} + +void e100_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, const size_t index){ + _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + _iface->poke32(E100_REG_RX_CTRL_STREAM_CMD(index), dsp_type1::calc_stream_cmd_word(stream_cmd)); + _iface->poke32(E100_REG_RX_CTRL_TIME_SECS(index), boost::uint32_t(stream_cmd.time_spec.get_full_secs())); + _iface->poke32(E100_REG_RX_CTRL_TIME_TICKS(index), stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); +} + +void e100_impl::handle_overrun(const size_t index){ + if (_io_impl->continuous_streaming){ + this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS, index); + } +} + +/*********************************************************************** + * Data Send + **********************************************************************/ +size_t e100_impl::get_max_send_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _send_frame_size - hdr_size; + return bpp/_send_otw_type.get_sample_size(); +} + +size_t e100_impl::send( + const send_buffs_type &buffs, size_t nsamps_per_buff, + const tx_metadata_t &metadata, const io_type_t &io_type, + send_mode_t send_mode, double timeout +){ + return _io_impl->send_handler.send( + buffs, nsamps_per_buff, + metadata, io_type, + send_mode, timeout + ); +} + +/*********************************************************************** + * Data Recv + **********************************************************************/ +size_t e100_impl::get_max_recv_samps_per_packet(void) const{ + static const size_t hdr_size = 0 + + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) + + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer + - sizeof(vrt::if_packet_info_t().cid) //no class id ever used + ; + size_t bpp = _recv_frame_size - hdr_size; + return bpp/_recv_otw_type.get_sample_size(); +} + +size_t e100_impl::recv( + const recv_buffs_type &buffs, size_t nsamps_per_buff, + rx_metadata_t &metadata, const io_type_t &io_type, + recv_mode_t recv_mode, double timeout +){ + return _io_impl->recv_handler.recv( + buffs, nsamps_per_buff, + metadata, io_type, + recv_mode, timeout + ); +} + +/*********************************************************************** + * Async Recv + **********************************************************************/ +bool e100_impl::recv_async_msg( + async_metadata_t &async_metadata, double timeout +){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); +} diff --git a/host/lib/usrp/e100/mboard_impl.cpp b/host/lib/usrp/e100/mboard_impl.cpp new file mode 100644 index 000000000..e7a46fe8e --- /dev/null +++ b/host/lib/usrp/e100/mboard_impl.cpp @@ -0,0 +1,256 @@ +// +// Copyright 2010-2011 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "e100_impl.hpp" +#include "e100_regs.hpp" +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Mboard Initialization + **********************************************************************/ +void e100_impl::mboard_init(void){ + _mboard_proxy = wax_obj_proxy::make( + boost::bind(&e100_impl::mboard_get, this, _1, _2), + boost::bind(&e100_impl::mboard_set, this, _1, _2) + ); + + //init the clock config + _clock_config = clock_config_t::internal(); + update_clock_config(); +} + +void e100_impl::update_clock_config(void){ + boost::uint32_t pps_flags = 0; + + //translate pps polarity enums + switch(_clock_config.pps_polarity){ + case clock_config_t::PPS_POS: pps_flags |= E100_FLAG_TIME64_PPS_POSEDGE; break; + case clock_config_t::PPS_NEG: pps_flags |= E100_FLAG_TIME64_PPS_NEGEDGE; break; + default: throw uhd::value_error("unhandled clock configuration pps polarity"); + } + + //set the pps flags + _iface->poke32(E100_REG_TIME64_FLAGS, pps_flags); + + //clock source ref 10mhz + switch(_clock_config.ref_source){ + case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break; + case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break; + case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break; + default: throw uhd::value_error("unhandled clock configuration ref source"); + } +} + +/*********************************************************************** + * Mboard Get + **********************************************************************/ +void e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){ + named_prop_t key = named_prop_t::extract(key_); + static const std::string dboard_name = "A"; + + //handle the get request conditioned on the key + switch(key.as()){ + case MBOARD_PROP_NAME: + val = std::string(_iface->get_cname() + " mboard"); + return; + + case MBOARD_PROP_OTHERS: + val = prop_names_t(); + return; + + case MBOARD_PROP_RX_DBOARD: + UHD_ASSERT_THROW(key.name == dboard_name); + val = _rx_dboard_proxy->get_link(); + return; + + case MBOARD_PROP_RX_DBOARD_NAMES: + val = prop_names_t(1, dboard_name); + return; + + case MBOARD_PROP_TX_DBOARD: + UHD_ASSERT_THROW(key.name == dboard_name); + val = _tx_dboard_proxy->get_link(); + return; + + case MBOARD_PROP_TX_DBOARD_NAMES: + val = prop_names_t(1, dboard_name); + return; + + case MBOARD_PROP_RX_DSP: + val = _rx_dsp_proxies[key.name]->get_link(); + return; + + case MBOARD_PROP_RX_DSP_NAMES: + val = _rx_dsp_proxies.keys(); + return; + + case MBOARD_PROP_TX_DSP: + val = _tx_dsp_proxies[key.name]->get_link(); + return; + + case MBOARD_PROP_TX_DSP_NAMES: + val = _tx_dsp_proxies.keys(); + return; + + case MBOARD_PROP_CLOCK_CONFIG: + val = _clock_config; + return; + + case MBOARD_PROP_RX_SUBDEV_SPEC: + val = _rx_subdev_spec; + return; + + case MBOARD_PROP_TX_SUBDEV_SPEC: + val = _tx_subdev_spec; + return; + + case MBOARD_PROP_EEPROM_MAP: + val = _iface->mb_eeprom; + return; + + case MBOARD_PROP_TIME_NOW: while(true){ + uint32_t secs = _iface->peek32(E100_REG_RB_TIME_NOW_SECS); + uint32_t ticks = _iface->peek32(E100_REG_RB_TIME_NOW_TICKS); + if (secs != _iface->peek32(E100_REG_RB_TIME_NOW_SECS)) continue; + val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); + return; + } + + case MBOARD_PROP_TIME_PPS: while(true){ + uint32_t secs = _iface->peek32(E100_REG_RB_TIME_PPS_SECS); + uint32_t ticks = _iface->peek32(E100_REG_RB_TIME_PPS_TICKS); + if (secs != _iface->peek32(E100_REG_RB_TIME_PPS_SECS)) continue; + val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); + return; + } + + case MBOARD_PROP_CLOCK_RATE: + val = _clock_ctrl->get_fpga_clock_rate(); + return; + + default: UHD_THROW_PROP_GET_ERROR(); + } +} + +/*********************************************************************** + * Mboard Set + **********************************************************************/ +void e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){ + //handle the get request conditioned on the key + switch(key.as()){ + + case MBOARD_PROP_TIME_NOW: + case MBOARD_PROP_TIME_PPS:{ + time_spec_t time_spec = val.as(); + _iface->poke32(E100_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); + boost::uint32_t imm_flags = (key.as() == MBOARD_PROP_TIME_NOW)? 1 : 0; + _iface->poke32(E100_REG_TIME64_IMM, imm_flags); + _iface->poke32(E100_REG_TIME64_SECS, time_spec.get_full_secs()); + } + return; + + case MBOARD_PROP_RX_SUBDEV_SPEC:{ + _rx_subdev_spec = val.as(); + verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); + //sanity check + UHD_ASSERT_THROW(_rx_subdev_spec.size() <= E100_NUM_RX_DSPS); + + //determine frontend swap IQ from the first channel + bool fe_swap_iq = false; + switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(0).sd_name)[SUBDEV_PROP_CONNECTION].as()){ + case SUBDEV_CONN_COMPLEX_QI: + case SUBDEV_CONN_REAL_Q: + fe_swap_iq = true; + break; + default: fe_swap_iq = false; + } + _iface->poke32(E100_REG_RX_FE_SWAP_IQ, fe_swap_iq? 1 : 0); + + //set the dsp mux for each channel + for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ + bool iq_swap = false, real_mode = false; + switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(i).sd_name)[SUBDEV_PROP_CONNECTION].as()){ + case SUBDEV_CONN_COMPLEX_IQ: + iq_swap = fe_swap_iq; + real_mode = false; + break; + case SUBDEV_CONN_COMPLEX_QI: + iq_swap = not fe_swap_iq; + real_mode = false; + break; + case SUBDEV_CONN_REAL_I: + iq_swap = fe_swap_iq; + real_mode = true; + break; + case SUBDEV_CONN_REAL_Q: + iq_swap = not fe_swap_iq; + real_mode = true; + break; + } + _iface->poke32(E100_REG_DSP_RX_MUX(i), + (iq_swap? E100_FLAG_DSP_RX_MUX_SWAP_IQ : 0) | + (real_mode? E100_FLAG_DSP_RX_MUX_REAL_MODE : 0) + ); + } + this->update_xport_channel_mapping(); + }return; + + case MBOARD_PROP_TX_SUBDEV_SPEC: + _tx_subdev_spec = val.as(); + verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); + //sanity check + UHD_ASSERT_THROW(_tx_subdev_spec.size() <= E100_NUM_TX_DSPS); + //set the mux + _iface->poke32(E100_REG_TX_FE_MUX, dsp_type1::calc_tx_mux_word( + _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as() + )); + return; + + case MBOARD_PROP_EEPROM_MAP: + // Step1: commit the map, writing only those values set. + // Step2: readback the entire eeprom map into the iface. + val.as().commit(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); + _iface->mb_eeprom = mboard_eeprom_t(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); + return; + + case MBOARD_PROP_CLOCK_CONFIG: + _clock_config = val.as(); + update_clock_config(); + return; + + case MBOARD_PROP_CLOCK_RATE: + UHD_MSG(warning) + << "I see that you are setting the master clock rate from the API.\n" + << "You may pass this into the device address as master_clock_rate=.\n" + << "This way, the clock rate is guaranteed to be initialized first.\n" + << "See the application notes for USRP-E1XX for further instructions.\n" + ; + _clock_ctrl->set_fpga_clock_rate(val.as()); + this->update_xport_channel_mapping(); + return; + + default: UHD_THROW_PROP_SET_ERROR(); + } +} diff --git a/host/lib/usrp/usrp_e100/CMakeLists.txt b/host/lib/usrp/usrp_e100/CMakeLists.txt deleted file mode 100644 index d0e20a3d8..000000000 --- a/host/lib/usrp/usrp_e100/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright 2010-2011 Ettus Research LLC -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -######################################################################## -# This file included, use CMake directory variables -######################################################################## - -######################################################################## -# Conditionally configure the USRP-E100 support -######################################################################## -LIBUHD_REGISTER_COMPONENT("USRP-E100" ENABLE_USRP_E100 OFF "ENABLE_LIBUHD;LINUX" OFF) - -IF(ENABLE_USRP_E100) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) - - LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/codec_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_iface.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_mmap_zero_copy.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_regs.hpp - ) -ENDIF(ENABLE_USRP_E100) diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp deleted file mode 100644 index 742959ae3..000000000 --- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp +++ /dev/null @@ -1,512 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "clock_ctrl.hpp" -#include "ad9522_regs.hpp" -#include -#include -#include -#include -#include "usrp_e100_regs.hpp" //spi slave constants -#include -#include -#include -#include -#include //gcd -#include -#include - -using namespace uhd; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const bool ENABLE_THE_TEST_OUT = true; -static const double REFERENCE_INPUT_RATE = 10e6; - -/*********************************************************************** - * Helpers - **********************************************************************/ -template static void set_clock_divider( - size_t divider, div_type &low, div_type &high, bypass_type &bypass -){ - high = divider/2 - 1; - low = divider - high - 2; - bypass = (divider == 1)? 1 : 0; -} - -/*********************************************************************** - * Clock rate calculation stuff: - * Using the internal VCO between 1400 and 1800 MHz - **********************************************************************/ -struct clock_settings_type{ - size_t ref_clock_doubler, r_counter, a_counter, b_counter, prescaler, vco_divider, chan_divider; - size_t get_n_counter(void) const{return prescaler * b_counter + a_counter;} - double get_ref_rate(void) const{return REFERENCE_INPUT_RATE * ref_clock_doubler;} - double get_vco_rate(void) const{return get_ref_rate()/r_counter * get_n_counter();} - double get_chan_rate(void) const{return get_vco_rate()/vco_divider;} - double get_out_rate(void) const{return get_chan_rate()/chan_divider;} - std::string to_pp_string(void) const{ - return str(boost::format( - " r_counter: %d\n" - " a_counter: %d\n" - " b_counter: %d\n" - " prescaler: %d\n" - " vco_divider: %d\n" - " chan_divider: %d\n" - " vco_rate: %fMHz\n" - " chan_rate: %fMHz\n" - " out_rate: %fMHz\n" - ) - % r_counter - % a_counter - % b_counter - % prescaler - % vco_divider - % chan_divider - % (get_vco_rate()/1e6) - % (get_chan_rate()/1e6) - % (get_out_rate()/1e6) - ); - } -}; - -//! gives the greatest divisor of num between 1 and max inclusive -template static inline T greatest_divisor(T num, T max){ - for (T i = max; i > 1; i--) if (num%i == 0) return i; return 1; -} - -//! gives the least divisor of num between min and num exclusive -template static inline T least_divisor(T num, T min){ - for (T i = min; i < num; i++) if (num%i == 0) return i; return 1; -} - -static clock_settings_type get_clock_settings(double rate){ - clock_settings_type cs; - cs.ref_clock_doubler = 2; //always doubling - cs.prescaler = 8; //set to 8 when input is under 2400 MHz - - //basic formulas used below: - //out_rate*X = ref_rate*Y - //X = i*ref_rate/gcd - //Y = i*out_rate/gcd - //X = chan_div * vco_div * R - //Y = P*B + A - - const boost::uint64_t out_rate = boost::uint64_t(rate); - const boost::uint64_t ref_rate = boost::uint64_t(cs.get_ref_rate()); - const size_t gcd = size_t(boost::math::gcd(ref_rate, out_rate)); - - for (size_t i = 1; i <= 100; i++){ - const size_t X = i*ref_rate/gcd; - const size_t Y = i*out_rate/gcd; - - //determine A and B (P is fixed) - cs.b_counter = Y/cs.prescaler; - cs.a_counter = Y - cs.b_counter*cs.prescaler; - - static const double vco_bound_pad = 100e6; - for ( //calculate an r divider that fits into the bounds of the vco - cs.r_counter = size_t(cs.get_n_counter()*cs.get_ref_rate()/(1800e6 - vco_bound_pad)); - cs.r_counter <= size_t(cs.get_n_counter()*cs.get_ref_rate()/(1400e6 + vco_bound_pad)) - and cs.r_counter > 0; cs.r_counter++ - ){ - - //determine chan_div and vco_div - //and fill in that order of preference - cs.chan_divider = greatest_divisor(X/cs.r_counter, 32); - cs.vco_divider = greatest_divisor(X/cs.chan_divider/cs.r_counter, 6); - - //avoid a vco divider of 1 (if possible) - if (cs.vco_divider == 1){ - cs.vco_divider = least_divisor(cs.chan_divider, 2); - cs.chan_divider /= cs.vco_divider; - } - - UHD_LOGV(always) - << "gcd " << gcd << std::endl - << "X " << X << std::endl - << "Y " << Y << std::endl - << cs.to_pp_string() << std::endl - ; - - //filter limits on the counters - if (cs.vco_divider == 1) continue; - if (cs.r_counter >= (1<<14)) continue; - if (cs.b_counter == 2) continue; - if (cs.b_counter == 1 and cs.a_counter != 0) continue; - if (cs.b_counter >= (1<<13)) continue; - if (cs.a_counter >= (1<<6)) continue; - - UHD_MSG(status) << "USRP-E100 clock control: " << i << std::endl << cs.to_pp_string() << std::endl; - return cs; - } - } - - throw uhd::value_error(str(boost::format( - "USRP-E100 clock control: could not calculate settings for clock rate %fMHz" - ) % (rate/1e6))); -} - -/*********************************************************************** - * Clock Control Implementation - **********************************************************************/ -class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{ -public: - usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface, double master_clock_rate){ - _iface = iface; - _chan_rate = 0.0; - _out_rate = 0.0; - - //perform soft-reset - _ad9522_regs.soft_reset = 1; - this->send_reg(0x000); - this->latch_regs(); - _ad9522_regs.soft_reset = 0; - - //init the clock gen registers - //Note: out0 should already be clocking the FPGA or this isnt going to work - _ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO; - _ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin - _ad9522_regs.status_pin_control = 0x1; //n divider - _ad9522_regs.ld_pin_control = 0x00; //dld - _ad9522_regs.refmon_pin_control = 0x12; //show ref2 - _ad9522_regs.lock_detect_counter = ad9522_regs_t::LOCK_DETECT_COUNTER_16CYC; - - this->use_internal_ref(); - - //initialize the FPGA clock rate - UHD_MSG(status) << boost::format("Initializing FPGA clock to %fMHz...") % (master_clock_rate/1e6) << std::endl; - this->set_fpga_clock_rate(master_clock_rate); - - this->enable_test_clock(ENABLE_THE_TEST_OUT); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - } - - ~usrp_e100_clock_ctrl_impl(void){ - this->enable_test_clock(ENABLE_THE_TEST_OUT); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - } - - /*********************************************************************** - * Clock rate control: - * - set clock rate w/ internal VCO - * - set clock rate w/ external VCXO - **********************************************************************/ - void set_clock_settings_with_internal_vco(double rate){ - const clock_settings_type cs = get_clock_settings(rate); - - //set the rates to private variables so the implementation knows! - _chan_rate = cs.get_chan_rate(); - _out_rate = cs.get_out_rate(); - - _ad9522_regs.enable_clock_doubler = (cs.ref_clock_doubler == 2)? 1 : 0; - - _ad9522_regs.set_r_counter(cs.r_counter); - _ad9522_regs.a_counter = cs.a_counter; - _ad9522_regs.set_b_counter(cs.b_counter); - UHD_ASSERT_THROW(cs.prescaler == 8); //assumes this below: - _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV8_9; - - _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; - _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA; - - _ad9522_regs.bypass_vco_divider = 0; - switch(cs.vco_divider){ - case 1: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV1; break; - case 2: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV2; break; - case 3: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV3; break; - case 4: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV4; break; - case 5: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; break; - case 6: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV6; break; - } - _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO; - - //setup fpga master clock - _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; - set_clock_divider(cs.chan_divider, - _ad9522_regs.divider0_low_cycles, - _ad9522_regs.divider0_high_cycles, - _ad9522_regs.divider0_bypass - ); - - //setup codec clock - _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; - set_clock_divider(cs.chan_divider, - _ad9522_regs.divider1_low_cycles, - _ad9522_regs.divider1_high_cycles, - _ad9522_regs.divider1_bypass - ); - - this->send_all_regs(); - calibrate_now(); - } - - void set_clock_settings_with_external_vcxo(double rate){ - //set the rates to private variables so the implementation knows! - _chan_rate = rate; - _out_rate = rate; - - _ad9522_regs.enable_clock_doubler = 1; //doubler always on - const double ref_rate = REFERENCE_INPUT_RATE*2; - - //bypass prescaler such that N = B - long gcd = boost::math::gcd(long(ref_rate), long(rate)); - _ad9522_regs.set_r_counter(int(ref_rate/gcd)); - _ad9522_regs.a_counter = 0; - _ad9522_regs.set_b_counter(int(rate/gcd)); - _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV1; - - //setup external vcxo - _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; - _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA; - _ad9522_regs.bypass_vco_divider = 1; - _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_EXTERNAL; - - //setup fpga master clock - _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; - _ad9522_regs.divider0_bypass = 1; - - //setup codec clock - _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; - _ad9522_regs.divider1_bypass = 1; - - this->send_all_regs(); - } - - void set_fpga_clock_rate(double rate){ - if (_out_rate == rate) return; - if (rate == 61.44e6) set_clock_settings_with_external_vcxo(rate); - else set_clock_settings_with_internal_vco(rate); - //clock rate changed! update dboard clocks and FPGA ticks per second - set_rx_dboard_clock_rate(rate); - set_tx_dboard_clock_rate(rate); - _iface->poke32(UE_REG_TIME64_TPS, boost::uint32_t(get_fpga_clock_rate())); - } - - double get_fpga_clock_rate(void){ - return this->_out_rate; - } - - /*********************************************************************** - * Special test clock output - **********************************************************************/ - void enable_test_clock(bool enb){ - //setup test clock (same divider as codec clock) - _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS; - _ad9522_regs.out4_cmos_configuration = (enb)? - ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON : - ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF; - this->send_reg(0x0F4); - this->latch_regs(); - } - - /*********************************************************************** - * RX Dboard Clock Control (output 9, divider 3) - **********************************************************************/ - void enable_rx_dboard_clock(bool enb){ - _ad9522_regs.out9_format = ad9522_regs_t::OUT9_FORMAT_CMOS; - _ad9522_regs.out9_cmos_configuration = (enb)? - ad9522_regs_t::OUT9_CMOS_CONFIGURATION_B_ON : - ad9522_regs_t::OUT9_CMOS_CONFIGURATION_OFF; - this->send_reg(0x0F9); - this->latch_regs(); - } - - std::vector get_rx_dboard_clock_rates(void){ - std::vector rates; - for(size_t div = 1; div <= 16+16; div++) - rates.push_back(this->_chan_rate/div); - return rates; - } - - void set_rx_dboard_clock_rate(double rate){ - assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate"); - _rx_clock_rate = rate; - size_t divider = size_t(this->_chan_rate/rate); - //set the divider registers - set_clock_divider(divider, - _ad9522_regs.divider3_low_cycles, - _ad9522_regs.divider3_high_cycles, - _ad9522_regs.divider3_bypass - ); - this->send_reg(0x199); - this->send_reg(0x19a); - this->soft_sync(); - } - - double get_rx_clock_rate(void){ - return _rx_clock_rate; - } - - /*********************************************************************** - * TX Dboard Clock Control (output 6, divider 2) - **********************************************************************/ - void enable_tx_dboard_clock(bool enb){ - _ad9522_regs.out6_format = ad9522_regs_t::OUT6_FORMAT_CMOS; - _ad9522_regs.out6_cmos_configuration = (enb)? - ad9522_regs_t::OUT6_CMOS_CONFIGURATION_B_ON : - ad9522_regs_t::OUT6_CMOS_CONFIGURATION_OFF; - this->send_reg(0x0F6); - this->latch_regs(); - } - - std::vector get_tx_dboard_clock_rates(void){ - return get_rx_dboard_clock_rates(); //same master clock, same dividers... - } - - void set_tx_dboard_clock_rate(double rate){ - assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate"); - _tx_clock_rate = rate; - size_t divider = size_t(this->_chan_rate/rate); - //set the divider registers - set_clock_divider(divider, - _ad9522_regs.divider2_low_cycles, - _ad9522_regs.divider2_high_cycles, - _ad9522_regs.divider2_bypass - ); - this->send_reg(0x196); - this->send_reg(0x197); - this->soft_sync(); - } - - double get_tx_clock_rate(void){ - return _tx_clock_rate; - } - - /*********************************************************************** - * Clock reference control - **********************************************************************/ - void use_internal_ref(void) { - _ad9522_regs.enable_ref2 = 1; - _ad9522_regs.enable_ref1 = 0; - _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; - _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL; - this->send_reg(0x01C); - this->latch_regs(); - } - - void use_external_ref(void) { - _ad9522_regs.enable_ref2 = 0; - _ad9522_regs.enable_ref1 = 1; - _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1; - _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_MANUAL; - this->send_reg(0x01C); - this->latch_regs(); - } - - void use_auto_ref(void) { - _ad9522_regs.enable_ref2 = 1; - _ad9522_regs.enable_ref1 = 1; - _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF1; - _ad9522_regs.enb_auto_ref_switchover = ad9522_regs_t::ENB_AUTO_REF_SWITCHOVER_AUTO; - this->send_reg(0x01C); - this->latch_regs(); - } - -private: - usrp_e100_iface::sptr _iface; - ad9522_regs_t _ad9522_regs; - double _out_rate; //rate at the fpga and codec - double _chan_rate; //rate before final dividers - double _rx_clock_rate, _tx_clock_rate; - - void latch_regs(void){ - _ad9522_regs.io_update = 1; - this->send_reg(0x232); - } - - void send_reg(boost::uint16_t addr){ - boost::uint32_t reg = _ad9522_regs.get_write_reg(addr); - UHD_LOGV(often) << "clock control write reg: " << std::hex << reg << std::endl; - _iface->write_spi( - UE_SPI_SS_AD9522, - spi_config_t::EDGE_RISE, - reg, 24 - ); - } - - void calibrate_now(void){ - //vco calibration routine: - _ad9522_regs.vco_calibration_now = 0; - this->send_reg(0x18); - this->latch_regs(); - _ad9522_regs.vco_calibration_now = 1; - this->send_reg(0x18); - this->latch_regs(); - //wait for calibration done: - static const boost::uint8_t addr = 0x01F; - for (size_t ms10 = 0; ms10 < 100; ms10++){ - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - boost::uint32_t reg = _iface->read_spi( - UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, - _ad9522_regs.get_read_reg(addr), 24 - ); - _ad9522_regs.set_reg(addr, reg); - if (_ad9522_regs.vco_calibration_finished) goto wait_for_ld; - } - UHD_MSG(error) << "USRP-E100 clock control: VCO calibration timeout" << std::endl; - wait_for_ld: - //wait for digital lock detect: - for (size_t ms10 = 0; ms10 < 100; ms10++){ - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - boost::uint32_t reg = _iface->read_spi( - UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, - _ad9522_regs.get_read_reg(addr), 24 - ); - _ad9522_regs.set_reg(addr, reg); - if (_ad9522_regs.digital_lock_detect) return; - } - UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl; - } - - void soft_sync(void){ - _ad9522_regs.soft_sync = 1; - this->send_reg(0x230); - this->latch_regs(); - _ad9522_regs.soft_sync = 0; - this->send_reg(0x230); - this->latch_regs(); - } - - void send_all_regs(void){ - //setup a list of register ranges to write - typedef std::pair range_t; - static const std::vector ranges = boost::assign::list_of - (range_t(0x000, 0x000)) (range_t(0x010, 0x01F)) - (range_t(0x0F0, 0x0FD)) (range_t(0x190, 0x19B)) - (range_t(0x1E0, 0x1E1)) (range_t(0x230, 0x230)) - ; - - //write initial register values and latch/update - BOOST_FOREACH(const range_t &range, ranges){ - for(boost::uint16_t addr = range.first; addr <= range.second; addr++){ - this->send_reg(addr); - } - } - this->latch_regs(); - } -}; - -/*********************************************************************** - * Clock Control Make - **********************************************************************/ -usrp_e100_clock_ctrl::sptr usrp_e100_clock_ctrl::make(usrp_e100_iface::sptr iface, double master_clock_rate){ - return sptr(new usrp_e100_clock_ctrl_impl(iface, master_clock_rate)); -} diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/usrp_e100/clock_ctrl.hpp deleted file mode 100644 index 6f16bc6ed..000000000 --- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_USRP_E100_CLOCK_CTRL_HPP -#define INCLUDED_USRP_E100_CLOCK_CTRL_HPP - -#include "usrp_e100_iface.hpp" -#include -#include -#include - -/*! - * The usrp-e clock control: - * - Setup system clocks. - * - Disable/enable clock lines. - */ -class usrp_e100_clock_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a new clock control object. - * \param iface the usrp_e100 iface object - * \param master clock rate the FPGA rate - * \return the clock control object - */ - static sptr make(usrp_e100_iface::sptr iface, double master_clock_rate); - - /*! - * Set the rate of the fpga clock line. - * Throws if rate is not valid. - * \param rate the new rate in Hz - */ - virtual void set_fpga_clock_rate(double rate) = 0; - - /*! - * Get the rate of the fpga clock line. - * \return the fpga clock rate in Hz - */ - virtual double get_fpga_clock_rate(void) = 0; - - /*! - * Get the possible rates of the rx dboard clock. - * \return a vector of clock rates in Hz - */ - virtual std::vector get_rx_dboard_clock_rates(void) = 0; - - /*! - * Get the possible rates of the tx dboard clock. - * \return a vector of clock rates in Hz - */ - virtual std::vector get_tx_dboard_clock_rates(void) = 0; - - /*! - * Set the rx dboard clock rate to a possible rate. - * \param rate the new clock rate in Hz - * \throw exception when rate cannot be achieved - */ - virtual void set_rx_dboard_clock_rate(double rate) = 0; - - /*! - * Set the tx dboard clock rate to a possible rate. - * \param rate the new clock rate in Hz - * \throw exception when rate cannot be achieved - */ - virtual void set_tx_dboard_clock_rate(double rate) = 0; - - /*! - * Get the current rx dboard clock rate. - * \return the clock rate in Hz - */ - virtual double get_rx_clock_rate(void) = 0; - - /*! - * Get the current tx dboard clock rate. - * \return the clock rate in Hz - */ - virtual double get_tx_clock_rate(void) = 0; - - /*! - * Enable/disable the rx dboard clock. - * \param enb true to enable - */ - virtual void enable_rx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable the tx dboard clock. - * \param enb true to enable - */ - virtual void enable_tx_dboard_clock(bool enb) = 0; - - /*! - * Use the internal TCXO reference - */ - virtual void use_internal_ref(void) = 0; - - /*! - * Use the external SMA reference - */ - virtual void use_external_ref(void) = 0; - - /*! - * Use external if available, internal otherwise - */ - virtual void use_auto_ref(void) = 0; - -}; - -#endif /* INCLUDED_USRP_E100_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.cpp b/host/lib/usrp/usrp_e100/codec_ctrl.cpp deleted file mode 100644 index 43ad94a88..000000000 --- a/host/lib/usrp/usrp_e100/codec_ctrl.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "codec_ctrl.hpp" -#include "ad9862_regs.hpp" -#include -#include -#include -#include -#include -#include -#include -#include "usrp_e100_regs.hpp" //spi slave constants -#include - -using namespace uhd; - -const gain_range_t usrp_e100_codec_ctrl::tx_pga_gain_range(-20, 0, double(0.1)); -const gain_range_t usrp_e100_codec_ctrl::rx_pga_gain_range(0, 20, 1); - -/*********************************************************************** - * Codec Control Implementation - **********************************************************************/ -class usrp_e100_codec_ctrl_impl : public usrp_e100_codec_ctrl{ -public: - //structors - usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface); - ~usrp_e100_codec_ctrl_impl(void); - - //aux adc and dac control - double read_aux_adc(aux_adc_t which); - void write_aux_dac(aux_dac_t which, double volts); - - //pga gain control - void set_tx_pga_gain(double); - double get_tx_pga_gain(void); - void set_rx_pga_gain(double, char); - double get_rx_pga_gain(char); - -private: - usrp_e100_iface::sptr _iface; - ad9862_regs_t _ad9862_regs; - void send_reg(boost::uint8_t addr); - void recv_reg(boost::uint8_t addr); -}; - -/*********************************************************************** - * Codec Control Structors - **********************************************************************/ -usrp_e100_codec_ctrl_impl::usrp_e100_codec_ctrl_impl(usrp_e100_iface::sptr iface){ - _iface = iface; - - //soft reset - _ad9862_regs.soft_reset = 1; - this->send_reg(0); - - //initialize the codec register settings - _ad9862_regs.sdio_bidir = ad9862_regs_t::SDIO_BIDIR_SDIO_SDO; - _ad9862_regs.lsb_first = ad9862_regs_t::LSB_FIRST_MSB; - _ad9862_regs.soft_reset = 0; - - //setup rx side of codec - _ad9862_regs.byp_buffer_a = 1; - _ad9862_regs.byp_buffer_b = 1; - _ad9862_regs.buffer_a_pd = 1; - _ad9862_regs.buffer_b_pd = 1; - _ad9862_regs.rx_pga_a = 0;//0x1f; //TODO bring under api control - _ad9862_regs.rx_pga_b = 0;//0x1f; //TODO bring under api control - _ad9862_regs.rx_twos_comp = 1; - _ad9862_regs.rx_hilbert = ad9862_regs_t::RX_HILBERT_DIS; - - //setup tx side of codec - _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; - _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; - _ad9862_regs.tx_retime = ad9862_regs_t::TX_RETIME_CLKOUT2; - _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control - _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; - _ad9862_regs.interp = ad9862_regs_t::INTERP_2; - _ad9862_regs.tx_twos_comp = 1; - _ad9862_regs.fine_mode = ad9862_regs_t::FINE_MODE_BYPASS; - _ad9862_regs.coarse_mod = ad9862_regs_t::COARSE_MOD_BYPASS; - _ad9862_regs.dac_a_coarse_gain = 0x3; - _ad9862_regs.dac_b_coarse_gain = 0x3; - _ad9862_regs.edges = ad9862_regs_t::EDGES_NORMAL; - - //setup the dll - _ad9862_regs.input_clk_ctrl = ad9862_regs_t::INPUT_CLK_CTRL_EXTERNAL; - _ad9862_regs.dll_mult = ad9862_regs_t::DLL_MULT_2; - _ad9862_regs.dll_mode = ad9862_regs_t::DLL_MODE_FAST; - - //write the register settings to the codec - for (uint8_t addr = 0; addr <= 25; addr++){ - this->send_reg(addr); - } - - //always start conversions for aux ADC - _ad9862_regs.start_a = 1; - _ad9862_regs.start_b = 1; - - //aux adc clock - _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; - this->send_reg(34); -} - -usrp_e100_codec_ctrl_impl::~usrp_e100_codec_ctrl_impl(void){ - //set aux dacs to zero - this->write_aux_dac(AUX_DAC_A, 0); - this->write_aux_dac(AUX_DAC_B, 0); - this->write_aux_dac(AUX_DAC_C, 0); - this->write_aux_dac(AUX_DAC_D, 0); - - //power down - _ad9862_regs.all_rx_pd = 1; - this->send_reg(1); - _ad9862_regs.tx_digital_pd = 1; - _ad9862_regs.tx_analog_pd = ad9862_regs_t::TX_ANALOG_PD_BOTH; - this->send_reg(8); -} - -/*********************************************************************** - * Codec Control Gain Control Methods - **********************************************************************/ -static const int mtpgw = 255; //maximum tx pga gain word - -void usrp_e100_codec_ctrl_impl::set_tx_pga_gain(double gain){ - int gain_word = int(mtpgw*(gain - tx_pga_gain_range.start())/(tx_pga_gain_range.stop() - tx_pga_gain_range.start())); - _ad9862_regs.tx_pga_gain = uhd::clip(gain_word, 0, mtpgw); - this->send_reg(16); -} - -double usrp_e100_codec_ctrl_impl::get_tx_pga_gain(void){ - return (_ad9862_regs.tx_pga_gain*(tx_pga_gain_range.stop() - tx_pga_gain_range.start())/mtpgw) + tx_pga_gain_range.start(); -} - -static const int mrpgw = 0x14; //maximum rx pga gain word - -void usrp_e100_codec_ctrl_impl::set_rx_pga_gain(double gain, char which){ - int gain_word = int(mrpgw*(gain - rx_pga_gain_range.start())/(rx_pga_gain_range.stop() - rx_pga_gain_range.start())); - gain_word = uhd::clip(gain_word, 0, mrpgw); - switch(which){ - case 'A': - _ad9862_regs.rx_pga_a = gain_word; - this->send_reg(2); - return; - case 'B': - _ad9862_regs.rx_pga_b = gain_word; - this->send_reg(3); - return; - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -double usrp_e100_codec_ctrl_impl::get_rx_pga_gain(char which){ - int gain_word; - switch(which){ - case 'A': gain_word = _ad9862_regs.rx_pga_a; break; - case 'B': gain_word = _ad9862_regs.rx_pga_b; break; - default: UHD_THROW_INVALID_CODE_PATH(); - } - return (gain_word*(rx_pga_gain_range.stop() - rx_pga_gain_range.start())/mrpgw) + rx_pga_gain_range.start(); -} - -/*********************************************************************** - * Codec Control AUX ADC Methods - **********************************************************************/ -static double aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ - return double((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; -} - -double usrp_e100_codec_ctrl_impl::read_aux_adc(aux_adc_t which){ - switch(which){ - case AUX_ADC_A1: - _ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1; - this->send_reg(34); //start conversion and select mux - this->recv_reg(28); //read the value (2 bytes, 2 reads) - this->recv_reg(29); - return aux_adc_to_volts(_ad9862_regs.aux_adc_a1_9_2, _ad9862_regs.aux_adc_a1_1_0); - - case AUX_ADC_A2: - _ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC2; - this->send_reg(34); //start conversion and select mux - this->recv_reg(26); //read the value (2 bytes, 2 reads) - this->recv_reg(27); - return aux_adc_to_volts(_ad9862_regs.aux_adc_a2_9_2, _ad9862_regs.aux_adc_a2_1_0); - - case AUX_ADC_B1: - _ad9862_regs.select_b = ad9862_regs_t::SELECT_B_AUX_ADC1; - this->send_reg(34); //start conversion and select mux - this->recv_reg(32); //read the value (2 bytes, 2 reads) - this->recv_reg(33); - return aux_adc_to_volts(_ad9862_regs.aux_adc_b1_9_2, _ad9862_regs.aux_adc_b1_1_0); - - case AUX_ADC_B2: - _ad9862_regs.select_b = ad9862_regs_t::SELECT_B_AUX_ADC2; - this->send_reg(34); //start conversion and select mux - this->recv_reg(30); //read the value (2 bytes, 2 reads) - this->recv_reg(31); - return aux_adc_to_volts(_ad9862_regs.aux_adc_b2_9_2, _ad9862_regs.aux_adc_b2_1_0); - } - UHD_THROW_INVALID_CODE_PATH(); -} - -/*********************************************************************** - * Codec Control AUX DAC Methods - **********************************************************************/ -void usrp_e100_codec_ctrl_impl::write_aux_dac(aux_dac_t which, double volts){ - //special case for aux dac d (aka sigma delta word) - if (which == AUX_DAC_D){ - boost::uint16_t dac_word = uhd::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); - _ad9862_regs.sig_delt_11_4 = boost::uint8_t(dac_word >> 4); - _ad9862_regs.sig_delt_3_0 = boost::uint8_t(dac_word & 0xf); - this->send_reg(42); - this->send_reg(43); - return; - } - - //calculate the dac word for aux dac a, b, c - boost::uint8_t dac_word = uhd::clip(boost::math::iround(volts*0xff/3.3), 0, 0xff); - - //setup a lookup table for the aux dac params (reg ref, reg addr) - typedef boost::tuple dac_params_t; - uhd::dict aux_dac_to_params = boost::assign::map_list_of - (AUX_DAC_A, dac_params_t(&_ad9862_regs.aux_dac_a, 36)) - (AUX_DAC_B, dac_params_t(&_ad9862_regs.aux_dac_b, 37)) - (AUX_DAC_C, dac_params_t(&_ad9862_regs.aux_dac_c, 38)) - ; - - //set the aux dac register - UHD_ASSERT_THROW(aux_dac_to_params.has_key(which)); - boost::uint8_t *reg_ref, reg_addr; - boost::tie(reg_ref, reg_addr) = aux_dac_to_params[which]; - *reg_ref = dac_word; - this->send_reg(reg_addr); -} - -/*********************************************************************** - * Codec Control SPI Methods - **********************************************************************/ -void usrp_e100_codec_ctrl_impl::send_reg(boost::uint8_t addr){ - boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); - UHD_LOGV(often) << "codec control write reg: " << std::hex << reg << std::endl; - _iface->write_spi( - UE_SPI_SS_AD9862, - spi_config_t::EDGE_RISE, - reg, 16 - ); -} - -void usrp_e100_codec_ctrl_impl::recv_reg(boost::uint8_t addr){ - boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); - UHD_LOGV(often) << "codec control read reg: " << std::hex << reg << std::endl; - boost::uint32_t ret = _iface->read_spi( - UE_SPI_SS_AD9862, - spi_config_t::EDGE_RISE, - reg, 16 - ); - UHD_LOGV(often) << "codec control read ret: " << std::hex << ret << std::endl; - _ad9862_regs.set_reg(addr, boost::uint16_t(ret)); -} - -/*********************************************************************** - * Codec Control Make - **********************************************************************/ -usrp_e100_codec_ctrl::sptr usrp_e100_codec_ctrl::make(usrp_e100_iface::sptr iface){ - return sptr(new usrp_e100_codec_ctrl_impl(iface)); -} diff --git a/host/lib/usrp/usrp_e100/codec_ctrl.hpp b/host/lib/usrp/usrp_e100/codec_ctrl.hpp deleted file mode 100644 index 05d7aab38..000000000 --- a/host/lib/usrp/usrp_e100/codec_ctrl.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_USRP_E100_CODEC_CTRL_HPP -#define INCLUDED_USRP_E100_CODEC_CTRL_HPP - -#include "usrp_e100_iface.hpp" -#include -#include -#include - -/*! - * The usrp-e codec control: - * - Init/power down codec. - * - Read aux adc, write aux dac. - */ -class usrp_e100_codec_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - static const uhd::gain_range_t tx_pga_gain_range; - static const uhd::gain_range_t rx_pga_gain_range; - - /*! - * Make a new codec control object. - * \param iface the usrp_e100 iface object - * \return the codec control object - */ - static sptr make(usrp_e100_iface::sptr iface); - - //! aux adc identifier constants - enum aux_adc_t{ - AUX_ADC_A2 = 0xA2, - AUX_ADC_A1 = 0xA1, - AUX_ADC_B2 = 0xB2, - AUX_ADC_B1 = 0xB1 - }; - - /*! - * Read an auxiliary adc: - * The internals remember which aux adc was read last. - * Therefore, the aux adc switch is only changed as needed. - * \param which which of the 4 adcs - * \return a value in volts - */ - virtual double read_aux_adc(aux_adc_t which) = 0; - - //! aux dac identifier constants - enum aux_dac_t{ - AUX_DAC_A = 0xA, - AUX_DAC_B = 0xB, - AUX_DAC_C = 0xC, - AUX_DAC_D = 0xD //really the sigma delta output - }; - - /*! - * Write an auxiliary dac. - * \param which which of the 4 dacs - * \param volts the level in in volts - */ - virtual void write_aux_dac(aux_dac_t which, double volts) = 0; - - //! Set the TX PGA gain - virtual void set_tx_pga_gain(double gain) = 0; - - //! Get the TX PGA gain - virtual double get_tx_pga_gain(void) = 0; - - //! Set the RX PGA gain ('A' or 'B') - virtual void set_rx_pga_gain(double gain, char which) = 0; - - //! Get the RX PGA gain ('A' or 'B') - virtual double get_rx_pga_gain(char which) = 0; -}; - -#endif /* INCLUDED_USRP_E100_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e100/codec_impl.cpp b/host/lib/usrp/usrp_e100/codec_impl.cpp deleted file mode 100644 index ae198aaa5..000000000 --- a/host/lib/usrp/usrp_e100/codec_impl.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_impl.hpp" -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Helper Methods - **********************************************************************/ -void usrp_e100_impl::codec_init(void){ - //make proxies - _rx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::rx_codec_get, this, _1, _2), - boost::bind(&usrp_e100_impl::rx_codec_set, this, _1, _2) - ); - _tx_codec_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::tx_codec_get, this, _1, _2), - boost::bind(&usrp_e100_impl::tx_codec_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Codec Properties - **********************************************************************/ -static const std::string ad9862_pga_gain_name = "ad9862 pga"; - -void usrp_e100_impl::rx_codec_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 CODEC_PROP_NAME: - val = std::string("usrp-e adc - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = usrp_e100_codec_ctrl::rx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_rx_pga_gain('B'); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp_e100_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as()){ - case CODEC_PROP_GAIN_I: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as(), 'A'); - return; - - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_rx_pga_gain(val.as(), 'B'); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Codec Properties - **********************************************************************/ -void usrp_e100_impl::tx_codec_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 CODEC_PROP_NAME: - val = std::string("usrp-e dac - ad9522"); - return; - - case CODEC_PROP_OTHERS: - val = prop_names_t(); - return; - - case CODEC_PROP_GAIN_NAMES: - val = prop_names_t(1, ad9862_pga_gain_name); - return; - - case CODEC_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = usrp_e100_codec_ctrl::tx_pga_gain_range; - return; - - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - val = _codec_ctrl->get_tx_pga_gain(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -void usrp_e100_impl::tx_codec_set(const wax::obj &key_, const wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - - //handle the set request conditioned on the key - switch(key.as()){ - case CODEC_PROP_GAIN_I: //only one gain for I and Q - case CODEC_PROP_GAIN_Q: - UHD_ASSERT_THROW(key.name == ad9862_pga_gain_name); - _codec_ctrl->set_tx_pga_gain(val.as()); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/dboard_iface.cpp b/host/lib/usrp/usrp_e100/dboard_iface.cpp deleted file mode 100644 index 61b5a1c92..000000000 --- a/host/lib/usrp/usrp_e100/dboard_iface.cpp +++ /dev/null @@ -1,300 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_iface.hpp" -#include "usrp_e100_regs.hpp" -#include "clock_ctrl.hpp" -#include "codec_ctrl.hpp" -#include -#include -#include -#include -#include //i2c and spi constants - -using namespace uhd; -using namespace uhd::usrp; -using namespace boost::assign; - -class usrp_e100_dboard_iface : public dboard_iface{ -public: - - usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec - ){ - _iface = iface; - _clock = clock; - _codec = codec; - - //init the clock rate shadows - this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); - this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate()); - - _iface->poke16(UE_REG_GPIO_RX_DBG, 0); - _iface->poke16(UE_REG_GPIO_TX_DBG, 0); - } - - ~usrp_e100_dboard_iface(void){ - /* NOP */ - } - - special_props_t get_special_props(void){ - special_props_t props; - props.soft_clock_divider = false; - props.mangle_i2c_addrs = false; - return props; - } - - void write_aux_dac(unit_t, aux_dac_t, double); - double read_aux_adc(unit_t, aux_adc_t); - - void _set_pin_ctrl(unit_t, boost::uint16_t); - void _set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); - void _set_gpio_ddr(unit_t, boost::uint16_t); - void _set_gpio_out(unit_t, boost::uint16_t); - void set_gpio_debug(unit_t, int); - boost::uint16_t read_gpio(unit_t); - - void write_i2c(boost::uint8_t, const byte_vector_t &); - byte_vector_t read_i2c(boost::uint8_t, size_t); - - void write_spi( - unit_t unit, - const spi_config_t &config, - boost::uint32_t data, - size_t num_bits - ); - - boost::uint32_t read_write_spi( - unit_t unit, - const spi_config_t &config, - boost::uint32_t data, - size_t num_bits - ); - - void set_clock_rate(unit_t, double); - 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: - usrp_e100_iface::sptr _iface; - usrp_e100_clock_ctrl::sptr _clock; - usrp_e100_codec_ctrl::sptr _codec; -}; - -/*********************************************************************** - * Make Function - **********************************************************************/ -dboard_iface::sptr make_usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec -){ - return dboard_iface::sptr(new usrp_e100_dboard_iface(iface, clock, codec)); -} - -/*********************************************************************** - * Clock Rates - **********************************************************************/ -void usrp_e100_dboard_iface::set_clock_rate(unit_t unit, double rate){ - switch(unit){ - case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); - case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate); - } -} - -std::vector usrp_e100_dboard_iface::get_clock_rates(unit_t unit){ - switch(unit){ - case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); - case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -double usrp_e100_dboard_iface::get_clock_rate(unit_t unit){ - switch(unit){ - case UNIT_RX: return _clock->get_rx_clock_rate(); - case UNIT_TX: return _clock->get_tx_clock_rate(); - } - UHD_THROW_INVALID_CODE_PATH(); -} - -void usrp_e100_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ - switch(unit){ - case UNIT_RX: return _clock->enable_rx_dboard_clock(enb); - case UNIT_TX: return _clock->enable_tx_dboard_clock(enb); - } -} - -double usrp_e100_dboard_iface::get_codec_rate(unit_t){ - return _clock->get_fpga_clock_rate(); -} - -/*********************************************************************** - * GPIO - **********************************************************************/ -void usrp_e100_dboard_iface::_set_pin_ctrl(unit_t unit, boost::uint16_t value){ - UHD_ASSERT_THROW(GPIO_SEL_ATR == 1); //make this assumption - switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_SEL, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_SEL, value); return; - } -} - -void usrp_e100_dboard_iface::_set_gpio_ddr(unit_t unit, boost::uint16_t value){ - switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_DDR, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_DDR, value); return; - } -} - -void usrp_e100_dboard_iface::_set_gpio_out(unit_t unit, boost::uint16_t value){ - switch(unit){ - case UNIT_RX: _iface->poke16(UE_REG_GPIO_RX_IO, value); return; - case UNIT_TX: _iface->poke16(UE_REG_GPIO_TX_IO, value); return; - } -} - -boost::uint16_t usrp_e100_dboard_iface::read_gpio(unit_t unit){ - switch(unit){ - case UNIT_RX: return _iface->peek16(UE_REG_GPIO_RX_IO); - case UNIT_TX: return _iface->peek16(UE_REG_GPIO_TX_IO); - default: UHD_THROW_INVALID_CODE_PATH(); - } -} - -void usrp_e100_dboard_iface::_set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){ - //define mapping of unit to atr regs to register address - static const uhd::dict< - unit_t, uhd::dict - > unit_to_atr_to_addr = map_list_of - (UNIT_RX, map_list_of - (ATR_REG_IDLE, UE_REG_ATR_IDLE_RXSIDE) - (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_RXSIDE) - (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_RXSIDE) - (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_RXSIDE) - ) - (UNIT_TX, map_list_of - (ATR_REG_IDLE, UE_REG_ATR_IDLE_TXSIDE) - (ATR_REG_TX_ONLY, UE_REG_ATR_INTX_TXSIDE) - (ATR_REG_RX_ONLY, UE_REG_ATR_INRX_TXSIDE) - (ATR_REG_FULL_DUPLEX, UE_REG_ATR_FULL_TXSIDE) - ) - ; - _iface->poke16(unit_to_atr_to_addr[unit][atr], value); -} - -void usrp_e100_dboard_iface::set_gpio_debug(unit_t unit, int which){ - //set this unit to all outputs - this->set_gpio_ddr(unit, 0xffff); - - //calculate the debug selections - boost::uint32_t dbg_sels = 0x0; - int sel = (which == 0)? GPIO_SEL_DEBUG_0 : GPIO_SEL_DEBUG_1; - for(size_t i = 0; i < 16; i++) dbg_sels |= sel << i; - - //set the debug on and which debug selection - switch(unit){ - case UNIT_RX: - _iface->poke16(UE_REG_GPIO_RX_DBG, 0xffff); - _iface->poke16(UE_REG_GPIO_RX_SEL, dbg_sels); - return; - - case UNIT_TX: - _iface->poke16(UE_REG_GPIO_TX_DBG, 0xffff); - _iface->poke16(UE_REG_GPIO_TX_SEL, dbg_sels); - return; - } -} - -/*********************************************************************** - * SPI - **********************************************************************/ -/*! - * Static function to convert a unit type to a spi slave device number. - * \param unit the dboard interface unit type enum - * \return the slave device number - */ -static boost::uint32_t unit_to_otw_spi_dev(dboard_iface::unit_t unit){ - switch(unit){ - case dboard_iface::UNIT_TX: return UE_SPI_SS_TX_DB; - case dboard_iface::UNIT_RX: return UE_SPI_SS_RX_DB; - } - UHD_THROW_INVALID_CODE_PATH(); -} - -void usrp_e100_dboard_iface::write_spi( - unit_t unit, - const spi_config_t &config, - boost::uint32_t data, - size_t num_bits -){ - _iface->write_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); -} - -boost::uint32_t usrp_e100_dboard_iface::read_write_spi( - unit_t unit, - const spi_config_t &config, - boost::uint32_t data, - size_t num_bits -){ - return _iface->read_spi(unit_to_otw_spi_dev(unit), config, data, num_bits); -} - -/*********************************************************************** - * I2C - **********************************************************************/ -void usrp_e100_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - return _iface->write_i2c(addr, bytes); -} - -byte_vector_t usrp_e100_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ - return _iface->read_i2c(addr, num_bytes); -} - -/*********************************************************************** - * Aux DAX/ADC - **********************************************************************/ -void usrp_e100_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, double value){ - //same aux dacs for each unit - static const uhd::dict which_to_aux_dac = map_list_of - (AUX_DAC_A, usrp_e100_codec_ctrl::AUX_DAC_A) - (AUX_DAC_B, usrp_e100_codec_ctrl::AUX_DAC_B) - (AUX_DAC_C, usrp_e100_codec_ctrl::AUX_DAC_C) - (AUX_DAC_D, usrp_e100_codec_ctrl::AUX_DAC_D) - ; - _codec->write_aux_dac(which_to_aux_dac[which], value); -} - -double usrp_e100_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){ - static const uhd::dict< - unit_t, uhd::dict - > unit_to_which_to_aux_adc = map_list_of - (UNIT_RX, map_list_of - (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A1) - (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B1) - ) - (UNIT_TX, map_list_of - (AUX_ADC_A, usrp_e100_codec_ctrl::AUX_ADC_A2) - (AUX_ADC_B, usrp_e100_codec_ctrl::AUX_ADC_B2) - ) - ; - return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]); -} diff --git a/host/lib/usrp/usrp_e100/dboard_impl.cpp b/host/lib/usrp/usrp_e100/dboard_impl.cpp deleted file mode 100644 index f6bbbd5e8..000000000 --- a/host/lib/usrp/usrp_e100/dboard_impl.cpp +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Dboard Initialization - **********************************************************************/ -void usrp_e100_impl::dboard_init(void){ - //read the dboard eeprom to extract the dboard ids - _rx_db_eeprom.load(*_iface, I2C_ADDR_RX_DB); - _tx_db_eeprom.load(*_iface, I2C_ADDR_TX_DB); - _gdb_eeprom.load(*_iface, I2C_ADDR_TX_DB ^ 5); - - //create a new dboard interface and manager - _dboard_iface = make_usrp_e100_dboard_iface( - _iface, _clock_ctrl, _codec_ctrl - ); - _dboard_manager = dboard_manager::make( - _rx_db_eeprom.id, - ((_gdb_eeprom.id == dboard_id_t::none())? _tx_db_eeprom : _gdb_eeprom).id, - _dboard_iface - ); - - //setup the dboard proxies - _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::rx_dboard_set, this, _1, _2) - ); - _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::tx_dboard_set, this, _1, _2) - ); -} - -/*********************************************************************** - * RX Dboard Get - **********************************************************************/ -void usrp_e100_impl::rx_dboard_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 DBOARD_PROP_NAME: - val = std::string("usrp-e dboard (rx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_rx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_rx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _rx_db_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _rx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _rx_db_eeprom.id, - _dboard_manager->get_rx_subdev(key.name), - _rx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_RX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX Dboard Set - **********************************************************************/ -void usrp_e100_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as()){ - case DBOARD_PROP_DBOARD_EEPROM: - _rx_db_eeprom = val.as(); - _rx_db_eeprom.store(*_iface, I2C_ADDR_RX_DB); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Get - **********************************************************************/ -void usrp_e100_impl::tx_dboard_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 DBOARD_PROP_NAME: - val = std::string("usrp-e dboard (tx unit)"); - return; - - case DBOARD_PROP_SUBDEV: - val = _dboard_manager->get_tx_subdev(key.name); - return; - - case DBOARD_PROP_SUBDEV_NAMES: - val = _dboard_manager->get_tx_subdev_names(); - return; - - case DBOARD_PROP_DBOARD_EEPROM: - val = _tx_db_eeprom; - return; - - case DBOARD_PROP_GBOARD_EEPROM: - val = _gdb_eeprom; - return; - - case DBOARD_PROP_DBOARD_IFACE: - val = _dboard_iface; - return; - - case DBOARD_PROP_CODEC: - val = _tx_codec_proxy->get_link(); - return; - - case DBOARD_PROP_GAIN_GROUP: - val = make_gain_group( - _tx_db_eeprom.id, - _dboard_manager->get_tx_subdev(key.name), - _tx_codec_proxy->get_link(), - GAIN_GROUP_POLICY_TX - ); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX Dboard Set - **********************************************************************/ -void usrp_e100_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ - switch(key.as()){ - case DBOARD_PROP_DBOARD_EEPROM: - _tx_db_eeprom = val.as(); - _tx_db_eeprom.store(*_iface, I2C_ADDR_TX_DB); - return; - - case DBOARD_PROP_GBOARD_EEPROM: - _gdb_eeprom = val.as(); - _gdb_eeprom.store(*_iface, I2C_ADDR_TX_DB ^ 5); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/dsp_impl.cpp b/host/lib/usrp/usrp_e100/dsp_impl.cpp deleted file mode 100644 index 57bfdc3c4..000000000 --- a/host/lib/usrp/usrp_e100/dsp_impl.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * DSP impl and methods - **********************************************************************/ -struct usrp_e100_impl::dsp_impl{ - uhd::dict ddc_decim; - uhd::dict ddc_freq; - uhd::dict duc_interp; - uhd::dict duc_freq; -}; - -/*********************************************************************** - * RX DDC Initialization - **********************************************************************/ -void usrp_e100_impl::dsp_init(void){ - //create new dsp impl - _dsp_impl = UHD_PIMPL_MAKE(dsp_impl, ()); - - //bind and initialize the rx dsps - for (size_t i = 0; i < E100_NUM_RX_DSPS; i++){ - _rx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::ddc_get, this, _1, _2, i), - boost::bind(&usrp_e100_impl::ddc_set, this, _1, _2, i) - ); - - //initial config and update - ddc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - ddc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); - - //setup the rx control registers - _iface->poke32(UE_REG_RX_CTRL_CLEAR(i), 1); //reset - _iface->poke32(UE_REG_RX_CTRL_NSAMPS_PP(i), this->get_max_recv_samps_per_packet()); - _iface->poke32(UE_REG_RX_CTRL_NCHANNELS(i), 1); - _iface->poke32(UE_REG_RX_CTRL_VRT_HDR(i), 0 - | (0x1 << 28) //if data with stream id - | (0x1 << 26) //has trailer - | (0x3 << 22) //integer time other - | (0x1 << 20) //fractional time sample count - ); - _iface->poke32(UE_REG_RX_CTRL_VRT_SID(i), E100_DSP_SID_BASE + i); - _iface->poke32(UE_REG_RX_CTRL_VRT_TLR(i), 0); - _iface->poke32(UE_REG_TIME64_TPS, size_t(_clock_ctrl->get_fpga_clock_rate())); - } - - //bind and initialize the tx dsps - for (size_t i = 0; i < E100_NUM_TX_DSPS; i++){ - _tx_dsp_proxies[str(boost::format("DSP%d")%i)] = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::duc_get, this, _1, _2, i), - boost::bind(&usrp_e100_impl::duc_set, this, _1, _2, i) - ); - - //initial config and update - duc_set(DSP_PROP_FREQ_SHIFT, double(0), i); - duc_set(DSP_PROP_HOST_RATE, double(_clock_ctrl->get_fpga_clock_rate()/16), i); - - //init the tx control registers - _iface->poke32(UE_REG_TX_CTRL_CLEAR_STATE, 1); //reset - _iface->poke32(UE_REG_TX_CTRL_NUM_CHAN, 0); //1 channel - _iface->poke32(UE_REG_TX_CTRL_REPORT_SID, E100_ASYNC_SID); - _iface->poke32(UE_REG_TX_CTRL_POLICY, UE_FLAG_TX_CTRL_POLICY_NEXT_PACKET); - } -} - -/*********************************************************************** - * RX DDC Get - **********************************************************************/ -void usrp_e100_impl::ddc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as()){ - case DSP_PROP_NAME: - val = str(boost::format("%s ddc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->ddc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->ddc_decim[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * RX DDC Set - **********************************************************************/ -void usrp_e100_impl::ddc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as()){ - - case DSP_PROP_STREAM_CMD: - issue_ddc_stream_cmd(val.as(), which_dsp); - return; - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as(); - _iface->poke32(UE_REG_DSP_RX_FREQ(which_dsp), - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _dsp_impl->ddc_freq[which_dsp] = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _dsp_impl->ddc_decim[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as()); - - //set the decimation - _iface->poke32(UE_REG_DSP_RX_DECIM(which_dsp), dsp_type1::calc_cic_filter_word(_dsp_impl->ddc_decim[which_dsp])); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Get - **********************************************************************/ -void usrp_e100_impl::duc_get(const wax::obj &key_, wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as()){ - case DSP_PROP_NAME: - val = str(boost::format("%s duc%d") % _iface->get_cname() % which_dsp); - return; - - case DSP_PROP_OTHERS: - val = prop_names_t(); //empty - return; - - case DSP_PROP_FREQ_SHIFT: - val = _dsp_impl->duc_freq[which_dsp]; - return; - - case DSP_PROP_CODEC_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - case DSP_PROP_HOST_RATE: - val = _clock_ctrl->get_fpga_clock_rate()/_dsp_impl->duc_interp[which_dsp]; - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * TX DUC Set - **********************************************************************/ -void usrp_e100_impl::duc_set(const wax::obj &key_, const wax::obj &val, size_t which_dsp){ - named_prop_t key = named_prop_t::extract(key_); - - switch(key.as()){ - - case DSP_PROP_FREQ_SHIFT:{ - double new_freq = val.as(); - _iface->poke32(UE_REG_DSP_TX_FREQ, - dsp_type1::calc_cordic_word_and_update(new_freq, _clock_ctrl->get_fpga_clock_rate()) - ); - _dsp_impl->duc_freq[which_dsp] = new_freq; //shadow - } - return; - - case DSP_PROP_HOST_RATE:{ - _dsp_impl->duc_interp[which_dsp] = boost::math::iround(_clock_ctrl->get_fpga_clock_rate()/val.as()); - - //set the interpolation - _iface->poke32(UE_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_dsp_impl->duc_interp[which_dsp])); - - //set the scaling - _iface->poke32(UE_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_dsp_impl->duc_interp[which_dsp])); - } - this->update_xport_channel_mapping(); //rate changed -> update - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/fpga_downloader.cpp b/host/lib/usrp/usrp_e100/fpga_downloader.cpp deleted file mode 100644 index b8420796f..000000000 --- a/host/lib/usrp/usrp_e100/fpga_downloader.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include -#ifdef UHD_DLL_EXPORTS -#include -#include -#else //special case when this file is externally included -#include -#include -#define UHD_MSG(type) std::cout -namespace uhd{ - typedef std::runtime_error os_error; - typedef std::runtime_error io_error; -} -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -/* - * Configuration connections - * - * CCK - MCSPI1_CLK - * DIN - MCSPI1_MOSI - * PROG_B - GPIO_175 - output (change mux) - * DONE - GPIO_173 - input (change mux) - * INIT_B - GPIO_114 - input (change mux) - * -*/ - -namespace usrp_e_fpga_downloader_utility{ - -const unsigned int PROG_B = 175; -const unsigned int DONE = 173; -const unsigned int INIT_B = 114; - -//static std::string bit_file = "safe_u1e.bin"; - -const int BUF_SIZE = 4096; - -enum gpio_direction {IN, OUT}; - -class gpio { - public: - - gpio(unsigned int gpio_num, gpio_direction pin_direction); - - bool get_value(); - void set_value(bool state); - - private: - - std::stringstream base_path; - std::fstream value_file; -}; - -class spidev { - public: - - spidev(std::string dev_name); - ~spidev(); - - void send(char *wbuf, char *rbuf, unsigned int nbytes); - - private: - - int fd; - -}; - -gpio::gpio(unsigned int gpio_num, gpio_direction pin_direction) -{ - std::fstream export_file; - - export_file.open("/sys/class/gpio/export", std::ios::out); - if (not export_file.is_open()) throw uhd::os_error( - "Failed to open gpio export file." - ); - - export_file << gpio_num << std::endl; - - base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush; - - std::fstream direction_file; - std::string direction_file_name; - - if (gpio_num != 114) { - direction_file_name = base_path.str() + "/direction"; - - direction_file.open(direction_file_name.c_str()); - if (!direction_file.is_open()) throw uhd::os_error( - "Failed to open direction file." - ); - if (pin_direction == OUT) - direction_file << "out" << std::endl; - else - direction_file << "in" << std::endl; - } - - std::string value_file_name; - - value_file_name = base_path.str() + "/value"; - - value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out); - if (!value_file.is_open()) throw uhd::os_error( - "Failed to open value file." - ); -} - -bool gpio::get_value() -{ - - std::string val; - - std::getline(value_file, val); - value_file.seekg(0); - - if (val == "0") - return false; - else if (val == "1") - return true; - else - throw uhd::os_error("Data read from value file|" + val + "|"); - - return false; -} - -void gpio::set_value(bool state) -{ - - if (state) - value_file << "1" << std::endl; - else - value_file << "0" << std::endl; -} - -static void prepare_fpga_for_configuration(gpio &prog, gpio &)//init) -{ - - prog.set_value(true); - prog.set_value(false); - prog.set_value(true); - -#if 0 - bool ready_to_program(false); - unsigned int count(0); - do { - ready_to_program = init.get_value(); - count++; - - sleep(1); - } while (count < 10 && !ready_to_program); - - if (count == 10) { - throw uhd::os_error("FPGA not ready for programming."); - } -#endif -} - -spidev::spidev(std::string fname) -{ - int ret; - int mode = 0; - int speed = 12000000; - int bits = 8; - - fd = open(fname.c_str(), O_RDWR); - - ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); - ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); - ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); -} - - -spidev::~spidev() -{ - close(fd); -} - -void spidev::send(char *buf, char *rbuf, unsigned int nbytes) -{ - int ret; - - struct spi_ioc_transfer tr; - tr.tx_buf = (unsigned long) buf; - tr.rx_buf = (unsigned long) rbuf; - tr.len = nbytes; - tr.delay_usecs = 0; - tr.speed_hz = 48000000; - tr.bits_per_word = 8; - - ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); - -} - -static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &done) -{ - std::ifstream bitstream; - - bitstream.open(file_name.c_str(), std::ios::binary); - if (!bitstream.is_open()) throw uhd::os_error( - "Coult not open the file: " + file_name - ); - - spidev spi("/dev/spidev1.0"); - char buf[BUF_SIZE]; - char rbuf[BUF_SIZE]; - - do { - bitstream.read(buf, BUF_SIZE); - spi.send(buf, rbuf, bitstream.gcount()); - - if (error.get_value()) - throw uhd::os_error("INIT_B went high, error occured."); - - if (!done.get_value()) - UHD_MSG(status) << "Configuration complete." << std::endl; - - } while (bitstream.gcount() == BUF_SIZE); -} - -}//namespace usrp_e_fpga_downloader_utility - -void usrp_e100_load_fpga(const std::string &bin_file){ - using namespace usrp_e_fpga_downloader_utility; - - gpio gpio_prog_b(PROG_B, OUT); - gpio gpio_init_b(INIT_B, IN); - gpio gpio_done (DONE, IN); - - UHD_MSG(status) << "Loading FPGA image: " << bin_file << "... " << std::flush; - -// if(std::system("/sbin/rmmod usrp_e") != 0){ -// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl; -// } - - prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); - - UHD_MSG(status) << "done = " << gpio_done.get_value() << std::endl; - - send_file_to_fpga(bin_file, gpio_init_b, gpio_done); - -// if(std::system("/sbin/modprobe usrp_e") != 0){ -// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl; -// } - -} - diff --git a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h b/host/lib/usrp/usrp_e100/include/linux/usrp_e.h deleted file mode 100644 index 4c6a5dd89..000000000 --- a/host/lib/usrp/usrp_e100/include/linux/usrp_e.h +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * Copyright (C) 2010 Ettus Research, LLC - * - * Written by Philip Balister - * - * 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 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __USRP_E_H -#define __USRP_E_H - -#include -#include - -struct usrp_e_ctl16 { - __u32 offset; - __u32 count; - __u16 buf[20]; -}; - -struct usrp_e_ctl32 { - __u32 offset; - __u32 count; - __u32 buf[10]; -}; - -/* SPI interface */ - -#define UE_SPI_TXONLY 0 -#define UE_SPI_TXRX 1 - -/* Defines for spi ctrl register */ -#define UE_SPI_CTRL_TXNEG (1<<10) -#define UE_SPI_CTRL_RXNEG (1<<9) - -#define UE_SPI_PUSH_RISE 0 -#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG -#define UE_SPI_LATCH_RISE 0 -#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG - -struct usrp_e_spi { - __u8 readback; - __u32 slave; - __u32 data; - __u32 length; - __u32 flags; -}; - -struct usrp_e_i2c { - __u8 addr; - __u32 len; - __u8 data[]; -}; - -#define USRP_E_IOC_MAGIC 'u' -#define USRP_E_WRITE_CTL16 _IOW(USRP_E_IOC_MAGIC, 0x20, struct usrp_e_ctl16) -#define USRP_E_READ_CTL16 _IOWR(USRP_E_IOC_MAGIC, 0x21, struct usrp_e_ctl16) -#define USRP_E_WRITE_CTL32 _IOW(USRP_E_IOC_MAGIC, 0x22, struct usrp_e_ctl32) -#define USRP_E_READ_CTL32 _IOWR(USRP_E_IOC_MAGIC, 0x23, struct usrp_e_ctl32) -#define USRP_E_SPI _IOWR(USRP_E_IOC_MAGIC, 0x24, struct usrp_e_spi) -#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c) -#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c) -#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) -#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) - -#define USRP_E_COMPAT_NUMBER 1 - -/* Flag defines */ -#define RB_USER (1<<0) -#define RB_KERNEL (1<<1) -#define RB_OVERRUN (1<<2) -#define RB_DMA_ACTIVE (1<<3) -#define RB_USER_PROCESS (1<<4) - -struct ring_buffer_info { - int flags; - int len; -}; - -struct usrp_e_ring_buffer_size_t { - int num_pages_rx_flags; - int num_rx_frames; - int num_pages_tx_flags; - int num_tx_frames; -}; - -#endif diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp deleted file mode 100644 index f590951dc..000000000 --- a/host/lib/usrp/usrp_e100/io_impl.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "../../transport/super_recv_packet_handler.hpp" -#include "../../transport/super_send_packet_handler.hpp" -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET; - -/*********************************************************************** - * Helpers - **********************************************************************/ -#if 1 -# define debug_print_buff(...) -#else -static void debug_print_buff(const std::string &what, managed_recv_buffer::sptr buff){ - std::ostringstream ss; - ss << boost::format( - "This is a %s packet, %u bytes.\n" - ) % what % buff->size(); - for (size_t i = 0; i < 9; i++){ - ss << boost::format(" buff[%u] = 0x%08x\n") % i % buff->cast()[i]; - } - ss << std::endl << std::endl; - UHD_MSG(status) << ss.str(); -} -#endif - -/*********************************************************************** - * io impl details (internal to this file) - * - pirate crew of 1 - * - bounded buffer - * - thread loop - * - vrt packet handler states - **********************************************************************/ -struct usrp_e100_impl::io_impl{ - io_impl(zero_copy_if::sptr &xport): - data_xport(xport), - async_msg_fifo(100/*messages deep*/) - { - for (size_t i = 0; i < E100_NUM_RX_DSPS; i++){ - typedef bounded_buffer booty_type; - recv_pirate_booty.push_back(new booty_type(data_xport->get_num_recv_frames())); - } - } - - ~io_impl(void){ - recv_pirate_crew.interrupt_all(); - recv_pirate_crew.join_all(); - for (size_t i = 0; i < recv_pirate_booty.size(); i++){ - delete recv_pirate_booty[i]; - } - } - - managed_recv_buffer::sptr get_recv_buff(const size_t index, double timeout){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - managed_recv_buffer::sptr buff; - recv_pirate_booty[index]->pop_with_timed_wait(buff, timeout); - return buff; //ASSUME buff == NULL when pop times-out - } - - //The data transport is listed first so that it is deconstructed last, - //which is after the states and booty which may hold managed buffers. - //This comment is invalid because its now a reference and not stored here. - zero_copy_if::sptr &data_xport; - - //state management for the vrt packet handler code - sph::recv_packet_handler recv_handler; - sph::send_packet_handler send_handler; - bool continuous_streaming; - - //a pirate's life is the life for me! - void recv_pirate_loop(boost::barrier &, usrp_e100_clock_ctrl::sptr); - std::vector *> recv_pirate_booty; - bounded_buffer async_msg_fifo; - boost::thread_group recv_pirate_crew; -}; - -/*********************************************************************** - * Receive Pirate Loop - * - while raiding, loot for recv buffers - * - put booty into the alignment buffer - **********************************************************************/ -void usrp_e100_impl::io_impl::recv_pirate_loop( - boost::barrier &spawn_barrier, usrp_e100_clock_ctrl::sptr clock_ctrl -){ - spawn_barrier.wait(); - set_thread_priority_safe(); - - while (not boost::this_thread::interruption_requested()){ - managed_recv_buffer::sptr buff = this->data_xport->get_recv_buff(); - if (buff.get() == NULL) continue; //ignore timeout buffers - - //handle an rx data packet or inline message - const boost::uint32_t *vrt_hdr = buff->cast(); - const size_t rx_index = uhd::wtohx(vrt_hdr[1]) - E100_DSP_SID_BASE; - if (rx_index < E100_NUM_RX_DSPS){ - debug_print_buff("data", buff); - recv_pirate_booty[rx_index]->push_with_wait(buff); - continue; - } - - //otherwise, unpack the vrt header and process below... - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); - try{vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);} - catch(const std::exception &e){ - UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl; - continue; - } - - //handle a tx async report message - if (if_packet_info.sid == E100_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - debug_print_buff("async", buff); - - //fill in the async metadata - async_metadata_t metadata; - metadata.channel = 0; - metadata.has_time_spec = if_packet_info.has_tsi and if_packet_info.has_tsf; - metadata.time_spec = time_spec_t( - time_t(if_packet_info.tsi), long(if_packet_info.tsf), clock_ctrl->get_fpga_clock_rate() - ); - metadata.event_code = async_metadata_t::event_code_t(sph::get_context_code(vrt_hdr, if_packet_info)); - - //print the famous U, and push the metadata into the message queue - if (metadata.event_code & underflow_flags) UHD_MSG(fastpath) << "U"; - async_msg_fifo.push_with_pop_on_full(metadata); - continue; - } - - debug_print_buff("unknown", buff); - } -} - -/*********************************************************************** - * Helper Functions - **********************************************************************/ -void usrp_e100_impl::io_init(void){ - - //setup before the registers (transport called to calculate max spp) - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_xport)); - - //clear state machines - _iface->poke32(UE_REG_CLEAR_RX, 0); - _iface->poke32(UE_REG_CLEAR_TX, 0); - - //spawn a pirate, yarrr! - boost::barrier spawn_barrier(2); - _io_impl->recv_pirate_crew.create_thread(boost::bind( - &usrp_e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), - boost::ref(spawn_barrier), _clock_ctrl - )); - spawn_barrier.wait(); - //update mapping here since it didnt b4 when io init not called first - update_xport_channel_mapping(); -} - -void usrp_e100_impl::update_xport_channel_mapping(void){ - if (_io_impl.get() == NULL) return; //not inited yet - - //set all of the relevant properties on the handler - boost::mutex::scoped_lock recv_lock = _io_impl->recv_handler.get_scoped_lock(); - _io_impl->recv_handler.resize(_rx_subdev_spec.size()); - _io_impl->recv_handler.set_vrt_unpacker(&vrt::if_hdr_unpack_le); - _io_impl->recv_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - //FIXME assumes homogeneous rates across all dsp - _io_impl->recv_handler.set_samp_rate(_rx_dsp_proxies[_rx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as()); - for (size_t chan = 0; chan < _io_impl->recv_handler.size(); chan++){ - _io_impl->recv_handler.set_xport_chan_get_buff(chan, boost::bind( - &usrp_e100_impl::io_impl::get_recv_buff, _io_impl.get(), chan, _1 - )); - _io_impl->recv_handler.set_overflow_handler(chan, boost::bind( - &usrp_e100_impl::handle_overrun, this, chan - )); - } - _io_impl->recv_handler.set_converter(_recv_otw_type); - - //set all of the relevant properties on the handler - boost::mutex::scoped_lock send_lock = _io_impl->send_handler.get_scoped_lock(); - _io_impl->send_handler.resize(_tx_subdev_spec.size()); - _io_impl->send_handler.set_vrt_packer(&vrt::if_hdr_pack_le); - _io_impl->send_handler.set_tick_rate(_clock_ctrl->get_fpga_clock_rate()); - //FIXME assumes homogeneous rates across all dsp - _io_impl->send_handler.set_samp_rate(_tx_dsp_proxies[_tx_dsp_proxies.keys().at(0)]->get_link()[DSP_PROP_HOST_RATE].as()); - for (size_t chan = 0; chan < _io_impl->send_handler.size(); chan++){ - _io_impl->send_handler.set_xport_chan_get_buff(chan, boost::bind( - &uhd::transport::zero_copy_if::get_send_buff, _io_impl->data_xport, _1 - )); - } - _io_impl->send_handler.set_converter(_send_otw_type); - _io_impl->send_handler.set_max_samples_per_packet(get_max_send_samps_per_packet()); -} - -void usrp_e100_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd, const size_t index){ - _io_impl->continuous_streaming = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - _iface->poke32(UE_REG_RX_CTRL_STREAM_CMD(index), dsp_type1::calc_stream_cmd_word(stream_cmd)); - _iface->poke32(UE_REG_RX_CTRL_TIME_SECS(index), boost::uint32_t(stream_cmd.time_spec.get_full_secs())); - _iface->poke32(UE_REG_RX_CTRL_TIME_TICKS(index), stream_cmd.time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); -} - -void usrp_e100_impl::handle_overrun(const size_t index){ - if (_io_impl->continuous_streaming){ - this->issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS, index); - } -} - -/*********************************************************************** - * Data Send - **********************************************************************/ -size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{ - static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - ; - size_t bpp = _send_frame_size - hdr_size; - return bpp/_send_otw_type.get_sample_size(); -} - -size_t usrp_e100_impl::send( - const send_buffs_type &buffs, size_t nsamps_per_buff, - const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode, double timeout -){ - return _io_impl->send_handler.send( - buffs, nsamps_per_buff, - metadata, io_type, - send_mode, timeout - ); -} - -/*********************************************************************** - * Data Recv - **********************************************************************/ -size_t usrp_e100_impl::get_max_recv_samps_per_packet(void) const{ - static const size_t hdr_size = 0 - + vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer - - sizeof(vrt::if_packet_info_t().cid) //no class id ever used - ; - size_t bpp = _recv_frame_size - hdr_size; - return bpp/_recv_otw_type.get_sample_size(); -} - -size_t usrp_e100_impl::recv( - const recv_buffs_type &buffs, size_t nsamps_per_buff, - rx_metadata_t &metadata, const io_type_t &io_type, - recv_mode_t recv_mode, double timeout -){ - return _io_impl->recv_handler.recv( - buffs, nsamps_per_buff, - metadata, io_type, - recv_mode, timeout - ); -} - -/*********************************************************************** - * Async Recv - **********************************************************************/ -bool usrp_e100_impl::recv_async_msg( - async_metadata_t &async_metadata, double timeout -){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); -} diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp deleted file mode 100644 index 549c9bf4f..000000000 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Mboard Initialization - **********************************************************************/ -void usrp_e100_impl::mboard_init(void){ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp_e100_impl::mboard_get, this, _1, _2), - boost::bind(&usrp_e100_impl::mboard_set, this, _1, _2) - ); - - //init the clock config - _clock_config = clock_config_t::internal(); - update_clock_config(); -} - -void usrp_e100_impl::update_clock_config(void){ - boost::uint32_t pps_flags = 0; - - //translate pps polarity enums - switch(_clock_config.pps_polarity){ - case clock_config_t::PPS_POS: pps_flags |= UE_FLAG_TIME64_PPS_POSEDGE; break; - case clock_config_t::PPS_NEG: pps_flags |= UE_FLAG_TIME64_PPS_NEGEDGE; break; - default: throw uhd::value_error("unhandled clock configuration pps polarity"); - } - - //set the pps flags - _iface->poke32(UE_REG_TIME64_FLAGS, pps_flags); - - //clock source ref 10mhz - switch(_clock_config.ref_source){ - case clock_config_t::REF_AUTO: _clock_ctrl->use_auto_ref(); break; - case clock_config_t::REF_INT: _clock_ctrl->use_internal_ref(); break; - case clock_config_t::REF_SMA: _clock_ctrl->use_auto_ref(); break; - default: throw uhd::value_error("unhandled clock configuration ref source"); - } -} - -/*********************************************************************** - * Mboard Get - **********************************************************************/ -void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){ - named_prop_t key = named_prop_t::extract(key_); - static const std::string dboard_name = "A"; - - //handle the get request conditioned on the key - switch(key.as()){ - case MBOARD_PROP_NAME: - val = std::string(_iface->get_cname() + " mboard"); - return; - - case MBOARD_PROP_OTHERS: - val = prop_names_t(); - return; - - case MBOARD_PROP_RX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _rx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_RX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_TX_DBOARD: - UHD_ASSERT_THROW(key.name == dboard_name); - val = _tx_dboard_proxy->get_link(); - return; - - case MBOARD_PROP_TX_DBOARD_NAMES: - val = prop_names_t(1, dboard_name); - return; - - case MBOARD_PROP_RX_DSP: - val = _rx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_RX_DSP_NAMES: - val = _rx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_TX_DSP: - val = _tx_dsp_proxies[key.name]->get_link(); - return; - - case MBOARD_PROP_TX_DSP_NAMES: - val = _tx_dsp_proxies.keys(); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - val = _clock_config; - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC: - val = _rx_subdev_spec; - return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - val = _tx_subdev_spec; - return; - - case MBOARD_PROP_EEPROM_MAP: - val = _iface->mb_eeprom; - return; - - case MBOARD_PROP_TIME_NOW: while(true){ - uint32_t secs = _iface->peek32(UE_REG_RB_TIME_NOW_SECS); - uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_NOW_TICKS); - if (secs != _iface->peek32(UE_REG_RB_TIME_NOW_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_TIME_PPS: while(true){ - uint32_t secs = _iface->peek32(UE_REG_RB_TIME_PPS_SECS); - uint32_t ticks = _iface->peek32(UE_REG_RB_TIME_PPS_TICKS); - if (secs != _iface->peek32(UE_REG_RB_TIME_PPS_SECS)) continue; - val = time_spec_t(secs, ticks, _clock_ctrl->get_fpga_clock_rate()); - return; - } - - case MBOARD_PROP_CLOCK_RATE: - val = _clock_ctrl->get_fpga_clock_rate(); - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Mboard Set - **********************************************************************/ -void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){ - //handle the get request conditioned on the key - switch(key.as()){ - - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_PPS:{ - time_spec_t time_spec = val.as(); - _iface->poke32(UE_REG_TIME64_TICKS, time_spec.get_tick_count(_clock_ctrl->get_fpga_clock_rate())); - boost::uint32_t imm_flags = (key.as() == MBOARD_PROP_TIME_NOW)? 1 : 0; - _iface->poke32(UE_REG_TIME64_IMM, imm_flags); - _iface->poke32(UE_REG_TIME64_SECS, time_spec.get_full_secs()); - } - return; - - case MBOARD_PROP_RX_SUBDEV_SPEC:{ - _rx_subdev_spec = val.as(); - verify_rx_subdev_spec(_rx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_rx_subdev_spec.size() <= E100_NUM_RX_DSPS); - - //determine frontend swap IQ from the first channel - bool fe_swap_iq = false; - switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(0).sd_name)[SUBDEV_PROP_CONNECTION].as()){ - case SUBDEV_CONN_COMPLEX_QI: - case SUBDEV_CONN_REAL_Q: - fe_swap_iq = true; - break; - default: fe_swap_iq = false; - } - _iface->poke32(UE_REG_RX_FE_SWAP_IQ, fe_swap_iq? 1 : 0); - - //set the dsp mux for each channel - for (size_t i = 0; i < _rx_subdev_spec.size(); i++){ - bool iq_swap = false, real_mode = false; - switch(_dboard_manager->get_rx_subdev(_rx_subdev_spec.at(i).sd_name)[SUBDEV_PROP_CONNECTION].as()){ - case SUBDEV_CONN_COMPLEX_IQ: - iq_swap = fe_swap_iq; - real_mode = false; - break; - case SUBDEV_CONN_COMPLEX_QI: - iq_swap = not fe_swap_iq; - real_mode = false; - break; - case SUBDEV_CONN_REAL_I: - iq_swap = fe_swap_iq; - real_mode = true; - break; - case SUBDEV_CONN_REAL_Q: - iq_swap = not fe_swap_iq; - real_mode = true; - break; - } - _iface->poke32(UE_REG_DSP_RX_MUX(i), - (iq_swap? UE_FLAG_DSP_RX_MUX_SWAP_IQ : 0) | - (real_mode? UE_FLAG_DSP_RX_MUX_REAL_MODE : 0) - ); - } - this->update_xport_channel_mapping(); - }return; - - case MBOARD_PROP_TX_SUBDEV_SPEC: - _tx_subdev_spec = val.as(); - verify_tx_subdev_spec(_tx_subdev_spec, _mboard_proxy->get_link()); - //sanity check - UHD_ASSERT_THROW(_tx_subdev_spec.size() <= E100_NUM_TX_DSPS); - //set the mux - _iface->poke32(UE_REG_TX_FE_MUX, dsp_type1::calc_tx_mux_word( - _dboard_manager->get_tx_subdev(_tx_subdev_spec.front().sd_name)[SUBDEV_PROP_CONNECTION].as() - )); - return; - - case MBOARD_PROP_EEPROM_MAP: - // Step1: commit the map, writing only those values set. - // Step2: readback the entire eeprom map into the iface. - val.as().commit(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); - _iface->mb_eeprom = mboard_eeprom_t(_iface->get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); - return; - - case MBOARD_PROP_CLOCK_CONFIG: - _clock_config = val.as(); - update_clock_config(); - return; - - case MBOARD_PROP_CLOCK_RATE: - UHD_MSG(warning) - << "I see that you are setting the master clock rate from the API.\n" - << "You may pass this into the device address as master_clock_rate=.\n" - << "This way, the clock rate is guaranteed to be initialized first.\n" - << "See the application notes for USRP-E1XX for further instructions.\n" - ; - _clock_ctrl->set_fpga_clock_rate(val.as()); - this->update_xport_channel_mapping(); - return; - - default: UHD_THROW_PROP_SET_ERROR(); - } -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp deleted file mode 100644 index 93c8cc7b5..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp +++ /dev/null @@ -1,393 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_iface.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include //ioctl -#include //open, close -#include //ioctl structures and constants -#include //sleep -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * I2C device node implementation wrapper - **********************************************************************/ -class i2c_dev_iface : public i2c_iface{ -public: - i2c_dev_iface(const std::string &node){ - if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ - throw uhd::io_error("Failed to open " + node); - } - } - - ~i2c_dev_iface(void){ - ::close(_node_fd); - } - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - byte_vector_t rw_bytes(bytes); - - //setup the message - i2c_msg msg; - msg.addr = addr; - msg.flags = 0; - msg.len = bytes.size(); - msg.buf = &rw_bytes.front(); - - //setup the data - i2c_rdwr_ioctl_data data; - data.msgs = &msg; - data.nmsgs = 1; - - //call the ioctl - UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0); - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ - byte_vector_t bytes(num_bytes); - - //setup the message - i2c_msg msg; - msg.addr = addr; - msg.flags = I2C_M_RD; - msg.len = bytes.size(); - msg.buf = &bytes.front(); - - //setup the data - i2c_rdwr_ioctl_data data; - data.msgs = &msg; - data.nmsgs = 1; - - //call the ioctl - UHD_ASSERT_THROW(::ioctl(_node_fd, I2C_RDWR, &data) >= 0); - - return bytes; - } - -private: int _node_fd; -}; - -/*********************************************************************** - * USRP-E100 interface implementation - **********************************************************************/ -class usrp_e100_iface_impl : public usrp_e100_iface{ -public: - - int get_file_descriptor(void){ - return _node_fd; - } - - void open(const std::string &node){ - UHD_MSG(status) << "Opening device node " << node << "..." << std::endl; - - //open the device node and check file descriptor - if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ - throw uhd::io_error("Failed to open " + node); - } - - //check the module compatibility number - int module_compat_num = ::ioctl(_node_fd, USRP_E_GET_COMPAT_NUMBER, NULL); - if (module_compat_num != USRP_E_COMPAT_NUMBER){ - throw uhd::runtime_error(str(boost::format( - "Expected module compatibility number 0x%x, but got 0x%x:\n" - "The module build is not compatible with the host code build." - ) % USRP_E_COMPAT_NUMBER % module_compat_num)); - } - } - - void close(void){ - ::close(_node_fd); - _node_fd = -1; - } - - /******************************************************************* - * Structors - ******************************************************************/ - usrp_e100_iface_impl(void): - _node_fd(-1), - _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3")) - { - mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100); - } - - ~usrp_e100_iface_impl(void){ - if (_node_fd >= 0) this->close(); - } - - /******************************************************************* - * IOCTL: provides the communication base for all other calls - ******************************************************************/ - void ioctl(int request, void *mem){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - if (::ioctl(_node_fd, request, mem) < 0){ - throw uhd::os_error(str( - boost::format("ioctl failed with request %d") % request - )); - } - } - - /******************************************************************* - * I2C device node interface - ******************************************************************/ - i2c_iface &get_i2c_dev_iface(void){ - return _i2c_dev_iface; - } - - /******************************************************************* - * Peek and Poke - ******************************************************************/ - void poke32(boost::uint32_t addr, boost::uint32_t value){ - //load the data struct - usrp_e_ctl32 data; - data.offset = addr; - data.count = 1; - data.buf[0] = value; - - //call the ioctl - this->ioctl(USRP_E_WRITE_CTL32, &data); - } - - void poke16(boost::uint32_t addr, boost::uint16_t value){ - //load the data struct - usrp_e_ctl16 data; - data.offset = addr; - data.count = 1; - data.buf[0] = value; - - //call the ioctl - this->ioctl(USRP_E_WRITE_CTL16, &data); - } - - boost::uint32_t peek32(boost::uint32_t addr){ - //load the data struct - usrp_e_ctl32 data; - data.offset = addr; - data.count = 1; - - //call the ioctl - this->ioctl(USRP_E_READ_CTL32, &data); - - return data.buf[0]; - } - - boost::uint16_t peek16(boost::uint32_t addr){ - //load the data struct - usrp_e_ctl16 data; - data.offset = addr; - data.count = 1; - - //call the ioctl - this->ioctl(USRP_E_READ_CTL16, &data); - - return data.buf[0]; - } - - /******************************************************************* - * I2C - ******************************************************************/ - static const size_t max_i2c_data_bytes = 10; - - void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - - //load the data struct - usrp_e_i2c *data = reinterpret_cast(mem); - data->addr = addr; - data->len = bytes.size(); - std::copy(bytes.begin(), bytes.end(), data->data); - - //call the spi ioctl - this->ioctl(USRP_E_I2C_WRITE, data); - } - - byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - - //load the data struct - usrp_e_i2c *data = reinterpret_cast(mem); - data->addr = addr; - data->len = num_bytes; - - //call the spi ioctl - this->ioctl(USRP_E_I2C_READ, data); - - //unload the data - byte_vector_t bytes(data->len); - UHD_ASSERT_THROW(bytes.size() == num_bytes); - std::copy(data->data, data->data+bytes.size(), bytes.begin()); - return bytes; - } - - /******************************************************************* - * SPI - ******************************************************************/ - boost::uint32_t transact_spi( - int which_slave, - const spi_config_t &config, - boost::uint32_t bits, - size_t num_bits, - bool readback - ){ - if (which_slave == UE_SPI_SS_AD9522) return bitbang_spi( - bits, num_bits, readback - ); - - //load data struct - usrp_e_spi data; - data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY; - data.slave = which_slave; - data.length = num_bits; - data.data = bits; - - //load the flags - data.flags = 0; - data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; - data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL : UE_SPI_PUSH_RISE; - - //call the spi ioctl - this->ioctl(USRP_E_SPI, &data); - - //unload the data - return data.data; - } - - boost::uint32_t bitbang_spi( - boost::uint32_t bits, - size_t num_bits, - bool readback - ){ - boost::uint32_t rb_bits = 0; - - _spi_bitbanger.spi_sen_gpio_write(0); - - for (size_t i = 0; i < num_bits; i++){ - _spi_bitbanger.spi_sclk_gpio_write(0); - _spi_bitbanger.spi_mosi_gpio_write((bits >> (num_bits-i-1)) & 0x1); - boost::this_thread::sleep(boost::posix_time::microseconds(10)); - if (readback) rb_bits = (rb_bits << 1) | _spi_bitbanger.spi_miso_gpio_read(); - _spi_bitbanger.spi_sclk_gpio_write(1); - boost::this_thread::sleep(boost::posix_time::microseconds(10)); - } - - _spi_bitbanger.spi_sen_gpio_write(1); - boost::this_thread::sleep(boost::posix_time::microseconds(100)); - - return rb_bits; - } - - class bitbang_spi_guts{ - public: - bitbang_spi_guts(void){ - //setup gpio pin directions - this->set_gpio_direction(spi_sclk_gpio, "out"); - this->set_gpio_direction(spi_sen_gpio, "out"); - this->set_gpio_direction(spi_mosi_gpio, "out"); - this->set_gpio_direction(spi_miso_gpio, "in"); - - //open the gpio pin values - _spi_sclk_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sclk_gpio).c_str()); - _spi_sen_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sen_gpio).c_str()); - _spi_mosi_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_mosi_gpio).c_str()); - _spi_miso_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_miso_gpio).c_str()); - } - - ~bitbang_spi_guts(void){ - this->set_gpio_direction(spi_sclk_gpio, "in"); - this->set_gpio_direction(spi_sen_gpio, "in"); - this->set_gpio_direction(spi_mosi_gpio, "in"); - } - - void spi_sclk_gpio_write(int val){ - _spi_sclk_gpio_value << val << std::endl << std::flush; - } - - void spi_sen_gpio_write(int val){ - _spi_sen_gpio_value << val << std::endl << std::flush; - } - - void spi_mosi_gpio_write(int val){ - _spi_mosi_gpio_value << val << std::endl << std::flush; - } - - int spi_miso_gpio_read(void){ - std::string val; - std::getline(_spi_miso_gpio_value, val); - _spi_miso_gpio_value.seekg(0); - return int(val.at(0) - '0') & 0x1; - } - - private: - enum{ - spi_sclk_gpio = 65, - spi_sen_gpio = 186, - spi_mosi_gpio = 145, - spi_miso_gpio = 147, - }; - - void set_gpio_direction(int gpio_num, const std::string &dir){ - std::ofstream export_file("/sys/class/gpio/export"); - export_file << gpio_num << std::endl << std::flush; - export_file.close(); - - std::ofstream dir_file(str(boost::format("/sys/class/gpio/gpio%d/direction") % gpio_num).c_str()); - dir_file << dir << std::endl << std::flush; - dir_file.close(); - } - - std::ofstream _spi_sclk_gpio_value, _spi_sen_gpio_value, _spi_mosi_gpio_value; - std::ifstream _spi_miso_gpio_value; - }; - - /******************************************************************* - * UART - ******************************************************************/ - void write_uart(boost::uint8_t, const std::string &) { - throw uhd::not_implemented_error("Unhandled command write_uart()"); - } - - std::string read_uart(boost::uint8_t) { - throw uhd::not_implemented_error("Unhandled command read_uart()"); - } - -private: - int _node_fd; - i2c_dev_iface _i2c_dev_iface; - boost::mutex _ctrl_mutex; - bitbang_spi_guts _spi_bitbanger; -}; - -/*********************************************************************** - * Public Make Function - **********************************************************************/ -usrp_e100_iface::sptr usrp_e100_iface::make(void){ - return sptr(new usrp_e100_iface_impl()); -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp deleted file mode 100644 index c7fa13393..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp +++ /dev/null @@ -1,90 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_USRP_E100_IFACE_HPP -#define INCLUDED_USRP_E100_IFACE_HPP - -#include -#include -#include -#include -#include -#include -#include - -//////////////////////////////////////////////////////////////////////// -// I2C addresses -//////////////////////////////////////////////////////////////////////// -#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx -#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) -#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) -#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) -//////////////////////////////////////////////////////////////////////// - -/*! - * The usrp-e interface class: - * Provides a set of functions to implementation layer. - * Including spi, peek, poke, control... - */ -class usrp_e100_iface : boost::noncopyable, public uhd::usrp::mboard_iface{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a new usrp-e interface with the control transport. - * \return a new usrp-e interface object - */ - static sptr make(void); - - //! TODO implement this for multiple hardwares revs in the future - std::string get_cname(void){ - return "USRP-E100"; - } - - /*! - * Get the underlying file descriptor. - * \return the file descriptor - */ - virtual int get_file_descriptor(void) = 0; - - /*! - * Open a device node into this iface. - * \param node the device node name - */ - virtual void open(const std::string &node) = 0; - - /*! - * Close the open device node in this iface. - */ - virtual void close(void) = 0; - - /*! - * Perform an ioctl call on the device node file descriptor. - * This will throw when the internal ioctl call fails. - * \param request the control word - * \param mem pointer to some memory - */ - virtual void ioctl(int request, void *mem) = 0; - - //! Get the I2C interface for the I2C device node - virtual uhd::i2c_iface &get_i2c_dev_iface(void) = 0; - - //motherboard eeprom map structure - uhd::usrp::mboard_eeprom_t mb_eeprom; -}; - -#endif /* INCLUDED_USRP_E100_IFACE_HPP */ diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp deleted file mode 100644 index c55d80a34..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_impl.hpp" -#include "usrp_e100_regs.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace uhd; -using namespace uhd::usrp; -namespace fs = boost::filesystem; - -/*********************************************************************** - * Discovery - **********************************************************************/ -static device_addrs_t usrp_e100_find(const device_addr_t &hint){ - device_addrs_t usrp_e100_addrs; - - //return an empty list of addresses when type is set to non-usrp-e - if (hint.has_key("type") and hint["type"] != "e100") return usrp_e100_addrs; - - //device node not provided, assume its 0 - if (not hint.has_key("node")){ - device_addr_t new_addr = hint; - new_addr["node"] = "/dev/usrp_e0"; - return usrp_e100_find(new_addr); - } - - //use the given device node name - if (fs::exists(hint["node"])){ - device_addr_t new_addr; - new_addr["type"] = "e100"; - new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); - try{ - usrp_e100_iface::sptr iface = usrp_e100_iface::make(); - new_addr["name"] = iface->mb_eeprom["name"]; - new_addr["serial"] = iface->mb_eeprom["serial"]; - } - catch(const std::exception &e){ - new_addr["name"] = ""; - new_addr["serial"] = ""; - } - if ( - (not hint.has_key("name") or hint["name"] == new_addr["name"]) and - (not hint.has_key("serial") or hint["serial"] == new_addr["serial"]) - ){ - usrp_e100_addrs.push_back(new_addr); - } - } - - return usrp_e100_addrs; -} - -/*********************************************************************** - * Make - **********************************************************************/ -static size_t hash_fpga_file(const std::string &file_path){ - size_t hash = 0; - std::ifstream file(file_path.c_str()); - if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); - while (file.good()) boost::hash_combine(hash, file.get()); - file.close(); - return hash; -} - -static device::sptr usrp_e100_make(const device_addr_t &device_addr){ - - //setup the main interface into fpga - const std::string node = device_addr["node"]; - usrp_e100_iface::sptr iface = usrp_e100_iface::make(); - iface->open(node); - - //setup clock control here to ensure that the FPGA has a good clock before we continue - const double master_clock_rate = device_addr.cast("master_clock_rate", E100_DEFAULT_CLOCK_RATE); - usrp_e100_clock_ctrl::sptr clock_ctrl = usrp_e100_clock_ctrl::make(iface, master_clock_rate); - - //extract the fpga path for usrp-e and compute hash - const std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", E100_FPGA_FILE_NAME)); - const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(usrp_e100_fpga_image)); - - //When the hash does not match: - // - close the device node - // - load the fpga bin file - // - re-open the device node - if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){ - iface->close(); - usrp_e100_load_fpga(usrp_e100_fpga_image); - iface->open(node); - } - - //Perform wishbone readback tests, these tests also write the hash - bool test_fail = false; - UHD_MSG(status) << "Performing wishbone readback test... " << std::flush; - for (size_t i = 0; i < 100; i++){ - iface->poke32(UE_REG_SR_MISC_TEST32, file_hash); - test_fail = iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash; - if (test_fail) break; //exit loop on any failure - } - UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; - - if (test_fail) UHD_MSG(error) << boost::format( - "The FPGA is either clocked improperly\n" - "or the FPGA build is not compatible.\n" - "Subsequent errors may follow...\n" - ); - - //check that the compatibility is correct - const boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT); - if (fpga_compat_num != E100_FPGA_COMPAT_NUM){ - throw uhd::runtime_error(str(boost::format( - "\nPlease update the FPGA image for your device.\n" - "See the application notes for USRP E-Series for instructions.\n" - "Expected FPGA compatibility number 0x%x, but got 0x%x:\n" - "The FPGA build is not compatible with the host code build." - ) % E100_FPGA_COMPAT_NUM % fpga_compat_num)); - } - - return device::sptr(new usrp_e100_impl(device_addr, iface, clock_ctrl)); -} - -UHD_STATIC_BLOCK(register_usrp_e100_device){ - device::register_device(&usrp_e100_find, &usrp_e100_make); -} - -/*********************************************************************** - * Structors - **********************************************************************/ -usrp_e100_impl::usrp_e100_impl( - const uhd::device_addr_t &device_addr, - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock_ctrl -): - _iface(iface), - _clock_ctrl(clock_ctrl), - _codec_ctrl(usrp_e100_codec_ctrl::make(_iface)), - _data_xport(usrp_e100_make_mmap_zero_copy(_iface)), - _recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast("recv_frame_size", 1e9)))), - _send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast("send_frame_size", 1e9)))) -{ - - //setup otw types - _send_otw_type.width = 16; - _send_otw_type.shift = 0; - _send_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - _recv_otw_type.width = 16; - _recv_otw_type.shift = 0; - _recv_otw_type.byteorder = otw_type_t::BO_LITTLE_ENDIAN; - - //initialize the mboard - mboard_init(); - - //initialize the dboards - dboard_init(); - - //initialize the dsps - dsp_init(); - - //init the codec properties - codec_init(); - - //set default subdev specs - this->mboard_set(MBOARD_PROP_RX_SUBDEV_SPEC, subdev_spec_t()); - this->mboard_set(MBOARD_PROP_TX_SUBDEV_SPEC, subdev_spec_t()); - - //init the io send/recv - io_init(); - -} - -usrp_e100_impl::~usrp_e100_impl(void){ - /* NOP */ -} - -/*********************************************************************** - * Device Get - **********************************************************************/ -void usrp_e100_impl::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 DEVICE_PROP_NAME: - val = std::string("usrp-e device"); - return; - - case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(key.name == ""); - val = _mboard_proxy->get_link(); - return; - - case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); //vector of size 1 with empty string - return; - - default: UHD_THROW_PROP_GET_ERROR(); - } -} - -/*********************************************************************** - * Device Set - **********************************************************************/ -void usrp_e100_impl::set(const wax::obj &, const wax::obj &){ - UHD_THROW_PROP_SET_ERROR(); -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp deleted file mode 100644 index 4aad18fab..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp +++ /dev/null @@ -1,183 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_iface.hpp" -#include "clock_ctrl.hpp" -#include "codec_ctrl.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef INCLUDED_USRP_E100_IMPL_HPP -#define INCLUDED_USRP_E100_IMPL_HPP - -uhd::transport::zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface); - -static const std::string E100_FPGA_FILE_NAME = "usrp_e100_fpga5.bin"; -static const boost::uint16_t E100_FPGA_COMPAT_NUM = 0x05; -static const double E100_DEFAULT_CLOCK_RATE = 64e6; -static const size_t E100_NUM_RX_DSPS = 2; -static const size_t E100_NUM_TX_DSPS = 1; -static const boost::uint32_t E100_DSP_SID_BASE = 2; //leave room for other dsp (increments by 1) -static const boost::uint32_t E100_ASYNC_SID = 1; - -//! load an fpga image from a bin file into the usrp-e fpga -extern void usrp_e100_load_fpga(const std::string &bin_file); - -/*! - * Make a usrp-e dboard interface. - * \param iface the usrp-e interface object - * \param clock the clock control interface - * \param codec the codec control interface - * \return a sptr to a new dboard interface - */ -uhd::usrp::dboard_iface::sptr make_usrp_e100_dboard_iface( - usrp_e100_iface::sptr iface, - usrp_e100_clock_ctrl::sptr clock, - usrp_e100_codec_ctrl::sptr codec -); - -/*! - * Simple wax obj proxy class: - * Provides a wax obj interface for a set and a get function. - * This allows us to create nested properties structures - * while maintaining flattened code within the implementation. - */ -class wax_obj_proxy : public wax::obj{ -public: - typedef boost::function get_t; - typedef boost::function set_t; - typedef boost::shared_ptr sptr; - - static sptr make(const get_t &get, const set_t &set){ - return sptr(new wax_obj_proxy(get, set)); - } - -private: - get_t _get; set_t _set; - wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; - void get(const wax::obj &key, wax::obj &val){return _get(key, val);} - void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} -}; - -/*! - * USRP-E100 implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ -class usrp_e100_impl : public uhd::device{ -public: - //structors - usrp_e100_impl( - const uhd::device_addr_t &, - usrp_e100_iface::sptr, - usrp_e100_clock_ctrl::sptr - ); - ~usrp_e100_impl(void); - - //the io interface - size_t send(const send_buffs_type &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); - size_t recv(const recv_buffs_type &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); - bool recv_async_msg(uhd::async_metadata_t &, double); - size_t get_max_send_samps_per_packet(void) const; - size_t get_max_recv_samps_per_packet(void) const; - -private: - //interface to ioctls and file descriptor - usrp_e100_iface::sptr _iface; - - //ad9522 clock control - usrp_e100_clock_ctrl::sptr _clock_ctrl; - - //ad9862 codec control - usrp_e100_codec_ctrl::sptr _codec_ctrl; - - //handle io stuff - uhd::transport::zero_copy_if::sptr _data_xport; - UHD_PIMPL_DECL(io_impl) _io_impl; - size_t _recv_frame_size, _send_frame_size; - uhd::otw_type_t _send_otw_type, _recv_otw_type; - void io_init(void); - void handle_overrun(size_t); - void update_xport_channel_mapping(void); - - //configuration shadows - uhd::clock_config_t _clock_config; - - //device functions and settings - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - - //mboard functions and settings - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - uhd::usrp::subdev_spec_t _rx_subdev_spec, _tx_subdev_spec; - - //xx dboard functions and settings - void dboard_init(void); - uhd::usrp::dboard_manager::sptr _dboard_manager; - uhd::usrp::dboard_iface::sptr _dboard_iface; - - //rx dboard functions and settings - uhd::usrp::dboard_eeprom_t _rx_db_eeprom; - void rx_dboard_get(const wax::obj &, wax::obj &); - void rx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_dboard_proxy; - - //tx dboard functions and settings - uhd::usrp::dboard_eeprom_t _tx_db_eeprom, _gdb_eeprom; - void tx_dboard_get(const wax::obj &, wax::obj &); - void tx_dboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _tx_dboard_proxy; - - //methods and shadows for the dsps - UHD_PIMPL_DECL(dsp_impl) _dsp_impl; - void dsp_init(void); - void issue_ddc_stream_cmd(const uhd::stream_cmd_t &, size_t); - - //properties interface for ddc - void ddc_get(const wax::obj &, wax::obj &, size_t); - void ddc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict _rx_dsp_proxies; - - //properties interface for duc - void duc_get(const wax::obj &, wax::obj &, size_t); - void duc_set(const wax::obj &, const wax::obj &, size_t); - uhd::dict _tx_dsp_proxies; - - //codec functions and settings - void codec_init(void); - void rx_codec_get(const wax::obj &, wax::obj &); - void rx_codec_set(const wax::obj &, const wax::obj &); - void tx_codec_get(const wax::obj &, wax::obj &); - void tx_codec_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _rx_codec_proxy, _tx_codec_proxy; - - //clock control functions and settings - void init_clock_config(void); - void update_clock_config(void); -}; - -#endif /* INCLUDED_USRP_E100_IMPL_HPP */ diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp deleted file mode 100644 index bb421507a..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// -// Copyright 2010-2011 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp_e100_iface.hpp" -#include -#include -#include -#include -#include //mmap -#include //getpagesize -#include //poll -#include - -using namespace uhd; -using namespace uhd::transport; - -#define fp_verbose false //fast-path verbose -static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout - -/*********************************************************************** - * Reusable managed receiver buffer: - * - The buffer knows how to claim and release a frame. - **********************************************************************/ -class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{ -public: - usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info): - _mem(mem), _info(info) { /* NOP */ } - - void release(void){ - if (_info->flags != RB_USER_PROCESS) return; - if (fp_verbose) UHD_LOGV(always) << "recv buff: release" << std::endl; - _info->flags = RB_KERNEL; //release the frame - } - - bool ready(void){return _info->flags & RB_USER;} - - sptr get_new(void){ - if (fp_verbose) UHD_LOGV(always) << " make_recv_buff: " << get_size() << std::endl; - _info->flags = RB_USER_PROCESS; //claim the frame - return make_managed_buffer(this); - } - -private: - const void *get_buff(void) const{return _mem;} - size_t get_size(void) const{return _info->len;} - - void *_mem; - ring_buffer_info *_info; -}; - -/*********************************************************************** - * Reusable managed send buffer: - * - The buffer knows how to claim and release a frame. - **********************************************************************/ -class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{ -public: - usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd): - _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ } - - void commit(size_t len){ - if (_info->flags != RB_USER_PROCESS) return; - if (fp_verbose) UHD_LOGV(always) << "send buff: commit " << len << std::endl; - _info->len = len; - _info->flags = RB_USER; //release the frame - if (::write(_fd, NULL, 0) < 0){ //notifies the kernel - UHD_LOGV(rarely) << UHD_THROW_SITE_INFO("write error") << std::endl; - } - } - - bool ready(void){return _info->flags & RB_KERNEL;} - - sptr get_new(void){ - if (fp_verbose) UHD_LOGV(always) << " make_send_buff: " << get_size() << std::endl; - _info->flags = RB_USER_PROCESS; //claim the frame - return make_managed_buffer(this); - } - -private: - void *get_buff(void) const{return _mem;} - size_t get_size(void) const{return _len;} - - void *_mem; - ring_buffer_info *_info; - size_t _len; - int _fd; -}; - -/*********************************************************************** - * The zero copy interface implementation - **********************************************************************/ -class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{ -public: - usrp_e100_mmap_zero_copy_impl(usrp_e100_iface::sptr iface): - _fd(iface->get_file_descriptor()), _recv_index(0), _send_index(0) - { - //get system sizes - iface->ioctl(USRP_E_GET_RB_INFO, &_rb_size); - size_t page_size = getpagesize(); - _frame_size = page_size/2; - - //calculate the memory size - _map_size = - (_rb_size.num_pages_rx_flags + _rb_size.num_pages_tx_flags) * page_size + - (_rb_size.num_rx_frames + _rb_size.num_tx_frames) * _frame_size; - - //print sizes summary - UHD_LOG - << "page_size: " << page_size << std::endl - << "frame_size: " << _frame_size << std::endl - << "num_pages_rx_flags: " << _rb_size.num_pages_rx_flags << std::endl - << "num_rx_frames: " << _rb_size.num_rx_frames << std::endl - << "num_pages_tx_flags: " << _rb_size.num_pages_tx_flags << std::endl - << "num_tx_frames: " << _rb_size.num_tx_frames << std::endl - << "map_size: " << _map_size << std::endl - ; - - //call mmap to get the memory - _mapped_mem = ::mmap( - NULL, _map_size, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0 - ); - UHD_ASSERT_THROW(_mapped_mem != MAP_FAILED); - - //calculate the memory offsets for info and buffers - size_t recv_info_off = 0; - size_t recv_buff_off = recv_info_off + (_rb_size.num_pages_rx_flags * page_size); - size_t send_info_off = recv_buff_off + (_rb_size.num_rx_frames * _frame_size); - size_t send_buff_off = send_info_off + (_rb_size.num_pages_tx_flags * page_size); - - //print offset summary - UHD_LOG - << "recv_info_off: " << recv_info_off << std::endl - << "recv_buff_off: " << recv_buff_off << std::endl - << "send_info_off: " << send_info_off << std::endl - << "send_buff_off: " << send_buff_off << std::endl - ; - - //pointers to sections in the mapped memory - ring_buffer_info (*recv_info)[], (*send_info)[]; - char *recv_buff, *send_buff; - - //set the internal pointers for info and buffers - typedef ring_buffer_info (*rbi_pta)[]; - char *rb_ptr = reinterpret_cast(_mapped_mem); - recv_info = reinterpret_cast(rb_ptr + recv_info_off); - recv_buff = rb_ptr + recv_buff_off; - send_info = reinterpret_cast(rb_ptr + send_info_off); - send_buff = rb_ptr + send_buff_off; - - //initialize the managed receive buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ - _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb( - recv_buff + get_recv_frame_size()*i, (*recv_info) + i - )); - } - - //initialize the managed send buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ - _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb( - send_buff + get_send_frame_size()*i, (*send_info) + i, - get_send_frame_size(), _fd - )); - } - } - - ~usrp_e100_mmap_zero_copy_impl(void){ - UHD_LOG << "cleanup: munmap" << std::endl; - ::munmap(_mapped_mem, _map_size); - } - - managed_recv_buffer::sptr get_recv_buff(double timeout){ - if (fp_verbose) UHD_LOGV(always) << "get_recv_buff: " << _recv_index << std::endl; - usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index]; - - //poll/wait for a ready frame - if (not mrb.ready()){ - for (size_t i = 0; i < poll_breakout; i++){ - pollfd pfd; - pfd.fd = _fd; - pfd.events = POLLIN; - ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3/poll_breakout)); - if (fp_verbose) UHD_LOGV(always) << " POLLIN: " << poll_ret << std::endl; - if (poll_ret > 0) goto found_user_frame; //good poll, continue on - } - return managed_recv_buffer::sptr(); //timed-out for real - } found_user_frame: - - //increment the index for the next call - if (++_recv_index == get_num_recv_frames()) _recv_index = 0; - - //return the managed buffer for this frame - return mrb.get_new(); - } - - size_t get_num_recv_frames(void) const{ - return _rb_size.num_rx_frames; - } - - size_t get_recv_frame_size(void) const{ - return _frame_size; - } - - managed_send_buffer::sptr get_send_buff(double timeout){ - if (fp_verbose) UHD_LOGV(always) << "get_send_buff: " << _send_index << std::endl; - usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index]; - - //poll/wait for a ready frame - if (not msb.ready()){ - pollfd pfd; - pfd.fd = _fd; - pfd.events = POLLOUT; - ssize_t poll_ret = ::poll(&pfd, 1, size_t(timeout*1e3)); - if (fp_verbose) UHD_LOGV(always) << " POLLOUT: " << poll_ret << std::endl; - if (poll_ret <= 0) return managed_send_buffer::sptr(); - } - - //increment the index for the next call - if (++_send_index == get_num_send_frames()) _send_index = 0; - - //return the managed buffer for this frame - return msb.get_new(); - } - - size_t get_num_send_frames(void) const{ - return _rb_size.num_tx_frames; - } - - size_t get_send_frame_size(void) const{ - return _frame_size; - } - -private: - //file descriptor for mmap - int _fd; - - //the mapped memory itself - void *_mapped_mem; - - //mapped memory sizes - usrp_e_ring_buffer_size_t _rb_size; - size_t _frame_size, _map_size; - - //re-usable managed buffers - std::vector _mrb_pool; - std::vector _msb_pool; - - //indexes into sub-sections of mapped memory - size_t _recv_index, _send_index; -}; - -/*********************************************************************** - * The zero copy interface make function - **********************************************************************/ -zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface){ - return zero_copy_if::sptr(new usrp_e100_mmap_zero_copy_impl(iface)); -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp deleted file mode 100644 index eace5d7df..000000000 --- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp +++ /dev/null @@ -1,242 +0,0 @@ - - -//////////////////////////////////////////////////////////////// -// -// Memory map for embedded wishbone bus -// -//////////////////////////////////////////////////////////////// - -// All addresses are byte addresses. All accesses are word (16-bit) accesses. -// This means that address bit 0 is usually 0. -// There are 11 bits of address for the control. - -#ifndef INCLUDED_USRP_E100_REGS_HPP -#define INCLUDED_USRP_E100_REGS_HPP - -///////////////////////////////////////////////////// -// Slave pointers - -#define UE_REG_SLAVE(n) ((n)<<7) - -///////////////////////////////////////////////////// -// Slave 0 -- Misc Regs - -#define UE_REG_MISC_BASE UE_REG_SLAVE(0) - -#define UE_REG_MISC_LED UE_REG_MISC_BASE + 0 -#define UE_REG_MISC_SW UE_REG_MISC_BASE + 2 -#define UE_REG_MISC_CGEN_CTRL UE_REG_MISC_BASE + 4 -#define UE_REG_MISC_CGEN_ST UE_REG_MISC_BASE + 6 -#define UE_REG_MISC_TEST UE_REG_MISC_BASE + 8 -#define UE_REG_MISC_RX_LEN UE_REG_MISC_BASE + 10 -#define UE_REG_MISC_TX_LEN UE_REG_MISC_BASE + 12 -#define UE_REG_MISC_XFER_RATE UE_REG_MISC_BASE + 14 -#define UE_REG_MISC_COMPAT UE_REG_MISC_BASE + 16 - -///////////////////////////////////////////////////// -// Slave 1 -- UART -// CLKDIV is 16 bits, others are only 8 - -#define UE_REG_UART_BASE UE_REG_SLAVE(1) - -#define UE_REG_UART_CLKDIV UE_REG_UART_BASE + 0 -#define UE_REG_UART_TXLEVEL UE_REG_UART_BASE + 2 -#define UE_REG_UART_RXLEVEL UE_REG_UART_BASE + 4 -#define UE_REG_UART_TXCHAR UE_REG_UART_BASE + 6 -#define UE_REG_UART_RXCHAR UE_REG_UART_BASE + 8 - -///////////////////////////////////////////////////// -// Slave 2 -- SPI Core -// This should be accessed through the IOCTL -// Users should not touch directly - -#define UE_REG_SPI_BASE UE_REG_SLAVE(2) - -//spi slave constants -#define UE_SPI_SS_AD9522 (1 << 3) -#define UE_SPI_SS_AD9862 (1 << 2) -#define UE_SPI_SS_TX_DB (1 << 1) -#define UE_SPI_SS_RX_DB (1 << 0) - -//////////////////////////////////////////////// -// Slave 3 -- I2C Core -// This should be accessed through the IOCTL -// Users should not touch directly - -#define UE_REG_I2C_BASE UE_REG_SLAVE(3) - - -//////////////////////////////////////////////// -// Slave 4 -- GPIO - -#define UE_REG_GPIO_BASE UE_REG_SLAVE(4) - -#define UE_REG_GPIO_RX_IO UE_REG_GPIO_BASE + 0 -#define UE_REG_GPIO_TX_IO UE_REG_GPIO_BASE + 2 -#define UE_REG_GPIO_RX_DDR UE_REG_GPIO_BASE + 4 -#define UE_REG_GPIO_TX_DDR UE_REG_GPIO_BASE + 6 -#define UE_REG_GPIO_RX_SEL UE_REG_GPIO_BASE + 8 -#define UE_REG_GPIO_TX_SEL UE_REG_GPIO_BASE + 10 -#define UE_REG_GPIO_RX_DBG UE_REG_GPIO_BASE + 12 -#define UE_REG_GPIO_TX_DBG UE_REG_GPIO_BASE + 14 - -//possible bit values for sel when dbg is 0: -#define GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg -#define GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic - -//possible bit values for sel when dbg is 1: -#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric -#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric - -/////////////////////////////////////////////////// -// Slave 6 -- ATR Controller -// 16 regs - -#define UE_REG_ATR_BASE UE_REG_SLAVE(6) - -#define UE_REG_ATR_IDLE_RXSIDE UE_REG_ATR_BASE + 0 -#define UE_REG_ATR_IDLE_TXSIDE UE_REG_ATR_BASE + 2 -#define UE_REG_ATR_INTX_RXSIDE UE_REG_ATR_BASE + 4 -#define UE_REG_ATR_INTX_TXSIDE UE_REG_ATR_BASE + 6 -#define UE_REG_ATR_INRX_RXSIDE UE_REG_ATR_BASE + 8 -#define UE_REG_ATR_INRX_TXSIDE UE_REG_ATR_BASE + 10 -#define UE_REG_ATR_FULL_RXSIDE UE_REG_ATR_BASE + 12 -#define UE_REG_ATR_FULL_TXSIDE UE_REG_ATR_BASE + 14 - -/////////////////////////////////////////////////// -// Slave 7 -- Readback Mux 32 - -#define UE_REG_RB_MUX_32_BASE UE_REG_SLAVE(7) - -#define UE_REG_RB_TIME_NOW_SECS UE_REG_RB_MUX_32_BASE + 0 -#define UE_REG_RB_TIME_NOW_TICKS UE_REG_RB_MUX_32_BASE + 4 -#define UE_REG_RB_TIME_PPS_SECS UE_REG_RB_MUX_32_BASE + 8 -#define UE_REG_RB_TIME_PPS_TICKS UE_REG_RB_MUX_32_BASE + 12 -#define UE_REG_RB_MISC_TEST32 UE_REG_RB_MUX_32_BASE + 16 - -//////////////////////////////////////////////////// -// Slave 8 -- Settings Bus -// -// Output-only, no readback, 64 registers total -// Each register must be written 64 bits at a time -// First the address xxx_xx00 and then xxx_xx10 - -// 64 total regs in address space -#define UE_SR_RX_CTRL0 0 // 9 regs (+0 to +8) -#define UE_SR_RX_DSP0 10 // 4 regs (+0 to +3) -#define UE_SR_RX_CTRL1 16 // 9 regs (+0 to +8) -#define UE_SR_RX_DSP1 26 // 4 regs (+0 to +3) -#define UE_SR_TX_CTRL 32 // 4 regs (+0 to +3) -#define UE_SR_TX_DSP 38 // 3 regs (+0 to +2) - -#define UE_SR_TIME64 42 // 6 regs (+0 to +5) -#define UE_SR_RX_FRONT 48 // 5 regs (+0 to +4) -#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4) - -#define UE_SR_REG_TEST32 60 // 1 reg -#define UE_SR_CLEAR_RX_FIFO 61 // 1 reg -#define UE_SR_CLEAR_TX_FIFO 62 // 1 reg -#define UE_SR_GLOBAL_RESET 63 // 1 reg - -#define UE_REG_SR_ADDR(n) (UE_REG_SLAVE(8) + (4*(n))) - -#define UE_REG_SR_MISC_TEST32 UE_REG_SR_ADDR(UE_SR_REG_TEST32) - -///////////////////////////////////////////////// -// Magic reset regs -//////////////////////////////////////////////// -#define UE_REG_CLEAR_RX UE_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) -#define UE_REG_CLEAR_TX UE_REG_SR_ADDR(UE_SR_CLEAR_RX_FIFO) -#define UE_REG_GLOBAL_RESET UE_REG_SR_ADDR(UE_SR_GLOBAL_RESET) - -///////////////////////////////////////////////// -// DSP RX Regs -//////////////////////////////////////////////// -#define UE_REG_DSP_RX_HELPER(which, offset) ((which == 0)? \ - (UE_REG_SR_ADDR(UE_SR_RX_DSP0 + offset)) : \ - (UE_REG_SR_ADDR(UE_SR_RX_DSP1 + offset))) - -#define UE_REG_DSP_RX_FREQ(which) UE_REG_DSP_RX_HELPER(which, 0) -#define UE_REG_DSP_RX_DECIM(which) UE_REG_DSP_RX_HELPER(which, 2) -#define UE_REG_DSP_RX_MUX(which) UE_REG_DSP_RX_HELPER(which, 3) - -#define UE_FLAG_DSP_RX_MUX_SWAP_IQ (1 << 0) -#define UE_FLAG_DSP_RX_MUX_REAL_MODE (1 << 1) - -/////////////////////////////////////////////////// -// RX CTRL regs -/////////////////////////////////////////////////// -#define UE_REG_RX_CTRL_HELPER(which, offset) ((which == 0)? \ - (UE_REG_SR_ADDR(UE_SR_RX_CTRL0 + offset)) : \ - (UE_REG_SR_ADDR(UE_SR_RX_CTRL1 + offset))) - -#define UE_REG_RX_CTRL_STREAM_CMD(which) UE_REG_RX_CTRL_HELPER(which, 0) -#define UE_REG_RX_CTRL_TIME_SECS(which) UE_REG_RX_CTRL_HELPER(which, 1) -#define UE_REG_RX_CTRL_TIME_TICKS(which) UE_REG_RX_CTRL_HELPER(which, 2) -#define UE_REG_RX_CTRL_CLEAR(which) UE_REG_RX_CTRL_HELPER(which, 3) -#define UE_REG_RX_CTRL_VRT_HDR(which) UE_REG_RX_CTRL_HELPER(which, 4) -#define UE_REG_RX_CTRL_VRT_SID(which) UE_REG_RX_CTRL_HELPER(which, 5) -#define UE_REG_RX_CTRL_VRT_TLR(which) UE_REG_RX_CTRL_HELPER(which, 6) -#define UE_REG_RX_CTRL_NSAMPS_PP(which) UE_REG_RX_CTRL_HELPER(which, 7) -#define UE_REG_RX_CTRL_NCHANNELS(which) UE_REG_RX_CTRL_HELPER(which, 8) - -///////////////////////////////////////////////// -// RX FE -//////////////////////////////////////////////// -#define UE_REG_RX_FE_SWAP_IQ UE_REG_SR_ADDR(UE_SR_RX_FRONT + 0) //lower bit -#define UE_REG_RX_FE_MAG_CORRECTION UE_REG_SR_ADDR(UE_SR_RX_FRONT + 1) //18 bits -#define UE_REG_RX_FE_PHASE_CORRECTION UE_REG_SR_ADDR(UE_SR_RX_FRONT + 2) //18 bits -#define UE_REG_RX_FE_OFFSET_I UE_REG_SR_ADDR(UE_SR_RX_FRONT + 3) //18 bits -#define UE_REG_RX_FE_OFFSET_Q UE_REG_SR_ADDR(UE_SR_RX_FRONT + 4) //18 bits - -///////////////////////////////////////////////// -// DSP TX Regs -//////////////////////////////////////////////// -#define UE_REG_DSP_TX_FREQ UE_REG_SR_ADDR(UE_SR_TX_DSP + 0) -#define UE_REG_DSP_TX_SCALE_IQ UE_REG_SR_ADDR(UE_SR_TX_DSP + 1) -#define UE_REG_DSP_TX_INTERP_RATE UE_REG_SR_ADDR(UE_SR_TX_DSP + 2) - -/////////////////////////////////////////////////// -// TX CTRL regs -/////////////////////////////////////////////////// -#define UE_REG_TX_CTRL_NUM_CHAN UE_REG_SR_ADDR(UE_SR_TX_CTRL + 0) -#define UE_REG_TX_CTRL_CLEAR_STATE UE_REG_SR_ADDR(UE_SR_TX_CTRL + 1) -#define UE_REG_TX_CTRL_REPORT_SID UE_REG_SR_ADDR(UE_SR_TX_CTRL + 2) -#define UE_REG_TX_CTRL_POLICY UE_REG_SR_ADDR(UE_SR_TX_CTRL + 3) -#define UE_REG_TX_CTRL_CYCLES_PER_UP UE_REG_SR_ADDR(UE_SR_TX_CTRL + 4) -#define UE_REG_TX_CTRL_PACKETS_PER_UP UE_REG_SR_ADDR(UE_SR_TX_CTRL + 5) - -#define UE_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0) -#define UE_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1) -#define UE_FLAG_TX_CTRL_POLICY_NEXT_BURST (0x1 << 2) - -///////////////////////////////////////////////// -// TX FE -//////////////////////////////////////////////// -#define UE_REG_TX_FE_DC_OFFSET_I UE_REG_SR_ADDR(UE_SR_TX_FRONT + 0) //24 bits -#define UE_REG_TX_FE_DC_OFFSET_Q UE_REG_SR_ADDR(UE_SR_TX_FRONT + 1) //24 bits -#define UE_REG_TX_FE_MAC_CORRECTION UE_REG_SR_ADDR(UE_SR_TX_FRONT + 2) //18 bits -#define UE_REG_TX_FE_PHASE_CORRECTION UE_REG_SR_ADDR(UE_SR_TX_FRONT + 3) //18 bits -#define UE_REG_TX_FE_MUX UE_REG_SR_ADDR(UE_SR_TX_FRONT + 4) //8 bits (std output = 0x10, reversed = 0x01) - -///////////////////////////////////////////////// -// VITA49 64 bit time (write only) -//////////////////////////////////////////////// -#define UE_REG_TIME64_SECS UE_REG_SR_ADDR(UE_SR_TIME64 + 0) -#define UE_REG_TIME64_TICKS UE_REG_SR_ADDR(UE_SR_TIME64 + 1) -#define UE_REG_TIME64_FLAGS UE_REG_SR_ADDR(UE_SR_TIME64 + 2) -#define UE_REG_TIME64_IMM UE_REG_SR_ADDR(UE_SR_TIME64 + 3) -#define UE_REG_TIME64_TPS UE_REG_SR_ADDR(UE_SR_TIME64 + 4) -#define UE_REG_TIME64_MIMO_SYNC UE_REG_SR_ADDR(UE_SR_TIME64 + 5) - -//pps flags (see above) -#define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0) -#define UE_FLAG_TIME64_PPS_POSEDGE (1 << 0) -#define UE_FLAG_TIME64_PPS_SMA (0 << 1) -#define UE_FLAG_TIME64_PPS_MIMO (1 << 1) - -#define UE_FLAG_TIME64_LATCH_NOW 1 -#define UE_FLAG_TIME64_LATCH_NEXT_PPS 0 - -#endif - -- cgit v1.2.3