plfm_chirp_controller.v
1 `timescale 1ns / 1ps 2 3 module plfm_chirp_controller_enhanced ( 4 input wire clk_120m, 5 input wire clk_100m, 6 input wire reset_n, 7 input wire new_chirp, 8 input wire new_elevation, 9 input wire new_azimuth, 10 input wire mixers_enable, 11 output reg [7:0] chirp_data, 12 output reg chirp_valid, 13 output wire new_chirp_frame, 14 output reg chirp_done, 15 output reg rf_switch_ctrl, 16 output wire rx_mixer_en, 17 output wire tx_mixer_en, 18 output wire adar_tx_load_1, 19 output wire adar_rx_load_1, 20 output wire adar_tx_load_2, 21 output wire adar_rx_load_2, 22 output wire adar_tx_load_3, 23 output wire adar_rx_load_3, 24 output wire adar_tx_load_4, 25 output wire adar_rx_load_4, 26 output reg adar_tr_1, 27 output reg adar_tr_2, 28 output reg adar_tr_3, 29 output reg adar_tr_4, 30 output reg [5:0] chirp_counter, 31 output reg [5:0] elevation_counter, 32 output reg [5:0] azimuth_counter 33 ); 34 35 // Chirp parameters 36 parameter F_START = 30000000; // 30 MHz (starting frequency) 37 parameter F_END = 10000000; // 10 MHz (ending frequency) 38 parameter FS = 120000000; // 120 MHz 39 40 // Timing parameters 41 parameter T1_SAMPLES = 3600; // 30us at 120MHz 42 parameter T1_RADAR_LISTENING = 16440; //137us at 120MHz 43 parameter T2_SAMPLES = 60; // 0.5us at 120MHz 44 parameter T2_RADAR_LISTENING = 20940; //174.5us at 120MHz 45 parameter GUARD_SAMPLES = 21048; // 175.4us at 120MHz 46 47 // Chirp and beam parameters 48 parameter CHIRP_MAX = 32; 49 parameter ELEVATION_MAX = 31; 50 parameter AZIMUTH_MAX = 50; 51 52 // State parameters 53 parameter IDLE = 3'b000; 54 parameter LONG_CHIRP = 3'b001; 55 parameter LONG_LISTEN = 3'b010; 56 parameter GUARD_TIME = 3'b011; 57 parameter SHORT_CHIRP = 3'b100; 58 parameter SHORT_LISTEN = 3'b101; 59 parameter DONE = 3'b110; 60 61 reg [2:0] current_state; 62 reg [2:0] next_state; 63 64 // Control registers 65 reg [15:0] sample_counter; 66 67 // Edge detection for input signals 68 wire chirp__toggling, elevation__toggling, azimuth__toggling; 69 70 // LUTs for chirp waveforms 71 (* ram_style = "block" *) reg [7:0] long_chirp_lut [0:3599]; // T1_SAMPLES-1 72 reg [7:0] short_chirp_lut [0:59]; // T2_SAMPLES-1 73 74 // Registered BRAM read output (sync-only for BRAM inference) 75 reg [7:0] long_chirp_rd_data; 76 77 // Edge detection 78 assign chirp__toggling = new_chirp; 79 assign elevation__toggling = new_elevation; 80 assign azimuth__toggling = new_azimuth; 81 assign new_chirp_frame = (current_state == IDLE && next_state == LONG_CHIRP); 82 83 // Mixer TX/RX sequencing — mutually exclusive based on chirp FSM state. 84 // TX mixer active during chirp transmission, RX mixer during listen. 85 // Both require mixers_enable (STM32 master enable) to be high. 86 assign tx_mixer_en = mixers_enable && (current_state == LONG_CHIRP || 87 current_state == SHORT_CHIRP); 88 assign rx_mixer_en = mixers_enable && (current_state == LONG_LISTEN || 89 current_state == SHORT_LISTEN); 90 91 // ADTR1000 pull to ground tx and rx load pins if not used 92 assign adar_tx_load_1 = 1'b0; 93 assign adar_rx_load_1 = 1'b0; 94 assign adar_tx_load_2 = 1'b0; 95 assign adar_rx_load_2 = 1'b0; 96 assign adar_tx_load_3 = 1'b0; 97 assign adar_rx_load_3 = 1'b0; 98 assign adar_tx_load_4 = 1'b0; 99 assign adar_rx_load_4 = 1'b0; 100 101 102 103 104 // LUT Initialization 105 // Long PLFM chirp LUT loaded from .mem file for BRAM inference 106 initial begin 107 $readmemh("long_chirp_lut.mem", long_chirp_lut); 108 end 109 110 // Synchronous-only BRAM read (no async reset) for BRAM inference 111 always @(posedge clk_120m) begin 112 long_chirp_rd_data <= long_chirp_lut[sample_counter]; 113 end 114 115 // Short PLFM chirp LUT initialization (too small for BRAM, keep inline) 116 initial begin 117 // Complete Short PLFM chirp LUT (0.5us, 30MHz to 10MHz) 118 short_chirp_lut[ 0] = 8'd255; short_chirp_lut[ 1] = 8'd237; short_chirp_lut[ 2] = 8'd187; short_chirp_lut[ 3] = 8'd118; short_chirp_lut[ 4] = 8'd 49; short_chirp_lut[ 5] = 8'd 6; short_chirp_lut[ 6] = 8'd 7; short_chirp_lut[ 7] = 8'd 54; 119 short_chirp_lut[ 8] = 8'd132; short_chirp_lut[ 9] = 8'd210; short_chirp_lut[10] = 8'd253; short_chirp_lut[11] = 8'd237; short_chirp_lut[12] = 8'd167; short_chirp_lut[13] = 8'd 75; short_chirp_lut[14] = 8'd 10; short_chirp_lut[15] = 8'd 10; 120 short_chirp_lut[16] = 8'd 80; short_chirp_lut[17] = 8'd180; short_chirp_lut[18] = 8'd248; short_chirp_lut[19] = 8'd237; short_chirp_lut[20] = 8'd150; short_chirp_lut[21] = 8'd 45; short_chirp_lut[22] = 8'd 1; short_chirp_lut[23] = 8'd 54; 121 short_chirp_lut[24] = 8'd167; short_chirp_lut[25] = 8'd249; short_chirp_lut[26] = 8'd228; short_chirp_lut[27] = 8'd118; short_chirp_lut[28] = 8'd 15; short_chirp_lut[29] = 8'd 18; short_chirp_lut[30] = 8'd127; short_chirp_lut[31] = 8'd238; 122 short_chirp_lut[32] = 8'd235; short_chirp_lut[33] = 8'd118; short_chirp_lut[34] = 8'd 10; short_chirp_lut[35] = 8'd 34; short_chirp_lut[36] = 8'd167; short_chirp_lut[37] = 8'd254; short_chirp_lut[38] = 8'd187; short_chirp_lut[39] = 8'd 45; 123 short_chirp_lut[40] = 8'd 8; short_chirp_lut[41] = 8'd129; short_chirp_lut[42] = 8'd248; short_chirp_lut[43] = 8'd201; short_chirp_lut[44] = 8'd 49; short_chirp_lut[45] = 8'd 10; short_chirp_lut[46] = 8'd145; short_chirp_lut[47] = 8'd254; 124 short_chirp_lut[48] = 8'd167; short_chirp_lut[49] = 8'd 17; short_chirp_lut[50] = 8'd 46; short_chirp_lut[51] = 8'd210; short_chirp_lut[52] = 8'd235; short_chirp_lut[53] = 8'd 75; short_chirp_lut[54] = 8'd 7; short_chirp_lut[55] = 8'd155; 125 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; 126 end 127 128 // chirp_counter is driven solely by the clk_120m FSM always block (line ~683). 129 // Removed redundant clk_100m driver that caused multi-driven register 130 // (synthesis failure, simulation race condition). 131 // The FSM internally sequences through CHIRP_MAX chirps per beam position, 132 // so external new_chirp edge counting is unnecessary here. 133 134 // Elevation counter 135 136 always @(posedge clk_100m or negedge reset_n) begin 137 if (!reset_n) begin 138 elevation_counter <= 6'b1; 139 end else begin 140 if (elevation__toggling) begin 141 if (elevation_counter == ELEVATION_MAX) begin 142 elevation_counter <= 6'b1; 143 end else begin 144 elevation_counter <= elevation_counter + 6'b1; 145 end 146 end 147 end 148 end 149 150 151 // Azimuth counter 152 153 always @(posedge clk_100m or negedge reset_n) begin 154 if (!reset_n) begin 155 azimuth_counter <= 6'd1; 156 end else begin 157 if (azimuth__toggling) begin 158 if (azimuth_counter == AZIMUTH_MAX) begin 159 azimuth_counter <= 6'd1; 160 end else begin 161 azimuth_counter <= azimuth_counter + 6'd1; 162 end 163 end 164 end 165 end 166 167 // State register 168 always @(posedge clk_120m or negedge reset_n) begin 169 if (!reset_n) begin 170 current_state <= IDLE; 171 end else begin 172 current_state <= next_state; 173 end 174 end 175 176 // Next state logic 177 always @(*) begin 178 case (current_state) 179 IDLE: begin 180 if (chirp__toggling && mixers_enable) 181 next_state = LONG_CHIRP; 182 else 183 next_state = IDLE; 184 end 185 186 LONG_CHIRP: begin 187 if (sample_counter == T1_SAMPLES-1) 188 next_state = LONG_LISTEN; 189 else 190 next_state = LONG_CHIRP; 191 end 192 193 LONG_LISTEN: begin 194 if (sample_counter == T1_RADAR_LISTENING-1) begin 195 if (chirp_counter == (CHIRP_MAX/2)-1) 196 next_state = GUARD_TIME; 197 else 198 next_state = LONG_CHIRP; 199 end else begin 200 next_state = LONG_LISTEN; 201 end 202 end 203 204 GUARD_TIME: begin 205 if (sample_counter == GUARD_SAMPLES-1) 206 next_state = SHORT_CHIRP; 207 else 208 next_state = GUARD_TIME; 209 end 210 211 SHORT_CHIRP: begin 212 if (sample_counter == T2_SAMPLES-1) 213 next_state = SHORT_LISTEN; 214 else 215 next_state = SHORT_CHIRP; 216 end 217 218 SHORT_LISTEN: begin 219 if (sample_counter == T2_RADAR_LISTENING-1) begin 220 if (chirp_counter == CHIRP_MAX-1) 221 next_state = DONE; 222 else 223 next_state = SHORT_CHIRP; 224 end else begin 225 next_state = SHORT_LISTEN; 226 end 227 end 228 229 DONE: begin 230 next_state = IDLE; 231 end 232 233 default: begin 234 next_state = IDLE; 235 end 236 endcase 237 end 238 239 always @(posedge clk_120m or negedge reset_n) begin 240 if (!reset_n) begin 241 sample_counter <= 0; 242 chirp_counter <= 0; 243 chirp_valid <= 0; 244 chirp_done <= 0; 245 chirp_data <= 8'd128; 246 rf_switch_ctrl <= 1'b0; 247 adar_tr_1 <= 1'b0; 248 adar_tr_2 <= 1'b0; 249 adar_tr_3 <= 1'b0; 250 adar_tr_4 <= 1'b0; 251 end else if (mixers_enable) begin 252 // Default outputs 253 chirp_valid <= 0; 254 chirp_done <= 0; 255 rf_switch_ctrl <= 0; 256 {adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4} <= 4'b0000; 257 258 // Sample counter increment logic 259 if (current_state == LONG_CHIRP || current_state == LONG_LISTEN || 260 current_state == GUARD_TIME || current_state == SHORT_CHIRP || 261 current_state == SHORT_LISTEN) begin 262 if (sample_counter == get_max_counter(current_state) - 1) begin 263 sample_counter <= 0; 264 // Increment chirp counter at end of listen states 265 if (current_state == LONG_LISTEN || current_state == SHORT_LISTEN) begin 266 chirp_counter <= chirp_counter + 1; 267 end 268 end else begin 269 sample_counter <= sample_counter + 1; 270 end 271 end else begin 272 sample_counter <= 0; 273 end 274 275 // State-specific outputs 276 case (current_state) 277 IDLE: begin 278 chirp_data <= 8'd128; 279 end 280 281 LONG_CHIRP: begin 282 rf_switch_ctrl <= 1'b1; 283 {adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4} <= 4'b1111; 284 285 // CRITICAL FIX: Generate valid signal 286 if (sample_counter < T1_SAMPLES) begin 287 chirp_data <= long_chirp_rd_data; 288 chirp_valid <= 1'b1; // Valid during entire chirp 289 end else begin 290 chirp_data <= 8'd128; 291 end 292 end 293 294 LONG_LISTEN: begin 295 chirp_data <= 8'd128; 296 rf_switch_ctrl <= 1'b0; 297 end 298 299 GUARD_TIME: begin 300 chirp_data <= 8'd128; 301 rf_switch_ctrl <= 1'b0; 302 end 303 304 SHORT_CHIRP: begin 305 rf_switch_ctrl <= 1'b1; 306 {adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4} <= 4'b1111; 307 308 // CRITICAL FIX: Generate valid signal for short chirp 309 if (sample_counter < T2_SAMPLES) begin 310 chirp_data <= short_chirp_lut[sample_counter]; 311 chirp_valid <= 1'b1; // Valid during entire chirp 312 end else begin 313 chirp_data <= 8'd128; 314 end 315 end 316 317 SHORT_LISTEN: begin 318 chirp_data <= 8'd128; 319 rf_switch_ctrl <= 1'b0; 320 end 321 322 DONE: begin 323 chirp_done <= 1'b1; 324 chirp_data <= 8'd128; 325 end 326 327 default: begin 328 chirp_data <= 8'd128; 329 end 330 endcase 331 end else begin 332 // Mixers disabled 333 chirp_data <= 8'd128; 334 chirp_valid <= 0; 335 chirp_done <= 0; 336 rf_switch_ctrl <= 0; 337 {adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4} <= 4'b0000; 338 sample_counter <= 0; 339 end 340 end 341 342 // Helper function to get max counter for each state 343 function [15:0] get_max_counter; 344 input [2:0] state; 345 begin 346 case (state) 347 LONG_CHIRP: get_max_counter = T1_SAMPLES; 348 LONG_LISTEN: get_max_counter = T1_RADAR_LISTENING; 349 GUARD_TIME: get_max_counter = GUARD_SAMPLES; 350 SHORT_CHIRP: get_max_counter = T2_SAMPLES; 351 SHORT_LISTEN: get_max_counter = T2_RADAR_LISTENING; 352 default: get_max_counter = 0; 353 endcase 354 end 355 endfunction 356 357 endmodule