|
|
@@ -0,0 +1,342 @@
|
|
|
+`timescale 1ns/1ps
|
|
|
+
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
+// pwm_trace_top - 8-input passive equipment Trace firmware
|
|
|
+//
|
|
|
+// J6 trace inputs (raw 3.3 V FPGA I/O):
|
|
|
+// heater, fan, motor1, motor2, motor3, limit1, limit2, limit3
|
|
|
+//
|
|
|
+// The five actuator/control lines are measured as generic digital pulse/PWM
|
|
|
+// signals (count/period/high-time). Their synchronized current level is also
|
|
|
+// reported, which makes static LOW and static HIGH observable.
|
|
|
+//
|
|
|
+// The three limit inputs are reported as raw synchronized levels, plus sticky
|
|
|
+// rising/falling flags since the previous report snapshot. No active-high or
|
|
|
+// active-low semantic assumption is made here.
|
|
|
+//
|
|
|
+// UART stays on the existing J5 signal. Protocol remains the 16-byte 0x82
|
|
|
+// packet format. At 115200 baud one 16-packet snapshot needs about 22.2 ms on
|
|
|
+// the wire, therefore the production report interval is 50 ms (not the old
|
|
|
+// single-channel 10 ms interval).
|
|
|
+// -----------------------------------------------------------------------------
|
|
|
+module pwm_trace_top #(
|
|
|
+ parameter integer CLOCK_HZ = 25_000_000,
|
|
|
+ parameter integer BAUD = 115_200,
|
|
|
+ parameter integer REPORT_MS = 50
|
|
|
+)(
|
|
|
+ input wire sys_clk,
|
|
|
+ input wire reset_n,
|
|
|
+
|
|
|
+ input wire trace_heater,
|
|
|
+ input wire trace_fan,
|
|
|
+ input wire trace_motor1,
|
|
|
+ input wire trace_motor2,
|
|
|
+ input wire trace_motor3,
|
|
|
+ input wire trace_limit1,
|
|
|
+ input wire trace_limit2,
|
|
|
+ input wire trace_limit3,
|
|
|
+
|
|
|
+ output wire uart_tx,
|
|
|
+ output wire led_activity_n
|
|
|
+);
|
|
|
+
|
|
|
+ localparam [7:0] PKT_TRACE = 8'h82;
|
|
|
+
|
|
|
+ localparam [15:0] EVT_HEATER_COUNT = 16'h5101;
|
|
|
+ localparam [15:0] EVT_HEATER_PERIOD = 16'h5102;
|
|
|
+ localparam [15:0] EVT_HEATER_HIGH = 16'h5103;
|
|
|
+
|
|
|
+ localparam [15:0] EVT_FAN_COUNT = 16'h5111;
|
|
|
+ localparam [15:0] EVT_FAN_PERIOD = 16'h5112;
|
|
|
+ localparam [15:0] EVT_FAN_HIGH = 16'h5113;
|
|
|
+
|
|
|
+ localparam [15:0] EVT_MOTOR1_COUNT = 16'h5121;
|
|
|
+ localparam [15:0] EVT_MOTOR1_PERIOD = 16'h5122;
|
|
|
+ localparam [15:0] EVT_MOTOR1_HIGH = 16'h5123;
|
|
|
+
|
|
|
+ localparam [15:0] EVT_MOTOR2_COUNT = 16'h5131;
|
|
|
+ localparam [15:0] EVT_MOTOR2_PERIOD = 16'h5132;
|
|
|
+ localparam [15:0] EVT_MOTOR2_HIGH = 16'h5133;
|
|
|
+
|
|
|
+ localparam [15:0] EVT_MOTOR3_COUNT = 16'h5141;
|
|
|
+ localparam [15:0] EVT_MOTOR3_PERIOD = 16'h5142;
|
|
|
+ localparam [15:0] EVT_MOTOR3_HIGH = 16'h5143;
|
|
|
+
|
|
|
+ // Status data layout:
|
|
|
+ // [ 7: 0] raw synchronized levels:
|
|
|
+ // bit0 heater, bit1 fan, bit2 motor1, bit3 motor2,
|
|
|
+ // bit4 motor3, bit5 limit1, bit6 limit2, bit7 limit3
|
|
|
+ // [12: 8] valid period/high flags for heater..motor3
|
|
|
+ // [17:13] recent-edge/present flags for heater..motor3
|
|
|
+ // [20:18] limit1..3 rising edge seen since previous snapshot
|
|
|
+ // [23:21] limit1..3 falling edge seen since previous snapshot
|
|
|
+ // [31:24] reserved = 0
|
|
|
+ localparam [15:0] EVT_DIGITAL_STATUS = 16'h5200;
|
|
|
+
|
|
|
+ localparam integer TICKS_PER_MS = CLOCK_HZ / 1000;
|
|
|
+ localparam integer REPORT_TICKS = TICKS_PER_MS * REPORT_MS;
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // Five generic PWM/pulse trace channels.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ wire [31:0] heater_count, heater_period, heater_high;
|
|
|
+ wire [31:0] fan_count, fan_period, fan_high;
|
|
|
+ wire [31:0] motor1_count, motor1_period, motor1_high;
|
|
|
+ wire [31:0] motor2_count, motor2_period, motor2_high;
|
|
|
+ wire [31:0] motor3_count, motor3_period, motor3_high;
|
|
|
+
|
|
|
+ wire heater_valid, fan_valid, motor1_valid, motor2_valid, motor3_valid;
|
|
|
+ wire heater_present, fan_present, motor1_present, motor2_present, motor3_present;
|
|
|
+ wire heater_level, fan_level, motor1_level, motor2_level, motor3_level;
|
|
|
+
|
|
|
+ pwm_trace_measure #(.CLK_HZ(CLOCK_HZ), .NO_SIGNAL_MS(100)) u_heater (
|
|
|
+ .clk(sys_clk), .reset_n(reset_n), .signal_in(trace_heater),
|
|
|
+ .edge_count(heater_count), .period_ticks(heater_period), .high_ticks(heater_high),
|
|
|
+ .measurement_valid(heater_valid), .signal_present(heater_present), .signal_level(heater_level)
|
|
|
+ );
|
|
|
+
|
|
|
+ pwm_trace_measure #(.CLK_HZ(CLOCK_HZ), .NO_SIGNAL_MS(100)) u_fan (
|
|
|
+ .clk(sys_clk), .reset_n(reset_n), .signal_in(trace_fan),
|
|
|
+ .edge_count(fan_count), .period_ticks(fan_period), .high_ticks(fan_high),
|
|
|
+ .measurement_valid(fan_valid), .signal_present(fan_present), .signal_level(fan_level)
|
|
|
+ );
|
|
|
+
|
|
|
+ pwm_trace_measure #(.CLK_HZ(CLOCK_HZ), .NO_SIGNAL_MS(100)) u_motor1 (
|
|
|
+ .clk(sys_clk), .reset_n(reset_n), .signal_in(trace_motor1),
|
|
|
+ .edge_count(motor1_count), .period_ticks(motor1_period), .high_ticks(motor1_high),
|
|
|
+ .measurement_valid(motor1_valid), .signal_present(motor1_present), .signal_level(motor1_level)
|
|
|
+ );
|
|
|
+
|
|
|
+ pwm_trace_measure #(.CLK_HZ(CLOCK_HZ), .NO_SIGNAL_MS(100)) u_motor2 (
|
|
|
+ .clk(sys_clk), .reset_n(reset_n), .signal_in(trace_motor2),
|
|
|
+ .edge_count(motor2_count), .period_ticks(motor2_period), .high_ticks(motor2_high),
|
|
|
+ .measurement_valid(motor2_valid), .signal_present(motor2_present), .signal_level(motor2_level)
|
|
|
+ );
|
|
|
+
|
|
|
+ pwm_trace_measure #(.CLK_HZ(CLOCK_HZ), .NO_SIGNAL_MS(100)) u_motor3 (
|
|
|
+ .clk(sys_clk), .reset_n(reset_n), .signal_in(trace_motor3),
|
|
|
+ .edge_count(motor3_count), .period_ticks(motor3_period), .high_ticks(motor3_high),
|
|
|
+ .measurement_valid(motor3_valid), .signal_present(motor3_present), .signal_level(motor3_level)
|
|
|
+ );
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // Limit switches: raw synchronized levels and sticky transition flags.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ wire [2:0] limit_level;
|
|
|
+ wire [2:0] limit_rise_seen;
|
|
|
+ wire [2:0] limit_fall_seen;
|
|
|
+ reg limit_clear_seen;
|
|
|
+
|
|
|
+ limit_trace_capture u_limits (
|
|
|
+ .clk (sys_clk),
|
|
|
+ .reset_n (reset_n),
|
|
|
+ .limit_in ({trace_limit3, trace_limit2, trace_limit1}),
|
|
|
+ .clear_seen(limit_clear_seen),
|
|
|
+ .level (limit_level),
|
|
|
+ .rise_seen (limit_rise_seen),
|
|
|
+ .fall_seen (limit_fall_seen)
|
|
|
+ );
|
|
|
+
|
|
|
+ assign led_activity_n = ~(
|
|
|
+ heater_present | fan_present | motor1_present | motor2_present | motor3_present |
|
|
|
+ heater_level | fan_level | motor1_level | motor2_level | motor3_level |
|
|
|
+ |limit_level
|
|
|
+ );
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // Millisecond timestamp.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ reg [31:0] ms_div;
|
|
|
+ reg [31:0] timestamp_ms;
|
|
|
+
|
|
|
+ always @(posedge sys_clk or negedge reset_n) begin
|
|
|
+ if (!reset_n) begin
|
|
|
+ ms_div <= 32'd0;
|
|
|
+ timestamp_ms <= 32'd0;
|
|
|
+ end else if (ms_div == TICKS_PER_MS - 1) begin
|
|
|
+ ms_div <= 32'd0;
|
|
|
+ timestamp_ms <= timestamp_ms + 1'b1;
|
|
|
+ end else begin
|
|
|
+ ms_div <= ms_div + 1'b1;
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // Periodic report trigger.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ reg [31:0] report_counter;
|
|
|
+ reg report_tick;
|
|
|
+
|
|
|
+ always @(posedge sys_clk or negedge reset_n) begin
|
|
|
+ if (!reset_n) begin
|
|
|
+ report_counter <= 32'd0;
|
|
|
+ report_tick <= 1'b0;
|
|
|
+ end else begin
|
|
|
+ report_tick <= 1'b0;
|
|
|
+ if (report_counter == REPORT_TICKS - 1) begin
|
|
|
+ report_counter <= 32'd0;
|
|
|
+ report_tick <= 1'b1;
|
|
|
+ end else begin
|
|
|
+ report_counter <= report_counter + 1'b1;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // Atomic snapshot registers.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ reg [31:0] snap_heater_count, snap_heater_period, snap_heater_high;
|
|
|
+ reg [31:0] snap_fan_count, snap_fan_period, snap_fan_high;
|
|
|
+ reg [31:0] snap_motor1_count, snap_motor1_period, snap_motor1_high;
|
|
|
+ reg [31:0] snap_motor2_count, snap_motor2_period, snap_motor2_high;
|
|
|
+ reg [31:0] snap_motor3_count, snap_motor3_period, snap_motor3_high;
|
|
|
+ reg [31:0] snap_status;
|
|
|
+ reg [31:0] snap_time;
|
|
|
+
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ // UART packet burst: 15 measurement packets + 1 status packet.
|
|
|
+ // -------------------------------------------------------------------------
|
|
|
+ reg [15:0] packet_seq;
|
|
|
+ reg [4:0] burst_index;
|
|
|
+ reg burst_active;
|
|
|
+ reg packet_start;
|
|
|
+ reg [15:0] packet_event;
|
|
|
+ reg [31:0] packet_data;
|
|
|
+ wire packet_busy;
|
|
|
+
|
|
|
+ trace_packet_tx #(
|
|
|
+ .CLOCK_HZ(CLOCK_HZ),
|
|
|
+ .BAUD(BAUD)
|
|
|
+ ) u_packet_tx (
|
|
|
+ .clk (sys_clk),
|
|
|
+ .reset_n (reset_n),
|
|
|
+ .start (packet_start),
|
|
|
+ .packet_type(PKT_TRACE),
|
|
|
+ .seq (packet_seq),
|
|
|
+ .event_id (packet_event),
|
|
|
+ .timestamp (snap_time),
|
|
|
+ .data (packet_data),
|
|
|
+ .uart_tx (uart_tx),
|
|
|
+ .busy (packet_busy)
|
|
|
+ );
|
|
|
+
|
|
|
+ always @(posedge sys_clk or negedge reset_n) begin
|
|
|
+ if (!reset_n) begin
|
|
|
+ snap_heater_count <= 32'd0; snap_heater_period <= 32'd0; snap_heater_high <= 32'd0;
|
|
|
+ snap_fan_count <= 32'd0; snap_fan_period <= 32'd0; snap_fan_high <= 32'd0;
|
|
|
+ snap_motor1_count <= 32'd0; snap_motor1_period <= 32'd0; snap_motor1_high <= 32'd0;
|
|
|
+ snap_motor2_count <= 32'd0; snap_motor2_period <= 32'd0; snap_motor2_high <= 32'd0;
|
|
|
+ snap_motor3_count <= 32'd0; snap_motor3_period <= 32'd0; snap_motor3_high <= 32'd0;
|
|
|
+ snap_status <= 32'd0;
|
|
|
+ snap_time <= 32'd0;
|
|
|
+
|
|
|
+ packet_seq <= 16'd0;
|
|
|
+ burst_index <= 5'd0;
|
|
|
+ burst_active <= 1'b0;
|
|
|
+ packet_start <= 1'b0;
|
|
|
+ packet_event <= 16'd0;
|
|
|
+ packet_data <= 32'd0;
|
|
|
+ limit_clear_seen <= 1'b0;
|
|
|
+ end else begin
|
|
|
+ packet_start <= 1'b0;
|
|
|
+ limit_clear_seen <= 1'b0;
|
|
|
+
|
|
|
+ // Accept a new snapshot only when the entire previous UART burst
|
|
|
+ // has completed. This prevents overlapping timestamps/data.
|
|
|
+ if (report_tick && !burst_active && !packet_busy) begin
|
|
|
+ snap_heater_count <= heater_count;
|
|
|
+ snap_fan_count <= fan_count;
|
|
|
+ snap_motor1_count <= motor1_count;
|
|
|
+ snap_motor2_count <= motor2_count;
|
|
|
+ snap_motor3_count <= motor3_count;
|
|
|
+
|
|
|
+ if (heater_valid && heater_present) begin
|
|
|
+ snap_heater_period <= heater_period;
|
|
|
+ snap_heater_high <= heater_high;
|
|
|
+ end else begin
|
|
|
+ snap_heater_period <= 32'd0;
|
|
|
+ snap_heater_high <= 32'd0;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (fan_valid && fan_present) begin
|
|
|
+ snap_fan_period <= fan_period;
|
|
|
+ snap_fan_high <= fan_high;
|
|
|
+ end else begin
|
|
|
+ snap_fan_period <= 32'd0;
|
|
|
+ snap_fan_high <= 32'd0;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (motor1_valid && motor1_present) begin
|
|
|
+ snap_motor1_period <= motor1_period;
|
|
|
+ snap_motor1_high <= motor1_high;
|
|
|
+ end else begin
|
|
|
+ snap_motor1_period <= 32'd0;
|
|
|
+ snap_motor1_high <= 32'd0;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (motor2_valid && motor2_present) begin
|
|
|
+ snap_motor2_period <= motor2_period;
|
|
|
+ snap_motor2_high <= motor2_high;
|
|
|
+ end else begin
|
|
|
+ snap_motor2_period <= 32'd0;
|
|
|
+ snap_motor2_high <= 32'd0;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (motor3_valid && motor3_present) begin
|
|
|
+ snap_motor3_period <= motor3_period;
|
|
|
+ snap_motor3_high <= motor3_high;
|
|
|
+ end else begin
|
|
|
+ snap_motor3_period <= 32'd0;
|
|
|
+ snap_motor3_high <= 32'd0;
|
|
|
+ end
|
|
|
+
|
|
|
+ snap_status <= {
|
|
|
+ 8'd0,
|
|
|
+ limit_fall_seen,
|
|
|
+ limit_rise_seen,
|
|
|
+ motor3_present, motor2_present, motor1_present, fan_present, heater_present,
|
|
|
+ motor3_valid, motor2_valid, motor1_valid, fan_valid, heater_valid,
|
|
|
+ limit_level[2], limit_level[1], limit_level[0],
|
|
|
+ motor3_level, motor2_level, motor1_level, fan_level, heater_level
|
|
|
+ };
|
|
|
+
|
|
|
+ snap_time <= timestamp_ms;
|
|
|
+ burst_index <= 5'd0;
|
|
|
+ burst_active <= 1'b1;
|
|
|
+ limit_clear_seen <= 1'b1;
|
|
|
+ end
|
|
|
+
|
|
|
+ if (burst_active && !packet_busy && !packet_start) begin
|
|
|
+ case (burst_index)
|
|
|
+ 5'd0: begin packet_event <= EVT_HEATER_COUNT; packet_data <= snap_heater_count; end
|
|
|
+ 5'd1: begin packet_event <= EVT_HEATER_PERIOD; packet_data <= snap_heater_period; end
|
|
|
+ 5'd2: begin packet_event <= EVT_HEATER_HIGH; packet_data <= snap_heater_high; end
|
|
|
+ 5'd3: begin packet_event <= EVT_FAN_COUNT; packet_data <= snap_fan_count; end
|
|
|
+ 5'd4: begin packet_event <= EVT_FAN_PERIOD; packet_data <= snap_fan_period; end
|
|
|
+ 5'd5: begin packet_event <= EVT_FAN_HIGH; packet_data <= snap_fan_high; end
|
|
|
+ 5'd6: begin packet_event <= EVT_MOTOR1_COUNT; packet_data <= snap_motor1_count; end
|
|
|
+ 5'd7: begin packet_event <= EVT_MOTOR1_PERIOD; packet_data <= snap_motor1_period; end
|
|
|
+ 5'd8: begin packet_event <= EVT_MOTOR1_HIGH; packet_data <= snap_motor1_high; end
|
|
|
+ 5'd9: begin packet_event <= EVT_MOTOR2_COUNT; packet_data <= snap_motor2_count; end
|
|
|
+ 5'd10: begin packet_event <= EVT_MOTOR2_PERIOD; packet_data <= snap_motor2_period; end
|
|
|
+ 5'd11: begin packet_event <= EVT_MOTOR2_HIGH; packet_data <= snap_motor2_high; end
|
|
|
+ 5'd12: begin packet_event <= EVT_MOTOR3_COUNT; packet_data <= snap_motor3_count; end
|
|
|
+ 5'd13: begin packet_event <= EVT_MOTOR3_PERIOD; packet_data <= snap_motor3_period; end
|
|
|
+ 5'd14: begin packet_event <= EVT_MOTOR3_HIGH; packet_data <= snap_motor3_high; end
|
|
|
+ default: begin packet_event <= EVT_DIGITAL_STATUS; packet_data <= snap_status; end
|
|
|
+ endcase
|
|
|
+
|
|
|
+ packet_start <= 1'b1;
|
|
|
+ packet_seq <= packet_seq + 1'b1;
|
|
|
+
|
|
|
+ if (burst_index == 5'd15) begin
|
|
|
+ burst_active <= 1'b0;
|
|
|
+ burst_index <= 5'd0;
|
|
|
+ end else begin
|
|
|
+ burst_index <= burst_index + 1'b1;
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+endmodule
|