diff options
Diffstat (limited to 'host/lib/usrp/usrp_e100')
| -rw-r--r-- | host/lib/usrp/usrp_e100/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/clock_ctrl.cpp | 326 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/clock_ctrl.hpp | 7 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/fpga_downloader.cpp (renamed from host/lib/usrp/usrp_e100/fpga-downloader.cc) | 42 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/io_impl.cpp | 90 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/mboard_impl.cpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/usrp_e100_iface.cpp | 6 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/usrp_e100_impl.hpp | 8 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp | 165 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/usrp_e100_regs.hpp | 94 | 
10 files changed, 529 insertions, 221 deletions
diff --git a/host/lib/usrp/usrp_e100/CMakeLists.txt b/host/lib/usrp/usrp_e100/CMakeLists.txt index c32dd87f8..acbac177e 100644 --- a/host/lib/usrp/usrp_e100/CMakeLists.txt +++ b/host/lib/usrp/usrp_e100/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2010 Ettus Research LLC +# 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 @@ -40,7 +40,7 @@ IF(ENABLE_USRP_E100)          ${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.cc +        ${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 diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp index 1fb1a7125..e29fe18ce 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -22,11 +22,26 @@  #include "usrp_e100_regs.hpp" //spi slave constants  #include <boost/assign/list_of.hpp>  #include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/thread/thread.hpp> +#include <boost/math/common_factor_rt.hpp> //gcd +#include <algorithm>  #include <utility>  #include <iostream>  using namespace uhd; +/*********************************************************************** + * Constants + **********************************************************************/ +static const bool CLOCK_SETTINGS_DEBUG = false; +static const bool ENABLE_THE_TEST_OUT = true; +static const double REFERENCE_INPUT_RATE = 10e6; +static const double DEFAULT_OUTPUT_RATE = 64e6; + +/*********************************************************************** + * Helpers + **********************************************************************/  template <typename div_type, typename bypass_type> static void set_clock_divider(      size_t divider, div_type &low, div_type &high, bypass_type &bypass  ){ @@ -36,24 +51,117 @@ template <typename div_type, typename bypass_type> static void set_clock_divider  }  /*********************************************************************** - * Constants + * Clock rate calculation stuff: + *   Using the internal VCO between 1400 and 1800 MHz   **********************************************************************/ -static const bool enable_test_clock = false; -static const size_t ref_clock_doubler = 2; //enabled below -static const double ref_clock_rate = 10e6 * ref_clock_doubler; +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<typename T> 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<typename T> 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 -static const size_t r_counter = 1; -static const size_t a_counter = 0; -static const size_t b_counter = 20 / ref_clock_doubler; -static const size_t prescaler = 8; //set below with enum, set to 8 when input is under 2400 MHz -static const size_t vco_divider = 5; //set below with enum +    //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 -static const size_t n_counter = prescaler * b_counter + a_counter; -static const size_t vco_clock_rate = ref_clock_rate/r_counter * n_counter; //between 1400 and 1800 MHz -static const double master_clock_rate = vco_clock_rate/vco_divider; +    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)); -static const size_t fpga_clock_divider = size_t(master_clock_rate/64e6); -static const size_t codec_clock_divider = size_t(master_clock_rate/64e6); +    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<size_t>(X/cs.r_counter, 32); +            cs.vco_divider = greatest_divisor<size_t>(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<size_t>(cs.chan_divider, 2); +                cs.chan_divider /= cs.vco_divider; +            } + +            if (CLOCK_SETTINGS_DEBUG){ +                std::cout << "gcd " << gcd << std::endl; +                std::cout << "X " << X << std::endl; +                std::cout << "Y " << Y << std::endl; +                std::cout << 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; + +            std::cout << "USRP-E100 clock control: " << i << std::endl << cs.to_pp_string() << std::endl; +            return cs; +        } +    } + +    throw std::runtime_error(str(boost::format( +        "USRP-E100 clock control: could not calculate settings for clock rate %fMHz" +    ) % (rate/1e6))); +}  /***********************************************************************   * Clock Control Implementation @@ -62,35 +170,70 @@ class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{  public:      usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface){          _iface = iface; +        _chan_rate = 0.0; +        _out_rate = 0.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.enable_clock_doubler = 1; //enable ref clock doubler          _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; -        _ad9522_regs.enable_ref2 = 1; -        _ad9522_regs.enable_ref1 = 0; -        _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; +        this->use_internal_ref(); + +        this->set_fpga_clock_rate(DEFAULT_OUTPUT_RATE); //initialize to something + +        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.set_r_counter(r_counter); -        _ad9522_regs.a_counter = a_counter; -        _ad9522_regs.set_b_counter(b_counter); +        _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.vco_calibration_now = 1; //calibrate it! -        _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; +        _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(fpga_clock_divider, +        set_clock_divider(cs.chan_divider,              _ad9522_regs.divider0_low_cycles,              _ad9522_regs.divider0_high_cycles,              _ad9522_regs.divider0_bypass @@ -98,52 +241,69 @@ public:          //setup codec clock          _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; -        set_clock_divider(codec_clock_divider, +        set_clock_divider(cs.chan_divider,              _ad9522_regs.divider1_low_cycles,              _ad9522_regs.divider1_high_cycles,              _ad9522_regs.divider1_bypass          ); -        //setup test clock (same divider as codec clock) -        _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS; -        _ad9522_regs.out4_cmos_configuration = (enable_test_clock)? -            ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON : -            ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF; +        this->send_all_regs(); +        calibrate_now(); +    } -        //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)) -        ; +    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; -        //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); +        _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();      } -    ~usrp_e100_clock_ctrl_impl(void){ -        this->enable_rx_dboard_clock(false); -        this->enable_tx_dboard_clock(false); +    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);      }      double get_fpga_clock_rate(void){ -        return master_clock_rate/fpga_clock_divider; +        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(0x0F0); +        this->latch_regs();      }      /*********************************************************************** @@ -161,13 +321,13 @@ public:      std::vector<double> get_rx_dboard_clock_rates(void){          std::vector<double> rates;          for(size_t div = 1; div <= 16+16; div++) -            rates.push_back(master_clock_rate/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"); -        size_t divider = size_t(master_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, @@ -197,7 +357,7 @@ public:      void set_tx_dboard_clock_rate(double rate){          assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate"); -        size_t divider = size_t(master_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, @@ -238,6 +398,8 @@ public:  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      void latch_regs(void){          _ad9522_regs.io_update = 1; @@ -253,6 +415,46 @@ private:              reg, 24, false /*no rb*/          );      } + +    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::uint32_t reg = _iface->transact_spi( +                UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, +                _ad9522_regs.get_read_reg(addr), 24, true /*rb*/ +            ); +            _ad9522_regs.set_reg(addr, reg); +            if (_ad9522_regs.vco_calibration_finished) return; +            boost::this_thread::sleep(boost::posix_time::milliseconds(10)); +        } +        std::cerr << "USRP-E100 clock control: VCO calibration timeout" << std::endl; +    } + +    void send_all_regs(void){ +        //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(); +    }  };  /*********************************************************************** diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/usrp_e100/clock_ctrl.hpp index d613d1473..1f9960ce4 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.hpp @@ -40,6 +40,13 @@ public:      static sptr make(usrp_e100_iface::sptr iface);      /*! +     * 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       */ diff --git a/host/lib/usrp/usrp_e100/fpga-downloader.cc b/host/lib/usrp/usrp_e100/fpga_downloader.cpp index 4a3d3b9af..c0013fcbd 100644 --- a/host/lib/usrp/usrp_e100/fpga-downloader.cc +++ b/host/lib/usrp/usrp_e100/fpga_downloader.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -43,6 +43,8 @@   *  */ +namespace usrp_e_fpga_downloader_utility{ +  const unsigned int PROG_B = 175;  const unsigned int DONE   = 173;  const unsigned int INIT_B = 114; @@ -209,11 +211,10 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d  {  	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; +	if (!bitstream.is_open()) throw std::runtime_error( +		"Coult not open the file: " + file_name +	);  	spidev spi("/dev/spidev1.0");  	char buf[BUF_SIZE]; @@ -232,35 +233,20 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d  	} 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); -} -*/ +}//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);  	std::cout << "Loading FPGA image: " << bin_file << "... " << std::flush; -	UHD_ASSERT_THROW(std::system("/sbin/rmmod usrp_e") == 0); +	if(std::system("/sbin/rmmod usrp_e") != 0){ +		std::cerr << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl; +	}  	prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b); @@ -268,7 +254,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){  	send_file_to_fpga(bin_file, gpio_init_b, gpio_done); -	UHD_ASSERT_THROW(std::system("/sbin/modprobe usrp_e") == 0); +	if(std::system("/sbin/modprobe usrp_e") != 0){ +		std::cerr << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl; +	}  } diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp index 2388482c7..fc6aaeaee 100644 --- a/host/lib/usrp/usrp_e100/io_impl.cpp +++ b/host/lib/usrp/usrp_e100/io_impl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -35,7 +35,8 @@ zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);  /***********************************************************************   * Constants   **********************************************************************/ -static const size_t tx_async_report_sid = 1; +static const size_t rx_data_inline_sid = 1; +static const size_t tx_async_report_sid = 2;  static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;  static const bool recv_debug = false; @@ -47,15 +48,12 @@ static const bool recv_debug = false;   * - vrt packet handler states   **********************************************************************/  struct usrp_e100_impl::io_impl{ -    //state management for the vrt packet handler code -    vrt_packet_handler::recv_state packet_handler_recv_state; -    vrt_packet_handler::send_state packet_handler_send_state; -    zero_copy_if::sptr data_xport; -    bool continuous_streaming;      io_impl(usrp_e100_iface::sptr iface):          data_xport(usrp_e100_make_mmap_zero_copy(iface)), -        recv_pirate_booty(recv_booty_type::make(data_xport->get_num_recv_frames())), -        async_msg_fifo(bounded_buffer<async_metadata_t>::make(100/*messages deep*/)) +        get_recv_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, this, _1)), +        get_send_buffs_fcn(boost::bind(&usrp_e100_impl::io_impl::get_send_buffs, this, _1)), +        recv_pirate_booty(data_xport->get_num_recv_frames()), +        async_msg_fifo(100/*messages deep*/)      {          /* NOP */      } @@ -66,17 +64,38 @@ struct usrp_e100_impl::io_impl{          recv_pirate_crew.join_all();      } -    bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs, double timeout){ +    bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){          UHD_ASSERT_THROW(buffs.size() == 1);          boost::this_thread::disable_interruption di; //disable because the wait can throw -        return recv_pirate_booty->pop_with_timed_wait(buffs.front(), timeout); +        return recv_pirate_booty.pop_with_timed_wait(buffs.front(), recv_timeout); +    } + +    bool get_send_buffs(vrt_packet_handler::managed_send_buffs_t &buffs){ +        UHD_ASSERT_THROW(buffs.size() == 1); +        buffs[0] = data_xport->get_send_buff(send_timeout); +        return buffs[0].get() != NULL;      } +    //The data transport is listed first so that it is deconstructed last, +    //which is after the states and booty which may hold managed buffers. +    zero_copy_if::sptr data_xport; + +    //bound callbacks for get buffs (bound once here, not in fast-path) +    vrt_packet_handler::get_recv_buffs_t get_recv_buffs_fcn; +    vrt_packet_handler::get_send_buffs_t get_send_buffs_fcn; + +    //timeouts set on calls to recv/send (passed into get buffs methods) +    double recv_timeout, send_timeout; + +    //state management for the vrt packet handler code +    vrt_packet_handler::recv_state packet_handler_recv_state; +    vrt_packet_handler::send_state packet_handler_send_state; +    bool continuous_streaming; +      //a pirate's life is the life for me!      void recv_pirate_loop(usrp_e100_clock_ctrl::sptr); -    typedef bounded_buffer<managed_recv_buffer::sptr> recv_booty_type; -    recv_booty_type::sptr recv_pirate_booty; -    bounded_buffer<async_metadata_t>::sptr async_msg_fifo; +    bounded_buffer<managed_recv_buffer::sptr> recv_pirate_booty; +    bounded_buffer<async_metadata_t> async_msg_fifo;      boost::thread_group recv_pirate_crew;      bool recv_pirate_crew_raiding;  }; @@ -110,8 +129,17 @@ void usrp_e100_impl::io_impl::recv_pirate_loop(usrp_e100_clock_ctrl::sptr clock_              const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();              vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); +            //handle an rx data packet or inline message +            if (if_packet_info.sid == rx_data_inline_sid){ +                if (recv_debug) std::cout << "this is rx_data_inline_sid\n"; +                //same number of frames as the data transport -> always immediate +                recv_pirate_booty.push_with_wait(buff); +                continue; +            } +              //handle a tx async report message              if (if_packet_info.sid == tx_async_report_sid and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ +                if (recv_debug) std::cout << "this is tx_async_report_sid\n";                  //fill in the async metadata                  async_metadata_t metadata; @@ -124,12 +152,11 @@ void usrp_e100_impl::io_impl::recv_pirate_loop(usrp_e100_clock_ctrl::sptr clock_                  //print the famous U, and push the metadata into the message queue                  if (metadata.event_code & underflow_flags) std::cerr << "U" << std::flush; -                async_msg_fifo->push_with_pop_on_full(metadata); +                async_msg_fifo.push_with_pop_on_full(metadata);                  continue;              } -            //same number of frames as the data transport -> always immediate -            recv_pirate_booty->push_with_wait(buff); +            if (recv_debug) std::cout << "this is unknown packet\n";          }catch(const std::exception &e){              std::cerr << "Error (usrp-e recv pirate loop): " << e.what() << std::endl; @@ -153,17 +180,20 @@ void usrp_e100_impl::io_init(void){      //setup before the registers (transport called to calculate max spp)      _io_impl = UHD_PIMPL_MAKE(io_impl, (_iface)); +    //clear state machines +    _iface->poke32(UE_REG_CTRL_RX_CLEAR, 0); +    _iface->poke32(UE_REG_CTRL_TX_CLEAR, 0); +      //setup rx data path      _iface->poke32(UE_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());      _iface->poke32(UE_REG_CTRL_RX_NCHANNELS, 1); -    _iface->poke32(UE_REG_CTRL_RX_CLEAR_OVERRUN, 1); //reset      _iface->poke32(UE_REG_CTRL_RX_VRT_HEADER, 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_CTRL_RX_VRT_STREAM_ID, 0); +    _iface->poke32(UE_REG_CTRL_RX_VRT_STREAM_ID, rx_data_inline_sid);      _iface->poke32(UE_REG_CTRL_RX_VRT_TRAILER, 0);      //setup the tx policy @@ -185,7 +215,6 @@ void usrp_e100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd){  void usrp_e100_impl::handle_overrun(size_t){      std::cerr << "O"; //the famous OOOOOOOOOOO -    _iface->poke32(UE_REG_CTRL_RX_CLEAR_OVERRUN, 0);      if (_io_impl->continuous_streaming){          this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);      } @@ -194,15 +223,6 @@ void usrp_e100_impl::handle_overrun(size_t){  /***********************************************************************   * Data Send   **********************************************************************/ -bool get_send_buffs( -    zero_copy_if::sptr trans, double timeout, -    vrt_packet_handler::managed_send_buffs_t &buffs -){ -    UHD_ASSERT_THROW(buffs.size() == 1); -    buffs[0] = trans->get_send_buff(timeout); -    return buffs[0].get() != NULL; -} -  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) @@ -213,10 +233,11 @@ size_t usrp_e100_impl::get_max_send_samps_per_packet(void) const{  }  size_t usrp_e100_impl::send( -    const std::vector<const void *> &buffs, size_t num_samps, +    const send_buffs_type &buffs, size_t num_samps,      const tx_metadata_t &metadata, const io_type_t &io_type,      send_mode_t send_mode, double timeout  ){ +    _io_impl->send_timeout = timeout;      return vrt_packet_handler::send(          _io_impl->packet_handler_send_state,       //last state of the send handler          buffs, num_samps,                          //buffer to fill @@ -224,7 +245,7 @@ size_t usrp_e100_impl::send(          io_type, _send_otw_type,                   //input and output types to convert          _clock_ctrl->get_fpga_clock_rate(),        //master clock tick rate          uhd::transport::vrt::if_hdr_pack_le, -        boost::bind(&get_send_buffs, _io_impl->data_xport, timeout, _1), +        _io_impl->get_send_buffs_fcn,          get_max_send_samps_per_packet()      );  } @@ -243,10 +264,11 @@ size_t usrp_e100_impl::get_max_recv_samps_per_packet(void) const{  }  size_t usrp_e100_impl::recv( -    const std::vector<void *> &buffs, size_t num_samps, +    const recv_buffs_type &buffs, size_t num_samps,      rx_metadata_t &metadata, const io_type_t &io_type,      recv_mode_t recv_mode, double timeout  ){ +    _io_impl->recv_timeout = timeout;      return vrt_packet_handler::recv(          _io_impl->packet_handler_recv_state,       //last state of the recv handler          buffs, num_samps,                          //buffer to fill @@ -254,7 +276,7 @@ size_t usrp_e100_impl::recv(          io_type, _recv_otw_type,                   //input and output types to convert          _clock_ctrl->get_fpga_clock_rate(),        //master clock tick rate          uhd::transport::vrt::if_hdr_unpack_le, -        boost::bind(&usrp_e100_impl::io_impl::get_recv_buffs, _io_impl.get(), _1, timeout), +        _io_impl->get_recv_buffs_fcn,          boost::bind(&usrp_e100_impl::handle_overrun, this, _1)      );  } @@ -266,5 +288,5 @@ 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); +    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 index f52d2e6fb..0e08cd435 100644 --- a/host/lib/usrp/usrp_e100/mboard_impl.cpp +++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp @@ -152,6 +152,10 @@ void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){          return;      } +    case MBOARD_PROP_CLOCK_RATE: +        val = _clock_ctrl->get_fpga_clock_rate(); +        return; +      default: UHD_THROW_PROP_GET_ERROR();      }  } @@ -211,6 +215,10 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){          update_clock_config();          return; +    case MBOARD_PROP_CLOCK_RATE: +        _clock_ctrl->set_fpga_clock_rate(val.as<double>()); +        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 index 40c7afabb..ad36dd97a 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -16,6 +16,7 @@  //  #include "usrp_e100_iface.hpp" +#include "usrp_e100_regs.hpp"  #include <uhd/utils/assert.hpp>  #include <sys/ioctl.h> //ioctl  #include <fcntl.h> //open, close @@ -108,6 +109,9 @@ public:              throw std::runtime_error("Failed to open " + node);          } +        //very first thing, reset all the wishbone, always do first! +        this->poke32(UE_REG_CLEAR_GLOBAL, 0); +          mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);      } diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp index df8e5dc9f..897616320 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -30,7 +30,7 @@  #ifndef INCLUDED_USRP_E100_IMPL_HPP  #define INCLUDED_USRP_E100_IMPL_HPP -static const boost::uint16_t USRP_E_COMPAT_NUM = 0x02; //make this 3 then the mainline fpga image gets fixed for embedded +static const boost::uint16_t USRP_E_COMPAT_NUM = 0x03;  //! load an fpga image from a bin file into the usrp-e fpga  extern void usrp_e100_load_fpga(const std::string &bin_file); @@ -83,8 +83,8 @@ public:      ~usrp_e100_impl(void);      //the io interface -    size_t send(const std::vector<const void *> &, size_t, const uhd::tx_metadata_t &, const uhd::io_type_t &, send_mode_t, double); -    size_t recv(const std::vector<void *> &, size_t, uhd::rx_metadata_t &, const uhd::io_type_t &, recv_mode_t, double); +    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; 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 index bf378a9b1..c155d426a 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// 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 @@ -22,8 +22,7 @@  #include <sys/mman.h> //mmap  #include <unistd.h> //getpagesize  #include <poll.h> //poll -#include <boost/bind.hpp> -#include <boost/enable_shared_from_this.hpp> +#include <vector>  #include <iostream>  using namespace uhd; @@ -34,9 +33,85 @@ static const bool sp_verbose = false; //slow-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) std::cout << "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) std::cout << "  make_recv_buff: " << get_size() << std::endl; +        _info->flags = RB_USER_PROCESS; //claim the frame +        return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter); +    } + +private: +    static void fake_deleter(void *obj){ +        static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release(); +    } + +    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) std::cout << "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 +            std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl; +        } +    } + +    bool ready(void){return _info->flags & RB_KERNEL;} + +    sptr get_new(void){ +        if (fp_verbose) std::cout << "  make_send_buff: " << get_size() << std::endl; +        _info->flags = RB_USER_PROCESS; //claim the frame +        return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter); +    } + +private: +    static void fake_deleter(void *obj){ +        static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0); +    } + +    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 boost::enable_shared_from_this<usrp_e100_mmap_zero_copy_impl> { +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) @@ -82,13 +157,32 @@ public:              std::cout << "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<char *>(_mapped_mem); -        _recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off); -        _recv_buff = rb_ptr + recv_buff_off; -        _send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off); -        _send_buff = rb_ptr + send_buff_off; +        recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off); +        recv_buff = rb_ptr + recv_buff_off; +        send_info = reinterpret_cast<rbi_pta>(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){ @@ -98,13 +192,10 @@ public:      managed_recv_buffer::sptr get_recv_buff(double timeout){          if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl; - -        //grab pointers to the info and buffer -        ring_buffer_info *info = (*_recv_info) + _recv_index; -        void *mem = _recv_buff + _frame_size*_recv_index; +        usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];          //poll/wait for a ready frame -        if (not (info->flags & RB_USER)){ +        if (not mrb.ready()){              for (size_t i = 0; i < poll_breakout; i++){                  pollfd pfd;                  pfd.fd = _fd; @@ -116,18 +207,11 @@ public:              return managed_recv_buffer::sptr(); //timed-out for real          } found_user_frame: -        //the process has claimed the frame -        info->flags = RB_USER_PROCESS; -          //increment the index for the next call -        if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; +        if (++_recv_index == get_num_recv_frames()) _recv_index = 0;          //return the managed buffer for this frame -        if (fp_verbose) std::cout << "  make_recv_buff: " << info->len << std::endl; -        return managed_recv_buffer::make_safe( -            boost::asio::const_buffer(mem, info->len), -            boost::bind(&usrp_e100_mmap_zero_copy_impl::release, shared_from_this(), info) -        ); +        return mrb.get_new();      }      size_t get_num_recv_frames(void) const{ @@ -140,13 +224,10 @@ public:      managed_send_buffer::sptr get_send_buff(double timeout){          if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl; - -        //grab pointers to the info and buffer -        ring_buffer_info *info = (*_send_info) + _send_index; -        void *mem = _send_buff + _frame_size*_send_index; +        usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];          //poll/wait for a ready frame -        if (not (info->flags & RB_KERNEL)){ +        if (not msb.ready()){              pollfd pfd;              pfd.fd = _fd;              pfd.events = POLLOUT; @@ -156,14 +237,10 @@ public:          }          //increment the index for the next call -        if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; +        if (++_send_index == get_num_send_frames()) _send_index = 0;          //return the managed buffer for this frame -        if (fp_verbose) std::cout << "  make_send_buff: " << _frame_size << std::endl; -        return managed_send_buffer::make_safe( -            boost::asio::mutable_buffer(mem, _frame_size), -            boost::bind(&usrp_e100_mmap_zero_copy_impl::commit, shared_from_this(), info, _1) -        ); +        return msb.get_new();      }      size_t get_num_send_frames(void) const{ @@ -175,21 +252,7 @@ public:      }  private: - -    void release(ring_buffer_info *info){ -        if (fp_verbose) std::cout << "recv buff: release" << std::endl; -        info->flags = RB_KERNEL; -    } - -    void commit(ring_buffer_info *info, size_t len){ -        if (fp_verbose) std::cout << "send buff: commit " << len << std::endl; -        info->len = len; -        info->flags = RB_USER; -        if (::write(_fd, NULL, 0) < 0){ -            std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl; -        } -    } - +    //file descriptor for mmap      int _fd;      //the mapped memory itself @@ -199,9 +262,9 @@ private:      usrp_e_ring_buffer_size_t _rb_size;      size_t _frame_size, _map_size; -    //pointers to sections in the mapped memory -    ring_buffer_info (*_recv_info)[], (*_send_info)[]; -    char *_recv_buff, *_send_buff; +    //re-usable managed buffers +    std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool; +    std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;      //indexes into sub-sections of mapped memory      size_t _recv_index, _send_index; diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp index a57fe5171..a030462d0 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp @@ -17,7 +17,6 @@  // Slave pointers  #define UE_REG_SLAVE(n) ((n)<<7) -#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))  /////////////////////////////////////////////////////  // Slave 0 -- Misc Regs @@ -89,16 +88,6 @@  #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 @@ -123,48 +112,72 @@  #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 + +#define UE_REG_SETTINGS_BASE_ADDR(n) (UE_REG_SLAVE(8) + (4*(n))) + +#define UE_REG_SR_MISC_TEST32        UE_REG_SETTINGS_BASE_ADDR(52) + +///////////////////////////////////////////////// +// Magic reset regs +//////////////////////////////////////////////// +#define UE_REG_CLEAR_ADDR(n)      (UE_REG_SETTINGS_BASE_ADDR(48) + (4*(n))) +#define UE_REG_CLEAR_RX           UE_REG_CLEAR_ADDR(0) +#define UE_REG_CLEAR_TX           UE_REG_CLEAR_ADDR(1) +#define UE_REG_CLEAR_GLOBAL       UE_REG_CLEAR_ADDR(2)  /////////////////////////////////////////////////  // DSP RX Regs  //////////////////////////////////////////////// -#define UE_REG_DSP_RX_FREQ         UE_REG_SR_ADDR(0) -#define UE_REG_DSP_RX_SCALE_IQ     UE_REG_SR_ADDR(1)  // {scale_i,scale_q} -#define UE_REG_DSP_RX_DECIM_RATE   UE_REG_SR_ADDR(2)  // hb and decim rate -#define UE_REG_DSP_RX_DCOFFSET_I   UE_REG_SR_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic -#define UE_REG_DSP_RX_DCOFFSET_Q   UE_REG_SR_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits -#define UE_REG_DSP_RX_MUX          UE_REG_SR_ADDR(5) +#define UE_REG_DSP_RX_ADDR(n)      (UE_REG_SETTINGS_BASE_ADDR(16) + (4*(n))) +#define UE_REG_DSP_RX_FREQ         UE_REG_DSP_RX_ADDR(0) +#define UE_REG_DSP_RX_SCALE_IQ     UE_REG_DSP_RX_ADDR(1) // {scale_i,scale_q} +#define UE_REG_DSP_RX_DECIM_RATE   UE_REG_DSP_RX_ADDR(2) // hb and decim rate +#define UE_REG_DSP_RX_DCOFFSET_I   UE_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic +#define UE_REG_DSP_RX_DCOFFSET_Q   UE_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits +#define UE_REG_DSP_RX_MUX          UE_REG_DSP_RX_ADDR(5)  ///////////////////////////////////////////////////  // VITA RX CTRL regs  /////////////////////////////////////////////////// +#define UE_REG_CTRL_RX_ADDR(n)           (UE_REG_SETTINGS_BASE_ADDR(0) + (4*(n)))  // The following 3 are logically a single command register.  // They are clocked into the underlying fifo when time_ticks is written. -#define UE_REG_CTRL_RX_STREAM_CMD        UE_REG_SR_ADDR(8) // {now, chain, num_samples(30) -#define UE_REG_CTRL_RX_TIME_SECS         UE_REG_SR_ADDR(9) -#define UE_REG_CTRL_RX_TIME_TICKS        UE_REG_SR_ADDR(10) -#define UE_REG_CTRL_RX_CLEAR_OVERRUN     UE_REG_SR_ADDR(11) // write anything to clear overrun -#define UE_REG_CTRL_RX_VRT_HEADER        UE_REG_SR_ADDR(12) // word 0 of packet.  FPGA fills in packet counter -#define UE_REG_CTRL_RX_VRT_STREAM_ID     UE_REG_SR_ADDR(13) // word 1 of packet. -#define UE_REG_CTRL_RX_VRT_TRAILER       UE_REG_SR_ADDR(14) -#define UE_REG_CTRL_RX_NSAMPS_PER_PKT    UE_REG_SR_ADDR(15) -#define UE_REG_CTRL_RX_NCHANNELS         UE_REG_SR_ADDR(16) // 1 in basic case, up to 4 for vector sources +#define UE_REG_CTRL_RX_STREAM_CMD        UE_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30) +#define UE_REG_CTRL_RX_TIME_SECS         UE_REG_CTRL_RX_ADDR(1) +#define UE_REG_CTRL_RX_TIME_TICKS        UE_REG_CTRL_RX_ADDR(2) +#define UE_REG_CTRL_RX_CLEAR             UE_REG_CTRL_RX_ADDR(3) // write anything to clear +#define UE_REG_CTRL_RX_VRT_HEADER        UE_REG_CTRL_RX_ADDR(4) // word 0 of packet.  FPGA fills in packet counter +#define UE_REG_CTRL_RX_VRT_STREAM_ID     UE_REG_CTRL_RX_ADDR(5) // word 1 of packet. +#define UE_REG_CTRL_RX_VRT_TRAILER       UE_REG_CTRL_RX_ADDR(6) +#define UE_REG_CTRL_RX_NSAMPS_PER_PKT    UE_REG_CTRL_RX_ADDR(7) +#define UE_REG_CTRL_RX_NCHANNELS         UE_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources  /////////////////////////////////////////////////  // DSP TX Regs  //////////////////////////////////////////////// -#define UE_REG_DSP_TX_FREQ         UE_REG_SR_ADDR(17) -#define UE_REG_DSP_TX_SCALE_IQ     UE_REG_SR_ADDR(18) // {scale_i,scale_q} -#define UE_REG_DSP_TX_INTERP_RATE  UE_REG_SR_ADDR(19) -#define UE_REG_DSP_TX_UNUSED       UE_REG_SR_ADDR(20) -#define UE_REG_DSP_TX_MUX          UE_REG_SR_ADDR(21) +#define UE_REG_DSP_TX_ADDR(n)      (UE_REG_SETTINGS_BASE_ADDR(32) + (4*(n))) +#define UE_REG_DSP_TX_FREQ         UE_REG_DSP_TX_ADDR(0) +#define UE_REG_DSP_TX_SCALE_IQ     UE_REG_DSP_TX_ADDR(1) // {scale_i,scale_q} +#define UE_REG_DSP_TX_INTERP_RATE  UE_REG_DSP_TX_ADDR(2) +#define UE_REG_DSP_TX_UNUSED       UE_REG_DSP_TX_ADDR(3) +#define UE_REG_DSP_TX_MUX          UE_REG_DSP_TX_ADDR(4)  /////////////////////////////////////////////////  // VITA TX CTRL regs  //////////////////////////////////////////////// -#define UE_REG_CTRL_TX_NCHANNELS         UE_REG_SR_ADDR(24) -#define UE_REG_CTRL_TX_CLEAR_UNDERRUN    UE_REG_SR_ADDR(25) -#define UE_REG_CTRL_TX_REPORT_SID        UE_REG_SR_ADDR(26) -#define UE_REG_CTRL_TX_POLICY            UE_REG_SR_ADDR(27) +#define UE_REG_CTRL_TX_ADDR(n)           (UE_REG_SETTINGS_BASE_ADDR(24) + (4*(n))) +#define UE_REG_CTRL_TX_NCHANNELS         UE_REG_CTRL_TX_ADDR(0) +#define UE_REG_CTRL_TX_CLEAR             UE_REG_CTRL_TX_ADDR(1) +#define UE_REG_CTRL_TX_REPORT_SID        UE_REG_CTRL_TX_ADDR(2) +#define UE_REG_CTRL_TX_POLICY            UE_REG_CTRL_TX_ADDR(3)  #define UE_FLAG_CTRL_TX_POLICY_WAIT          (0x1 << 0)  #define UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET   (0x1 << 1) @@ -189,11 +202,12 @@     *     * </pre>     */ -#define UE_REG_TIME64_SECS  UE_REG_SR_ADDR(28)  // value to set absolute secs to on next PPS -#define UE_REG_TIME64_TICKS UE_REG_SR_ADDR(29)  // value to set absolute ticks to on next PPS -#define UE_REG_TIME64_FLAGS UE_REG_SR_ADDR(30)  // flags - see chart above -#define UE_REG_TIME64_IMM   UE_REG_SR_ADDR(31)  // set immediate (0=latch on next pps, 1=latch immediate, default=0) -#define UE_REG_TIME64_TPS   UE_REG_SR_ADDR(31)  // clock ticks per second (counter rollover) +#define UE_REG_TIME64_ADDR(n)     (UE_REG_SETTINGS_BASE_ADDR(40) + (4*(n))) +#define UE_REG_TIME64_SECS        UE_REG_TIME64_ADDR(0)  // value to set absolute secs to on next PPS +#define UE_REG_TIME64_TICKS       UE_REG_TIME64_ADDR(1)  // value to set absolute ticks to on next PPS +#define UE_REG_TIME64_FLAGS       UE_REG_TIME64_ADDR(2)  // flags - see chart above +#define UE_REG_TIME64_IMM         UE_REG_TIME64_ADDR(3)  // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define UE_REG_TIME64_TPS         UE_REG_TIME64_ADDR(4)  // clock ticks per second (counter rollover)  //pps flags (see above)  #define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0)  | 
