From de4d2fca9030cda04de1457abe8cba6a70ba0b95 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 2 Jul 2012 13:53:11 -0700 Subject: usrp: added fifo_ctrl_excelsior for FIFO control + async msgs The fifo_ctrl_excelsior is the host code for dealing with E100/B100 control messages and async messages. It also has the SPI implementation. Timed commands are implemented on top of this code. --- host/lib/usrp/common/CMakeLists.txt | 3 +- host/lib/usrp/common/fifo_ctrl_excelsior.cpp | 293 +++++++++++++++++++++++++++ host/lib/usrp/common/fifo_ctrl_excelsior.hpp | 63 ++++++ 3 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 host/lib/usrp/common/fifo_ctrl_excelsior.cpp create mode 100644 host/lib/usrp/common/fifo_ctrl_excelsior.hpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/common/CMakeLists.txt b/host/lib/usrp/common/CMakeLists.txt index 9abd34afa..fa07e3d1d 100644 --- a/host/lib/usrp/common/CMakeLists.txt +++ b/host/lib/usrp/common/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2011 Ettus Research LLC +# Copyright 2011-2012 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 @@ -32,4 +32,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/apply_corrections.cpp ${CMAKE_CURRENT_SOURCE_DIR}/validate_subdev_spec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/recv_packet_demuxer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fifo_ctrl_excelsior.cpp ) diff --git a/host/lib/usrp/common/fifo_ctrl_excelsior.cpp b/host/lib/usrp/common/fifo_ctrl_excelsior.cpp new file mode 100644 index 000000000..5e4a1e243 --- /dev/null +++ b/host/lib/usrp/common/fifo_ctrl_excelsior.cpp @@ -0,0 +1,293 @@ +// +// Copyright 2012 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 "fifo_ctrl_excelsior.hpp" +#include "async_packet_handler.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::transport; + +static const size_t POKE32_CMD = (1 << 8); +static const size_t PEEK32_CMD = 0; +static const double ACK_TIMEOUT = 0.5; +static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command +static const boost::uint32_t MAX_SEQS_OUT = 15; + +#define SPI_DIV _config.spi_base + 0 +#define SPI_CTRL _config.spi_base + 4 +#define SPI_DATA _config.spi_base + 8 +#define SPI_DIVIDER 4 + +struct ctrl_result_t{ + boost::uint32_t msg[2]; +}; + +class fifo_ctrl_excelsior_impl : public fifo_ctrl_excelsior{ +public: + + fifo_ctrl_excelsior_impl(zero_copy_if::sptr xport, const fifo_ctrl_excelsior_config &config): + _xport(xport), + _config(config), + _seq_out(0), + _seq_ack(0), + _timeout(ACK_TIMEOUT), + _async_fifo(1000), + _ctrl_fifo(MAX_SEQS_OUT+1) + { + while (_xport->get_recv_buff(0.0)){} //flush + this->set_time(uhd::time_spec_t(0.0)); + this->set_tick_rate(1.0); //something possible but bogus + _msg_task = task::make(boost::bind(&fifo_ctrl_excelsior_impl::handle_msg, this)); + this->init_spi(); + } + + ~fifo_ctrl_excelsior_impl(void){ + _timeout = ACK_TIMEOUT; //reset timeout to something small + UHD_SAFE_CALL( + this->peek32(0); //dummy peek with the purpose of ack'ing all packets + ) + } + + bool pop_async_msg(async_metadata_t &async_metadata, double timeout){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return _async_fifo.pop_with_timed_wait(async_metadata, timeout); + } + + void handle_msg(void){ + set_thread_priority_safe(); + while (not boost::this_thread::interruption_requested()){ + this->handle_msg1(); + } + } + + void handle_msg1(void){ + managed_recv_buffer::sptr buff = _xport->get_recv_buff(); + if (not buff) return; + const boost::uint32_t *pkt = buff->cast(); + vrt::if_packet_info_t packet_info; + packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); + try{ + vrt::if_hdr_unpack_le(pkt, packet_info); + } + catch(const std::exception &ex){ + UHD_MSG(error) << "FIFO ctrl bad VITA packet: " << ex.what() << std::endl; + } + if (packet_info.has_sid and packet_info.sid == _config.ctrl_sid_base){ + ctrl_result_t res = ctrl_result_t(); + res.msg[0] = uhd::wtohx(pkt[packet_info.num_header_words32+0]); + res.msg[1] = uhd::wtohx(pkt[packet_info.num_header_words32+1]); + _ctrl_fifo.push_with_haste(res); + } + else if (packet_info.has_sid and packet_info.sid >= _config.async_sid_base and packet_info.sid <= _config.async_sid_base + _config.num_async_chan){ + async_metadata_t metadata; + load_metadata_from_buff(uhd::wtohx, metadata, packet_info, pkt, _tick_rate, packet_info.sid - _config.async_sid_base); + _async_fifo.push_with_pop_on_full(metadata); + standard_async_msg_prints(metadata); + } + else{ + UHD_MSG(error) << "FIFO ctrl got unknown SID: " << packet_info.sid << std::endl; + } + } + + /******************************************************************* + * Peek and poke 32 bit implementation + ******************************************************************/ + void poke32(wb_addr_type addr, boost::uint32_t data){ + boost::mutex::scoped_lock lock(_mutex); + + this->send_pkt(addr, data, POKE32_CMD); + + this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + } + + boost::uint32_t peek32(wb_addr_type addr){ + boost::mutex::scoped_lock lock(_mutex); + + this->send_pkt(addr, 0, PEEK32_CMD); + + return this->wait_for_ack(_seq_out); + } + + /******************************************************************* + * Peek and poke 16 bit not implemented + ******************************************************************/ + void poke16(wb_addr_type, boost::uint16_t){ + throw uhd::not_implemented_error("poke16 not implemented in fifo ctrl module"); + } + + boost::uint16_t peek16(wb_addr_type){ + throw uhd::not_implemented_error("peek16 not implemented in fifo ctrl module"); + } + + /******************************************************************* + * FIFO controlled SPI implementation + ******************************************************************/ + void init_spi(void){ + boost::mutex::scoped_lock lock(_mutex); + + this->send_pkt(SPI_DIV, SPI_DIVIDER, POKE32_CMD); + this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + + _ctrl_word_cache = 0; // force update first time around + } + + boost::uint32_t transact_spi( + int which_slave, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback + ){ + boost::mutex::scoped_lock lock(_mutex); + + //load control word + boost::uint32_t ctrl_word = 0; + ctrl_word |= ((which_slave & 0xffffff) << 0); + ctrl_word |= ((num_bits & 0x3ff) << 24); + if (config.mosi_edge == spi_config_t::EDGE_FALL) ctrl_word |= (1 << 31); + if (config.miso_edge == spi_config_t::EDGE_RISE) ctrl_word |= (1 << 30); + + //load data word (must be in upper bits) + const boost::uint32_t data_out = data << (32 - num_bits); + + //conditionally send control word + if (_ctrl_word_cache != ctrl_word){ + this->send_pkt(SPI_CTRL, ctrl_word, POKE32_CMD); + this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + _ctrl_word_cache = ctrl_word; + } + + //send data word + this->send_pkt(SPI_DATA, data_out, POKE32_CMD); + this->wait_for_ack(_seq_out-MAX_SEQS_OUT); + + //conditional readback + if (readback){ + this->send_pkt(_config.spi_rb, 0, PEEK32_CMD); + return this->wait_for_ack(_seq_out); + } + + return 0; + } + + /******************************************************************* + * Update methods for time + ******************************************************************/ + void set_time(const uhd::time_spec_t &time){ + boost::mutex::scoped_lock lock(_mutex); + _time = time; + _use_time = _time != uhd::time_spec_t(0.0); + if (_use_time) _timeout = MASSIVE_TIMEOUT; //permanently sets larger timeout + } + + void set_tick_rate(const double rate){ + boost::mutex::scoped_lock lock(_mutex); + _tick_rate = rate; + } + +private: + + /******************************************************************* + * Primary control and interaction private methods + ******************************************************************/ + UHD_INLINE void send_pkt(wb_addr_type addr, boost::uint32_t data, int cmd){ + managed_send_buffer::sptr buff = _xport->get_send_buff(0.0); + if (not buff){ + throw uhd::runtime_error("fifo ctrl timed out getting a send buffer"); + } + boost::uint32_t *pkt = buff->cast(); + + //load packet info + vrt::if_packet_info_t packet_info; + packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_CONTEXT; + packet_info.num_payload_words32 = 2; + packet_info.num_payload_bytes = packet_info.num_payload_words32*sizeof(boost::uint32_t); + packet_info.packet_count = ++_seq_out; + packet_info.tsf = _time.to_ticks(_tick_rate); + packet_info.sob = false; + packet_info.eob = false; + packet_info.has_sid = false; + packet_info.has_cid = false; + packet_info.has_tsi = false; + packet_info.has_tsf = _use_time; + packet_info.has_tlr = false; + + //load header + vrt::if_hdr_pack_le(pkt, packet_info); + + //load payload + const boost::uint32_t ctrl_word = (addr/4 & 0xff) | cmd | (_seq_out << 16); + pkt[packet_info.num_header_words32+0] = uhd::htowx(ctrl_word); + pkt[packet_info.num_header_words32+1] = uhd::htowx(data); + + //send the buffer over the interface + buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32)); + } + + UHD_INLINE bool wraparound_lt16(const boost::int16_t i0, const boost::int16_t i1){ + if (((i0 ^ i1) & 0x8000) == 0) //same sign bits + return boost::uint16_t(i0) < boost::uint16_t(i1); + return boost::int16_t(i1 - i0) > 0; + } + + UHD_INLINE boost::uint32_t wait_for_ack(const boost::uint16_t seq_to_ack){ + + while (wraparound_lt16(_seq_ack, seq_to_ack)){ + ctrl_result_t res = ctrl_result_t(); + if (not _ctrl_fifo.pop_with_timed_wait(res, _timeout)){ + throw uhd::runtime_error("fifo ctrl timed out looking for acks"); + } + _seq_ack = res.msg[0] >> 16; + if (_seq_ack == seq_to_ack) return res.msg[1]; + } + + return 0; + } + + zero_copy_if::sptr _xport; + const fifo_ctrl_excelsior_config _config; + boost::mutex _mutex; + boost::uint16_t _seq_out; + boost::uint16_t _seq_ack; + uhd::time_spec_t _time; + bool _use_time; + double _tick_rate; + double _timeout; + boost::uint32_t _ctrl_word_cache; + bounded_buffer _async_fifo; + bounded_buffer _ctrl_fifo; + task::sptr _msg_task; +}; + + +fifo_ctrl_excelsior::sptr fifo_ctrl_excelsior::make(zero_copy_if::sptr xport, const fifo_ctrl_excelsior_config &config) +{ + return sptr(new fifo_ctrl_excelsior_impl(xport, config)); +} diff --git a/host/lib/usrp/common/fifo_ctrl_excelsior.hpp b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp new file mode 100644 index 000000000..c3ef65a2c --- /dev/null +++ b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp @@ -0,0 +1,63 @@ +// +// Copyright 2012 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_B200_CTRL_HPP +#define INCLUDED_B200_CTRL_HPP + +#include +#include +#include +#include +#include +#include +#include "wb_iface.hpp" +#include + + +struct fifo_ctrl_excelsior_config +{ + size_t async_sid_base; + size_t num_async_chan; + size_t ctrl_sid_base; + size_t spi_base; + size_t spi_rb; +}; + +/*! + * Provide access to peek, poke, spi, and async messages. + */ +class fifo_ctrl_excelsior : public wb_iface, public uhd::spi_iface{ +public: + typedef boost::shared_ptr sptr; + + //! Make a new control object + static sptr make( + uhd::transport::zero_copy_if::sptr xport, + const fifo_ctrl_excelsior_config &config + ); + + //! Set the command time that will activate + virtual void set_time(const uhd::time_spec_t &time) = 0; + + //! Set the tick rate (converting time into ticks) + virtual void set_tick_rate(const double rate) = 0; + + //! Pop an async message from the queue or timeout + virtual bool pop_async_msg(uhd::async_metadata_t &async_metadata, double timeout) = 0; +}; + +#endif /* INCLUDED_B200_CTRL_HPP */ -- cgit v1.2.3 From 7a1824e8fddadd915e2d7490a8b57764b815b09f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 2 Jul 2012 13:59:05 -0700 Subject: b100: squashed host code for fifo control/timed commands This uses the new b100/e100 common core and FIFO control modules. Subsequent commit will be the compatible FPGA merge. --- host/lib/usrp/b100/CMakeLists.txt | 3 +- host/lib/usrp/b100/b100_impl.cpp | 91 ++++++++++++++++------------ host/lib/usrp/b100/b100_impl.hpp | 30 ++++------ host/lib/usrp/b100/b100_regs.hpp | 116 +++++++++--------------------------- host/lib/usrp/b100/dboard_iface.cpp | 2 +- host/lib/usrp/b100/io_impl.cpp | 72 +--------------------- 6 files changed, 99 insertions(+), 215 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt index 1237f52d1..d2c33b512 100644 --- a/host/lib/usrp/b100/CMakeLists.txt +++ b/host/lib/usrp/b100/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2011 Ettus Research LLC +# Copyright 2011-2012 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 @@ -26,7 +26,6 @@ LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF) IF(ENABLE_B100) LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/b100_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index eec777842..94dc88db4 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -17,12 +17,11 @@ #include "apply_corrections.hpp" #include "b100_impl.hpp" -#include "b100_ctrl.hpp" +#include "b100_regs.hpp" #include "fpga_regs_standard.h" #include "usrp_i2c_addr.h" #include "usrp_commands.h" #include -#include "ctrl_packet.hpp" #include #include #include @@ -33,7 +32,6 @@ #include #include #include -#include "b100_regs.hpp" #include #include @@ -188,10 +186,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //create the control transport device_addr_t ctrl_xport_args; - ctrl_xport_args["recv_frame_size"] = boost::lexical_cast(CTRL_PACKET_LENGTH); + ctrl_xport_args["recv_frame_size"] = "512"; ctrl_xport_args["num_recv_frames"] = "16"; - ctrl_xport_args["send_frame_size"] = boost::lexical_cast(CTRL_PACKET_LENGTH); - ctrl_xport_args["num_send_frames"] = "4"; + ctrl_xport_args["send_frame_size"] = "512"; + ctrl_xport_args["num_send_frames"] = "16"; _ctrl_transport = usb_zero_copy::make( handle, @@ -199,17 +197,22 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ 3, 4, //interface, endpoint ctrl_xport_args ); - while (_ctrl_transport->get_recv_buff(0.0)){} //flush ctrl xport this->enable_gpif(true); //////////////////////////////////////////////////////////////////// - // Initialize FPGA wishbone communication + // Initialize FPGA control communication //////////////////////////////////////////////////////////////////// - _fpga_ctrl = b100_ctrl::make(_ctrl_transport); - _fpga_ctrl->poke32(B100_REG_GLOBAL_RESET, 0); //global fpga reset + fifo_ctrl_excelsior_config fifo_ctrl_config; + fifo_ctrl_config.async_sid_base = B100_TX_ASYNC_SID; + fifo_ctrl_config.num_async_chan = 1; + fifo_ctrl_config.ctrl_sid_base = B100_CTRL_MSG_SID; + fifo_ctrl_config.spi_base = TOREG(SR_SPI); + fifo_ctrl_config.spi_rb = REG_RB_SPI; + _fifo_ctrl = fifo_ctrl_excelsior::make(_ctrl_transport, fifo_ctrl_config); + //perform a test peek operation try{ - _fpga_ctrl->peek32(0); + _fifo_ctrl->peek32(0); } //try reset once in the case of failure catch(const uhd::exception &){ @@ -217,7 +220,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ UHD_MSG(warning) << "The control endpoint was left in a bad state.\n" "Attempting endpoint re-enumeration...\n" << std::endl; - _fpga_ctrl.reset(); + _fifo_ctrl.reset(); _ctrl_transport.reset(); _fx2_ctrl->usrp_fx2_reset(); goto b100_impl_constructor_begin; @@ -227,8 +230,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Initialize peripherals after reset //////////////////////////////////////////////////////////////////// - _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, B100_REG_SLAVE(3)); - _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, B100_REG_SLAVE(2)); + _fpga_i2c_ctrl = i2c_core_200::make(_fifo_ctrl, TOREG(SR_I2C), REG_RB_I2C); //////////////////////////////////////////////////////////////////// // Create data transport @@ -242,6 +244,10 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384"); data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); + //let packet padder know the LUT size in number of words32 + const size_t rx_lut_size = size_t(data_xport_args.cast("recv_frame_size", 0.0)); + _fifo_ctrl->poke32(TOREG(SR_PADDER+0), rx_lut_size/sizeof(boost::uint32_t)); + _data_transport = usb_zero_copy::make_wrapper( usb_zero_copy::make( handle, // identifier @@ -251,7 +257,6 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ ), B100_MAX_PKT_BYTE_LIMIT ); - while (_data_transport->get_recv_buff(0.0)){} //flush data xport //////////////////////////////////////////////////////////////////// // Initialize the properties tree @@ -277,12 +282,17 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //^^^ clock created up top, just reg props here... ^^^ _tree->create(mb_path / "tick_rate") .publish(boost::bind(&b100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_tick_rate, _fifo_ctrl, _1)) .subscribe(boost::bind(&b100_impl::update_tick_rate, this, _1)); + //subscribe the command time while we are at it + _tree->create(mb_path / "time/cmd") + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_time, _fifo_ctrl, _1)); + //////////////////////////////////////////////////////////////////// // create codec control objects //////////////////////////////////////////////////////////////////// - _codec_ctrl = b100_codec_ctrl::make(_fpga_spi_ctrl); + _codec_ctrl = b100_codec_ctrl::make(_fifo_ctrl); const fs_path rx_codec_path = mb_path / "rx_codecs/A"; const fs_path tx_codec_path = mb_path / "tx_codecs/A"; _tree->create(rx_codec_path / "name").set("ad9522"); @@ -304,8 +314,8 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create frontend control objects //////////////////////////////////////////////////////////////////// - _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_FRONT)); - _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_FRONT)); + _rx_fe = rx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_RX_FE)); + _tx_fe = tx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_TX_FE)); _tree->create(mb_path / "rx_subdev_spec") .subscribe(boost::bind(&b100_impl::update_rx_subdev_spec, this, _1)); @@ -334,13 +344,17 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create rx dsp control objects //////////////////////////////////////////////////////////////////// - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP0), B100_REG_SR_ADDR(B100_SR_RX_CTRL0), B100_RX_SID_BASE + 0 - )); - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_RX_DSP1), B100_REG_SR_ADDR(B100_SR_RX_CTRL1), B100_RX_SID_BASE + 1 - )); - for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + const size_t num_rx_dsps = _fifo_ctrl->peek32(REG_RB_NUM_RX_DSP); + for (size_t dspno = 0; dspno < num_rx_dsps; dspno++) + { + const size_t sr_off = dspno*32; + _rx_dsps.push_back(rx_dsp_core_200::make( + _fifo_ctrl, + TOREG(SR_RX_DSP0+sr_off), + TOREG(SR_RX_CTRL0+sr_off), + B100_RX_SID_BASE + dspno + )); + _rx_dsps[dspno]->set_link_rate(B100_LINK_RATE_BPS); _tree->access(mb_path / "tick_rate") .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); @@ -363,7 +377,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ // create tx dsp control objects //////////////////////////////////////////////////////////////////// _tx_dsp = tx_dsp_core_200::make( - _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TX_DSP), B100_REG_SR_ADDR(B100_SR_TX_CTRL), B100_TX_ASYNC_SID + _fifo_ctrl, TOREG(SR_TX_DSP), TOREG(SR_TX_CTRL), B100_TX_ASYNC_SID ); _tx_dsp->set_link_rate(B100_LINK_RATE_BPS); _tree->access(mb_path / "tick_rate") @@ -383,12 +397,12 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ // create time control objects //////////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_hi_now = B100_REG_RB_TIME_NOW_HI; - time64_rb_bases.rb_lo_now = B100_REG_RB_TIME_NOW_LO; - time64_rb_bases.rb_hi_pps = B100_REG_RB_TIME_PPS_HI; - time64_rb_bases.rb_lo_pps = B100_REG_RB_TIME_PPS_LO; + time64_rb_bases.rb_hi_now = REG_RB_TIME_NOW_HI; + time64_rb_bases.rb_lo_now = REG_RB_TIME_NOW_LO; + time64_rb_bases.rb_hi_pps = REG_RB_TIME_PPS_HI; + time64_rb_bases.rb_lo_pps = REG_RB_TIME_PPS_LO; _time64 = time64_core_200::make( - _fpga_ctrl, B100_REG_SR_ADDR(B100_SR_TIME64), time64_rb_bases + _fifo_ctrl, TOREG(SR_TIME64), time64_rb_bases ); _tree->access(mb_path / "tick_rate") .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); @@ -412,7 +426,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create user-defined control objects //////////////////////////////////////////////////////////////////// - _user = user_settings_core_200::make(_fpga_ctrl, B100_REG_SR_ADDR(B100_SR_USER_REGS)); + _user = user_settings_core_200::make(_fifo_ctrl, TOREG(SR_USER_REGS)); _tree->create(mb_path / "user/regs") .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1)); @@ -438,7 +452,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ .subscribe(boost::bind(&b100_impl::set_db_eeprom, this, "gdb", _1)); //create a new dboard interface and manager - _dboard_iface = make_b100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _dboard_iface = make_b100_dboard_iface(_fifo_ctrl, _fpga_i2c_ctrl, _fifo_ctrl/*spi*/, _clock_ctrl, _codec_ctrl); _tree->create(mb_path / "dboards/A/iface").set(_dboard_iface); _dboard_manager = dboard_manager::make( rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, @@ -458,7 +472,11 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ } //initialize io handling - this->io_init(); + _recv_demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), B100_RX_SID_BASE); + + //allocate streamer weak ptrs containers + _rx_streamers.resize(_rx_dsps.size()); + _tx_streamers.resize(1/*known to be 1 dsp*/); //////////////////////////////////////////////////////////////////// // do some post-init tasks @@ -483,8 +501,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ } b100_impl::~b100_impl(void){ - //set an empty async callback now that we deconstruct - _fpga_ctrl->set_async_cb(b100_ctrl::async_cb_type()); + //NOP } void b100_impl::check_fw_compat(void){ @@ -502,7 +519,7 @@ void b100_impl::check_fw_compat(void){ } void b100_impl::check_fpga_compat(void){ - const boost::uint32_t fpga_compat_num = _fpga_ctrl->peek32(B100_REG_RB_COMPAT); + const boost::uint32_t fpga_compat_num = _fifo_ctrl->peek32(REG_RB_COMPAT); boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff; if (fpga_major == 0){ //old version scheme fpga_major = fpga_minor; diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp index 22e22bcff..250229fb8 100644 --- a/host/lib/usrp/b100/b100_impl.hpp +++ b/host/lib/usrp/b100/b100_impl.hpp @@ -19,20 +19,19 @@ #define INCLUDED_B100_IMPL_HPP #include "fx2_ctrl.hpp" -#include "b100_ctrl.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" -#include "spi_core_100.hpp" -#include "i2c_core_100.hpp" +#include "i2c_core_200.hpp" #include "rx_frontend_core_200.hpp" #include "tx_frontend_core_200.hpp" #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" #include "time64_core_200.hpp" +#include "fifo_ctrl_excelsior.hpp" #include "user_settings_core_200.hpp" +#include "recv_packet_demuxer.hpp" #include #include -#include #include #include #include @@ -47,10 +46,11 @@ static const double B100_LINK_RATE_BPS = 256e6/5; //pratical link rate (< 480 Mbps) static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx"; static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin"; -static const boost::uint16_t B100_FW_COMPAT_NUM = 0x03; -static const boost::uint16_t B100_FPGA_COMPAT_NUM = 10; -static const boost::uint32_t B100_RX_SID_BASE = 2; -static const boost::uint32_t B100_TX_ASYNC_SID = 1; +static const boost::uint16_t B100_FW_COMPAT_NUM = 0x04; +static const boost::uint16_t B100_FPGA_COMPAT_NUM = 11; +static const boost::uint32_t B100_RX_SID_BASE = 30; +static const boost::uint32_t B100_TX_ASYNC_SID = 10; +static const boost::uint32_t B100_CTRL_MSG_SID = 20; static const double B100_DEFAULT_TICK_RATE = 64e6; static const size_t B100_MAX_PKT_BYTE_LIMIT = 2048; static const std::string B100_EEPROM_MAP_KEY = "B100"; @@ -80,8 +80,8 @@ private: uhd::property_tree::sptr _tree; //controllers - spi_core_100::sptr _fpga_spi_ctrl; - i2c_core_100::sptr _fpga_i2c_ctrl; + fifo_ctrl_excelsior::sptr _fifo_ctrl; + i2c_core_200::sptr _fpga_i2c_ctrl; rx_frontend_core_200::sptr _rx_fe; tx_frontend_core_200::sptr _tx_fe; std::vector _rx_dsps; @@ -90,20 +90,17 @@ private: user_settings_core_200::sptr _user; b100_clock_ctrl::sptr _clock_ctrl; b100_codec_ctrl::sptr _codec_ctrl; - b100_ctrl::sptr _fpga_ctrl; uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; //transports - uhd::transport::zero_copy_if::sptr _data_transport, _ctrl_transport; + uhd::transport::zero_copy_if::sptr _ctrl_transport; + uhd::transport::zero_copy_if::sptr _data_transport; + uhd::usrp::recv_packet_demuxer::sptr _recv_demuxer; //dboard stuff uhd::usrp::dboard_manager::sptr _dboard_manager; uhd::usrp::dboard_iface::sptr _dboard_iface; - //handle io stuff - UHD_PIMPL_DECL(io_impl) _io_impl; - void io_init(void); - //device properties interface uhd::property_tree::sptr get_tree(void) const{ return _tree; @@ -126,7 +123,6 @@ private: void update_clock_source(const std::string &); void enable_gpif(const bool); void clear_fpga_fifo(void); - void handle_async_message(uhd::transport::managed_recv_buffer::sptr); uhd::sensor_value_t get_ref_locked(void); void set_rx_fe_corrections(const double); void set_tx_fe_corrections(const double); diff --git a/host/lib/usrp/b100/b100_regs.hpp b/host/lib/usrp/b100/b100_regs.hpp index 987a09f03..48eb0460d 100644 --- a/host/lib/usrp/b100/b100_regs.hpp +++ b/host/lib/usrp/b100/b100_regs.hpp @@ -15,109 +15,49 @@ // along with this program. If not, see . // -//////////////////////////////////////////////////////////////// -// -// Memory map for wishbone bus -// -//////////////////////////////////////////////////////////////// - -// All addresses are byte addresses. All accesses are word (16-bit) accesses. -// This means that address bit 0 is usually 0. -// There are 11 bits of address for the control. - #ifndef INCLUDED_B100_REGS_HPP #define INCLUDED_B100_REGS_HPP -///////////////////////////////////////////////////// -// Slave pointers +#include -#define B100_REG_SLAVE(n) ((n)<<7) +#define TOREG(x) ((x)*4) -///////////////////////////////////////////////////// -// Slave 0 -- Misc Regs +#define localparam static const int -#define B100_REG_MISC_BASE B100_REG_SLAVE(0) +localparam SR_MISC = 0; // 5 +localparam SR_USER_REGS = 5; // 2 +localparam SR_PADDER = 10; // 2 -#define B100_REG_MISC_LED B100_REG_MISC_BASE + 0 -#define B100_REG_MISC_SW B100_REG_MISC_BASE + 2 -#define B100_REG_MISC_CGEN_CTRL B100_REG_MISC_BASE + 4 -#define B100_REG_MISC_CGEN_ST B100_REG_MISC_BASE + 6 +localparam SR_TX_CTRL = 32; // 6 +localparam SR_TX_DSP = 40; // 5 +localparam SR_TX_FE = 48; // 5 -///////////////////////////////////////////////////// -// Slave 1 -- UART -// CLKDIV is 16 bits, others are only 8 +localparam SR_RX_CTRL0 = 96; // 9 +localparam SR_RX_DSP0 = 106; // 7 +localparam SR_RX_FE = 114; // 5 -#define B100_REG_UART_BASE B100_REG_SLAVE(1) +localparam SR_RX_CTRL1 = 128; // 9 +localparam SR_RX_DSP1 = 138; // 7 -#define B100_REG_UART_CLKDIV B100_REG_UART_BASE + 0 -#define B100_REG_UART_TXLEVEL B100_REG_UART_BASE + 2 -#define B100_REG_UART_RXLEVEL B100_REG_UART_BASE + 4 -#define B100_REG_UART_TXCHAR B100_REG_UART_BASE + 6 -#define B100_REG_UART_RXCHAR B100_REG_UART_BASE + 8 +localparam SR_TIME64 = 192; // 6 +localparam SR_SPI = 208; // 3 +localparam SR_I2C = 216; // 1 +localparam SR_GPIO = 224; // 5 -///////////////////////////////////////////////////// -// Slave 2 -- SPI Core -//these are 32-bit registers mapped onto the 16-bit Wishbone bus. -//Using peek32/poke32 should allow transparent use of these registers. -#define B100_REG_SPI_BASE B100_REG_SLAVE(2) +#define REG_RB_TIME_NOW_HI TOREG(10) +#define REG_RB_TIME_NOW_LO TOREG(11) +#define REG_RB_TIME_PPS_HI TOREG(14) +#define REG_RB_TIME_PPS_LO TOREG(15) +#define REG_RB_SPI TOREG(0) +#define REG_RB_COMPAT TOREG(1) +#define REG_RB_GPIO TOREG(3) +#define REG_RB_I2C TOREG(2) +#define REG_RB_NUM_RX_DSP TOREG(6) //spi slave constants #define B100_SPI_SS_AD9862 (1 << 2) #define B100_SPI_SS_TX_DB (1 << 1) #define B100_SPI_SS_RX_DB (1 << 0) -//////////////////////////////////////////////// -// Slave 3 -- I2C Core - -#define B100_REG_I2C_BASE B100_REG_SLAVE(3) - -/////////////////////////////////////////////////// -// Slave 7 -- Readback Mux 32 - -#define B100_REG_RB_MUX_32_BASE B100_REG_SLAVE(7) - -#define B100_REG_RB_TIME_NOW_HI B100_REG_RB_MUX_32_BASE + 0 -#define B100_REG_RB_TIME_NOW_LO B100_REG_RB_MUX_32_BASE + 4 -#define B100_REG_RB_TIME_PPS_HI B100_REG_RB_MUX_32_BASE + 8 -#define B100_REG_RB_TIME_PPS_LO B100_REG_RB_MUX_32_BASE + 12 -#define B100_REG_RB_MISC_TEST32 B100_REG_RB_MUX_32_BASE + 16 -#define B100_REG_RB_COMPAT B100_REG_RB_MUX_32_BASE + 24 -#define B100_REG_RB_GPIO B100_REG_RB_MUX_32_BASE + 28 - -//////////////////////////////////////////////////// -// Slaves 8 & 9 -- Settings Bus -// -// Output-only, no readback, 64 registers total -// Each register must be written 32 bits at a time -// First the address xxx_xx00 and then xxx_xx10 -// 64 total regs in address space -#define B100_SR_RX_CTRL0 0 // 9 regs (+0 to +8) -#define B100_SR_RX_DSP0 10 // 4 regs (+0 to +3) -#define B100_SR_RX_CTRL1 16 // 9 regs (+0 to +8) -#define B100_SR_RX_DSP1 26 // 4 regs (+0 to +3) -#define B100_SR_TX_CTRL 32 // 4 regs (+0 to +3) -#define B100_SR_TX_DSP 38 // 3 regs (+0 to +2) - -#define B100_SR_TIME64 42 // 6 regs (+0 to +5) -#define B100_SR_RX_FRONT 48 // 5 regs (+0 to +4) -#define B100_SR_TX_FRONT 54 // 5 regs (+0 to +4) - -#define B100_SR_REG_TEST32 60 // 1 reg -#define B100_SR_CLEAR_FIFO 61 // 1 reg -#define B100_SR_GLOBAL_RESET 63 // 1 reg -#define B100_SR_USER_REGS 64 // 2 regs - -#define B100_SR_GPIO 128 - -#define B100_REG_SR_ADDR(n) (B100_REG_SLAVE(8) + (4*(n))) - -#define B100_REG_SR_MISC_TEST32 B100_REG_SR_ADDR(B100_SR_REG_TEST32) - -///////////////////////////////////////////////// -// Magic reset regs -//////////////////////////////////////////////// -#define B100_REG_CLEAR_FIFO B100_REG_SR_ADDR(B100_SR_CLEAR_FIFO) -#define B100_REG_GLOBAL_RESET B100_REG_SR_ADDR(B100_SR_GLOBAL_RESET) - -#endif +#endif /*INCLUDED_B100_REGS_HPP*/ diff --git a/host/lib/usrp/b100/dboard_iface.cpp b/host/lib/usrp/b100/dboard_iface.cpp index 39ad5c5ac..25604da72 100644 --- a/host/lib/usrp/b100/dboard_iface.cpp +++ b/host/lib/usrp/b100/dboard_iface.cpp @@ -45,7 +45,7 @@ public: _spi_iface = spi_iface; _clock = clock; _codec = codec; - _gpio = gpio_core_200::make(_wb_iface, B100_REG_SR_ADDR(B100_SR_GPIO), B100_REG_RB_GPIO); + _gpio = gpio_core_200::make(_wb_iface, TOREG(SR_GPIO), REG_RB_GPIO); //init the clock rate shadows this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp index 674380cca..723756dcc 100644 --- a/host/lib/usrp/b100/io_impl.cpp +++ b/host/lib/usrp/b100/io_impl.cpp @@ -15,16 +15,10 @@ // along with this program. If not, see . // -#include "recv_packet_demuxer.hpp" #include "validate_subdev_spec.hpp" -#include "async_packet_handler.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" -#include "usrp_commands.h" #include "b100_impl.hpp" -#include "b100_regs.hpp" -#include -#include #include #include #include @@ -37,66 +31,6 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; -/*********************************************************************** - * IO Implementation Details - **********************************************************************/ -struct b100_impl::io_impl{ - io_impl(void): - async_msg_fifo(1000/*messages deep*/) - { /* NOP */ } - - zero_copy_if::sptr data_transport; - bounded_buffer async_msg_fifo; - recv_packet_demuxer::sptr demuxer; - double tick_rate; -}; - -/*********************************************************************** - * Initialize internals within this file - **********************************************************************/ -void b100_impl::io_init(void){ - - //clear fifo state machines - _fpga_ctrl->poke32(B100_REG_CLEAR_FIFO, 0); - - //allocate streamer weak ptrs containers - _rx_streamers.resize(_rx_dsps.size()); - _tx_streamers.resize(1/*known to be 1 dsp*/); - - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, ()); - _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), B100_RX_SID_BASE); - - //now its safe to register the async callback - _fpga_ctrl->set_async_cb(boost::bind(&b100_impl::handle_async_message, this, _1)); -} - -void b100_impl::handle_async_message(managed_recv_buffer::sptr rbuf){ - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = rbuf->size()/sizeof(boost::uint32_t); - const boost::uint32_t *vrt_hdr = rbuf->cast(); - try{ - vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info); - } - catch(const std::exception &e){ - UHD_MSG(error) << "Error (handle_async_message): " << e.what() << std::endl; - } - - if (if_packet_info.sid == B100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - - //fill in the async metadata - async_metadata_t metadata; - load_metadata_from_buff(uhd::wtohx, metadata, if_packet_info, vrt_hdr, _io_impl->tick_rate); - - //push the message onto the queue - _io_impl->async_msg_fifo.push_with_pop_on_full(metadata); - - //print some fastpath messages - standard_async_msg_prints(metadata); - } - else UHD_MSG(error) << "Unknown async packet" << std::endl; -} - void b100_impl::update_rates(void){ const fs_path mb_path = "/mboards/0"; _tree->access(mb_path / "tick_rate").update(); @@ -111,7 +45,6 @@ void b100_impl::update_rates(void){ } void b100_impl::update_tick_rate(const double rate){ - _io_impl->tick_rate = rate; //update the tick rate on all existing streamers -> thread safe for (size_t i = 0; i < _rx_streamers.size(); i++){ @@ -181,8 +114,7 @@ void b100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ bool b100_impl::recv_async_msg( async_metadata_t &async_metadata, double timeout ){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); + return _fifo_ctrl->pop_async_msg(async_metadata, timeout); } /*********************************************************************** @@ -227,7 +159,7 @@ rx_streamer::sptr b100_impl::get_rx_stream(const uhd::stream_args_t &args_){ _rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this _rx_dsps[dsp]->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( - &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1 + &recv_packet_demuxer::get_recv_buff, _recv_demuxer, dsp, _1 ), true /*flush*/); my_streamer->set_overflow_handler(chan_i, boost::bind( &rx_dsp_core_200::handle_overflow, _rx_dsps[dsp] -- cgit v1.2.3 From 58484632eb793b1ee1ffd06b9807023551133a1b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 2 Jul 2012 14:08:12 -0700 Subject: e100: squashed host code for fifo control/timed commands This uses the new b100/e100 common core and FIFO control modules. Subsequent commit will be the compatible FPGA merge. Conflicts: host/lib/usrp/e100/io_impl.cpp --- host/lib/usrp/e100/dboard_iface.cpp | 2 +- host/lib/usrp/e100/e100_ctrl.cpp | 181 +++++++++++++++++++++++------- host/lib/usrp/e100/e100_ctrl.hpp | 9 +- host/lib/usrp/e100/e100_impl.cpp | 145 ++++++++++++++---------- host/lib/usrp/e100/e100_impl.hpp | 22 ++-- host/lib/usrp/e100/e100_regs.hpp | 130 +++++---------------- host/lib/usrp/e100/include/linux/usrp_e.h | 4 +- host/lib/usrp/e100/io_impl.cpp | 143 +---------------------- 8 files changed, 272 insertions(+), 364 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/e100/dboard_iface.cpp b/host/lib/usrp/e100/dboard_iface.cpp index 6afc7bc48..532b2dc9e 100644 --- a/host/lib/usrp/e100/dboard_iface.cpp +++ b/host/lib/usrp/e100/dboard_iface.cpp @@ -45,7 +45,7 @@ public: _spi_iface = spi_iface; _clock = clock; _codec = codec; - _gpio = gpio_core_200::make(_wb_iface, E100_REG_SR_ADDR(UE_SR_GPIO), E100_REG_RB_GPIO); + _gpio = gpio_core_200::make(_wb_iface, TOREG(SR_GPIO), REG_RB_GPIO); //init the clock rate shadows this->set_clock_rate(UNIT_RX, _clock->get_fpga_clock_rate()); diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index eb529c9c1..408d259dc 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2011-2012 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 @@ -23,13 +23,16 @@ #include //ioctl #include //open, close #include //ioctl structures and constants +#include //poll #include //sleep #include +#include #include #include #include using namespace uhd; +using namespace uhd::transport; /*********************************************************************** * Sysfs GPIO wrapper class @@ -70,6 +73,53 @@ private: std::fstream _value_file; }; +/*********************************************************************** + * Protection for dual GPIO access - sometimes MISO, sometimes have resp + **********************************************************************/ +static boost::mutex gpio_has_resp_mutex; +static boost::condition_variable gpio_has_resp_cond; +static bool gpio_has_resp_claimed = false; +static gpio gpio_has_resp(147, "in"); + +struct gpio_has_resp_claimer +{ + gpio_has_resp_claimer(void) + { + boost::mutex::scoped_lock lock(gpio_has_resp_mutex); + gpio_has_resp_claimed = true; + } + + ~gpio_has_resp_claimer(void) + { + boost::mutex::scoped_lock lock(gpio_has_resp_mutex); + gpio_has_resp_claimed = false; + lock.unlock(); + gpio_has_resp_cond.notify_one(); + } +}; + +static inline bool gpio_has_resp_value(void) +{ + boost::mutex::scoped_lock lock(gpio_has_resp_mutex); + while (gpio_has_resp_claimed) + { + gpio_has_resp_cond.wait(lock); + } + return bool(gpio_has_resp()); +} + +static bool inline gpio_has_resp_wait(const double timeout) +{ + if (gpio_has_resp_value()) return true; + const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1e6)); + while (boost::get_system_time() < exit_time) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + if (gpio_has_resp_value()) return true; + } + return false; +} + /*********************************************************************** * Aux spi implementation **********************************************************************/ @@ -79,7 +129,8 @@ public: spi_sclk_gpio(65, "out"), spi_sen_gpio(186, "out"), spi_mosi_gpio(145, "out"), - spi_miso_gpio(147, "in"){} + //spi_miso_gpio(147, "in"){} + spi_miso_gpio(gpio_has_resp){} boost::uint32_t transact_spi( int, const spi_config_t &, //not used params @@ -87,6 +138,8 @@ public: size_t num_bits, bool readback ){ + gpio_has_resp_claimer claimer(); + boost::uint32_t rb_bits = 0; this->spi_sen_gpio(0); @@ -105,7 +158,7 @@ public: } private: - gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, spi_miso_gpio; + gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, &spi_miso_gpio; }; uhd::spi_iface::sptr e100_ctrl::make_aux_spi_iface(void){ @@ -243,6 +296,57 @@ uhd::uart_iface::sptr e100_ctrl::make_gps_uart_iface(const std::string &node){ return uhd::uart_iface::sptr(new uart_dev_iface(node)); } +/*********************************************************************** + * Simple managed buffers + **********************************************************************/ +struct e100_simpl_mrb : managed_recv_buffer +{ + usrp_e_ctl32 data; + e100_ctrl *ctrl; + + void release(void) + { + //NOP + } + + sptr get_new(void) + { + const size_t max_words32 = 8; //.LAST_ADDR(10'h00f)) resp_fifo_to_gpmc + + //load the data struct + data.offset = 0; + data.count = max_words32; + + //call the ioctl + ctrl->ioctl(USRP_E_READ_CTL32, &data); + + if (data.buf[0] == 0 or ~data.buf[0] == 0) return sptr(); //bad VRT hdr, treat like timeout + + return make(this, data.buf, sizeof(data.buf)); + } +}; + +struct e100_simpl_msb : managed_send_buffer +{ + usrp_e_ctl32 data; + e100_ctrl *ctrl; + + void release(void) + { + //load the data struct + data.offset = 0; + data.count = size()/4+1/*1 for flush pad*/; + + //call the ioctl + ctrl->ioctl(USRP_E_WRITE_CTL32, &data); + } + + sptr get_new(void) + { + return make(this, data.buf, sizeof(data.buf)); + } +}; + /*********************************************************************** * USRP-E100 control implementation **********************************************************************/ @@ -273,8 +377,14 @@ public: ) % USRP_E_COMPAT_NUMBER % module_compat_num)); } - //perform a global reset after opening - this->poke32(E100_REG_GLOBAL_RESET, 0); + //hit the magic arst condition + //async_reset <= ~EM_NCS6 && ~EM_NWE && (EM_A[9:2] == 8'hff) && EM_D[0]; + usrp_e_ctl16 datax; + datax.offset = 0x3fc; + datax.count = 2; + datax.buf[0] = 1; + datax.buf[1] = 0; + this->ioctl(USRP_E_WRITE_CTL16, &datax); } ~e100_ctrl_impl(void){ @@ -293,58 +403,45 @@ public: )); } } + /******************************************************************* - * Peek and Poke + * The managed buffer interface ******************************************************************/ - void poke32(wb_addr_type addr, boost::uint32_t value){ - //load the data struct - usrp_e_ctl32 data; - data.offset = addr; - data.count = 1; - data.buf[0] = value; - - //call the ioctl - this->ioctl(USRP_E_WRITE_CTL32, &data); + managed_recv_buffer::sptr get_recv_buff(double timeout){ + if (not gpio_has_resp_wait(timeout)) + { + return managed_recv_buffer::sptr(); + } + _mrb.ctrl = this; + return _mrb.get_new(); } - void poke16(wb_addr_type addr, boost::uint16_t value){ - //load the data struct - usrp_e_ctl16 data; - data.offset = addr; - data.count = 1; - data.buf[0] = value; - - //call the ioctl - this->ioctl(USRP_E_WRITE_CTL16, &data); + managed_send_buffer::sptr get_send_buff(double){ + _msb.ctrl = this; + return _msb.get_new(); } - boost::uint32_t peek32(wb_addr_type addr){ - //load the data struct - usrp_e_ctl32 data; - data.offset = addr; - data.count = 1; - - //call the ioctl - this->ioctl(USRP_E_READ_CTL32, &data); - - return data.buf[0]; + size_t get_num_recv_frames(void) const{ + return 1; } - boost::uint16_t peek16(wb_addr_type addr){ - //load the data struct - usrp_e_ctl16 data; - data.offset = addr; - data.count = 1; + size_t get_recv_frame_size(void) const{ + return sizeof(_mrb.data.buf); + } - //call the ioctl - this->ioctl(USRP_E_READ_CTL16, &data); + size_t get_num_send_frames(void) const{ + return 1; + } - return data.buf[0]; + size_t get_send_frame_size(void) const{ + return sizeof(_msb.data.buf); } private: int _node_fd; boost::mutex _ioctl_mutex; + e100_simpl_mrb _mrb; + e100_simpl_msb _msb; }; /*********************************************************************** diff --git a/host/lib/usrp/e100/e100_ctrl.hpp b/host/lib/usrp/e100/e100_ctrl.hpp index fd66791d4..72dce134e 100644 --- a/host/lib/usrp/e100/e100_ctrl.hpp +++ b/host/lib/usrp/e100/e100_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2011 Ettus Research LLC +// Copyright 2012 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 @@ -18,12 +18,11 @@ #ifndef INCLUDED_B100_CTRL_HPP #define INCLUDED_B100_CTRL_HPP -#include "wb_iface.hpp" +#include #include #include -#include -class e100_ctrl : boost::noncopyable, public wb_iface{ +class e100_ctrl : public uhd::transport::zero_copy_if{ public: typedef boost::shared_ptr sptr; @@ -33,7 +32,7 @@ public: //! Make an i2c iface for the i2c device node static uhd::i2c_iface::sptr make_dev_i2c_iface(const std::string &node); - //! Make an i2c iface for the i2c device node + //! Make a spi iface for the spi gpio static uhd::spi_iface::sptr make_aux_spi_iface(void); //! Make a uart iface for the uart device node diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index d55ea5ec5..a517dfcba 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -28,6 +28,7 @@ #include #include #include +#include using namespace uhd; using namespace uhd::usrp; @@ -86,15 +87,6 @@ static device_addrs_t e100_find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -static size_t hash_fpga_file(const std::string &file_path){ - size_t hash = 0; - std::ifstream file(file_path.c_str()); - if (not file.good()) throw uhd::io_error("cannot open fpga file for read: " + file_path); - while (file.good()) boost::hash_combine(hash, file.get()); - file.close(); - return hash; -} - static device::sptr e100_make(const device_addr_t &device_addr){ return device::sptr(new e100_impl(device_addr)); } @@ -114,10 +106,6 @@ static const uhd::dict model_to_fpga_file_name = boost e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _tree = property_tree::make(); - //setup the main interface into fpga - const std::string node = device_addr["node"]; - _fpga_ctrl = e100_ctrl::make(node); - //read the eeprom so we can determine the hardware _dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, E100_EEPROM_MAP_KEY); @@ -134,19 +122,11 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //extract the fpga path and compute hash const std::string default_fpga_file_name = model_to_fpga_file_name[model]; const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name)); - const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(e100_fpga_image)); - - //When the hash does not match: - // - close the device node - // - load the fpga bin file - // - re-open the device node - if (_fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash){ - _fpga_ctrl.reset(); - e100_load_fpga(e100_fpga_image); - _fpga_ctrl = e100_ctrl::make(node); - } + e100_load_fpga(e100_fpga_image); - //setup clock control here to ensure that the FPGA has a good clock before we continue + //////////////////////////////////////////////////////////////////// + // Setup the FPGA clock over AUX SPI + //////////////////////////////////////////////////////////////////// bool dboard_clocks_diff = true; if (mb_eeprom.get("revision", "0") == "3") dboard_clocks_diff = false; else if (mb_eeprom.get("revision", "0") == "4") dboard_clocks_diff = true; @@ -158,12 +138,32 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ _aux_spi_iface = e100_ctrl::make_aux_spi_iface(); _clock_ctrl = e100_clock_ctrl::make(_aux_spi_iface, master_clock_rate, dboard_clocks_diff); + //////////////////////////////////////////////////////////////////// + // setup the main interface into fpga + // - do this after aux spi, because we share gpio147 + //////////////////////////////////////////////////////////////////// + const std::string node = device_addr["node"]; + _fpga_ctrl = e100_ctrl::make(node); + + //////////////////////////////////////////////////////////////////// + // Initialize FPGA control communication + //////////////////////////////////////////////////////////////////// + fifo_ctrl_excelsior_config fifo_ctrl_config; + fifo_ctrl_config.async_sid_base = E100_TX_ASYNC_SID; + fifo_ctrl_config.num_async_chan = 1; + fifo_ctrl_config.ctrl_sid_base = E100_CTRL_MSG_SID; + fifo_ctrl_config.spi_base = TOREG(SR_SPI); + fifo_ctrl_config.spi_rb = REG_RB_SPI; + _fifo_ctrl = fifo_ctrl_excelsior::make(_fpga_ctrl, fifo_ctrl_config); + //Perform wishbone readback tests, these tests also write the hash bool test_fail = false; - UHD_MSG(status) << "Performing wishbone readback test... " << std::flush; + UHD_MSG(status) << "Performing control readback test... " << std::flush; + size_t hash = time(NULL); for (size_t i = 0; i < 100; i++){ - _fpga_ctrl->poke32(E100_REG_SR_MISC_TEST32, file_hash); - test_fail = _fpga_ctrl->peek32(E100_REG_RB_MISC_TEST32) != file_hash; + boost::hash_combine(hash, i); + _fifo_ctrl->poke32(TOREG(SR_MISC+0), boost::uint32_t(hash)); + test_fail = _fifo_ctrl->peek32(REG_RB_CONFIG0) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; @@ -180,8 +180,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Create controller objects //////////////////////////////////////////////////////////////////// - _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, E100_REG_SLAVE(3)); - _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, E100_REG_SLAVE(2)); + _fpga_i2c_ctrl = i2c_core_200::make(_fifo_ctrl, TOREG(SR_I2C), REG_RB_I2C); _data_transport = e100_make_mmap_zero_copy(_fpga_ctrl); //////////////////////////////////////////////////////////////////// @@ -205,12 +204,17 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //^^^ clock created up top, just reg props here... ^^^ _tree->create(mb_path / "tick_rate") .publish(boost::bind(&e100_clock_ctrl::get_fpga_clock_rate, _clock_ctrl)) + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_tick_rate, _fifo_ctrl, _1)) .subscribe(boost::bind(&e100_impl::update_tick_rate, this, _1)); + //subscribe the command time while we are at it + _tree->create(mb_path / "time/cmd") + .subscribe(boost::bind(&fifo_ctrl_excelsior::set_time, _fifo_ctrl, _1)); + //////////////////////////////////////////////////////////////////// // create codec control objects //////////////////////////////////////////////////////////////////// - _codec_ctrl = e100_codec_ctrl::make(_fpga_spi_ctrl); + _codec_ctrl = e100_codec_ctrl::make(_fifo_ctrl/*spi*/); const fs_path rx_codec_path = mb_path / "rx_codecs/A"; const fs_path tx_codec_path = mb_path / "tx_codecs/A"; _tree->create(rx_codec_path / "name").set("ad9522"); @@ -232,24 +236,37 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // Create the GPSDO control //////////////////////////////////////////////////////////////////// - try{ - _gps = gps_ctrl::make(e100_ctrl::make_gps_uart_iface(E100_UART_DEV_NODE)); - } - catch(std::exception &e){ - UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; - } - if (_gps.get() != NULL and _gps->gps_detected()){ - BOOST_FOREACH(const std::string &name, _gps->get_sensors()){ - _tree->create(mb_path / "sensors" / name) - .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + static const fs::path GPSDO_VOLATILE_PATH("/media/ram/e100_internal_gpsdo.cache"); + if (not fs::exists(GPSDO_VOLATILE_PATH)) + { + UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush; + try{ + _gps = gps_ctrl::make(e100_ctrl::make_gps_uart_iface(E100_UART_DEV_NODE)); + } + catch(std::exception &e){ + UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; + } + if (_gps and _gps->gps_detected()) + { + UHD_MSG(status) << "found" << std::endl; + BOOST_FOREACH(const std::string &name, _gps->get_sensors()) + { + _tree->create(mb_path / "sensors" / name) + .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + } + } + else + { + UHD_MSG(status) << "not found" << std::endl; + std::ofstream(GPSDO_VOLATILE_PATH.string().c_str(), std::ofstream::binary) << "42" << std::endl; } } //////////////////////////////////////////////////////////////////// // create frontend control objects //////////////////////////////////////////////////////////////////// - _rx_fe = rx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_FRONT)); - _tx_fe = tx_frontend_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_FRONT)); + _rx_fe = rx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_RX_FE)); + _tx_fe = tx_frontend_core_200::make(_fifo_ctrl, TOREG(SR_TX_FE)); _tree->create(mb_path / "rx_subdev_spec") .subscribe(boost::bind(&e100_impl::update_rx_subdev_spec, this, _1)); @@ -278,13 +295,17 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create rx dsp control objects //////////////////////////////////////////////////////////////////// - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP0), E100_REG_SR_ADDR(UE_SR_RX_CTRL0), E100_RX_SID_BASE + 0 - )); - _rx_dsps.push_back(rx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_RX_DSP1), E100_REG_SR_ADDR(UE_SR_RX_CTRL1), E100_RX_SID_BASE + 1 - )); - for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){ + const size_t num_rx_dsps = _fifo_ctrl->peek32(REG_RB_NUM_RX_DSP); + for (size_t dspno = 0; dspno < num_rx_dsps; dspno++) + { + const size_t sr_off = dspno*32; + _rx_dsps.push_back(rx_dsp_core_200::make( + _fifo_ctrl, + TOREG(SR_RX_DSP0+sr_off), + TOREG(SR_RX_CTRL0+sr_off), + E100_RX_SID_BASE + dspno + )); + _rx_dsps[dspno]->set_link_rate(E100_RX_LINK_RATE_BPS); _tree->access(mb_path / "tick_rate") .subscribe(boost::bind(&rx_dsp_core_200::set_tick_rate, _rx_dsps[dspno], _1)); @@ -307,7 +328,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ // create tx dsp control objects //////////////////////////////////////////////////////////////////// _tx_dsp = tx_dsp_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TX_DSP), E100_REG_SR_ADDR(UE_SR_TX_CTRL), E100_TX_ASYNC_SID + _fifo_ctrl, TOREG(SR_TX_DSP), TOREG(SR_TX_CTRL), E100_TX_ASYNC_SID ); _tx_dsp->set_link_rate(E100_TX_LINK_RATE_BPS); _tree->access(mb_path / "tick_rate") @@ -327,12 +348,12 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ // create time control objects //////////////////////////////////////////////////////////////////// time64_core_200::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_hi_now = E100_REG_RB_TIME_NOW_HI; - time64_rb_bases.rb_lo_now = E100_REG_RB_TIME_NOW_LO; - time64_rb_bases.rb_hi_pps = E100_REG_RB_TIME_PPS_HI; - time64_rb_bases.rb_lo_pps = E100_REG_RB_TIME_PPS_LO; + time64_rb_bases.rb_hi_now = REG_RB_TIME_NOW_HI; + time64_rb_bases.rb_lo_now = REG_RB_TIME_NOW_LO; + time64_rb_bases.rb_hi_pps = REG_RB_TIME_PPS_HI; + time64_rb_bases.rb_lo_pps = REG_RB_TIME_PPS_LO; _time64 = time64_core_200::make( - _fpga_ctrl, E100_REG_SR_ADDR(UE_SR_TIME64), time64_rb_bases + _fifo_ctrl, TOREG(SR_TIME64), time64_rb_bases ); _tree->access(mb_path / "tick_rate") .subscribe(boost::bind(&time64_core_200::set_tick_rate, _time64, _1)); @@ -357,7 +378,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //////////////////////////////////////////////////////////////////// // create user-defined control objects //////////////////////////////////////////////////////////////////// - _user = user_settings_core_200::make(_fpga_ctrl, E100_REG_SR_ADDR(UE_SR_USER_REGS)); + _user = user_settings_core_200::make(_fifo_ctrl, TOREG(SR_USER_REGS)); _tree->create(mb_path / "user/regs") .subscribe(boost::bind(&user_settings_core_200::set_reg, _user, _1)); @@ -383,7 +404,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ .subscribe(boost::bind(&e100_impl::set_db_eeprom, this, "gdb", _1)); //create a new dboard interface and manager - _dboard_iface = make_e100_dboard_iface(_fpga_ctrl, _fpga_i2c_ctrl, _fpga_spi_ctrl, _clock_ctrl, _codec_ctrl); + _dboard_iface = make_e100_dboard_iface(_fifo_ctrl, _fpga_i2c_ctrl, _fifo_ctrl/*spi*/, _clock_ctrl, _codec_ctrl); _tree->create(mb_path / "dboards/A/iface").set(_dboard_iface); _dboard_manager = dboard_manager::make( rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, @@ -403,7 +424,11 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ } //initialize io handling - this->io_init(); + _recv_demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE); + + //allocate streamer weak ptrs containers + _rx_streamers.resize(_rx_dsps.size()); + _tx_streamers.resize(1/*known to be 1 dsp*/); //////////////////////////////////////////////////////////////////// // do some post-init tasks @@ -474,7 +499,7 @@ sensor_value_t e100_impl::get_ref_locked(void){ } void e100_impl::check_fpga_compat(void){ - const boost::uint32_t fpga_compat_num = _fpga_ctrl->peek32(E100_REG_RB_COMPAT); + const boost::uint32_t fpga_compat_num = _fifo_ctrl->peek32(REG_RB_COMPAT); boost::uint16_t fpga_major = fpga_compat_num >> 16, fpga_minor = fpga_compat_num & 0xffff; if (fpga_major == 0){ //old version scheme fpga_major = fpga_minor; diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp index 381c085e0..6f64d4b80 100644 --- a/host/lib/usrp/e100/e100_impl.hpp +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -18,17 +18,17 @@ #include "e100_ctrl.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" -#include "spi_core_100.hpp" -#include "i2c_core_100.hpp" +#include "i2c_core_200.hpp" #include "rx_frontend_core_200.hpp" #include "tx_frontend_core_200.hpp" #include "rx_dsp_core_200.hpp" #include "tx_dsp_core_200.hpp" #include "time64_core_200.hpp" +#include "fifo_ctrl_excelsior.hpp" #include "user_settings_core_200.hpp" +#include "recv_packet_demuxer.hpp" #include #include -#include #include #include #include @@ -49,9 +49,10 @@ static const double E100_RX_LINK_RATE_BPS = 166e6/3/2*2; static const double E100_TX_LINK_RATE_BPS = 166e6/3/1*2; static const std::string E100_I2C_DEV_NODE = "/dev/i2c-3"; static const std::string E100_UART_DEV_NODE = "/dev/ttyO0"; -static const boost::uint16_t E100_FPGA_COMPAT_NUM = 10; -static const boost::uint32_t E100_RX_SID_BASE = 2; -static const boost::uint32_t E100_TX_ASYNC_SID = 1; +static const boost::uint16_t E100_FPGA_COMPAT_NUM = 11; +static const boost::uint32_t E100_RX_SID_BASE = 30; +static const boost::uint32_t E100_TX_ASYNC_SID = 10; +static const boost::uint32_t E100_CTRL_MSG_SID = 20; static const double E100_DEFAULT_CLOCK_RATE = 64e6; static const std::string E100_EEPROM_MAP_KEY = "E100"; @@ -87,8 +88,8 @@ private: uhd::property_tree::sptr _tree; //controllers - spi_core_100::sptr _fpga_spi_ctrl; - i2c_core_100::sptr _fpga_i2c_ctrl; + fifo_ctrl_excelsior::sptr _fifo_ctrl; + i2c_core_200::sptr _fpga_i2c_ctrl; rx_frontend_core_200::sptr _rx_fe; tx_frontend_core_200::sptr _tx_fe; std::vector _rx_dsps; @@ -104,15 +105,12 @@ private: //transports uhd::transport::zero_copy_if::sptr _data_transport; + uhd::usrp::recv_packet_demuxer::sptr _recv_demuxer; //dboard stuff uhd::usrp::dboard_manager::sptr _dboard_manager; uhd::usrp::dboard_iface::sptr _dboard_iface; - //handle io stuff - UHD_PIMPL_DECL(io_impl) _io_impl; - void io_init(void); - //device properties interface uhd::property_tree::sptr get_tree(void) const{ return _tree; diff --git a/host/lib/usrp/e100/e100_regs.hpp b/host/lib/usrp/e100/e100_regs.hpp index 75be2cfbe..654163dce 100644 --- a/host/lib/usrp/e100/e100_regs.hpp +++ b/host/lib/usrp/e100/e100_regs.hpp @@ -15,55 +15,45 @@ // along with this program. If not, see . // -//////////////////////////////////////////////////////////////// -// -// Memory map for embedded wishbone bus -// -//////////////////////////////////////////////////////////////// - -// All addresses are byte addresses. All accesses are word (16-bit) accesses. -// This means that address bit 0 is usually 0. -// There are 11 bits of address for the control. - #ifndef INCLUDED_E100_REGS_HPP #define INCLUDED_E100_REGS_HPP -///////////////////////////////////////////////////// -// Slave pointers +#include -#define E100_REG_SLAVE(n) ((n)<<7) +#define TOREG(x) ((x)*4) -///////////////////////////////////////////////////// -// Slave 0 -- Misc Regs +#define localparam static const int -#define E100_REG_MISC_BASE E100_REG_SLAVE(0) +localparam SR_MISC = 0; // 5 +localparam SR_USER_REGS = 5; // 2 -#define E100_REG_MISC_LED E100_REG_MISC_BASE + 0 -#define E100_REG_MISC_SW E100_REG_MISC_BASE + 2 -#define E100_REG_MISC_CGEN_CTRL E100_REG_MISC_BASE + 4 -#define E100_REG_MISC_CGEN_ST E100_REG_MISC_BASE + 6 -#define E100_REG_MISC_TEST E100_REG_MISC_BASE + 8 -#define E100_REG_MISC_RX_LEN E100_REG_MISC_BASE + 10 -#define E100_REG_MISC_TX_LEN E100_REG_MISC_BASE + 12 -#define E100_REG_MISC_XFER_RATE E100_REG_MISC_BASE + 14 +localparam SR_TX_CTRL = 32; // 6 +localparam SR_TX_DSP = 40; // 5 +localparam SR_TX_FE = 48; // 5 -///////////////////////////////////////////////////// -// Slave 1 -- UART -// CLKDIV is 16 bits, others are only 8 +localparam SR_RX_CTRL0 = 96; // 9 +localparam SR_RX_DSP0 = 106; // 7 +localparam SR_RX_FE = 114; // 5 -#define E100_REG_UART_BASE E100_REG_SLAVE(1) +localparam SR_RX_CTRL1 = 128; // 9 +localparam SR_RX_DSP1 = 138; // 7 -#define E100_REG_UART_CLKDIV E100_REG_UART_BASE + 0 -#define E100_REG_UART_TXLEVEL E100_REG_UART_BASE + 2 -#define E100_REG_UART_RXLEVEL E100_REG_UART_BASE + 4 -#define E100_REG_UART_TXCHAR E100_REG_UART_BASE + 6 -#define E100_REG_UART_RXCHAR E100_REG_UART_BASE + 8 +localparam SR_TIME64 = 192; // 6 +localparam SR_SPI = 208; // 3 +localparam SR_I2C = 216; // 1 +localparam SR_GPIO = 224; // 5 -///////////////////////////////////////////////////// -// Slave 2 -- SPI Core -//these are 32-bit registers mapped onto the 16-bit Wishbone bus. -//Using peek32/poke32 should allow transparent use of these registers. -#define E100_REG_SPI_BASE E100_REG_SLAVE(2) +#define REG_RB_TIME_NOW_HI TOREG(10) +#define REG_RB_TIME_NOW_LO TOREG(11) +#define REG_RB_TIME_PPS_HI TOREG(14) +#define REG_RB_TIME_PPS_LO TOREG(15) +#define REG_RB_SPI TOREG(0) +#define REG_RB_COMPAT TOREG(1) +#define REG_RB_GPIO TOREG(3) +#define REG_RB_I2C TOREG(2) +#define REG_RB_CONFIG0 TOREG(4) +#define REG_RB_CONFIG1 TOREG(5) +#define REG_RB_NUM_RX_DSP TOREG(6) //spi slave constants #define UE_SPI_SS_AD9522 (1 << 3) @@ -71,67 +61,5 @@ #define UE_SPI_SS_TX_DB (1 << 1) #define UE_SPI_SS_RX_DB (1 << 0) -//////////////////////////////////////////////// -// Slave 3 -- I2C Core - -#define E100_REG_I2C_BASE E100_REG_SLAVE(3) - -//////////////////////////////////////////////// -// Slave 5 -- Error messages buffer - -#define E100_REG_ERR_BUFF E100_REG_SLAVE(5) - -/////////////////////////////////////////////////// -// Slave 7 -- Readback Mux 32 - -#define E100_REG_RB_MUX_32_BASE E100_REG_SLAVE(7) - -#define E100_REG_RB_TIME_NOW_HI E100_REG_RB_MUX_32_BASE + 0 -#define E100_REG_RB_TIME_NOW_LO E100_REG_RB_MUX_32_BASE + 4 -#define E100_REG_RB_TIME_PPS_HI E100_REG_RB_MUX_32_BASE + 8 -#define E100_REG_RB_TIME_PPS_LO E100_REG_RB_MUX_32_BASE + 12 -#define E100_REG_RB_MISC_TEST32 E100_REG_RB_MUX_32_BASE + 16 -#define E100_REG_RB_ERR_STATUS E100_REG_RB_MUX_32_BASE + 20 -#define E100_REG_RB_COMPAT E100_REG_RB_MUX_32_BASE + 24 -#define E100_REG_RB_GPIO E100_REG_RB_MUX_32_BASE + 28 - -//////////////////////////////////////////////////// -// Slave 8 -- Settings Bus -// -// Output-only, no readback, 64 registers total -// Each register must be written 64 bits at a time -// First the address xxx_xx00 and then xxx_xx10 - -// 64 total regs in address space -#define UE_SR_RX_CTRL0 0 // 9 regs (+0 to +8) -#define UE_SR_RX_DSP0 10 // 4 regs (+0 to +3) -#define UE_SR_RX_CTRL1 16 // 9 regs (+0 to +8) -#define UE_SR_RX_DSP1 26 // 4 regs (+0 to +3) -#define UE_SR_ERR_CTRL 30 // 1 reg -#define UE_SR_TX_CTRL 32 // 4 regs (+0 to +3) -#define UE_SR_TX_DSP 38 // 3 regs (+0 to +2) - -#define UE_SR_TIME64 42 // 6 regs (+0 to +5) -#define UE_SR_RX_FRONT 48 // 5 regs (+0 to +4) -#define UE_SR_TX_FRONT 54 // 5 regs (+0 to +4) - -#define UE_SR_REG_TEST32 60 // 1 reg -#define UE_SR_CLEAR_FIFO 61 // 1 reg -#define UE_SR_GLOBAL_RESET 63 // 1 reg -#define UE_SR_USER_REGS 64 // 2 regs - -#define UE_SR_GPIO 128 - -#define E100_REG_SR_ADDR(n) (E100_REG_SLAVE(8) + (4*(n))) - -#define E100_REG_SR_MISC_TEST32 E100_REG_SR_ADDR(UE_SR_REG_TEST32) -#define E100_REG_SR_ERR_CTRL E100_REG_SR_ADDR(UE_SR_ERR_CTRL) - -///////////////////////////////////////////////// -// Magic reset regs -//////////////////////////////////////////////// -#define E100_REG_CLEAR_FIFO E100_REG_SR_ADDR(UE_SR_CLEAR_FIFO) -#define E100_REG_GLOBAL_RESET E100_REG_SR_ADDR(UE_SR_GLOBAL_RESET) - -#endif +#endif /*INCLUDED_E100_REGS_HPP*/ diff --git a/host/lib/usrp/e100/include/linux/usrp_e.h b/host/lib/usrp/e100/include/linux/usrp_e.h index 37e9ee31a..f0512a40c 100644 --- a/host/lib/usrp/e100/include/linux/usrp_e.h +++ b/host/lib/usrp/e100/include/linux/usrp_e.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Ettus Research, LLC + * Copyright (C) 2010-2012 Ettus Research, LLC * * Written by Philip Balister * @@ -36,7 +36,7 @@ struct usrp_e_ctl32 { #define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) #define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) -#define USRP_E_COMPAT_NUMBER 3 +#define USRP_E_COMPAT_NUMBER 4 /* Flag defines */ #define RB_USER (1<<0) diff --git a/host/lib/usrp/e100/io_impl.cpp b/host/lib/usrp/e100/io_impl.cpp index 332fe76ae..4d521e222 100644 --- a/host/lib/usrp/e100/io_impl.cpp +++ b/host/lib/usrp/e100/io_impl.cpp @@ -15,27 +15,16 @@ // along with this program. If not, see . // -#include "recv_packet_demuxer.hpp" #include "validate_subdev_spec.hpp" #include "async_packet_handler.hpp" #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" -#include //ioctl structures and constants #include "e100_impl.hpp" -#include "e100_regs.hpp" #include #include #include -#include -#include #include #include -#include -#include -#include //poll -#include //open, close -#include -#include #include using namespace uhd; @@ -44,134 +33,7 @@ using namespace uhd::transport; static const size_t vrt_send_header_offset_words32 = 1; -/*********************************************************************** - * io impl details (internal to this file) - * - pirate crew of 1 - * - bounded buffer - * - thread loop - * - vrt packet handler states - **********************************************************************/ -struct e100_impl::io_impl{ - io_impl(void): - false_alarm(0), async_msg_fifo(1000/*messages deep*/) - { /* NOP */ } - - double tick_rate; //set by update tick rate method - e100_ctrl::sptr iface; //so handle irq can peek and poke - void handle_irq(void); - size_t false_alarm; - //The data transport is listed first so that it is deconstructed last, - //which is after the states and booty which may hold managed buffers. - recv_packet_demuxer::sptr demuxer; - - //a pirate's life is the life for me! - void recv_pirate_loop( - spi_iface::sptr //keep a sptr to iface which shares gpio147 - ){ - //open the GPIO and set it up for an IRQ - std::ofstream edge_file("/sys/class/gpio/gpio147/edge"); - edge_file << "rising" << std::endl << std::flush; - edge_file.close(); - int fd = ::open("/sys/class/gpio/gpio147/value", O_RDONLY); - if (fd < 0) UHD_MSG(error) << "Unable to open GPIO for IRQ\n"; - - while (not boost::this_thread::interruption_requested()){ - pollfd pfd; - pfd.fd = fd; - pfd.events = POLLPRI | POLLERR; - ssize_t ret = ::poll(&pfd, 1, 100/*ms*/); - if (ret > 0) this->handle_irq(); - } - - //cleanup before thread exit - ::close(fd); - } - bounded_buffer async_msg_fifo; - task::sptr pirate_task; -}; - -void e100_impl::io_impl::handle_irq(void){ - //check the status of the async msg buffer - const boost::uint32_t status = iface->peek32(E100_REG_RB_ERR_STATUS); - if ((status & 0x3) == 0){ //not done or error - //This could be a false-alarm because spi readback is mixed in. - //So we just sleep for a bit rather than interrupt continuously. - if (false_alarm++ > 3) boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - return; - } - false_alarm = 0; //its a real message, reset the count... - //std::cout << boost::format("status: 0x%x") % status << std::endl; - - //load the data struct and call the ioctl - usrp_e_ctl32 data; - data.offset = E100_REG_ERR_BUFF; - data.count = status >> 16; - iface->ioctl(USRP_E_READ_CTL32, &data); - //for (size_t i = 0; i < data.count; i++){ - //data.buf[i] = iface->peek32(E100_REG_ERR_BUFF + i*sizeof(boost::uint32_t)); - //std::cout << boost::format(" buff[%u] = 0x%08x\n") % i % data.buf[i]; - //} - - //unpack the vrt header and process below... - vrt::if_packet_info_t if_packet_info; - if_packet_info.num_packet_words32 = data.count; - try{vrt::if_hdr_unpack_le(data.buf, if_packet_info);} - catch(const std::exception &e){ - UHD_MSG(error) << "Error unpacking vrt header:\n" << e.what() << std::endl; - goto prepare; - } - - //handle a tx async report message - if (if_packet_info.sid == E100_TX_ASYNC_SID and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ - - //fill in the async metadata - async_metadata_t metadata; - load_metadata_from_buff(uhd::wtohx, metadata, if_packet_info, data.buf, tick_rate); - - //push the message onto the queue - async_msg_fifo.push_with_pop_on_full(metadata); - - //print some fastpath messages - standard_async_msg_prints(metadata); - } - - //prepare for the next round - prepare: - iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear - while ((iface->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle - iface->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start -} - -/*********************************************************************** - * Helper Functions - **********************************************************************/ -void e100_impl::io_init(void){ - - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, ()); - _io_impl->demuxer = recv_packet_demuxer::make(_data_transport, _rx_dsps.size(), E100_RX_SID_BASE); - _io_impl->iface = _fpga_ctrl; - - //clear fifo state machines - _fpga_ctrl->poke32(E100_REG_CLEAR_FIFO, 0); - - //allocate streamer weak ptrs containers - _rx_streamers.resize(_rx_dsps.size()); - _tx_streamers.resize(1/*known to be 1 dsp*/); - - //prepare the async msg buffer for incoming messages - _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 0); //clear - while ((_fpga_ctrl->peek32(E100_REG_RB_ERR_STATUS) & (1 << 2)) == 0){} //wait for idle - _fpga_ctrl->poke32(E100_REG_SR_ERR_CTRL, 1 << 1); //start - - //spawn a pirate, yarrr! - _io_impl->pirate_task = task::make(boost::bind( - &e100_impl::io_impl::recv_pirate_loop, _io_impl.get(), _aux_spi_iface - )); -} - void e100_impl::update_tick_rate(const double rate){ - _io_impl->tick_rate = rate; //update the tick rate on all existing streamers -> thread safe for (size_t i = 0; i < _rx_streamers.size(); i++){ @@ -254,8 +116,7 @@ void e100_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec){ bool e100_impl::recv_async_msg( async_metadata_t &async_metadata, double timeout ){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return _io_impl->async_msg_fifo.pop_with_timed_wait(async_metadata, timeout); + return _fifo_ctrl->pop_async_msg(async_metadata, timeout); } /*********************************************************************** @@ -300,7 +161,7 @@ rx_streamer::sptr e100_impl::get_rx_stream(const uhd::stream_args_t &args_){ _rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this _rx_dsps[dsp]->setup(args); my_streamer->set_xport_chan_get_buff(chan_i, boost::bind( - &recv_packet_demuxer::get_recv_buff, _io_impl->demuxer, dsp, _1 + &recv_packet_demuxer::get_recv_buff, _recv_demuxer, dsp, _1 ), true /*flush*/); my_streamer->set_overflow_handler(chan_i, boost::bind( &rx_dsp_core_200::handle_overflow, _rx_dsps[dsp] -- cgit v1.2.3 From 2f4149bf4524a49658d8898430ecf4fb3c5c71f7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 14 Jul 2012 04:41:09 -0700 Subject: e100: cleanup and make better use of IRQ gpio for control response --- host/lib/usrp/e100/e100_ctrl.cpp | 95 +++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 50 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index 408d259dc..397543f14 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -76,49 +76,7 @@ private: /*********************************************************************** * Protection for dual GPIO access - sometimes MISO, sometimes have resp **********************************************************************/ -static boost::mutex gpio_has_resp_mutex; -static boost::condition_variable gpio_has_resp_cond; -static bool gpio_has_resp_claimed = false; -static gpio gpio_has_resp(147, "in"); - -struct gpio_has_resp_claimer -{ - gpio_has_resp_claimer(void) - { - boost::mutex::scoped_lock lock(gpio_has_resp_mutex); - gpio_has_resp_claimed = true; - } - - ~gpio_has_resp_claimer(void) - { - boost::mutex::scoped_lock lock(gpio_has_resp_mutex); - gpio_has_resp_claimed = false; - lock.unlock(); - gpio_has_resp_cond.notify_one(); - } -}; - -static inline bool gpio_has_resp_value(void) -{ - boost::mutex::scoped_lock lock(gpio_has_resp_mutex); - while (gpio_has_resp_claimed) - { - gpio_has_resp_cond.wait(lock); - } - return bool(gpio_has_resp()); -} - -static bool inline gpio_has_resp_wait(const double timeout) -{ - if (gpio_has_resp_value()) return true; - const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1e6)); - while (boost::get_system_time() < exit_time) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - if (gpio_has_resp_value()) return true; - } - return false; -} +static boost::mutex gpio_irq_resp_mutex; /*********************************************************************** * Aux spi implementation @@ -129,8 +87,7 @@ public: spi_sclk_gpio(65, "out"), spi_sen_gpio(186, "out"), spi_mosi_gpio(145, "out"), - //spi_miso_gpio(147, "in"){} - spi_miso_gpio(gpio_has_resp){} + spi_miso_gpio(147, "in"){} boost::uint32_t transact_spi( int, const spi_config_t &, //not used params @@ -138,7 +95,7 @@ public: size_t num_bits, bool readback ){ - gpio_has_resp_claimer claimer(); + boost::mutex::scoped_lock lock(gpio_irq_resp_mutex); boost::uint32_t rb_bits = 0; this->spi_sen_gpio(0); @@ -158,7 +115,7 @@ public: } private: - gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, &spi_miso_gpio; + gpio spi_sclk_gpio, spi_sen_gpio, spi_mosi_gpio, spi_miso_gpio; }; uhd::spi_iface::sptr e100_ctrl::make_aux_spi_iface(void){ @@ -385,9 +342,16 @@ public: datax.buf[0] = 1; datax.buf[1] = 0; this->ioctl(USRP_E_WRITE_CTL16, &datax); + + std::ofstream edge_file("/sys/class/gpio/gpio147/edge"); + edge_file << "rising" << std::endl << std::flush; + edge_file.close(); + _irq_fd = ::open("/sys/class/gpio/gpio147/value", O_RDONLY); + if (_irq_fd < 0) UHD_MSG(error) << "Unable to open GPIO for IRQ\n"; } ~e100_ctrl_impl(void){ + ::close(_irq_fd); ::close(_node_fd); } @@ -407,16 +371,46 @@ public: /******************************************************************* * The managed buffer interface ******************************************************************/ - managed_recv_buffer::sptr get_recv_buff(double timeout){ - if (not gpio_has_resp_wait(timeout)) + UHD_INLINE bool resp_read(void) + { + //thread stuff ensures that this GPIO isnt shared + boost::mutex::scoped_lock lock(gpio_irq_resp_mutex); + + //perform a read of the GPIO IRQ state + char ch; + ::read(_irq_fd, &ch, sizeof(ch)); + ::lseek(_irq_fd, SEEK_SET, 0); + return ch == '1'; + } + + UHD_INLINE bool resp_wait(const double timeout) + { + //perform a check, if it fails, poll + if (this->resp_read()) return true; + + //poll IRQ GPIO for some action + pollfd pfd; + pfd.fd = _irq_fd; + pfd.events = POLLPRI | POLLERR; + ::poll(&pfd, 1, long(timeout*1000)/*ms*/); + + //perform a GPIO read again for result + return this->resp_read(); + } + + managed_recv_buffer::sptr get_recv_buff(double timeout) + { + if (not this->resp_wait(timeout)) { return managed_recv_buffer::sptr(); } + _mrb.ctrl = this; return _mrb.get_new(); } - managed_send_buffer::sptr get_send_buff(double){ + managed_send_buffer::sptr get_send_buff(double) + { _msb.ctrl = this; return _msb.get_new(); } @@ -439,6 +433,7 @@ public: private: int _node_fd; + int _irq_fd; boost::mutex _ioctl_mutex; e100_simpl_mrb _mrb; e100_simpl_msb _msb; -- cgit v1.2.3 From f3e7f66907bf2d77258ae38a6117927a46fe41a6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 16 Jul 2012 20:47:49 -0700 Subject: e100: ctrl impl changes for header offset --- host/lib/usrp/e100/e100_ctrl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/e100/e100_ctrl.cpp b/host/lib/usrp/e100/e100_ctrl.cpp index 397543f14..5a9b93633 100644 --- a/host/lib/usrp/e100/e100_ctrl.cpp +++ b/host/lib/usrp/e100/e100_ctrl.cpp @@ -292,7 +292,7 @@ struct e100_simpl_msb : managed_send_buffer { //load the data struct data.offset = 0; - data.count = size()/4+1/*1 for flush pad*/; + data.count = size()/4+1/*1 for header offset*/; //call the ioctl ctrl->ioctl(USRP_E_WRITE_CTL32, &data); @@ -300,7 +300,7 @@ struct e100_simpl_msb : managed_send_buffer sptr get_new(void) { - return make(this, data.buf, sizeof(data.buf)); + return make(this, data.buf+1, sizeof(data.buf)-4); } }; -- cgit v1.2.3 From ba9a627475446582afa9b6e624a1248748a98951 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 19 Jul 2012 14:20:45 -0700 Subject: b100/e100: clock source option for pps phase sync abuse --- host/docs/usrp_e1x0.rst | 2 +- host/lib/usrp/b100/b100_impl.cpp | 13 +++++++++++++ host/lib/usrp/e100/e100_impl.cpp | 13 +++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/docs/usrp_e1x0.rst b/host/docs/usrp_e1x0.rst index 9373e5255..189cbb86b 100644 --- a/host/docs/usrp_e1x0.rst +++ b/host/docs/usrp_e1x0.rst @@ -130,7 +130,7 @@ The LEDs on the front panel can be useful in debugging hardware and software issues. The LEDs reveal the following about the state of the device: * **LED A:** transmitting -* **LED B:** fpga loaded +* **LED B:** PPS signal * **LED C:** receiving * **LED D:** fpga loaded * **LED E:** reference lock diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index 94dc88db4..b226e113a 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -554,6 +554,19 @@ void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_e } void b100_impl::update_clock_source(const std::string &source){ + + if (source == "pps_sync"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 1); + return; + } + if (source == "_pps_sync_"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 3); + return; + } + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 0); + if (source == "auto") _clock_ctrl->use_auto_ref(); else if (source == "internal") _clock_ctrl->use_internal_ref(); else if (source == "external") _clock_ctrl->use_external_ref(); diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index a517dfcba..ef0351bd2 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -486,6 +486,19 @@ void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_e } void e100_impl::update_clock_source(const std::string &source){ + + if (source == "pps_sync"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 1); + return; + } + if (source == "_pps_sync_"){ + _clock_ctrl->use_external_ref(); + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 3); + return; + } + _fifo_ctrl->poke32(TOREG(SR_MISC+2), 0); + if (source == "auto") _clock_ctrl->use_auto_ref(); else if (source == "internal") _clock_ctrl->use_internal_ref(); else if (source == "external") _clock_ctrl->use_external_ref(); -- cgit v1.2.3 From b4f3b83acbe8d3b69767d7c23b4bc798095c8214 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 19 Jul 2012 17:11:41 -0700 Subject: e100: added extra error message for FPGA not found --- host/lib/usrp/e100/e100_impl.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index ef0351bd2..eb8804776 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -121,7 +121,14 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){ //extract the fpga path and compute hash const std::string default_fpga_file_name = model_to_fpga_file_name[model]; - const std::string e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name)); + std::string e100_fpga_image; + try{ + e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name)); + } + catch(...){ + UHD_MSG(error) << boost::format("Could not find FPGA image. %s\n") % print_images_error(); + throw; + } e100_load_fpga(e100_fpga_image); //////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 072c88af872fd9d2fc8cbf7b1c1a0ab31cc62c86 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 4 Aug 2012 15:15:18 -0400 Subject: b100: removed unused files from merge --- host/lib/usrp/b100/b100_ctrl.cpp | 257 ------------------------------------- host/lib/usrp/b100/b100_ctrl.hpp | 70 ---------- host/lib/usrp/b100/ctrl_packet.hpp | 75 ----------- 3 files changed, 402 deletions(-) delete mode 100644 host/lib/usrp/b100/b100_ctrl.cpp delete mode 100644 host/lib/usrp/b100/b100_ctrl.hpp delete mode 100644 host/lib/usrp/b100/ctrl_packet.hpp (limited to 'host/lib/usrp') diff --git a/host/lib/usrp/b100/b100_ctrl.cpp b/host/lib/usrp/b100/b100_ctrl.cpp deleted file mode 100644 index e6136c00e..000000000 --- a/host/lib/usrp/b100/b100_ctrl.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// -// Copyright 2011 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 "b100_ctrl.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctrl_packet.hpp" -#include -#include -#include - -using namespace uhd::transport; -using namespace uhd; - -bool b100_ctrl_debug = false; - -class b100_ctrl_impl : public b100_ctrl { -public: - b100_ctrl_impl(uhd::transport::zero_copy_if::sptr ctrl_transport): - sync_ctrl_fifo(2), - _ctrl_transport(ctrl_transport), - _seq(0) - { - viking_marauder = task::make(boost::bind(&b100_ctrl_impl::viking_marauder_loop, this)); - } - - ~b100_ctrl_impl(void){ - //stop the marauder first so it cant access deconstructed objects - viking_marauder.reset(); - } - - int write(boost::uint32_t addr, const ctrl_data_t &data); - ctrl_data_t read(boost::uint32_t addr, size_t len); - - bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout); - - void poke32(wb_addr_type addr, boost::uint32_t data){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - ctrl_data_t words(2); - words[0] = data & 0x0000FFFF; - words[1] = data >> 16; - this->write(addr, words); - } - - boost::uint32_t peek32(wb_addr_type addr){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - ctrl_data_t words = this->read(addr, 2); - return boost::uint32_t((boost::uint32_t(words[1]) << 16) | words[0]); - } - - void poke16(wb_addr_type addr, boost::uint16_t data){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - ctrl_data_t words(1); - words[0] = data; - this->write(addr, words); - } - - boost::uint16_t peek16(wb_addr_type addr){ - boost::mutex::scoped_lock lock(_ctrl_mutex); - - ctrl_data_t words = this->read(addr, 1); - return boost::uint16_t(words[0]); - } - - void set_async_cb(const async_cb_type &async_cb){ - boost::mutex::scoped_lock lock(_async_mutex); - _async_cb = async_cb; - } - -private: - int send_pkt(boost::uint16_t *cmd); - - //änd hërë wë gö ä-Vïkïng för äsynchronous control packets - void viking_marauder_loop(void); - bounded_buffer sync_ctrl_fifo; - async_cb_type _async_cb; - task::sptr viking_marauder; - - uhd::transport::zero_copy_if::sptr _ctrl_transport; - boost::uint8_t _seq; - boost::mutex _ctrl_mutex, _async_mutex; -}; - -/*********************************************************************** - * helper functions for packing/unpacking control packets - **********************************************************************/ -void pack_ctrl_pkt(boost::uint16_t *pkt_buff, - const ctrl_pkt_t &pkt){ - //first two bits are OP - //next six bits are CALLBACKS - //next 8 bits are SEQUENCE - //next 16 bits are LENGTH (16-bit word) - //next 32 bits are ADDRESS (16-bit word LSW) - //then DATA (28 16-bit words) - pkt_buff[0] = (boost::uint16_t(pkt.pkt_meta.op) << 14) | (boost::uint16_t(pkt.pkt_meta.callbacks) << 8) | pkt.pkt_meta.seq; - pkt_buff[1] = pkt.pkt_meta.len; - pkt_buff[2] = (pkt.pkt_meta.addr & 0x00000FFF); - pkt_buff[3] = 0x0000; //address high bits always 0 on this device - - for(size_t i = 0; i < pkt.data.size(); i++) { - pkt_buff[4+i] = pkt.data[i]; - } -} - -void unpack_ctrl_pkt(const boost::uint16_t *pkt_buff, - ctrl_pkt_t &pkt){ - pkt.pkt_meta.seq = pkt_buff[0] & 0xFF; - pkt.pkt_meta.op = CTRL_PKT_OP_READ; //really this is useless - pkt.pkt_meta.len = pkt_buff[1]; - pkt.pkt_meta.callbacks = 0; //callbacks aren't implemented yet - pkt.pkt_meta.addr = pkt_buff[2] | boost::uint32_t(pkt_buff[3] << 16); - - //let's check this so we don't go pushing 64K of crap onto the pkt - if(pkt.pkt_meta.len > CTRL_PACKET_DATA_LENGTH) { - throw uhd::runtime_error("Received control packet too long"); - } - - for(int i = 4; i < 4+pkt.pkt_meta.len; i++) pkt.data.push_back(pkt_buff[i]); -} - -int b100_ctrl_impl::send_pkt(boost::uint16_t *cmd) { - managed_send_buffer::sptr sbuf = _ctrl_transport->get_send_buff(); - if(!sbuf.get()) { - throw uhd::runtime_error("Control channel send error"); - } - - //FIXME there's a better way to do this - for(size_t i = 0; i < (CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)); i++) { - sbuf->cast()[i] = cmd[i]; - } - sbuf->commit(CTRL_PACKET_LENGTH); //fixed size transaction - return 0; -} - -int b100_ctrl_impl::write(boost::uint32_t addr, const ctrl_data_t &data) { - UHD_ASSERT_THROW(data.size() <= (CTRL_PACKET_DATA_LENGTH / sizeof(boost::uint16_t))); - ctrl_pkt_t pkt; - pkt.data = data; - pkt.pkt_meta.op = CTRL_PKT_OP_WRITE; - pkt.pkt_meta.callbacks = 0; - pkt.pkt_meta.seq = _seq++; - pkt.pkt_meta.len = pkt.data.size(); - pkt.pkt_meta.addr = addr; - boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {}; - - pack_ctrl_pkt(pkt_buff, pkt); - size_t result = send_pkt(pkt_buff); - return result; -} - -ctrl_data_t b100_ctrl_impl::read(boost::uint32_t addr, size_t len) { - UHD_ASSERT_THROW(len <= (CTRL_PACKET_DATA_LENGTH / sizeof(boost::uint16_t))); - - ctrl_pkt_t pkt; - pkt.pkt_meta.op = CTRL_PKT_OP_READ; - pkt.pkt_meta.callbacks = 0; - pkt.pkt_meta.seq = _seq++; - pkt.pkt_meta.len = len; - pkt.pkt_meta.addr = addr; - boost::uint16_t pkt_buff[CTRL_PACKET_LENGTH / sizeof(boost::uint16_t)] = {}; - - //flush anything that might be in the queue - while (get_ctrl_data(pkt.data, 0.0)){ - UHD_MSG(error) << "B100: control read found unexpected packet." << std::endl; - } - - pack_ctrl_pkt(pkt_buff, pkt); - send_pkt(pkt_buff); - - //block with timeout waiting for the response to appear - if (not get_ctrl_data(pkt.data, 0.1)) throw uhd::runtime_error( - "B100: timeout waiting for control response packet." - ); - - return pkt.data; -} - -/*********************************************************************** - * Viking marauders go pillaging for asynchronous control packets in the - * control response endpoint. Sync packets go in sync_ctrl_fifo, - * async TX error messages go in async_msg_fifo. sync_ctrl_fifo should - * never have more than 1 message in it, since it's expected that we'll - * wait for a control operation to finish before starting another one. - **********************************************************************/ -void b100_ctrl_impl::viking_marauder_loop(void){ - set_thread_priority_safe(); - - while (not boost::this_thread::interruption_requested()){ - managed_recv_buffer::sptr rbuf = _ctrl_transport->get_recv_buff(1.0); - if(rbuf.get() == NULL) continue; //that's ok, there are plenty of villages to pillage! - const boost::uint16_t *pkt_buf = rbuf->cast(); - - if(pkt_buf[0] >> 8 == CTRL_PACKET_HEADER_MAGIC) { - //so it's got a control packet header, let's parse it. - ctrl_pkt_t pkt; - unpack_ctrl_pkt(pkt_buf, pkt); - - if(pkt.pkt_meta.seq != boost::uint8_t(_seq - 1)) { - UHD_MSG(error) - << "Sequence error on control channel." << std::endl - << "Exiting control loop." << std::endl - ; - return; - } - if(pkt.pkt_meta.len > (CTRL_PACKET_LENGTH - CTRL_PACKET_HEADER_LENGTH)) { - UHD_MSG(error) - << "Control channel packet length too long" << std::endl - << "Exiting control loop." << std::endl - ; - return; - } - - //push it onto the queue - sync_ctrl_fifo.push_with_pop_on_full(pkt.data); - } - else{ //otherwise let the async callback handle it - boost::mutex::scoped_lock lock(_async_mutex); - if (not _async_cb.empty()) _async_cb(rbuf); - } - } -} - -bool b100_ctrl_impl::get_ctrl_data(ctrl_data_t &pkt_data, double timeout){ - boost::this_thread::disable_interruption di; //disable because the wait can throw - return sync_ctrl_fifo.pop_with_timed_wait(pkt_data, timeout); -} - -/*********************************************************************** - * Public make function for b100_ctrl interface - **********************************************************************/ -b100_ctrl::sptr b100_ctrl::make(uhd::transport::zero_copy_if::sptr ctrl_transport){ - return sptr(new b100_ctrl_impl(ctrl_transport)); -} diff --git a/host/lib/usrp/b100/b100_ctrl.hpp b/host/lib/usrp/b100/b100_ctrl.hpp deleted file mode 100644 index 74884d525..000000000 --- a/host/lib/usrp/b100/b100_ctrl.hpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright 2011 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_B100_CTRL_HPP -#define INCLUDED_B100_CTRL_HPP - -#include "wb_iface.hpp" -#include -#include -#include -#include -#include "ctrl_packet.hpp" -#include - -class b100_ctrl : boost::noncopyable, public wb_iface{ -public: - typedef boost::shared_ptr sptr; - typedef boost::function async_cb_type; - - /*! - * Make a USRP control object from a data transport - * \param ctrl_transport a USB data transport - * \return a new b100 control object - */ - static sptr make(uhd::transport::zero_copy_if::sptr ctrl_transport); - - //! set an async callback for messages - virtual void set_async_cb(const async_cb_type &async_cb) = 0; - - /*! - * Write a byte vector to an FPGA register - * \param addr the FPGA register address - * \param bytes the data to write - * \return 0 on success, error code on failure - */ - virtual int write(boost::uint32_t addr, const ctrl_data_t &data) = 0; - - /*! - * Read a byte vector from an FPGA register (blocking read) - * \param addr the FPGA register address - * \param len the length of the read - * \return a vector of bytes from the register(s) in question - */ - virtual ctrl_data_t read(boost::uint32_t addr, size_t len) = 0; - - /*! - * Get a sync ctrl packet (blocking) - * \param the packet data buffer - * \param the timeout value - * \return true if it got something - */ - virtual bool get_ctrl_data(ctrl_data_t &pkt_data, double timeout) = 0; - -}; - -#endif /* INCLUDED_B100_CTRL_HPP */ diff --git a/host/lib/usrp/b100/ctrl_packet.hpp b/host/lib/usrp/b100/ctrl_packet.hpp deleted file mode 100644 index bab1f0de1..000000000 --- a/host/lib/usrp/b100/ctrl_packet.hpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright 2011 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_CTRL_PACKET_HPP -#define INCLUDED_CTRL_PACKET_HPP - -#include -#include -#include - -typedef std::vector ctrl_data_t; - -/*! - * Control packet operation type - */ -enum ctrl_pkt_op_t { - CTRL_PKT_OP_WRITE = 1, - CTRL_PKT_OP_READ = 2, - CTRL_PKT_OP_READBACK = 3 -}; - -/*! - * Control packet transaction length - */ -const size_t CTRL_PACKET_LENGTH = 32; -const size_t CTRL_PACKET_HEADER_LENGTH = 8; -const size_t CTRL_PACKET_DATA_LENGTH = 24; //=length-header - -/*! - * Control packet header magic value - */ -const boost::uint8_t CTRL_PACKET_HEADER_MAGIC = 0xAA; - -/*! - * Callback triggers for readback operation - */ -//FIXME: these are not real numbers, callbacks aren't implemented yet -const boost::uint16_t CTRL_PACKET_CALLBACK_SPI = 0x0001; -const boost::uint16_t CTRL_PACKET_CALLBACK_I2C = 0x0002; -//and so on - -/*! - * Metadata structure to describe a control packet - */ -struct UHD_API ctrl_pkt_meta_t { - ctrl_pkt_op_t op; - boost::uint8_t callbacks; - boost::uint8_t seq; - boost::uint16_t len; - boost::uint32_t addr; -}; - -/*! - * Full control packet structure - */ -struct UHD_API ctrl_pkt_t { - ctrl_pkt_meta_t pkt_meta; - ctrl_data_t data; -}; - -#endif /* INCLUDED_CTRL_PACKET_HPP */ -- cgit v1.2.3