Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional cfo cor #30

Merged
merged 2 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 70 additions & 54 deletions hdl/PSS_detector.sv
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module PSS_detector
parameter INITIAL_DETECTION_SHIFT = 3,
parameter INITIAL_CFO_MODE = 0,
parameter CIC_RATE = 2,
parameter HAS_CFO_CALC = 1,

localparam SAMPLE_RATE = 1920000,
localparam AXI_ADDRESS_WIDTH = 11
Expand Down Expand Up @@ -393,73 +394,85 @@ reg CFO_calc_valid_in;
reg CFO_calc_valid_out;
reg signed [CFO_DW - 1 : 0] CFO_angle;
reg signed [DDS_DW - 1 : 0] CFO_DDS_inc;
CFO_calc #(
.C_DW(C_DW),
.CFO_DW(CFO_DW),
.DDS_DW(DDS_DW)
)
CFO_calc_i(
.clk_i(clk_i),
.reset_ni(reset_int_n),
.C0_i(C0_in),
.C1_i(C1_in),
.valid_i(CFO_calc_valid_in),
if (HAS_CFO_CALC) begin
CFO_calc #(
.C_DW(C_DW),
.CFO_DW(CFO_DW),
.DDS_DW(DDS_DW)
)
CFO_calc_i(
.clk_i(clk_i),
.reset_ni(reset_int_n),
.C0_i(C0_in),
.C1_i(C1_in),
.valid_i(CFO_calc_valid_in),

.CFO_angle_o(CFO_angle),
.CFO_DDS_inc_o(CFO_DDS_inc),
.valid_o(CFO_calc_valid_out)
);
.CFO_angle_o(CFO_angle),
.CFO_DDS_inc_o(CFO_DDS_inc),
.valid_o(CFO_calc_valid_out)
);
end else begin
always_comb begin
CFO_calc_valid_out <= '0;
CFO_DDS_inc <= '0;
CFO_angle <= '0;
end
end

localparam [1 : 0] SEARCH = 0;
localparam [1 : 0] FIND = 1;
localparam [1 : 0] PAUSE = 2;
reg N_id_2_valid;

reg [1 : 0] CFO_state;
localparam [1 : 0] WAIT_FOR_PEAK = 0;
localparam [1 : 0] DISABLE_CFO_IN = 1;
localparam [1 : 0] WAIT_FOR_CFO = 2;

//-------------------------------------------------------------------------------
// FSM to control CFO_calc
// it is not sensitive to new incoming peaks while it waits for CFO_calc to finish
// this can cause a peak to be ignored if it follows close after another peak
//
// TODO: signal a valid N_id_2 only of the calculated CFO is below a certain threshold,
// i.e. +- 100 Hz, if it is above, wait for next SSB with corrected CFO
always @(posedge clk_i) begin
if (!reset_int_n) begin
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_valid_o <= '0;
end else begin
case (CFO_state)
WAIT_FOR_PEAK : begin
CFO_valid_o <= '0;
if (N_id_2_valid) begin
C0_in <= C0_f[N_id_2_o];
C1_in <= C1_f[N_id_2_o];
CFO_calc_valid_in <= 1;
CFO_state <= DISABLE_CFO_IN;
if (HAS_CFO_CALC) begin
reg [1 : 0] CFO_state;
localparam [1 : 0] WAIT_FOR_PEAK = 0;
localparam [1 : 0] DISABLE_CFO_IN = 1;
localparam [1 : 0] WAIT_FOR_CFO = 2;
always @(posedge clk_i) begin
if (!reset_int_n) begin
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_valid_o <= '0;
end else begin
case (CFO_state)
WAIT_FOR_PEAK : begin
CFO_valid_o <= '0;
if (N_id_2_valid) begin
C0_in <= C0_f[N_id_2_o];
C1_in <= C1_f[N_id_2_o];
CFO_calc_valid_in <= 1;
CFO_state <= DISABLE_CFO_IN;
end
end
end
DISABLE_CFO_IN : begin
CFO_calc_valid_in <= '0;
CFO_state <= WAIT_FOR_CFO;
end
WAIT_FOR_CFO : begin
if (CFO_calc_valid_out) begin
$display("PSS_detector: detected CFO angle is %f deg", $itor(CFO_angle) / $itor((2**(CFO_DW - 1) - 1)) * $itor(180));
$display("PSS_detector: detected CFO frequency is %f Hz", $itor(CFO_angle) * SAMPLE_RATE / 64 / (2**(CFO_DW - 1) - 1));
$display("PSS detector: detected CFO DDS_inc is %d", CFO_DDS_inc);
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= cfo_mode == CFO_MODE_AUTO ? CFO_angle : '0;
CFO_DDS_inc_o <= cfo_mode == CFO_MODE_AUTO ? CFO_DDS_inc : '0;
CFO_valid_o <= 1 && (cfo_mode == CFO_MODE_AUTO);
DISABLE_CFO_IN : begin
CFO_calc_valid_in <= '0;
CFO_state <= WAIT_FOR_CFO;
end
end
endcase
WAIT_FOR_CFO : begin
if (CFO_calc_valid_out) begin
$display("PSS_detector: detected CFO angle is %f deg", $itor(CFO_angle) / $itor((2**(CFO_DW - 1) - 1)) * $itor(180));
$display("PSS_detector: detected CFO frequency is %f Hz", $itor(CFO_angle) * SAMPLE_RATE / 64 / (2**(CFO_DW - 1) - 1));
$display("PSS detector: detected CFO DDS_inc is %d", CFO_DDS_inc);
CFO_state <= WAIT_FOR_PEAK;
CFO_angle_o <= cfo_mode == CFO_MODE_AUTO ? CFO_angle : '0;
CFO_DDS_inc_o <= cfo_mode == CFO_MODE_AUTO ? CFO_DDS_inc : '0;
CFO_valid_o <= 1 && (cfo_mode == CFO_MODE_AUTO);
end
end
endcase
end
end
end else begin
always_comb begin
CFO_valid_o <= '0;
CFO_DDS_inc_o <= '0;
CFO_angle_o <= '0;
end
end

