From a7c230cb1f97b452da027d5baa71891f2066d430 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 28 Apr 2010 16:35:22 -0700 Subject: Added reload flag to the stream cmd. This reloads the last command to handle continuous streaming in hardware. Moved rx control register setup and stream command issuing to the host. --- host/lib/usrp/usrp2/mboard_impl.cpp | 59 ++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 34 deletions(-) (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 36bef4f25..48aeb2a62 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -119,40 +119,31 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO); - out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0; - out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); - out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq())); - - //set these to defaults, then change in the switch statement - out_data.data.stream_cmd.continuous = 0; - out_data.data.stream_cmd.chain = 0; - out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps); - - //setup chain, num samps, and continuous below - switch(stream_cmd.stream_mode){ - case stream_cmd_t::STREAM_MODE_START_CONTINUOUS: - out_data.data.stream_cmd.continuous = 1; - break; - - case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: - out_data.data.stream_cmd.num_samps = htonl(0); - break; - - case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE: - //all set by defaults above - break; - - case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE: - out_data.data.stream_cmd.chain = 1; - break; - } - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE); + UHD_ASSERT_THROW(stream_cmd.num_samps <= FR_RX_CTRL_MAX_SAMPS_PER_CMD); + + //setup the mode to instruction flags + typedef boost::tuple inst_t; + static const uhd::dict mode_to_inst = boost::assign::map_list_of + //reload, chain, samps + (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) + (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) + ; + + //setup the instruction flag values + bool inst_reload, inst_chain, inst_samps; + boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; + + //issue the stream command + _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (stream_cmd.stream_now)? 1 : 0, + (inst_chain)? 1 : 0, + (inst_reload)? 1 : 0 + )); + _iface->poke32(FR_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs); + _iface->poke32(FR_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq())); } /*********************************************************************** -- cgit v1.2.3 From 30bd666e306cb8f8c947c6ba99a76f7c49484597 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 28 Apr 2010 17:38:22 -0700 Subject: Moved some misc setting registers into host. --- firmware/microblaze/lib/u2_init.c | 10 ---------- host/lib/usrp/usrp2/mboard_impl.cpp | 13 ++++++++++--- host/lib/usrp/usrp2/usrp2_regs.hpp | 20 ++++++++++++++++++-- 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index b4fbb9e88..6809101c0 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -46,8 +46,6 @@ get_hw_rev(void) bool u2_init(void) { - dsp_rx_regs->gpio_stream_enable = 0; // I, Q LSBs come from DSP - hal_io_init(); // init spi, so that we can switch over to the high-speed clock @@ -60,14 +58,6 @@ u2_init(void) // set up the default clocks clocks_init(); - // clocks_enable_test_clk(true,1); - - // Enable ADCs - output_regs->adc_ctrl = ADC_CTRL_ON; - - // Set up serdes - output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN); - pic_init(); // progammable interrupt controller bp_init(); // buffer pool diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 48aeb2a62..2c8fd2df4 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -63,6 +63,13 @@ void usrp2_impl::mboard_init(void){ boost::uint16_t data = ad9777_regs.get_write_reg(addr); _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/); } + + //enable ADCs + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); + + //set up serdes + _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); + } void usrp2_impl::init_clock_config(void){ @@ -97,9 +104,9 @@ void usrp2_impl::update_clock_config(void){ //clock source ref 10mhz switch(_clock_config.ref_source){ - case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break; - case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break; + case clock_config_t::REF_INT : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x10); break; + case clock_config_t::REF_SMA : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x1C); break; + case clock_config_t::REF_MIMO: _iface->poke32(FR_MISC_CTRL_CLOCK, 0x15); break; default: throw std::runtime_error("usrp2: unhandled clock configuration reference source"); } diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 67a342217..feeccaa34 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -64,7 +64,23 @@ ///////////////////////////////////////////////// // Misc Control //////////////////////////////////////////////// -#define FR_CLOCK_CONTROL _SR_ADDR(0) +#define FR_MISC_CTRL_CLOCK _SR_ADDR(0) +#define FR_MISC_CTRL_SERDES _SR_ADDR(1) +#define FR_MISC_CTRL_ADC _SR_ADDR(2) +#define FR_MISC_CTRL_LEDS _SR_ADDR(3) +#define FR_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy +#define FR_MISC_CTRL_DBG_MUX _SR_ADDR(5) +#define FR_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else... +#define FR_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache +#define FR_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs + +#define FRF_MISC_CTRL_SERDES_ENABLE 8 +#define FRF_MISC_CTRL_SERDES_PRBSEN 4 +#define FRF_MISC_CTRL_SERDES_LOOPEN 2 +#define FRF_MISC_CTRL_SERDES_RXEN 1 + +#define FRF_MISC_CTRL_ADC_ON 0x0F +#define FRF_MISC_CTRL_ADC_OFF 0x00 ///////////////////////////////////////////////// // VITA49 64 bit time (write only) @@ -208,7 +224,7 @@ #define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14 /////////////////////////////////////////////////// -// ATR Controller, Slave 11 +// VITA RX CTRL regs /////////////////////////////////////////////////// // The following 3 are logically a single command register. // They are clocked into the underlying fifo when time_ticks is written. -- cgit v1.2.3 From bf7ef6aeb502839797894cac4d7518029a0d04c4 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 15:14:48 -0700 Subject: Moved adc and dac control into codec control source file. The codec control powers down the chips on destruction. --- host/lib/usrp/usrp2/CMakeLists.txt | 3 +- host/lib/usrp/usrp2/clock_control.cpp | 157 ---------------------------------- host/lib/usrp/usrp2/clock_control.hpp | 60 ------------- host/lib/usrp/usrp2/clock_ctrl.cpp | 155 +++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/clock_ctrl.hpp | 60 +++++++++++++ host/lib/usrp/usrp2/codec_ctrl.cpp | 91 ++++++++++++++++++++ host/lib/usrp/usrp2/codec_ctrl.hpp | 38 ++++++++ host/lib/usrp/usrp2/dboard_iface.cpp | 18 ++-- host/lib/usrp/usrp2/dboard_impl.cpp | 2 +- host/lib/usrp/usrp2/mboard_impl.cpp | 32 +------ host/lib/usrp/usrp2/usrp2_impl.cpp | 2 + host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +- 12 files changed, 364 insertions(+), 262 deletions(-) delete mode 100644 host/lib/usrp/usrp2/clock_control.cpp delete mode 100644 host/lib/usrp/usrp2/clock_control.hpp create mode 100644 host/lib/usrp/usrp2/clock_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/clock_ctrl.hpp create mode 100644 host/lib/usrp/usrp2/codec_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/codec_ctrl.hpp (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index f9907e21e..6c7881861 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -18,7 +18,8 @@ #This file will be included by cmake, use absolute paths! LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_control.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp deleted file mode 100644 index 72f1f1c7a..000000000 --- a/host/lib/usrp/usrp2/clock_control.cpp +++ /dev/null @@ -1,157 +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 "usrp2_impl.hpp" -#include "clock_control.hpp" -#include "ad9510_regs.hpp" -#include "usrp2_regs.hpp" //spi slave constants -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*! - * A usrp2 clock control specific to the ad9510 ic. - */ -class clock_control_ad9510 : public clock_control{ -public: - clock_control_ad9510(usrp2_iface::sptr iface){ - _iface = iface; - - _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; - this->write_reg(0x09); - - // Setup the clock registers to 100MHz: - // This was already done by the firmware (or the host couldnt communicate). - // We could remove this part, and just leave it to the firmware. - // But why not leave it in for those who want to mess with clock settings? - // 100mhz = 10mhz/R * (P*B + A) - - _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); - - _ad9510_regs.acounter = 0; - this->write_reg(0x04); - - _ad9510_regs.bcounter_msb = 0; - _ad9510_regs.bcounter_lsb = 5; - this->write_reg(0x05); - this->write_reg(0x06); - - _ad9510_regs.ref_counter_msb = 0; - _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 - this->write_reg(0x0B); - this->write_reg(0x0C); - - /* regs will be updated in commands below */ - - this->enable_external_ref(false); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - - /* private clock enables, must be set here */ - this->enable_dac_clock(true); - this->enable_adc_clock(true); - - } - - ~clock_control_ad9510(void){ - /* private clock enables, must be set here */ - this->enable_dac_clock(false); - this->enable_adc_clock(false); - } - - //uses output clock 7 (cmos) - void enable_rx_dboard_clock(bool enb){ - _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->update_regs(); - } - - //uses output clock 6 (cmos) - 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); - this->update_regs(); - } - - /*! - * If we are to use an external reference, enable the charge pump. - * \param enb true to enable the CP - */ - void enable_external_ref(bool enb){ - _ad9510_regs.charge_pump_mode = (enb)? - ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL : - 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->update_regs(); - } - -private: - /*! - * Write a single register to the spi regs. - * \param addr the address to write - */ - void write_reg(boost::uint8_t addr){ - boost::uint32_t data = _ad9510_regs.get_write_reg(addr); - _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/); - } - - /*! - * Tells the ad9510 to latch the settings into the operational registers. - */ - void update_regs(void){ - _ad9510_regs.update_registers = 1; - this->write_reg(0x5a); - } - - //uses output clock 3 (pecl) - 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; - this->write_reg(0x3F); - this->update_regs(); - } - - //uses output clock 4 (lvds) - 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; - this->write_reg(0x40); - this->update_regs(); - } - - usrp2_iface::sptr _iface; - ad9510_regs_t _ad9510_regs; -}; - -/*********************************************************************** - * Public make function for the ad9510 clock control - **********************************************************************/ -clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){ - return clock_control::sptr(new clock_control_ad9510(iface)); -} diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_control.hpp deleted file mode 100644 index b64a53196..000000000 --- a/host/lib/usrp/usrp2/clock_control.hpp +++ /dev/null @@ -1,60 +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 . -// - -#ifndef INCLUDED_CLOCK_CONTROL_HPP -#define INCLUDED_CLOCK_CONTROL_HPP - -#include "usrp2_iface.hpp" -#include -#include - -class clock_control : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a clock config for the ad9510 ic. - * \param _iface a pointer to the usrp2 interface object - * \return a new clock control object - */ - static sptr make_ad9510(usrp2_iface::sptr iface); - - /*! - * Enable/disable the rx dboard clock. - * \param enb true to enable - */ - virtual void enable_rx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable the tx dboard clock. - * \param enb true to enable - */ - virtual void enable_tx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable external reference. - * \param enb true to enable - */ - virtual void enable_external_ref(bool enb) = 0; - - /*! - * TODO other clock control api here.... - */ - -}; - -#endif /* INCLUDED_CLOCK_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp new file mode 100644 index 000000000..db8d8a886 --- /dev/null +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -0,0 +1,155 @@ +// +// 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 "clock_ctrl.hpp" +#include "ad9510_regs.hpp" +#include "usrp2_regs.hpp" //spi slave constants +#include + +using namespace uhd; + +/*! + * A usrp2 clock control specific to the ad9510 ic. + */ +class clock_ctrl_impl : public clock_ctrl{ +public: + clock_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + + _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; + this->write_reg(0x09); + + // Setup the clock registers to 100MHz: + // This was already done by the firmware (or the host couldnt communicate). + // We could remove this part, and just leave it to the firmware. + // But why not leave it in for those who want to mess with clock settings? + // 100mhz = 10mhz/R * (P*B + A) + + _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); + + _ad9510_regs.acounter = 0; + this->write_reg(0x04); + + _ad9510_regs.bcounter_msb = 0; + _ad9510_regs.bcounter_lsb = 5; + this->write_reg(0x05); + this->write_reg(0x06); + + _ad9510_regs.ref_counter_msb = 0; + _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 + this->write_reg(0x0B); + this->write_reg(0x0C); + + /* regs will be updated in commands below */ + + this->enable_external_ref(false); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + + /* private clock enables, must be set here */ + this->enable_dac_clock(true); + this->enable_adc_clock(true); + + } + + ~clock_ctrl_impl(void){ + /* private clock enables, must be set here */ + this->enable_dac_clock(false); + this->enable_adc_clock(false); + } + + //uses output clock 7 (cmos) + void enable_rx_dboard_clock(bool enb){ + _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->update_regs(); + } + + //uses output clock 6 (cmos) + 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); + this->update_regs(); + } + + /*! + * If we are to use an external reference, enable the charge pump. + * \param enb true to enable the CP + */ + void enable_external_ref(bool enb){ + _ad9510_regs.charge_pump_mode = (enb)? + ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL : + 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->update_regs(); + } + +private: + /*! + * Write a single register to the spi regs. + * \param addr the address to write + */ + void write_reg(boost::uint8_t addr){ + boost::uint32_t data = _ad9510_regs.get_write_reg(addr); + _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/); + } + + /*! + * Tells the ad9510 to latch the settings into the operational registers. + */ + void update_regs(void){ + _ad9510_regs.update_registers = 1; + this->write_reg(0x5a); + } + + //uses output clock 3 (pecl) + 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; + this->write_reg(0x3F); + this->update_regs(); + } + + //uses output clock 4 (lvds) + 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; + this->write_reg(0x40); + this->update_regs(); + } + + usrp2_iface::sptr _iface; + ad9510_regs_t _ad9510_regs; +}; + +/*********************************************************************** + * Public make function for the ad9510 clock control + **********************************************************************/ +clock_ctrl::sptr clock_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new clock_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp new file mode 100644 index 000000000..3208008a9 --- /dev/null +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -0,0 +1,60 @@ +// +// 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 . +// + +#ifndef INCLUDED_CLOCK_CONTROL_HPP +#define INCLUDED_CLOCK_CONTROL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class clock_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a clock config for the ad9510 ic. + * \param _iface a pointer to the usrp2 interface object + * \return a new clock control object + */ + static sptr make(usrp2_iface::sptr iface); + + /*! + * Enable/disable the rx dboard clock. + * \param enb true to enable + */ + virtual void enable_rx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable the tx dboard clock. + * \param enb true to enable + */ + virtual void enable_tx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable external reference. + * \param enb true to enable + */ + virtual void enable_external_ref(bool enb) = 0; + + /*! + * TODO other clock control api here.... + */ + +}; + +#endif /* INCLUDED_CLOCK_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp new file mode 100644 index 000000000..452aa39b1 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -0,0 +1,91 @@ +// +// 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 "codec_ctrl.hpp" +#include "ad9777_regs.hpp" +#include "usrp2_regs.hpp" +#include +#include +#include + +static const bool codec_ctrl_debug = false; + +using namespace uhd; + +/*! + * A usrp2 codec control specific to the ad9777 ic. + */ +class codec_ctrl_impl : public codec_ctrl{ +public: + codec_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + + //setup the ad9777 dac + _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; + _ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; + _ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; + _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; + _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; + _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; + //I dac values + _ad9777_regs.idac_fine_gain_adjust = 0; + _ad9777_regs.idac_coarse_gain_adjust = 0xf; + _ad9777_regs.idac_offset_adjust_lsb = 0; + _ad9777_regs.idac_offset_adjust_msb = 0; + //Q dac values + _ad9777_regs.qdac_fine_gain_adjust = 0; + _ad9777_regs.qdac_coarse_gain_adjust = 0xf; + _ad9777_regs.qdac_offset_adjust_lsb = 0; + _ad9777_regs.qdac_offset_adjust_msb = 0; + //write all regs + for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ + send_ad9777_reg(addr); + } + + //power-up adc + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); + } + + ~codec_ctrl_impl(void){ + //power-down dac + _ad9777_regs.power_down_mode = 1; + send_ad9777_reg(0); + + //power-down adc + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF); + } + +private: + ad9777_regs_t _ad9777_regs; + usrp2_iface::sptr _iface; + + void send_ad9777_reg(boost::uint8_t addr){ + boost::uint16_t reg = _ad9777_regs.get_write_reg(addr); + if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl; + _iface->transact_spi( + SPI_SS_AD9777, spi_config_t::EDGE_RISE, + reg, 6, false /*no rb*/ + ); + } +}; + +/*********************************************************************** + * Public make function for the usrp2 codec control + **********************************************************************/ +codec_ctrl::sptr codec_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp new file mode 100644 index 000000000..c34fb8159 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -0,0 +1,38 @@ +// +// 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 . +// + +#ifndef INCLUDED_CODEC_CONTROL_HPP +#define INCLUDED_CODEC_CONTROL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class codec_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a codec control for the DAC and ADC. + * \param _iface a pointer to the usrp2 interface object + * \return a new codec control object + */ + static sptr make(usrp2_iface::sptr iface); + +}; + +#endif /* INCLUDED_CODEC_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 372a5af07..d33a11fd6 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -16,7 +16,7 @@ // #include "usrp2_iface.hpp" -#include "clock_control.hpp" +#include "clock_ctrl.hpp" #include "usrp2_regs.hpp" //wishbone address constants #include #include @@ -33,7 +33,7 @@ using namespace boost::assign; class usrp2_dboard_iface : public dboard_iface{ public: - usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl); + usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl); ~usrp2_dboard_iface(void); void write_aux_dac(unit_t, int, float); @@ -66,7 +66,7 @@ public: private: usrp2_iface::sptr _iface; - clock_control::sptr _clk_ctrl; + clock_ctrl::sptr _clock_ctrl; boost::uint32_t _ddr_shadow; uhd::dict _dac_regs; @@ -78,17 +78,17 @@ private: **********************************************************************/ dboard_iface::sptr make_usrp2_dboard_iface( usrp2_iface::sptr iface, - clock_control::sptr clk_ctrl + clock_ctrl::sptr clock_ctrl ){ - return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl)); + return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl)); } /*********************************************************************** * Structors **********************************************************************/ -usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){ +usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl){ _iface = iface; - _clk_ctrl = clk_ctrl; + _clock_ctrl = clock_ctrl; _ddr_shadow = 0; //set the selection mux to use atr @@ -123,8 +123,8 @@ double usrp2_dboard_iface::get_clock_rate(unit_t){ void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ switch(unit){ - case UNIT_RX: _clk_ctrl->enable_rx_dboard_clock(enb); return; - case UNIT_TX: _clk_ctrl->enable_tx_dboard_clock(enb); return; + case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return; + case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return; } } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 403faf5cf..0f8a739f2 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -39,7 +39,7 @@ void usrp2_impl::dboard_init(void){ //create a new dboard interface and manager dboard_iface::sptr _dboard_iface( - make_usrp2_dboard_iface(_iface, _clk_ctrl) + make_usrp2_dboard_iface(_iface, _clock_ctrl) ); _dboard_manager = dboard_manager::make( _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 2c8fd2df4..892e45f49 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -17,7 +17,6 @@ #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" -#include "ad9777_regs.hpp" #include #include #include @@ -38,35 +37,6 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); - _clk_ctrl = clock_control::make_ad9510(_iface); - - //setup the ad9777 dac - ad9777_regs_t ad9777_regs; - ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; - ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; - ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; - ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; - ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; - ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; - //I dac values - ad9777_regs.idac_fine_gain_adjust = 0; - ad9777_regs.idac_coarse_gain_adjust = 0xf; - ad9777_regs.idac_offset_adjust_lsb = 0; - ad9777_regs.idac_offset_adjust_msb = 0; - //Q dac values - ad9777_regs.qdac_fine_gain_adjust = 0; - ad9777_regs.qdac_coarse_gain_adjust = 0xf; - ad9777_regs.qdac_offset_adjust_lsb = 0; - ad9777_regs.qdac_offset_adjust_msb = 0; - //write all regs - for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ - boost::uint16_t data = ad9777_regs.get_write_reg(addr); - _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/); - } - - //enable ADCs - _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); - //set up serdes _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); @@ -112,7 +82,7 @@ void usrp2_impl::update_clock_config(void){ //clock source ref 10mhz bool use_external = _clock_config.ref_source != clock_config_t::REF_INT; - _clk_ctrl->enable_external_ref(use_external); + _clock_ctrl->enable_external_ref(use_external); } void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 1dde8c054..ef7754c33 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -147,6 +147,8 @@ usrp2_impl::usrp2_impl( //make a new interface for usrp2 stuff _iface = usrp2_iface::make(ctrl_transport); + _clock_ctrl = clock_ctrl::make(_iface); + _codec_ctrl = codec_ctrl::make(_iface); //load the allowed decim/interp rates //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 1c9387744..871050356 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -19,7 +19,8 @@ #define INCLUDED_USRP2_IMPL_HPP #include "usrp2_iface.hpp" -#include "clock_control.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" #include #include #include @@ -40,7 +41,7 @@ */ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( usrp2_iface::sptr iface, - clock_control::sptr clk_ctrl + clock_ctrl::sptr clk_ctrl ); /*! @@ -114,7 +115,8 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces - clock_control::sptr _clk_ctrl; + clock_ctrl::sptr _clock_ctrl; + codec_ctrl::sptr _codec_ctrl; usrp2_iface::sptr _iface; //the raw io interface (samples are in the usrp2 native format) -- cgit v1.2.3 From 7c7b0d0a0dc8dd0cb4f0229fbc55978d6f2e253c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 16:37:12 -0700 Subject: Added a place for serdes control on the host. Fix bug in codec control. Comment out some clock control in fw code. --- firmware/microblaze/lib/clocks.c | 30 ++++++++++++------------ firmware/microblaze/lib/clocks.h | 10 ++++---- host/lib/usrp/usrp2/CMakeLists.txt | 1 + host/lib/usrp/usrp2/clock_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.cpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/mboard_impl.cpp | 4 ---- host/lib/usrp/usrp2/serdes_ctrl.cpp | 46 +++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/serdes_ctrl.hpp | 40 ++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 1 + host/lib/usrp/usrp2/usrp2_impl.hpp | 4 +++- 11 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.hpp (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c index d9d4fcd3c..ccc4a7cc7 100644 --- a/firmware/microblaze/lib/clocks.c +++ b/firmware/microblaze/lib/clocks.c @@ -48,14 +48,14 @@ clocks_init(void) clocks_mimo_config(MC_WE_DONT_LOCK); // Set up other clocks - clocks_enable_test_clk(false, 0); - clocks_enable_tx_dboard(false, 0); - clocks_enable_rx_dboard(false, 0); + //clocks_enable_test_clk(false, 0); + //clocks_enable_tx_dboard(false, 0); + //clocks_enable_rx_dboard(false, 0); clocks_enable_eth_phyclk(false, 0); // Enable clock to ADCs and DACs - clocks_enable_dac_clk(true, 1); - clocks_enable_adc_clk(true, 1); + //clocks_enable_dac_clk(true, 1); + //clocks_enable_adc_clk(true, 1); } @@ -168,11 +168,11 @@ clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mod } // Clock 0 -void +/*void clocks_enable_test_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); -} +}*/ // Clock 1 void @@ -211,29 +211,29 @@ clocks_enable_eth_phyclk(bool enable, int divisor) } // Clock 3 -void +/*void clocks_enable_dac_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); -} +}*/ // Clock 4 -void +/*void clocks_enable_adc_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); -} +}*/ // Clock 6 -void +/*void clocks_enable_tx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); -} +}*/ // Clock 7 -void +/*void clocks_enable_rx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); -} +}*/ diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 141fc61e0..43d5a05c2 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -53,7 +53,7 @@ bool clocks_lock_detect(); /*! * \brief Enable or disable test clock (extra clock signal) */ -void clocks_enable_test_clk(bool enable, int divisor); +//void clocks_enable_test_clk(bool enable, int divisor); /*! * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. @@ -73,23 +73,23 @@ void clocks_enable_eth_phyclk(bool enable, int divisor); /*! * \brief Enable or disable clock to DAC */ -void clocks_enable_dac_clk(bool enable, int divisor); +//void clocks_enable_dac_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to ADC */ -void clocks_enable_adc_clk(bool enable, int divisor); +//void clocks_enable_adc_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to Rx daughterboard */ -void clocks_enable_rx_dboard(bool enable, int divisor); +//void clocks_enable_rx_dboard(bool enable, int divisor); /*! * \brief Enable or disable clock to Tx daughterboard */ -void clocks_enable_tx_dboard(bool enable, int divisor); +//void clocks_enable_tx_dboard(bool enable, int divisor); #endif /* INCLUDED_CLOCKS_H */ diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 6c7881861..fee67dff9 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp ) diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 3208008a9..706bf4246 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CLOCK_CONTROL_HPP -#define INCLUDED_CLOCK_CONTROL_HPP +#ifndef INCLUDED_CLOCK_CTRL_HPP +#define INCLUDED_CLOCK_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -57,4 +57,4 @@ public: }; -#endif /* INCLUDED_CLOCK_CONTROL_HPP */ +#endif /* INCLUDED_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 452aa39b1..d1e16881b 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -53,7 +53,7 @@ public: _ad9777_regs.qdac_offset_adjust_msb = 0; //write all regs for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ - send_ad9777_reg(addr); + this->send_ad9777_reg(addr); } //power-up adc @@ -63,7 +63,7 @@ public: ~codec_ctrl_impl(void){ //power-down dac _ad9777_regs.power_down_mode = 1; - send_ad9777_reg(0); + this->send_ad9777_reg(0); //power-down adc _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF); @@ -78,7 +78,7 @@ private: if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl; _iface->transact_spi( SPI_SS_AD9777, spi_config_t::EDGE_RISE, - reg, 6, false /*no rb*/ + reg, 16, false /*no rb*/ ); } }; diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index c34fb8159..0ee52f476 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CODEC_CONTROL_HPP -#define INCLUDED_CODEC_CONTROL_HPP +#ifndef INCLUDED_CODEC_CTRL_HPP +#define INCLUDED_CODEC_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -35,4 +35,4 @@ public: }; -#endif /* INCLUDED_CODEC_CONTROL_HPP */ +#endif /* INCLUDED_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 892e45f49..7e62bedf0 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -36,10 +36,6 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_get, this, _1, _2), boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); - - //set up serdes - _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); - } void usrp2_impl::init_clock_config(void){ diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp new file mode 100644 index 000000000..dde22b499 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp @@ -0,0 +1,46 @@ +// +// 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 "serdes_ctrl.hpp" +#include "usrp2_regs.hpp" + +using namespace uhd; + +/*! + * A usrp2 serdes control implementation + */ +class serdes_ctrl_impl : public serdes_ctrl{ +public: + serdes_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); + } + + ~serdes_ctrl_impl(void){ + _iface->poke32(FR_MISC_CTRL_SERDES, 0); //power-down + } + +private: + usrp2_iface::sptr _iface; +}; + +/*********************************************************************** + * Public make function for the usrp2 serdes control + **********************************************************************/ +serdes_ctrl::sptr serdes_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new serdes_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp new file mode 100644 index 000000000..586238739 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.hpp @@ -0,0 +1,40 @@ +// +// 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 . +// + +#ifndef INCLUDED_SERDES_CTRL_HPP +#define INCLUDED_SERDES_CTRL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class serdes_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a serdes control object for the usrp2 serdes port. + * \param _iface a pointer to the usrp2 interface object + * \return a new serdes control object + */ + static sptr make(usrp2_iface::sptr iface); + + //TODO fill me in with virtual methods + +}; + +#endif /* INCLUDED_SERDES_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index ef7754c33..5c1d7f9e3 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -149,6 +149,7 @@ usrp2_impl::usrp2_impl( _iface = usrp2_iface::make(ctrl_transport); _clock_ctrl = clock_ctrl::make(_iface); _codec_ctrl = codec_ctrl::make(_iface); + _serdes_ctrl = serdes_ctrl::make(_iface); //load the allowed decim/interp rates //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 871050356..c5b6af810 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -21,6 +21,7 @@ #include "usrp2_iface.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "serdes_ctrl.hpp" #include #include #include @@ -115,9 +116,10 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces + usrp2_iface::sptr _iface; clock_ctrl::sptr _clock_ctrl; codec_ctrl::sptr _codec_ctrl; - usrp2_iface::sptr _iface; + serdes_ctrl::sptr _serdes_ctrl; //the raw io interface (samples are in the usrp2 native format) void recv_raw(uhd::rx_metadata_t &); -- cgit v1.2.3 From 81f211c94f761c92baaf1a2997a7f9b9b7718182 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 11 May 2010 16:35:01 -0700 Subject: Moved usrp2 eeprom addr read/write to host control over i2c/eeprom interface calls. No longer part of the dude/bro protocol. Simplified the mac and ip addr read write code in mboard impl. Modified the mac addr type to take byte_vector_t from serial.hpp types. --- firmware/microblaze/apps/txrx_uhd.c | 23 +++-------------- host/include/uhd/types/mac_addr.hpp | 16 +++++------- host/include/uhd/utils/algorithm.hpp | 5 ++++ host/lib/types.cpp | 27 ++++++++++--------- host/lib/usrp/usrp2/fw_common.h | 10 ++------ host/lib/usrp/usrp2/mboard_impl.cpp | 50 +++++++++--------------------------- host/lib/usrp/usrp2/usrp2_iface.hpp | 7 +++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 4 +-- 8 files changed, 53 insertions(+), 89 deletions(-) (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index db830fa51..7ad4ab110 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -185,7 +185,7 @@ void handle_udp_ctrl_packet( printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", USRP2_PROTO_VERSION, ctrl_data_in->proto_ver ); - ctrl_data_in_id = USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO; + ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; } //ensure that this is not a short packet @@ -209,28 +209,11 @@ void handle_udp_ctrl_packet( /******************************************************************* * Addressing ******************************************************************/ - case USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; + case USRP2_CTRL_ID_WAZZUP_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); break; - case USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; - set_ip_addr((struct ip_addr *)&ctrl_data_in->data.ip_addr); - memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); - break; - - case USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - - case USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - ethernet_set_mac_addr((eth_mac_addr_t *)&ctrl_data_in->data.mac_addr); - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - /******************************************************************* * SPI ******************************************************************/ diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp index 3cd1fe86b..034b6a348 100644 --- a/host/include/uhd/types/mac_addr.hpp +++ b/host/include/uhd/types/mac_addr.hpp @@ -19,7 +19,7 @@ #define INCLUDED_UHD_TYPES_MAC_ADDR_HPP #include -#include +#include #include namespace uhd{ @@ -30,14 +30,12 @@ namespace uhd{ */ class UHD_API mac_addr_t{ public: - static const size_t hlen = 6; - /*! * Create a mac address a byte array. - * \param bytes a pointer for the byte array + * \param bytes a vector of bytes * \return a new mac address */ - static mac_addr_t from_bytes(const boost::uint8_t *bytes); + static mac_addr_t from_bytes(const byte_vector_t &bytes); /*! * Create a mac address from a string. @@ -48,9 +46,9 @@ namespace uhd{ /*! * Get the byte representation of the mac address. - * \return a pointer to the internal byte array + * \return a vector of bytes */ - const boost::uint8_t *to_bytes(void) const; + byte_vector_t to_bytes(void) const; /*! * Get the string representation of this mac address. @@ -59,8 +57,8 @@ namespace uhd{ std::string to_string(void) const; private: - mac_addr_t(const boost::uint8_t *bytes); //private constructor - boost::uint8_t _bytes[hlen]; //internal representation + mac_addr_t(const byte_vector_t &bytes); //private constructor + byte_vector_t _bytes; //internal representation }; } //namespace uhd diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index 72b655745..146b56c63 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -26,6 +26,11 @@ */ namespace std{ + template inline + void copy(const RangeSrc &src, RangeDst &dst){ + std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); + } + template inline bool has(const Range &range, const T &value){ return boost::end(range) != std::find(boost::begin(range), boost::end(range), value); diff --git a/host/lib/types.cpp b/host/lib/types.cpp index ec9c8ac01..33eb550a1 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #include #include @@ -164,17 +165,19 @@ std::string device_addr_t::to_string(void) const{ /*********************************************************************** * mac addr **********************************************************************/ -mac_addr_t::mac_addr_t(const boost::uint8_t *bytes){ - std::copy(bytes, bytes+hlen, _bytes); +mac_addr_t::mac_addr_t(const byte_vector_t &bytes){ + UHD_ASSERT_THROW(bytes.size() == 6); + _bytes = bytes; } -mac_addr_t mac_addr_t::from_bytes(const boost::uint8_t *bytes){ +mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ return mac_addr_t(bytes); } mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ - boost::uint8_t p[hlen] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB + byte_vector_t bytes = boost::assign::list_of + (0x00)(0x50)(0xC2)(0x85)(0x30)(0x00); // Matt's IAB try{ //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx @@ -189,7 +192,7 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ int hex_num; std::istringstream iss(hex_strs[i]); iss >> std::hex >> hex_num; - p[i] = boost::uint8_t(hex_num); + bytes[i] = boost::uint8_t(hex_num); } } @@ -199,19 +202,19 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ )); } - return from_bytes(p); + return mac_addr_t::from_bytes(bytes); } -const boost::uint8_t *mac_addr_t::to_bytes(void) const{ +byte_vector_t mac_addr_t::to_bytes(void) const{ return _bytes; } std::string mac_addr_t::to_string(void) const{ - return str( - boost::format("%02x:%02x:%02x:%02x:%02x:%02x") - % int(to_bytes()[0]) % int(to_bytes()[1]) % int(to_bytes()[2]) - % int(to_bytes()[3]) % int(to_bytes()[4]) % int(to_bytes()[5]) - ); + std::string addr = ""; + BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){ + addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte)); + } + return addr; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index f28013cf6..75f5b1779 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -53,13 +53,8 @@ typedef enum{ //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums //USRP2_CTRL_ID_SUX_MAN, - USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO = 'a', - USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE = 'A', - USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO = 'b', - - USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO = 'm', - USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE = 'M', - USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO = 'n', + USRP2_CTRL_ID_WAZZUP_BRO = 'a', + USRP2_CTRL_ID_WAZZUP_DUDE = 'A', USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's', USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S', @@ -96,7 +91,6 @@ typedef struct{ _SINS_ uint32_t seq; union{ _SINS_ uint32_t ip_addr; - _SINS_ uint8_t mac_addr[6]; struct { _SINS_ uint8_t dev; _SINS_ uint8_t miso_edge; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 7e62bedf0..9ae68d158 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -19,10 +19,11 @@ #include "usrp2_regs.hpp" #include #include +#include #include #include #include -#include //htonl and ntohl +#include #include using namespace uhd; @@ -129,30 +130,15 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); - - //extract the address - val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string(); + byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6); + val = mac_addr_t::from_bytes(bytes).to_string(); return; } if (key.as() == "ip-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); - - //extract the address - val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string(); + boost::asio::ip::address_v4::bytes_type bytes; + std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes); + val = boost::asio::ip::address_v4(bytes).to_string(); return; } } @@ -223,27 +209,15 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO); - mac_addr_t mac_addr = mac_addr_t::from_string(val.as()); - std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + byte_vector_t bytes = mac_addr_t::from_string(val.as()).to_bytes(); + _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes); return; } if (key.as() == "ip-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO); - out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as()).to_ulong()); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); + byte_vector_t bytes(4); + std::copy(boost::asio::ip::address_v4::from_string(val.as()).to_bytes(), bytes); + _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes); return; } } diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 7158c58d0..caf6623e2 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -32,7 +32,14 @@ #define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) #define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) #define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout //////////////////////////////////////////////////////////////////////// +#define EE_MBOARD_REV_LSB 0x00 //1 byte +#define EE_MBOARD_REV_MSB 0x01 //1 byte +#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian /*! * The usrp2 interface class: diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 5c1d7f9e3..2b7bdeea2 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -72,7 +72,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION); - ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); + ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO); udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); //loop and recieve until the timeout @@ -83,7 +83,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ if (len >= sizeof(usrp2_ctrl_data_t)){ //handle the received data switch(ntohl(ctrl_data_in.id)){ - case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: + case USRP2_CTRL_ID_WAZZUP_DUDE: //make a boost asio ipv4 with the raw addr in host byte order boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; -- cgit v1.2.3 From d20595a3fe9ba864d824c160c3db39fc7a3d1e7c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 09:52:43 -0700 Subject: calculate max samples per packet using otw type --- host/lib/usrp/usrp2/io_impl.cpp | 23 +++++++++++++++-------- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 ++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 27 +++++++++++++++++++-------- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 7c9d003ce..de0c76eb1 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -31,10 +31,16 @@ namespace asio = boost::asio; * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //setup otw type - _otw_type.width = 16; - _otw_type.shift = 0; - _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //initially empty copy buffer _rx_copy_buff = asio::buffer("", 0); @@ -49,7 +55,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); + std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -121,7 +128,7 @@ size_t usrp2_impl::send( boost::uint32_t *tx_mem = send_buff->cast(); size_t num_samps = std::min(std::min( asio::buffer_size(buff)/io_type.size, - size_t(_max_tx_samples_per_packet)), + size_t(max_tx_samps_per_packet())), send_buff->size()/io_type.size ); @@ -148,7 +155,7 @@ size_t usrp2_impl::send( //copy-convert the samples into the send buffer convert_io_type_to_otw_type( asio::buffer_cast(buff), io_type, - (void*)items, _otw_type, + (void*)items, _tx_otw_type, num_samps ); @@ -192,7 +199,7 @@ size_t usrp2_impl::recv( //copy-convert the samples from the recv buffer convert_otw_type_to_io_type( - (const void*)items, _otw_type, + (const void*)items, _rx_otw_type, asio::buffer_cast(buff), io_type, num_samps ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ae68d158..a10529102 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b7bdeea2..3b7156802 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -211,11 +211,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_rx_samples_per_packet); + val = max_rx_samps_per_packet(); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_tx_samples_per_packet); + val = max_tx_samps_per_packet(); return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index c5b6af810..e2d37e512 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -125,21 +125,32 @@ private: void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; + + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ static const size_t _mtu = 1500; //FIXME we have no idea static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp) - static const size_t _max_rx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 + static const size_t _max_rx_bytes_per_packet = + _mtu - _hdrs - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) ; - static const size_t _max_tx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - uhd::transport::vrt::max_header_words32 + static const size_t _max_tx_bytes_per_packet = + _mtu - _hdrs - + uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; + size_t max_rx_samps_per_packet(void){ + return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + } + size_t max_tx_samps_per_packet(void){ + return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + } + uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; size_t _fragment_offset_in_samps; - uhd::otw_type_t _otw_type; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); //udp transports for control and data -- cgit v1.2.3 From 17c494b79a99d947a150cdbc582ba331aeb57786 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 14:26:43 -0700 Subject: Added tx timed samples example. Added called to device to get max samples per packet. Removed device props that gave max samples per packet. --- host/examples/CMakeLists.txt | 4 ++ host/examples/rx_timed_samples.cpp | 13 +++-- host/examples/tx_timed_samples.cpp | 92 ++++++++++++++++++++++++++++++++++ host/include/uhd/device.hpp | 33 ++++++++---- host/include/uhd/usrp/device_props.hpp | 4 +- host/lib/usrp/usrp2/io_impl.cpp | 6 +-- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 8 --- host/lib/usrp/usrp2/usrp2_impl.hpp | 12 ++--- 9 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 host/examples/tx_timed_samples.cpp (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 242857625..a537c0901 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -18,3 +18,7 @@ ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp) TARGET_LINK_LIBRARIES(rx_timed_samples uhd) INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) + +ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) +TARGET_LINK_LIBRARIES(tx_timed_samples uhd) +INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4b8774036..d2306c7c4 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string args; int seconds_in_future; size_t total_num_samps; - double rx_rate; + double rx_rate, freq; //setup the program options po::options_description desc("Allowed options"); @@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to receive") ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to receive") ("rxrate", po::value(&rx_rate)->default_value(100e6/16), "rate of incoming samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + po::notify(vm); //print the help message if (vm.count("help")){ @@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ sdev->set_rx_rate(rx_rate); std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl; std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_rx_freq(freq); sdev->set_time_now(uhd::time_spec_t(0)); //setup streaming @@ -78,10 +80,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ uhd::rx_metadata_t md; - std::complex buff[1000]; + std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff, sizeof(buff)), - md, uhd::io_type_t::COMPLEX_FLOAT32 + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET ); if (num_rx_samps == 0) continue; //wait for packets with contents diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp new file mode 100644 index 000000000..6dee69cd5 --- /dev/null +++ b/host/examples/tx_timed_samples.cpp @@ -0,0 +1,92 @@ +// +// 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 + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + //variables to be set by po + std::string args; + int seconds_in_future; + size_t total_num_samps; + double tx_rate, freq; + float ampl; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit") + ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") + ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") + ("ampl", po::value(&l)->default_value(0.3), "amplitude of each sample") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + + //set properties on the device + std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; + sdev->set_tx_rate(tx_rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; + std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_tx_freq(freq); + sdev->set_time_now(uhd::time_spec_t(0)); + + //data to send + std::vector > buff(total_num_samps, std::complex(ampl, ampl)); + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = true; + md.has_time_spec = true; + md.time_spec = uhd::time_spec_t(seconds_in_future); + + //send the entire buffer, let the driver handle fragmentation + size_t num_tx_samps = dev->send( + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; + + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index a76b34ee2..27b461184 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -86,6 +86,16 @@ public: SEND_MODE_ONE_PACKET = 1 }; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -113,16 +123,6 @@ public: send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; - /*! - * Recv modes for the device recv routine. - */ - enum recv_mode_t{ - //! Tells the recv routine to recv the entire buffer - RECV_MODE_FULL_BUFF = 0, - //! Tells the recv routine to return after one packet - RECV_MODE_ONE_PACKET = 1 - }; - /*! * Receive a buffer containing IF data and its metadata. * @@ -161,6 +161,19 @@ public: const io_type_t &io_type, recv_mode_t recv_mode = RECV_MODE_ONE_PACKET ) = 0; + + /*! + * Get the maximum number of samples per packet on send. + * \return the number of samples + */ + virtual size_t get_max_send_samps_per_packet(void) const = 0; + + /*! + * Get the maximum number of samples per packet on recv. + * \return the number of samples + */ + virtual size_t get_max_recv_samps_per_packet(void) const = 0; + }; } //namespace uhd diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index b8f6f5cd4..983bcb672 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{ enum device_prop_t{ DEVICE_PROP_NAME = 'n', //ro, std::string DEVICE_PROP_MBOARD = 'm', //ro, wax::obj - DEVICE_PROP_MBOARD_NAMES = 'M', //ro, prop_names_t - DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t - DEVICE_PROP_MAX_TX_SAMPLES = 't' //ro, size_t + DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t }; //////////////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 485cc2bd9..b6ab919e7 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -48,8 +48,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -77,7 +77,7 @@ size_t usrp2_impl::send( io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport, //zero copy interface - max_tx_samps_per_packet() + get_max_send_samps_per_packet() ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index a10529102..f17efd88e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 3b7156802..af3ec216a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); return; - case DEVICE_PROP_MAX_RX_SAMPLES: - val = max_rx_samps_per_packet(); - return; - - case DEVICE_PROP_MAX_TX_SAMPLES: - val = max_tx_samps_per_packet(); - return; - default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ad674f594..afea9683c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,12 +104,18 @@ public: ~usrp2_impl(void); //the io interface + size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } size_t send( const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t ); + size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } size_t recv( const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, @@ -146,12 +152,6 @@ private: _mtu - _hdrs - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; - size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); - } - size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); - } vrt_packet_handler::recv_state _packet_handler_recv_state; vrt_packet_handler::send_state _packet_handler_send_state; -- cgit v1.2.3 From 830e34fe30737432a5bfa4b19cc4bad5b4e425ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 11:47:53 -0700 Subject: fix for time64 register write order --- host/lib/usrp/usrp2/mboard_impl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'host/lib/usrp/usrp2/mboard_impl.cpp') diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index f17efd88e..a2aeadf16 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -83,13 +83,15 @@ void usrp2_impl::update_clock_config(void){ } void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ - //set ticks and seconds - _iface->poke32(FR_TIME64_SECS, time_spec.secs); + //set the ticks _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq())); - //set the register to latch it all in + //set the flags register boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS; _iface->poke32(FR_TIME64_IMM, imm_flags); + + //set the seconds (latches in all 3 registers) + _iface->poke32(FR_TIME64_SECS, time_spec.secs); } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ -- cgit v1.2.3