aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-06-21 19:39:15 +0000
committerJosh Blum <josh@joshknows.com>2010-06-21 19:39:15 +0000
commitdf6cc603fd5e9dc34665385ac84b94eadf074074 (patch)
tree1e7a5574c4dbff0424b629434312affde7408766 /host/lib
parenta9319441d688620e18d5621cc59b98769e670468 (diff)
downloaduhd-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/lib')
-rw-r--r--host/lib/usrp/usrp_e/clock_ctrl.cpp290
-rw-r--r--host/lib/usrp/usrp_e/clock_ctrl.hpp27
-rw-r--r--host/lib/usrp/usrp_e/dboard_iface.cpp53
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]);