From 275b29e07f97cdf638ecb22c602d26b7d340547a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 2 Apr 2010 17:54:06 -0700 Subject: some work on rfx board code --- host/lib/usrp/dboard/db_rfx.cpp | 300 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 host/lib/usrp/dboard/db_rfx.cpp (limited to 'host/lib/usrp/dboard/db_rfx.cpp') diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp new file mode 100644 index 000000000..4fb036d38 --- /dev/null +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -0,0 +1,300 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program 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 version 3 of the License, or +// (at your option) any later version. +// +// This program 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 this program. If not, see . +// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; + +/*********************************************************************** + * The RFX series of dboards + **********************************************************************/ +class rfx_xcvr : public xcvr_dboard_base{ +public: + rfx_xcvr(ctor_args_t const& args, const freq_range_t &freq_range); + ~rfx_xcvr(void); + + void rx_get(const wax::obj &key, wax::obj &val); + void rx_set(const wax::obj &key, const wax::obj &val); + + void tx_get(const wax::obj &key, wax::obj &val); + void tx_set(const wax::obj &key, const wax::obj &val); + +private: + freq_range_t _freq_range; + double _lo_freq; + std::string _rx_ant; + float _rx_pga0_gain; + + void set_lo_freq(double freq); + void set_rx_ant(const std::string &ant); + void set_rx_pga0_gain(float gain); +}; + +/*********************************************************************** + * Register the RFX dboards + **********************************************************************/ +static dboard_base::sptr make_rfx_flex400(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(400e6, 500e6))); +} + +static dboard_base::sptr make_rfx_flex900(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(750e6, 1050e6))); +} + +static dboard_base::sptr make_rfx_flex1200(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1150e6, 1450e6))); +} + +static dboard_base::sptr make_rfx_flex1800(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(1500e6, 2100e6))); +} + +static dboard_base::sptr make_rfx_flex2400(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new rfx_xcvr(args, freq_range_t(2300e6, 2900e6))); +} + +UHD_STATIC_BLOCK(reg_rfx_dboards){ + dboard_manager::register_dboard(0x0024, &make_rfx_flex400, "Flex 400 Rx MIMO B"); + dboard_manager::register_dboard(0x0028, &make_rfx_flex400, "Flex 400 Tx MIMO B"); + + dboard_manager::register_dboard(0x0025, &make_rfx_flex900, "Flex 900 Rx MIMO B"); + dboard_manager::register_dboard(0x0029, &make_rfx_flex900, "Flex 900 Tx MIMO B"); + + dboard_manager::register_dboard(0x0026, &make_rfx_flex1200, "Flex 1200 Rx MIMO B"); + dboard_manager::register_dboard(0x002a, &make_rfx_flex1200, "Flex 1200 Tx MIMO B"); + + dboard_manager::register_dboard(0x0034, &make_rfx_flex1800, "Flex 1800 Rx MIMO B"); + dboard_manager::register_dboard(0x0035, &make_rfx_flex1800, "Flex 1800 Tx MIMO B"); + + dboard_manager::register_dboard(0x0027, &make_rfx_flex2400, "Flex 2400 Rx MIMO B"); + dboard_manager::register_dboard(0x002b, &make_rfx_flex2400, "Flex 2400 Tx MIMO B"); +} + +/*********************************************************************** + * Structors + **********************************************************************/ +rfx_xcvr::rfx_xcvr( + ctor_args_t const& args, + const freq_range_t &freq_range +) : xcvr_dboard_base(args){ + _freq_range = freq_range; + set_lo_freq((_freq_range.min + _freq_range.max)/2.0); + set_rx_ant("rx2"); + set_rx_pga0_gain(0); +} + +rfx_xcvr::~rfx_xcvr(void){ + /* NOP */ +} + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void rfx_xcvr::set_lo_freq(double freq){ + /* NOP */ +} + +void rfx_xcvr::set_rx_ant(const std::string &ant){ + /* NOP */ +} + +void rfx_xcvr::set_rx_pga0_gain(float gain){ + /* NOP */ +} + +/*********************************************************************** + * RX Get and Set + **********************************************************************/ +void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_NAME: + val = dboard_id::to_string(get_rx_id()); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + val = _rx_pga0_gain; + return; + + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 45, float(0.022)); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(1, "pga0"); + return; + + case SUBDEV_PROP_FREQ: + val = _lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = _freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = _rx_ant; + return; + + case SUBDEV_PROP_ANTENNA_NAMES:{ + prop_names_t ants = list_of("tx/rx")("rx2"); + val = ants; + } + return; + + case SUBDEV_PROP_QUADRATURE: + val = true; + return; + + case SUBDEV_PROP_IQ_SWAPPED: + val = true; + return; + + case SUBDEV_PROP_SPECTRUM_INVERTED: + val = false; + return; + + case SUBDEV_PROP_LO_INTERFERES: + val = false; + return; + } +} + +void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + + case SUBDEV_PROP_GAIN: + ASSERT_THROW(name == "pga0"); + set_rx_pga0_gain(val.as()); + return; + + case SUBDEV_PROP_ANTENNA: + set_rx_ant(val.as()); + return; + + default: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_rx_id()))); + } +} + +/*********************************************************************** + * TX Get and Set + **********************************************************************/ +void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + case SUBDEV_PROP_NAME: + val = dboard_id::to_string(get_tx_id()); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + val = float(0); + return; + + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 0, 0); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_FREQ: + val = _lo_freq; + return; + + case SUBDEV_PROP_FREQ_RANGE: + val = _freq_range; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string("tx/rx"); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = prop_names_t(1, "tx/rx"); + return; + + case SUBDEV_PROP_QUADRATURE: + val = true; + return; + + case SUBDEV_PROP_IQ_SWAPPED: + val = false; + return; + + case SUBDEV_PROP_SPECTRUM_INVERTED: + val = false; + return; + + case SUBDEV_PROP_LO_INTERFERES: + val = true; + return; + } +} + +void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(key.as()){ + + case SUBDEV_PROP_GAIN: + //no gains to set! + return; + + case SUBDEV_PROP_ANTENNA: + //its always set to tx/rx, so we only allow this value + ASSERT_THROW(val.as() == "tx/rx"); + return; + + default: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_tx_id()))); + } +} -- cgit v1.2.3 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 (limited to 'host/lib/usrp/dboard/db_rfx.cpp') 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 From b66a74ff1f629af714e26040b410d472c08be522 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 7 Apr 2010 00:46:42 -0700 Subject: Reworked the spi part of the dboard interface. It turns out to be more complicated. The integer type is better for holding the bits. The edges can be different, so the spi config hold 2 edge setting for mosi and miso. --- firmware/microblaze/apps/txrx.c | 25 ++------ host/include/uhd/usrp/dboard_interface.hpp | 100 ++++++++++++++++------------- host/lib/CMakeLists.txt | 1 - host/lib/usrp/dboard/db_rfx.cpp | 16 ++--- host/lib/usrp/dboard_interface.cpp | 53 --------------- host/lib/usrp/usrp2/dboard_interface.cpp | 95 ++++++++++++++++----------- host/lib/usrp/usrp2/fw_common.h | 7 +- 7 files changed, 128 insertions(+), 169 deletions(-) delete mode 100644 host/lib/usrp/dboard_interface.cpp (limited to 'host/lib/usrp/dboard/db_rfx.cpp') diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 69a04d771..561f3148f 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -253,29 +253,18 @@ void handle_udp_ctrl_packet( * SPI ******************************************************************/ case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ - uint8_t num_bytes = ctrl_data_in->data.spi_args.bytes; - - //load the data from the array of bytes - uint32_t data = 0x0; - for (size_t i = 0; i < num_bytes; i++){ - data = (data << 8) | ctrl_data_in->data.spi_args.data[i]; - } - //transact uint32_t result = spi_transact( (ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, - ctrl_data_in->data.spi_args.dev, - data, num_bytes*8, //length in bits - (ctrl_data_in->data.spi_args.edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_RISE : SPIF_PUSH_FALL | - (ctrl_data_in->data.spi_args.edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL + ctrl_data_in->data.spi_args.dev, //which device + ctrl_data_in->data.spi_args.data, //32 bit data + ctrl_data_in->data.spi_args.num_bits, //length in bits + (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | + (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL ); - //load the result into the array of bytes - for (size_t i = 0; i < num_bytes; i++){ - uint8_t byte_shift = num_bytes - i - 1; - ctrl_data_out.data.spi_args.data[i] = (result >> (byte_shift*8)) & 0xff; - } - ctrl_data_out.data.spi_args.bytes = num_bytes; + //load output + ctrl_data_out.data.spi_args.data = result; ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; } break; diff --git a/host/include/uhd/usrp/dboard_interface.hpp b/host/include/uhd/usrp/dboard_interface.hpp index b3bab131d..dab5a2281 100644 --- a/host/include/uhd/usrp/dboard_interface.hpp +++ b/host/include/uhd/usrp/dboard_interface.hpp @@ -42,16 +42,31 @@ public: UNIT_TYPE_TX = 't' }; - //tells the host which device to use - enum spi_dev_t{ - SPI_DEV_RX = 'r', - SPI_DEV_TX = 't' - }; - - //args for spi format - enum spi_edge_t{ - SPI_EDGE_RISE = 'r', - SPI_EDGE_FALL = 'f' + //spi configuration struct + struct UHD_API spi_config_t{ + /*! + * The edge type specifies when data is valid + * relative to the edge of the serial clock. + */ + enum edge_t{ + EDGE_RISE = 'r', + EDGE_FALL = 'f' + }; + + //! on what edge is the mosi data valid? + edge_t mosi_edge; + + //! on what edge is the miso data valid? + edge_t miso_edge; + + /*! + * Create a new spi config. + * \param edge the default edge for mosi and miso + */ + spi_config_t(edge_t edge = EDGE_RISE){ + mosi_edge = edge; + miso_edge = edge; + } }; //tell the host which gpio bank @@ -68,10 +83,6 @@ public: ATR_REG_FULL_DUPLEX = 'f' }; - //structors - dboard_interface(void); - virtual ~dboard_interface(void); - /*! * Write to an aux dac. * \param unit which unit rx or tx @@ -131,61 +142,60 @@ public: /*! * \brief Write data to SPI bus peripheral. * - * \param dev which spi device - * \param edge args for format - * \param buf the data to write + * \param unit which unit, rx or tx + * \param config configuration settings + * \param data the bits to write LSB first + * \param num_bits the number of bits in data */ - void write_spi(spi_dev_t dev, spi_edge_t edge, const byte_vector_t &buf); + virtual void write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ) = 0; /*! * \brief Read data to SPI bus peripheral. * - * \param dev which spi device - * \param edge args for format - * \param num_bytes number of bytes to read + * \param unit which unit, rx or tx + * \param config configuration settings + * \param num_bits the number of bits * \return the data that was read */ - byte_vector_t read_spi(spi_dev_t dev, spi_edge_t edge, size_t num_bytes); + virtual boost::uint32_t read_spi( + unit_type_t unit, + const spi_config_t &config, + size_t num_bits + ) = 0; /*! * \brief Read and write data to SPI bus peripheral. * The data read back will be the same length as the input buffer. * - * \param dev which spi device - * \param edge args for format - * \param buf the data to write + * \param unit which unit, rx or tx + * \param config configuration settings + * \param data the bits to write LSB first + * \param num_bits the number of bits in data * \return the data that was read */ - byte_vector_t read_write_spi(spi_dev_t dev, spi_edge_t edge, const byte_vector_t &buf); + virtual boost::uint32_t read_write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ) = 0; /*! * \brief Get the rate of the rx dboard clock. - * \return the clock rate + * \return the clock rate in Hz */ virtual double get_rx_clock_rate(void) = 0; /*! * \brief Get the rate of the tx dboard clock. - * \return the clock rate + * \return the clock rate in Hz */ virtual double get_tx_clock_rate(void) = 0; - -private: - /*! - * \brief Read and write data to SPI bus peripheral. - * - * \param dev which spi device - * \param edge args for format - * \param buf the data to write - * \param readback false for write only - * \return the data that was read - */ - virtual byte_vector_t transact_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf, - bool readback - ) = 0; }; }} //namespace diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index a4bf46f1a..f21a4a491 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -30,7 +30,6 @@ SET(libuhd_sources usrp/dboard/db_basic_and_lf.cpp usrp/dboard/db_rfx.cpp usrp/dboard_base.cpp - usrp/dboard_interface.cpp usrp/simple_usrp.cpp usrp/dboard_manager.cpp usrp/tune_helper.cpp diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 57ea03da5..68fa51144 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -136,17 +136,11 @@ void rfx_xcvr::reload_adf4360_regs(void){ (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 - //); + this->get_interface()->write_spi( + dboard_interface::UNIT_TYPE_TX, + dboard_interface::spi_config_t::EDGE_RISE, + _adf4360_regs.get_reg(addr), 24 + ); } } diff --git a/host/lib/usrp/dboard_interface.cpp b/host/lib/usrp/dboard_interface.cpp deleted file mode 100644 index c40c9b398..000000000 --- a/host/lib/usrp/dboard_interface.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program 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 version 3 of the License, or -// (at your option) any later version. -// -// This program 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 this program. If not, see . -// - -#include - -using namespace uhd::usrp; - -dboard_interface::dboard_interface(void){ - /* NOP */ -} - -dboard_interface::~dboard_interface(void){ - /* NOP */ -} - -void dboard_interface::write_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf -){ - transact_spi(dev, edge, buf, false); //dont readback -} - -dboard_interface::byte_vector_t dboard_interface::read_spi( - spi_dev_t dev, - spi_edge_t edge, - size_t num_bytes -){ - byte_vector_t buf(num_bytes, 0x00); //dummy data - return transact_spi(dev, edge, buf, true); //readback -} - -dboard_interface::byte_vector_t dboard_interface::read_write_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf -){ - return transact_spi(dev, edge, buf, true); //readback -} diff --git a/host/lib/usrp/usrp2/dboard_interface.cpp b/host/lib/usrp/usrp2/dboard_interface.cpp index 6dd756420..eee7c087a 100644 --- a/host/lib/usrp/usrp2/dboard_interface.cpp +++ b/host/lib/usrp/usrp2/dboard_interface.cpp @@ -42,9 +42,35 @@ public: double get_rx_clock_rate(void); double get_tx_clock_rate(void); + void write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ){ + transact_spi(unit, config, data, num_bits, false /*no rb*/); + } + + boost::uint32_t read_spi( + unit_type_t unit, + const spi_config_t &config, + size_t num_bits + ){ + return transact_spi(unit, config, 0, num_bits, true /*rb*/); + } + + boost::uint32_t read_write_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits + ){ + return transact_spi(unit, config, data, num_bits, true /*rb*/); + } + private: - byte_vector_t transact_spi( - spi_dev_t, spi_edge_t, const byte_vector_t &, bool + boost::uint32_t transact_spi( + unit_type_t, const spi_config_t &, boost::uint32_t, size_t, bool ); usrp2_impl *_impl; @@ -136,17 +162,17 @@ void usrp2_dboard_interface::set_atr_reg(gpio_bank_t bank, atr_reg_t atr, boost: * SPI **********************************************************************/ /*! - * Static function to convert a spi dev enum - * to an over-the-wire value for the usrp2 control. - * \param dev the dboard interface spi dev enum + * Static function to convert a unit type enum + * to an over-the-wire value for the spi device. + * \param unit the dboard interface unit type enum * \return an over the wire representation */ -static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ - switch(dev){ - case uhd::usrp::dboard_interface::SPI_DEV_TX: return SPI_SS_TX_DB; - case uhd::usrp::dboard_interface::SPI_DEV_RX: return SPI_SS_RX_DB; +static boost::uint8_t unit_to_otw_dev(dboard_interface::unit_type_t unit){ + switch(unit){ + case dboard_interface::UNIT_TYPE_TX: return SPI_SS_TX_DB; + case dboard_interface::UNIT_TYPE_RX: return SPI_SS_RX_DB; } - throw std::invalid_argument("unknown spi device type"); + throw std::invalid_argument("unknown unit type type"); } /*! @@ -155,43 +181,36 @@ static boost::uint8_t spi_dev_to_otw(dboard_interface::spi_dev_t dev){ * \param edge the dboard interface spi edge enum * \return an over the wire representation */ -static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_edge_t edge){ +static boost::uint8_t spi_edge_to_otw(dboard_interface::spi_config_t::edge_t edge){ switch(edge){ - case uhd::usrp::dboard_interface::SPI_EDGE_RISE: return USRP2_CLK_EDGE_RISE; - case uhd::usrp::dboard_interface::SPI_EDGE_FALL: return USRP2_CLK_EDGE_FALL; + case dboard_interface::spi_config_t::EDGE_RISE: return USRP2_CLK_EDGE_RISE; + case dboard_interface::spi_config_t::EDGE_FALL: return USRP2_CLK_EDGE_FALL; } throw std::invalid_argument("unknown spi edge type"); } -dboard_interface::byte_vector_t usrp2_dboard_interface::transact_spi( - spi_dev_t dev, - spi_edge_t edge, - const byte_vector_t &buf, +boost::uint32_t usrp2_dboard_interface::transact_spi( + unit_type_t unit, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits, bool readback ){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO); - out_data.data.spi_args.dev = spi_dev_to_otw(dev); - out_data.data.spi_args.edge = spi_edge_to_otw(edge); + out_data.data.spi_args.dev = unit_to_otw_dev(unit); + out_data.data.spi_args.miso_edge = spi_edge_to_otw(config.miso_edge); + out_data.data.spi_args.mosi_edge = spi_edge_to_otw(config.mosi_edge); out_data.data.spi_args.readback = (readback)? 1 : 0; - out_data.data.spi_args.bytes = buf.size(); - - //limitation of spi transaction size - ASSERT_THROW(buf.size() <= sizeof(out_data.data.spi_args.data)); - - //copy in the data - std::copy(buf.begin(), buf.end(), out_data.data.spi_args.data); + out_data.data.spi_args.num_bits = num_bits; + out_data.data.spi_args.data = htonl(data); //send and recv usrp2_ctrl_data_t in_data = _impl->ctrl_send_and_recv(out_data); ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); - ASSERT_THROW(in_data.data.spi_args.bytes == buf.size()); - //copy out the data - byte_vector_t result(buf.size()); - std::copy(in_data.data.spi_args.data, in_data.data.spi_args.data + buf.size(), result.begin()); - return result; + return ntohl(out_data.data.spi_args.data); } /*********************************************************************** @@ -245,19 +264,19 @@ dboard_interface::byte_vector_t usrp2_dboard_interface::read_i2c(int i2c_addr, s * \param unit the dboard interface unit type enum * \return an over the wire representation */ -static boost::uint8_t spi_dev_to_otw(dboard_interface::unit_type_t unit){ +static boost::uint8_t unit_to_otw(dboard_interface::unit_type_t unit){ switch(unit){ - case uhd::usrp::dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; - case uhd::usrp::dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; + case dboard_interface::UNIT_TYPE_TX: return USRP2_DIR_TX; + case dboard_interface::UNIT_TYPE_RX: return USRP2_DIR_RX; } throw std::invalid_argument("unknown unit type type"); } -void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, int which, int value){ +void usrp2_dboard_interface::write_aux_dac(unit_type_t unit, int which, int value){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_WRITE_THIS_TO_THE_AUX_DAC_BRO); - out_data.data.aux_args.dir = spi_dev_to_otw(unit); + out_data.data.aux_args.dir = unit_to_otw(unit); out_data.data.aux_args.which = which; out_data.data.aux_args.value = htonl(value); @@ -266,11 +285,11 @@ void usrp2_dboard_interface::write_aux_dac(dboard_interface::unit_type_t unit, i ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_DONE_WITH_THAT_AUX_DAC_DUDE); } -int usrp2_dboard_interface::read_aux_adc(dboard_interface::unit_type_t unit, int which){ +int usrp2_dboard_interface::read_aux_adc(unit_type_t unit, int which){ //setup the out data usrp2_ctrl_data_t out_data; out_data.id = htonl(USRP2_CTRL_ID_READ_FROM_THIS_AUX_ADC_BRO); - out_data.data.aux_args.dir = spi_dev_to_otw(unit); + out_data.data.aux_args.dir = unit_to_otw(unit); out_data.data.aux_args.which = which; //send and recv diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 019f3b931..b600a2a70 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -110,10 +110,11 @@ typedef struct{ } dboard_ids; struct { _SINS_ uint8_t dev; - _SINS_ uint8_t edge; + _SINS_ uint8_t miso_edge; + _SINS_ uint8_t mosi_edge; _SINS_ uint8_t readback; - _SINS_ uint8_t bytes; - _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; + _SINS_ uint32_t data; + _SINS_ uint8_t num_bits; } spi_args; struct { _SINS_ uint8_t addr; -- cgit v1.2.3