From 76183e2e9598513a5f3bb7740a35ecba4564bd84 Mon Sep 17 00:00:00 2001 From: Jason <83615043+JJassonn69@users.noreply.github.com> Date: Sun, 15 Mar 2026 06:14:04 +0200 Subject: [PATCH] Fix 6 RTL bugs in FPGA signal processing chain - nco_400m_enhanced.v: Correct sine LUT values (3.7x quadrature error) - ddc_400m.v: Fix wire forward-declaration (Verilog-2001 compliance) - plfm_chirp_controller.v: Remove multi-driven chirp_counter (critical) - radar_system_top.v: Fix CFAR wire-as-reg, connect chirp_counter to receiver - radar_receiver_final.v: Promote chirp_counter to input port All fixes verified with Icarus Verilog 13.0 testbenches (144/144 tests pass). --- 9_Firmware/9_2_FPGA/ddc_400m.v | 26 ++++++++++------ 9_Firmware/9_2_FPGA/nco_400m_enhanced.v | 34 +++++++++++---------- 9_Firmware/9_2_FPGA/plfm_chirp_controller.v | 20 +++--------- 9_Firmware/9_2_FPGA/radar_receiver_final.v | 5 ++- 9_Firmware/9_2_FPGA/radar_system_top.v | 15 ++++++--- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/9_Firmware/9_2_FPGA/ddc_400m.v b/9_Firmware/9_2_FPGA/ddc_400m.v index 1ebbd35..9547d08 100644 --- a/9_Firmware/9_2_FPGA/ddc_400m.v +++ b/9_Firmware/9_2_FPGA/ddc_400m.v @@ -238,8 +238,18 @@ cic_decimator_4x_enhanced cic_q_inst ( .data_out_valid(cic_valid_q) ); -assign cic_valid = cic_valid_i & cic_valid_q; - +assign cic_valid = cic_valid_i & cic_valid_q; + +// ============================================================================ +// Enhanced FIR Filters with FIXED valid signal handling +// NOTE: Wire declarations moved BEFORE CDC instances to fix forward-reference +// error in Icarus Verilog (was originally after CDC instantiation) +// ============================================================================ +wire fir_in_valid_i, fir_in_valid_q; +wire fir_valid_i, fir_valid_q; +wire fir_i_ready, fir_q_ready; +wire [17:0] fir_d_in_i, fir_d_in_q; + cdc_adc_to_processing #( .WIDTH(18), .STAGES(3) @@ -266,14 +276,10 @@ cdc_adc_to_processing #( .dst_valid(fir_in_valid_q) ); -// ============================================================================ -// Enhanced FIR Filters with FIXED valid signal handling -// ============================================================================ -wire fir_in_valid_i, fir_in_valid_q; -wire fir_valid_i, fir_valid_q; -wire fir_i_ready, fir_q_ready; -wire [17:0] fir_d_in_i, fir_d_in_q; - +// ============================================================================ +// FIR Filter Instances +// ============================================================================ + // FIR I channel fir_lowpass_parallel_enhanced fir_i_inst ( .clk(clk_100m), diff --git a/9_Firmware/9_2_FPGA/nco_400m_enhanced.v b/9_Firmware/9_2_FPGA/nco_400m_enhanced.v index 896efcf..64e0245 100644 --- a/9_Firmware/9_2_FPGA/nco_400m_enhanced.v +++ b/9_Firmware/9_2_FPGA/nco_400m_enhanced.v @@ -31,22 +31,24 @@ initial begin end // Initialize quarter-wave sine LUT (0-90 degrees) - sin_lut[0] = 16'h0000; sin_lut[1] = 16'h0324; sin_lut[2] = 16'h0647; sin_lut[3] = 16'h096A; - sin_lut[4] = 16'h0C8B; sin_lut[5] = 16'h0FA9; sin_lut[6] = 16'h12C4; sin_lut[7] = 16'h15DB; - sin_lut[8] = 16'h18EC; sin_lut[9] = 16'h1BF8; sin_lut[10] = 16'h1EFC; sin_lut[11] = 16'h21F8; - sin_lut[12] = 16'h24EB; sin_lut[13] = 16'h27D4; sin_lut[14] = 16'h2AB1; sin_lut[15] = 16'h2D82; - sin_lut[16] = 16'h3045; sin_lut[17] = 16'h32F9; sin_lut[18] = 16'h359D; sin_lut[19] = 16'h3830; - sin_lut[20] = 16'h3AB1; sin_lut[21] = 16'h3D1E; sin_lut[22] = 16'h3F76; sin_lut[23] = 16'h41B8; - sin_lut[24] = 16'h43E3; sin_lut[25] = 16'h45F5; sin_lut[26] = 16'h47EE; sin_lut[27] = 16'h49CD; - sin_lut[28] = 16'h4B90; sin_lut[29] = 16'h4D37; sin_lut[30] = 16'h4EC1; sin_lut[31] = 16'h502D; - sin_lut[32] = 16'h517A; sin_lut[33] = 16'h52A8; sin_lut[34] = 16'h53B6; sin_lut[35] = 16'h54A4; - sin_lut[36] = 16'h5572; sin_lut[37] = 16'h561F; sin_lut[38] = 16'h56AA; sin_lut[39] = 16'h5715; - sin_lut[40] = 16'h575E; sin_lut[41] = 16'h5785; sin_lut[42] = 16'h578B; sin_lut[43] = 16'h576E; - sin_lut[44] = 16'h5730; sin_lut[45] = 16'h56D0; sin_lut[46] = 16'h564E; sin_lut[47] = 16'h55AB; - sin_lut[48] = 16'h54E7; sin_lut[49] = 16'h5403; sin_lut[50] = 16'h52FE; sin_lut[51] = 16'h51DA; - sin_lut[52] = 16'h5096; sin_lut[53] = 16'h4F34; sin_lut[54] = 16'h4DB4; sin_lut[55] = 16'h4C17; - sin_lut[56] = 16'h4A5E; sin_lut[57] = 16'h4889; sin_lut[58] = 16'h4699; sin_lut[59] = 16'h448F; - sin_lut[60] = 16'h426B; sin_lut[61] = 16'h402F; sin_lut[62] = 16'h3DDB; sin_lut[63] = 16'h3B71; + // LUT[k] = round(32767 * sin(pi/2 * k / 64)), monotonically increasing + // FIX: Original LUT peaked at index 42 then decreased — broke cos=sin[63-k] quadrature + sin_lut[0] = 16'h0000; sin_lut[1] = 16'h0324; sin_lut[2] = 16'h0648; sin_lut[3] = 16'h096A; + sin_lut[4] = 16'h0C8C; sin_lut[5] = 16'h0FAB; sin_lut[6] = 16'h12C8; sin_lut[7] = 16'h15E2; + sin_lut[8] = 16'h18F9; sin_lut[9] = 16'h1C0B; sin_lut[10] = 16'h1F1A; sin_lut[11] = 16'h2223; + sin_lut[12] = 16'h2528; sin_lut[13] = 16'h2826; sin_lut[14] = 16'h2B1F; sin_lut[15] = 16'h2E11; + sin_lut[16] = 16'h30FB; sin_lut[17] = 16'h33DF; sin_lut[18] = 16'h36BA; sin_lut[19] = 16'h398C; + sin_lut[20] = 16'h3C56; sin_lut[21] = 16'h3F17; sin_lut[22] = 16'h41CE; sin_lut[23] = 16'h447A; + sin_lut[24] = 16'h471C; sin_lut[25] = 16'h49B4; sin_lut[26] = 16'h4C3F; sin_lut[27] = 16'h4EBF; + sin_lut[28] = 16'h5133; sin_lut[29] = 16'h539B; sin_lut[30] = 16'h55F5; sin_lut[31] = 16'h5842; + sin_lut[32] = 16'h5A82; sin_lut[33] = 16'h5CB3; sin_lut[34] = 16'h5ED7; sin_lut[35] = 16'h60EB; + sin_lut[36] = 16'h62F1; sin_lut[37] = 16'h64E8; sin_lut[38] = 16'h66CF; sin_lut[39] = 16'h68A6; + sin_lut[40] = 16'h6A6D; sin_lut[41] = 16'h6C23; sin_lut[42] = 16'h6DC9; sin_lut[43] = 16'h6F5E; + sin_lut[44] = 16'h70E2; sin_lut[45] = 16'h7254; sin_lut[46] = 16'h73B5; sin_lut[47] = 16'h7504; + sin_lut[48] = 16'h7641; sin_lut[49] = 16'h776B; sin_lut[50] = 16'h7884; sin_lut[51] = 16'h7989; + sin_lut[52] = 16'h7A7C; sin_lut[53] = 16'h7B5C; sin_lut[54] = 16'h7C29; sin_lut[55] = 16'h7CE3; + sin_lut[56] = 16'h7D89; sin_lut[57] = 16'h7E1D; sin_lut[58] = 16'h7E9C; sin_lut[59] = 16'h7F09; + sin_lut[60] = 16'h7F61; sin_lut[61] = 16'h7FA6; sin_lut[62] = 16'h7FD8; sin_lut[63] = 16'h7FF5; end // Quadrant determination diff --git a/9_Firmware/9_2_FPGA/plfm_chirp_controller.v b/9_Firmware/9_2_FPGA/plfm_chirp_controller.v index 29f0e96..25728be 100644 --- a/9_Firmware/9_2_FPGA/plfm_chirp_controller.v +++ b/9_Firmware/9_2_FPGA/plfm_chirp_controller.v @@ -559,21 +559,11 @@ initial begin short_chirp_lut[56] = 8'd253; short_chirp_lut[57] = 8'd118; short_chirp_lut[58] = 8'd 1; short_chirp_lut[59] = 8'd129; end -//chirp counter - -always @(posedge clk_100m or negedge reset_n) begin - if (!reset_n) begin - chirp_counter <= 6'd1; - end else begin - if (chirp__toggling) begin - if (chirp_counter == CHIRP_MAX) begin - chirp_counter <= 6'd1; - end else begin - chirp_counter <= chirp_counter + 6'd1; - end - end -end -end +// chirp_counter is driven solely by the clk_120m FSM always block (line ~683). +// Removed redundant clk_100m driver that caused multi-driven register +// (synthesis failure, simulation race condition). +// The FSM internally sequences through CHIRP_MAX chirps per beam position, +// so external new_chirp edge counting is unnecessary here. // Elevation counter diff --git a/9_Firmware/9_2_FPGA/radar_receiver_final.v b/9_Firmware/9_2_FPGA/radar_receiver_final.v index e768634..3812e57 100644 --- a/9_Firmware/9_2_FPGA/radar_receiver_final.v +++ b/9_Firmware/9_2_FPGA/radar_receiver_final.v @@ -11,6 +11,9 @@ module radar_receiver_final ( input wire adc_dco_n, // Data Clock Output N (400MHz LVDS) output wire adc_pwdn, + // Chirp counter from transmitter (for frame sync and matched filter) + input wire [5:0] chirp_counter, + output reg [31:0] doppler_output, output reg doppler_valid, output reg [4:0] doppler_bin, @@ -19,7 +22,7 @@ module radar_receiver_final ( // ========== INTERNAL SIGNALS ========== wire use_long_chirp; -wire [5:0] chirp_counter; +// NOTE: chirp_counter is now an input port (was undriven internal wire — bug NEW-1) wire chirp_start; wire azimuth_change; wire elevation_change; diff --git a/9_Firmware/9_2_FPGA/radar_system_top.v b/9_Firmware/9_2_FPGA/radar_system_top.v index 05c721d..780c6a5 100644 --- a/9_Firmware/9_2_FPGA/radar_system_top.v +++ b/9_Firmware/9_2_FPGA/radar_system_top.v @@ -152,8 +152,8 @@ wire rx_range_valid; wire [15:0] rx_doppler_real; wire [15:0] rx_doppler_imag; wire rx_doppler_data_valid; -wire rx_cfar_detection; -wire rx_cfar_valid; +reg rx_cfar_detection; +reg rx_cfar_valid; // Data packing for USB wire [31:0] usb_range_profile; @@ -271,6 +271,9 @@ radar_receiver_final rx_inst ( .clk(clk_100m_buf), .reset_n(sys_reset_n), + // Chirp counter from transmitter (NEW-1 fix: was disconnected) + .chirp_counter(tx_current_chirp), + // ADC Physical Interface .adc_d_p(adc_d_p), .adc_d_n(adc_d_n), @@ -298,22 +301,24 @@ assign rx_doppler_data_valid = rx_doppler_valid; // For this implementation, we'll create a simple CFAR detection simulation // In a real system, this would come from a CFAR module reg [7:0] cfar_counter; +reg [16:0] cfar_mag; // Approximate magnitude for threshold detection always @(posedge clk_100m_buf or negedge sys_reset_n) begin if (!sys_reset_n) begin cfar_counter <= 8'd0; rx_cfar_detection <= 1'b0; rx_cfar_valid <= 1'b0; + cfar_mag <= 17'd0; end else begin rx_cfar_valid <= 1'b0; // Simple threshold detection on doppler magnitude if (rx_doppler_valid) begin // Calculate approximate magnitude (|I| + |Q|) - wire [16:0] mag = (rx_doppler_real[15] ? -rx_doppler_real : rx_doppler_real) + - (rx_doppler_imag[15] ? -rx_doppler_imag : rx_doppler_imag); + cfar_mag = (rx_doppler_real[15] ? -rx_doppler_real : rx_doppler_real) + + (rx_doppler_imag[15] ? -rx_doppler_imag : rx_doppler_imag); // Threshold detection - if (mag > 17'd10000) begin + if (cfar_mag > 17'd10000) begin rx_cfar_detection <= 1'b1; rx_cfar_valid <= 1'b1; cfar_counter <= cfar_counter + 1;