umtrx: external rx fe switch for quad dsp support -- has issues

This commit is contained in:
Josh Blum
2014-04-21 11:02:56 -07:00
parent e61909566e
commit 640043a6e3
8 changed files with 372 additions and 96 deletions

View File

@@ -154,6 +154,7 @@ module umtrx_core
localparam SR_TX_DSP1 = 170; // 5
localparam SR_DIVSW = 180; // 2
localparam SR_RX_FE_SW = 183; // 1
localparam SR_SPI_CORE = 185; // 3
// FIFO Sizes, 9 = 512 lines, 10 = 1024, 11 = 2048
@@ -163,9 +164,9 @@ module umtrx_core
localparam ETH_TX_FIFOSIZE = 9;
localparam ETH_RX_FIFOSIZE = 11;
wire [7:0] set_addr, set_addr_dsp, set_addr_sys, set_addr_udp_wb, set_addr_udp_sys;
wire [31:0] set_data, set_data_dsp, set_data_sys, set_data_udp_wb, set_data_udp_sys;
wire set_stb, set_stb_dsp, set_stb_sys, set_stb_udp_wb, set_stb_udp_sys;
wire [7:0] set_addr, set_addr_dsp, set_addr_sys, set_addr_fe, set_addr_udp_wb, set_addr_udp_sys;
wire [31:0] set_data, set_data_dsp, set_data_sys, set_data_fe, set_data_udp_wb, set_data_udp_sys;
wire set_stb, set_stb_dsp, set_stb_sys, set_stb_fe, set_stb_udp_wb, set_stb_udp_sys;
reg wb_rst;
wire dsp_rst, sys_rst, fe_rst;
@@ -189,8 +190,6 @@ module umtrx_core
wire [63:0] vita_time, vita_time_pps;
wire run_rx0, run_rx1, run_tx0, run_tx1;
wire run_rx0_mux, run_rx1_mux;
wire run_tx0_mux, run_tx1_mux;
//generate sync reset signals for dsp and sys domains
reset_sync sys_rst_sync(.clk(sys_clk), .reset_in(wb_rst), .reset_out(sys_rst));
@@ -489,6 +488,10 @@ module umtrx_core
(.clk_i(wb_clk), .rst_i(wb_rst), .set_stb_i(set_stb), .set_addr_i(set_addr), .set_data_i(set_data),
.clk_o(sys_clk), .rst_o(sys_rst), .set_stb_o(set_stb_sys), .set_addr_o(set_addr_sys), .set_data_o(set_data_sys));
settings_bus_crossclock settings_bus_fe_crossclock
(.clk_i(dsp_clk), .rst_i(dsp_rst), .set_stb_i(set_stb_dsp), .set_addr_i(set_addr_dsp), .set_data_i(set_data_dsp),
.clk_o(fe_clk), .rst_o(fe_rst), .set_stb_o(set_stb_fe), .set_addr_o(set_addr_fe), .set_data_o(set_data_fe));
wire set_stb_dsp0, set_stb_dsp1;
wire [31:0] set_data_dsp0, set_data_dsp1;
wire [7:0] set_addr_dsp0, set_addr_dsp1;
@@ -574,14 +577,8 @@ module umtrx_core
// 1 = controlled by HW, 0 = by SW
// In Rev3 there are only 6 leds, and the highest one is on the ETH connector
//FIXME
assign run_tx0_mux = run_tx0;
assign run_rx0_mux = run_rx0;
assign run_tx1_mux = run_tx1;
assign run_rx1_mux = run_rx1;
wire [7:0] led_src, led_sw;
wire [7:0] led_hw = {run_tx0_mux, run_rx0_mux, run_tx1_mux, run_rx1_mux, 1'b0};
wire [7:0] led_hw = {run_tx0, run_rx0, run_tx1, run_rx1, 1'b0};
setting_reg #(.my_addr(SR_MISC+3),.width(8)) sr_led
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(led_sw),.changed());
@@ -663,14 +660,43 @@ module umtrx_core
.ss_pad_o(spiflash_cs),
.sclk_pad_o(spiflash_clk),.mosi_pad_o(spiflash_mosi),.miso_pad_i(spiflash_miso) );
// /////////////////////////////////////////////////////////////////////////
// RX Frontend
wire [23:0] front0_i, front0_q;
rx_frontend #(.BASE(SR_RX_FRONT0)) rx_frontend0
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.i_out(front0_i), .q_out(front0_q), .run(1'b1),
.adc_a({adc0_a, 4'b0}), .adc_b({adc0_b, 4'b0})
);
wire [23:0] front1_i, front1_q;
rx_frontend #(.BASE(SR_RX_FRONT1)) rx_frontend1
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.i_out(front1_i), .q_out(front1_q), .run(1'b1),
.adc_a({adc1_a, 4'b0}), .adc_b({adc1_b, 4'b0})
);
// /////////////////////////////////////////////////////////////////////////
// RX chains
//switch to select frontend used per DSP
wire [3:0] rx_fe_sw;
setting_reg #(.my_addr(SR_RX_FE_SW),.width(4)) sr_rx_fe_sw
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),.out(rx_fe_sw),.changed());
//run logic to map running DSPs to active frontends
wire [3:0] run_rx_dsp;
assign run_rx0 = |((~run_rx_dsp) & rx_fe_sw);
assign run_rx1 = |(run_rx_dsp & rx_fe_sw);
//*
umtrx_rx_chain
#(
.PROT_DEST(4),
.DSPNO(0),
.FRONT_BASE(SR_RX_FRONT0),
.DSP_BASE(SR_RX_DSP0),
.CTRL_BASE(SR_RX_CTRL0),
.FIFOSIZE(DSP_RX_FIFOSIZE),
@@ -682,7 +708,11 @@ module umtrx_core
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.adc_i(adc0_a), .adc_q(adc0_b), .adc_stb(adc0_strobe), .run(run_rx0),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[0]?front1_i:front0_i),
.front_q(rx_fe_sw[0]?front1_q:front0_q),
.adc_stb(rx_fe_sw[0]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[0]),
.vita_data_sys(dsp_rx0_data), .vita_valid_sys(dsp_rx0_valid), .vita_ready_sys(dsp_rx0_ready),
.vita_time(vita_time)
);
@@ -691,7 +721,6 @@ module umtrx_core
#(
.PROT_DEST(5),
.DSPNO(1),
.FRONT_BASE(SR_RX_FRONT1),
.DSP_BASE(SR_RX_DSP1),
.CTRL_BASE(SR_RX_CTRL1),
.FIFOSIZE(DSP_RX_FIFOSIZE)
@@ -702,7 +731,11 @@ module umtrx_core
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.adc_i(adc1_a), .adc_q(adc1_b), .adc_stb(adc1_strobe), .run(run_rx1),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[1]?front1_i:front0_i),
.front_q(rx_fe_sw[1]?front1_q:front0_q),
.adc_stb(rx_fe_sw[1]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[1]),
.vita_data_sys(dsp_rx1_data), .vita_valid_sys(dsp_rx1_valid), .vita_ready_sys(dsp_rx1_ready),
.vita_time(vita_time)
);
@@ -711,8 +744,57 @@ module umtrx_core
assign dsp_rx0_valid = 0;
assign dsp_rx1_valid = 0;
//*/
/*
umtrx_rx_chain
#(
.PROT_DEST(6),
.DSPNO(2),
.DSP_BASE(SR_RX_DSP2),
.CTRL_BASE(SR_RX_CTRL2),
.FIFOSIZE(DSP_RX_FIFOSIZE)
)
umtrx_rx_chain2
(
.sys_clk(sys_clk), .sys_rst(sys_rst),
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[2]?front1_i:front0_i),
.front_q(rx_fe_sw[2]?front1_q:front0_q),
.adc_stb(rx_fe_sw[2]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[2]),
.vita_data_sys(dsp_rx2_data), .vita_valid_sys(dsp_rx2_valid), .vita_ready_sys(dsp_rx2_ready),
.vita_time(vita_time)
);
umtrx_rx_chain
#(
.PROT_DEST(7),
.DSPNO(3),
.DSP_BASE(SR_RX_DSP3),
.CTRL_BASE(SR_RX_CTRL3),
.FIFOSIZE(DSP_RX_FIFOSIZE)
)
umtrx_rx_chain3
(
.sys_clk(sys_clk), .sys_rst(sys_rst),
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[3]?front1_i:front0_i),
.front_q(rx_fe_sw[3]?front1_q:front0_q),
.adc_stb(rx_fe_sw[3]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[3]),
.vita_data_sys(dsp_rx3_data), .vita_valid_sys(dsp_rx3_valid), .vita_ready_sys(dsp_rx3_ready),
.vita_time(vita_time)
);
//*/
//*
assign dsp_rx2_valid = 0;
assign dsp_rx3_valid = 0;
//*/
// /////////////////////////////////////////////////////////////////////////
// TX chains
@@ -735,7 +817,8 @@ assign dsp_rx3_valid = 0;
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.dac_i(dac0_a), .dac_q(dac0_b), .dac_stb(dac0_strobe), .run(run_tx0),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.dac_a(dac0_a), .dac_b(dac0_b), .dac_stb(dac0_strobe), .run(run_tx0),
.vita_data_sys(sram0_data), .vita_valid_sys(sram0_valid), .vita_ready_sys(sram0_ready),
.err_data_sys(err_tx0_data), .err_valid_sys(err_tx0_valid), .err_ready_sys(err_tx0_ready),
.vita_time(vita_time)
@@ -756,7 +839,8 @@ assign dsp_rx3_valid = 0;
.dsp_clk(dsp_clk), .dsp_rst(dsp_rst),
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.dac_i(dac1_a), .dac_q(dac1_b), .dac_stb(dac1_strobe), .run(run_tx1),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_dsp), .set_data_fe(set_data_fe),
.dac_a(dac1_a), .dac_b(dac1_b), .dac_stb(dac1_strobe), .run(run_tx1),
.vita_data_sys(sram1_data), .vita_valid_sys(sram1_valid), .vita_ready_sys(sram1_ready),
.err_data_sys(err_tx1_data), .err_valid_sys(err_tx1_valid), .err_ready_sys(err_tx1_ready),
.vita_time(vita_time)

