aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fpga/usrp2/control_lib/Makefile.srcs5
-rw-r--r--fpga/usrp2/top/u1e/u1e_core.v81
-rw-r--r--host/CMakeLists.txt2
-rw-r--r--host/apps/omap_debug/usrp-e-crc-rw.c149
-rw-r--r--host/apps/omap_debug/usrp-e-mm-loopback.c2
-rw-r--r--host/apps/omap_debug/usrp_e.h11
-rw-r--r--host/docs/CMakeLists.txt1
-rw-r--r--host/docs/index.rst4
-rw-r--r--host/docs/usrp_e1xx.rst65
-rw-r--r--host/examples/rx_timed_samples.cpp9
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9522_regs.py8
-rw-r--r--host/lib/usrp/usrp_e100/CMakeLists.txt4
-rw-r--r--host/lib/usrp/usrp_e100/clock_ctrl.cpp326
-rw-r--r--host/lib/usrp/usrp_e100/clock_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp_e100/fpga_downloader.cpp (renamed from host/lib/usrp/usrp_e100/fpga-downloader.cc)42
-rw-r--r--host/lib/usrp/usrp_e100/io_impl.cpp23
-rw-r--r--host/lib/usrp/usrp_e100/mboard_impl.cpp8
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_iface.cpp6
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.hpp2
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_regs.hpp94
-rw-r--r--host/usrp_e_utils/CMakeLists.txt51
-rw-r--r--host/usrp_e_utils/clkgen_config.hpp (renamed from host/utils/clkgen-config.cpp)67
-rw-r--r--host/usrp_e_utils/usrp-e-debug-pins.c (renamed from host/utils/usrp-e-debug-pins.c)0
-rw-r--r--host/usrp_e_utils/usrp-e-i2c.c (renamed from host/utils/usrp-e-i2c.c)0
-rw-r--r--host/usrp_e_utils/usrp-e-loopback.c (renamed from host/utils/usrp-e-loopback.c)0
-rw-r--r--host/usrp_e_utils/usrp-e-spi.c (renamed from host/utils/usrp-e-spi.c)0
-rw-r--r--host/usrp_e_utils/usrp-e-utility.cpp75
-rw-r--r--host/usrp_e_utils/usrp-e-wb-test.cpp115
-rw-r--r--host/utils/CMakeLists.txt16
-rw-r--r--host/utils/fpga-downloader.cpp267
-rw-r--r--images/Makefile16
31 files changed, 913 insertions, 543 deletions
diff --git a/fpga/usrp2/control_lib/Makefile.srcs b/fpga/usrp2/control_lib/Makefile.srcs
index 751b40828..5ae185ee8 100644
--- a/fpga/usrp2/control_lib/Makefile.srcs
+++ b/fpga/usrp2/control_lib/Makefile.srcs
@@ -50,4 +50,9 @@ bootram.v \
nsgpio16LE.v \
settings_bus_16LE.v \
atr_controller16.v \
+newfifo/fifo_pacer.v \
+newfifo/packet_generator32.v \
+newfifo/packet_generator.v \
+newfifo/packet_verifier32.v \
+newfifo/packet_verifier.v \
))
diff --git a/fpga/usrp2/top/u1e/u1e_core.v b/fpga/usrp2/top/u1e/u1e_core.v
index d590b4fb1..7d5924bea 100644
--- a/fpga/usrp2/top/u1e/u1e_core.v
+++ b/fpga/usrp2/top/u1e/u1e_core.v
@@ -29,18 +29,22 @@ module u1e_core
localparam TXFIFOSIZE = 13;
localparam RXFIFOSIZE = 13;
- localparam SR_RX_DSP = 0; // 5 regs
- localparam SR_CLEAR_FIFO = 6; // 1 reg
- localparam SR_RX_CTRL = 8; // 9 regs
- localparam SR_TX_DSP = 17; // 5 regs
- localparam SR_TX_CTRL = 24; // 2 regs
- localparam SR_TIME64 = 28; // 4 regs
+ // 64 total regs in address space
+ localparam SR_RX_CTRL = 0; // 9 regs (+0 to +8)
+ localparam SR_RX_DSP = 16; // 7 regs (+0 to +6)
+ localparam SR_TX_CTRL = 24; // 6 regs (+0 to +5)
+ localparam SR_TX_DSP = 32; // 5 regs (+0 to +4)
+ localparam SR_TIME64 = 40; // 6 regs (+0 to +5)
+ localparam SR_CLEAR_RX_FIFO = 48; // 1 reg
+ localparam SR_CLEAR_TX_FIFO = 49; // 1 reg
+ localparam SR_GLOBAL_RESET = 50; // 1 reg
+ localparam SR_REG_TEST32 = 52; // 1 reg
wire [7:0] COMPAT_NUM = 8'd3;
wire wb_clk = clk_fpga;
- wire wb_rst = rst_fpga;
-
+ wire wb_rst, global_reset;
+
wire pps_int;
wire [63:0] vita_time, vita_time_pps;
reg [15:0] reg_leds, reg_cgen_ctrl, reg_test, xfer_rate;
@@ -51,6 +55,12 @@ module u1e_core
wire [31:0] debug_vt;
+ setting_reg #(.my_addr(SR_GLOBAL_RESET), .width(1)) sr_reset
+ (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(global_reset));
+
+ reset_sync reset_sync(.clk(wb_clk), .reset_in(rst_fpga | global_reset), .reset_out(wb_rst));
+
// /////////////////////////////////////////////////////////////////////////////////////
// GPMC Slave to Wishbone Master
localparam dw = 16;
@@ -72,15 +82,16 @@ module u1e_core
wire [7:0] rate;
wire bus_error;
-
- wire clear_rx_int, clear_tx_int, clear_tx, clear_rx, do_clear;
+ wire clear_tx, clear_rx;
- setting_reg #(.my_addr(SR_CLEAR_FIFO), .width(2)) sr_clear
+ setting_reg #(.my_addr(SR_CLEAR_RX_FIFO), .width(1)) sr_clear_rx
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
- .in(set_data),.out({clear_tx_int,clear_rx_int}),.changed(do_clear));
- assign clear_tx = clear_tx_int & do_clear;
- assign clear_rx = clear_rx_int & do_clear;
-
+ .in(set_data),.out(),.changed(clear_rx));
+
+ setting_reg #(.my_addr(SR_CLEAR_TX_FIFO), .width(1)) sr_clear_tx
+ (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_tx));
+
gpmc_async #(.TXFIFOSIZE(TXFIFOSIZE), .RXFIFOSIZE(RXFIFOSIZE))
gpmc (.arst(wb_rst),
.EM_CLK(EM_CLK), .EM_D(EM_D), .EM_A(EM_A), .EM_NBE(EM_NBE),
@@ -149,7 +160,8 @@ module u1e_core
.src1_rdy_i(rx_src_rdy_int), .dst1_rdy_o(rx_dst_rdy_int),
.src2_rdy_o(rx_src_rdy), .dst2_rdy_i(rx_dst_rdy),
.underrun(), .overrun(rx_overrun));
-
+
+ wire run_tx, run_rx, strobe_tx, strobe_rx;
`endif // `ifdef TIMED
`ifdef DSP
@@ -203,7 +215,9 @@ module u1e_core
wire run_tx;
vita_tx_chain #(.BASE_CTRL(SR_TX_CTRL), .BASE_DSP(SR_TX_DSP),
- .REPORT_ERROR(1), .PROT_ENG_FLAGS(0))
+ .REPORT_ERROR(1), .DO_FLOW_CONTROL(0),
+ .PROT_ENG_FLAGS(0), .USE_TRANS_HEADER(0),
+ .DSP_NUMBER(0))
vita_tx_chain
(.clk(wb_clk), .reset(wb_rst),
.set_stb(set_stb),.set_addr(set_addr),.set_data(set_data),
@@ -258,7 +272,7 @@ module u1e_core
.s2_addr(4'h2), .s2_mask(4'hF), .s3_addr(4'h3), .s3_mask(4'hF),
.s4_addr(4'h4), .s4_mask(4'hF), .s5_addr(4'h5), .s5_mask(4'hF),
.s6_addr(4'h6), .s6_mask(4'hF), .s7_addr(4'h7), .s7_mask(4'hF),
- .s8_addr(4'h8), .s8_mask(4'hF), .s9_addr(4'h9), .s9_mask(4'hF),
+ .s8_addr(4'h8), .s8_mask(4'hE), .s9_addr(4'hf), .s9_mask(4'hF), // slave 8 is double wide
.sa_addr(4'ha), .sa_mask(4'hF), .sb_addr(4'hb), .sb_mask(4'hF),
.sc_addr(4'hc), .sc_mask(4'hF), .sd_addr(4'hd), .sd_mask(4'hF),
.se_addr(4'he), .se_mask(4'hF), .sf_addr(4'hf), .sf_mask(4'hF))
@@ -299,7 +313,7 @@ module u1e_core
.sf_dat_o(sf_dat_mosi),.sf_adr_o(sf_adr),.sf_sel_o(sf_sel),.sf_we_o(sf_we),.sf_cyc_o(sf_cyc),.sf_stb_o(sf_stb),
.sf_dat_i(sf_dat_miso),.sf_ack_i(sf_ack),.sf_err_i(0),.sf_rty_i(0) );
- assign s8_ack = 0; assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0;
+ assign s5_ack = 0; assign s9_ack = 0; assign sa_ack = 0; assign sb_ack = 0;
assign sc_ack = 0; assign sd_ack = 0; assign se_ack = 0; assign sf_ack = 0;
// /////////////////////////////////////////////////////////////////////////////////////
@@ -409,12 +423,12 @@ module u1e_core
.gpio( {io_tx,io_rx} ) );
// /////////////////////////////////////////////////////////////////////////
- // Settings Bus -- Slave #5
+ // Settings Bus -- Slave #8 + 9
- // only have 32 regs, 32 bits each with current setup...
- settings_bus_16LE #(.AWIDTH(11),.RWIDTH(11-4-2)) settings_bus_16LE
- (.wb_clk(wb_clk),.wb_rst(wb_rst),.wb_adr_i(s5_adr),.wb_dat_i(s5_dat_mosi),
- .wb_stb_i(s5_stb),.wb_we_i(s5_we),.wb_ack_o(s5_ack),
+ // only have 64 regs, 32 bits each with current setup...
+ settings_bus_16LE #(.AWIDTH(11),.RWIDTH(6)) settings_bus_16LE
+ (.wb_clk(wb_clk),.wb_rst(wb_rst),.wb_adr_i(s8_adr),.wb_dat_i(s8_dat_mosi),
+ .wb_stb_i(s8_stb),.wb_we_i(s8_we),.wb_ack_o(s8_ack),
.strobe(set_stb),.addr(set_addr),.data(set_data) );
// /////////////////////////////////////////////////////////////////////////
@@ -429,15 +443,24 @@ module u1e_core
// /////////////////////////////////////////////////////////////////////////
// Readback mux 32 -- Slave #7
+ wire [31:0] reg_test32;
+
+ setting_reg #(.my_addr(SR_REG_TEST32)) sr_reg_test32
+ (.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(reg_test32),.changed());
+
wb_readback_mux_16LE readback_mux_32
(.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s7_stb),
.wb_adr_i(s7_adr), .wb_dat_o(s7_dat_miso), .wb_ack_o(s7_ack),
- .word00(vita_time[63:32]), .word01(vita_time[31:0]),
- .word02(vita_time_pps[63:32]),.word03(vita_time_pps[31:0]),
- .word04(32'b0),.word05(32'b0),.word06(32'b0),.word07(32'b0),
- .word08(32'b0),.word09(32'b0),.word10(32'b0),.word11(32'b0),
- .word12(32'b0),.word13(32'b0),.word14(32'b0),.word15(32'b0)
+ .word00(vita_time[63:32]), .word01(vita_time[31:0]),
+ .word02(vita_time_pps[63:32]), .word03(vita_time_pps[31:0]),
+ .word04(reg_test32), .word05(32'b0),
+ .word06(32'b0), .word07(32'b0),
+ .word08(32'b0), .word09(32'b0),
+ .word10(32'b0), .word11(32'b0),
+ .word12(32'b0), .word13(32'b0),
+ .word14(32'b0), .word15(32'b0)
);
// /////////////////////////////////////////////////////////////////////////
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index e64c1031f..6b2ac4e64 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -183,6 +183,8 @@ IF(ENABLE_UTILS)
ADD_SUBDIRECTORY(utils)
ENDIF(ENABLE_UTILS)
+ADD_SUBDIRECTORY(usrp_e_utils)
+
########################################################################
# Print Summary
########################################################################
diff --git a/host/apps/omap_debug/usrp-e-crc-rw.c b/host/apps/omap_debug/usrp-e-crc-rw.c
index c3ae45cc1..c6f3427f0 100644
--- a/host/apps/omap_debug/usrp-e-crc-rw.c
+++ b/host/apps/omap_debug/usrp-e-crc-rw.c
@@ -8,11 +8,19 @@
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
+#include <poll.h>
+#include <sys/mman.h>
#include "usrp_e.h"
// max length #define PKT_DATA_LENGTH 1016
static int packet_data_length;
+struct ring_buffer_info (*rxi)[];
+struct ring_buffer_info (*txi)[];
+__u8 *rx_buf;
+__u8 *tx_buf;
+static struct usrp_e_ring_buffer_size_t rb_size;
+
static int fp;
static u_int32_t crc_tab[256];
@@ -44,8 +52,7 @@ static u_int32_t chksum_crc32_gentab(void)
static void *read_thread(void *threadid)
{
int cnt;
- struct usrp_transfer_frame *rx_data;
- int rx_pkt_cnt;
+ int rx_pkt_cnt, rb_read;
int i;
unsigned long crc;
unsigned int rx_crc;
@@ -53,70 +60,56 @@ static void *read_thread(void *threadid)
struct timeval start_time, finish_time;
__u8 *p;
- __u32 *pi;
printf("Greetings from the reading thread!\n");
// IMPORTANT: must assume max length packet from fpga
- rx_data = malloc(2048);
-
+
rx_pkt_cnt = 0;
+ rb_read = 0;
bytes_transfered = 0;
gettimeofday(&start_time, NULL);
while (1) {
- cnt = read(fp, rx_data, 2048);
- if (cnt < 0)
- printf("Error returned from read: %d\n", cnt);
-
- rx_pkt_cnt++;
-
-#if 0
- if (rx_pkt_cnt == 512) {
- printf(".");
- fflush(stdout);
- rx_pkt_cnt = 0;
+ while (!((*rxi)[rb_read].flags & RB_USER)) {
+ struct pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLIN;
+ ssize_t ret = poll(&pfd, 1, -1);
}
-#endif
+ (*rxi)[rb_read].flags = RB_USER_PROCESS;
- if (rx_data->status & RB_OVERRUN)
- printf("O");
-
- printf("rx_data->len = %d\n", rx_data->len);
+ rx_pkt_cnt++;
+ cnt = (*rxi)[rb_read].len;
+ p = rx_buf + (rb_read * 2048);
-
+ rx_crc = *(int *) &p[cnt-4];
crc = 0xFFFFFFFF;
- for (i = 0; i < rx_data->len - 4; i+=2) {
+ for (i = 0; i < cnt - 4; i+=2) {
crc = ((crc >> 8) & 0x00FFFFFF) ^
- crc_tab[(crc ^ rx_data->buf[i+1]) & 0xFF];
-printf("idx = %d, data = %X, crc = %X\n", i, rx_data->buf[i+1],crc);
+ crc_tab[(crc ^ p[i+1]) & 0xFF];
+//printf("idx = %d, data = %X, crc = %X\n", i, p[i+1],crc);
crc = ((crc >> 8) & 0x00FFFFFF) ^
- crc_tab[(crc ^ rx_data->buf[i]) & 0xFF];
-printf("idx = %d, data = %X, crc = %X\n", i, rx_data->buf[i],crc);
+ crc_tab[(crc ^ p[i]) & 0xFF];
+//printf("idx = %d, data = %X, crc = %X\n", i, p[i],crc);
}
- p = &rx_data->buf[rx_data->len - 4];
- pi = (__u32 *) p;
- rx_crc = *pi;
-
-#if 1
- printf("rx_data->len = %d\n", rx_data->len);
- printf("rx_data->status = %d\n", rx_data->status);
- for (i = 0; i < rx_data->len; i++)
- printf("idx = %d, data = %X\n", i, rx_data->buf[i]);
- printf("calc crc = %lX, rx crc = %X\n", crc, rx_crc);
- fflush(stdout);
- break;
-#endif
+ (*rxi)[rb_read].flags = RB_KERNEL;
+#if 0
if (rx_crc != (crc & 0xFFFFFFFF)) {
printf("CRC Error, calc crc: %X, rx_crc: %X\n",
(crc & 0xFFFFFFFF), rx_crc);
}
+#endif
+
+ rb_read++;
+ if (rb_read == rb_size.num_rx_frames)
+ rb_read = 0;
- bytes_transfered += rx_data->len;
+ bytes_transfered += cnt;
if (bytes_transfered > (100 * 1000000)) {
gettimeofday(&finish_time, NULL);
@@ -124,7 +117,7 @@ printf("idx = %d, data = %X, crc = %X\n", i, rx_data->buf[i],crc);
printf("Bytes transfered = %ld, elapsed seconds = %ld\n", bytes_transfered, elapsed_seconds);
printf("RX data transfer rate = %f K Samples/second\n",
- (float) bytes_transfered / (float) elapsed_seconds / 250);
+ (float) bytes_transfered / (float) elapsed_seconds / 4000);
start_time = finish_time;
@@ -135,17 +128,17 @@ printf("idx = %d, data = %X, crc = %X\n", i, rx_data->buf[i],crc);
static void *write_thread(void *threadid)
{
- int seq_number, i, cnt, tx_pkt_cnt;
+ int i, tx_pkt_cnt, rb_write;
int tx_len;
unsigned long crc;
- struct usrp_transfer_frame *tx_data;
unsigned long bytes_transfered, elapsed_seconds;
struct timeval start_time, finish_time;
+ __u8 *p;
printf("Greetings from the write thread!\n");
+ rb_write = 0;
tx_pkt_cnt = 0;
- tx_data = malloc(2048);
bytes_transfered = 0;
gettimeofday(&start_time, NULL);
@@ -153,6 +146,14 @@ static void *write_thread(void *threadid)
while (1) {
tx_pkt_cnt++;
+ p = tx_buf + (rb_write * 2048);
+
+// printf("p = %p\n", p);
+
+ if (packet_data_length > 0)
+ tx_len = packet_data_length;
+ else
+ tx_len = (random() & 0x1ff) + (2044 - 512);
#if 0
if (tx_pkt_cnt == 512) {
@@ -170,25 +171,33 @@ static void *write_thread(void *threadid)
}
#endif
- tx_len = 2048 - sizeof(struct usrp_transfer_frame) - sizeof(int);
- tx_data->len = tx_len + sizeof(int);
+// printf("Checking for space at rb entry = %d\n", rb_write);
+ while (!((*txi)[rb_write].flags & RB_KERNEL)) {
+ struct pollfd pfd;
+ pfd.fd = fp;
+ pfd.events = POLLOUT;
+ ssize_t ret = poll(&pfd, 1, -1);
+ }
+// printf("Got space\n");
crc = 0xFFFFFFFF;
- for (i = 0; i < tx_len; i++) {
- tx_data->buf[i] = i & 0xFF;
+ for (i = 0; i < tx_len-4; i++) {
+ p[i] = i & 0xFF;
crc = ((crc >> 8) & 0x00FFFFFF) ^
- crc_tab[(crc ^ tx_data->buf[i]) & 0xFF];
+ crc_tab[(crc ^ p[i]) & 0xFF];
}
- *((int *) &tx_data[tx_len]) = crc;
+ *(int *) &p[tx_len-4] = crc;
- cnt = write(fp, tx_data, 2048);
- if (cnt < 0)
- printf("Error returned from write: %d\n", cnt);
+ (*txi)[rb_write].len = tx_len;
+ (*txi)[rb_write].flags = RB_USER;
+ rb_write++;
+ if (rb_write == rb_size.num_tx_frames)
+ rb_write = 0;
- bytes_transfered += tx_data->len;
+ bytes_transfered += tx_len;
if (bytes_transfered > (100 * 1000000)) {
gettimeofday(&finish_time, NULL);
@@ -196,7 +205,7 @@ static void *write_thread(void *threadid)
printf("Bytes transfered = %d, elapsed seconds = %d\n", bytes_transfered, elapsed_seconds);
printf("TX data transfer rate = %f K Samples/second\n",
- (float) bytes_transfered / (float) elapsed_seconds / 250);
+ (float) bytes_transfered / (float) elapsed_seconds / 4000);
start_time = finish_time;
@@ -213,13 +222,16 @@ int main(int argc, char *argv[])
pthread_t tx, rx;
long int t;
int fpga_config_flag ,decimation;
+ int ret, map_size, page_size;
+ void *rb;
+
struct usrp_e_ctl16 d;
struct sched_param s = {
.sched_priority = 1
};
if (argc < 4) {
- printf("%s t|w|rw decimation data_size\n", argv[0]);
+ printf("%s r|w|rw decimation data_size\n", argv[0]);
return -1;
}
@@ -231,6 +243,29 @@ int main(int argc, char *argv[])
fp = open("/dev/usrp_e0", O_RDWR);
printf("fp = %d\n", fp);
+ page_size = getpagesize();
+
+ ret = ioctl(fp, USRP_E_GET_RB_INFO, &rb_size);
+
+ map_size = (rb_size.num_pages_rx_flags + rb_size.num_pages_tx_flags) * page_size +
+ (rb_size.num_rx_frames + rb_size.num_tx_frames) * (page_size >> 1);
+
+ rb = mmap(0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fp, 0);
+ if (rb == MAP_FAILED) {
+ perror("mmap failed");
+ return -1;
+ }
+
+ printf("rb = %X\n", rb);
+
+ rxi = rb;
+ rx_buf = rb + (rb_size.num_pages_rx_flags * page_size);
+ txi = rb + (rb_size.num_pages_rx_flags * page_size) +
+ (rb_size.num_rx_frames * page_size >> 1);
+ tx_buf = rb + (rb_size.num_pages_rx_flags * page_size) +
+ (rb_size.num_rx_frames * page_size >> 1) +
+ (rb_size.num_pages_tx_flags * page_size);
+
fpga_config_flag = 0;
if (strcmp(argv[1], "w") == 0)
fpga_config_flag |= (1 << 15);
diff --git a/host/apps/omap_debug/usrp-e-mm-loopback.c b/host/apps/omap_debug/usrp-e-mm-loopback.c
index f5fc83c87..b67eecd21 100644
--- a/host/apps/omap_debug/usrp-e-mm-loopback.c
+++ b/host/apps/omap_debug/usrp-e-mm-loopback.c
@@ -75,6 +75,8 @@ static void *read_thread(void *threadid)
ssize_t ret = poll(&pfd, 1, -1);
}
+ (*rxi)[rb_read].flags = RB_USER_PROCESS;
+
// printf("pkt received, rb_read = %d\n", rb_read);
cnt = (*rxi)[rb_read].len;
diff --git a/host/apps/omap_debug/usrp_e.h b/host/apps/omap_debug/usrp_e.h
index f96706c4a..4c6a5dd89 100644
--- a/host/apps/omap_debug/usrp_e.h
+++ b/host/apps/omap_debug/usrp_e.h
@@ -34,16 +34,13 @@ struct usrp_e_ctl32 {
#define UE_SPI_TXRX 1
/* Defines for spi ctrl register */
-#define UE_SPI_CTRL_TXNEG (BIT(10))
-#define UE_SPI_CTRL_RXNEG (BIT(9))
+#define UE_SPI_CTRL_TXNEG (1<<10)
+#define UE_SPI_CTRL_RXNEG (1<<9)
#define UE_SPI_PUSH_RISE 0
#define UE_SPI_PUSH_FALL UE_SPI_CTRL_TXNEG
#define UE_SPI_LATCH_RISE 0
#define UE_SPI_LATCH_FALL UE_SPI_CTRL_RXNEG
-#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28)
-
-#define USRP_E_COMPAT_NUMBER 1
struct usrp_e_spi {
__u8 readback;
@@ -68,12 +65,16 @@ struct usrp_e_i2c {
#define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c)
#define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c)
#define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t)
+#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28)
+
+#define USRP_E_COMPAT_NUMBER 1
/* Flag defines */
#define RB_USER (1<<0)
#define RB_KERNEL (1<<1)
#define RB_OVERRUN (1<<2)
#define RB_DMA_ACTIVE (1<<3)
+#define RB_USER_PROCESS (1<<4)
struct ring_buffer_info {
int flags;
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt
index 0c2cadfc2..c04262b63 100644
--- a/host/docs/CMakeLists.txt
+++ b/host/docs/CMakeLists.txt
@@ -29,6 +29,7 @@ SET(manual_sources
transport.rst
usrp1.rst
usrp2.rst
+ usrp_e1xx.rst
)
########################################################################
diff --git a/host/docs/index.rst b/host/docs/index.rst
index 6dac2680c..734300164 100644
--- a/host/docs/index.rst
+++ b/host/docs/index.rst
@@ -24,7 +24,9 @@ Application Notes
* `Device Identification Notes <./identification.html>`_
* `Firmware and FPGA Image Notes <./images.html>`_
* `USRP1 Application Notes <./usrp1.html>`_
-* `USRP2 and N Series Application Notes <./usrp2.html>`_
+* `USRP2 Application Notes <./usrp2.html>`_
+* `USRP-N2XX Series Application Notes <./usrp2.html>`_
+* `USRP-E1XX Series Application Notes <./usrp_e1xx.html>`_
* `Daughterboard Application Notes <./dboards.html>`_
* `Transport Application Notes <./transport.html>`_
diff --git a/host/docs/usrp_e1xx.rst b/host/docs/usrp_e1xx.rst
new file mode 100644
index 000000000..ffcd370dd
--- /dev/null
+++ b/host/docs/usrp_e1xx.rst
@@ -0,0 +1,65 @@
+========================================================================
+UHD - USRP-E1XX Series Application Notes
+========================================================================
+
+.. contents:: Table of Contents
+
+------------------------------------------------------------------------
+Specify a non-standard image
+------------------------------------------------------------------------
+The UHD will automatically select the USRP embedded FPGA image from the installed images package.
+The FPGA image selection can be overridden with the "fpga" device address parameter.
+
+Example device address string representations to specify non-standard FPGA image:
+
+::
+
+ fpga=usrp_e100_custom.bin
+
+------------------------------------------------------------------------
+Changing the master clock rate
+------------------------------------------------------------------------
+The master clock rate of the USRP embedded feeds both the FPGA DSP and the codec chip.
+UHD can dynamically reconfigure the clock rate though the set_master_clock_rate() API call.
+Hundreds of rates between 32MHz and 64MHz are available.
+A few notable rates are:
+
+* 64MHz - maximum rate of the codec chip
+* 61.44MHz - good for UMTS/WCDMA applications
+* 52Mhz - good for GSM applications
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set 61.44MHz - uses external VCXO
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To use the 61.44MHz clock rate, the USRP embedded will require two jumpers to be moved.
+
+* J16 is a two pin header, remove the jumper (or leave it on pin1 only)
+* J15 is a three pin header, move the jumper to (pin1, pin2)
+
+For the correct clock settings, call usrp->set_master_clock_rate(61.44e6)
+before any other parameters are set in your application.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Set other rates - uses internal VCO
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To use other clock rates, the jumpers will need to be in the default position.
+
+* J16 is a two pin header, move the jumper to (pin1, pin2)
+* J15 is a three pin header, move the jumper to (pin2, pin3)
+
+For the correct clock settings, call usrp->set_master_clock_rate(rate)
+before any other parameters are set in your application.
+
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Clock rate recovery - unbricking
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+It is possible to set a clock rate such that the UHD can no longer communicate with the FPGA.
+When this occurs, it is necessary to use the usrp-e-utility to recover the clock generator.
+The recovery utility works by loading a special pass-through FPGA image so the computer
+can talk directly to the clock generator over a SPI interface.
+
+Run the following commands to restore the clock generator to a usable state:
+::
+
+ cd <prefix>/share/uhd/usrp_e_utilities
+ ./usrp-e-utility --fpga=../images/usrp_e100_pt_fpga.bin --reclk
diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp
index 9ebe36c5a..630b4a7a9 100644
--- a/host/examples/rx_timed_samples.cpp
+++ b/host/examples/rx_timed_samples.cpp
@@ -32,7 +32,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
double seconds_in_future;
size_t total_num_samps;
- double rate, freq;
+ double rate, freq, clock;
//setup the program options
po::options_description desc("Allowed options");
@@ -41,6 +41,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("args", po::value<std::string>(&args)->default_value(""), "single uhd device address args")
("secs", po::value<double>(&seconds_in_future)->default_value(3), "number of seconds in the future to receive")
("nsamps", po::value<size_t>(&total_num_samps)->default_value(1000), "total number of samples to receive")
+ ("clock", po::value<double>(&clock), "master clock frequency in Hz")
("rate", po::value<double>(&rate)->default_value(100e6/16), "rate of incoming samples")
("freq", po::value<double>(&freq)->default_value(0), "rf center frequency in Hz")
("dilv", "specify to disable inner-loop verbose")
@@ -63,6 +64,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
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;
+ //optionally set the clock rate (do before setting anything else)
+ if (vm.count("clock")){
+ std::cout << boost::format("Setting master clock rate: %f MHz...") % (clock/1e6) << std::endl;
+ usrp->set_master_clock_rate(clock);
+ }
+
//set the rx sample rate
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rate/1e6) << std::endl;
usrp->set_rx_rate(rate);
diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py
index a5debe568..86605c34a 100755
--- a/host/lib/ic_reg_maps/gen_ad9522_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py
@@ -80,6 +80,14 @@ external_zero_delay_fcds 0x01E[4:3] 0
enable_external_zero_delay 0x01E[2] 0
enable_zero_delay 0x01E[1] 0
########################################################################
+vco_calibration_finished 0x01F[6] 0
+holdover_active 0x01F[5] 0
+ref2_selected 0x01F[4] 0
+vco_freq_gt_thresh 0x01F[3] 0
+ref2_freq_gt_thresh 0x01F[2] 0
+ref1_freq_gt_thresh 0x01F[1] 0
+digital_lock_detect 0x01F[0] 0
+########################################################################
#for $i in range(12)
#set $addr = ($i + 0x0F0)
out$(i)_format $(addr)[7] 0 lvds, cmos
diff --git a/host/lib/usrp/usrp_e100/CMakeLists.txt b/host/lib/usrp/usrp_e100/CMakeLists.txt
index c32dd87f8..acbac177e 100644
--- a/host/lib/usrp/usrp_e100/CMakeLists.txt
+++ b/host/lib/usrp/usrp_e100/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -40,7 +40,7 @@ IF(ENABLE_USRP_E100)
${CMAKE_CURRENT_SOURCE_DIR}/dboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/dsp_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/fpga-downloader.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/usrp_e100_impl.cpp
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp
index 1fb1a7125..e29fe18ce 100644
--- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp_e100/clock_ctrl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -22,11 +22,26 @@
#include "usrp_e100_regs.hpp" //spi slave constants
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/math/common_factor_rt.hpp> //gcd
+#include <algorithm>
#include <utility>
#include <iostream>
using namespace uhd;
+/***********************************************************************
+ * Constants
+ **********************************************************************/
+static const bool CLOCK_SETTINGS_DEBUG = false;
+static const bool ENABLE_THE_TEST_OUT = true;
+static const double REFERENCE_INPUT_RATE = 10e6;
+static const double DEFAULT_OUTPUT_RATE = 64e6;
+
+/***********************************************************************
+ * Helpers
+ **********************************************************************/
template <typename div_type, typename bypass_type> static void set_clock_divider(
size_t divider, div_type &low, div_type &high, bypass_type &bypass
){
@@ -36,24 +51,117 @@ template <typename div_type, typename bypass_type> static void set_clock_divider
}
/***********************************************************************
- * Constants
+ * Clock rate calculation stuff:
+ * Using the internal VCO between 1400 and 1800 MHz
**********************************************************************/
-static const bool enable_test_clock = false;
-static const size_t ref_clock_doubler = 2; //enabled below
-static const double ref_clock_rate = 10e6 * ref_clock_doubler;
+struct clock_settings_type{
+ size_t ref_clock_doubler, r_counter, a_counter, b_counter, prescaler, vco_divider, chan_divider;
+ size_t get_n_counter(void) const{return prescaler * b_counter + a_counter;}
+ double get_ref_rate(void) const{return REFERENCE_INPUT_RATE * ref_clock_doubler;}
+ double get_vco_rate(void) const{return get_ref_rate()/r_counter * get_n_counter();}
+ double get_chan_rate(void) const{return get_vco_rate()/vco_divider;}
+ double get_out_rate(void) const{return get_chan_rate()/chan_divider;}
+ std::string to_pp_string(void) const{
+ return str(boost::format(
+ " r_counter: %d\n"
+ " a_counter: %d\n"
+ " b_counter: %d\n"
+ " prescaler: %d\n"
+ " vco_divider: %d\n"
+ " chan_divider: %d\n"
+ " vco_rate: %fMHz\n"
+ " chan_rate: %fMHz\n"
+ " out_rate: %fMHz\n"
+ )
+ % r_counter
+ % a_counter
+ % b_counter
+ % prescaler
+ % vco_divider
+ % chan_divider
+ % (get_vco_rate()/1e6)
+ % (get_chan_rate()/1e6)
+ % (get_out_rate()/1e6)
+ );
+ }
+};
+
+//! gives the greatest divisor of num between 1 and max inclusive
+template<typename T> static inline T greatest_divisor(T num, T max){
+ for (T i = max; i > 1; i--) if (num%i == 0) return i; return 1;
+}
+
+//! gives the least divisor of num between min and num exclusive
+template<typename T> static inline T least_divisor(T num, T min){
+ for (T i = min; i < num; i++) if (num%i == 0) return i; return 1;
+}
+
+static clock_settings_type get_clock_settings(double rate){
+ clock_settings_type cs;
+ cs.ref_clock_doubler = 2; //always doubling
+ cs.prescaler = 8; //set to 8 when input is under 2400 MHz
-static const size_t r_counter = 1;
-static const size_t a_counter = 0;
-static const size_t b_counter = 20 / ref_clock_doubler;
-static const size_t prescaler = 8; //set below with enum, set to 8 when input is under 2400 MHz
-static const size_t vco_divider = 5; //set below with enum
+ //basic formulas used below:
+ //out_rate*X = ref_rate*Y
+ //X = i*ref_rate/gcd
+ //Y = i*out_rate/gcd
+ //X = chan_div * vco_div * R
+ //Y = P*B + A
-static const size_t n_counter = prescaler * b_counter + a_counter;
-static const size_t vco_clock_rate = ref_clock_rate/r_counter * n_counter; //between 1400 and 1800 MHz
-static const double master_clock_rate = vco_clock_rate/vco_divider;
+ const boost::uint64_t out_rate = boost::uint64_t(rate);
+ const boost::uint64_t ref_rate = boost::uint64_t(cs.get_ref_rate());
+ const size_t gcd = size_t(boost::math::gcd(ref_rate, out_rate));
-static const size_t fpga_clock_divider = size_t(master_clock_rate/64e6);
-static const size_t codec_clock_divider = size_t(master_clock_rate/64e6);
+ for (size_t i = 1; i <= 100; i++){
+ const size_t X = i*ref_rate/gcd;
+ const size_t Y = i*out_rate/gcd;
+
+ //determine A and B (P is fixed)
+ cs.b_counter = Y/cs.prescaler;
+ cs.a_counter = Y - cs.b_counter*cs.prescaler;
+
+ static const double vco_bound_pad = 100e6;
+ for ( //calculate an r divider that fits into the bounds of the vco
+ cs.r_counter = size_t(cs.get_n_counter()*cs.get_ref_rate()/(1800e6 - vco_bound_pad));
+ cs.r_counter <= size_t(cs.get_n_counter()*cs.get_ref_rate()/(1400e6 + vco_bound_pad))
+ and cs.r_counter > 0; cs.r_counter++
+ ){
+
+ //determine chan_div and vco_div
+ //and fill in that order of preference
+ cs.chan_divider = greatest_divisor<size_t>(X/cs.r_counter, 32);
+ cs.vco_divider = greatest_divisor<size_t>(X/cs.chan_divider/cs.r_counter, 6);
+
+ //avoid a vco divider of 1 (if possible)
+ if (cs.vco_divider == 1){
+ cs.vco_divider = least_divisor<size_t>(cs.chan_divider, 2);
+ cs.chan_divider /= cs.vco_divider;
+ }
+
+ if (CLOCK_SETTINGS_DEBUG){
+ std::cout << "gcd " << gcd << std::endl;
+ std::cout << "X " << X << std::endl;
+ std::cout << "Y " << Y << std::endl;
+ std::cout << cs.to_pp_string() << std::endl;
+ }
+
+ //filter limits on the counters
+ if (cs.vco_divider == 1) continue;
+ if (cs.r_counter >= (1<<14)) continue;
+ if (cs.b_counter == 2) continue;
+ if (cs.b_counter == 1 and cs.a_counter != 0) continue;
+ if (cs.b_counter >= (1<<13)) continue;
+ if (cs.a_counter >= (1<<6)) continue;
+
+ std::cout << "USRP-E100 clock control: " << i << std::endl << cs.to_pp_string() << std::endl;
+ return cs;
+ }
+ }
+
+ throw std::runtime_error(str(boost::format(
+ "USRP-E100 clock control: could not calculate settings for clock rate %fMHz"
+ ) % (rate/1e6)));
+}
/***********************************************************************
* Clock Control Implementation
@@ -62,35 +170,70 @@ class usrp_e100_clock_ctrl_impl : public usrp_e100_clock_ctrl{
public:
usrp_e100_clock_ctrl_impl(usrp_e100_iface::sptr iface){
_iface = iface;
+ _chan_rate = 0.0;
+ _out_rate = 0.0;
//init the clock gen registers
//Note: out0 should already be clocking the FPGA or this isnt going to work
_ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO;
- _ad9522_regs.enable_clock_doubler = 1; //enable ref clock doubler
_ad9522_regs.enb_stat_eeprom_at_stat_pin = 0; //use status pin
_ad9522_regs.status_pin_control = 0x1; //n divider
_ad9522_regs.ld_pin_control = 0x00; //dld
_ad9522_regs.refmon_pin_control = 0x12; //show ref2
+ _ad9522_regs.lock_detect_counter = ad9522_regs_t::LOCK_DETECT_COUNTER_16CYC;
- _ad9522_regs.enable_ref2 = 1;
- _ad9522_regs.enable_ref1 = 0;
- _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2;
+ this->use_internal_ref();
+
+ this->set_fpga_clock_rate(DEFAULT_OUTPUT_RATE); //initialize to something
+
+ this->enable_test_clock(ENABLE_THE_TEST_OUT);
+ this->enable_rx_dboard_clock(false);
+ this->enable_tx_dboard_clock(false);
+ }
+
+ ~usrp_e100_clock_ctrl_impl(void){
+ this->enable_test_clock(ENABLE_THE_TEST_OUT);
+ this->enable_rx_dboard_clock(false);
+ this->enable_tx_dboard_clock(false);
+ }
+
+ /***********************************************************************
+ * Clock rate control:
+ * - set clock rate w/ internal VCO
+ * - set clock rate w/ external VCXO
+ **********************************************************************/
+ void set_clock_settings_with_internal_vco(double rate){
+ const clock_settings_type cs = get_clock_settings(rate);
+
+ //set the rates to private variables so the implementation knows!
+ _chan_rate = cs.get_chan_rate();
+ _out_rate = cs.get_out_rate();
- _ad9522_regs.set_r_counter(r_counter);
- _ad9522_regs.a_counter = a_counter;
- _ad9522_regs.set_b_counter(b_counter);
+ _ad9522_regs.enable_clock_doubler = (cs.ref_clock_doubler == 2)? 1 : 0;
+
+ _ad9522_regs.set_r_counter(cs.r_counter);
+ _ad9522_regs.a_counter = cs.a_counter;
+ _ad9522_regs.set_b_counter(cs.b_counter);
+ UHD_ASSERT_THROW(cs.prescaler == 8); //assumes this below:
_ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV8_9;
_ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL;
_ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA;
- _ad9522_regs.vco_calibration_now = 1; //calibrate it!
- _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5;
+ _ad9522_regs.bypass_vco_divider = 0;
+ switch(cs.vco_divider){
+ case 1: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV1; break;
+ case 2: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV2; break;
+ case 3: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV3; break;
+ case 4: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV4; break;
+ case 5: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; break;
+ case 6: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV6; break;
+ }
_ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO;
//setup fpga master clock
_ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS;
- set_clock_divider(fpga_clock_divider,
+ set_clock_divider(cs.chan_divider,
_ad9522_regs.divider0_low_cycles,
_ad9522_regs.divider0_high_cycles,
_ad9522_regs.divider0_bypass
@@ -98,52 +241,69 @@ public:
//setup codec clock
_ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS;
- set_clock_divider(codec_clock_divider,
+ set_clock_divider(cs.chan_divider,
_ad9522_regs.divider1_low_cycles,
_ad9522_regs.divider1_high_cycles,
_ad9522_regs.divider1_bypass
);
- //setup test clock (same divider as codec clock)
- _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS;
- _ad9522_regs.out4_cmos_configuration = (enable_test_clock)?
- ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON :
- ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF;
+ this->send_all_regs();
+ calibrate_now();
+ }
- //setup a list of register ranges to write
- typedef std::pair<boost::uint16_t, boost::uint16_t> range_t;
- static const std::vector<range_t> ranges = boost::assign::list_of
- (range_t(0x000, 0x000)) (range_t(0x010, 0x01F))
- (range_t(0x0F0, 0x0FD)) (range_t(0x190, 0x19B))
- (range_t(0x1E0, 0x1E1)) (range_t(0x230, 0x230))
- ;
+ void set_clock_settings_with_external_vcxo(double rate){
+ //set the rates to private variables so the implementation knows!
+ _chan_rate = rate;
+ _out_rate = rate;
- //write initial register values and latch/update
- BOOST_FOREACH(const range_t &range, ranges){
- for(boost::uint16_t addr = range.first; addr <= range.second; addr++){
- this->send_reg(addr);
- }
- }
- this->latch_regs();
- //test read:
- //boost::uint32_t reg = _ad9522_regs.get_read_reg(0x01b);
- //boost::uint32_t result = _iface->transact_spi(
- // UE_SPI_SS_AD9522,
- // spi_config_t::EDGE_RISE,
- // reg, 24, true /*no*/
- //);
- //std::cout << "result " << std::hex << result << std::endl;
- this->enable_rx_dboard_clock(false);
- this->enable_tx_dboard_clock(false);
+ _ad9522_regs.enable_clock_doubler = 1; //doubler always on
+ const double ref_rate = REFERENCE_INPUT_RATE*2;
+
+ //bypass prescaler such that N = B
+ long gcd = boost::math::gcd(long(ref_rate), long(rate));
+ _ad9522_regs.set_r_counter(int(ref_rate/gcd));
+ _ad9522_regs.a_counter = 0;
+ _ad9522_regs.set_b_counter(int(rate/gcd));
+ _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV1;
+
+ //setup external vcxo
+ _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL;
+ _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA;
+ _ad9522_regs.bypass_vco_divider = 1;
+ _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_EXTERNAL;
+
+ //setup fpga master clock
+ _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS;
+ _ad9522_regs.divider0_bypass = 1;
+
+ //setup codec clock
+ _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS;
+ _ad9522_regs.divider1_bypass = 1;
+
+ this->send_all_regs();
}
- ~usrp_e100_clock_ctrl_impl(void){
- this->enable_rx_dboard_clock(false);
- this->enable_tx_dboard_clock(false);
+ void set_fpga_clock_rate(double rate){
+ if (_out_rate == rate) return;
+ if (rate == 61.44e6) set_clock_settings_with_external_vcxo(rate);
+ else set_clock_settings_with_internal_vco(rate);
}
double get_fpga_clock_rate(void){
- return master_clock_rate/fpga_clock_divider;
+ return this->_out_rate;
+ }
+
+ /***********************************************************************
+ * Special test clock output
+ **********************************************************************/
+ void enable_test_clock(bool enb){
+ //setup test clock (same divider as codec clock)
+ _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS;
+ _ad9522_regs.out4_cmos_configuration = (enb)?
+ ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON :
+ ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF;
+ this->send_reg(0x0F0);
+ this->latch_regs();
}
/***********************************************************************
@@ -161,13 +321,13 @@ public:
std::vector<double> get_rx_dboard_clock_rates(void){
std::vector<double> rates;
for(size_t div = 1; div <= 16+16; div++)
- rates.push_back(master_clock_rate/div);
+ rates.push_back(this->_chan_rate/div);
return rates;
}
void set_rx_dboard_clock_rate(double rate){
assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate");
- size_t divider = size_t(master_clock_rate/rate);
+ size_t divider = size_t(this->_chan_rate/rate);
//set the divider registers
set_clock_divider(divider,
_ad9522_regs.divider3_low_cycles,
@@ -197,7 +357,7 @@ public:
void set_tx_dboard_clock_rate(double rate){
assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate");
- size_t divider = size_t(master_clock_rate/rate);
+ size_t divider = size_t(this->_chan_rate/rate);
//set the divider registers
set_clock_divider(divider,
_ad9522_regs.divider2_low_cycles,
@@ -238,6 +398,8 @@ public:
private:
usrp_e100_iface::sptr _iface;
ad9522_regs_t _ad9522_regs;
+ double _out_rate; //rate at the fpga and codec
+ double _chan_rate; //rate before final dividers
void latch_regs(void){
_ad9522_regs.io_update = 1;
@@ -253,6 +415,46 @@ private:
reg, 24, false /*no rb*/
);
}
+
+ void calibrate_now(void){
+ //vco calibration routine:
+ _ad9522_regs.vco_calibration_now = 0;
+ this->send_reg(0x18);
+ this->latch_regs();
+ _ad9522_regs.vco_calibration_now = 1;
+ this->send_reg(0x18);
+ this->latch_regs();
+ //wait for calibration done:
+ static const boost::uint8_t addr = 0x01F;
+ for (size_t ms10 = 0; ms10 < 100; ms10++){
+ boost::uint32_t reg = _iface->transact_spi(
+ UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE,
+ _ad9522_regs.get_read_reg(addr), 24, true /*rb*/
+ );
+ _ad9522_regs.set_reg(addr, reg);
+ if (_ad9522_regs.vco_calibration_finished) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+ }
+ std::cerr << "USRP-E100 clock control: VCO calibration timeout" << std::endl;
+ }
+
+ void send_all_regs(void){
+ //setup a list of register ranges to write
+ typedef std::pair<boost::uint16_t, boost::uint16_t> range_t;
+ static const std::vector<range_t> ranges = boost::assign::list_of
+ (range_t(0x000, 0x000)) (range_t(0x010, 0x01F))
+ (range_t(0x0F0, 0x0FD)) (range_t(0x190, 0x19B))
+ (range_t(0x1E0, 0x1E1)) (range_t(0x230, 0x230))
+ ;
+
+ //write initial register values and latch/update
+ BOOST_FOREACH(const range_t &range, ranges){
+ for(boost::uint16_t addr = range.first; addr <= range.second; addr++){
+ this->send_reg(addr);
+ }
+ }
+ this->latch_regs();
+ }
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/usrp_e100/clock_ctrl.hpp
index d613d1473..1f9960ce4 100644
--- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp
+++ b/host/lib/usrp/usrp_e100/clock_ctrl.hpp
@@ -40,6 +40,13 @@ public:
static sptr make(usrp_e100_iface::sptr iface);
/*!
+ * Set the rate of the fpga clock line.
+ * Throws if rate is not valid.
+ * \param rate the new rate in Hz
+ */
+ virtual void set_fpga_clock_rate(double rate) = 0;
+
+ /*!
* Get the rate of the fpga clock line.
* \return the fpga clock rate in Hz
*/
diff --git a/host/lib/usrp/usrp_e100/fpga-downloader.cc b/host/lib/usrp/usrp_e100/fpga_downloader.cpp
index 4a3d3b9af..c0013fcbd 100644
--- a/host/lib/usrp/usrp_e100/fpga-downloader.cc
+++ b/host/lib/usrp/usrp_e100/fpga_downloader.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -43,6 +43,8 @@
*
*/
+namespace usrp_e_fpga_downloader_utility{
+
const unsigned int PROG_B = 175;
const unsigned int DONE = 173;
const unsigned int INIT_B = 114;
@@ -209,11 +211,10 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d
{
std::ifstream bitstream;
- std::cout << "File name - " << file_name.c_str() << std::endl;
-
bitstream.open(file_name.c_str(), std::ios::binary);
- if (!bitstream.is_open())
- std::cout << "File " << file_name << " not opened succesfully." << std::endl;
+ if (!bitstream.is_open()) throw std::runtime_error(
+ "Coult not open the file: " + file_name
+ );
spidev spi("/dev/spidev1.0");
char buf[BUF_SIZE];
@@ -232,35 +233,20 @@ static void send_file_to_fpga(const std::string &file_name, gpio &error, gpio &d
} while (bitstream.gcount() == BUF_SIZE);
}
-/*
-int main(int argc, char *argv[])
-{
-
- gpio gpio_prog_b(PROG_B, OUT);
- gpio gpio_init_b(INIT_B, IN);
- gpio gpio_done (DONE, IN);
-
- if (argc == 2)
- bit_file = argv[1];
-
- std::cout << "FPGA config file: " << bit_file << std::endl;
-
- prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
-
- std::cout << "Done = " << gpio_done.get_value() << std::endl;
-
- send_file_to_fpga(bit_file, gpio_init_b, gpio_done);
-}
-*/
+}//namespace usrp_e_fpga_downloader_utility
void usrp_e100_load_fpga(const std::string &bin_file){
+ using namespace usrp_e_fpga_downloader_utility;
+
gpio gpio_prog_b(PROG_B, OUT);
gpio gpio_init_b(INIT_B, IN);
gpio gpio_done (DONE, IN);
std::cout << "Loading FPGA image: " << bin_file << "... " << std::flush;
- UHD_ASSERT_THROW(std::system("/sbin/rmmod usrp_e") == 0);
+ if(std::system("/sbin/rmmod usrp_e") != 0){
+ std::cerr << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl;
+ }
prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
@@ -268,7 +254,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){
send_file_to_fpga(bin_file, gpio_init_b, gpio_done);
- UHD_ASSERT_THROW(std::system("/sbin/modprobe usrp_e") == 0);
+ if(std::system("/sbin/modprobe usrp_e") != 0){
+ std::cerr << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl;
+ }
}
diff --git a/host/lib/usrp/usrp_e100/io_impl.cpp b/host/lib/usrp/usrp_e100/io_impl.cpp
index cf2410e4f..5fb2da7b8 100644
--- a/host/lib/usrp/usrp_e100/io_impl.cpp
+++ b/host/lib/usrp/usrp_e100/io_impl.cpp
@@ -35,7 +35,8 @@ zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);
/***********************************************************************
* Constants
**********************************************************************/
-static const size_t tx_async_report_sid = 1;
+static const size_t rx_data_inline_sid = 1;
+static const size_t tx_async_report_sid = 2;
static const int underflow_flags = async_metadata_t::EVENT_CODE_UNDERFLOW | async_metadata_t::EVENT_CODE_UNDERFLOW_IN_PACKET;
static const bool recv_debug = false;
@@ -109,8 +110,17 @@ void usrp_e100_impl::io_impl::recv_pirate_loop(usrp_e100_clock_ctrl::sptr clock_
const boost::uint32_t *vrt_hdr = buff->cast<const boost::uint32_t *>();
vrt::if_hdr_unpack_le(vrt_hdr, if_packet_info);
+ //handle an rx data packet or inline message
+ if (if_packet_info.sid == rx_data_inline_sid){
+ if (recv_debug) std::cout << "this is rx_data_inline_sid\n";
+ //same number of frames as the data transport -> always immediate
+ recv_pirate_booty.push_with_wait(buff);
+ continue;
+ }
+
//handle a tx async report message
if (if_packet_info.sid == tx_async_report_sid and if_packet_info.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){
+ if (recv_debug) std::cout << "this is tx_async_report_sid\n";
//fill in the async metadata
async_metadata_t metadata;
@@ -127,8 +137,7 @@ void usrp_e100_impl::io_impl::recv_pirate_loop(usrp_e100_clock_ctrl::sptr clock_
continue;
}
- //same number of frames as the data transport -> always immediate
- recv_pirate_booty.push_with_wait(buff);
+ if (recv_debug) std::cout << "this is unknown packet\n";
}catch(const std::exception &e){
std::cerr << "Error (usrp-e recv pirate loop): " << e.what() << std::endl;
@@ -152,17 +161,20 @@ void usrp_e100_impl::io_init(void){
//setup before the registers (transport called to calculate max spp)
_io_impl = UHD_PIMPL_MAKE(io_impl, (_iface));
+ //clear state machines
+ _iface->poke32(UE_REG_CTRL_RX_CLEAR, 0);
+ _iface->poke32(UE_REG_CTRL_TX_CLEAR, 0);
+
//setup rx data path
_iface->poke32(UE_REG_CTRL_RX_NSAMPS_PER_PKT, get_max_recv_samps_per_packet());
_iface->poke32(UE_REG_CTRL_RX_NCHANNELS, 1);
- _iface->poke32(UE_REG_CTRL_RX_CLEAR_OVERRUN, 1); //reset
_iface->poke32(UE_REG_CTRL_RX_VRT_HEADER, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
| (0x3 << 22) //integer time other
| (0x1 << 20) //fractional time sample count
);
- _iface->poke32(UE_REG_CTRL_RX_VRT_STREAM_ID, 0);
+ _iface->poke32(UE_REG_CTRL_RX_VRT_STREAM_ID, rx_data_inline_sid);
_iface->poke32(UE_REG_CTRL_RX_VRT_TRAILER, 0);
//setup the tx policy
@@ -184,7 +196,6 @@ void usrp_e100_impl::issue_stream_cmd(const stream_cmd_t &stream_cmd){
void usrp_e100_impl::handle_overrun(size_t){
std::cerr << "O"; //the famous OOOOOOOOOOO
- _iface->poke32(UE_REG_CTRL_RX_CLEAR_OVERRUN, 0);
if (_io_impl->continuous_streaming){
this->issue_stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
}
diff --git a/host/lib/usrp/usrp_e100/mboard_impl.cpp b/host/lib/usrp/usrp_e100/mboard_impl.cpp
index f52d2e6fb..0e08cd435 100644
--- a/host/lib/usrp/usrp_e100/mboard_impl.cpp
+++ b/host/lib/usrp/usrp_e100/mboard_impl.cpp
@@ -152,6 +152,10 @@ void usrp_e100_impl::mboard_get(const wax::obj &key_, wax::obj &val){
return;
}
+ case MBOARD_PROP_CLOCK_RATE:
+ val = _clock_ctrl->get_fpga_clock_rate();
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -211,6 +215,10 @@ void usrp_e100_impl::mboard_set(const wax::obj &key, const wax::obj &val){
update_clock_config();
return;
+ case MBOARD_PROP_CLOCK_RATE:
+ _clock_ctrl->set_fpga_clock_rate(val.as<double>());
+ return;
+
default: UHD_THROW_PROP_SET_ERROR();
}
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
index 40c7afabb..ad36dd97a 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010-2011 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
//
#include "usrp_e100_iface.hpp"
+#include "usrp_e100_regs.hpp"
#include <uhd/utils/assert.hpp>
#include <sys/ioctl.h> //ioctl
#include <fcntl.h> //open, close
@@ -108,6 +109,9 @@ public:
throw std::runtime_error("Failed to open " + node);
}
+ //very first thing, reset all the wishbone, always do first!
+ this->poke32(UE_REG_CLEAR_GLOBAL, 0);
+
mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
index 2dc401305..897616320 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
@@ -30,7 +30,7 @@
#ifndef INCLUDED_USRP_E100_IMPL_HPP
#define INCLUDED_USRP_E100_IMPL_HPP
-static const boost::uint16_t USRP_E_COMPAT_NUM = 0x02; //make this 3 then the mainline fpga image gets fixed for embedded
+static const boost::uint16_t USRP_E_COMPAT_NUM = 0x03;
//! load an fpga image from a bin file into the usrp-e fpga
extern void usrp_e100_load_fpga(const std::string &bin_file);
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
index a57fe5171..a030462d0 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_regs.hpp
@@ -17,7 +17,6 @@
// Slave pointers
#define UE_REG_SLAVE(n) ((n)<<7)
-#define UE_REG_SR_ADDR(n) ((UE_REG_SLAVE(5)) + (4*(n)))
/////////////////////////////////////////////////////
// Slave 0 -- Misc Regs
@@ -89,16 +88,6 @@
#define GPIO_SEL_DEBUG_0 0 // if pin is an output, debug lines from FPGA fabric
#define GPIO_SEL_DEBUG_1 1 // if pin is an output, debug lines from FPGA fabric
-
-////////////////////////////////////////////////////
-// Slave 5 -- Settings Bus
-//
-// Output-only, no readback, 32 registers total
-// Each register must be written 32 bits at a time
-// First the address xxx_xx00 and then xxx_xx10
-
-#define UE_REG_SETTINGS_BASE UE_REG_SLAVE(5)
-
///////////////////////////////////////////////////
// Slave 6 -- ATR Controller
// 16 regs
@@ -123,48 +112,72 @@
#define UE_REG_RB_TIME_NOW_TICKS UE_REG_RB_MUX_32_BASE + 4
#define UE_REG_RB_TIME_PPS_SECS UE_REG_RB_MUX_32_BASE + 8
#define UE_REG_RB_TIME_PPS_TICKS UE_REG_RB_MUX_32_BASE + 12
+#define UE_REG_RB_MISC_TEST32 UE_REG_RB_MUX_32_BASE + 16
+
+////////////////////////////////////////////////////
+// Slave 8 -- Settings Bus
+//
+// Output-only, no readback, 64 registers total
+// Each register must be written 64 bits at a time
+// First the address xxx_xx00 and then xxx_xx10
+
+#define UE_REG_SETTINGS_BASE_ADDR(n) (UE_REG_SLAVE(8) + (4*(n)))
+
+#define UE_REG_SR_MISC_TEST32 UE_REG_SETTINGS_BASE_ADDR(52)
+
+/////////////////////////////////////////////////
+// Magic reset regs
+////////////////////////////////////////////////
+#define UE_REG_CLEAR_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(48) + (4*(n)))
+#define UE_REG_CLEAR_RX UE_REG_CLEAR_ADDR(0)
+#define UE_REG_CLEAR_TX UE_REG_CLEAR_ADDR(1)
+#define UE_REG_CLEAR_GLOBAL UE_REG_CLEAR_ADDR(2)
/////////////////////////////////////////////////
// DSP RX Regs
////////////////////////////////////////////////
-#define UE_REG_DSP_RX_FREQ UE_REG_SR_ADDR(0)
-#define UE_REG_DSP_RX_SCALE_IQ UE_REG_SR_ADDR(1) // {scale_i,scale_q}
-#define UE_REG_DSP_RX_DECIM_RATE UE_REG_SR_ADDR(2) // hb and decim rate
-#define UE_REG_DSP_RX_DCOFFSET_I UE_REG_SR_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic
-#define UE_REG_DSP_RX_DCOFFSET_Q UE_REG_SR_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits
-#define UE_REG_DSP_RX_MUX UE_REG_SR_ADDR(5)
+#define UE_REG_DSP_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(16) + (4*(n)))
+#define UE_REG_DSP_RX_FREQ UE_REG_DSP_RX_ADDR(0)
+#define UE_REG_DSP_RX_SCALE_IQ UE_REG_DSP_RX_ADDR(1) // {scale_i,scale_q}
+#define UE_REG_DSP_RX_DECIM_RATE UE_REG_DSP_RX_ADDR(2) // hb and decim rate
+#define UE_REG_DSP_RX_DCOFFSET_I UE_REG_DSP_RX_ADDR(3) // Bit 31 high sets fixed offset mode, using lower 14 bits, // otherwise it is automatic
+#define UE_REG_DSP_RX_DCOFFSET_Q UE_REG_DSP_RX_ADDR(4) // Bit 31 high sets fixed offset mode, using lower 14 bits
+#define UE_REG_DSP_RX_MUX UE_REG_DSP_RX_ADDR(5)
///////////////////////////////////////////////////
// VITA RX CTRL regs
///////////////////////////////////////////////////
+#define UE_REG_CTRL_RX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(0) + (4*(n)))
// The following 3 are logically a single command register.
// They are clocked into the underlying fifo when time_ticks is written.
-#define UE_REG_CTRL_RX_STREAM_CMD UE_REG_SR_ADDR(8) // {now, chain, num_samples(30)
-#define UE_REG_CTRL_RX_TIME_SECS UE_REG_SR_ADDR(9)
-#define UE_REG_CTRL_RX_TIME_TICKS UE_REG_SR_ADDR(10)
-#define UE_REG_CTRL_RX_CLEAR_OVERRUN UE_REG_SR_ADDR(11) // write anything to clear overrun
-#define UE_REG_CTRL_RX_VRT_HEADER UE_REG_SR_ADDR(12) // word 0 of packet. FPGA fills in packet counter
-#define UE_REG_CTRL_RX_VRT_STREAM_ID UE_REG_SR_ADDR(13) // word 1 of packet.
-#define UE_REG_CTRL_RX_VRT_TRAILER UE_REG_SR_ADDR(14)
-#define UE_REG_CTRL_RX_NSAMPS_PER_PKT UE_REG_SR_ADDR(15)
-#define UE_REG_CTRL_RX_NCHANNELS UE_REG_SR_ADDR(16) // 1 in basic case, up to 4 for vector sources
+#define UE_REG_CTRL_RX_STREAM_CMD UE_REG_CTRL_RX_ADDR(0) // {now, chain, num_samples(30)
+#define UE_REG_CTRL_RX_TIME_SECS UE_REG_CTRL_RX_ADDR(1)
+#define UE_REG_CTRL_RX_TIME_TICKS UE_REG_CTRL_RX_ADDR(2)
+#define UE_REG_CTRL_RX_CLEAR UE_REG_CTRL_RX_ADDR(3) // write anything to clear
+#define UE_REG_CTRL_RX_VRT_HEADER UE_REG_CTRL_RX_ADDR(4) // word 0 of packet. FPGA fills in packet counter
+#define UE_REG_CTRL_RX_VRT_STREAM_ID UE_REG_CTRL_RX_ADDR(5) // word 1 of packet.
+#define UE_REG_CTRL_RX_VRT_TRAILER UE_REG_CTRL_RX_ADDR(6)
+#define UE_REG_CTRL_RX_NSAMPS_PER_PKT UE_REG_CTRL_RX_ADDR(7)
+#define UE_REG_CTRL_RX_NCHANNELS UE_REG_CTRL_RX_ADDR(8) // 1 in basic case, up to 4 for vector sources
/////////////////////////////////////////////////
// DSP TX Regs
////////////////////////////////////////////////
-#define UE_REG_DSP_TX_FREQ UE_REG_SR_ADDR(17)
-#define UE_REG_DSP_TX_SCALE_IQ UE_REG_SR_ADDR(18) // {scale_i,scale_q}
-#define UE_REG_DSP_TX_INTERP_RATE UE_REG_SR_ADDR(19)
-#define UE_REG_DSP_TX_UNUSED UE_REG_SR_ADDR(20)
-#define UE_REG_DSP_TX_MUX UE_REG_SR_ADDR(21)
+#define UE_REG_DSP_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(32) + (4*(n)))
+#define UE_REG_DSP_TX_FREQ UE_REG_DSP_TX_ADDR(0)
+#define UE_REG_DSP_TX_SCALE_IQ UE_REG_DSP_TX_ADDR(1) // {scale_i,scale_q}
+#define UE_REG_DSP_TX_INTERP_RATE UE_REG_DSP_TX_ADDR(2)
+#define UE_REG_DSP_TX_UNUSED UE_REG_DSP_TX_ADDR(3)
+#define UE_REG_DSP_TX_MUX UE_REG_DSP_TX_ADDR(4)
/////////////////////////////////////////////////
// VITA TX CTRL regs
////////////////////////////////////////////////
-#define UE_REG_CTRL_TX_NCHANNELS UE_REG_SR_ADDR(24)
-#define UE_REG_CTRL_TX_CLEAR_UNDERRUN UE_REG_SR_ADDR(25)
-#define UE_REG_CTRL_TX_REPORT_SID UE_REG_SR_ADDR(26)
-#define UE_REG_CTRL_TX_POLICY UE_REG_SR_ADDR(27)
+#define UE_REG_CTRL_TX_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(24) + (4*(n)))
+#define UE_REG_CTRL_TX_NCHANNELS UE_REG_CTRL_TX_ADDR(0)
+#define UE_REG_CTRL_TX_CLEAR UE_REG_CTRL_TX_ADDR(1)
+#define UE_REG_CTRL_TX_REPORT_SID UE_REG_CTRL_TX_ADDR(2)
+#define UE_REG_CTRL_TX_POLICY UE_REG_CTRL_TX_ADDR(3)
#define UE_FLAG_CTRL_TX_POLICY_WAIT (0x1 << 0)
#define UE_FLAG_CTRL_TX_POLICY_NEXT_PACKET (0x1 << 1)
@@ -189,11 +202,12 @@
*
* </pre>
*/
-#define UE_REG_TIME64_SECS UE_REG_SR_ADDR(28) // value to set absolute secs to on next PPS
-#define UE_REG_TIME64_TICKS UE_REG_SR_ADDR(29) // value to set absolute ticks to on next PPS
-#define UE_REG_TIME64_FLAGS UE_REG_SR_ADDR(30) // flags - see chart above
-#define UE_REG_TIME64_IMM UE_REG_SR_ADDR(31) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
-#define UE_REG_TIME64_TPS UE_REG_SR_ADDR(31) // clock ticks per second (counter rollover)
+#define UE_REG_TIME64_ADDR(n) (UE_REG_SETTINGS_BASE_ADDR(40) + (4*(n)))
+#define UE_REG_TIME64_SECS UE_REG_TIME64_ADDR(0) // value to set absolute secs to on next PPS
+#define UE_REG_TIME64_TICKS UE_REG_TIME64_ADDR(1) // value to set absolute ticks to on next PPS
+#define UE_REG_TIME64_FLAGS UE_REG_TIME64_ADDR(2) // flags - see chart above
+#define UE_REG_TIME64_IMM UE_REG_TIME64_ADDR(3) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
+#define UE_REG_TIME64_TPS UE_REG_TIME64_ADDR(4) // clock ticks per second (counter rollover)
//pps flags (see above)
#define UE_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
diff --git a/host/usrp_e_utils/CMakeLists.txt b/host/usrp_e_utils/CMakeLists.txt
new file mode 100644
index 000000000..5123af592
--- /dev/null
+++ b/host/usrp_e_utils/CMakeLists.txt
@@ -0,0 +1,51 @@
+#
+# Copyright 2011 Ettus Research LLC
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# USRP embedded utilities that get installed into the share path
+########################################################################
+IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ SET(LINUX_TARGET TRUE)
+ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+
+LIBUHD_REGISTER_COMPONENT("USRP-E Utils" ENABLE_USRP_E_UTILS OFF "LINUX_TARGET" OFF)
+
+IF(ENABLE_USRP_E_UTILS)
+ ENABLE_LANGUAGE(C)
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100/include)
+ INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/lib/ic_reg_maps)
+
+ SET(usrp_e_utils_sources
+ usrp-e-utility.cpp
+ usrp-e-loopback.c
+ usrp-e-wb-test.cpp
+ usrp-e-debug-pins.c
+ usrp-e-i2c.c
+ usrp-e-spi.c
+ )
+
+ #for each source: build an executable and install
+ FOREACH(util_source ${usrp_e_utils_sources})
+ GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE)
+ ADD_EXECUTABLE(${util_name} ${util_source})
+ TARGET_LINK_LIBRARIES(${util_name} ${Boost_LIBRARIES})
+ INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_DATA_DIR}/usrp_e_utils)
+ ENDFOREACH(util_source)
+
+ENDIF(ENABLE_USRP_E_UTILS)
diff --git a/host/utils/clkgen-config.cpp b/host/usrp_e_utils/clkgen_config.hpp
index e8279b4ae..f39f8bb19 100644
--- a/host/utils/clkgen-config.cpp
+++ b/host/usrp_e_utils/clkgen_config.hpp
@@ -1,24 +1,22 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
- *
- * This file is part of UHD
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
-*/
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef USRP_E_UTILS_CLKGEN_CONFIG_HPP
+#define USRP_E_UTILS_CLKGEN_CONFIG_HPP
#include <iostream>
#include <sstream>
@@ -33,6 +31,7 @@
#include <linux/spi/spidev.h>
+namespace usrp_e_clkgen_config_utility{
// Programming data for clock gen chip
static const unsigned int config_data[] = {
@@ -73,7 +72,7 @@ static const unsigned int config_data[] = {
0x019021,
0x019100,
0x019200,
- 0x019333,
+ 0x019321,
0x019400,
0x019500,
0x019611,
@@ -157,6 +156,7 @@ class spidev {
};
gpio::gpio(unsigned int _gpio_num, gpio_direction pin_direction, bool close_action)
+:close_action(close_action)
{
std::fstream export_file;
@@ -264,10 +264,10 @@ void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
tr.rx_buf = (unsigned long) rbuf;
tr.len = nbytes;
tr.delay_usecs = 0;
- tr.speed_hz = 12000000;
+ tr.speed_hz = 12000;
tr.bits_per_word = 24;
- ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
}
@@ -278,19 +278,28 @@ static void send_config_to_clkgen(gpio &chip_select, const unsigned int data[],
for (unsigned int i = 0; i < data_size; i++) {
- std::cout << "sending " << std::hex << data[i] << std::endl;
+ //std::cout << "sending " << std::hex << data[i] << std::endl;
chip_select.set_value(0);
spi.send((char *)&data[i], (char *)&rbuf, 4);
chip_select.set_value(1);
-
+ unsigned int addr = (data[i] >> 8) & 0xfff;
+ if (addr == 0x232 || addr == 0x000){
+ std::cout << "." << std::flush;
+ sleep(1);
+ }
};
+ std::cout << std::endl;
}
-int main(int argc, char *argv[])
-{
+}//namespace usrp_e_clkgen_config_utility
+//int main(int argc, char *argv[])
+static void clock_genconfig_main(void)
+{
+ using namespace usrp_e_clkgen_config_utility;
gpio clkgen_select(CLKGEN_SELECT, OUT, true);
- send_config_to_clkgen(clkgen_select, config_data, sizeof(config_data)/sizeof(unsigned int));
+ send_config_to_clkgen(clkgen_select, config_data, sizeof(config_data)/sizeof(config_data[0]));
}
+#endif /*USRP_E_UTILS_CLKGEN_CONFIG_HPP*/
diff --git a/host/utils/usrp-e-debug-pins.c b/host/usrp_e_utils/usrp-e-debug-pins.c
index 94f898b67..94f898b67 100644
--- a/host/utils/usrp-e-debug-pins.c
+++ b/host/usrp_e_utils/usrp-e-debug-pins.c
diff --git a/host/utils/usrp-e-i2c.c b/host/usrp_e_utils/usrp-e-i2c.c
index c6fd4c632..c6fd4c632 100644
--- a/host/utils/usrp-e-i2c.c
+++ b/host/usrp_e_utils/usrp-e-i2c.c
diff --git a/host/utils/usrp-e-loopback.c b/host/usrp_e_utils/usrp-e-loopback.c
index 454d81ba7..454d81ba7 100644
--- a/host/utils/usrp-e-loopback.c
+++ b/host/usrp_e_utils/usrp-e-loopback.c
diff --git a/host/utils/usrp-e-spi.c b/host/usrp_e_utils/usrp-e-spi.c
index 5203f56a8..5203f56a8 100644
--- a/host/utils/usrp-e-spi.c
+++ b/host/usrp_e_utils/usrp-e-spi.c
diff --git a/host/usrp_e_utils/usrp-e-utility.cpp b/host/usrp_e_utils/usrp-e-utility.cpp
new file mode 100644
index 000000000..b926cf49d
--- /dev/null
+++ b/host/usrp_e_utils/usrp-e-utility.cpp
@@ -0,0 +1,75 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/safe_main.hpp>
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <stdexcept>
+#include <iostream>
+
+#include "fpga_downloader.cpp"
+#include "clkgen_config.hpp"
+
+namespace po = boost::program_options;
+
+int UHD_SAFE_MAIN(int argc, char *argv[]){
+
+ //variables to be set by po
+ std::string fpga_path;
+
+ //setup the program options
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("fpga", po::value<std::string>(&fpga_path), "loads the specified FPGA file")
+ ("reclk", "runs the clock recovery")
+ ;
+ 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 USRP-E Utility %s") % desc << std::endl;
+ return ~0;
+ }
+
+ bool loaded_fpga_image = false;
+ if (vm.count("fpga") != 0){
+ std::cout << "USRP-E Utility loading the FPGA..." << std::endl << std::endl;
+ usrp_e100_load_fpga(fpga_path);
+ loaded_fpga_image = true;
+ sleep(1);
+ }
+
+ if (vm.count("reclk") != 0){
+ std::cout << "USRP-E Utility running the clock recovery..." << std::flush;
+ //if an image was not loaded or specified, we load pass-through
+ if (fpga_path.empty()) throw std::runtime_error(
+ "Please specify the path to the pass-though FPGA image for your device.\n"
+ " usrp-e-utility --reclk --fpga=/usr/share/uhd/images/usrp_e1xx_pt_fpga.bin"
+ );
+ clock_genconfig_main();
+ if (std::system("rm /tmp/usrp*hash") != 0){ //clear hash so driver must reload
+ std::cerr << "No hash to remove! Don't worry, its not a problem." << std::endl;
+ }
+ }
+
+ std::cout << "Done!" << std::endl;
+
+ return 0;
+}
diff --git a/host/usrp_e_utils/usrp-e-wb-test.cpp b/host/usrp_e_utils/usrp-e-wb-test.cpp
new file mode 100644
index 000000000..3d6a8d101
--- /dev/null
+++ b/host/usrp_e_utils/usrp-e-wb-test.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+#include <iostream>
+
+#include <sys/ioctl.h> //ioctl
+#include <fcntl.h> //open, close
+
+#include <linux/usrp_e.h>
+#include "usrp_e100_regs.hpp"
+
+static const size_t num_test_iters = 10000000;
+
+static int fp;
+
+static int peek16(int reg){
+ int ret;
+ struct usrp_e_ctl16 d;
+
+ d.offset = reg;
+ d.count = 1;
+ ret = ioctl(fp, USRP_E_READ_CTL16, &d);
+ return d.buf[0];
+}
+
+static void poke16(int reg, int val){
+ int ret;
+ struct usrp_e_ctl16 d;
+
+ d.offset = reg;
+ d.count = 1;
+ d.buf[0] = val;
+ ret = ioctl(fp, USRP_E_WRITE_CTL16, &d);
+}
+
+static int peek32(int reg){
+ int ret;
+ struct usrp_e_ctl32 d;
+
+ d.offset = reg;
+ d.count = 1;
+ ret = ioctl(fp, USRP_E_READ_CTL32, &d);
+ return d.buf[0];
+}
+
+static void poke32(int reg, int val){
+ int ret;
+ struct usrp_e_ctl32 d;
+
+ d.offset = reg;
+ d.count = 1;
+ d.buf[0] = val;
+ ret = ioctl(fp, USRP_E_WRITE_CTL32, &d);
+}
+
+int main(int, char *[]){
+
+ srandom(time(NULL)); //seed random()
+
+ if ((fp = ::open("/dev/usrp_e0", O_RDWR)) < 0){
+ std::cerr << "Open failed" << std::endl;
+ return -1;
+ }
+
+ size_t num_pass = 0, num_fail = 0;
+ for (size_t i = 0; i < num_test_iters; i++){
+ if(i%1000000 == 0) {
+ std::cout << "num pass: " << num_pass;
+ std::cout << "\tnum fail: " << num_fail << std::endl;
+ }
+ //make random values
+ int random_test32 = ::random();
+ int random_test16 = ::random() & 0xffff;
+ int random_secs = ::random();
+
+ //set a bunch of registers
+ poke16(UE_REG_MISC_TEST, random_test16);
+ poke32(UE_REG_SR_MISC_TEST32, random_test32);
+ poke32(UE_REG_TIME64_TICKS, 0);
+ poke32(UE_REG_TIME64_IMM, 1); //immediate
+ poke32(UE_REG_TIME64_SECS, random_secs);
+
+ //read a bunch of registers
+ if (
+ (peek16(UE_REG_MISC_TEST) == random_test16) and
+ (peek32(UE_REG_RB_MISC_TEST32) == random_test32) and
+ (peek32(UE_REG_RB_TIME_NOW_SECS) == random_secs) and
+// (peek32(UE_REG_RB_TIME_NOW_TICKS) < 1000000) and
+ true) num_pass++;
+ else num_fail++;
+ }
+
+ std::cout << "num pass: " << num_pass << std::endl;
+ std::cout << "num fail: " << num_fail << std::endl;
+
+ ::close(fp);
+ return 0;
+}
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 2df1c3529..53527c03d 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2010 Ettus Research LLC
+# Copyright 2010-2011 Ettus Research LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,20 +45,6 @@ IF(ENABLE_USRP1)
)
ENDIF(ENABLE_USRP1)
-IF(ENABLE_USRP_E100)
- ENABLE_LANGUAGE(C)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/usrp/usrp_e100/include)
- LIST(APPEND util_share_sources
- fpga-downloader.cpp
- clkgen-config.cpp
- usrp-e-loopback.c
- usrp-e-debug-pins.c
- usrp-e-i2c.c
- usrp-e-spi.c
- )
-ENDIF(ENABLE_USRP_E100)
-
#for each source: build an executable and install
FOREACH(util_source ${util_share_sources})
GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE)
diff --git a/host/utils/fpga-downloader.cpp b/host/utils/fpga-downloader.cpp
deleted file mode 100644
index 80ee71600..000000000
--- a/host/utils/fpga-downloader.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2004,2008,2009 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
-*/
-
-#include <iostream>
-#include <sstream>
-#include <fstream>
-#include <string>
-#include <cstdlib>
-
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <linux/spi/spidev.h>
-
-/*
- * Configuration connections
- *
- * CCK - MCSPI1_CLK
- * DIN - MCSPI1_MOSI
- * PROG_B - GPIO_175 - output (change mux)
- * DONE - GPIO_173 - input (change mux)
- * INIT_B - GPIO_114 - input (change mux)
- *
-*/
-
-const unsigned int PROG_B = 175;
-const unsigned int DONE = 173;
-const unsigned int INIT_B = 114;
-
-static std::string bit_file = "safe_u1e.bin";
-
-const int BUF_SIZE = 4096;
-
-enum gpio_direction {IN, OUT};
-
-class gpio {
- public:
-
- gpio(unsigned int gpio_num, gpio_direction pin_direction);
-
- bool get_value();
- void set_value(bool state);
-
- private:
-
- std::stringstream base_path;
- std::fstream value_file;
-};
-
-class spidev {
- public:
-
- spidev(std::string dev_name);
- ~spidev();
-
- void send(char *wbuf, char *rbuf, unsigned int nbytes);
-
- private:
-
- int fd;
-
-};
-
-gpio::gpio(unsigned int gpio_num, gpio_direction pin_direction)
-{
- std::fstream export_file;
-
- export_file.open("/sys/class/gpio/export", std::ios::out);
- if (!export_file.is_open()) ///\todo Poor error handling
- std::cout << "Failed to open gpio export file." << std::endl;
-
- export_file << gpio_num << std::endl;
-
- base_path << "/sys/class/gpio/gpio" << gpio_num << std::flush;
-
- std::fstream direction_file;
- std::string direction_file_name;
-
- direction_file_name = base_path.str() + "/direction";
-
- direction_file.open(direction_file_name.c_str());
- if (!direction_file.is_open())
- std::cout << "Failed to open direction file." << std::endl;
- if (pin_direction == OUT)
- direction_file << "out" << std::endl;
- else
- direction_file << "in" << std::endl;
-
- std::string value_file_name;
-
- value_file_name = base_path.str() + "/value";
-
- value_file.open(value_file_name.c_str(), std::ios_base::in | std::ios_base::out);
- if (!value_file.is_open())
- std::cout << "Failed to open value file." << std::endl;
-}
-
-bool gpio::get_value()
-{
-
- std::string val;
-
- std::getline(value_file, val);
- value_file.seekg(0);
-
- if (val == "0")
- return false;
- else if (val == "1")
- return true;
- else
- std::cout << "Data read from value file|" << val << "|" << std::endl;
-
- return false;
-}
-
-void gpio::set_value(bool state)
-{
-
- if (state)
- value_file << "1" << std::endl;
- else
- value_file << "0" << std::endl;
-}
-
-static void prepare_fpga_for_configuration(gpio &prog, gpio &init)
-{
-
- prog.set_value(true);
- prog.set_value(false);
- prog.set_value(true);
-
-#if 0
- bool ready_to_program(false);
- unsigned int count(0);
- do {
- ready_to_program = init.get_value();
- count++;
-
- sleep(1);
- } while (count < 10 && !ready_to_program);
-
- if (count == 10) {
- std::cout << "FPGA not ready for programming." << std::endl;
- exit(-1);
- }
-#endif
-}
-
-spidev::spidev(std::string fname)
-{
- int ret;
- int mode = 0;
- int speed = 12000000;
- int bits = 8;
-
- fd = open(fname.c_str(), O_RDWR);
-
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
- ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
- ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
-}
-
-
-spidev::~spidev()
-{
- close(fd);
-}
-
-void spidev::send(char *buf, char *rbuf, unsigned int nbytes)
-{
- int ret;
-
- struct spi_ioc_transfer tr;
- tr.tx_buf = (unsigned long) buf;
- tr.rx_buf = (unsigned long) rbuf;
- tr.len = nbytes;
- tr.delay_usecs = 0;
- tr.speed_hz = 48000000;
- tr.bits_per_word = 8;
-
- ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
-
-}
-
-static void send_file_to_fpga(std::string &file_name, gpio &error, gpio &done)
-{
- std::ifstream bitstream;
-
- std::cout << "File name - " << file_name.c_str() << std::endl;
-
- bitstream.open(file_name.c_str(), std::ios::binary);
- if (!bitstream.is_open())
- std::cout << "File " << file_name << " not opened succesfully." << std::endl;
-
- spidev spi("/dev/spidev1.0");
- char buf[BUF_SIZE];
- char rbuf[BUF_SIZE];
-
- do {
- bitstream.read(buf, BUF_SIZE);
- spi.send(buf, rbuf, bitstream.gcount());
-
- if (error.get_value())
- std::cout << "INIT_B went high, error occured." << std::endl;
-
- if (!done.get_value())
- std::cout << "Configuration complete." << std::endl;
-
- } while (bitstream.gcount() == BUF_SIZE);
-}
-
-int main(int argc, char *argv[])
-{
-
- gpio gpio_prog_b(PROG_B, OUT);
- gpio gpio_init_b(INIT_B, IN);
- gpio gpio_done (DONE, IN);
-
- if (argc == 2)
- bit_file = argv[1];
-
- bool module_found(false);
- std::ifstream mod_file("/proc/modules");
- while (!mod_file.eof()) {
- std::string line;
- getline(mod_file, line);
- if (line.find("usrp_e") != std::string::npos)
- module_found = true;
- }
- mod_file.close();
-
- if (module_found) {
- std::cout << "USRP Embedded kernel module loaded, not loading FPGA." << std::endl;
- return -1;
- }
-
- std::cout << "FPGA config file: " << bit_file << std::endl;
-
- prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
-
- std::cout << "Done = " << gpio_done.get_value() << std::endl;
-
- send_file_to_fpga(bit_file, gpio_init_b, gpio_done);
-}
-
diff --git a/images/Makefile b/images/Makefile
index 34c18cdc2..cfc783ee4 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -152,6 +152,22 @@ $(_usrp_e100_fpga_bin): $(GLOBAL_DEPS)
endif
########################################################################
+# USRP-E100 pass-through fpga
+########################################################################
+ifdef HAS_XTCLSH
+
+_usrp_e100_pt_fpga_dir = $(TOP_FPGA_DIR)/usrp2/top/u1e_passthru
+_usrp_e100_pt_fpga_bin = $(BUILT_IMAGES_DIR)/usrp_e100_pt_fpga.bin
+IMAGES_LIST += $(_usrp_e100_pt_fpga_bin)
+
+$(_usrp_e100_pt_fpga_bin): $(GLOBAL_DEPS)
+ cd $(_usrp_e100_pt_fpga_dir) && make clean
+ cd $(_usrp_e100_pt_fpga_dir) && make bin
+ cp $(_usrp_e100_pt_fpga_dir)/build/passthru.bin $@
+
+endif
+
+########################################################################
# Build rules
########################################################################
images: $(IMAGES_LIST)