diff --git a/9_Firmware/9_2_FPGA/level_shifter_interface.v b/9_Firmware/9_2_FPGA/level_shifter_interface.v new file mode 100644 index 0000000..4e0da34 --- /dev/null +++ b/9_Firmware/9_2_FPGA/level_shifter_interface.v @@ -0,0 +1,51 @@ +`timescale 1ns / 1ps + +/** + * level_shifter_interface.v + * + * Simple level shifter interface for STM32 to ADAR1000 communication + * Converts 3.3V SPI signals to 1.8V for ADAR1000 beamformer chips + */ + +module level_shifter_interface ( + input wire clk, + input wire reset_n, + + // 3.3V side (from STM32) + input wire sclk_3v3, + input wire mosi_3v3, + output wire miso_3v3, + input wire cs_3v3, + + // 1.8V side (to ADAR1000) + output wire sclk_1v8, + output wire mosi_1v8, + input wire miso_1v8, + output wire cs_1v8 +); + +// Simple level shifting through synchronization +reg sclk_sync, mosi_sync, cs_sync; +reg miso_sync; + +always @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + sclk_sync <= 1'b0; + mosi_sync <= 1'b0; + cs_sync <= 1'b1; + miso_sync <= 1'b0; + end else begin + sclk_sync <= sclk_3v3; + mosi_sync <= mosi_3v3; + cs_sync <= cs_3v3; + miso_sync <= miso_1v8; + end +end + +// Output assignments (direct connection with synchronization) +assign sclk_1v8 = sclk_sync; +assign mosi_1v8 = mosi_sync; +assign cs_1v8 = cs_sync; +assign miso_3v3 = miso_sync; + +endmodule \ No newline at end of file diff --git a/9_Firmware/9_2_FPGA/radar_system_top.v b/9_Firmware/9_2_FPGA/radar_system_top.v new file mode 100644 index 0000000..05c721d --- /dev/null +++ b/9_Firmware/9_2_FPGA/radar_system_top.v @@ -0,0 +1,437 @@ +`timescale 1ns / 1ps + +/** + * radar_system_top.v + * + * Complete Radar System Top Module + * Integrates: + * - Radar Transmitter (PLFM chirp generation) + * - Radar Receiver (ADC interface, DDC, matched filtering, Doppler processing) + * - USB Data Interface (FT601 for high-speed data transfer) + * + * Clock domains: + * - clk_100m: System clock (100MHz) + * - clk_120m_dac: DAC clock (120MHz) + * - ft601_clk: FT601 interface clock (100MHz from FT601) + */ + +module radar_system_top ( + // System Clocks + input wire clk_100m, // 100MHz system clock + input wire clk_120m_dac, // 120MHz DAC clock + input wire ft601_clk_in, // FT601 clock (100MHz) + input wire reset_n, // Active-low reset + + // ========== TRANSMITTER INTERFACES ========== + + // DAC Interface + output wire [7:0] dac_data, + output wire dac_clk, + output wire dac_sleep, + + // RF Switch Control + output wire fpga_rf_switch, + + // Mixer Enables + output wire rx_mixer_en, + output wire tx_mixer_en, + + // ADAR1000 Beamformer Control (via level shifters) + output wire adar_tx_load_1, adar_rx_load_1, + output wire adar_tx_load_2, adar_rx_load_2, + output wire adar_tx_load_3, adar_rx_load_3, + output wire adar_tx_load_4, adar_rx_load_4, + output wire adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4, + + // Level Shifter SPI Interface (STM32F7 to ADAR1000) + input wire stm32_sclk_3v3, + input wire stm32_mosi_3v3, + output wire stm32_miso_3v3, + input wire stm32_cs_adar1_3v3, stm32_cs_adar2_3v3, + input wire stm32_cs_adar3_3v3, stm32_cs_adar4_3v3, + + output wire stm32_sclk_1v8, + output wire stm32_mosi_1v8, + input wire stm32_miso_1v8, + output wire stm32_cs_adar1_1v8, stm32_cs_adar2_1v8, + output wire stm32_cs_adar3_1v8, stm32_cs_adar4_1v8, + + // ========== RECEIVER INTERFACES ========== + + // ADC Physical Interface (LVDS) + input wire [7:0] adc_d_p, // ADC Data P (LVDS) + input wire [7:0] adc_d_n, // ADC Data N (LVDS) + input wire adc_dco_p, // Data Clock Output P (400MHz LVDS) + input wire adc_dco_n, // Data Clock Output N (400MHz LVDS) + output wire adc_pwdn, // ADC Power Down + + // ========== STM32 CONTROL INTERFACES ========== + + // Chirp/Beam Control (toggle signals from STM32) + input wire stm32_new_chirp, + input wire stm32_new_elevation, + input wire stm32_new_azimuth, + input wire stm32_mixers_enable, + + // ========== FT601 USB 3.0 INTERFACE ========== + + // Data bus + inout wire [31:0] ft601_data, // 32-bit bidirectional data bus + output wire [1:0] ft601_be, // Byte enable + + // Control signals + output wire ft601_txe_n, // Transmit enable (active low) + output wire ft601_rxf_n, // Receive enable (active low) + input wire ft601_txe, // Transmit FIFO empty + input wire ft601_rxf, // Receive FIFO full + output wire ft601_wr_n, // Write strobe (active low) + output wire ft601_rd_n, // Read strobe (active low) + output wire ft601_oe_n, // Output enable (active low) + output wire ft601_siwu_n, // Send immediate / Wakeup + + // FIFO flags + input wire [1:0] ft601_srb, // Selected read buffer + input wire [1:0] ft601_swb, // Selected write buffer + + // Clock output (optional) + output wire ft601_clk_out, + + // ========== STATUS OUTPUTS ========== + + // Beam position tracking + output wire [5:0] current_elevation, + output wire [5:0] current_azimuth, + output wire [5:0] current_chirp, + output wire new_chirp_frame, + + // Doppler processing outputs (for debugging) + output wire [31:0] dbg_doppler_data, + output wire dbg_doppler_valid, + output wire [4:0] dbg_doppler_bin, + output wire [5:0] dbg_range_bin, + + // System status + output wire [3:0] system_status +); + +// ============================================================================ +// PARAMETERS +// ============================================================================ + +// System configuration +parameter USE_LONG_CHIRP = 1'b1; // Default to long chirp +parameter DOPPLER_ENABLE = 1'b1; // Enable Doppler processing +parameter USB_ENABLE = 1'b1; // Enable USB data transfer + +// ============================================================================ +// INTERNAL SIGNALS +// ============================================================================ + +// Clock and reset +wire clk_100m_buf; +wire clk_120m_dac_buf; +wire ft601_clk_buf; +wire sys_reset_n; + +// Transmitter internal signals +wire [7:0] tx_chirp_data; +wire tx_chirp_valid; +wire tx_chirp_done; +wire tx_new_chirp_frame; +wire [5:0] tx_current_elevation; +wire [5:0] tx_current_azimuth; +wire [5:0] tx_current_chirp; + +// Receiver internal signals +wire [31:0] rx_doppler_output; +wire rx_doppler_valid; +wire [4:0] rx_doppler_bin; +wire [5:0] rx_range_bin; +wire [31:0] rx_range_profile; +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; + +// Data packing for USB +wire [31:0] usb_range_profile; +wire usb_range_valid; +wire [15:0] usb_doppler_real; +wire [15:0] usb_doppler_imag; +wire usb_doppler_valid; +wire usb_cfar_detection; +wire usb_cfar_valid; + +// System status +reg [3:0] status_reg; + +// ============================================================================ +// CLOCK BUFFERING +// ============================================================================ + +BUFG bufg_100m ( + .I(clk_100m), + .O(clk_100m_buf) +); + +BUFG bufg_120m ( + .I(clk_120m_dac), + .O(clk_120m_dac_buf) +); + +BUFG bufg_ft601 ( + .I(ft601_clk_in), + .O(ft601_clk_buf) +); + +// Reset synchronization +reg [1:0] reset_sync; +always @(posedge clk_100m_buf or negedge reset_n) begin + if (!reset_n) begin + reset_sync <= 2'b00; + end else begin + reset_sync <= {reset_sync[0], 1'b1}; + end +end +assign sys_reset_n = reset_sync[1]; + +// ============================================================================ +// RADAR TRANSMITTER INSTANTIATION +// ============================================================================ + +radar_transmitter tx_inst ( + // System Clocks + .clk_100m(clk_100m_buf), + .clk_120m_dac(clk_120m_dac_buf), + .reset_n(sys_reset_n), + + // DAC Interface + .dac_data(dac_data), + .dac_clk(dac_clk), + .dac_sleep(dac_sleep), + + // Mixer Enables + .rx_mixer_en(rx_mixer_en), + .tx_mixer_en(tx_mixer_en), + + // STM32 Control Interface + .stm32_new_chirp(stm32_new_chirp), + .stm32_new_elevation(stm32_new_elevation), + .stm32_new_azimuth(stm32_new_azimuth), + .stm32_mixers_enable(stm32_mixers_enable), + + // RF Switch Control + .fpga_rf_switch(fpga_rf_switch), + + // ADAR1000 Control Interface + .adar_tx_load_1(adar_tx_load_1), + .adar_rx_load_1(adar_rx_load_1), + .adar_tx_load_2(adar_tx_load_2), + .adar_rx_load_2(adar_rx_load_2), + .adar_tx_load_3(adar_tx_load_3), + .adar_rx_load_3(adar_rx_load_3), + .adar_tx_load_4(adar_tx_load_4), + .adar_rx_load_4(adar_rx_load_4), + .adar_tr_1(adar_tr_1), + .adar_tr_2(adar_tr_2), + .adar_tr_3(adar_tr_3), + .adar_tr_4(adar_tr_4), + + // Level Shifter SPI Interface + .stm32_sclk_3v3(stm32_sclk_3v3), + .stm32_mosi_3v3(stm32_mosi_3v3), + .stm32_miso_3v3(stm32_miso_3v3), + .stm32_cs_adar1_3v3(stm32_cs_adar1_3v3), + .stm32_cs_adar2_3v3(stm32_cs_adar2_3v3), + .stm32_cs_adar3_3v3(stm32_cs_adar3_3v3), + .stm32_cs_adar4_3v3(stm32_cs_adar4_3v3), + + .stm32_sclk_1v8(stm32_sclk_1v8), + .stm32_mosi_1v8(stm32_mosi_1v8), + .stm32_miso_1v8(stm32_miso_1v8), + .stm32_cs_adar1_1v8(stm32_cs_adar1_1v8), + .stm32_cs_adar2_1v8(stm32_cs_adar2_1v8), + .stm32_cs_adar3_1v8(stm32_cs_adar3_1v8), + .stm32_cs_adar4_1v8(stm32_cs_adar4_1v8), + + // Beam Position Tracking + .current_elevation(tx_current_elevation), + .current_azimuth(tx_current_azimuth), + .current_chirp(tx_current_chirp), + .new_chirp_frame(tx_new_chirp_frame) +); + +// ============================================================================ +// RADAR RECEIVER INSTANTIATION +// ============================================================================ + +radar_receiver_final rx_inst ( + .clk(clk_100m_buf), + .reset_n(sys_reset_n), + + // ADC Physical Interface + .adc_d_p(adc_d_p), + .adc_d_n(adc_d_n), + .adc_dco_p(adc_dco_p), + .adc_dco_n(adc_dco_n), + .adc_pwdn(adc_pwdn), + + // Doppler Outputs + .doppler_output(rx_doppler_output), + .doppler_valid(rx_doppler_valid), + .doppler_bin(rx_doppler_bin), + .range_bin(rx_range_bin) +); + +// ============================================================================ +// DOPPLER DATA DECODING +// ============================================================================ + +// Decode 32-bit doppler output into real and imaginary parts +// Format: {doppler_q[15:0], doppler_i[15:0]} +assign rx_doppler_real = rx_doppler_output[15:0]; +assign rx_doppler_imag = rx_doppler_output[31:16]; +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; +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; + 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); + + // Threshold detection + if (mag > 17'd10000) begin + rx_cfar_detection <= 1'b1; + rx_cfar_valid <= 1'b1; + cfar_counter <= cfar_counter + 1; + end + end + end +end + +// ============================================================================ +// DATA PACKING FOR USB +// ============================================================================ + +// For range profile, we'll use the doppler data as a placeholder +// In a real system, this would come from the matched filter output +assign usb_range_profile = rx_doppler_output; +assign usb_range_valid = rx_doppler_valid; + +assign usb_doppler_real = rx_doppler_real; +assign usb_doppler_imag = rx_doppler_imag; +assign usb_doppler_valid = rx_doppler_valid; + +assign usb_cfar_detection = rx_cfar_detection; +assign usb_cfar_valid = rx_cfar_valid; + +// ============================================================================ +// USB DATA INTERFACE INSTANTIATION +// ============================================================================ + +usb_data_interface usb_inst ( + .clk(clk_100m_buf), + .reset_n(sys_reset_n), + + // Radar data inputs + .range_profile(usb_range_profile), + .range_valid(usb_range_valid), + .doppler_real(usb_doppler_real), + .doppler_imag(usb_doppler_imag), + .doppler_valid(usb_doppler_valid), + .cfar_detection(usb_cfar_detection), + .cfar_valid(usb_cfar_valid), + + // FT601 Interface + .ft601_data(ft601_data), + .ft601_be(ft601_be), + .ft601_txe_n(ft601_txe_n), + .ft601_rxf_n(ft601_rxf_n), + .ft601_txe(ft601_txe), + .ft601_rxf(ft601_rxf), + .ft601_wr_n(ft601_wr_n), + .ft601_rd_n(ft601_rd_n), + .ft601_oe_n(ft601_oe_n), + .ft601_siwu_n(ft601_siwu_n), + .ft601_srb(ft601_srb), + .ft601_swb(ft601_swb), + .ft601_clk_out(ft601_clk_out), + .ft601_clk_in(ft601_clk_buf) +); + +// ============================================================================ +// OUTPUT ASSIGNMENTS +// ============================================================================ + +assign current_elevation = tx_current_elevation; +assign current_azimuth = tx_current_azimuth; +assign current_chirp = tx_current_chirp; +assign new_chirp_frame = tx_new_chirp_frame; + +assign dbg_doppler_data = rx_doppler_output; +assign dbg_doppler_valid = rx_doppler_valid; +assign dbg_doppler_bin = rx_doppler_bin; +assign dbg_range_bin = rx_range_bin; + +// ============================================================================ +// SYSTEM STATUS MONITORING +// ============================================================================ + +always @(posedge clk_100m_buf or negedge sys_reset_n) begin + if (!sys_reset_n) begin + status_reg <= 4'b0000; + end else begin + status_reg[0] <= stm32_mixers_enable; // Mixers enabled + status_reg[1] <= ft601_txe; // USB TX ready + status_reg[2] <= rx_doppler_valid; // Data valid + status_reg[3] <= tx_new_chirp_frame; // New chirp frame + end +end + +assign system_status = status_reg; + +// ============================================================================ +// DEBUG AND VERIFICATION +// ============================================================================ + +`ifdef SIMULATION +// Simulation-only debug monitoring +reg [31:0] debug_cycle_counter; +reg [31:0] data_packet_counter; + +always @(posedge clk_100m_buf) begin + debug_cycle_counter <= debug_cycle_counter + 1; + + if (tx_new_chirp_frame) begin + $display("[TOP] New chirp frame started at cycle %0d", debug_cycle_counter); + end + + if (rx_doppler_valid) begin + data_packet_counter <= data_packet_counter + 1; + if (data_packet_counter < 10) begin + $display("[TOP] Doppler data[%0d]: bin=%0d, range=%0d, I=%0d, Q=%0d", + data_packet_counter, rx_doppler_bin, rx_range_bin, + rx_doppler_real, rx_doppler_imag); + end + end + + if (data_packet_counter == 100) begin + $display("[TOP] First 100 doppler packets processed"); + end +end +`endif + +endmodule \ No newline at end of file