114 lines
4.3 KiB
Verilog
114 lines
4.3 KiB
Verilog
// de_monitor.v
|
|
//
|
|
// Monitors DE timing on the pixel-clock side (RxCLKOUT, ~72 MHz).
|
|
//
|
|
// - Counts DE rising edges per frame.
|
|
// - Counts pixel-clock cycles per DE active interval (line width).
|
|
// - Frame boundary is declared when DE has been idle longer than one
|
|
// line period (the gap between the last active line and the first
|
|
// line of the next frame is the vertical blanking interval, which is
|
|
// many line periods long; any intra-frame gap is shorter than one
|
|
// line period).
|
|
// - Flags an anomaly if the just-finished frame had lines != EXPECTED_LINES,
|
|
// or if any line in the frame had width != EXPECTED_WIDTH.
|
|
//
|
|
// Outputs on `frame_done` (1 pix_clk pulse):
|
|
// lines_o - lines counted in the frame that just ended
|
|
// width_o - width of the offending line if any width was wrong,
|
|
// otherwise the width of the last line in the frame
|
|
// anomaly_o - 1 if lines_o != EXPECTED_LINES or any width was wrong
|
|
//
|
|
// Assumes DE is active-high (DS90CF386 default for the Ampire panel).
|
|
|
|
module de_monitor #(
|
|
parameter [15:0] EXPECTED_LINES = 16'd800,
|
|
parameter [15:0] EXPECTED_WIDTH = 16'd1280,
|
|
// Idle-gap threshold for declaring "end of frame". Must be larger
|
|
// than one full line period in pixel clocks (~1432 for this panel)
|
|
// and smaller than the vertical blanking interval (~54k pixels).
|
|
parameter [15:0] FRAME_GAP_PIX = 16'd2048
|
|
)(
|
|
input wire pix_clk,
|
|
input wire rst_n,
|
|
input wire de,
|
|
|
|
output reg frame_done, // 1 pix_clk pulse
|
|
output reg [15:0] lines_o,
|
|
output reg [15:0] width_o,
|
|
output reg anomaly_o
|
|
);
|
|
|
|
reg de_q;
|
|
wire de_rise = de & ~de_q;
|
|
wire de_fall = ~de & de_q;
|
|
|
|
reg [15:0] line_width; // running width of current DE-high interval
|
|
reg [15:0] last_width; // width of most recent completed line
|
|
reg [15:0] bad_width; // sticky: width of first wrong-width line in frame
|
|
reg any_bad_width; // sticky: at least one wrong-width line this frame
|
|
|
|
reg [15:0] line_count; // lines seen so far in current frame
|
|
reg [15:0] gap_count; // pixel-clocks since DE last fell
|
|
reg frame_active; // we have seen at least one DE this frame
|
|
|
|
always @(posedge pix_clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
de_q <= 1'b0;
|
|
line_width <= 16'd0;
|
|
last_width <= 16'd0;
|
|
bad_width <= 16'd0;
|
|
any_bad_width <= 1'b0;
|
|
line_count <= 16'd0;
|
|
gap_count <= 16'd0;
|
|
frame_active <= 1'b0;
|
|
frame_done <= 1'b0;
|
|
lines_o <= 16'd0;
|
|
width_o <= 16'd0;
|
|
anomaly_o <= 1'b0;
|
|
end else begin
|
|
de_q <= de;
|
|
frame_done <= 1'b0;
|
|
|
|
// --- per-line width measurement ---
|
|
if (de_rise) begin
|
|
line_width <= 16'd1;
|
|
end else if (de) begin
|
|
line_width <= line_width + 16'd1;
|
|
end
|
|
|
|
if (de_fall) begin
|
|
last_width <= line_width;
|
|
if (line_width != EXPECTED_WIDTH && !any_bad_width) begin
|
|
bad_width <= line_width;
|
|
any_bad_width <= 1'b1;
|
|
end
|
|
end
|
|
|
|
// --- line counting & frame-boundary detection ---
|
|
if (de_rise) begin
|
|
line_count <= line_count + 16'd1;
|
|
frame_active <= 1'b1;
|
|
gap_count <= 16'd0;
|
|
end else if (!de) begin
|
|
if (gap_count != 16'hFFFF) gap_count <= gap_count + 16'd1;
|
|
|
|
// End of frame: long DE-idle after at least one line.
|
|
if (frame_active && gap_count == FRAME_GAP_PIX) begin
|
|
frame_done <= 1'b1;
|
|
lines_o <= line_count;
|
|
width_o <= any_bad_width ? bad_width : last_width;
|
|
anomaly_o <= (line_count != EXPECTED_LINES) || any_bad_width;
|
|
|
|
// reset frame state
|
|
line_count <= 16'd0;
|
|
gap_count <= 16'd0;
|
|
any_bad_width <= 1'b0;
|
|
bad_width <= 16'd0;
|
|
frame_active <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|