mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-11-03 05:23:14 +00:00
umtrx: external rx fe switch for quad dsp support -- has issues
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
/*******************************************************************
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
220
host/umtrx_test_chains.cpp
Normal 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>(&l)->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;
|
||||
}
|
||||
Reference in New Issue
Block a user