fcf3999e39
Split cdc_adc_to_processing reset_n into src_reset_n/dst_reset_n so source and destination clock domains use correctly-synchronized resets. Previously cdc_chirp_counter's destination-side sync chain (100MHz) was reset by sys_reset_120m_n (120MHz domain), causing 30 CDC critical warnings. RTL changes: - cdc_modules.v: split reset port, source logic uses src_reset_n, destination sync chains + output logic use dst_reset_n - radar_system_top.v: cdc_chirp_counter gets proper per-domain resets - ddc_400m.v: CDC_FIR_i/q use reset_n_400m (src) and reset_n (dst) - formal/fv_cdc_adc.v: updated wrapper for new port interface Build 7 fixes (previously untouched): - radar_transmitter.v: SPI level-shifter assigns, STM32 GPIO CDC sync - latency_buffer_2159.v: BRAM read registration - constraints: ft601 IOB -quiet fix - tb_latency_buffer.v: updated for BRAM changes Testbench hardening (tb_cdc_modules.v, +31 new assertions): - A5-A7: split-domain reset tests (staggered deassertion, independent dst reset while src active — catches the P0 bug class) - A8: port connectivity (no X/Z on outputs) - B7: cdc_single_bit port connectivity - C6: cdc_handshake reset recovery + port connectivity Full regression: 13/13 test suites pass (257 total assertions).
250 lines
7.9 KiB
Verilog
250 lines
7.9 KiB
Verilog
`timescale 1ns / 1ps
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Company:
|
|
// Engineer:
|
|
//
|
|
// Create Date: 19:04:35 12/14/2025
|
|
// Design Name:
|
|
// Module Name: radar_transmitter
|
|
// Project Name:
|
|
// Target Devices:
|
|
// Tool versions:
|
|
// Description:
|
|
//
|
|
// Dependencies:
|
|
//
|
|
// Revision:
|
|
// Revision 0.01 - File Created
|
|
// Additional Comments:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
module radar_transmitter(
|
|
// System Clocks
|
|
input wire clk_100m, // System clock
|
|
input wire clk_120m_dac, // 120MHz DAC clock
|
|
input wire reset_n, // Reset synchronized to clk_120m_dac
|
|
input wire reset_100m_n, // Reset synchronized to clk_100m (for edge detectors/CDC)
|
|
|
|
// DAC Interface
|
|
output wire [7:0] dac_data,
|
|
output wire dac_clk,
|
|
output wire dac_sleep,
|
|
output wire rx_mixer_en,
|
|
output wire tx_mixer_en,
|
|
|
|
// STM32 Control Interface
|
|
input wire stm32_new_chirp,
|
|
input wire stm32_new_elevation,
|
|
input wire stm32_new_azimuth,
|
|
input wire stm32_mixers_enable,
|
|
|
|
output wire fpga_rf_switch,
|
|
|
|
// ADAR1000 Control Interface
|
|
output wire adar_tx_load_1,
|
|
output wire adar_rx_load_1,
|
|
output wire adar_tx_load_2,
|
|
output wire adar_rx_load_2,
|
|
output wire adar_tx_load_3,
|
|
output wire adar_rx_load_3,
|
|
output wire adar_tx_load_4,
|
|
output wire adar_rx_load_4,
|
|
output wire adar_tr_1,
|
|
output wire adar_tr_2,
|
|
output wire adar_tr_3,
|
|
output wire 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,
|
|
input wire stm32_cs_adar2_3v3,
|
|
input wire stm32_cs_adar3_3v3,
|
|
input wire 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,
|
|
output wire stm32_cs_adar2_1v8,
|
|
output wire stm32_cs_adar3_1v8,
|
|
output wire stm32_cs_adar4_1v8,
|
|
|
|
// 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
|
|
|
|
|
|
);
|
|
|
|
// ========== SPI LEVEL SHIFTER PASSTHROUGH ==========
|
|
// FPGA bridges 3.3V STM32 SPI bus (Bank 15) to 1.8V ADAR1000 SPI bus (Bank 34).
|
|
// The FPGA I/O banks handle the actual voltage translation; these assigns
|
|
// route the signals through the fabric.
|
|
assign stm32_sclk_1v8 = stm32_sclk_3v3;
|
|
assign stm32_mosi_1v8 = stm32_mosi_3v3;
|
|
assign stm32_miso_3v3 = stm32_miso_1v8;
|
|
assign stm32_cs_adar1_1v8 = stm32_cs_adar1_3v3;
|
|
assign stm32_cs_adar2_1v8 = stm32_cs_adar2_3v3;
|
|
assign stm32_cs_adar3_1v8 = stm32_cs_adar3_3v3;
|
|
assign stm32_cs_adar4_1v8 = stm32_cs_adar4_3v3;
|
|
|
|
// Edge Detection Signals
|
|
wire new_chirp_pulse;
|
|
wire new_elevation_pulse;
|
|
wire new_azimuth_pulse;
|
|
|
|
// CDC: Synchronized versions of async STM32 GPIO inputs to clk_100m
|
|
wire stm32_new_chirp_sync;
|
|
wire stm32_new_elevation_sync;
|
|
wire stm32_new_azimuth_sync;
|
|
|
|
// CDC: Synchronized versions of signals crossing clk_100m -> clk_120m_dac
|
|
wire mixers_enable_120m; // stm32_mixers_enable sync'd to clk_120m_dac
|
|
wire new_chirp_pulse_120m; // new_chirp_pulse (toggle CDC) in clk_120m_dac domain
|
|
|
|
// Chirp Control Signals
|
|
wire [7:0] chirp_data;
|
|
wire chirp_valid;
|
|
wire chirp_sequence_done;
|
|
|
|
// Toggle CDC for new_chirp_pulse: clk_100m -> clk_120m_dac
|
|
// Edge detector produces a 1-cycle pulse on clk_100m. A level synchronizer
|
|
// would miss it (120/100 MHz ratio). Toggle CDC converts pulse to level toggle,
|
|
// syncs the toggle, then detects edges on the destination side.
|
|
reg chirp_toggle_100m;
|
|
always @(posedge clk_100m or negedge reset_100m_n) begin
|
|
if (!reset_100m_n)
|
|
chirp_toggle_100m <= 1'b0;
|
|
else if (new_chirp_pulse)
|
|
chirp_toggle_100m <= ~chirp_toggle_100m;
|
|
end
|
|
|
|
// Sync the toggle to clk_120m_dac domain
|
|
wire chirp_toggle_120m;
|
|
cdc_single_bit #(.STAGES(3)) cdc_chirp_toggle (
|
|
.src_clk(clk_100m),
|
|
.dst_clk(clk_120m_dac),
|
|
.reset_n(reset_n),
|
|
.src_signal(chirp_toggle_100m),
|
|
.dst_signal(chirp_toggle_120m)
|
|
);
|
|
|
|
// Detect edges on synchronized toggle to recover pulse in clk_120m domain
|
|
reg chirp_toggle_120m_prev;
|
|
always @(posedge clk_120m_dac or negedge reset_n) begin
|
|
if (!reset_n)
|
|
chirp_toggle_120m_prev <= 1'b0;
|
|
else
|
|
chirp_toggle_120m_prev <= chirp_toggle_120m;
|
|
end
|
|
assign new_chirp_pulse_120m = chirp_toggle_120m ^ chirp_toggle_120m_prev;
|
|
|
|
// Sync stm32_mixers_enable (async GPIO level) to clk_120m_dac domain
|
|
cdc_single_bit #(.STAGES(3)) cdc_mixers_en_120m (
|
|
.src_clk(clk_100m), // Treat as pseudo-source (GPIO is async)
|
|
.dst_clk(clk_120m_dac),
|
|
.reset_n(reset_n),
|
|
.src_signal(stm32_mixers_enable),
|
|
.dst_signal(mixers_enable_120m)
|
|
);
|
|
|
|
// CDC synchronizers: async STM32 GPIO inputs -> clk_100m domain
|
|
// These prevent metastability in the edge detectors. Without these,
|
|
// the edge detector's first FF can go metastable, and the XOR output
|
|
// can glitch, producing false chirp/elevation/azimuth pulses.
|
|
cdc_single_bit #(.STAGES(2)) cdc_stm32_chirp (
|
|
.src_clk(clk_100m), // Pseudo-source for async GPIO
|
|
.dst_clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.src_signal(stm32_new_chirp),
|
|
.dst_signal(stm32_new_chirp_sync)
|
|
);
|
|
|
|
cdc_single_bit #(.STAGES(2)) cdc_stm32_elevation (
|
|
.src_clk(clk_100m),
|
|
.dst_clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.src_signal(stm32_new_elevation),
|
|
.dst_signal(stm32_new_elevation_sync)
|
|
);
|
|
|
|
cdc_single_bit #(.STAGES(2)) cdc_stm32_azimuth (
|
|
.src_clk(clk_100m),
|
|
.dst_clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.src_signal(stm32_new_azimuth),
|
|
.dst_signal(stm32_new_azimuth_sync)
|
|
);
|
|
|
|
// Enhanced STM32 Input Edge Detection with Debouncing
|
|
// Inputs are now CDC-synchronized (safe from metastability)
|
|
edge_detector_enhanced chirp_edge (
|
|
.clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.signal_in(stm32_new_chirp_sync),
|
|
.rising_falling_edge(new_chirp_pulse)
|
|
);
|
|
|
|
edge_detector_enhanced elevation_edge (
|
|
.clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.signal_in(stm32_new_elevation_sync),
|
|
.rising_falling_edge(new_elevation_pulse)
|
|
);
|
|
|
|
edge_detector_enhanced azimuth_edge (
|
|
.clk(clk_100m),
|
|
.reset_n(reset_100m_n),
|
|
.signal_in(stm32_new_azimuth_sync),
|
|
.rising_falling_edge(new_azimuth_pulse)
|
|
);
|
|
|
|
// Enhanced PLFM Chirp Generation
|
|
plfm_chirp_controller_enhanced plfm_chirp_inst (
|
|
.clk_120m(clk_120m_dac),
|
|
.clk_100m(clk_100m),
|
|
.reset_n(reset_n),
|
|
.new_chirp(new_chirp_pulse_120m), // CDC-synchronized pulse in clk_120m domain
|
|
.new_elevation(new_elevation_pulse),
|
|
.new_azimuth(new_azimuth_pulse),
|
|
.new_chirp_frame(new_chirp_frame),
|
|
.mixers_enable(mixers_enable_120m), // CDC-synchronized level in clk_120m domain
|
|
.chirp_data(chirp_data),
|
|
.chirp_valid(chirp_valid),
|
|
.chirp_done(chirp_sequence_done),
|
|
.rf_switch_ctrl(fpga_rf_switch),
|
|
.rx_mixer_en(rx_mixer_en),
|
|
.tx_mixer_en(tx_mixer_en),
|
|
.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),
|
|
.elevation_counter(current_elevation),
|
|
.azimuth_counter(current_azimuth),
|
|
.chirp_counter(current_chirp)
|
|
);
|
|
|
|
// Enhanced DAC Interface
|
|
dac_interface_enhanced dac_interface_inst (
|
|
.clk_120m(clk_120m_dac),
|
|
.reset_n(reset_n),
|
|
.chirp_data(chirp_data),
|
|
.chirp_valid(chirp_valid),
|
|
.dac_data(dac_data),
|
|
.dac_clk(dac_clk),
|
|
.dac_sleep(dac_sleep)
|
|
);
|
|
endmodule
|