summaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp88
1 files changed, 78 insertions, 10 deletions
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index c38b006b0..4a5786aa4 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -15,6 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+static const bool rfx_debug = true;
+
// IO Pin functions
#define POWER_UP (1 << 7) // Low enables power supply
#define ANT_SW (1 << 6) // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2
@@ -39,6 +41,7 @@
#include <uhd/usrp/dboard_manager.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
+#include <boost/math/special_functions/round.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -215,25 +218,85 @@ double rfx_xcvr::set_lo_freq(
dboard_iface::unit_t unit,
double target_freq
){
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: target frequency %f Mhz"
+ ) % (target_freq/100e6) << std::endl;
+
//clip the input
target_freq = std::clip(target_freq, _freq_range.min, _freq_range.max);
+ if (_div2[unit]) target_freq *= 2;
- //load the registers
- adf4360_regs_t regs;
+ //map prescalers to the register enums
+ static const uhd::dict<int, adf4360_regs_t::prescaler_value_t> prescaler_to_enum = map_list_of
+ (8, adf4360_regs_t::PRESCALER_VALUE_8_9)
+ (16, adf4360_regs_t::PRESCALER_VALUE_16_17)
+ (32, adf4360_regs_t::PRESCALER_VALUE_32_33)
+ ;
- if (_div2[unit]) target_freq *= 2;
- regs.divide_by_2_output = (_div2[unit])?
- adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
- adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
+ //calculate the following values
+ // fvco = [P*B + A] * fref/R
+ // fvco*R/fref = P*B + A = N
+ int A, B, P, R; double N;
+ static const int
+ B_min = 3, B_max = 8191,
+ A_min = 0, A_max = 31,
+ P_min = 8, P_max = 32;
+ static const int
+ N_min = P_min*B_min + A_min,
+ N_max = P_max*B_max + A_max;
+ double ref_freq = this->get_iface()->get_clock_rate(unit);
+ double ratio = target_freq/ref_freq;
+
+ for(R = 1; R < 11; R++){
+ //increment R and see if this allows for a large enough N
+ N = ratio*R;
+ if (N < N_min) continue;
+ N = std::clip<double>(N, N_min, N_max);
+ break;
+ }
- //TODO
+ //discover the best value for P, B, and A
+ BOOST_FOREACH(P, prescaler_to_enum.keys()){
+ B = int(std::floor(N/P));
+ if (B > B_max) continue;
+ B = std::clip(B, B_min, B_max);
+ A = boost::math::iround(N - P*B);
+ A = std::clip(A, A_min, A_max);
+ break;
+ }
+ //load the register values
+ adf4360_regs_t regs;
+ regs.core_power_level = adf4360_regs_t::CORE_POWER_LEVEL_10MA;
+ regs.counter_operation = adf4360_regs_t::COUNTER_OPERATION_NORMAL;
+ regs.muxout_control = adf4360_regs_t::MUXOUT_CONTROL_DLD;
+ regs.phase_detector_polarity = adf4360_regs_t::PHASE_DETECTOR_POLARITY_POS;
+ regs.charge_pump_output = adf4360_regs_t::CHARGE_PUMP_OUTPUT_NORMAL;
+ regs.cp_gain_0 = adf4360_regs_t::CP_GAIN_0_SET1;
+ regs.mute_till_ld = adf4360_regs_t::MUTE_TILL_LD_ENB;
+ regs.output_power_level = adf4360_regs_t::OUTPUT_POWER_LEVEL_3_5MA;
+ regs.current_setting1 = adf4360_regs_t::CURRENT_SETTING1_0_31MA;
+ regs.current_setting2 = adf4360_regs_t::CURRENT_SETTING2_0_31MA;
+ regs.power_down = adf4360_regs_t::POWER_DOWN_NORMAL_OP;
+ regs.prescaler_value = prescaler_to_enum[P];
+ regs.a_counter = A;
+ regs.b_counter = B;
+ regs.cp_gain_1 = adf4360_regs_t::CP_GAIN_1_SET1;
+ regs.divide_by_2_output = (_div2[unit])?
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
+ adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
+ regs.divide_by_2_prescaler = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
+ regs.r_counter = R;
+ regs.ablpw = adf4360_regs_t::ABLPW_3_0NS;
+ regs.lock_detect_precision = adf4360_regs_t::LOCK_DETECT_PRECISION_5CYCLES;
+ regs.test_mode_bit = 0;
+ regs.band_select_clock_div = adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8;
//write the registers
- std::vector<adf4360_regs_t::addr_t> addrs = list_of
+ std::vector<adf4360_regs_t::addr_t> addrs = list_of //correct power-up sequence to write registers (R, C, N)
+ (adf4360_regs_t::ADDR_RCOUNTER)
(adf4360_regs_t::ADDR_CONTROL)
(adf4360_regs_t::ADDR_NCOUNTER)
- (adf4360_regs_t::ADDR_RCOUNTER)
;
BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){
this->get_iface()->write_spi(
@@ -243,7 +306,12 @@ double rfx_xcvr::set_lo_freq(
}
//return the actual frequency
- return target_freq; //TODO... and remember to check div2
+ double actual_freq = double(P*B + A) * ref_freq / double(R);
+ if (_div2[unit]) actual_freq /= 2;
+ if (rfx_debug) std::cerr << boost::format(
+ "RFX tune: actual frequency %f Mhz"
+ ) % (actual_freq/100e6) << std::endl;
+ return actual_freq;
}
/***********************************************************************