View File

@@ -6,7 +6,6 @@ module umtrx_rx_chain
#(
parameter PROT_DEST = 0, //framer index
parameter DSPNO = 0, //the dsp unit number: 0, 1, 2...
parameter FRONT_BASE = 0,
parameter DSP_BASE = 0,
parameter CTRL_BASE = 0,
parameter FIFOSIZE = 10,
@@ -27,9 +26,14 @@ module umtrx_rx_chain
input [7:0] set_addr_dsp,
input [31:0] set_data_dsp,
//dsp clock domain
input [11:0] adc_i,
input [11:0] adc_q,
//settings bus fe clock domain
input set_stb_fe,
input [7:0] set_addr_fe,
input [31:0] set_data_fe,
//fe clock domain
input [23:0] front_i,
input [23:0] front_q,
input adc_stb,
output run,
@@ -42,37 +46,6 @@ module umtrx_rx_chain
wire [63:0] vita_time
);
/*******************************************************************
* Create settings bus for fe clock domain
******************************************************************/
wire set_stb_fe;
wire [7:0] set_addr_fe;
wire [31:0] set_data_fe;
settings_bus_crossclock settings_bus_fe_crossclock
(.clk_i(dsp_clk), .rst_i(dsp_rst), .set_stb_i(set_stb_dsp), .set_addr_i(set_addr_dsp), .set_data_i(set_data_dsp),
.clk_o(fe_clk), .rst_o(fe_rst), .set_stb_o(set_stb_fe), .set_addr_o(set_addr_fe), .set_data_o(set_data_fe));
/*******************************************************************
* Cross ADC signals from dsp to fe clock domain
******************************************************************/
reg [15:0] adc_a_16, adc_b_16;
always @(posedge dsp_clk) begin
adc_a_16 <= {adc_i, 4'b0};
adc_b_16 <= {adc_q, 4'b0};
end
/*******************************************************************
* RX frontend on fe clock domain
******************************************************************/
wire [23:0] front_i, front_q;
rx_frontend #(.BASE(FRONT_BASE)) rx_frontend
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.i_out(front_i), .q_out(front_q), .run(1'b1),
.adc_a(adc_a_16), .adc_b(adc_b_16)
);
/*******************************************************************
* DDC chain on fe clock domain
******************************************************************/
@@ -168,7 +141,6 @@ module umtrx_rx_chain
assign DATA[63:32] = vita_data_dsp;
assign DATA[95:64] = vita_sample;
assign DATA[127:96] = ddc_sample;
assign DATA[159:128] = {adc_a_16, adc_b_16};
assign DATA[191:160] = set_data_dsp;
assign DATA[223:192] = set_data_fe;
assign DATA[255] = adc_stb;

View File

@@ -26,9 +26,14 @@ module umtrx_tx_chain
input [7:0] set_addr_dsp,
input [31:0] set_data_dsp,
//settings bus fe clock domain
input set_stb_fe,
input [7:0] set_addr_fe,
input [31:0] set_data_fe,
//dsp clock domain
output reg [11:0] dac_i,
output reg [11:0] dac_q,
output reg [11:0] dac_a,
output reg [11:0] dac_b,
input dac_stb,
output run,
@@ -46,24 +51,14 @@ module umtrx_tx_chain
wire [63:0] vita_time
);
/*******************************************************************
* Create settings bus for fe clock domain
******************************************************************/
wire set_stb_fe;
wire [7:0] set_addr_fe;
wire [31:0] set_data_fe;
settings_bus_crossclock settings_bus_fe_crossclock
(.clk_i(dsp_clk), .rst_i(dsp_rst), .set_stb_i(set_stb_dsp), .set_addr_i(set_addr_dsp), .set_data_i(set_data_dsp),
.clk_o(fe_clk), .rst_o(fe_rst), .set_stb_o(set_stb_fe), .set_addr_o(set_addr_fe), .set_data_o(set_data_fe));
/*******************************************************************
* Cross DAC signals from fe to dsp clock domain
* dac_i/q come from a register on the fe clock domain
* dac_a/b come from a register on the fe clock domain
******************************************************************/
wire [15:0] dac_a_16, dac_b_16;
always @(posedge fe_clk) begin
dac_i <= dac_a_16[15:4];
dac_q <= dac_b_16[15:4];
dac_a <= dac_a_16[15:4];
dac_b <= dac_b_16[15:4];
end
/*******************************************************************

View File

@@ -69,6 +69,7 @@ SET(BOOST_REQUIRED_COMPONENTS
filesystem
system
thread
program_options
)
IF(UNIX AND EXISTS "/usr/lib64")
@@ -125,7 +126,7 @@ endif()
########################################################################
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
add_library(umtrx MODULE ${UMTRX_SOURCES})
target_link_libraries(umtrx ${POTHOS_LIBRARIES} ${UMTRX_LIBRARIES})
target_link_libraries(umtrx ${UMTRX_LIBRARIES})
########################################################################
# Install the UmTRX module
@@ -142,3 +143,7 @@ INSTALL(PROGRAMS
utils/umtrx_net_burner
DESTINATION bin
)
add_executable(umtrx_test_chains umtrx_test_chains.cpp)
target_link_libraries(umtrx_test_chains ${UMTRX_LIBRARIES})
install(TARGETS umtrx_test_chains DESTINATION bin)

View File

@@ -484,8 +484,8 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
_rx_streamers.resize(_rx_dsps.size());
_tx_streamers.resize(_tx_dsps.size());
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:0"));
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:0"));
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:0 B:0"));
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:0 B:0"));
_tree->access<std::string>(mb_path / "clock_source" / "value").set("internal");
_tree->access<std::string>(mb_path / "time_source" / "value").set("none");
}

View File

@@ -59,14 +59,27 @@ static const size_t vrt_send_header_offset_words32 = 1;
**********************************************************************/
void umtrx_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec)
{
//sanity checking
validate_subdev_spec(_tree, spec, "rx");
boost::uint32_t rx_fe_sw = 0;
for (size_t i = 0; i < spec.size(); i++)
{
UHD_ASSERT_THROW(spec[i].sd_name == "0");
UHD_ASSERT_THROW(spec[i].db_name == "A" or spec[i].db_name == "B");
if (spec[i].db_name == "A") rx_fe_sw |= (0 << i);
if (spec[i].db_name == "B") rx_fe_sw |= (1 << i);
}
_ctrl->poke32(U2_REG_SR_ADDR(SR_RX_FE_SW), rx_fe_sw);
}
void umtrx_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec)
{
//sanity checking
validate_subdev_spec(_tree, spec, "tx");
for (size_t i = 0; i < spec.size(); i++)
{
if (i == 0) UHD_ASSERT_THROW(spec[i].db_name == "A");
if (i == 1) UHD_ASSERT_THROW(spec[i].db_name == "B");
}
}
/***********************************************************************
@@ -187,7 +200,7 @@ uhd::rx_streamer::sptr umtrx_impl::get_rx_stream(const uhd::stream_args_t &args_
}
//create the transport
std::vector<zero_copy_if::sptr> xports(_rx_dsps.size());
std::vector<zero_copy_if::sptr> xports;
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++)
{
const size_t dsp = args.channels[chan_i];
@@ -197,7 +210,7 @@ uhd::rx_streamer::sptr umtrx_impl::get_rx_stream(const uhd::stream_args_t &args_
if (dsp == 2) which = UMTRX_DSP_RX2_FRAMER;
if (dsp == 3) which = UMTRX_DSP_RX3_FRAMER;
UHD_ASSERT_THROW(which != size_t(~0));
xports[dsp] = make_xport(which, args.args);
xports.push_back(make_xport(which, args.args));
}
//calculate packet size
@@ -233,7 +246,7 @@ uhd::rx_streamer::sptr umtrx_impl::get_rx_stream(const uhd::stream_args_t &args_
_rx_dsps[dsp]->set_nsamps_per_packet(spp); //seems to be a good place to set this
_rx_dsps[dsp]->setup(args);
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&zero_copy_if::get_recv_buff, xports[dsp], _1
&zero_copy_if::get_recv_buff, xports[chan_i], _1
), true /*flush*/);
my_streamer->set_issue_stream_cmd(chan_i, boost::bind(
&rx_dsp_core_200::issue_stream_command, _rx_dsps[dsp], _1));
@@ -387,6 +400,7 @@ static void handle_tx_async_msgs(
}
stop_flow_control();
while (not xport->get_recv_buff()){};//flush after fc off
}
/***********************************************************************
@@ -408,7 +422,7 @@ uhd::tx_streamer::sptr umtrx_impl::get_tx_stream(const uhd::stream_args_t &args_
}
//create the transport
std::vector<zero_copy_if::sptr> xports(_tx_dsps.size());
std::vector<zero_copy_if::sptr> xports;
for (size_t chan_i = 0; chan_i < args.channels.size(); chan_i++)
{
const size_t dsp = args.channels[chan_i];
@@ -416,7 +430,7 @@ uhd::tx_streamer::sptr umtrx_impl::get_tx_stream(const uhd::stream_args_t &args_
if (dsp == 0) which = UMTRX_DSP_TX0_FRAMER;
if (dsp == 1) which = UMTRX_DSP_TX1_FRAMER;
UHD_ASSERT_THROW(which != size_t(~0));
xports[dsp] = make_xport(which, args.args);
xports.push_back(make_xport(which, args.args));
}
//calculate packet size
@@ -464,7 +478,7 @@ uhd::tx_streamer::sptr umtrx_impl::get_tx_stream(const uhd::stream_args_t &args_
my_streamer->set_xport_chan_sid(chan_i, true, sid);
//create a flow control monitor
const size_t fc_window = UMTRX_SRAM_BYTES/xports[dsp]->get_send_frame_size();
const size_t fc_window = UMTRX_SRAM_BYTES/xports[chan_i]->get_send_frame_size();
flow_control_monitor::sptr fc_mon(new flow_control_monitor(fc_window));
//enable flow control packets
@@ -479,11 +493,11 @@ uhd::tx_streamer::sptr umtrx_impl::get_tx_stream(const uhd::stream_args_t &args_
boost::function<void(void)> stop_flow_control = boost::bind(&tx_dsp_core_200::set_updates, _tx_dsps[dsp], 0, 0);
task::sptr task = task::make(boost::bind(
&handle_tx_async_msgs, chan_i, this->get_master_clock_rate(),
fc_mon, xports[dsp], stop_flow_control, async_md, _old_async_queue));
fc_mon, xports[chan_i], stop_flow_control, async_md, _old_async_queue));
//buffer get method handles flow control and hold task reference count
my_streamer->set_xport_chan_get_buff(chan_i, boost::bind(
&get_send_buff, task, fc_mon, xports[dsp], _1
&get_send_buff, task, fc_mon, xports[chan_i], _1
));
_tx_streamers[dsp] = my_streamer; //store weak pointer

View File

@@ -62,20 +62,14 @@ localparam SR_TX_CTRL1 = 161; // 6
localparam SR_TX_DSP1 = 170; // 5
localparam SR_DIVSW = 180; // 2
localparam SR_RX_FE_SW = 183; // 1
localparam SR_SPI_CORE = 185; // 3
#define U2_REG_SR_ADDR(sr) (SETTING_REGS_BASE + (4 * (sr)))
#define U2_REG_ROUTER_CTRL_PORTS U2_REG_SR_ADDR(SR_BUF_POOL) + 8
/////////////////////////////////////////////////
// SPI Slave Constants
////////////////////////////////////////////////
// Masks for controlling different peripherals
#define SPI_SS_RX_DB 16
#define SPI_SS_TX_DB 128
////////////////////////////////////////////////
// Masks for controlling different peripherals in UmTRX
#define SPI_SS_LMS1 1
@@ -95,14 +89,6 @@ localparam SR_SPI_CORE = 185; // 3
#define U2_REG_MISC_CTRL_RAM_PAGE U2_REG_SR_ADDR(6)
#define U2_REG_MISC_CTRL_FLUSH_ICACHE U2_REG_SR_ADDR(7)
#define U2_FLAG_MISC_CTRL_SERDES_ENABLE 8
#define U2_FLAG_MISC_CTRL_SERDES_PRBSEN 4
#define U2_FLAG_MISC_CTRL_SERDES_LOOPEN 2
#define U2_FLAG_MISC_CTRL_SERDES_RXEN 1
#define U2_FLAG_MISC_CTRL_ADC_ON 0x0F
#define U2_FLAG_MISC_CTRL_ADC_OFF 0x00
/////////////////////////////////////////////////
// Readback regs
////////////////////////////////////////////////

220
host/umtrx_test_chains.cpp Normal file
View File

@@ -0,0 +1,220 @@
//
// Copyright 2010-2011,2014 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/thread/thread.hpp>
#include <boost/format.hpp>
#include <iostream>
#include <complex>
namespace po = boost::program_options;
/***********************************************************************
* TX chain test
**********************************************************************/
static void test_tx_chain(uhd::usrp::multi_usrp::sptr usrp, const uhd::stream_args_t &stream_args, const float ampl, const double begin_delta, const size_t total_num_samps)
{
//create a transmit streamer
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
//allocate buffer with data to send
std::vector<std::complex<float> > buff(tx_stream->get_max_num_samps(), std::complex<float>(ampl, ampl));
std::vector<std::complex<float> *> buffs(tx_stream->get_num_channels(), &buff.front()); //same buff all channels
//setup metadata for the first packet
uhd::tx_metadata_t md;
md.start_of_burst = false;
md.end_of_burst = false;
md.has_time_spec = true;
md.time_spec = uhd::time_spec_t(begin_delta) + usrp->get_time_now();
//the first call to send() will block this many seconds before sending:
const double timeout = begin_delta + 0.1; //timeout (delay before transmit + padding)
size_t num_acc_samps = 0; //number of accumulated samples
while(num_acc_samps < total_num_samps){
size_t samps_to_send = std::min(total_num_samps - num_acc_samps, buff.size());
//send a single packet
size_t num_tx_samps = tx_stream->send(
buffs, samps_to_send, md, timeout
);
//do not use time spec for subsequent packets
md.has_time_spec = false;
if (num_tx_samps < samps_to_send) std::cerr << "Send timeout..." << std::endl;
//std::cout << boost::format("Sent packet: %u samples") % num_tx_samps << std::endl;
num_acc_samps += num_tx_samps;
}
//send a mini EOB packet
md.end_of_burst = true;
tx_stream->send("", 0, md);
//std::cout << std::endl << "Waiting for async burst ACK... " << std::flush;
uhd::async_metadata_t async_md;
bool got_async_burst_ack = false;
//loop through all messages for the ACK packet (may have underflow messages in queue)
while (not got_async_burst_ack and tx_stream->recv_async_msg(async_md, timeout)){
got_async_burst_ack = (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK);
}
std::cout << (got_async_burst_ack? "success" : "fail") << std::endl;
}
/***********************************************************************
* RX chain test
**********************************************************************/
static void test_rx_chain(uhd::usrp::multi_usrp::sptr usrp, const uhd::stream_args_t &stream_args, const double begin_delta, const size_t total_num_samps)
{
//create a receive streamer
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
//setup streaming
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps = total_num_samps;
stream_cmd.stream_now = false;
stream_cmd.time_spec = uhd::time_spec_t(begin_delta) + usrp->get_time_now();
rx_stream->issue_stream_cmd(stream_cmd);
//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(rx_stream->get_max_num_samps());
std::vector<std::complex<float> *> buffs(rx_stream->get_num_channels(), &buff.front()); //same buff all channels
//the first call to recv() will block this many seconds before receiving
double timeout = begin_delta + 0.1; //timeout (delay before receive + padding)
size_t num_acc_samps = 0; //number of accumulated samples
while(num_acc_samps < total_num_samps){
//receive a single packet
size_t num_rx_samps = rx_stream->recv(
buffs, buff.size(), md, timeout, true
);
//use a small timeout for subsequent packets
timeout = 0.1;
//handle the error code
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) break;
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;
num_acc_samps += num_rx_samps;
}
if (num_acc_samps < total_num_samps) std::cerr << "Receive timeout before all samples received..." << std::endl;
std::cout << ((num_acc_samps == total_num_samps)? "success" : "fail") << std::endl;
}
int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::set_thread_priority_safe();
//variables to be set by po
std::string args;
double begin_delta;
size_t num_samps;
double rx_rate;
double tx_rate;
float ampl;
//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")
("secs", po::value<double>(&begin_delta)->default_value(0.5), "number of seconds time test setup")
("nsamps", po::value<size_t>(&num_samps)->default_value(100000), "total number of samples test with")
("rx_rate", po::value<double>(&rx_rate)->default_value(6.5e6), "rate of outgoing samples")
("tx_rate", po::value<double>(&tx_rate)->default_value(6.5e6), "rate of outgoing samples")
("ampl", po::value<float>(&ampl)->default_value(float(0.3)), "amplitude of each sample")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl;
return ~0;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
std::cout << boost::format("Using Device: %s") % usrp->get_pp_string() << std::endl;
//set the tx sample rate
std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
usrp->set_tx_rate(tx_rate);
std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl;
//set the rx sample rate
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl;
usrp->set_rx_rate(rx_rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
usrp->set_time_now(uhd::time_spec_t(0.0));
//test tx chains
for (size_t i = 0; i < 2; i++)
{
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(i);
test_tx_chain(usrp, stream_args, ampl, begin_delta, num_samps);
}
{
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(0);
stream_args.channels.push_back(1);
test_tx_chain(usrp, stream_args, ampl, begin_delta, num_samps);
}
//test rx chains
for (size_t i = 0; i < 2; i++)
{
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(i);
test_rx_chain(usrp, stream_args, begin_delta, num_samps);
}
{
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(0);
stream_args.channels.push_back(1);
test_rx_chain(usrp, stream_args, begin_delta, num_samps);
}
//finished
std::cout << std::endl << "Done!" << std::endl << std::endl;
return EXIT_SUCCESS;
}