diff options
author | Josh Blum <josh@joshknows.com> | 2010-06-21 19:39:15 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-06-21 19:39:15 +0000 |
commit | df6cc603fd5e9dc34665385ac84b94eadf074074 (patch) | |
tree | 1e7a5574c4dbff0424b629434312affde7408766 /host | |
parent | a9319441d688620e18d5621cc59b98769e670468 (diff) | |
download | uhd-df6cc603fd5e9dc34665385ac84b94eadf074074.tar.gz uhd-df6cc603fd5e9dc34665385ac84b94eadf074074.tar.bz2 uhd-df6cc603fd5e9dc34665385ac84b94eadf074074.zip |
usrp-e: added clock rate control to dboard iface and clock control impl
Diffstat (limited to 'host')
-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]); |