diff options
31 files changed, 664 insertions, 224 deletions
| diff --git a/firmware/zpu/apps/txrx_uhd.c b/firmware/zpu/apps/txrx_uhd.c index a4bfce0ec..0142aa3d4 100644 --- a/firmware/zpu/apps/txrx_uhd.c +++ b/firmware/zpu/apps/txrx_uhd.c @@ -89,6 +89,10 @@ static void handle_udp_data_packet(          which = 1;          break; +    case USRP2_UDP_FIFO_CRTL_PORT: +        which = 3; +        break; +      default: return;      } @@ -177,8 +181,8 @@ static void handle_udp_ctrl_packet(                  ctrl_data_in->data.spi_args.dev,      //which device                  ctrl_data_in->data.spi_args.data,     //32 bit data                  ctrl_data_in->data.spi_args.num_bits, //length in bits -                (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | -                (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL +                (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPI_PUSH_FALL : SPI_PUSH_RISE | +                (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPI_LATCH_RISE : SPI_LATCH_FALL              );              //load output @@ -338,6 +342,7 @@ main(void)    register_udp_listener(USRP2_UDP_RX_DSP0_PORT, handle_udp_data_packet);    register_udp_listener(USRP2_UDP_RX_DSP1_PORT, handle_udp_data_packet);    register_udp_listener(USRP2_UDP_TX_DSP0_PORT, handle_udp_data_packet); +  register_udp_listener(USRP2_UDP_FIFO_CRTL_PORT, handle_udp_data_packet);  #ifdef USRP2P    register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); diff --git a/firmware/zpu/lib/ad9510.c b/firmware/zpu/lib/ad9510.c index 4d3acb65d..4021a9bf7 100644 --- a/firmware/zpu/lib/ad9510.c +++ b/firmware/zpu/lib/ad9510.c @@ -1,5 +1,5 @@ -/* -*- c++ -*- */  /* + * Copyright 2012 Ettus Research LLC   * Copyright 2008 Free Software Foundation, Inc.   *   * This program is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ ad9510_write_reg(int regno, uint8_t value)  {    uint32_t inst = WR | (regno & 0xff);    uint32_t v = (inst << 8) | (value & 0xff); -  spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPIF_PUSH_FALL); +  spi_transact(SPI_TXONLY, SPI_SS_AD9510, v, 24, SPI_PUSH_FALL);  }  int @@ -37,6 +37,6 @@ ad9510_read_reg(int regno)    uint32_t inst = RD | (regno & 0xff);    uint32_t v = (inst << 8) | 0;    uint32_t r = spi_transact(SPI_TXRX, SPI_SS_AD9510, v, 24, -			    SPIF_PUSH_FALL | SPIF_LATCH_FALL); +			    SPI_PUSH_FALL | SPI_LATCH_FALL);    return r & 0xff;  } diff --git a/firmware/zpu/lib/clocks.c b/firmware/zpu/lib/clocks.c index c1e8ce827..bc1954e13 100644 --- a/firmware/zpu/lib/clocks.c +++ b/firmware/zpu/lib/clocks.c @@ -43,7 +43,10 @@ clocks_init(void)    //enable the 100MHz clock output to the FPGA for 50MHz CPU clock    clocks_enable_fpga_clk(true, 1); -  spi_wait(); +  //! Cannot SPI wait since SPI is on DSP clock +  //! because DSP clock goes away until DCM reset. +  //! However, spi is quick, the cpu is slow, its already ready... +  //spi_wait();    //wait for the clock to stabilize    while(!clocks_lock_detect()); diff --git a/firmware/zpu/lib/memory_map.h b/firmware/zpu/lib/memory_map.h index 9d47522ca..4290ee20a 100644 --- a/firmware/zpu/lib/memory_map.h +++ b/firmware/zpu/lib/memory_map.h @@ -1,4 +1,4 @@ -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2012 Ettus Research LLC  /*   * Copyright 2007,2008,2009 Free Software Foundation, Inc.   * @@ -49,18 +49,6 @@  // SPI Core, Slave 2.  See core docs for more info  ///////////////////////////////////////////////////// -typedef struct { -  volatile uint32_t	txrx0; -  volatile uint32_t	txrx1; -  volatile uint32_t	txrx2; -  volatile uint32_t	txrx3; -  volatile uint32_t	ctrl; -  volatile uint32_t	div; -  volatile uint32_t	ss; -} spi_regs_t; - -#define spi_regs ((spi_regs_t *) SPI_BASE) -  // Masks for controlling different peripherals  #define SPI_SS_AD9510    1  #define SPI_SS_AD9777    2 @@ -124,7 +112,8 @@ typedef struct {  ///////////////////////////////////////////////////  typedef struct { -  volatile uint32_t _padding[8]; +  volatile uint32_t spi; +  volatile uint32_t _padding[7];    volatile uint32_t status;    volatile uint32_t _unused;    volatile uint32_t time64_secs_rb; @@ -133,7 +122,10 @@ typedef struct {    volatile uint32_t irqs;  } router_status_t; +#define SPI_READY_IRQ (1 << 12) +  #define router_status ((router_status_t *) READBACK_BASE) +#define readback_mux ((router_status_t *) READBACK_BASE) //alias with a better name  /*!   * \brief return non-zero if we're running under the simulator @@ -207,7 +199,7 @@ typedef struct {  #define SR_SIMTIMER   8   // 2  #define SR_TIME64    10   // 6  #define SR_BUF_POOL  16   // 4 - +#define SR_SPI_CORE  20   // 3  #define SR_RX_FRONT  24   // 5  #define SR_RX_CTRL0  32   // 9  #define SR_RX_DSP0   48   // 7 @@ -224,6 +216,21 @@ typedef struct {  #define SR_ADDR_BLDRDONE _SR_ADDR(5) +// --- spi core control regs --- + +typedef struct { +  volatile uint32_t divider; +  volatile uint32_t control; +  volatile uint32_t data; +} spi_core_t; + +#define SPI_CORE_SLAVE_SELECT_SHIFT 0 +#define SPI_CORE_NUM_BITS_SHIFT 24 +#define SPI_CORE_DATA_IN_EDGE_SHIFT 30 +#define SPI_CORE_DATA_OUT_EDGE_SHIFT 31 + +#define spi_core ((spi_core_t *) _SR_ADDR(SR_SPI_CORE)) +  // --- packet router control regs ---  typedef struct { diff --git a/firmware/zpu/lib/spi.c b/firmware/zpu/lib/spi.c index af0d8a68f..6f2f74899 100644 --- a/firmware/zpu/lib/spi.c +++ b/firmware/zpu/lib/spi.c @@ -1,4 +1,5 @@  /* + * Copyright 2012 Ettus Research LLC   * Copyright 2007,2008 Free Software Foundation, Inc.   *   * This program is free software: you can redistribute it and/or modify @@ -17,94 +18,38 @@  #include "spi.h"  #include "memory_map.h" -#include "pic.h"  #include "nonstdio.h" -//void (*volatile spi_callback)(void); //SPI callback when xfer complete. - -//static void spi_irq_handler(unsigned irq); - -void -spi_init(void)  +void spi_init(void)  { -  /* -   * f_sclk = f_wb / ((div + 1) * 2) -   */ -  spi_regs->div = 1;  // 0 = Div by 2 (25 MHz); 1 = Div-by-4 (12.5 MHz) +    spi_core->divider = 10;  } -void -spi_wait(void)  +void spi_wait(void)  { -  while (spi_regs->ctrl & SPI_CTRL_GO_BSY) -    ; +    while ((readback_mux->irqs & SPI_READY_IRQ) == 0){ +        //NOP +    }  } -uint32_t -spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)  +uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags)  { -  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); -  int ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; - -  spi_wait(); - -  // Tell it which SPI slave device to access -  spi_regs->ss = slave & 0xffff; - -  // Data we will send -  spi_regs->txrx0 = data; +    uint32_t control_word = 0; +    control_word |= (slave << SPI_CORE_SLAVE_SELECT_SHIFT); +    control_word |= (length << SPI_CORE_NUM_BITS_SHIFT); +    if ((flags & SPI_PUSH_RISE)  != 0) control_word |= (1 << SPI_CORE_DATA_OUT_EDGE_SHIFT); +    if ((flags & SPI_PUSH_FALL)  != 0) control_word |= (0 << SPI_CORE_DATA_OUT_EDGE_SHIFT); +    if ((flags & SPI_LATCH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_IN_EDGE_SHIFT); +    if ((flags & SPI_LATCH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_IN_EDGE_SHIFT); -  // Run it -- write once and rewrite with GO set -  spi_regs->ctrl = ctrl; -  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; +    const uint32_t data_out = data << (32 - length); -  if(readback) {      spi_wait(); -    return spi_regs->txrx0; -  } -  else -    return 0; -} +    spi_core->control = control_word; +    spi_core->data = data_out; -/* -void spi_register_callback(void (*volatile callback)(void)) { -  spi_callback = callback; -} - -static void spi_irq_handler(unsigned irq) { -//  printf("SPI IRQ handler\n"); -//  uint32_t wat = spi_regs->ctrl; //read a register just to clear the interrupt -  //spi_regs->ctrl &= ~SPI_CTRL_IE; -  if(spi_callback) spi_callback(); //we could just use the PIC to register the user's callback, but this provides the ability to do other things later -} +    if (!readback) return 0; -uint32_t spi_get_data(void) { -  return spi_regs->txrx0; -} - -bool  -spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)) { -  flags &= (SPI_CTRL_TXNEG | SPI_CTRL_RXNEG); -  int ctrl = SPI_CTRL_ASS | SPI_CTRL_IE | (SPI_CTRL_CHAR_LEN_MASK & length) | flags; - -  if(spi_regs->ctrl & SPI_CTRL_GO_BSY) { -    printf("Async SPI busy!\n"); -    return false; //we don't wait on busy, we just return failure. we count on the host to not set up another transaction before the last one finishes. -  } - -  // Tell it which SPI slave device to access -  spi_regs->ss = slave & 0xffff; - -  // Data we will send -  spi_regs->txrx0 = data; - -  spi_register_callback(callback); -  pic_register_handler(IRQ_SPI, spi_irq_handler); - -  // Run it -- write once and rewrite with GO set -  spi_regs->ctrl = ctrl; -  spi_regs->ctrl = ctrl | SPI_CTRL_GO_BSY; - -  return true; +    spi_wait(); +    return readback_mux->spi;  } -*/ diff --git a/firmware/zpu/lib/spi.h b/firmware/zpu/lib/spi.h index 71245150a..125e1a502 100644 --- a/firmware/zpu/lib/spi.h +++ b/firmware/zpu/lib/spi.h @@ -1,5 +1,5 @@ -/* -*- c -*- */  /* + * Copyright 2012 Ettus Research LLC   * Copyright 2006,2007 Free Software Foundation, Inc.   *   * This program is free software: you can redistribute it and/or modify @@ -19,8 +19,8 @@  #ifndef INCLUDED_SPI_H  #define INCLUDED_SPI_H -#include <memory_map.h>  #include <stdbool.h> +#include <stdint.h>  /*!   * \brief One time call to initialize SPI @@ -39,39 +39,11 @@ void spi_wait(void);  /*   * Flags for spi_transact   */ -#define SPIF_PUSH_RISE   0		// push tx data on rising edge of SCLK -#define SPIF_PUSH_FALL   SPI_CTRL_TXNEG	// push tx data on falling edge of SCLK -#define SPIF_LATCH_RISE  0		// latch rx data on rising edge of SCLK -#define SPIF_LATCH_FALL  SPI_CTRL_RXNEG	// latch rx data on falling edge of SCLK - - -uint32_t -spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags); - -//uint32_t spi_get_data(void); -//static void spi_irq_handler(unsigned irq); -//void spi_register_callback(void (*volatile callback)(void)); - -//bool  -//spi_async_transact(int slave, uint32_t data, int length, uint32_t flags, void (*volatile callback)(void)); - -// ---------------------------------------------------------------- -// Routines that manipulate the FLASH SPI BUS -// ---------------------------------------------------------------- - -/*! - * \brief One time call to initialize SPI - */ -void spif_init(void); - -/*!  - * \brief Wait for last SPI transaction to complete. - * Unless you need to know it completed, it's not necessary to call this. - */ -void spif_wait(void); - -uint32_t -spif_transact(bool readback_, int slave, uint32_t data, int length, uint32_t flags); +#define SPI_PUSH_RISE   (1 << 0)		// push tx data on rising edge of SCLK +#define SPI_PUSH_FALL   (1 << 1)	// push tx data on falling edge of SCLK +#define SPI_LATCH_RISE  (1 << 2)		// latch rx data on rising edge of SCLK +#define SPI_LATCH_FALL  (1 << 3)	// latch rx data on falling edge of SCLK +uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags);  #endif /* INCLUDED_SPI_H */ diff --git a/firmware/zpu/lib/u2_init.c b/firmware/zpu/lib/u2_init.c index 71bd2c594..77c8c0722 100644 --- a/firmware/zpu/lib/u2_init.c +++ b/firmware/zpu/lib/u2_init.c @@ -51,6 +51,7 @@ u2_init(void)    hal_enable_ints();    // flash all leds to let us know board is alive +#ifndef BOOTLOADER    hal_set_led_src(0x0, 0x1f); /* software ctrl */    hal_set_leds(0x0, 0x1f);    mdelay(300);    hal_set_leds(LED_E, LED_E); mdelay(300); @@ -61,6 +62,7 @@ u2_init(void)      hal_set_leds(0x0,    0x1f); mdelay(100);      hal_set_leds(blinks, 0x1f); mdelay(100);    } +#endif    hal_set_led_src(0x1f & ~LED_D, 0x1f); /* hardware ctrl */    hal_set_leds(LED_D, 0x1f);  // Leave one on diff --git a/firmware/zpu/usrp2p/spi_flash.c b/firmware/zpu/usrp2p/spi_flash.c index 9406f8042..09f908edb 100644 --- a/firmware/zpu/usrp2p/spi_flash.c +++ b/firmware/zpu/usrp2p/spi_flash.c @@ -1,7 +1,6 @@ -/* -*- c++ -*- */  /*   * Copyright 2009 Free Software Foundation, Inc. - * Copyright 2009-2011 Ettus Research LLC + * Copyright 2009-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 @@ -17,6 +16,7 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ +#include "spi_flash.h"  #include "spi_flash_private.h"  //#include <stdlib.h>  #include <nonstdio.h> diff --git a/firmware/zpu/usrp2p/spi_flash.h b/firmware/zpu/usrp2p/spi_flash.h index a10533e08..8a8facdca 100644 --- a/firmware/zpu/usrp2p/spi_flash.h +++ b/firmware/zpu/usrp2p/spi_flash.h @@ -23,10 +23,18 @@  #include <stdint.h>  #include <stdbool.h> -  #define SPI_FLASH_PAGE_SIZE	256  #define SPI_SS_FLASH 1 +#define SPIF_PUSH_RISE   0             // push tx data on rising edge of SCLK +#define SPIF_PUSH_FALL   SPI_CTRL_TXNEG        // push tx data on falling edge of SCLK +#define SPIF_LATCH_RISE  0             // latch rx data on rising edge of SCLK +#define SPIF_LATCH_FALL  SPI_CTRL_RXNEG        // latch rx data on falling edge of SCLK + +void spif_init(void); +void spif_wait(void); + +uint32_t spif_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags);  uint32_t spi_flash_rdid(void);	/* Read ID */  uint32_t spi_flash_rdsr(void);	/* Read Status Register */ diff --git a/firmware/zpu/usrp2p/spif.c b/firmware/zpu/usrp2p/spif.c index 91da73155..60807ca4a 100644 --- a/firmware/zpu/usrp2p/spif.c +++ b/firmware/zpu/usrp2p/spif.c @@ -21,6 +21,7 @@   */  #include "spi.h" +#include "spi_flash.h"  #include "memory_map.h"  void diff --git a/firmware/zpu/usrp2p/udp_fw_update.c b/firmware/zpu/usrp2p/udp_fw_update.c index 5689388a8..cd9e7d902 100644 --- a/firmware/zpu/usrp2p/udp_fw_update.c +++ b/firmware/zpu/usrp2p/udp_fw_update.c @@ -1,6 +1,5 @@ -/* -*- c++ -*- */  /* - * Copyright 2010 Ettus Research LLC + * Copyright 2010-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 @@ -19,6 +18,7 @@  //Routines to handle updating the SPI Flash firmware via UDP  #include <net_common.h> +#include "memory_map.h"  #include "usrp2/fw_common.h"  #include "spi.h"  #include "spi_flash.h" diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 3c9a3880a..151a7cdf0 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -27,6 +27,7 @@ SET(example_sources      rx_timed_samples.cpp      test_messages.cpp      test_pps_input.cpp +    test_timed_commands.cpp      tx_bursts.cpp      tx_samples_from_file.cpp      tx_timed_samples.cpp diff --git a/host/examples/test_timed_commands.cpp b/host/examples/test_timed_commands.cpp new file mode 100644 index 000000000..34c83dfd6 --- /dev/null +++ b/host/examples/test_timed_commands.cpp @@ -0,0 +1,129 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#include <uhd/utils/thread_priority.hpp> +#include <uhd/utils/safe_main.hpp> +#include <uhd/usrp/multi_usrp.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <complex> + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ +    uhd::set_thread_priority_safe(); + +    //variables to be set by po +    std::string args; + +    //setup the program options +    po::options_description desc("Allowed options"); +    desc.add_options() +        ("help", "help message") +        ("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args") +    ; +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //print the help message +    if (vm.count("help")){ +        std::cout << boost::format("UHD Test Timed Commands %s") % desc << std::endl; +        return ~0; +    } + +    //create a usrp device +    std::cout << std::endl; +    std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; +    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); +    std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl; + +    //check if timed commands are supported +    std::cout << std::endl; +    std::cout << "Testing support for timed commands on this hardware... " << std::flush; +    try{ +        usrp->set_command_time(uhd::time_spec_t(0.0)); +        usrp->clear_command_time(); +    } +    catch (const std::exception &e){ +        std::cout << "fail" << std::endl; +        std::cerr << "Got exception: " << e.what() << std::endl; +        std::cerr << "Timed commands are not supported on this hardware." << std::endl; +        return ~0; +    } +    std::cout << "pass" << std::endl; + +    //readback time really fast, time diff is small +    std::cout << std::endl; +    std::cout << "Perform fast readback of registers:" << std::endl; +    uhd::time_spec_t total_time; +    for (size_t i = 0; i < 100; i++){ +        const uhd::time_spec_t t0 = usrp->get_time_now(); +        const uhd::time_spec_t t1 = usrp->get_time_now(); +        total_time += (t1-t0); +    } +    std::cout << boost::format( +        "Difference between paired reads: %f us" +    ) % (total_time.get_real_secs()/100*1e6) << std::endl; + +    //use a timed command to start a stream at a specific time +    //this is not the right way start streaming at time x, +    //but it should approximate it within control RTT/2 +    //setup streaming +    std::cout << std::endl; +    std::cout << "About to start streaming using timed command:" << std::endl; +     +    //create a receive streamer +    uhd::stream_args_t stream_args("fc32"); //complex floats +    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args); +     +    uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE); +    stream_cmd.num_samps = 100; +    stream_cmd.stream_now = true; +    const uhd::time_spec_t stream_time = usrp->get_time_now() + uhd::time_spec_t(0.1); +    usrp->set_command_time(stream_time); +    usrp->issue_stream_cmd(stream_cmd); +    usrp->clear_command_time(); + +    //meta-data will be filled in by recv() +    uhd::rx_metadata_t md; + +    //allocate buffer to receive with samples +    std::vector<std::complex<float> > buff(stream_cmd.num_samps); + +    const size_t num_rx_samps = rx_stream->recv(&buff.front(), buff.size(), md); +    if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE){ +        throw std::runtime_error(str(boost::format( +            "Unexpected error code 0x%x" +        ) % md.error_code)); +    } +    std::cout << boost::format( +        "Received packet: %u samples, %u full secs, %f frac secs" +    ) % num_rx_samps % md.time_spec.get_full_secs() % md.time_spec.get_frac_secs() << std::endl; +    std::cout << boost::format( +        "Stream time was: %u full secs, %f frac secs" +    ) % stream_time.get_full_secs() % stream_time.get_frac_secs() << std::endl; +    std::cout << boost::format( +        "Difference between stream time and first packet: %f us" +    ) % ((md.time_spec-stream_time).get_real_secs()/100*1e6) << std::endl; + +    //finished +    std::cout << std::endl << "Done!" << std::endl << std::endl; + +    return 0; +} diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp index 6a377fdac..3c5eecd65 100644 --- a/host/examples/tx_waveforms.cpp +++ b/host/examples/tx_waveforms.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -24,6 +24,7 @@  #include <boost/math/special_functions/round.hpp>  #include <boost/foreach.hpp>  #include <boost/format.hpp> +#include <boost/thread.hpp>  #include <iostream>  #include <complex>  #include <csignal> @@ -174,6 +175,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){          if (vm.count("ant")) usrp->set_tx_antenna(ant, chan);      } +    boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for some setup time +      //for the const wave, set the wave freq for small samples per period      if (wave_freq == 0 and wave_type == "CONST"){          wave_freq = usrp->get_tx_rate()/2; diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp index d1cd5b373..3cfc1e95f 100644 --- a/host/lib/usrp/dboard/db_sbx_common.cpp +++ b/host/lib/usrp/dboard/db_sbx_common.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 @@ -213,8 +213,8 @@ void sbx_xcvr::update_atr(void){      int tx_pga0_iobits = tx_pga0_gain_to_iobits(_tx_gains["PGA0"]);      int rx_lo_lpf_en = (_rx_lo_freq == sbx_enable_rx_lo_filter.clip(_rx_lo_freq)) ? LO_LPF_EN : 0;      int tx_lo_lpf_en = (_tx_lo_freq == sbx_enable_tx_lo_filter.clip(_tx_lo_freq)) ? LO_LPF_EN : 0; -    int rx_ld_led = get_locked(dboard_iface::UNIT_RX).to_bool() ? 0 : RX_LED_LD; -    int tx_ld_led = get_locked(dboard_iface::UNIT_TX).to_bool() ? 0 : TX_LED_LD; +    int rx_ld_led = _rx_lo_lock_cache ? 0 : RX_LED_LD; +    int tx_ld_led = _tx_lo_lock_cache ? 0 : TX_LED_LD;      int rx_ant_led = _rx_ant == "TX/RX" ? RX_LED_RX1RX2 : 0;      int tx_ant_led = _tx_ant == "TX/RX" ? 0 : TX_LED_TXRX; @@ -283,8 +283,14 @@ void sbx_xcvr::set_tx_ant(const std::string &ant){   **********************************************************************/  double sbx_xcvr::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {      const double actual = db_actual->set_lo_freq(unit, target_freq); -    if (unit == dboard_iface::UNIT_RX) _rx_lo_freq = actual; -    if (unit == dboard_iface::UNIT_TX) _tx_lo_freq = actual; +    if (unit == dboard_iface::UNIT_RX){ +        _rx_lo_lock_cache = false; +        _rx_lo_freq = actual; +    } +    if (unit == dboard_iface::UNIT_TX){ +        _tx_lo_lock_cache = false; +        _tx_lo_freq = actual; +    }      update_atr();      return actual;  } @@ -292,6 +298,13 @@ double sbx_xcvr::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {  sensor_value_t sbx_xcvr::get_locked(dboard_iface::unit_t unit) {      const bool locked = (this->get_iface()->read_gpio(unit) & LOCKDET_MASK) != 0; + +    if (unit == dboard_iface::UNIT_RX) _rx_lo_lock_cache = locked; +    if (unit == dboard_iface::UNIT_TX) _tx_lo_lock_cache = locked; + +    //write the new lock cache setting to atr regs +    update_atr(); +      return sensor_value_t("LO", locked, "locked", "unlocked");  } diff --git a/host/lib/usrp/dboard/db_sbx_common.hpp b/host/lib/usrp/dboard/db_sbx_common.hpp index 501a7f1fc..2a0e83115 100644 --- a/host/lib/usrp/dboard/db_sbx_common.hpp +++ b/host/lib/usrp/dboard/db_sbx_common.hpp @@ -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 @@ -138,6 +138,7 @@ protected:      uhd::dict<std::string, double> _tx_gains, _rx_gains;      double       _rx_lo_freq, _tx_lo_freq;      std::string  _tx_ant, _rx_ant; +    bool _rx_lo_lock_cache, _tx_lo_lock_cache;      void set_rx_ant(const std::string &ant);      void set_tx_ant(const std::string &ant); diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp index 6e20d5882..040bef12f 100644 --- a/host/lib/usrp/dboard/db_sbx_version3.cpp +++ b/host/lib/usrp/dboard/db_sbx_version3.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 @@ -75,7 +75,6 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar      if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;      //increase RF divider until acceptable VCO frequency -    //start with target_freq*2 because mixer has divide by 2      double vco_freq = target_freq;      while (vco_freq < 2.2e9) {          vco_freq *= 2; @@ -83,7 +82,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar      }      //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler) -    adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5; +    adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;      /*       * The goal here is to loop though possible R dividers, @@ -91,7 +90,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar       * (frac) dividers.       *       * Calculate the N and F dividers for each set of values. -     * The loop exists when it meets all of the constraints. +     * The loop exits when it meets all of the constraints.       * The resulting loop values are loaded into the registers.       *       * from pg.21 @@ -110,7 +109,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar          if (pfd_freq > 25e6) continue;          //ignore fractional part of tuning -        N = int(std::floor(vco_freq/pfd_freq)); +        N = int(std::floor(target_freq/pfd_freq));          //keep N > minimum int divider requirement          if (N < prescaler_to_min_int_div[prescaler]) continue; @@ -125,7 +124,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar      //Fractional-N calculation      MOD = 4095; //max fractional accuracy -    FRAC = int((vco_freq/pfd_freq - N)*MOD); +    FRAC = int((target_freq/pfd_freq - N)*MOD);      //Reference divide-by-2 for 50% duty cycle      // if R even, move one divide by 2 to to regs.reference_divide_by_2 @@ -135,12 +134,12 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar      }      //actual frequency calculation -    actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv); +    actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));      UHD_LOGV(often)          << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl -        << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s" -            ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl +        << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d" +            ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl          << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"              ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl; @@ -155,6 +154,9 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar      regs.frac_12_bit = FRAC;      regs.int_16_bit = N;      regs.mod_12_bit = MOD; +    regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD))); +    regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED; +    regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;      regs.prescaler = prescaler;      regs.r_counter_10_bit = R;      regs.reference_divide_by_2 = T; diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp index c8128d5f4..12bc9b76e 100644 --- a/host/lib/usrp/dboard/db_sbx_version4.cpp +++ b/host/lib/usrp/dboard/db_sbx_version4.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 @@ -142,8 +142,8 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar      UHD_LOGV(often)          << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl -        << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s" -            ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl +        << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d" +            ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl          << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"              ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl; diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 42c654e6b..e2efa9a00 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -356,12 +356,27 @@ public:          return true;      } -    void set_command_time(const time_spec_t &, size_t){ -        throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it."); +    void set_command_time(const time_spec_t &time_spec, size_t mboard){ +        if (mboard != ALL_MBOARDS){ +            if (not _tree->exists(mb_root(mboard) / "time/cmd")){ +                throw uhd::not_implemented_error("timed command feature not implemented on this hardware"); +            } +            _tree->access<time_spec_t>(mb_root(mboard) / "time/cmd").set(time_spec); +            return; +        } +        for (size_t m = 0; m < get_num_mboards(); m++){ +            set_command_time(time_spec, m); +        }      } -    void clear_command_time(size_t){ -        throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it."); +    void clear_command_time(size_t mboard){ +        if (mboard != ALL_MBOARDS){ +            _tree->access<time_spec_t>(mb_root(mboard) / "time/cmd").set(time_spec_t(0.0)); +            return; +        } +        for (size_t m = 0; m < get_num_mboards(); m++){ +            clear_command_time(m); +        }      }      void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){ diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 10f7407b0..da39d9df1 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/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,5 +32,6 @@ IF(ENABLE_USRP2)          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_fifo_ctrl.cpp      )  ENDIF(ENABLE_USRP2) diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 7d3ffefa2..769795aad 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -35,8 +35,9 @@ static const bool enb_test_clk = false;   */  class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{  public: -    usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){ +    usrp2_clock_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){          _iface = iface; +        _spiface = spiface;          clk_regs = usrp2_clk_regs_t(_iface->get_rev());          _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; @@ -331,7 +332,7 @@ private:       */      void write_reg(boost::uint8_t addr){          boost::uint32_t data = _ad9510_regs.get_write_reg(addr); -        _iface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24); +        _spiface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24);      }      /*! @@ -377,7 +378,7 @@ private:      }      usrp2_iface::sptr _iface; - +    uhd::spi_iface::sptr _spiface;      usrp2_clk_regs_t clk_regs;      ad9510_regs_t _ad9510_regs;  }; @@ -385,6 +386,6 @@ private:  /***********************************************************************   * Public make function for the ad9510 clock control   **********************************************************************/ -usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_clock_ctrl_impl(iface)); +usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ +    return sptr(new usrp2_clock_ctrl_impl(iface, spiface));  } diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 9ccbc959e..067e1e35d 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-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 @@ -29,10 +29,11 @@ public:      /*!       * Make a clock config for the ad9510 ic. -     * \param _iface a pointer to the usrp2 interface object +     * \param iface a pointer to the usrp2 interface object +     * \param spiface the interface to spi       * \return a new clock control object       */ -    static sptr make(usrp2_iface::sptr iface); +    static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);      /*!       * Get the master clock frequency for the fpga. diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 06bf83b15..b53c4d9df 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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,8 +32,9 @@ using namespace uhd;   */  class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{  public: -    usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){ +    usrp2_codec_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){          _iface = iface; +        _spiface = spiface;          //setup the ad9777 dac          _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; @@ -189,11 +190,12 @@ private:      ad9777_regs_t _ad9777_regs;      ads62p44_regs_t _ads62p44_regs;      usrp2_iface::sptr _iface; +    uhd::spi_iface::sptr _spiface;      void send_ad9777_reg(boost::uint8_t addr){          boost::uint16_t reg = _ad9777_regs.get_write_reg(addr);          UHD_LOGV(always) << "send_ad9777_reg: " << std::hex << reg << std::endl; -        _iface->write_spi( +        _spiface->write_spi(              SPI_SS_AD9777, spi_config_t::EDGE_RISE,              reg, 16          ); @@ -201,7 +203,7 @@ private:      void send_ads62p44_reg(boost::uint8_t addr) {          boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr); -        _iface->write_spi( +        _spiface->write_spi(              SPI_SS_ADS62P44, spi_config_t::EDGE_FALL,              reg, 16          ); @@ -211,6 +213,6 @@ private:  /***********************************************************************   * Public make function for the usrp2 codec control   **********************************************************************/ -usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface){ -    return sptr(new usrp2_codec_ctrl_impl(iface)); +usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ +    return sptr(new usrp2_codec_ctrl_impl(iface, spiface));  } diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index ca300e2b1..b0d815be2 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -28,10 +28,11 @@ public:      /*!       * Make a codec control for the DAC and ADC. -     * \param _iface a pointer to the usrp2 interface object +     * \param iface a pointer to the usrp2 interface object +     * \param spiface the interface to spi       * \return a new codec control object       */ -    static sptr make(usrp2_iface::sptr iface); +    static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface);      /*!       * Set the modulation mode for the DAC. diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index bc510c8a1..edd9ef242 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -16,7 +16,7 @@  //  #include "gpio_core_200.hpp" -#include "usrp2_iface.hpp" +#include <uhd/types/serial.hpp>  #include "clock_ctrl.hpp"  #include "usrp2_regs.hpp" //wishbone address constants  #include <uhd/usrp/dboard_iface.hpp> @@ -35,7 +35,12 @@ using namespace boost::assign;  class usrp2_dboard_iface : public dboard_iface{  public: -    usrp2_dboard_iface(usrp2_iface::sptr iface, usrp2_clock_ctrl::sptr clock_ctrl); +    usrp2_dboard_iface( +        wb_iface::sptr wb_iface, +        uhd::i2c_iface::sptr i2c_iface, +        uhd::spi_iface::sptr spi_iface, +        usrp2_clock_ctrl::sptr clock_ctrl +    );      ~usrp2_dboard_iface(void);      special_props_t get_special_props(void){ @@ -79,7 +84,8 @@ public:      );  private: -    usrp2_iface::sptr _iface; +    uhd::i2c_iface::sptr _i2c_iface; +    uhd::spi_iface::sptr _spi_iface;      usrp2_clock_ctrl::sptr _clock_ctrl;      gpio_core_200::sptr _gpio; @@ -92,22 +98,28 @@ private:   * Make Function   **********************************************************************/  dboard_iface::sptr make_usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clock_ctrl  ){ -    return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl)); +    return dboard_iface::sptr(new usrp2_dboard_iface(wb_iface, i2c_iface, spi_iface, clock_ctrl));  }  /***********************************************************************   * Structors   **********************************************************************/  usrp2_dboard_iface::usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clock_ctrl -){ -    _iface = iface; -    _clock_ctrl = clock_ctrl; -    _gpio = gpio_core_200::make(_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB); +): +    _i2c_iface(i2c_iface), +    _spi_iface(spi_iface), +    _clock_ctrl(clock_ctrl) +{ +    _gpio = gpio_core_200::make(wb_iface, U2_REG_SR_ADDR(SR_GPIO), U2_REG_GPIO_RB);      //reset the aux dacs      _dac_regs[UNIT_RX] = ad5623_regs_t(); @@ -202,7 +214,7 @@ void usrp2_dboard_iface::write_spi(      boost::uint32_t data,      size_t num_bits  ){ -    _iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits); +    _spi_iface->write_spi(unit_to_spi_dev[unit], config, data, num_bits);  }  boost::uint32_t usrp2_dboard_iface::read_write_spi( @@ -211,18 +223,18 @@ boost::uint32_t usrp2_dboard_iface::read_write_spi(      boost::uint32_t data,      size_t num_bits  ){ -    return _iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits); +    return _spi_iface->read_spi(unit_to_spi_dev[unit], config, data, num_bits);  }  /***********************************************************************   * I2C   **********************************************************************/  void usrp2_dboard_iface::write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ -    return _iface->write_i2c(addr, bytes); +    return _i2c_iface->write_i2c(addr, bytes);  }  byte_vector_t usrp2_dboard_iface::read_i2c(boost::uint8_t addr, size_t num_bytes){ -    return _iface->read_i2c(addr, num_bytes); +    return _i2c_iface->read_i2c(addr, num_bytes);  }  /*********************************************************************** @@ -233,7 +245,7 @@ void usrp2_dboard_iface::_write_aux_dac(unit_t unit){          (UNIT_RX, SPI_SS_RX_DAC)          (UNIT_TX, SPI_SS_TX_DAC)      ; -    _iface->write_spi( +    _spi_iface->write_spi(          unit_to_spi_dac[unit], spi_config_t::EDGE_FALL,           _dac_regs[unit].get_reg(), 24      ); @@ -281,11 +293,11 @@ double usrp2_dboard_iface::read_aux_adc(unit_t unit, aux_adc_t which){      } ad7922_regs.chn = ad7922_regs.mod; //normal mode: mod == chn      //write and read spi -    _iface->write_spi( +    _spi_iface->write_spi(          unit_to_spi_adc[unit], config,          ad7922_regs.get_reg(), 16      ); -    ad7922_regs.set_reg(boost::uint16_t(_iface->read_spi( +    ad7922_regs.set_reg(boost::uint16_t(_spi_iface->read_spi(          unit_to_spi_adc[unit], config,          ad7922_regs.get_reg(), 16      ))); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 2add74c47..acd5d1f3a 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -1,5 +1,5 @@  // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -30,8 +30,8 @@ extern "C" {  #endif  //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 9 -#define USRP2_FW_COMPAT_NUM 11 +#define USRP2_FPGA_COMPAT_NUM 10 +#define USRP2_FW_COMPAT_NUM 12  #define USRP2_FW_VER_MINOR 2  //used to differentiate control packets over data port @@ -51,6 +51,7 @@ typedef struct{  #define USRP2_UDP_RX_DSP0_PORT 49156  #define USRP2_UDP_TX_DSP0_PORT 49157  #define USRP2_UDP_RX_DSP1_PORT 49158 +#define USRP2_UDP_FIFO_CRTL_PORT 49159  #define USRP2_UDP_UART_BASE_PORT 49170  #define USRP2_UDP_UART_GPS_PORT 49172 diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp new file mode 100644 index 000000000..0f652b294 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp @@ -0,0 +1,246 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#include "usrp2_regs.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/utils/safe_call.hpp> +#include <uhd/transport/vrt_if_packet.hpp> +#include "usrp2_fifo_ctrl.hpp" +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/asio.hpp> //htonl +#include <boost/format.hpp> + +using namespace uhd; +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 = 64; + +#define SPI_DIV SR_SPI_CORE + 0 +#define SPI_CTRL SR_SPI_CORE + 1 +#define SPI_DATA SR_SPI_CORE + 2 +#define SPI_READBACK 0 +// spi clock rate = master_clock/(div+1)/2 (10MHz in this case) +#define SPI_DIVIDER 4 + +class usrp2_fifo_ctrl_impl : public usrp2_fifo_ctrl{ +public: + +    usrp2_fifo_ctrl_impl(zero_copy_if::sptr xport): +        _xport(xport), +        _seq_out(0), +        _seq_ack(0), +        _timeout(ACK_TIMEOUT) +    { +        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 +        this->init_spi(); +    } + +    ~usrp2_fifo_ctrl_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 +        ) +    } + +    /******************************************************************* +     * 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 - SETTING_REGS_BASE)/4, 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 - READBACK_BASE)/4, 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(SPI_READBACK, 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 *trans = buff->cast<boost::uint32_t *>(); +        trans[0] = htonl(++_seq_out); +        boost::uint32_t *pkt = trans + 1; + +        //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_be(pkt, packet_info); + +        //load payload +        const boost::uint32_t ctrl_word = (addr & 0xff) | cmd | (_seq_out << 16); +        pkt[packet_info.num_header_words32+0] = htonl(ctrl_word); +        pkt[packet_info.num_header_words32+1] = htonl(data); + +        //send the buffer over the interface +        buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32+1)); +    } + +    UHD_INLINE bool wraparound_lt16(const boost::int16_t i0, const boost::int16_t i1){ +        if (i0 == i1) return false; +        const int s0 = boost::uint16_t(i0) >> 15; +        const int s1 = boost::uint16_t(i1) >> 15; +        if (s0 != s1) return boost::int16_t(i1 - i0) > 0; +        return boost::uint16_t(i0) < boost::uint16_t(i1); +    } + +    UHD_INLINE boost::uint32_t wait_for_ack(const boost::uint16_t seq_to_ack){ + +        while (wraparound_lt16(_seq_ack, seq_to_ack)){ +            managed_recv_buffer::sptr buff = _xport->get_recv_buff(_timeout); +            if (not buff){ +                throw uhd::runtime_error("fifo ctrl timed out looking for acks"); +            } +            const boost::uint32_t *pkt = buff->cast<const boost::uint32_t *>(); +            vrt::if_packet_info_t packet_info; +            packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); +            vrt::if_hdr_unpack_be(pkt, packet_info); +            _seq_ack = ntohl(pkt[packet_info.num_header_words32+0]) >> 16; +            if (_seq_ack == seq_to_ack){ +                return ntohl(pkt[packet_info.num_header_words32+1]); +            } +        } + +        return 0; +    } + +    zero_copy_if::sptr _xport; +    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; +}; + + +usrp2_fifo_ctrl::sptr usrp2_fifo_ctrl::make(zero_copy_if::sptr xport){ +    return sptr(new usrp2_fifo_ctrl_impl(xport)); +} diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp new file mode 100644 index 000000000..b48d05aa2 --- /dev/null +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp @@ -0,0 +1,47 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_USRP2_FIFO_CTRL_HPP +#define INCLUDED_USRP2_FIFO_CTRL_HPP + +#include <uhd/types/time_spec.hpp> +#include <uhd/types/serial.hpp> +#include <uhd/transport/zero_copy.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include "wb_iface.hpp" +#include <string> + +/*! + * The usrp2 FIFO control class: + * Provide high-speed peek/poke interface. + */ +class usrp2_fifo_ctrl : public wb_iface, public uhd::spi_iface{ +public: +    typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr; + +    //! Make a new FIFO control object +    static sptr make(uhd::transport::zero_copy_if::sptr xport); + +    //! 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; +}; + +#endif /* INCLUDED_USRP2_FIFO_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 20a74db2c..2e3d1e479 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -377,8 +377,15 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          _mbc[mb].tx_dsp_xport = make_xport(              addr, BOOST_STRINGIZE(USRP2_UDP_TX_DSP0_PORT), device_args_i, "send"          ); +        UHD_LOG << "Making transport for Control..." << std::endl; +        _mbc[mb].fifo_ctrl_xport = make_xport( +            addr, BOOST_STRINGIZE(USRP2_UDP_FIFO_CRTL_PORT), device_addr_t(), "" +        );          //set the filter on the router to take dsp data from this port -        _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, USRP2_UDP_TX_DSP0_PORT); +        _mbc[mb].iface->poke32(U2_REG_ROUTER_CTRL_PORTS, (USRP2_UDP_FIFO_CRTL_PORT << 16) | USRP2_UDP_TX_DSP0_PORT); + +        //create the fifo control interface for high speed register access +        _mbc[mb].fifo_ctrl = usrp2_fifo_ctrl::make(_mbc[mb].fifo_ctrl_xport);          ////////////////////////////////////////////////////////////////          // setup the mboard eeprom @@ -390,7 +397,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          ////////////////////////////////////////////////////////////////          // create clock control objects          //////////////////////////////////////////////////////////////// -        _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface); +        _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface, _mbc[mb].fifo_ctrl/*spi*/);          _tree->create<double>(mb_path / "tick_rate")              .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock))              .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1)); @@ -402,7 +409,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          const fs_path tx_codec_path = mb_path / "tx_codecs/A";          _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists          _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists -        _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface); +        _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface, _mbc[mb].fifo_ctrl/*spi*/);          switch(_mbc[mb].iface->get_rev()){          case usrp2_iface::USRP_N200:          case usrp2_iface::USRP_N210: @@ -455,10 +462,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create frontend control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].rx_fe = rx_frontend_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_FRONT) +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_RX_FRONT)          );          _mbc[mb].tx_fe = tx_frontend_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_FRONT) +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_TX_FRONT)          );          _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec") @@ -489,10 +496,10 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create rx dsp control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), USRP2_RX_SID_BASE + 0, true          ));          _mbc[mb].rx_dsps.push_back(rx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), USRP2_RX_SID_BASE + 1, true          ));          for (size_t dspno = 0; dspno < _mbc[mb].rx_dsps.size(); dspno++){              _mbc[mb].rx_dsps[dspno]->set_link_rate(USRP2_LINK_RATE_BPS); @@ -517,7 +524,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          // create tx dsp control objects          ////////////////////////////////////////////////////////////////          _mbc[mb].tx_dsp = tx_dsp_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID          );          _mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS);          _tree->access<double>(mb_path / "tick_rate") @@ -551,7 +558,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){          time64_rb_bases.rb_hi_pps = U2_REG_TIME64_HI_RB_PPS;          time64_rb_bases.rb_lo_pps = U2_REG_TIME64_LO_RB_PPS;          _mbc[mb].time64 = time64_core_200::make( -            _mbc[mb].iface, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles +            _mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_TIME64), time64_rb_bases, mimo_clock_sync_delay_cycles          );          _tree->access<double>(mb_path / "tick_rate")              .subscribe(boost::bind(&time64_core_200::set_tick_rate, _mbc[mb].time64, _1)); @@ -571,11 +578,23 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){              .subscribe(boost::bind(&usrp2_impl::update_clock_source, this, mb, _1));          static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("mimo");          _tree->create<std::vector<std::string> >(mb_path / "clock_source/options").set(clock_sources); +        //plug timed commands into tree here +        switch(_mbc[mb].iface->get_rev()){ +        case usrp2_iface::USRP_N200: +        case usrp2_iface::USRP_N210: +        case usrp2_iface::USRP_N200_R4: +        case usrp2_iface::USRP_N210_R4: +            _tree->create<time_spec_t>(mb_path / "time/cmd") +                .subscribe(boost::bind(&usrp2_fifo_ctrl::set_time, _mbc[mb].fifo_ctrl, _1)); +        default: break; //otherwise, do not register +        } +        _tree->access<double>(mb_path / "tick_rate") +            .subscribe(boost::bind(&usrp2_fifo_ctrl::set_tick_rate, _mbc[mb].fifo_ctrl, _1));          ////////////////////////////////////////////////////////////////////          // create user-defined control objects          //////////////////////////////////////////////////////////////////// -        _mbc[mb].user = user_settings_core_200::make(_mbc[mb].iface, U2_REG_SR_ADDR(SR_USER_REGS)); +        _mbc[mb].user = user_settings_core_200::make(_mbc[mb].fifo_ctrl, U2_REG_SR_ADDR(SR_USER_REGS));          _tree->create<user_settings_core_200::user_reg_t>(mb_path / "user/regs")              .subscribe(boost::bind(&user_settings_core_200::set_reg, _mbc[mb].user, _1)); @@ -601,7 +620,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){              .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1));          //create a new dboard interface and manager -        _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].iface, _mbc[mb].clock); +        _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].fifo_ctrl/*wb*/, _mbc[mb].iface/*i2c*/, _mbc[mb].fifo_ctrl/*spi*/, _mbc[mb].clock);          _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface);          _mbc[mb].dboard_manager = dboard_manager::make(              rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, @@ -671,12 +690,12 @@ void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, c  }  sensor_value_t usrp2_impl::get_mimo_locked(const std::string &mb){ -    const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0; +    const bool lock = (_mbc[mb].fifo_ctrl->peek32(U2_REG_IRQ_RB) & (1<<10)) != 0;      return sensor_value_t("MIMO", lock, "locked", "unlocked");  }  sensor_value_t usrp2_impl::get_ref_locked(const std::string &mb){ -    const bool lock = (_mbc[mb].iface->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0; +    const bool lock = (_mbc[mb].fifo_ctrl->peek32(U2_REG_IRQ_RB) & (1<<11)) != 0;      return sensor_value_t("Ref", lock, "locked", "unlocked");  } @@ -715,13 +734,14 @@ meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb){  }  void usrp2_impl::update_clock_source(const std::string &mb, const std::string &source){ +    //NOTICE: U2_REG_MISC_CTRL_CLOCK is on the wb clock, and cannot be set from fifo_ctrl      //clock source ref 10mhz      switch(_mbc[mb].iface->get_rev()){      case usrp2_iface::USRP_N200:      case usrp2_iface::USRP_N210:      case usrp2_iface::USRP_N200_R4:      case usrp2_iface::USRP_N210_R4: -        if (source == "internal")       _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12); +        if      (source == "internal")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x12);          else if (source == "external")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);          else if (source == "mimo")      _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);          else throw uhd::value_error("unhandled clock configuration reference source: " + source); @@ -730,7 +750,7 @@ void usrp2_impl::update_clock_source(const std::string &mb, const std::string &s      case usrp2_iface::USRP2_REV3:      case usrp2_iface::USRP2_REV4: -        if (source == "internal")       _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); +        if      (source == "internal")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10);          else if (source == "external")  _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C);          else if (source == "mimo")      _mbc[mb].iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15);          else throw uhd::value_error("unhandled clock configuration reference source: " + source); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 6053c3890..3d2fbf14f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -18,7 +18,9 @@  #ifndef INCLUDED_USRP2_IMPL_HPP  #define INCLUDED_USRP2_IMPL_HPP +#include "gpio_core_200.hpp"  #include "usrp2_iface.hpp" +#include "usrp2_fifo_ctrl.hpp"  #include "clock_ctrl.hpp"  #include "codec_ctrl.hpp"  #include "rx_frontend_core_200.hpp" @@ -52,14 +54,11 @@ static const size_t USRP2_SRAM_BYTES = size_t(1 << 20);  static const boost::uint32_t USRP2_TX_ASYNC_SID = 2;  static const boost::uint32_t USRP2_RX_SID_BASE = 3; -/*! - * Make a usrp2 dboard interface. - * \param iface the usrp2 interface object - * \param clk_ctrl the clock control object - * \return a sptr to a new dboard interface - */ +//! Make a usrp2 dboard interface.  uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( -    usrp2_iface::sptr iface, +    wb_iface::sptr wb_iface, +    uhd::i2c_iface::sptr i2c_iface, +    uhd::spi_iface::sptr spi_iface,      usrp2_clock_ctrl::sptr clk_ctrl  ); @@ -82,6 +81,7 @@ private:      uhd::property_tree::sptr _tree;      struct mb_container_type{          usrp2_iface::sptr iface; +        usrp2_fifo_ctrl::sptr fifo_ctrl;          usrp2_clock_ctrl::sptr clock;          usrp2_codec_ctrl::sptr codec;          uhd::gps_ctrl::sptr gps; @@ -95,6 +95,7 @@ private:          user_settings_core_200::sptr user;          std::vector<uhd::transport::zero_copy_if::sptr> rx_dsp_xports;          uhd::transport::zero_copy_if::sptr tx_dsp_xport; +        uhd::transport::zero_copy_if::sptr fifo_ctrl_xport;          uhd::usrp::dboard_manager::sptr dboard_manager;          uhd::usrp::dboard_iface::sptr dboard_iface;          size_t rx_chan_occ, tx_chan_occ; diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index e14798ecb..7fe83e709 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -36,10 +36,10 @@  // Setting register offsets  ////////////////////////////////////////////////////////////////////////  #define SR_MISC       0   // 7 regs -#define SR_SIMTIMER   8   // 2 +#define SR_USER_REGS  8   // 2  #define SR_TIME64    10   // 6  #define SR_BUF_POOL  16   // 4 -#define SR_USER_REGS 20   // 2 +#define SR_SPI_CORE  20   // 3  #define SR_RX_FRONT  24   // 5  #define SR_RX_CTRL0  32   // 9  #define SR_RX_DSP0   48   // 7 | 