Expand All @@ -473,6 +486,9 @@ end
//
// If USE_MODE is 0, the FSM is permanently in SEARCH mode
wire [1 : 0] mode_select;
localparam [1 : 0] SEARCH = 0;
localparam [1 : 0] FIND = 1;
localparam [1 : 0] PAUSE = 2;
assign mode_select = USE_MODE ? mode_i : SEARCH;
reg [1 : 0] N_id_2;

Expand Down
159 changes: 85 additions & 74 deletions hdl/receiver.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module receiver
parameter VARIABLE_NOISE_LIMIT = 1,
parameter INITIAL_DETECTION_SHIFT = 4,
parameter INITIAL_CFO_MODE = 0,
parameter HAS_CFO_COR = 1,

localparam BLK_EXP_LEN = 8,
localparam FFT_LEN = 2 ** NFFT,
Expand Down Expand Up @@ -336,84 +337,93 @@ sample_id_cdc_i(
.m_axis_out_tempty()
);

reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc, CFO_DDS_inc_f;
reg CFO_valid;
wire [DDS_OUT_DW - 1 : 0] DDS_out;
wire DDS_out_valid;
reg [DDS_PHASE_DW - 1 : 0] DDS_phase;
reg DDS_phase_valid;

always @(posedge clk_i) begin
if (!reset_ni) begin
DDS_phase <= '0;
DDS_phase_valid <= '0;
CFO_DDS_inc_f <= '0;
end
else begin
DDS_phase_valid <= 1;
if (CFO_mode == 0) begin
if (CFO_valid) begin
// CFO_DDS_inc_f <= '0; // deactive CFO correction for debugging
CFO_DDS_inc_f <= CFO_DDS_inc_f - CFO_DDS_inc; // incoming CFO_DDS_inc are relative to last one !
end
if(FIFO_out_tvalid) begin
DDS_phase <= DDS_phase + CFO_DDS_inc_f;
end
end else begin
// manual CFO mode
CFO_DDS_inc_f <= '0;
reg CFO_valid;
reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc;
if (HAS_CFO_COR) begin
reg signed [DDS_PHASE_DW - 1 : 0] CFO_DDS_inc_f;
wire [DDS_OUT_DW - 1 : 0] DDS_out;
wire DDS_out_valid;
reg [DDS_PHASE_DW - 1 : 0] DDS_phase;
reg DDS_phase_valid;

always @(posedge clk_i) begin
if (!reset_ni) begin
DDS_phase <= '0;
DDS_phase_valid <= '0;
CFO_DDS_inc_f <= '0;
end
else begin
DDS_phase_valid <= 1;
if (CFO_mode == 0) begin
if (CFO_valid) begin
// CFO_DDS_inc_f <= '0; // deactive CFO correction for debugging
CFO_DDS_inc_f <= CFO_DDS_inc_f - CFO_DDS_inc; // incoming CFO_DDS_inc are relative to last one !
end
if(FIFO_out_tvalid) begin
DDS_phase <= DDS_phase + CFO_DDS_inc_f;
end
end else begin
// manual CFO mode
CFO_DDS_inc_f <= '0;
DDS_phase <= '0;
end
end
end
end

