`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2025/08/04 18:50:44
// Design Name:
// Module Name: img_data_pkt
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module img_data_pkt(
input rst_n , //复位信号,低电平有效
//图像相关信号
input cam_pclk , //像素时钟
input cam_vsync , //帧同步信号
input cam_href , //行同步信号
input [7 :0] cam_data , //有效数据
input transfer_flag , //图像开始传输标志,1:开始传输 0:停止传输
//以太网相关信号
input eth_tx_clk , //以太网发送时钟
input udp_tx_req , //udp 发送数据请求信号 ,读fifo数据请求信号。
input udp_tx_done , //udp 发送数据完成信号
output reg udp_tx_start_en, //udp 开始发送信号
output [7 :0] udp_tx_data , //udp 发送的数据
output reg [15:0] udp_tx_byte_num //udp 单包发送的有效字节数
);
//图像帧头,用于标志一帧数据的开始
parameter IMG_FRAME_HEAD = {32'hf0_5a_a5_0f};
parameter CMOS_H_PIXEL = 16'd640; //图像水平方向分辨率
parameter CMOS_V_PIXEL = 16'd480; //图像垂直方向分辨率
reg cam_vsync_d0,cam_vsync_d1;
wire neg_cam_vsync;
assign neg_cam_vsync=(~cam_vsync_d0)&cam_vsync_d1;
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin
cam_vsync_d0 <= 1'b0;
cam_vsync_d1 <= 1'b0;
end
else begin
cam_vsync_d0 <= cam_vsync;
cam_vsync_d1 <= cam_vsync_d0;
end
end
reg cam_href_d0,cam_href_d1;
wire neg_cam_href;
assign neg_cam_href=(~cam_href_d0)&cam_href_d1; //?? delete
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin
cam_href_d0 <= 1'b0;
cam_href_d1 <= 1'b0;
end
else begin
cam_href_d0 <= cam_href;
cam_href_d1 <= cam_href_d0;
end
end
reg transfer_flag_d0,transfer_flag_d1; //在cam_pclk时钟域下进行两级寄存器同步
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin
transfer_flag_d0 <= 1'b0;
transfer_flag_d1 <= 1'b0;
end
else begin
transfer_flag_d0 <= transfer_flag;
transfer_flag_d1 <= transfer_flag_d0;
end
end
reg udp_tx_done_d0,udp_tx_done_d1; //在cam_pclk时钟域下进行两级寄存器同步
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin
udp_tx_done_d0 <= 1'b0;
udp_tx_done_d1 <= 1'b0;
end
else begin
udp_tx_done_d0 <= udp_tx_done;
udp_tx_done_d1 <= udp_tx_done_d0;
end
end
reg first_line;
always @(posedge cam_pclk or negedge rst_n) begin //帧同步信号下降沿之后到第一个tx_done之间拉高
if(!rst_n)
first_line <= 1'b0;
else if(!transfer_flag_d1)
first_line <= 1'b0;
else if(neg_cam_vsync)
first_line <= 1'b1;
else if(udp_tx_done_d1)
first_line <= 1'b0;
end
reg [3:0] neg_cam_vsync_cnt; //帧同步信号下降沿之后开始计数
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n)
neg_cam_vsync_cnt <= 1'b0;
else if(neg_cam_vsync_cnt==4'd9)
neg_cam_vsync_cnt <= neg_cam_vsync_cnt;
else if(neg_cam_vsync)
neg_cam_vsync_cnt <= neg_cam_vsync_cnt+1'd1;
end
wire fifo_rst;
assign fifo_rst=!rst_n&transfer_flag_d1&!neg_cam_vsync;
reg wr_en;
reg [7:0] din;
reg [7:0]frame_head_t[7:0];
always @(posedge cam_pclk or negedge rst_n) begin
if(!rst_n) begin
wr_en <= 1'b0;
din <= 8'd0;
frame_head_t[0]<=IMG_FRAME_HEAD[31:24];
frame_head_t[1]<=IMG_FRAME_HEAD[23:16];
frame_head_t[2]<=IMG_FRAME_HEAD[15:8];
frame_head_t[3]<=IMG_FRAME_HEAD[7:0];
frame_head_t[4]<=CMOS_H_PIXEL[15:8];
frame_head_t[5]<=CMOS_H_PIXEL[7:0];
frame_head_t[6]<=CMOS_V_PIXEL[15:8];
frame_head_t[7]<=CMOS_V_PIXEL[7:0];
end
else if(transfer_flag_d1) begin
if(neg_cam_vsync_cnt>=4'd1&&neg_cam_vsync_cnt<=4'd8) begin
wr_en <= 1'b1;
din <= frame_head_t[neg_cam_vsync_cnt-1];
end
else if(cam_href) begin
wr_en <= 1'b1;
din <= cam_data;
end
else begin
wr_en <= 1'b0;
din <= 8'd0;
end
end
else begin
wr_en <= 1'b0;
din <= 8'd0;
end
end
reg first_line_d0,first_line_d1; //在eth_tx_clk时钟域下进行两级寄存器同步
always @(posedge eth_tx_clk or negedge rst_n) begin
if(!rst_n) begin
first_line_d0 <= 1'b0;
first_line_d1 <= 1'b0;
end
else begin
first_line_d0 <= first_line;
first_line_d1 <= first_line_d0;
end
end
always @(posedge eth_tx_clk or negedge rst_n) begin
if(!rst_n)
udp_tx_byte_num <= (CMOS_H_PIXEL<<1);
else if(first_line_d1)
udp_tx_byte_num <= (CMOS_H_PIXEL<<1)+8; //第一行时发生的字节数要加上8个字节的帧头数
else
udp_tx_byte_num <= (CMOS_H_PIXEL<<1);
end
reg eth_tx_busy;
always @(posedge eth_tx_clk or negedge rst_n) begin
if(!rst_n)
eth_tx_busy <= 1'b0;
else if(udp_tx_start_en)
eth_tx_busy <= 1'b1;
else if(udp_tx_done)
eth_tx_busy <= 1'b0;
end
wire [10:0] wr_data_count,rd_data_count;
always @(posedge eth_tx_clk or negedge rst_n) begin
if(!rst_n)
udp_tx_start_en <= 1'b0;
else if((!eth_tx_busy)&&rd_data_count>=udp_tx_byte_num)
udp_tx_start_en <= 1'b1;
else
udp_tx_start_en <= 1'b0;
end
async_2048_8bit u_async_2048_8bit (
.rst(fifo_rst), // input wire rst
.wr_clk(cam_pclk), // input wire wr_clk
.rd_clk(eth_tx_clk), // input wire rd_clk
.din(din), // input wire [7 : 0] din
.wr_en(wr_en), // input wire wr_en
.rd_en(udp_tx_req), // input wire rd_en
.dout(udp_tx_data), // output wire [7 : 0] dout
.full(), // output wire full
.empty(), // output wire empty
.rd_data_count(rd_data_count), // output wire [10 : 0] rd_data_count
.wr_data_count(wr_data_count), // output wire [10 : 0] wr_data_count
.wr_rst_busy(), // output wire wr_rst_busy
.rd_rst_busy() // output wire rd_rst_busy
);
endmodule