From e6151334096167d1d26609f7233105020af91f40 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 6 Apr 2010 19:05:02 -0700 Subject: added code for adf4360 chip --- host/lib/usrp/dboard/adf4360_regs.hpp | 185 +++++++++++++++++++++++++++++++ host/lib/usrp/dboard/db_rfx.cpp | 29 ++++- host/lib/usrp/dboard/gen_adf4360_regs.py | 168 ++++++++++++++++++++++++++++ 3 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 host/lib/usrp/dboard/adf4360_regs.hpp create mode 100755 host/lib/usrp/dboard/gen_adf4360_regs.py diff --git a/host/lib/usrp/dboard/adf4360_regs.hpp b/host/lib/usrp/dboard/adf4360_regs.hpp new file mode 100644 index 000000000..309ff50e9 --- /dev/null +++ b/host/lib/usrp/dboard/adf4360_regs.hpp @@ -0,0 +1,185 @@ + + +/*********************************************************************** + * This file was generated by gen_adf4360_regs.py on Tue Apr 6 18:40:51 2010 + **********************************************************************/ + +#ifndef INCLUDED_ADF4360_REGS_HPP +#define INCLUDED_ADF4360_REGS_HPP + +#include + +struct adf4360_regs_t{ + enum core_power_level_t{ + CORE_POWER_LEVEL_5MA = 0, + CORE_POWER_LEVEL_10MA = 1, + CORE_POWER_LEVEL_15MA = 2, + CORE_POWER_LEVEL_20MA = 3 + } core_power_level; + enum counter_reset_t{ + COUNTER_RESET_NORMAL = 0, + COUNTER_RESET_RESET = 1 + } counter_reset; + enum muxout_control_t{ + MUXOUT_CONTROL_3STATE = 0, + MUXOUT_CONTROL_DLD = 1, + MUXOUT_CONTROL_NDIV = 2, + MUXOUT_CONTROL_DVDD = 3, + MUXOUT_CONTROL_RDIV = 4, + MUXOUT_CONTROL_NCHAN_OD_LD = 5, + MUXOUT_CONTROL_SDO = 6, + MUXOUT_CONTROL_DGND = 7 + } muxout_control; + enum phase_detector_polarity_t{ + PHASE_DETECTOR_POLARITY_NEG = 0, + PHASE_DETECTOR_POLARITY_POS = 1 + } phase_detector_polarity; + enum cp_three_state_t{ + CP_THREE_STATE_NORMAL = 0, + CP_THREE_STATE_3STATE = 1 + } cp_three_state; + enum cp_gain_0_t{ + CP_GAIN_0_SET1 = 0, + CP_GAIN_0_SET2 = 1 + } cp_gain_0; + enum mute_till_ld_t{ + MUTE_TILL_LD_DIS = 0, + MUTE_TILL_LD_ENB = 1 + } mute_till_ld; + enum output_power_level_t{ + OUTPUT_POWER_LEVEL_3_5MA = 0, + OUTPUT_POWER_LEVEL_5_0MA = 1, + OUTPUT_POWER_LEVEL_7_5MA = 2, + OUTPUT_POWER_LEVEL_11_0MA = 3 + } output_power_level; + enum current_setting1_t{ + CURRENT_SETTING1_0_31 = 0, + CURRENT_SETTING1_0_62 = 1, + CURRENT_SETTING1_0_93 = 2, + CURRENT_SETTING1_1_25 = 3, + CURRENT_SETTING1_1_56 = 4, + CURRENT_SETTING1_1_87 = 5, + CURRENT_SETTING1_2_18 = 6, + CURRENT_SETTING1_2_50 = 7 + } current_setting1; + enum current_setting2_t{ + CURRENT_SETTING2_0_31 = 0, + CURRENT_SETTING2_0_62 = 1, + CURRENT_SETTING2_0_93 = 2, + CURRENT_SETTING2_1_25 = 3, + CURRENT_SETTING2_1_56 = 4, + CURRENT_SETTING2_1_87 = 5, + CURRENT_SETTING2_2_18 = 6, + CURRENT_SETTING2_2_50 = 7 + } current_setting2; + enum power_down_t{ + POWER_DOWN_NORMAL_OP = 0, + POWER_DOWN_ASYNC_PD = 1, + POWER_DOWN_SYNC_PD = 3 + } power_down; + enum prescaler_value_t{ + PRESCALER_VALUE_8_9 = 0, + PRESCALER_VALUE_16_17 = 1, + PRESCALER_VALUE_32_33 = 2 + } prescaler_value; + boost::uint8_t a_counter; + boost::uint16_t b_counter; + enum cp_gain_1_t{ + CP_GAIN_1_SET1 = 0, + CP_GAIN_1_SET2 = 1 + } cp_gain_1; + enum divide_by_2_output_t{ + DIVIDE_BY_2_OUTPUT_FUND = 0, + DIVIDE_BY_2_OUTPUT_DIV2 = 1 + } divide_by_2_output; + enum divide_by_2_prescaler_t{ + DIVIDE_BY_2_PRESCALER_FUND = 0, + DIVIDE_BY_2_PRESCALER_DIV2 = 1 + } divide_by_2_prescaler; + boost::uint16_t r_counter; + enum ablpw_t{ + ABLPW_3_0NS = 0, + ABLPW_1_3NS = 1, + ABLPW_6_0NS = 2 + } ablpw; + enum lock_detect_precision_t{ + LOCK_DETECT_PRECISION_3CYCLES = 0, + LOCK_DETECT_PRECISION_5CYCLES = 1 + } lock_detect_precision; + boost::uint8_t test_mode_bit; + enum band_select_clock_div_t{ + BAND_SELECT_CLOCK_DIV_1 = 0, + BAND_SELECT_CLOCK_DIV_2 = 1, + BAND_SELECT_CLOCK_DIV_4 = 2, + BAND_SELECT_CLOCK_DIV_8 = 3 + } band_select_clock_div; + + adf4360_regs_t(void){ + core_power_level = CORE_POWER_LEVEL_5MA; + counter_reset = COUNTER_RESET_NORMAL; + muxout_control = MUXOUT_CONTROL_3STATE; + phase_detector_polarity = PHASE_DETECTOR_POLARITY_NEG; + cp_three_state = CP_THREE_STATE_NORMAL; + cp_gain_0 = CP_GAIN_0_SET1; + mute_till_ld = MUTE_TILL_LD_DIS; + output_power_level = OUTPUT_POWER_LEVEL_3_5MA; + current_setting1 = CURRENT_SETTING1_0_31; + current_setting2 = CURRENT_SETTING2_0_31; + power_down = POWER_DOWN_NORMAL_OP; + prescaler_value = PRESCALER_VALUE_8_9; + a_counter = 0; + b_counter = 0; + cp_gain_1 = CP_GAIN_1_SET1; + divide_by_2_output = DIVIDE_BY_2_OUTPUT_FUND; + divide_by_2_prescaler = DIVIDE_BY_2_PRESCALER_FUND; + r_counter = 0; + ablpw = ABLPW_3_0NS; + lock_detect_precision = LOCK_DETECT_PRECISION_3CYCLES; + test_mode_bit = 0; + band_select_clock_div = BAND_SELECT_CLOCK_DIV_1; + } + + 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){ + case 0: + reg |= (boost::uint32_t(core_power_level) & 0x3) << 2; + reg |= (boost::uint32_t(counter_reset) & 0x1) << 4; + reg |= (boost::uint32_t(muxout_control) & 0x7) << 5; + reg |= (boost::uint32_t(phase_detector_polarity) & 0x1) << 8; + reg |= (boost::uint32_t(cp_three_state) & 0x1) << 9; + reg |= (boost::uint32_t(cp_gain_0) & 0x1) << 10; + reg |= (boost::uint32_t(mute_till_ld) & 0x1) << 11; + reg |= (boost::uint32_t(output_power_level) & 0x3) << 12; + reg |= (boost::uint32_t(current_setting1) & 0x7) << 14; + reg |= (boost::uint32_t(current_setting2) & 0x7) << 17; + reg |= (boost::uint32_t(power_down) & 0x3) << 20; + reg |= (boost::uint32_t(prescaler_value) & 0x3) << 22; + break; + case 1: + reg |= (boost::uint32_t(r_counter) & 0x3fff) << 2; + reg |= (boost::uint32_t(ablpw) & 0x3) << 16; + reg |= (boost::uint32_t(lock_detect_precision) & 0x1) << 18; + reg |= (boost::uint32_t(test_mode_bit) & 0x1) << 19; + reg |= (boost::uint32_t(band_select_clock_div) & 0x3) << 20; + break; + case 2: + reg |= (boost::uint32_t(a_counter) & 0x1f) << 2; + reg |= (boost::uint32_t(b_counter) & 0x1fff) << 8; + reg |= (boost::uint32_t(cp_gain_1) & 0x1) << 21; + reg |= (boost::uint32_t(divide_by_2_output) & 0x1) << 22; + reg |= (boost::uint32_t(divide_by_2_prescaler) & 0x1) << 23; + break; + } + return reg; + } +}; + +#endif /* INCLUDED_ADF4360_REGS_HPP */ + diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 4fb036d38..57ea03da5 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include "adf4360_regs.hpp" #include #include #include @@ -47,10 +48,12 @@ private: double _lo_freq; std::string _rx_ant; float _rx_pga0_gain; + adf4360_regs_t _adf4360_regs; void set_lo_freq(double freq); void set_rx_ant(const std::string &ant); void set_rx_pga0_gain(float gain); + void reload_adf4360_regs(void); }; /*********************************************************************** @@ -115,6 +118,7 @@ rfx_xcvr::~rfx_xcvr(void){ **********************************************************************/ void rfx_xcvr::set_lo_freq(double freq){ /* NOP */ + reload_adf4360_regs(); } void rfx_xcvr::set_rx_ant(const std::string &ant){ @@ -125,6 +129,27 @@ void rfx_xcvr::set_rx_pga0_gain(float gain){ /* NOP */ } +void rfx_xcvr::reload_adf4360_regs(void){ + std::vector addrs = list_of + (adf4360_regs_t::ADDR_CONTROL) + (adf4360_regs_t::ADDR_NCOUNTER) + (adf4360_regs_t::ADDR_RCOUNTER) + ; + BOOST_FOREACH(adf4360_regs_t::addr_t addr, addrs){ + boost::uint32_t reg = _adf4360_regs.get_reg(addr); + dboard_interface::byte_vector_t spi_bytes = list_of + ((reg >> 16) & 0xff) + ((reg >> 8) & 0xff) + ((reg >> 0) & 0xff) + ; + //this->get_interface.write_spi( + // dboard_interface::SPI_DEV_TX, + // dboard_interface::SPI_EDGE_FALL, + // spi_bytes + //); + } +} + /*********************************************************************** * RX Get and Set **********************************************************************/ @@ -184,7 +209,7 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ val = false; return; - case SUBDEV_PROP_LO_INTERFERES: + case SUBDEV_PROP_USE_LO_OFFSET: val = false; return; } @@ -270,7 +295,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ val = false; return; - case SUBDEV_PROP_LO_INTERFERES: + case SUBDEV_PROP_USE_LO_OFFSET: val = true; return; } diff --git a/host/lib/usrp/dboard/gen_adf4360_regs.py b/host/lib/usrp/dboard/gen_adf4360_regs.py new file mode 100755 index 000000000..f16e59e2a --- /dev/null +++ b/host/lib/usrp/dboard/gen_adf4360_regs.py @@ -0,0 +1,168 @@ +#!/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 +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()) + print parse_tmpl(HEADER_TEXT, regs=regs, file=__file__) -- cgit v1.2.3