summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--firmware/zpu/apps/txrx_uhd.c9
-rw-r--r--firmware/zpu/lib/ad9510.c6
-rw-r--r--firmware/zpu/lib/clocks.c5
-rw-r--r--firmware/zpu/lib/memory_map.h37
-rw-r--r--firmware/zpu/lib/spi.c97
-rw-r--r--firmware/zpu/lib/spi.h42
-rw-r--r--firmware/zpu/lib/u2_init.c2
-rw-r--r--firmware/zpu/usrp2p/spi_flash.c4
-rw-r--r--firmware/zpu/usrp2p/spi_flash.h10
-rw-r--r--firmware/zpu/usrp2p/spif.c1
-rw-r--r--firmware/zpu/usrp2p/udp_fw_update.c4
-rw-r--r--host/examples/CMakeLists.txt1
-rw-r--r--host/examples/test_timed_commands.cpp129
-rw-r--r--host/examples/tx_waveforms.cpp5
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.cpp23
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.hpp3
-rw-r--r--host/lib/usrp/dboard/db_sbx_version3.cpp20
-rw-r--r--host/lib/usrp/dboard/db_sbx_version4.cpp6
-rw-r--r--host/lib/usrp/multi_usrp.cpp23
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt3
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp13
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp14
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp48
-rw-r--r--host/lib/usrp/usrp2/fw_common.h7
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp246
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp47
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp50
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp15
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp4
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