From fa96b25b99dbd19ac0689cab9bcab84063287ad3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 10 Apr 2010 07:20:16 -0700 Subject: moved regs generator to ic reg maps folder, others will go there as well --- host/lib/ic_reg_maps/gen_adf4360_regs.py | 169 +++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100755 host/lib/ic_reg_maps/gen_adf4360_regs.py (limited to 'host/lib/ic_reg_maps/gen_adf4360_regs.py') diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py new file mode 100755 index 000000000..702c3060f --- /dev/null +++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Copyright 2008,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either asversion 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +import re +import sys +from Cheetah.Template import Template +def parse_tmpl(_tmpl_text, **kwargs): + return str(Template(_tmpl_text, kwargs)) + +######################################################################## +# Template for raw text data describing registers +# name addr[bit range inclusive] default optional enums +######################################################################## +REGS_DATA_TMPL="""\ +######################################################################## +## address 0 +######################################################################## +core_power_level 0[2:3] 0 5ma, 10ma, 15ma, 20ma +counter_reset 0[4] 0 normal, reset +muxout_control 0[5:7] 0 3state, dld, ndiv, dvdd, rdiv, nchan_od_ld, sdo, dgnd +phase_detector_polarity 0[8] 0 neg, pos +cp_three_state 0[9] 0 normal, 3state +cp_gain_0 0[10] 0 set1, set2 +mute_till_ld 0[11] 0 dis, enb +output_power_level 0[12:13] 0 3_5ma, 5_0ma, 7_5ma, 11_0ma +#set $current_setting_enums = "0_31, 0_62, 0_93, 1_25, 1_56, 1_87, 2_18, 2_50" +current_setting1 0[14:16] 0 $current_setting_enums +current_setting2 0[17:19] 0 $current_setting_enums +power_down 0[20:21] 0 normal_op=0, async_pd=1, sync_pd=3 +prescaler_value 0[22:23] 0 8_9, 16_17, 32_33 +######################################################################## +## address 2 +######################################################################## +a_counter 2[2:6] 0 +b_counter 2[8:20] 0 +cp_gain_1 2[21] 0 set1, set2 +divide_by_2_output 2[22] 0 fund, div2 +divide_by_2_prescaler 2[23] 0 fund, div2 +######################################################################## +## address 1 +######################################################################## +r_counter 1[2:15] 0 +ablpw 1[16:17] 0 3_0ns, 1_3ns, 6_0ns +lock_detect_precision 1[18] 0 3cycles, 5cycles +test_mode_bit 1[19] 0 +band_select_clock_div 1[20:21] 0 1, 2, 4, 8 +""" + +######################################################################## +# Header and Source templates below +######################################################################## +HEADER_TEXT=""" +#import time + +/*********************************************************************** + * This file was generated by $file on $time.strftime("%c") + **********************************************************************/ + +\#ifndef INCLUDED_ADF4360_REGS_HPP +\#define INCLUDED_ADF4360_REGS_HPP + +\#include + +struct adf4360_regs_t{ +#for $reg in $regs + #if $reg.get_enums() + enum $(reg.get_name())_t{ + #for $i, $enum in enumerate($reg.get_enums()) + #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' + $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma + #end for + } $reg.get_name(); + #else + boost::$reg.get_stdint_type() $reg.get_name(); + #end if +#end for + + adf4360_regs_t(void){ +#for $reg in $regs + $reg.get_name() = $reg.get_default(); +#end for + } + + enum addr_t{ + ADDR_CONTROL = 0, + ADDR_NCOUNTER = 2, + ADDR_RCOUNTER = 1 + }; + + boost::uint32_t get_reg(addr_t addr){ + boost::uint32_t reg = addr & 0x3; + switch(addr){ + #for $addr in (0, 1, 2) + case $addr: + #for $reg in filter(lambda r: r.get_addr() == addr, $regs) + reg |= (boost::uint32_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift(); + #end for + break; + #end for + } + return reg; + } +}; + +\#endif /* INCLUDED_ADF4360_REGS_HPP */ +""" + +class reg: + def __init__(self, reg_des): + x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) + name, addr, bit_range, default, enums = x.groups() + + #store variables + self._name = name + self._addr = int(addr) + if ':' in bit_range: self._addr_spec = map(int, bit_range.split(':')) + else: self._addr_spec = int(bit_range), int(bit_range) + self._default = int(default) + + #extract enum + self._enums = list() + if enums: + enum_val = 0 + for enum_str in map(str.strip, enums.split(',')): + if '=' in enum_str: + enum_name, enum_val = enum_str.split('=') + enum_val = int(enum_val) + else: enum_name = enum_str + self._enums.append((enum_name, enum_val)) + enum_val += 1 + + def get_addr(self): return self._addr + def get_enums(self): return self._enums + def get_name(self): return self._name + def get_default(self): + for key, val in self.get_enums(): + if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) + return self._default + def get_stdint_type(self): + if self.get_bit_width() <= 8: return 'uint8_t' + if self.get_bit_width() <= 16: return 'uint16_t' + if self.get_bit_width() <= 32: return 'uint32_t' + if self.get_bit_width() <= 64: return 'uint64_t' + raise Exception, 'too damn big' + def get_shift(self): return self._addr_spec[0] + def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) + def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 + +if __name__ == '__main__': + regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines()) + open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__)) -- cgit v1.2.3 From 0718961ed11dc82b9430d9fa5da985f7ffcd5d2a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 15 Apr 2010 16:11:42 -0700 Subject: work on rfx registers --- host/lib/ic_reg_maps/gen_adf4360_regs.py | 6 +-- host/lib/usrp/dboard/db_rfx.cpp | 88 ++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 13 deletions(-) (limited to 'host/lib/ic_reg_maps/gen_adf4360_regs.py') diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py index e7c2c9435..bcad1ffd3 100755 --- a/host/lib/ic_reg_maps/gen_adf4360_regs.py +++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py @@ -37,14 +37,14 @@ REGS_DATA_TMPL="""\ ## address 0 ######################################################################## core_power_level 0[2:3] 0 5ma, 10ma, 15ma, 20ma -counter_reset 0[4] 0 normal, reset +counter_operation 0[4] 0 normal, reset muxout_control 0[5:7] 0 3state, dld, ndiv, dvdd, rdiv, nchan_od_ld, sdo, dgnd phase_detector_polarity 0[8] 0 neg, pos -cp_three_state 0[9] 0 normal, 3state +charge_pump_output 0[9] 0 normal, 3state cp_gain_0 0[10] 0 set1, set2 mute_till_ld 0[11] 0 dis, enb output_power_level 0[12:13] 0 3_5ma, 5_0ma, 7_5ma, 11_0ma -#set $current_setting_enums = "0_31, 0_62, 0_93, 1_25, 1_56, 1_87, 2_18, 2_50" +#set $current_setting_enums = ', '.join(map(lambda x: x+"ma", "0_31 0_62 0_93 1_25 1_56 1_87 2_18 2_50".split())) current_setting1 0[14:16] 0 $current_setting_enums current_setting2 0[17:19] 0 $current_setting_enums power_down 0[20:21] 0 normal_op=0, async_pd=1, sync_pd=3 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 . // +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 #include #include +#include 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 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(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 addrs = list_of + std::vector 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; } /*********************************************************************** -- cgit v1.2.3