FPGA: Restore FIR filter in rx_frontend_gen3

The FIR filter applied gain.  Removing it caused incorrect scaling and
signals where every other sample was zero.  Also parameterized heterodyne
frontend processing so it would not use resources in images not
requiring it.

Signed-off-by: michael-west <michael.west@ettus.com>


Original-commit: c27519624ec0f3a44ac1130635a03dafcf2e7f13
This commit is contained in:
michael-west
2023-01-19 10:05:27 -06:00
committed by Wade Fife
parent 740202aa22
commit b8163da1d1
5 changed files with 73 additions and 18 deletions
+6 -3
View File
@@ -14,7 +14,10 @@ module fe_control #(
parameter NUM_CHANNELS = 2,
parameter [7:0] SR_FE_CHAN_OFFSET = 16,
parameter [7:0] SR_TX_FE_BASE = 192,
parameter [7:0] SR_RX_FE_BASE = 200
parameter [7:0] SR_RX_FE_BASE = 200,
parameter BYPASS_DC_OFFSET_CORR = 0,
parameter BYPASS_IQ_COMP = 0,
parameter BYPASS_HETERODYNE = 1
)(
input clk, input reset,
// Commands from Radio Core
@@ -37,7 +40,7 @@ module fe_control #(
tx_frontend_gen3 #(
.SR_OFFSET_I(SR_TX_OFFSET_I), .SR_OFFSET_Q(SR_TX_OFFSET_Q),.SR_MAG_CORRECTION(SR_TX_MAG_CORRECTION),
.SR_PHASE_CORRECTION(SR_TX_PHASE_CORRECTION), .SR_MUX(SR_TX_MUX),
.BYPASS_DC_OFFSET_CORR(0), .BYPASS_IQ_COMP(0),
.BYPASS_DC_OFFSET_CORR(BYPASS_DC_OFFSET_CORR), .BYPASS_IQ_COMP(BYPASS_IQ_COMP),
.DEVICE("7SERIES")
) tx_fe_corr_i (
.clk(clk), .reset(reset),
@@ -56,7 +59,7 @@ module fe_control #(
rx_frontend_gen3 #(
.SR_MAG_CORRECTION(SR_RX_MAG_CORRECTION), .SR_PHASE_CORRECTION(SR_RX_PHASE_CORRECTION), .SR_OFFSET_I(SR_RX_OFFSET_I),
.SR_OFFSET_Q(SR_RX_OFFSET_Q), .SR_IQ_MAPPING(SR_RX_IQ_MAPPING), .SR_HET_PHASE_INCR(SR_RX_HET_PHASE_INCR),
.BYPASS_DC_OFFSET_CORR(0), .BYPASS_IQ_COMP(0), .BYPASS_REALMODE_DSP(0),
.BYPASS_DC_OFFSET_CORR(BYPASS_DC_OFFSET_CORR), .BYPASS_IQ_COMP(BYPASS_IQ_COMP), .BYPASS_HETERODYNE(BYPASS_HETERODYNE),
.DEVICE("7SERIES")
) rx_fe_corr_i (
.clk(clk), .reset(reset), .sync_in(time_sync),
@@ -22,13 +22,12 @@
// This register uses the following bits:
//
// Bit 0: Set to 1 to swap I and Q.
// Bit 1: Set to 1 to enable real mode (only relevant if
// BYPASS_REALMODE_DSP is set to 0, see below). If it is 1, then
// Bit 1: Set to 1 to enable real mode. If it is 1, then
// the Q input signal is ignored and assumed to be zero.
// Bit 2: Set to 1 to invert the Q input signal
// Bit 3: Set to 1 to invert the I input signal
// Bit 4: Set to 1 to enable the quarter-rate downconverter (only relevant
// when BYPASS_REALMODE_DSP is set to 0, see below).
// when BYPASS_HETERODYNE is set to 0, see below).
// Bit 7: Disable all corrections in this module.
//
// 2) DC offset correction. See the rx_dcoffset module for details. This is
@@ -49,13 +48,15 @@
// B is the value written to the register at SR_PHASE_CORRECTION.
// Set BYPASS_IQ_COMP to 1 to not synthesize this step.
//
// 4) Real-to-imaginary conversion. The converter is only enabled when the
// 4) Heterodyne conversion. The converter is only enabled when the
// "downconvert" bit in the SR_IQ_MAPPING register is asserted. In this
// case, it enables a quarter-rate mixer. The direction of this mixer is
// controlled by the SR_HET_PHASE_INCR register (a 0 in this register
// rotates by pi/2 every clock cycle, a 1 in this register rotates by -pi/2).
//
// Set BYPASS_REALMODE_DSP to 1 to not synthesize this step.
// The mixer is followed by a non-decimating FIR filter.
//
// Set BYPASS_HETERODYNE to 1 to not synthesize this step.
//
//
// UHD Developers Note: This module is typically controlled by rx_frontend_core_3000 in UHD,
@@ -74,7 +75,7 @@
// increment value
// BYPASS_DC_OFFSET_CORR : Set to 1 to disable DC offset correction
// BYPASS_IQ_COMP : Set to 1 to disable IQ offset correction
// BYPASS_REALMODE_DSP : Set to 1 to disable realmode to complex conversion
// BYPASS_HETERODYNE : Set to 1 to disable heterodyne conversion
// DEVICE : Unused.
//
module rx_frontend_gen3 #(
@@ -86,7 +87,7 @@ module rx_frontend_gen3 #(
parameter SR_HET_PHASE_INCR = 5,
parameter BYPASS_DC_OFFSET_CORR = 0,
parameter BYPASS_IQ_COMP = 0,
parameter BYPASS_REALMODE_DSP = 0,
parameter BYPASS_HETERODYNE = 0,
parameter DEVICE = "7SERIES"
)(
input clk, input reset, input sync_in,
@@ -248,10 +249,12 @@ module rx_frontend_gen3 #(
* - Realmode decimation (by 2)
********************************************************/
generate
if (BYPASS_REALMODE_DSP == 0) begin
if (BYPASS_HETERODYNE == 0) begin
wire [23:0] adc_i_dsp_cout, adc_q_dsp_cout;
wire [23:0] adc_i_filt, adc_q_filt;
wire adc_dsp_cout_stb;
wire adc_filt_stb;
// 90 degree mixer
quarter_rate_downconverter #(.WIDTH(24)) qr_dc_i(
@@ -260,9 +263,57 @@ module rx_frontend_gen3 #(
.o_tdata({adc_i_dsp_cout, adc_q_dsp_cout}), .o_tlast(), .o_tvalid(adc_dsp_cout_stb), .o_tready(1'b1),
.dirctn(phase_dir));
assign adc_dsp_stb = downconvert ? adc_dsp_cout_stb : adc_comp_stb;
assign adc_i_dsp = downconvert ? adc_i_dsp_cout : adc_i_comp;
assign adc_q_dsp = downconvert ? adc_q_dsp_cout : adc_q_comp;
// Double FIR block
localparam HB_COEFS = {-18'd62, 18'd0, 18'd194, 18'd0, -18'd440, 18'd0, 18'd855, 18'd0, -18'd1505, 18'd0, 18'd2478, 18'd0,
-18'd3900, 18'd0, 18'd5990, 18'd0, -18'd9187, 18'd0, 18'd14632, 18'd0, -18'd26536, 18'd0, 18'd83009, 18'd131071, 18'd83009,
18'd0, -18'd26536, 18'd0, 18'd14632, 18'd0, -18'd9187, 18'd0, 18'd5990, 18'd0, -18'd3900, 18'd0, 18'd2478, 18'd0, -18'd1505,
18'd0, 18'd855, 18'd0, -18'd440, 18'd0, 18'd194, 18'd0, -18'd62};
// FIR filter for real part
axi_fir_filter #(.IN_WIDTH(24), .COEFF_WIDTH(18), .OUT_WIDTH(24), .NUM_COEFFS(47), .COEFFS_VEC(HB_COEFS),
.RELOADABLE_COEFFS(0), .BLANK_OUTPUT(0), .SYMMETRIC_COEFFS(1), .SKIP_ZERO_COEFFS(1), .USE_EMBEDDED_REGS_COEFFS(0)
) hbfir0(
.clk(clk),
.reset(reset),
.clear(reset),
.s_axis_data_tdata(adc_i_dsp_cout),
.s_axis_data_tlast(1'b1),
.s_axis_data_tvalid(adc_dsp_cout_stb),
.s_axis_data_tready(),
.m_axis_data_tdata(adc_i_filt),
.m_axis_data_tlast(),
.m_axis_data_tvalid(adc_filt_stb),
.m_axis_data_tready(1'b1),
.s_axis_reload_tdata(18'd0),
.s_axis_reload_tvalid(1'b0),
.s_axis_reload_tlast(1'b0),
.s_axis_reload_tready()
);
// FIR filter for imag. part
axi_fir_filter #(.IN_WIDTH(24), .COEFF_WIDTH(18), .OUT_WIDTH(24), .NUM_COEFFS(47), .COEFFS_VEC(HB_COEFS),
.RELOADABLE_COEFFS(0), .BLANK_OUTPUT(0), .SYMMETRIC_COEFFS(1), .SKIP_ZERO_COEFFS(1), .USE_EMBEDDED_REGS_COEFFS(0)
) hbfir1(
.clk(clk),
.reset(reset),
.clear(reset),
.s_axis_data_tdata(adc_q_dsp_cout),
.s_axis_data_tlast(1'b1),
.s_axis_data_tvalid(adc_dsp_cout_stb),
.s_axis_data_tready(),
.m_axis_data_tdata(adc_q_filt),
.m_axis_data_tlast(),
.m_axis_data_tvalid(),
.m_axis_data_tready(1'b1),
.s_axis_reload_tdata(18'd0),
.s_axis_reload_tvalid(1'b0),
.s_axis_reload_tlast(1'b0),
.s_axis_reload_tready()
);
assign adc_dsp_stb = downconvert ? adc_filt_stb : adc_comp_stb;
assign adc_i_dsp = downconvert ? adc_i_filt : adc_i_comp;
assign adc_q_dsp = downconvert ? adc_q_filt : adc_q_comp;
end else begin
assign adc_dsp_stb = adc_comp_stb;
@@ -56,7 +56,7 @@ module rx_frontend_gen3_tb;
localparam BYPASS_DC_OFFSET_CORR = 0;
localparam BYPASS_IQ_COMP = 0;
localparam BYPASS_REALMODE_DSP = 0;
localparam BYPASS_HETERODYNE = 0;
localparam DEVICE = "7SERIES";
logic sync_in;
@@ -79,7 +79,7 @@ module rx_frontend_gen3_tb;
.SR_HET_PHASE_INCR (SR_HET_PHASE_INCR),
.BYPASS_DC_OFFSET_CORR (BYPASS_DC_OFFSET_CORR),
.BYPASS_IQ_COMP (BYPASS_IQ_COMP),
.BYPASS_REALMODE_DSP (BYPASS_REALMODE_DSP),
.BYPASS_HETERODYNE (BYPASS_HETERODYNE),
.DEVICE (DEVICE)
) rx_frontend_gen3_i (
.clk (clk),