aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/usrp2/clock_ctrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/usrp2/clock_ctrl.cpp')
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp145
1 files changed, 100 insertions, 45 deletions
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index 232f3b32a..428d5539b 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -18,6 +18,7 @@
#include "clock_ctrl.hpp"
#include "ad9510_regs.hpp"
#include "usrp2_regs.hpp" //spi slave constants
+#include "usrp2_clk_regs.hpp"
#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
@@ -32,9 +33,10 @@ class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{
public:
usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){
_iface = iface;
+ clk_regs = usrp2_clk_regs_t(_iface->get_rev());
_ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
- this->write_reg(0x09);
+ this->write_reg(clk_regs.pll_3);
// Setup the clock registers to 100MHz:
// This was already done by the firmware (or the host couldnt communicate).
@@ -44,20 +46,20 @@ public:
_ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL;
_ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2;
- this->write_reg(0x0A);
+ this->write_reg(clk_regs.pll_4);
_ad9510_regs.acounter = 0;
- this->write_reg(0x04);
+ this->write_reg(clk_regs.acounter);
_ad9510_regs.bcounter_msb = 0;
_ad9510_regs.bcounter_lsb = 5;
- this->write_reg(0x05);
- this->write_reg(0x06);
+ this->write_reg(clk_regs.bcounter_msb);
+ this->write_reg(clk_regs.bcounter_lsb);
_ad9510_regs.ref_counter_msb = 0;
_ad9510_regs.ref_counter_lsb = 1; // r divider = 1
- this->write_reg(0x0B);
- this->write_reg(0x0C);
+ this->write_reg(clk_regs.ref_counter_msb);
+ this->write_reg(clk_regs.ref_counter_lsb);
/* regs will be updated in commands below */
@@ -84,16 +86,13 @@ public:
}
void enable_mimo_clock_out(bool enb){
- boost::uint16_t rev = boost::lexical_cast<boost::uint16_t>(_iface->mb_eeprom["rev"]);
- boost::uint8_t rev_hi = boost::uint8_t(rev >> 8);
-
//calculate the low and high dividers
size_t divider = size_t(this->get_master_clock_rate()/10e6);
size_t high = divider/2;
size_t low = divider - high;
- switch(rev_hi){
- case 3: //clock 2
+ switch(clk_regs.exp){
+ case 2: //U2 rev 3
_ad9510_regs.power_down_lvpecl_out2 = enb?
ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL :
ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD;
@@ -102,11 +101,9 @@ public:
_ad9510_regs.divider_low_cycles_out2 = low - 1;
_ad9510_regs.divider_high_cycles_out2 = high - 1;
_ad9510_regs.bypass_divider_out2 = 0;
- this->write_reg(0x3e);
- this->write_reg(0x4c);
break;
- case 4: //clock 5
+ case 5: //U2 rev 4
_ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_LVDS;
_ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA;
@@ -114,14 +111,23 @@ public:
_ad9510_regs.divider_low_cycles_out5 = low - 1;
_ad9510_regs.divider_high_cycles_out5 = high - 1;
_ad9510_regs.bypass_divider_out5 = 0;
- this->write_reg(0x41);
- this->write_reg(0x52);
+ break;
+
+ case 6: //U2+
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_LVDS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ //set the registers (divider - 1)
+ _ad9510_regs.divider_low_cycles_out6 = low - 1;
+ _ad9510_regs.divider_high_cycles_out6 = high - 1;
+ _ad9510_regs.bypass_divider_out5 = 0;
break;
- //TODO FIXME do i want to throw, what about uninitialized boards?
- //default: throw std::runtime_error("unknown rev hi in mboard eeprom");
- default: std::cerr << "unknown rev hi: " << rev_hi << std::endl;
+ default:
+ break;
}
+ this->write_reg(clk_regs.output(clk_regs.exp));
+ this->write_reg(clk_regs.div_lo(clk_regs.exp));
this->update_regs();
}
@@ -130,7 +136,7 @@ public:
_ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
_ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
- this->write_reg(0x43);
+ this->write_reg(clk_regs.output(clk_regs.rx_db));
this->update_regs();
}
@@ -146,8 +152,8 @@ public:
_ad9510_regs.divider_low_cycles_out7 = low - 1;
_ad9510_regs.divider_high_cycles_out7 = high - 1;
//write the registers
- this->write_reg(0x56);
- this->write_reg(0x57);
+ this->write_reg(clk_regs.div_lo(clk_regs.rx_db));
+ this->write_reg(clk_regs.div_hi(clk_regs.rx_db));
this->update_regs();
}
@@ -157,12 +163,22 @@ public:
return rates;
}
- //uses output clock 6 (cmos)
+ //uses output clock 6 (cmos) on USRP2 and output clock 5 (cmos) on USRP2+
void enable_tx_dboard_clock(bool enb){
- _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
- _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
- this->write_reg(0x42);
+ switch(clk_regs.tx_db) {
+ case 5: //USRP2+
+ _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_CMOS;
+ _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA;
+ break;
+ case 6: //USRP2
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ break;
+ }
+
+ this->write_reg(clk_regs.output(clk_regs.tx_db));
this->update_regs();
}
@@ -174,18 +190,44 @@ public:
//calculate the low and high dividers
size_t high = divider/2;
size_t low = divider - high;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out6 = low - 1;
- _ad9510_regs.divider_high_cycles_out6 = high - 1;
+
+ switch(clk_regs.tx_db) {
+ case 5: //USRP2+
+ _ad9510_regs.bypass_divider_out5 = (divider == 1)? 1 : 0;
+ _ad9510_regs.divider_low_cycles_out5 = low - 1;
+ _ad9510_regs.divider_high_cycles_out5 = high - 1;
+ break;
+ case 6: //USRP2
+ //bypass when the divider ratio is one
+ _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
+ //set the registers (divider - 1)
+ _ad9510_regs.divider_low_cycles_out6 = low - 1;
+ _ad9510_regs.divider_high_cycles_out6 = high - 1;
+ break;
+ }
+
//write the registers
- this->write_reg(0x54);
- this->write_reg(0x55);
+ this->write_reg(clk_regs.div_hi(clk_regs.tx_db));
+ this->write_reg(clk_regs.div_lo(clk_regs.tx_db));
this->update_regs();
}
std::vector<double> get_rates_tx_dboard_clock(void){
return get_rates_rx_dboard_clock(); //same master clock, same dividers...
}
+
+ void enable_test_clock(bool enb) {
+ _ad9510_regs.power_down_lvpecl_out0 = enb?
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_NORMAL :
+ ad9510_regs_t::POWER_DOWN_LVPECL_OUT0_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out0 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT0_810MV;
+ _ad9510_regs.divider_low_cycles_out0 = 0;
+ _ad9510_regs.divider_high_cycles_out0 = 0;
+ _ad9510_regs.bypass_divider_out0 = 1;
+ this->write_reg(0x3c);
+ this->write_reg(0x48);
+ this->write_reg(0x49);
+ }
/*!
* If we are to use an external reference, enable the charge pump.
@@ -197,7 +239,7 @@ public:
ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ;
_ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH;
_ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS;
- this->write_reg(0x08);
+ this->write_reg(clk_regs.pll_2);
this->update_regs();
}
@@ -220,33 +262,46 @@ private:
*/
void update_regs(void){
_ad9510_regs.update_registers = 1;
- this->write_reg(0x5a);
+ this->write_reg(clk_regs.update);
}
//uses output clock 3 (pecl)
+ //this is the same between USRP2 and USRP2+ and doesn't get a switch statement
void enable_dac_clock(bool enb){
_ad9510_regs.power_down_lvpecl_out3 = (enb)?
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
_ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
_ad9510_regs.bypass_divider_out3 = 1;
- this->write_reg(0x3F);
- this->write_reg(0x4F);
+ this->write_reg(clk_regs.output(clk_regs.dac));
+ this->write_reg(clk_regs.div_hi(clk_regs.dac));
this->update_regs();
}
- //uses output clock 4 (lvds)
+ //uses output clock 4 (lvds) on USRP2 and output clock 2 (lvpecl) on USRP2+
void enable_adc_clock(bool enb){
- _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
- _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
- _ad9510_regs.bypass_divider_out4 = 1;
- this->write_reg(0x40);
- this->write_reg(0x51);
+ switch(clk_regs.adc) {
+ case 2:
+ _ad9510_regs.power_down_lvpecl_out2 = enb? ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_500MV;
+ _ad9510_regs.bypass_divider_out2 = 1;
+ break;
+ case 4:
+ _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
+ _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ _ad9510_regs.bypass_divider_out4 = 1;
+ break;
+ }
+
+ this->write_reg(clk_regs.output(clk_regs.adc));
+ this->write_reg(clk_regs.div_hi(clk_regs.adc));
this->update_regs();
}
-
+
usrp2_iface::sptr _iface;
+
+ usrp2_clk_regs_t clk_regs;
ad9510_regs_t _ad9510_regs;
};