diff options
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/ic_reg_maps/.gitignore | 1 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_ad9862_regs.py | 20 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/CMakeLists.txt | 59 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/clock_ctrl.cpp | 175 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/clock_ctrl.hpp | 73 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/codec_ctrl.cpp | 247 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/codec_ctrl.hpp | 75 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/dboard_iface.cpp | 238 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/dboard_impl.cpp | 79 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/dsp_impl.cpp | 69 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/fpga-downloader.cc | 262 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/mboard_impl.cpp | 113 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_iface.cpp | 190 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_iface.hpp | 106 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_impl.cpp | 156 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_impl.hpp | 148 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_none.cpp | 38 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/usrp_e_regs.hpp | 115 | 
19 files changed, 2155 insertions, 10 deletions
| diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 7b765b0d3..6cf896db8 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -72,6 +72,7 @@ INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/transport/CMakeLists.txt)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/CMakeLists.txt)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/dboard/CMakeLists.txt)  INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp2/CMakeLists.txt) +INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/usrp/usrp_e/CMakeLists.txt)  ########################################################################  # Setup defines for module loading diff --git a/host/lib/ic_reg_maps/.gitignore b/host/lib/ic_reg_maps/.gitignore index a74b07aee..053049d05 100644 --- a/host/lib/ic_reg_maps/.gitignore +++ b/host/lib/ic_reg_maps/.gitignore @@ -1 +1,2 @@  /*.pyc +/*.pyo diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py index fdbea5828..00340224c 100755 --- a/host/lib/ic_reg_maps/gen_ad9862_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py @@ -30,14 +30,14 @@ soft_reset         0[5]              0  ########################################################################  ## Rx Power Down  ######################################################################## -pd_vref_diff       1[7]              0 -pd_vref            1[6]              0 -pd_rx_digital      1[5]              0 -pd_rx_channel_b    1[4]              0 -pd_rx_channel_a    1[3]              0 -pd_buffer_b        1[2]              0 -pd_buffer_a        1[1]              0 -pd_all_rx          1[0]              0 +vref_diff_pd       1[7]              0 +vref_pd            1[6]              0 +rx_digital_pd      1[5]              0 +rx_channel_b_pd    1[4]              0 +rx_channel_a_pd    1[3]              0 +buffer_b_pd        1[2]              0 +buffer_a_pd        1[1]              0 +all_rx_pd          1[0]              0  ########################################################################  ## Rx A and B  ######################################################################## @@ -123,7 +123,7 @@ ftw_23_16              23[0:7]            0  ########################################################################  ## DLL  ######################################################################## -input_clk_ctrl         24[6]              0       external, internal +input_clk_ctrl         24[6]              0       internal, external  adc_div2               24[5]              0       normal, div2  dll_mult               24[3:4]            0       1, 2, 4  dll_pd                 24[2]              0 @@ -233,7 +233,7 @@ boost::uint16_t get_write_reg(boost::uint8_t addr){  }  boost::uint16_t get_read_reg(boost::uint8_t addr){ -    return (boost::uint16_t(addr) << 8) | (1 << 7); +    return (boost::uint16_t(addr) << 8) | (1 << 15);  }  """ diff --git a/host/lib/usrp/usrp_e/CMakeLists.txt b/host/lib/usrp/usrp_e/CMakeLists.txt new file mode 100644 index 000000000..c25b2cba4 --- /dev/null +++ b/host/lib/usrp/usrp_e/CMakeLists.txt @@ -0,0 +1,59 @@ +# +# Copyright 2010 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +#This file will be included by cmake, use absolute paths! + +######################################################################## +# Helpful macro to check for required headers +######################################################################## +INCLUDE(CheckIncludeFileCXX) +SET(HAVE_USRP_E_REQUIRED_HEADERS TRUE) +MACRO(USRP_E_REQUIRE_HEADER header variable) +    CHECK_INCLUDE_FILE_CXX(${header} ${variable}) +    IF(NOT ${variable}) +        SET(HAVE_USRP_E_REQUIRED_HEADERS FALSE) +    ENDIF(NOT ${variable}) +ENDMACRO(USRP_E_REQUIRE_HEADER) + +######################################################################## +# Conditionally configure the USRP-E support +######################################################################## +MESSAGE(STATUS "Configuring usrp-e support...") + +USRP_E_REQUIRE_HEADER(linux/ioctl.h      HAVE_LINUX_IOCTL_H) +USRP_E_REQUIRE_HEADER(linux/spi/spidev.h HAVE_LINUX_SPI_SPIDEV_H) +USRP_E_REQUIRE_HEADER(linux/usrp_e.h     HAVE_LINUX_USRP_E_H) + +IF(HAVE_USRP_E_REQUIRED_HEADERS) +    MESSAGE(STATUS "  Building usrp-e support.") +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/clock_ctrl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/codec_ctrl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/dboard_impl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/dboard_iface.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/dsp_impl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/fpga-downloader.cc +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/mboard_impl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_impl.cpp +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_iface.cpp +    ) +ELSE(HAVE_USRP_E_REQUIRED_HEADERS) +    MESSAGE(STATUS "  Skipping usrp-e support.") +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e/usrp_e_none.cpp +    ) +ENDIF(HAVE_USRP_E_REQUIRED_HEADERS) diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp new file mode 100644 index 000000000..5f7269412 --- /dev/null +++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp @@ -0,0 +1,175 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "clock_ctrl.hpp" +#include "ad9522_regs.hpp" +#include <boost/cstdint.hpp> +#include "usrp_e_regs.hpp" //spi slave constants +#include <boost/assign/list_of.hpp> +#include <boost/foreach.hpp> +#include <utility> +#include <iostream> + +using namespace uhd; + +/*********************************************************************** + * Clock Control Implementation + **********************************************************************/ +class clock_ctrl_impl : public clock_ctrl{ +public: +    //structors +    clock_ctrl_impl(usrp_e_iface::sptr iface); +    ~clock_ctrl_impl(void); + +    void enable_rx_dboard_clock(bool enb); +    void enable_tx_dboard_clock(bool enb); + +    double get_fpga_clock_rate(void){return 64e6;} +    double get_rx_dboard_clock_rate(void){return get_fpga_clock_rate();} +    double get_tx_dboard_clock_rate(void){return get_fpga_clock_rate();} + +private: +    usrp_e_iface::sptr _iface; +    ad9522_regs_t _ad9522_regs; + +    void latch_regs(void){ +        _ad9522_regs.io_update = 1; +        this->send_reg(0x232); +    } +    void send_reg(boost::uint16_t addr); +}; + +/*********************************************************************** + * Clock Control Methods + **********************************************************************/ +clock_ctrl_impl::clock_ctrl_impl(usrp_e_iface::sptr iface){ +    _iface = iface; + +    //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.status_pin_control = 0x1; //n divider +    _ad9522_regs.ld_pin_control = 0x32; //show ref2 +    _ad9522_regs.refmon_pin_control = 0x12; //show ref2 + +    _ad9522_regs.enable_ref2 = 1; +    _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; + +    _ad9522_regs.r_counter_lsb = 1; +    _ad9522_regs.r_counter_msb = 0; +    _ad9522_regs.a_counter = 0; +    _ad9522_regs.b_counter_lsb = 20; +    _ad9522_regs.b_counter_msb = 0; +    _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_3_0MA; + +    _ad9522_regs.vco_calibration_now = 1; //calibrate it! +    _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; +    _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; +    _ad9522_regs.divider0_low_cycles = 2; //3 low +    _ad9522_regs.divider0_high_cycles = 1; //2 high + +    //setup codec clock +    _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; +    _ad9522_regs.divider1_low_cycles = 2; //3 low +    _ad9522_regs.divider1_high_cycles = 1; //2 high + +    //setup test clock (same divider as codec clock) +    _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS; +    _ad9522_regs.out4_cmos_configuration = (true)? +        ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON : +        ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF; + +    //setup a list of register ranges to write +    typedef std::pair<boost::uint16_t, boost::uint16_t> range_t; +    static const std::vector<range_t> 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(); +    //test read: +    //boost::uint32_t reg = _ad9522_regs.get_read_reg(0x01b); +    //boost::uint32_t result = _iface->transact_spi( +    //    UE_SPI_SS_AD9522, +    //    spi_config_t::EDGE_RISE, +    //    reg, 24, true /*no*/ +    //); +    //std::cout << "result " << std::hex << result << std::endl; +    this->enable_rx_dboard_clock(false); +    this->enable_tx_dboard_clock(false); +} + +clock_ctrl_impl::~clock_ctrl_impl(void){ +    this->enable_rx_dboard_clock(false); +    this->enable_tx_dboard_clock(false); +} + +void clock_ctrl_impl::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); + +    _ad9522_regs.divider3_low_cycles = 2; //3 low +    _ad9522_regs.divider3_high_cycles = 1; //2 high +    this->send_reg(0x199); +    this->latch_regs(); +} + +void clock_ctrl_impl::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); + +    _ad9522_regs.divider2_low_cycles = 2; //3 low +    _ad9522_regs.divider2_high_cycles = 1; //2 high +    this->send_reg(0x196); +    this->latch_regs(); +} + +void clock_ctrl_impl::send_reg(boost::uint16_t addr){ +    boost::uint32_t reg = _ad9522_regs.get_write_reg(addr); +    //std::cout << "clock control write reg: " << std::hex << reg << std::endl; +    _iface->transact_spi( +        UE_SPI_SS_AD9522, +        spi_config_t::EDGE_RISE, +        reg, 24, false /*no rb*/ +    ); +} + +/*********************************************************************** + * Clock Control Make + **********************************************************************/ +clock_ctrl::sptr clock_ctrl::make(usrp_e_iface::sptr iface){ +    return sptr(new clock_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp_e/clock_ctrl.hpp b/host/lib/usrp/usrp_e/clock_ctrl.hpp new file mode 100644 index 000000000..994b83564 --- /dev/null +++ b/host/lib/usrp/usrp_e/clock_ctrl.hpp @@ -0,0 +1,73 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_USRP_E_CLOCK_CTRL_HPP +#define INCLUDED_USRP_E_CLOCK_CTRL_HPP + +#include "usrp_e_iface.hpp" +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +/*! + * The usrp-e clock control: + * - Setup system clocks. + * - Disable/enable clock lines. + */ +class clock_ctrl : boost::noncopyable{ +public: +    typedef boost::shared_ptr<clock_ctrl> sptr; + +    /*! +     * Make a new clock control object. +     * \param iface the usrp_e iface object +     * \return the clock control object +     */ +    static sptr make(usrp_e_iface::sptr iface); + +    /*! +     * 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 rate of the dboard clock clock line. +     * \return the dboard clock rate in Hz +     */ +    virtual double get_rx_dboard_clock_rate(void) = 0; + +    /*! +     * Get the rate of the dboard clock clock line. +     * \return the dboard clock rate in Hz +     */ +    virtual double get_tx_dboard_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; + +}; + +#endif /* INCLUDED_USRP_E_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e/codec_ctrl.cpp b/host/lib/usrp/usrp_e/codec_ctrl.cpp new file mode 100644 index 000000000..ce05ac9eb --- /dev/null +++ b/host/lib/usrp/usrp_e/codec_ctrl.cpp @@ -0,0 +1,247 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "codec_ctrl.hpp" +#include "ad9862_regs.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/algorithm.hpp> +#include <boost/cstdint.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/math/special_functions/round.hpp> +#include "usrp_e_regs.hpp" //spi slave constants +#include <boost/assign/list_of.hpp> +#include <iostream> + +using namespace uhd; + +static const bool codec_debug = true; + +/*********************************************************************** + * Codec Control Implementation + **********************************************************************/ +class codec_ctrl_impl : public codec_ctrl{ +public: +    //structors +    codec_ctrl_impl(usrp_e_iface::sptr iface); +    ~codec_ctrl_impl(void); + +    //aux adc and dac control +    float read_aux_adc(aux_adc_t which); +    void write_aux_dac(aux_dac_t which, float volts); + +private: +    usrp_e_iface::sptr _iface; +    ad9862_regs_t _ad9862_regs; +    aux_adc_t _last_aux_adc_a, _last_aux_adc_b; +    void send_reg(boost::uint8_t addr); +    void recv_reg(boost::uint8_t addr); +}; + +/*********************************************************************** + * Codec Control Structors + **********************************************************************/ +codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ +    _iface = iface; + +    //FIXME temp poke !!! +    _iface->poke16(UE_REG_MISC_TEST, 0x0f00); + +    //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 = 0x1f;  //TODO bring under api control +    _ad9862_regs.rx_pga_b = 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_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_4; +    _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; + +    //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); +    } + +    //aux adc clock +    _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; +    this->send_reg(34); +} + +codec_ctrl_impl::~codec_ctrl_impl(void){ +    return; //FIXME remove this later + +    //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 AUX ADC Methods + **********************************************************************/ +static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ +    return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +} + +float codec_ctrl_impl::read_aux_adc(aux_adc_t which){ +    //check to see if the switch needs to be set +    bool write_switch = false; +    switch(which){ + +    case AUX_ADC_A1: +    case AUX_ADC_A2: +        if (which != _last_aux_adc_a){ +            _ad9862_regs.select_a = (which == AUX_ADC_A1)? +                ad9862_regs_t::SELECT_A_AUX_ADC1: ad9862_regs_t::SELECT_A_AUX_ADC2; +            _last_aux_adc_a = which; +            write_switch = true; +        } +        break; + +    case AUX_ADC_B1: +    case AUX_ADC_B2: +        if (which != _last_aux_adc_b){ +            _ad9862_regs.select_b = (which == AUX_ADC_B1)? +                ad9862_regs_t::SELECT_B_AUX_ADC1: ad9862_regs_t::SELECT_B_AUX_ADC2; +            _last_aux_adc_b = which; +            write_switch = true; +        } +        break; + +    } + +    //write the switch if it changed +    if(write_switch) this->send_reg(34); + +    //map aux adcs to register values to read +    static const uhd::dict<aux_adc_t, boost::uint8_t> aux_dac_to_addr = boost::assign::map_list_of +        (AUX_ADC_A2, 26) (AUX_ADC_A1, 28) +        (AUX_ADC_B2, 30) (AUX_ADC_B1, 32) +    ; + +    //read the value +    this->recv_reg(aux_dac_to_addr[which]+0); +    this->recv_reg(aux_dac_to_addr[which]+1); + +    //return the value scaled to volts +    switch(which){ +    case AUX_ADC_A1: return aux_adc_to_volts(_ad9862_regs.aux_adc_a1_9_2, _ad9862_regs.aux_adc_a1_1_0); +    case AUX_ADC_A2: return aux_adc_to_volts(_ad9862_regs.aux_adc_a2_9_2, _ad9862_regs.aux_adc_a2_1_0); +    case AUX_ADC_B1: return aux_adc_to_volts(_ad9862_regs.aux_adc_b1_9_2, _ad9862_regs.aux_adc_b1_1_0); +    case AUX_ADC_B2: return aux_adc_to_volts(_ad9862_regs.aux_adc_b2_9_2, _ad9862_regs.aux_adc_b2_1_0); +    } +    UHD_ASSERT_THROW(false); +} + +/*********************************************************************** + * Codec Control AUX DAC Methods + **********************************************************************/ +void codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts){ +    //special case for aux dac d (aka sigma delta word) +    if (which == AUX_DAC_D){ +        boost::uint16_t dac_word = std::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 = std::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<boost::uint8_t*, boost::uint8_t> dac_params_t; +    uhd::dict<aux_dac_t, dac_params_t> 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 codec_ctrl_impl::send_reg(boost::uint8_t addr){ +    boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); +    if (codec_debug) std::cout << "codec control write reg: " << std::hex << reg << std::endl; +    _iface->transact_spi( +        UE_SPI_SS_AD9862, +        spi_config_t::EDGE_RISE, +        reg, 16, false /*no rb*/ +    ); +} + +void codec_ctrl_impl::recv_reg(boost::uint8_t addr){ +    boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); +    if (codec_debug) std::cout << "codec control read reg: " << std::hex << reg << std::endl; +    boost::uint32_t ret = _iface->transact_spi( +        UE_SPI_SS_AD9862, +        spi_config_t::EDGE_RISE, +        reg, 16, true /*rb*/ +    ); +    if (codec_debug) std::cout << "codec control read ret: " << std::hex << ret << std::endl; +    _ad9862_regs.set_reg(addr, boost::uint16_t(ret)); +} + +/*********************************************************************** + * Codec Control Make + **********************************************************************/ +codec_ctrl::sptr codec_ctrl::make(usrp_e_iface::sptr iface){ +    return sptr(new codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp_e/codec_ctrl.hpp b/host/lib/usrp/usrp_e/codec_ctrl.hpp new file mode 100644 index 000000000..efdcd7142 --- /dev/null +++ b/host/lib/usrp/usrp_e/codec_ctrl.hpp @@ -0,0 +1,75 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_USRP_E_CODEC_CTRL_HPP +#define INCLUDED_USRP_E_CODEC_CTRL_HPP + +#include "usrp_e_iface.hpp" +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> + +/*! + * The usrp-e codec control: + * - Init/power down codec. + * - Read aux adc, write aux dac. + */ +class codec_ctrl : boost::noncopyable{ +public: +    typedef boost::shared_ptr<codec_ctrl> sptr; + +    /*! +     * Make a new clock control object. +     * \param iface the usrp_e iface object +     * \return the clock control object +     */ +    static sptr make(usrp_e_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 float 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, float volts) = 0; + +}; + +#endif /* INCLUDED_USRP_E_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e/dboard_iface.cpp b/host/lib/usrp/usrp_e/dboard_iface.cpp new file mode 100644 index 000000000..23255b58c --- /dev/null +++ b/host/lib/usrp/usrp_e/dboard_iface.cpp @@ -0,0 +1,238 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp_e_iface.hpp" +#include "usrp_e_regs.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include <uhd/usrp/dboard_iface.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/assign/list_of.hpp> +#include <linux/usrp_e.h> //i2c and spi constants + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +class usrp_e_dboard_iface : public dboard_iface{ +public: + +    usrp_e_dboard_iface( +        usrp_e_iface::sptr iface, +        clock_ctrl::sptr clock, +        codec_ctrl::sptr codec +    ){ +        _iface = iface; +        _clock = clock; +        _codec = codec; +    } + +    ~usrp_e_dboard_iface(void){ +        /* NOP */ +    } + +    void write_aux_dac(unit_t, int, float); +    float read_aux_adc(unit_t, int); + +    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 write_gpio(unit_t, boost::uint16_t); +    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 +    ); + +    double get_clock_rate(unit_t); +    void set_clock_enabled(unit_t, bool); + +private: +    usrp_e_iface::sptr _iface; +    clock_ctrl::sptr _clock; +    codec_ctrl::sptr _codec; +}; + +/*********************************************************************** + * Make Function + **********************************************************************/ +dboard_iface::sptr make_usrp_e_dboard_iface( +    usrp_e_iface::sptr iface, +    clock_ctrl::sptr clock, +    codec_ctrl::sptr codec +){ +    return dboard_iface::sptr(new usrp_e_dboard_iface(iface, clock, codec)); +} + +/*********************************************************************** + * Clock Rates + **********************************************************************/ +double usrp_e_dboard_iface::get_clock_rate(unit_t unit){ +    switch(unit){ +    case UNIT_RX: return _clock->get_rx_dboard_clock_rate(); +    case UNIT_TX: return _clock->get_tx_dboard_clock_rate(); +    } +    UHD_ASSERT_THROW(false); +} + +void usrp_e_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); +    } +} + +/*********************************************************************** + * GPIO + **********************************************************************/ +void usrp_e_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_e_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_e_dboard_iface::write_gpio(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_e_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); +    } +    UHD_ASSERT_THROW(false); +} + +void usrp_e_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<atr_reg_t, boost::uint32_t> +    > 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); +} + +/*********************************************************************** + * 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; +    } +    throw std::invalid_argument("unknown unit type"); +} + +void usrp_e_dboard_iface::write_spi( +    unit_t unit, +    const spi_config_t &config, +    boost::uint32_t data, +    size_t num_bits +){ +    _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, false /*no rb*/); +} + +boost::uint32_t usrp_e_dboard_iface::read_write_spi( +    unit_t unit, +    const spi_config_t &config, +    boost::uint32_t data, +    size_t num_bits +){ +    return _iface->transact_spi(unit_to_otw_spi_dev(unit), config, data, num_bits, true /*rb*/); +} + +/*********************************************************************** + * I2C + **********************************************************************/ +void usrp_e_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ +    return _iface->write_i2c(addr, bytes); +} + +byte_vector_t usrp_e_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ +    return _iface->read_i2c(addr, num_bytes); +} + +/*********************************************************************** + * Aux DAX/ADC + **********************************************************************/ +void usrp_e_dboard_iface::write_aux_dac(dboard_iface::unit_t, int which, float value){ +    //same aux dacs for each unit +    static const uhd::dict<int, codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of +        (0, codec_ctrl::AUX_DAC_A) (1, codec_ctrl::AUX_DAC_B) +        (2, codec_ctrl::AUX_DAC_C) (3, codec_ctrl::AUX_DAC_D) +    ; +    _codec->write_aux_dac(which_to_aux_dac[which], value); +} + +float usrp_e_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, int which){ +    static const uhd::dict< +        unit_t, uhd::dict<int, codec_ctrl::aux_adc_t> +    > unit_to_which_to_aux_adc = map_list_of +        (UNIT_RX, map_list_of +            (0, codec_ctrl::AUX_ADC_A1) +            (1, codec_ctrl::AUX_ADC_B1) +        ) +        (UNIT_TX, map_list_of +            (0, codec_ctrl::AUX_ADC_A2) +            (1, 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_e/dboard_impl.cpp b/host/lib/usrp/usrp_e/dboard_impl.cpp new file mode 100644 index 000000000..31f792306 --- /dev/null +++ b/host/lib/usrp/usrp_e/dboard_impl.cpp @@ -0,0 +1,79 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/bind.hpp> +#include "usrp_e_impl.hpp" +#include <iostream> + +using namespace uhd::usrp; + +/*********************************************************************** + * Dboard Initialization + **********************************************************************/ +void usrp_e_impl::dboard_init(void){ +    _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); +    _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); + +    std::cout << _rx_db_eeprom.id.to_pp_string() << std::endl; +    std::cout << _tx_db_eeprom.id.to_pp_string() << std::endl; + +    //create a new dboard interface and manager +    dboard_iface::sptr dboard_iface( +        make_usrp_e_dboard_iface(_iface, _clock_ctrl, _codec_ctrl) +    ); +    _dboard_manager = dboard_manager::make( +        _rx_db_eeprom.id, _tx_db_eeprom.id, dboard_iface +    ); + +    //setup the dboard proxies +    _rx_dboard_proxy = wax_obj_proxy::make( +        boost::bind(&usrp_e_impl::rx_dboard_get, this, _1, _2), +        boost::bind(&usrp_e_impl::rx_dboard_set, this, _1, _2) +    ); +    _tx_dboard_proxy = wax_obj_proxy::make( +        boost::bind(&usrp_e_impl::tx_dboard_get, this, _1, _2), +        boost::bind(&usrp_e_impl::tx_dboard_set, this, _1, _2) +    ); +} + +/*********************************************************************** + * RX Dboard Get + **********************************************************************/ +void usrp_e_impl::rx_dboard_get(const wax::obj &, wax::obj &){ +    UHD_THROW_PROP_GET_ERROR(); +} + +/*********************************************************************** + * RX Dboard Set + **********************************************************************/ +void usrp_e_impl::rx_dboard_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} + +/*********************************************************************** + * TX Dboard Get + **********************************************************************/ +void usrp_e_impl::tx_dboard_get(const wax::obj &, wax::obj &){ +    UHD_THROW_PROP_GET_ERROR(); +} + +/*********************************************************************** + * TX Dboard Set + **********************************************************************/ +void usrp_e_impl::tx_dboard_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp_e/dsp_impl.cpp b/host/lib/usrp/usrp_e/dsp_impl.cpp new file mode 100644 index 000000000..272ac71b3 --- /dev/null +++ b/host/lib/usrp/usrp_e/dsp_impl.cpp @@ -0,0 +1,69 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <boost/bind.hpp> +#include "usrp_e_impl.hpp" + +using namespace uhd::usrp; + +/*********************************************************************** + * RX DDC Initialization + **********************************************************************/ +void usrp_e_impl::rx_ddc_init(void){ +    _rx_ddc_proxy = wax_obj_proxy::make( +        boost::bind(&usrp_e_impl::rx_ddc_get, this, _1, _2), +        boost::bind(&usrp_e_impl::rx_ddc_set, this, _1, _2) +    ); +} + +/*********************************************************************** + * RX DDC Get + **********************************************************************/ +void usrp_e_impl::rx_ddc_get(const wax::obj &, wax::obj &){ +    UHD_THROW_PROP_GET_ERROR(); +} + +/*********************************************************************** + * RX DDC Set + **********************************************************************/ +void usrp_e_impl::rx_ddc_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} + +/*********************************************************************** + * TX DUC Initialization + **********************************************************************/ +void usrp_e_impl::tx_duc_init(void){ +    _tx_duc_proxy = wax_obj_proxy::make( +        boost::bind(&usrp_e_impl::tx_duc_get, this, _1, _2), +        boost::bind(&usrp_e_impl::tx_duc_set, this, _1, _2) +    ); +} + +/*********************************************************************** + * TX DUC Get + **********************************************************************/ +void usrp_e_impl::tx_duc_get(const wax::obj &, wax::obj &){ +    UHD_THROW_PROP_GET_ERROR(); +} + +/*********************************************************************** + * TX DUC Set + **********************************************************************/ +void usrp_e_impl::tx_duc_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp_e/fpga-downloader.cc b/host/lib/usrp/usrp_e/fpga-downloader.cc new file mode 100644 index 000000000..4429786a9 --- /dev/null +++ b/host/lib/usrp/usrp_e/fpga-downloader.cc @@ -0,0 +1,262 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <iostream> +#include <sstream> +#include <fstream> +#include <string> +#include <cstdlib> + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/spi/spidev.h> + +/* + * 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) + * +*/ + +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 (!export_file.is_open())  ///\todo Poor error handling +		std::cout << "Failed to open gpio export file." << std::endl; + +	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; + +	direction_file_name = base_path.str() + "/direction"; + +	direction_file.open(direction_file_name.c_str());  +	if (!direction_file.is_open()) +		std::cout << "Failed to open direction file." << std::endl; +	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()) +		std::cout << "Failed to open value file." << std::endl; +} + +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 +		std::cout << "Data read from value file|" << val << "|" << std::endl; + +	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) { +		std::cout << "FPGA not ready for programming." << std::endl; +		exit(-1); +	} +#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; + +	std::cout << "File name - " << file_name.c_str() << std::endl; + +	bitstream.open(file_name.c_str(), std::ios::binary); +	if (!bitstream.is_open()) +		std::cout << "File " << file_name << " not opened succesfully." << std::endl; + +	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()) +			std::cout << "INIT_B went high, error occured." << std::endl; + +		if (!done.get_value()) +			std::cout << "Configuration complete." << std::endl; + +	} while (bitstream.gcount() == BUF_SIZE); +} + +/* +int main(int argc, char *argv[]) +{ + +	gpio gpio_prog_b(PROG_B, OUT); +	gpio gpio_init_b(INIT_B, IN); +	gpio gpio_done  (DONE,   IN); + +	if (argc == 2) +		bit_file = argv[1]; + +	std::cout << "FPGA config file: " << bit_file << std::endl; + +	prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); + +	std::cout << "Done = " << gpio_done.get_value() << std::endl; + +	send_file_to_fpga(bit_file, gpio_init_b, gpio_done); +} +*/ + +#include <uhd/usrp/usrp_e.hpp> +void uhd::usrp::usrp_e::load_fpga(const std::string &bin_file){ +	gpio gpio_prog_b(PROG_B, OUT); +	gpio gpio_init_b(INIT_B, IN); +	gpio gpio_done  (DONE,   IN); + +	std::cout << "FPGA config file: " << bin_file << std::endl; + +	prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); + +	std::cout << "Done = " << gpio_done.get_value() << std::endl; + +	send_file_to_fpga(bin_file, gpio_init_b, gpio_done); +} diff --git a/host/lib/usrp/usrp_e/mboard_impl.cpp b/host/lib/usrp/usrp_e/mboard_impl.cpp new file mode 100644 index 000000000..00ce4b782 --- /dev/null +++ b/host/lib/usrp/usrp_e/mboard_impl.cpp @@ -0,0 +1,113 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp_e_impl.hpp" +#include <uhd/utils/assert.hpp> +#include <uhd/usrp/mboard_props.hpp> +#include <boost/bind.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Mboard Initialization + **********************************************************************/ +void usrp_e_impl::mboard_init(void){ +    _mboard_proxy = wax_obj_proxy::make( +        boost::bind(&usrp_e_impl::mboard_get, this, _1, _2), +        boost::bind(&usrp_e_impl::mboard_set, this, _1, _2) +    ); + +    //init the clock config +    _clock_config.ref_source = clock_config_t::REF_AUTO; +    _clock_config.pps_source = clock_config_t::PPS_SMA; + +    //TODO poke the clock config regs +} + +/*********************************************************************** + * Mboard Get + **********************************************************************/ +void usrp_e_impl::mboard_get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + + +    //handle the get request conditioned on the key +    switch(key.as<mboard_prop_t>()){ +    case MBOARD_PROP_NAME: +        val = std::string("usrp-e mboard"); +        return; + +    case MBOARD_PROP_OTHERS: +        val = prop_names_t(); +        return; + +    case MBOARD_PROP_RX_DBOARD: +        UHD_ASSERT_THROW(name == ""); +        val = _rx_dboard_proxy->get_link(); +        return; + +    case MBOARD_PROP_RX_DBOARD_NAMES: +        val = prop_names_t(1, ""); //vector of size 1 with empty string +        return; + +    case MBOARD_PROP_TX_DBOARD: +        UHD_ASSERT_THROW(name == ""); +        val = _tx_dboard_proxy->get_link(); +        return; + +    case MBOARD_PROP_TX_DBOARD_NAMES: +        val = prop_names_t(1, ""); //vector of size 1 with empty string +        return; + +    case MBOARD_PROP_STREAM_CMD: +        //val = TODO +        return; + +    case MBOARD_PROP_RX_DSP: +        UHD_ASSERT_THROW(name == "ddc0"); +        val = _rx_ddc_proxy->get_link(); +        return; + +    case MBOARD_PROP_RX_DSP_NAMES: +        val = prop_names_t(1, "ddc0"); +        return; + +    case MBOARD_PROP_TX_DSP: +        UHD_ASSERT_THROW(name == "duc0"); +        val = _tx_duc_proxy->get_link(); +        return; + +    case MBOARD_PROP_TX_DSP_NAMES: +        val = prop_names_t(1, "duc0"); +        return; + +    case MBOARD_PROP_CLOCK_CONFIG: +        val = _clock_config; +        return; + +    default: UHD_THROW_PROP_GET_ERROR(); +    } +} + +/*********************************************************************** + * Mboard Set + **********************************************************************/ +void usrp_e_impl::mboard_set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.cpp b/host/lib/usrp/usrp_e/usrp_e_iface.cpp new file mode 100644 index 000000000..98d8ef478 --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_iface.cpp @@ -0,0 +1,190 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp_e_iface.hpp" +#include <uhd/utils/assert.hpp> +#include <sys/ioctl.h> //ioctl +#include <fcntl.h> //open, close +#include <linux/usrp_e.h> //ioctl structures and constants +#include <boost/format.hpp> +#include <boost/thread.hpp> //mutex +#include <stdexcept> + +using namespace uhd; + +class usrp_e_iface_impl : public usrp_e_iface{ +public: + +    /******************************************************************* +     * Structors +     ******************************************************************/ +    usrp_e_iface_impl(const std::string &node){ +        //open the device node and check file descriptor +        if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){ +            throw std::runtime_error(str( +                boost::format("Failed to open %s") % node +            )); +        } +    } + +    ~usrp_e_iface_impl(void){ +        //close the device node file descriptor +        ::close(_node_fd); +    } + +    /******************************************************************* +     * 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 std::runtime_error(str( +                boost::format("ioctl failed with request %d") % request +            )); +        } +    } + +    /******************************************************************* +     * 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<usrp_e_i2c&>(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<usrp_e_i2c&>(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 +    ){ +        //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; +    } + +private: +    int _node_fd; +    boost::mutex _ctrl_mutex; +}; + +/*********************************************************************** + * Public Make Function + **********************************************************************/ +usrp_e_iface::sptr usrp_e_iface::make(const std::string &node){ +    return sptr(new usrp_e_iface_impl(node)); +} diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.hpp b/host/lib/usrp/usrp_e/usrp_e_iface.hpp new file mode 100644 index 000000000..6363a24b2 --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_iface.hpp @@ -0,0 +1,106 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_USRP_E_IFACE_HPP +#define INCLUDED_USRP_E_IFACE_HPP + +#include <uhd/transport/udp_simple.hpp> +#include <uhd/types/serial.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <boost/cstdint.hpp> + +//////////////////////////////////////////////////////////////////////// +// 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_e_iface : boost::noncopyable, public uhd::i2c_iface{ +public: +    typedef boost::shared_ptr<usrp_e_iface> sptr; + +    /*! +     * Make a new usrp-e interface with the control transport. +     * \param node the device node name +     * \return a new usrp-e interface object +     */ +    static sptr make(const std::string &node); + +    /*! +     * 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; + +    /*! +     * Write a register (32 bits) +     * \param addr the address +     * \param data the 32bit data +     */ +    virtual void poke32(boost::uint32_t addr, boost::uint32_t data) = 0; + +    /*! +     * Read a register (32 bits) +     * \param addr the address +     * \return the 32bit data +     */ +    virtual boost::uint32_t peek32(boost::uint32_t addr) = 0; + +    /*! +     * Write a register (16 bits) +     * \param addr the address +     * \param data the 16bit data +     */ +    virtual void poke16(boost::uint32_t addr, boost::uint16_t data) = 0; + +    /*! +     * Read a register (16 bits) +     * \param addr the address +     * \return the 16bit data +     */ +    virtual boost::uint16_t peek16(boost::uint32_t addr) = 0; + +    /*! +     * Perform an spi transaction. +     * \param which_slave the slave device number +     * \param config spi config args +     * \param data the bits to write +     * \param num_bits how many bits in data +     * \param readback true to readback a value +     * \return spi data if readback set +     */ +    virtual boost::uint32_t transact_spi( +        int which_slave, +        const uhd::spi_config_t &config, +        boost::uint32_t data, +        size_t num_bits, +        bool readback +    ) = 0; +}; + +#endif /* INCLUDED_USRP_E_IFACE_HPP */ diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.cpp b/host/lib/usrp/usrp_e/usrp_e_impl.cpp new file mode 100644 index 000000000..4a398e21c --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_impl.cpp @@ -0,0 +1,156 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp_e_impl.hpp" +#include <uhd/usrp/device_props.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> +#include <boost/format.hpp> +#include <boost/filesystem.hpp> +#include <iostream> + +using namespace uhd; +using namespace uhd::usrp; +namespace fs = boost::filesystem; + +UHD_STATIC_BLOCK(register_usrp_e_device){ +    device::register_device(&usrp_e::find, &usrp_e::make); +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static std::string abs_path(const std::string &file_path){ +    return fs::system_complete(fs::path(file_path)).file_string(); +} + +/*********************************************************************** + * Discovery + **********************************************************************/ +device_addrs_t usrp_e::find(const device_addr_t &hint){ +    device_addrs_t usrp_e_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_e::find(new_addr); +    } + +    //use the given device node name +    if (fs::exists(hint["node"])){ +        device_addr_t new_addr; +        new_addr["name"] = "USRP-E"; +        new_addr["node"] = abs_path(hint["node"]); +        usrp_e_addrs.push_back(new_addr); +    } + +    return usrp_e_addrs; +} + +/*********************************************************************** + * Make + **********************************************************************/ +device::sptr usrp_e::make(const device_addr_t &device_addr){ +    return sptr(new usrp_e_impl(device_addr["node"])); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +usrp_e_impl::usrp_e_impl(const std::string &node){ +    std::cout << boost::format("Opening USRP-E on %s") % node << std::endl; + +    //setup various interfaces into hardware +    _iface = usrp_e_iface::make(node); +    _clock_ctrl = clock_ctrl::make(_iface); +    _codec_ctrl = codec_ctrl::make(_iface); + +    //initialize the mboard +    mboard_init(); + +    //initialize the dboards +    dboard_init(); + +    //initialize the dsps +    rx_ddc_init(); +    tx_duc_init(); +} + +usrp_e_impl::~usrp_e_impl(void){ +    /* NOP */ +} + +/*********************************************************************** + * Device Get + **********************************************************************/ +void usrp_e_impl::get(const wax::obj &key_, wax::obj &val){ +    wax::obj key; std::string name; +    boost::tie(key, name) = extract_named_prop(key_); + +    //handle the get request conditioned on the key +    switch(key.as<device_prop_t>()){ +    case DEVICE_PROP_NAME: +        val = std::string("usrp-e device"); +        return; + +    case DEVICE_PROP_MBOARD: +        UHD_ASSERT_THROW(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_e_impl::set(const wax::obj &, const wax::obj &){ +    UHD_THROW_PROP_SET_ERROR(); +} + +/*********************************************************************** + * Device IO (TODO) + **********************************************************************/ +size_t usrp_e_impl::send( +    const boost::asio::const_buffer &, +    const uhd::tx_metadata_t &, +    const io_type_t &, +    send_mode_t +){ +    if (true){ +        throw std::runtime_error(str(boost::format("usrp-e send: cannot handle type \"%s\"") % "")); +    } +    return 0; +} + +size_t usrp_e_impl::recv( +    const boost::asio::mutable_buffer &, +    uhd::rx_metadata_t &, +    const io_type_t &, +    recv_mode_t +){ +    if (true){ +        throw std::runtime_error(str(boost::format("usrp-e recv: cannot handle type \"%s\"") % "")); +    } +    return 0; +} diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp new file mode 100644 index 000000000..a2cdbc31e --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp @@ -0,0 +1,148 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "usrp_e_iface.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" +#include <uhd/usrp/usrp_e.hpp> +#include <uhd/usrp/dboard_eeprom.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/usrp/dboard_manager.hpp> + +#ifndef INCLUDED_USRP_E_IMPL_HPP +#define INCLUDED_USRP_E_IMPL_HPP + +/*! + * 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_e_dboard_iface( +    usrp_e_iface::sptr iface, +    clock_ctrl::sptr clock, +    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<void(const wax::obj &, wax::obj &)>       get_t; +    typedef boost::function<void(const wax::obj &, const wax::obj &)> set_t; +    typedef boost::shared_ptr<wax_obj_proxy> sptr; + +    static sptr make(const get_t &get, const set_t &set){ +        return sptr(new wax_obj_proxy(get, set)); +    } + +    ~wax_obj_proxy(void){ +        /* NOP */ +    } + +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); +    } +}; + +/*! + * USRP1E implementation guts: + * The implementation details are encapsulated here. + * Handles properties on the mboard, dboard, dsps... + */ +class usrp_e_impl : public uhd::device{ +public: +    //structors +    usrp_e_impl(const std::string &node); +    ~usrp_e_impl(void); + +    //the io interface +    size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t); +    size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t); +    size_t get_max_send_samps_per_packet(void) const{return _max_num_samples;} +    size_t get_max_recv_samps_per_packet(void) const{return _max_num_samples;} + +private: +    static const size_t _max_num_samples = 2048/sizeof(boost::uint32_t); +    usrp_e_iface::sptr _iface; + +    uhd::clock_config_t _clock_config; + +    //ad9522 clock control +    clock_ctrl::sptr _clock_ctrl; + +    //ad9862 codec control +    codec_ctrl::sptr _codec_ctrl; + +    //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; + +    //xx dboard functions and settings +    void dboard_init(void); +    uhd::usrp::dboard_manager::sptr _dboard_manager; + +    //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; +    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; + +    //rx ddc functions and settings +    void rx_ddc_init(void); +    void rx_ddc_get(const wax::obj &, wax::obj &); +    void rx_ddc_set(const wax::obj &, const wax::obj &); +    wax_obj_proxy::sptr _rx_ddc_proxy; + +    //tx duc functions and settings +    void tx_duc_init(void); +    void tx_duc_get(const wax::obj &, wax::obj &); +    void tx_duc_set(const wax::obj &, const wax::obj &); +    wax_obj_proxy::sptr _tx_duc_proxy; +}; + +#endif /* INCLUDED_USRP_E_IMPL_HPP */ diff --git a/host/lib/usrp/usrp_e/usrp_e_none.cpp b/host/lib/usrp/usrp_e/usrp_e_none.cpp new file mode 100644 index 000000000..09a3c6946 --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_none.cpp @@ -0,0 +1,38 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/usrp/usrp_e.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +/*! + * This file defines the usrp1e discover and make functions + * when the required kernel module headers are not present. + */ + +device_addrs_t usrp_e::find(const device_addr_t &){ +    return device_addrs_t(); //return empty list +} + +device::sptr usrp_e::make(const device_addr_t &){ +    throw std::runtime_error("this build has no usrp1e support"); +} + +void usrp_e::load_fpga(const std::string &){ +    throw std::runtime_error("this build has no usrp1e support"); +} diff --git a/host/lib/usrp/usrp_e/usrp_e_regs.hpp b/host/lib/usrp/usrp_e/usrp_e_regs.hpp new file mode 100644 index 000000000..51a47f061 --- /dev/null +++ b/host/lib/usrp/usrp_e/usrp_e_regs.hpp @@ -0,0 +1,115 @@ + + +//////////////////////////////////////////////////////////////// +// +//         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 __USRP_E_REGS_H +#define __USRP_E_REGS_H + +///////////////////////////////////////////////////// +// 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 + +///////////////////////////////////////////////////// +// 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 5 -- Settings Bus +// +// Output-only, no readback, 32 registers total +//  Each register must be written 32 bits at a time +//  First the address xxx_xx00 and then xxx_xx10 + +#define UE_REG_SETTINGS_BASE UE_REG_SLAVE(5) + +/////////////////////////////////////////////////// +// 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 + +#endif + | 
