diff options
| -rw-r--r-- | host/lib/usrp/usrp_e/clock_ctrl.cpp | 290 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/clock_ctrl.hpp | 27 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e/dboard_iface.cpp | 53 | 
3 files changed, 226 insertions, 144 deletions
| diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp index e37b17a54..36799ef63 100644 --- a/host/lib/usrp/usrp_e/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp @@ -17,6 +17,7 @@  #include "clock_ctrl.hpp"  #include "ad9522_regs.hpp" +#include <uhd/utils/assert.hpp>  #include <boost/cstdint.hpp>  #include "usrp_e_regs.hpp" //spi slave constants  #include <boost/assign/list_of.hpp> @@ -26,21 +27,171 @@  using namespace uhd; +template <typename div_type> static void set_clock_divider( +    size_t divider, div_type &low, div_type &high +){ +    high = divider/2; +    low = divider-high; +} + +/*********************************************************************** + * Constants + **********************************************************************/ +static const double master_clock_rate = 320e6; +static const size_t fpga_clock_divider = 5; //64 MHz +static const size_t codec_clock_divider = 5; //64 MHz +  /***********************************************************************   * Clock Control Implementation   **********************************************************************/  class usrp_e_clock_ctrl_impl : public usrp_e_clock_ctrl{  public: -    //structors -    usrp_e_clock_ctrl_impl(usrp_e_iface::sptr iface); -    ~usrp_e_clock_ctrl_impl(void); +    usrp_e_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; +        set_clock_divider(fpga_clock_divider, +            _ad9522_regs.divider0_low_cycles, +            _ad9522_regs.divider0_high_cycles +        ); + +        //setup codec clock +        _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; +        set_clock_divider(codec_clock_divider, +            _ad9522_regs.divider1_low_cycles, +            _ad9522_regs.divider1_high_cycles +        ); + +        //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); +    } + +    ~usrp_e_clock_ctrl_impl(void){ +        this->enable_rx_dboard_clock(false); +        this->enable_tx_dboard_clock(false); +    } -    void enable_rx_dboard_clock(bool enb); -    void enable_tx_dboard_clock(bool enb); +    double get_fpga_clock_rate(void){ +        return master_clock_rate/fpga_clock_divider; +    } -    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();} +    /*********************************************************************** +     * RX Dboard Clock Control (output 9, divider 3) +     **********************************************************************/ +    void enable_rx_dboard_clock(bool enb){ +        _ad9522_regs.out9_format = ad9522_regs_t::OUT9_FORMAT_CMOS; +        _ad9522_regs.out9_cmos_configuration = (enb)? +            ad9522_regs_t::OUT9_CMOS_CONFIGURATION_B_ON : +            ad9522_regs_t::OUT9_CMOS_CONFIGURATION_OFF; +        this->send_reg(0x0F9); +        this->latch_regs(); +    } + +    std::vector<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); +        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(rate/master_clock_rate); +        //bypass when the divider ratio is one +        _ad9522_regs.divider3_bypass = (divider == 1)? 1 : 0; +        this->send_reg(0x19a); +        //set the divider registers +        set_clock_divider(divider, +            _ad9522_regs.divider3_low_cycles, +            _ad9522_regs.divider3_high_cycles +        ); +        this->send_reg(0x199); +        this->latch_regs(); +    } + +    /*********************************************************************** +     * TX Dboard Clock Control (output 6, divider 2) +     **********************************************************************/ +    void enable_tx_dboard_clock(bool enb){ +        _ad9522_regs.out6_format = ad9522_regs_t::OUT6_FORMAT_CMOS; +        _ad9522_regs.out6_cmos_configuration = (enb)? +            ad9522_regs_t::OUT6_CMOS_CONFIGURATION_B_ON : +            ad9522_regs_t::OUT6_CMOS_CONFIGURATION_OFF; +        this->send_reg(0x0F6); +        this->latch_regs(); +    } + +    std::vector<double> get_tx_dboard_clock_rates(void){ +        return get_rx_dboard_clock_rates(); //same master clock, same dividers... +    } + +    void set_tx_dboard_clock_rate(double rate){ +        assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate"); +        size_t divider = size_t(rate/master_clock_rate); +        //bypass when the divider ratio is one +        _ad9522_regs.divider2_bypass = (divider == 1)? 1 : 0; +        this->send_reg(0x197); +        //set the divider registers +        set_clock_divider(divider, +            _ad9522_regs.divider2_low_cycles, +            _ad9522_regs.divider2_high_cycles +        ); +        this->send_reg(0x196); +        this->latch_regs(); +    }  private:      usrp_e_iface::sptr _iface; @@ -50,122 +201,17 @@ private:          _ad9522_regs.io_update = 1;          this->send_reg(0x232);      } -    void send_reg(boost::uint16_t addr); -}; -/*********************************************************************** - * Clock Control Methods - **********************************************************************/ -usrp_e_clock_ctrl_impl::usrp_e_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); -        } +    void 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*/ +        );      } -    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); -} - -usrp_e_clock_ctrl_impl::~usrp_e_clock_ctrl_impl(void){ -    this->enable_rx_dboard_clock(false); -    this->enable_tx_dboard_clock(false); -} - -void usrp_e_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 usrp_e_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 usrp_e_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 diff --git a/host/lib/usrp/usrp_e/clock_ctrl.hpp b/host/lib/usrp/usrp_e/clock_ctrl.hpp index 692b9eb0e..3b5103ed1 100644 --- a/host/lib/usrp/usrp_e/clock_ctrl.hpp +++ b/host/lib/usrp/usrp_e/clock_ctrl.hpp @@ -21,6 +21,7 @@  #include "usrp_e_iface.hpp"  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp> +#include <vector>  /*!   * The usrp-e clock control: @@ -45,16 +46,30 @@ public:      virtual double get_fpga_clock_rate(void) = 0;      /*! -     * Get the rate of the dboard clock clock line. -     * \return the dboard clock rate in Hz +     * Get the possible rates of the rx dboard clock. +     * \return a vector of clock rates in Hz       */ -    virtual double get_rx_dboard_clock_rate(void) = 0; +    virtual std::vector<double> get_rx_dboard_clock_rates(void) = 0;      /*! -     * Get the rate of the dboard clock clock line. -     * \return the dboard clock rate in Hz +     * Get the possible rates of the tx dboard clock. +     * \return a vector of clock rates in Hz       */ -    virtual double get_tx_dboard_clock_rate(void) = 0; +    virtual std::vector<double> get_tx_dboard_clock_rates(void) = 0; + +    /*! +     * Set the rx dboard clock rate to a possible rate. +     * \param rate the new clock rate in Hz +     * \throw exception when rate cannot be achieved +     */ +    virtual void set_rx_dboard_clock_rate(double rate) = 0; + +    /*! +     * Set the tx dboard clock rate to a possible rate. +     * \param rate the new clock rate in Hz +     * \throw exception when rate cannot be achieved +     */ +    virtual void set_tx_dboard_clock_rate(double rate) = 0;      /*!       * Enable/disable the rx dboard clock. diff --git a/host/lib/usrp/usrp_e/dboard_iface.cpp b/host/lib/usrp/usrp_e/dboard_iface.cpp index 594f2a23e..ce00cd40d 100644 --- a/host/lib/usrp/usrp_e/dboard_iface.cpp +++ b/host/lib/usrp/usrp_e/dboard_iface.cpp @@ -40,14 +40,18 @@ public:          _iface = iface;          _clock = clock;          _codec = codec; + +        //init the clock rate shadows +        this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); +        this->set_clock_rate(UNIT_TX, _clock->get_fpga_clock_rate());      }      ~usrp_e_dboard_iface(void){          /* NOP */      } -    void write_aux_dac(unit_t, int, float); -    float read_aux_adc(unit_t, int); +    void write_aux_dac(unit_t, aux_dac_t, float); +    float read_aux_adc(unit_t, aux_adc_t);      void set_pin_ctrl(unit_t, boost::uint16_t);      void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); @@ -72,6 +76,8 @@ public:          size_t num_bits      ); +    void set_clock_rate(unit_t, double); +    std::vector<double> get_clock_rates(unit_t);      double get_clock_rate(unit_t);      void set_clock_enabled(unit_t, bool); @@ -79,6 +85,7 @@ private:      usrp_e_iface::sptr _iface;      usrp_e_clock_ctrl::sptr _clock;      usrp_e_codec_ctrl::sptr _codec; +    uhd::dict<unit_t, double> _clock_rates;  };  /*********************************************************************** @@ -95,12 +102,24 @@ dboard_iface::sptr make_usrp_e_dboard_iface(  /***********************************************************************   * Clock Rates   **********************************************************************/ -double usrp_e_dboard_iface::get_clock_rate(unit_t unit){ +void usrp_e_dboard_iface::set_clock_rate(unit_t unit, double rate){ +    _clock_rates[unit] = rate;      switch(unit){ -    case UNIT_RX: return _clock->get_rx_dboard_clock_rate(); -    case UNIT_TX: return _clock->get_tx_dboard_clock_rate(); +    case UNIT_RX: return _clock->set_rx_dboard_clock_rate(rate); +    case UNIT_TX: return _clock->set_tx_dboard_clock_rate(rate);      } -    UHD_ASSERT_THROW(false); +} + +std::vector<double> usrp_e_dboard_iface::get_clock_rates(unit_t unit){ +    switch(unit){ +    case UNIT_RX: return _clock->get_rx_dboard_clock_rates(); +    case UNIT_TX: return _clock->get_tx_dboard_clock_rates(); +    default: UHD_THROW_INVALID_CODE_PATH(); +    } +} + +double usrp_e_dboard_iface::get_clock_rate(unit_t unit){ +    return _clock_rates[unit];  }  void usrp_e_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ @@ -212,26 +231,28 @@ byte_vector_t usrp_e_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_byte  /***********************************************************************   * Aux DAX/ADC   **********************************************************************/ -void usrp_e_dboard_iface::write_aux_dac(dboard_iface::unit_t, int which, float value){ +void usrp_e_dboard_iface::write_aux_dac(dboard_iface::unit_t, aux_dac_t which, float value){      //same aux dacs for each unit -    static const uhd::dict<int, usrp_e_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of -        (0, usrp_e_codec_ctrl::AUX_DAC_A) (1, usrp_e_codec_ctrl::AUX_DAC_B) -        (2, usrp_e_codec_ctrl::AUX_DAC_C) (3, usrp_e_codec_ctrl::AUX_DAC_D) +    static const uhd::dict<aux_dac_t, usrp_e_codec_ctrl::aux_dac_t> which_to_aux_dac = map_list_of +        (AUX_DAC_A, usrp_e_codec_ctrl::AUX_DAC_A) +        (AUX_DAC_B, usrp_e_codec_ctrl::AUX_DAC_B) +        (AUX_DAC_C, usrp_e_codec_ctrl::AUX_DAC_C) +        (AUX_DAC_D, usrp_e_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){ +float usrp_e_dboard_iface::read_aux_adc(dboard_iface::unit_t unit, aux_adc_t which){      static const uhd::dict< -        unit_t, uhd::dict<int, usrp_e_codec_ctrl::aux_adc_t> +        unit_t, uhd::dict<aux_adc_t, usrp_e_codec_ctrl::aux_adc_t>      > unit_to_which_to_aux_adc = map_list_of          (UNIT_RX, map_list_of -            (0, usrp_e_codec_ctrl::AUX_ADC_A1) -            (1, usrp_e_codec_ctrl::AUX_ADC_B1) +            (AUX_ADC_A, usrp_e_codec_ctrl::AUX_ADC_A1) +            (AUX_ADC_B, usrp_e_codec_ctrl::AUX_ADC_B1)          )          (UNIT_TX, map_list_of -            (0, usrp_e_codec_ctrl::AUX_ADC_A2) -            (1, usrp_e_codec_ctrl::AUX_ADC_B2) +            (AUX_ADC_A, usrp_e_codec_ctrl::AUX_ADC_A2) +            (AUX_ADC_B, usrp_e_codec_ctrl::AUX_ADC_B2)          )      ;      return _codec->read_aux_adc(unit_to_which_to_aux_adc[unit][which]); | 