dds #(
.PHASE_DW(DDS_PHASE_DW),
.OUT_DW(DDS_OUT_DW/2),
.USE_TAYLOR(1),
.LUT_DW(16),
.SIN_COS(1),
.NEGATIVE_SINE(0),
.NEGATIVE_COSINE(0),
.USE_LUT_FILE(0)
)
dds_i(
.clk(clk_i),
.reset_n(reset_ni),

.s_axis_phase_tdata(DDS_phase),
.s_axis_phase_tvalid(DDS_phase_valid),

.m_axis_out_tdata(DDS_out),
.m_axis_out_tvalid(DDS_out_valid),

.m_axis_out_sin_tdata(),
.m_axis_out_sin_tvalid(),
.m_axis_out_cos_tdata(),
.m_axis_out_cos_tvalid()
);

complex_multiplier #(
.OPERAND_WIDTH_A(DDS_OUT_DW/2),
.OPERAND_WIDTH_B(IN_DW/2),
.OPERAND_WIDTH_OUT(COMPL_MULT_OUT_DW/2),
.BLOCKING(0),
.GROWTH_BITS(-2), // input is rotating vector with length 2^(IN_DW/2 - 1), therefore bit growth is 2 bits less than worst case
// TODO: WARNING, this can create an overflow if the DDS is not perfect (outputs vector with length > 1)
.BYTE_ALIGNED(0)
)
complex_multiplier_i(
.aclk(clk_i),
.aresetn(reset_ni),

.s_axis_a_tdata(DDS_out),
.s_axis_a_tvalid(DDS_out_valid),
.s_axis_b_tdata(FIFO_out_tdata),
.s_axis_b_tvalid(FIFO_out_tvalid),

.m_axis_dout_tdata(mult_out_tdata),
.m_axis_dout_tvalid(mult_out_tvalid)
);
dds #(
.PHASE_DW(DDS_PHASE_DW),
.OUT_DW(DDS_OUT_DW/2),
.USE_TAYLOR(1),
.LUT_DW(16),
.SIN_COS(1),
.NEGATIVE_SINE(0),
.NEGATIVE_COSINE(0),
.USE_LUT_FILE(0)
)
dds_i(
.clk(clk_i),
.reset_n(reset_ni),

.s_axis_phase_tdata(DDS_phase),
.s_axis_phase_tvalid(DDS_phase_valid),

.m_axis_out_tdata(DDS_out),
.m_axis_out_tvalid(DDS_out_valid),

.m_axis_out_sin_tdata(),
.m_axis_out_sin_tvalid(),
.m_axis_out_cos_tdata(),
.m_axis_out_cos_tvalid()
);

complex_multiplier #(
.OPERAND_WIDTH_A(DDS_OUT_DW/2),
.OPERAND_WIDTH_B(IN_DW/2),
.OPERAND_WIDTH_OUT(COMPL_MULT_OUT_DW/2),
.BLOCKING(0),
.GROWTH_BITS(-2), // input is rotating vector with length 2^(IN_DW/2 - 1), therefore bit growth is 2 bits less than worst case
// TODO: WARNING, this can create an overflow if the DDS is not perfect (outputs vector with length > 1)
.BYTE_ALIGNED(0)
)
complex_multiplier_i(
.aclk(clk_i),
.aresetn(reset_ni),

.s_axis_a_tdata(DDS_out),
.s_axis_a_tvalid(DDS_out_valid),
.s_axis_b_tdata(FIFO_out_tdata),
.s_axis_b_tvalid(FIFO_out_tvalid),

.m_axis_dout_tdata(mult_out_tdata),
.m_axis_dout_tvalid(mult_out_tvalid)
);
end else begin
always_comb begin
mult_out_tdata <= FIFO_out_tdata;
mult_out_tvalid <= FIFO_out_tvalid;
end
end

assign m_axis_PSS_out_tdata = pss_out_data;
assign m_axis_PSS_out_tvalid = pss_out_valid;
Expand Down Expand Up @@ -450,7 +460,8 @@ PSS_detector #(
.VARIABLE_NOISE_LIMIT(VARIABLE_NOISE_LIMIT),
.INITIAL_DETECTION_SHIFT(INITIAL_DETECTION_SHIFT),
.INITIAL_CFO_MODE(INITIAL_CFO_MODE),
.CIC_RATE(CIC_RATE)
.CIC_RATE(CIC_RATE),
.HAS_CFO_CALC(HAS_CFO_COR)
)
PSS_detector_i(
.clk_i(clk_i),
Expand Down
Loading