FPGA ov5640视频以太网传输

2024-05-09 04:20

本文主要是介绍FPGA ov5640视频以太网传输,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 实验任务

使用DFZU4EV MPSoC 开发板及双目OV5640摄像头其中一个摄像头实现图像采集,并通过开发板上的以太网接口发送给上位机实时显示。

2 Verilog代码

2.1 顶层模块

`timescale 1ns / 1ps
//以太网传输视频顶层模块module ov5640_udp_pc (input        sys_clk_p,   //系统时钟  input        sys_clk_n,   //系统时钟input        sys_rst_n,   //系统复位信号,低电平有效 //以太网接口input        eth_rxc,     //RGMII接收数据时钟input        eth_rx_ctl,  //RGMII输入数据有效信号input  [3:0] eth_rxd,     //RGMII输入数据output       eth_txc,     //RGMII发送数据时钟    output       eth_tx_ctl,  //RGMII输出数据有效信号output [3:0] eth_txd,     //RGMII输出数据           //摄像头接口                       input        cam_pclk,   //cmos 数据像素时钟input        cam_vsync,  //cmos 场同步信号input        cam_href,   //cmos 行同步信号input  [7:0] cam_data,   //cmos 数据output       cam_rst_n,  //cmos 复位信号,低电平有效output       cam_pwdn,   //电源休眠模式选择 0:正常模式 1:电源休眠模式output       cam_scl,    //cmos SCCB_SCL线inout        cam_sda     //cmos SCCB_SDA线      
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};parameter H_CMOS_DISP = 11'd640;  //CMOS分辨率--行parameter V_CMOS_DISP = 11'd480;  //CMOS分辨率--列	parameter TOTAL_H_PIXEL = H_CMOS_DISP + 12'd1216;  //水平总像素大小parameter TOTAL_V_PIXEL = V_CMOS_DISP + 12'd504;  //垂直总像素大小//wire definewire        clk_100m;  //100Mhz时钟wire        eth_tx_clk;  //以太网发送时钟wire        cmos_frame_vsync;  //输出帧有效场同步信号   wire        img_data_en;  //摄像头图像有效信号wire [15:0] img_data;  //摄像头图像有效数据wire        transfer_flag;  //图像开始传输标志,0:开始传输 1:停止传输wire        eth_rx_clk;  //以太网接收时钟wire        udp_tx_start_en;  //以太网开始发送信号wire [15:0] udp_tx_byte_num;  //以太网发送的有效字节数wire [31:0] udp_tx_data;  //以太网发送的数据    wire        udp_rec_pkt_done;  //以太网单包数据接收完成信号wire        udp_rec_en;  //以太网接收使能信号wire [31:0] udp_rec_data;  //以太网接收到的数据wire [15:0] udp_rec_byte_num;  //以太网接收到的字节个数wire        udp_tx_req;  //以太网发送请求数据信号wire        udp_tx_done;  //以太网发送完成信号//*****************************************************//**                    main code//*****************************************************IBUFDS diff_clock (.I (sys_clk_p),  //系统差分输入时钟.IB(sys_clk_n),  //系统差分输入时钟.O (clk_100m)    //输出系统时钟);ov5640_dri u_ov5640_dri (.clk(clk_100m),  //时钟.rst_n(sys_rst_n),  //复位信号,低电平有效//摄像头接口 .cam_pclk(cam_pclk),  //cmos 数据像素时钟.cam_vsync(cam_vsync),  //cmos 场同步信号.cam_href(cam_href),  //cmos 行同步信号.cam_data(cam_data),  //cmos 数据  .cam_rst_n(cam_rst_n),  //cmos 复位信号,低电平有效.cam_pwdn(cam_pwdn),  //cmos 电源休眠模式选择信号.cam_scl(cam_scl),  //cmos SCCB_SCL线.cam_sda(cam_sda),  //cmos SCCB_SDA线   //摄像头分辨率配置接口.cmos_h_pixel(H_CMOS_DISP),  //水平方向分辨率.cmos_v_pixel(V_CMOS_DISP),  //垂直方向分辨率.total_h_pixel(TOTAL_H_PIXEL),  //水平总像素大小.total_v_pixel(TOTAL_V_PIXEL),  //垂直总像素大小.capture_start(),  //图像采集开始信号.cam_init_done(),  //摄像头初始化完成//用户接口.cmos_frame_vsync(cmos_frame_vsync),  //帧有效信号    .cmos_frame_href(),  //行有效信号.cmos_frame_valid(img_data_en),  //数据有效使能信号.cmos_frame_data(img_data)  //有效数据  );//开始传输控制模块   start_transfer_ctrl u_start_transfer_ctrl (.clk             (eth_rx_clk),.rst_n           (sys_rst_n),.udp_rec_pkt_done(udp_rec_pkt_done),.udp_rec_en      (udp_rec_en),.udp_rec_data    (udp_rec_data),.udp_rec_byte_num(udp_rec_byte_num),.transfer_flag   (transfer_flag)      //图像开始传输标志,1:开始传输 0:停止传输);//图像封装模块     img_data_pkt u_img_data_pkt (.rst_n          (sys_rst_n),.cam_pclk       (cam_pclk),.img_vsync      (cmos_frame_vsync),.img_data_en    (img_data_en),.img_data       (img_data),.transfer_flag  (transfer_flag),.eth_tx_clk     (eth_tx_clk),.udp_tx_req     (udp_tx_req),.udp_tx_done    (udp_tx_done),.udp_tx_start_en(udp_tx_start_en),.udp_tx_data    (udp_tx_data),.udp_tx_byte_num(udp_tx_byte_num));//以太网顶层模块    eth_top #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP),.DES_MAC  (DES_MAC),.DES_IP   (DES_IP)) u_eth_top (.sys_rst_n (sys_rst_n),   //系统复位信号,低电平有效            //以太网RGMII接口             .eth_rxc   (eth_rxc),     //RGMII接收数据时钟.eth_rx_ctl(eth_rx_ctl),  //RGMII输入数据有效信号.eth_rxd   (eth_rxd),     //RGMII输入数据.eth_txc   (eth_txc),     //RGMII发送数据时钟    .eth_tx_ctl(eth_tx_ctl),  //RGMII输出数据有效信号.eth_txd   (eth_txd),     //RGMII输出数据          .gmii_rx_clk    (eth_rx_clk),.gmii_tx_clk    (eth_tx_clk),.udp_tx_start_en(udp_tx_start_en),.tx_data        (udp_tx_data),.tx_byte_num    (udp_tx_byte_num),.udp_tx_done    (udp_tx_done),.tx_req         (udp_tx_req),.rec_pkt_done   (udp_rec_pkt_done),.rec_en         (udp_rec_en),.rec_data       (udp_rec_data),.rec_byte_num   (udp_rec_byte_num));endmodule

2.2 ov5640顶层驱动模块

`timescale 1ns / 1ps
//ov5640驱动模块module ov5640_dri (input        clk,        //时钟input        rst_n,      //复位信号,低电平有效//摄像头接口 input        cam_pclk,   //cmos 数据像素时钟input        cam_vsync,  //cmos 场同步信号input        cam_href,   //cmos 行同步信号input  [7:0] cam_data,   //cmos 数据  output       cam_rst_n,  //cmos 复位信号,低电平有效output       cam_pwdn,   //cmos 电源休眠模式选择信号output       cam_scl,    //cmos SCCB_SCL线inout        cam_sda,    //cmos SCCB_SDA线   //摄像头分辨率配置接口input  [12:0] cmos_h_pixel,   //水平方向分辨率input  [12:0] cmos_v_pixel,   //垂直方向分辨率input  [12:0] total_h_pixel,  //水平总像素大小input  [12:0] total_v_pixel,  //垂直总像素大小input         capture_start,  //图像采集开始信号output        cam_init_done,  //摄像头初始化完成//用户接口output        cmos_frame_vsync,  //帧有效信号    output        cmos_frame_href,   //行有效信号output        cmos_frame_valid,  //数据有效使能信号output [15:0] cmos_frame_data    //有效数据  
);//parameter defineparameter SLAVE_ADDR = 7'h3c;  //OV5640的器件地址7'h3cparameter BIT_CTRL = 1'b1;  //OV5640的字节地址为16位  0:8位 1:16位parameter CLK_FREQ = 27'd100_000_000;  //i2c_dri模块的驱动时钟频率 parameter I2C_FREQ = 18'd250_000;  //I2C的SCL时钟频率,不超过400KHz//wire difinewire        i2c_exec;  //I2C触发执行信号wire [23:0] i2c_data;  //I2C要配置的地址与数据(高8位地址,低8位数据)          wire        i2c_done;  //I2C寄存器配置完成信号wire        i2c_dri_clk;  //I2C操作时钟wire [ 7:0] i2c_data_r;  //I2C读出的数据wire        i2c_rh_wl;  //I2C读写控制信号//*****************************************************//**                    main code                      //*****************************************************//电源休眠模式选择 0:正常模式 1:电源休眠模式assign cam_pwdn  = 1'b0;assign cam_rst_n = 1'b1;//I2C配置模块i2c_ov5640_rgb565_cfg u_i2c_cfg (.clk  (i2c_dri_clk),.rst_n(rst_n),.i2c_exec  (i2c_exec),.i2c_data  (i2c_data),.i2c_rh_wl (i2c_rh_wl),  //I2C读写控制信号.i2c_done  (i2c_done),.i2c_data_r(i2c_data_r),.cmos_h_pixel (cmos_h_pixel),   //CMOS水平方向像素个数.cmos_v_pixel (cmos_v_pixel),   //CMOS垂直方向像素个数.total_h_pixel(total_h_pixel),  //水平总像素大小.total_v_pixel(total_v_pixel),  //垂直总像素大小.init_done(cam_init_done));//I2C驱动模块i2c_dri #(.SLAVE_ADDR(SLAVE_ADDR),  //参数传递.CLK_FREQ  (CLK_FREQ),.I2C_FREQ  (I2C_FREQ)) u_i2c_dr (.clk  (clk),.rst_n(rst_n),.i2c_exec  (i2c_exec),.bit_ctrl  (BIT_CTRL),.i2c_rh_wl (i2c_rh_wl),       //固定为0,只用到了IIC驱动的写操作   .i2c_addr  (i2c_data[23:8]),.i2c_data_w(i2c_data[7:0]),.i2c_data_r(i2c_data_r),.i2c_done  (i2c_done),.scl    (cam_scl),.sda    (cam_sda),.dri_clk(i2c_dri_clk)  //I2C操作时钟);//CMOS图像数据采集模块cmos_capture_data u_cmos_capture_data (  //系统初始化完成之后再开始采集数据 .rst_n(rst_n & cam_init_done),.cam_pclk (cam_pclk),.cam_vsync(cam_vsync),.cam_href (cam_href),.cam_data (cam_data),.cmos_frame_vsync(cmos_frame_vsync),.cmos_frame_href (cmos_frame_href),.cmos_frame_valid(cmos_frame_valid),  //数据有效使能信号.cmos_frame_data (cmos_frame_data)    //有效数据 );endmodule

2.3 ov5640寄存器配置模块

`timescale 1ns / 1ps
//ov5640寄存器配置模块module i2c_ov5640_rgb565_cfg (input clk,   //时钟信号input rst_n, //复位信号,低电平有效input      [ 7:0] i2c_data_r,     //I2C读出的数据input             i2c_done,       //I2C寄存器配置完成信号input      [12:0] cmos_h_pixel,input      [12:0] cmos_v_pixel,input      [12:0] total_h_pixel,  //水平总像素大小input      [12:0] total_v_pixel,  //垂直总像素大小output reg        i2c_exec,       //I2C触发执行信号   output reg [23:0] i2c_data,       //I2C要配置的地址与数据(高16位地址,低8位数据)output reg        i2c_rh_wl,      //I2C读写控制信号output reg        init_done       //初始化完成信号
);//parameter definelocalparam REG_NUM = 8'd250;  //总共需要配置的寄存器个数//reg definereg [14:0] start_init_cnt;  //等待延时计数器reg [ 7:0] init_reg_cnt;  //寄存器配置个数计数器//*****************************************************//**                    main code//*****************************************************SCL配置成250KHz,输入的clk时钟频率为1Mhz,周期为1us 20000*1us = 20ms//OV5640上电到开始配置SCCB至少等待20msalways @(posedge clk or negedge rst_n) beginif (!rst_n) start_init_cnt <= 1'b0;else if (start_init_cnt < 15'd20000) beginstart_init_cnt <= start_init_cnt + 1'b1;endend//寄存器配置个数计数    always @(posedge clk or negedge rst_n) beginif (!rst_n) init_reg_cnt <= 8'd0;else if (i2c_exec) init_reg_cnt <= init_reg_cnt + 8'b1;end//i2c触发执行信号   always @(posedge clk or negedge rst_n) beginif (!rst_n) i2c_exec <= 1'b0;else if (start_init_cnt == 15'd20000 - 1'b1) i2c_exec <= 1'b1;else if (i2c_done && (init_reg_cnt < REG_NUM)) i2c_exec <= 1'b1;else i2c_exec <= 1'b0;end//配置I2C读写控制信号always @(posedge clk or negedge rst_n) beginif (!rst_n) i2c_rh_wl <= 1'b1;else if (init_reg_cnt == 8'd2) i2c_rh_wl <= 1'b0;end//初始化完成信号always @(posedge clk or negedge rst_n) beginif (!rst_n) init_done <= 1'b0;else if ((init_reg_cnt == REG_NUM) && i2c_done) init_done <= 1'b1;end//配置寄存器地址与数据always @(posedge clk or negedge rst_n) beginif (!rst_n) i2c_data <= 24'b0;else begincase (init_reg_cnt)//先读OV5640 ID8'd0: i2c_data <= {16'h300a, 8'h0};  //8'd1: i2c_data <= {16'h300b, 8'h0};  //8'd2: i2c_data <= {16'h3008, 8'h82};  //Bit[7]:复位 Bit[6]:电源休眠8'd3: i2c_data <= {16'h3008, 8'h02};  //正常工作模式8'd4: i2c_data <= {16'h3103, 8'h02};  //Bit[1]:1 PLL Clock//引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]8'd5: i2c_data <= {8'h30, 8'h17, 8'hff};//引脚输入/输出控制 D[5:0]/GPIO1/GPIO0 8'd6: i2c_data <= {16'h3018, 8'hff};8'd7: i2c_data <= {16'h3037, 8'h13};  //PLL分频控制8'd8: i2c_data <= {16'h3108, 8'h01};  //系统根分频器8'd9: i2c_data <= {16'h3630, 8'h36};8'd10: i2c_data <= {16'h3631, 8'h0e};8'd11: i2c_data <= {16'h3632, 8'he2};8'd12: i2c_data <= {16'h3633, 8'h12};8'd13: i2c_data <= {16'h3621, 8'he0};8'd14: i2c_data <= {16'h3704, 8'ha0};8'd15: i2c_data <= {16'h3703, 8'h5a};8'd16: i2c_data <= {16'h3715, 8'h78};8'd17: i2c_data <= {16'h3717, 8'h01};8'd18: i2c_data <= {16'h370b, 8'h60};8'd19: i2c_data <= {16'h3705, 8'h1a};8'd20: i2c_data <= {16'h3905, 8'h02};8'd21: i2c_data <= {16'h3906, 8'h10};8'd22: i2c_data <= {16'h3901, 8'h0a};8'd23: i2c_data <= {16'h3731, 8'h12};8'd24: i2c_data <= {16'h3600, 8'h08};  //VCM控制,用于自动聚焦8'd25: i2c_data <= {16'h3601, 8'h33};  //VCM控制,用于自动聚焦8'd26: i2c_data <= {16'h302d, 8'h60};  //系统控制8'd27: i2c_data <= {16'h3620, 8'h52};8'd28: i2c_data <= {16'h371b, 8'h20};8'd29: i2c_data <= {16'h471c, 8'h50};8'd30: i2c_data <= {16'h3a13, 8'h43};  //AEC(自动曝光控制)8'd31: i2c_data <= {16'h3a18, 8'h00};  //AEC 增益上限8'd32: i2c_data <= {16'h3a19, 8'hf8};  //AEC 增益上限8'd33: i2c_data <= {16'h3635, 8'h13};8'd34: i2c_data <= {16'h3636, 8'h03};8'd35: i2c_data <= {16'h3634, 8'h40};8'd36: i2c_data <= {16'h3622, 8'h01};8'd37: i2c_data <= {16'h3c01, 8'h34};8'd38: i2c_data <= {16'h3c04, 8'h28};8'd39: i2c_data <= {16'h3c05, 8'h98};8'd40: i2c_data <= {16'h3c06, 8'h00};  //light meter 1 阈值[15:8]8'd41: i2c_data <= {16'h3c07, 8'h08};  //light meter 1 阈值[7:0]8'd42: i2c_data <= {16'h3c08, 8'h00};  //light meter 2 阈值[15:8]8'd43: i2c_data <= {16'h3c09, 8'h1c};  //light meter 2 阈值[7:0]8'd44: i2c_data <= {16'h3c0a, 8'h9c};  //sample number[15:8]8'd45: i2c_data <= {16'h3c0b, 8'h40};  //sample number[7:0]8'd46: i2c_data <= {16'h3810, 8'h00};  //Timing Hoffset[11:8]8'd47: i2c_data <= {16'h3811, 8'h10};  //Timing Hoffset[7:0]8'd48: i2c_data <= {16'h3812, 8'h00};  //Timing Voffset[10:8]8'd49: i2c_data <= {16'h3708, 8'h64};8'd50: i2c_data <= {16'h4001, 8'h02};  //BLC(黑电平校准)补偿起始行号8'd51: i2c_data <= {16'h4005, 8'h1a};  //BLC(黑电平校准)补偿始终更新8'd52: i2c_data <= {16'h3000, 8'h00};  //系统块复位控制8'd53: i2c_data <= {16'h3004, 8'hff};  //时钟使能控制8'd54: i2c_data <= {16'h4300, 8'h61};  //格式控制 RGB5658'd55: i2c_data <= {16'h501f, 8'h01};  //ISP RGB8'd56: i2c_data <= {16'h440e, 8'h00};8'd57: i2c_data <= {16'h5000, 8'ha7};  //ISP控制8'd58: i2c_data <= {16'h3a0f, 8'h30};  //AEC控制;stable range in high8'd59: i2c_data <= {16'h3a10, 8'h28};  //AEC控制;stable range in low8'd60: i2c_data <= {16'h3a1b, 8'h30};  //AEC控制;stable range out high8'd61: i2c_data <= {16'h3a1e, 8'h26};  //AEC控制;stable range out low8'd62: i2c_data <= {16'h3a11, 8'h60};  //AEC控制; fast zone high8'd63: i2c_data <= {16'h3a1f, 8'h14};  //AEC控制; fast zone low//LENC(镜头校正)控制 16'h5800~16'h583d8'd64: i2c_data <= {16'h5800, 8'h23};8'd65: i2c_data <= {16'h5801, 8'h14};8'd66: i2c_data <= {16'h5802, 8'h0f};8'd67: i2c_data <= {16'h5803, 8'h0f};8'd68: i2c_data <= {16'h5804, 8'h12};8'd69: i2c_data <= {16'h5805, 8'h26};8'd70: i2c_data <= {16'h5806, 8'h0c};8'd71: i2c_data <= {16'h5807, 8'h08};8'd72: i2c_data <= {16'h5808, 8'h05};8'd73: i2c_data <= {16'h5809, 8'h05};8'd74: i2c_data <= {16'h580a, 8'h08};8'd75: i2c_data <= {16'h580b, 8'h0d};8'd76: i2c_data <= {16'h580c, 8'h08};8'd77: i2c_data <= {16'h580d, 8'h03};8'd78: i2c_data <= {16'h580e, 8'h00};8'd79: i2c_data <= {16'h580f, 8'h00};8'd80: i2c_data <= {16'h5810, 8'h03};8'd81: i2c_data <= {16'h5811, 8'h09};8'd82: i2c_data <= {16'h5812, 8'h07};8'd83: i2c_data <= {16'h5813, 8'h03};8'd84: i2c_data <= {16'h5814, 8'h00};8'd85: i2c_data <= {16'h5815, 8'h01};8'd86: i2c_data <= {16'h5816, 8'h03};8'd87: i2c_data <= {16'h5817, 8'h08};8'd88: i2c_data <= {16'h5818, 8'h0d};8'd89: i2c_data <= {16'h5819, 8'h08};8'd90: i2c_data <= {16'h581a, 8'h05};8'd91: i2c_data <= {16'h581b, 8'h06};8'd92: i2c_data <= {16'h581c, 8'h08};8'd93: i2c_data <= {16'h581d, 8'h0e};8'd94: i2c_data <= {16'h581e, 8'h29};8'd95: i2c_data <= {16'h581f, 8'h17};8'd96: i2c_data <= {16'h5820, 8'h11};8'd97: i2c_data <= {16'h5821, 8'h11};8'd98: i2c_data <= {16'h5822, 8'h15};8'd99: i2c_data <= {16'h5823, 8'h28};8'd100: i2c_data <= {16'h5824, 8'h46};8'd101: i2c_data <= {16'h5825, 8'h26};8'd102: i2c_data <= {16'h5826, 8'h08};8'd103: i2c_data <= {16'h5827, 8'h26};8'd104: i2c_data <= {16'h5828, 8'h64};8'd105: i2c_data <= {16'h5829, 8'h26};8'd106: i2c_data <= {16'h582a, 8'h24};8'd107: i2c_data <= {16'h582b, 8'h22};8'd108: i2c_data <= {16'h582c, 8'h24};8'd109: i2c_data <= {16'h582d, 8'h24};8'd110: i2c_data <= {16'h582e, 8'h06};8'd111: i2c_data <= {16'h582f, 8'h22};8'd112: i2c_data <= {16'h5830, 8'h40};8'd113: i2c_data <= {16'h5831, 8'h42};8'd114: i2c_data <= {16'h5832, 8'h24};8'd115: i2c_data <= {16'h5833, 8'h26};8'd116: i2c_data <= {16'h5834, 8'h24};8'd117: i2c_data <= {16'h5835, 8'h22};8'd118: i2c_data <= {16'h5836, 8'h22};8'd119: i2c_data <= {16'h5837, 8'h26};8'd120: i2c_data <= {16'h5838, 8'h44};8'd121: i2c_data <= {16'h5839, 8'h24};8'd122: i2c_data <= {16'h583a, 8'h26};8'd123: i2c_data <= {16'h583b, 8'h28};8'd124: i2c_data <= {16'h583c, 8'h42};8'd125: i2c_data <= {16'h583d, 8'hce};//AWB(自动白平衡控制) 16'h5180~16'h519e8'd126: i2c_data <= {16'h5180, 8'hff};8'd127: i2c_data <= {16'h5181, 8'hf2};8'd128: i2c_data <= {16'h5182, 8'h00};8'd129: i2c_data <= {16'h5183, 8'h14};8'd130: i2c_data <= {16'h5184, 8'h25};8'd131: i2c_data <= {16'h5185, 8'h24};8'd132: i2c_data <= {16'h5186, 8'h09};8'd133: i2c_data <= {16'h5187, 8'h09};8'd134: i2c_data <= {16'h5188, 8'h09};8'd135: i2c_data <= {16'h5189, 8'h75};8'd136: i2c_data <= {16'h518a, 8'h54};8'd137: i2c_data <= {16'h518b, 8'he0};8'd138: i2c_data <= {16'h518c, 8'hb2};8'd139: i2c_data <= {16'h518d, 8'h42};8'd140: i2c_data <= {16'h518e, 8'h3d};8'd141: i2c_data <= {16'h518f, 8'h56};8'd142: i2c_data <= {16'h5190, 8'h46};8'd143: i2c_data <= {16'h5191, 8'hf8};8'd144: i2c_data <= {16'h5192, 8'h04};8'd145: i2c_data <= {16'h5193, 8'h70};8'd146: i2c_data <= {16'h5194, 8'hf0};8'd147: i2c_data <= {16'h5195, 8'hf0};8'd148: i2c_data <= {16'h5196, 8'h03};8'd149: i2c_data <= {16'h5197, 8'h01};8'd150: i2c_data <= {16'h5198, 8'h04};8'd151: i2c_data <= {16'h5199, 8'h12};8'd152: i2c_data <= {16'h519a, 8'h04};8'd153: i2c_data <= {16'h519b, 8'h00};8'd154: i2c_data <= {16'h519c, 8'h06};8'd155: i2c_data <= {16'h519d, 8'h82};8'd156: i2c_data <= {16'h519e, 8'h38};//Gamma(伽马)控制 16'h5480~16'h54908'd157: i2c_data <= {16'h5480, 8'h01};8'd158: i2c_data <= {16'h5481, 8'h08};8'd159: i2c_data <= {16'h5482, 8'h14};8'd160: i2c_data <= {16'h5483, 8'h28};8'd161: i2c_data <= {16'h5484, 8'h51};8'd162: i2c_data <= {16'h5485, 8'h65};8'd163: i2c_data <= {16'h5486, 8'h71};8'd164: i2c_data <= {16'h5487, 8'h7d};8'd165: i2c_data <= {16'h5488, 8'h87};8'd166: i2c_data <= {16'h5489, 8'h91};8'd167: i2c_data <= {16'h548a, 8'h9a};8'd168: i2c_data <= {16'h548b, 8'haa};8'd169: i2c_data <= {16'h548c, 8'hb8};8'd170: i2c_data <= {16'h548d, 8'hcd};8'd171: i2c_data <= {16'h548e, 8'hdd};8'd172: i2c_data <= {16'h548f, 8'hea};8'd173: i2c_data <= {16'h5490, 8'h1d};//CMX(彩色矩阵控制) 16'h5381~16'h538b8'd174: i2c_data <= {16'h5381, 8'h1e};8'd175: i2c_data <= {16'h5382, 8'h5b};8'd176: i2c_data <= {16'h5383, 8'h08};8'd177: i2c_data <= {16'h5384, 8'h0a};8'd178: i2c_data <= {16'h5385, 8'h7e};8'd179: i2c_data <= {16'h5386, 8'h88};8'd180: i2c_data <= {16'h5387, 8'h7c};8'd181: i2c_data <= {16'h5388, 8'h6c};8'd182: i2c_data <= {16'h5389, 8'h10};8'd183: i2c_data <= {16'h538a, 8'h01};8'd184: i2c_data <= {16'h538b, 8'h98};//SDE(特殊数码效果)控制 16'h5580~16'h558b8'd185: i2c_data <= {16'h5580, 8'h06};8'd186: i2c_data <= {16'h5583, 8'h40};8'd187: i2c_data <= {16'h5584, 8'h10};8'd188: i2c_data <= {16'h5589, 8'h10};8'd189: i2c_data <= {16'h558a, 8'h00};8'd190: i2c_data <= {16'h558b, 8'hf8};8'd191: i2c_data <= {16'h501d, 8'h40};  //ISP MISC//CIP(颜色插值)控制 (16'h5300~16'h530c)8'd192: i2c_data <= {16'h5300, 8'h08};8'd193: i2c_data <= {16'h5301, 8'h30};8'd194: i2c_data <= {16'h5302, 8'h10};8'd195: i2c_data <= {16'h5303, 8'h00};8'd196: i2c_data <= {16'h5304, 8'h08};8'd197: i2c_data <= {16'h5305, 8'h30};8'd198: i2c_data <= {16'h5306, 8'h08};8'd199: i2c_data <= {16'h5307, 8'h16};8'd200: i2c_data <= {16'h5309, 8'h08};8'd201: i2c_data <= {16'h530a, 8'h30};8'd202: i2c_data <= {16'h530b, 8'h04};8'd203: i2c_data <= {16'h530c, 8'h06};8'd204: i2c_data <= {16'h5025, 8'h00};//系统时钟分频 Bit[7:4]:系统时钟分频 input clock =24Mhz, PCLK = 48Mhz8'd205: i2c_data <= {16'h3035, 8'h11};8'd206: i2c_data <= {16'h3036, 8'h3c};  //PLL倍频8'd207: i2c_data <= {16'h3c07, 8'h08};//时序控制 16'h3800~16'h38218'd208: i2c_data <= {16'h3820, 8'h46};8'd209: i2c_data <= {16'h3821, 8'h01};8'd210: i2c_data <= {16'h3814, 8'h31};8'd211: i2c_data <= {16'h3815, 8'h31};8'd212: i2c_data <= {16'h3800, 8'h00};8'd213: i2c_data <= {16'h3801, 8'h00};8'd214: i2c_data <= {16'h3802, 8'h00};8'd215: i2c_data <= {16'h3803, 8'h04};8'd216: i2c_data <= {16'h3804, 8'h0a};8'd217: i2c_data <= {16'h3805, 8'h3f};8'd218: i2c_data <= {16'h3806, 8'h07};8'd219: i2c_data <= {16'h3807, 8'h9b};//设置输出像素个数//DVP 输出水平像素点数高4位8'd220: i2c_data <= {16'h3808, {4'd0, cmos_h_pixel[11:8]}};//DVP 输出水平像素点数低8位8'd221: i2c_data <= {16'h3809, cmos_h_pixel[7:0]};//DVP 输出垂直像素点数高3位8'd222: i2c_data <= {16'h380a, {5'd0, cmos_v_pixel[10:8]}};//DVP 输出垂直像素点数低8位8'd223: i2c_data <= {16'h380b, cmos_v_pixel[7:0]};//水平总像素大小高5位8'd224: i2c_data <= {16'h380c, {3'd0, total_h_pixel[12:8]}};//水平总像素大小低8位 8'd225: i2c_data <= {16'h380d, total_h_pixel[7:0]};//垂直总像素大小高5位 8'd226: i2c_data <= {16'h380e, {3'd0, total_v_pixel[12:8]}};//垂直总像素大小低8位     8'd227: i2c_data <= {16'h380f, total_v_pixel[7:0]};8'd228: i2c_data <= {16'h3813, 8'h06};8'd229: i2c_data <= {16'h3618, 8'h00};8'd230: i2c_data <= {16'h3612, 8'h29};8'd231: i2c_data <= {16'h3709, 8'h52};8'd232: i2c_data <= {16'h370c, 8'h03};8'd233: i2c_data <= {16'h3a02, 8'h17};  //60Hz max exposure8'd234: i2c_data <= {16'h3a03, 8'h10};  //60Hz max exposure8'd235: i2c_data <= {16'h3a14, 8'h17};  //50Hz max exposure8'd236: i2c_data <= {16'h3a15, 8'h10};  //50Hz max exposure8'd237: i2c_data <= {16'h4004, 8'h02};  //BLC(背光) 2 lines8'd238: i2c_data <= {16'h4713, 8'h03};  //JPEG mode 38'd239: i2c_data <= {16'h4407, 8'h04};  //量化标度8'd240: i2c_data <= {16'h460c, 8'h22};8'd241: i2c_data <= {16'h4837, 8'h22};  //DVP CLK divider8'd242: i2c_data <= {16'h3824, 8'h02};  //DVP CLK divider8'd243: i2c_data <= {16'h5001, 8'ha3};  //ISP 控制8'd244: i2c_data <= {16'h3b07, 8'h0a};  //帧曝光模式  //彩条测试使能 8'd245: i2c_data <= {16'h503d, 8'h00};  //8'h00:正常模式 8'h80:彩条显示//测试闪光灯功能8'd246: i2c_data <= {16'h3016, 8'h02};8'd247: i2c_data <= {16'h301c, 8'h02};8'd248: i2c_data <= {16'h3019, 8'h02};  //打开闪光灯8'd249: i2c_data <= {16'h3019, 8'h00};  //关闭闪光灯//只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写default: i2c_data <= {16'h300a, 8'h00};  //器件ID高8位endcaseendendendmodule

2.4 iic驱动模块

`timescale 1ns / 1ps
//IIC驱动模块module i2c_dri #(parameter   SLAVE_ADDR = 7'b1010000   ,  //EEPROM从机地址parameter   CLK_FREQ   = 26'd50_000_000, //模块输入的时钟频率parameter   I2C_FREQ   = 18'd250_000     //IIC_SCL的时钟频率
) (input clk,input rst_n,//i2c interface                      input             i2c_exec,    //I2C触发执行信号input             bit_ctrl,    //字地址位控制(16b/8b)input             i2c_rh_wl,   //I2C读写控制信号input      [15:0] i2c_addr,    //I2C器件内地址input      [ 7:0] i2c_data_w,  //I2C要写的数据output reg [ 7:0] i2c_data_r,  //I2C读出的数据output reg        i2c_done,    //I2C一次操作完成output reg        i2c_ack,     //I2C应答标志 0:应答 1:未应答output reg        scl,         //I2C的SCL时钟信号inout             sda,         //I2C的SDA信号//user interface                   output reg dri_clk  //驱动I2C操作的驱动时钟
);//localparam definelocalparam st_idle = 8'b0000_0001;  //空闲状态localparam st_sladdr = 8'b0000_0010;  //发送器件地址(slave address)localparam st_addr16 = 8'b0000_0100;  //发送16位字地址localparam st_addr8 = 8'b0000_1000;  //发送8位字地址localparam st_data_wr = 8'b0001_0000;  //写数据(8 bit)localparam st_addr_rd = 8'b0010_0000;  //发送器件地址读localparam st_data_rd = 8'b0100_0000;  //读数据(8 bit)localparam st_stop = 8'b1000_0000;  //结束I2C操作//reg definereg         sda_dir;  //I2C数据(SDA)方向控制reg         sda_out;  //SDA输出信号reg         st_done;  //状态结束reg         wr_flag;  //写标志reg  [ 6:0] cnt;  //计数reg  [ 7:0] cur_state;  //状态机当前状态reg  [ 7:0] next_state;  //状态机下一状态reg  [15:0] addr_t;  //地址reg  [ 7:0] data_r;  //读取的数据reg  [ 7:0] data_wr_t;  //I2C需写的数据的临时寄存reg  [ 9:0] clk_cnt;  //分频时钟计数//wire definewire        sda_in;  //SDA输入信号wire [ 8:0] clk_divide;  //模块驱动时钟的分频系数//*****************************************************//**                    main code//*****************************************************//SDA控制assign sda        = sda_dir ? sda_out : 1'bz;  //SDA数据输出或高阻assign sda_in     = sda;  //SDA数据输入assign clk_divide = (CLK_FREQ / I2C_FREQ) >> 2'd2;  //模块驱动时钟的分频系数//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作always @(posedge clk or negedge rst_n) beginif (!rst_n) begindri_clk <= 1'b0;clk_cnt <= 10'd0;end else if (clk_cnt == clk_divide[8:1] - 1'd1) beginclk_cnt <= 10'd0;dri_clk <= ~dri_clk;end else clk_cnt <= clk_cnt + 1'b1;end//(三段式状态机)同步时序描述状态转移always @(posedge dri_clk or negedge rst_n) beginif (!rst_n) cur_state <= st_idle;else cur_state <= next_state;end//组合逻辑判断状态转移条件always @(*) beginnext_state = st_idle;case (cur_state)st_idle: begin  //空闲状态if (i2c_exec) beginnext_state = st_sladdr;end else next_state = st_idle;endst_sladdr: beginif (st_done) beginif (bit_ctrl)  //判断是16位还是8位字地址next_state = st_addr16;else next_state = st_addr8;end else next_state = st_sladdr;endst_addr16: begin  //写16位字地址if (st_done) beginnext_state = st_addr8;end else beginnext_state = st_addr16;endendst_addr8: begin  //8位字地址if (st_done) beginif (wr_flag == 1'b0)  //读写判断next_state = st_data_wr;else next_state = st_addr_rd;end else beginnext_state = st_addr8;endendst_data_wr: begin  //写数据(8 bit)if (st_done) next_state = st_stop;else next_state = st_data_wr;endst_addr_rd: begin  //写地址以进行读数据if (st_done) beginnext_state = st_data_rd;end else beginnext_state = st_addr_rd;endendst_data_rd: begin  //读取数据(8 bit)if (st_done) next_state = st_stop;else next_state = st_data_rd;endst_stop: begin  //结束I2C操作if (st_done) next_state = st_idle;else next_state = st_stop;enddefault: next_state = st_idle;endcaseend//时序电路描述状态输出always @(posedge dri_clk or negedge rst_n) begin//复位初始化if (!rst_n) beginscl        <= 1'b1;sda_out    <= 1'b1;sda_dir    <= 1'b1;i2c_done   <= 1'b0;i2c_ack    <= 1'b0;cnt        <= 1'b0;st_done    <= 1'b0;data_r     <= 1'b0;i2c_data_r <= 1'b0;wr_flag    <= 1'b0;addr_t     <= 1'b0;data_wr_t  <= 1'b0;end else beginst_done <= 1'b0;cnt     <= cnt + 1'b1;case (cur_state)st_idle: begin  //空闲状态scl      <= 1'b1;sda_out  <= 1'b1;sda_dir  <= 1'b1;i2c_done <= 1'b0;cnt      <= 7'b0;if (i2c_exec) beginwr_flag   <= i2c_rh_wl ;addr_t    <= i2c_addr  ;data_wr_t <= i2c_data_w;i2c_ack <= 1'b0;endendst_sladdr: begin  //写地址(器件地址和字地址)case (cnt)7'd1:    sda_out <= 1'b0;  //开始I2C7'd3:    scl <= 1'b0;7'd4:    sda_out <= SLAVE_ADDR[6];  //传送器件地址7'd5:    scl <= 1'b1;7'd7:    scl <= 1'b0;7'd8:    sda_out <= SLAVE_ADDR[5];7'd9:    scl <= 1'b1;7'd11:   scl <= 1'b0;7'd12:   sda_out <= SLAVE_ADDR[4];7'd13:   scl <= 1'b1;7'd15:   scl <= 1'b0;7'd16:   sda_out <= SLAVE_ADDR[3];7'd17:   scl <= 1'b1;7'd19:   scl <= 1'b0;7'd20:   sda_out <= SLAVE_ADDR[2];7'd21:   scl <= 1'b1;7'd23:   scl <= 1'b0;7'd24:   sda_out <= SLAVE_ADDR[1];7'd25:   scl <= 1'b1;7'd27:   scl <= 1'b0;7'd28:   sda_out <= SLAVE_ADDR[0];7'd29:   scl <= 1'b1;7'd31:   scl <= 1'b0;7'd32:   sda_out <= 1'b0;  //0:写7'd33:   scl <= 1'b1;7'd35:   scl <= 1'b0;7'd36: beginsda_dir <= 1'b0;sda_out <= 1'b1;end7'd37:   scl <= 1'b1;7'd38: begin  //从机应答 st_done <= 1'b1;if (sda_in == 1'b1)  //高电平表示未应答i2c_ack <= 1'b1;  //拉高应答标志位     end7'd39: beginscl <= 1'b0;cnt <= 1'b0;enddefault: ;endcaseendst_addr16: begincase (cnt)7'd0: beginsda_dir <= 1'b1;sda_out <= addr_t[15];  //传送字地址end7'd1:    scl <= 1'b1;7'd3:    scl <= 1'b0;7'd4:    sda_out <= addr_t[14];7'd5:    scl <= 1'b1;7'd7:    scl <= 1'b0;7'd8:    sda_out <= addr_t[13];7'd9:    scl <= 1'b1;7'd11:   scl <= 1'b0;7'd12:   sda_out <= addr_t[12];7'd13:   scl <= 1'b1;7'd15:   scl <= 1'b0;7'd16:   sda_out <= addr_t[11];7'd17:   scl <= 1'b1;7'd19:   scl <= 1'b0;7'd20:   sda_out <= addr_t[10];7'd21:   scl <= 1'b1;7'd23:   scl <= 1'b0;7'd24:   sda_out <= addr_t[9];7'd25:   scl <= 1'b1;7'd27:   scl <= 1'b0;7'd28:   sda_out <= addr_t[8];7'd29:   scl <= 1'b1;7'd31:   scl <= 1'b0;7'd32: beginsda_dir <= 1'b0;sda_out <= 1'b1;end7'd33:   scl <= 1'b1;7'd34: begin  //从机应答st_done <= 1'b1;if (sda_in == 1'b1)  //高电平表示未应答i2c_ack <= 1'b1;  //拉高应答标志位    end7'd35: beginscl <= 1'b0;cnt <= 1'b0;enddefault: ;endcaseendst_addr8: begincase (cnt)7'd0: beginsda_dir <= 1'b1;sda_out <= addr_t[7];  //字地址end7'd1:    scl <= 1'b1;7'd3:    scl <= 1'b0;7'd4:    sda_out <= addr_t[6];7'd5:    scl <= 1'b1;7'd7:    scl <= 1'b0;7'd8:    sda_out <= addr_t[5];7'd9:    scl <= 1'b1;7'd11:   scl <= 1'b0;7'd12:   sda_out <= addr_t[4];7'd13:   scl <= 1'b1;7'd15:   scl <= 1'b0;7'd16:   sda_out <= addr_t[3];7'd17:   scl <= 1'b1;7'd19:   scl <= 1'b0;7'd20:   sda_out <= addr_t[2];7'd21:   scl <= 1'b1;7'd23:   scl <= 1'b0;7'd24:   sda_out <= addr_t[1];7'd25:   scl <= 1'b1;7'd27:   scl <= 1'b0;7'd28:   sda_out <= addr_t[0];7'd29:   scl <= 1'b1;7'd31:   scl <= 1'b0;7'd32: beginsda_dir <= 1'b0;sda_out <= 1'b1;end7'd33:   scl <= 1'b1;7'd34: begin  //从机应答st_done <= 1'b1;if (sda_in == 1'b1)  //高电平表示未应答i2c_ack <= 1'b1;  //拉高应答标志位    end7'd35: beginscl <= 1'b0;cnt <= 1'b0;enddefault: ;endcaseendst_data_wr: begin  //写数据(8 bit)case (cnt)7'd0: beginsda_out <= data_wr_t[7];  //I2C写8位数据sda_dir <= 1'b1;end7'd1:    scl <= 1'b1;7'd3:    scl <= 1'b0;7'd4:    sda_out <= data_wr_t[6];7'd5:    scl <= 1'b1;7'd7:    scl <= 1'b0;7'd8:    sda_out <= data_wr_t[5];7'd9:    scl <= 1'b1;7'd11:   scl <= 1'b0;7'd12:   sda_out <= data_wr_t[4];7'd13:   scl <= 1'b1;7'd15:   scl <= 1'b0;7'd16:   sda_out <= data_wr_t[3];7'd17:   scl <= 1'b1;7'd19:   scl <= 1'b0;7'd20:   sda_out <= data_wr_t[2];7'd21:   scl <= 1'b1;7'd23:   scl <= 1'b0;7'd24:   sda_out <= data_wr_t[1];7'd25:   scl <= 1'b1;7'd27:   scl <= 1'b0;7'd28:   sda_out <= data_wr_t[0];7'd29:   scl <= 1'b1;7'd31:   scl <= 1'b0;7'd32: beginsda_dir <= 1'b0;sda_out <= 1'b1;end7'd33:   scl <= 1'b1;7'd34: begin  //从机应答st_done <= 1'b1;if (sda_in == 1'b1)  //高电平表示未应答i2c_ack <= 1'b1;  //拉高应答标志位    end7'd35: beginscl <= 1'b0;cnt <= 1'b0;enddefault: ;endcaseendst_addr_rd: begin  //写地址以进行读数据case (cnt)7'd0: beginsda_dir <= 1'b1;sda_out <= 1'b1;end7'd1:    scl <= 1'b1;7'd2:    sda_out <= 1'b0;  //重新开始7'd3:    scl <= 1'b0;7'd4:    sda_out <= SLAVE_ADDR[6];  //传送器件地址7'd5:    scl <= 1'b1;7'd7:    scl <= 1'b0;7'd8:    sda_out <= SLAVE_ADDR[5];7'd9:    scl <= 1'b1;7'd11:   scl <= 1'b0;7'd12:   sda_out <= SLAVE_ADDR[4];7'd13:   scl <= 1'b1;7'd15:   scl <= 1'b0;7'd16:   sda_out <= SLAVE_ADDR[3];7'd17:   scl <= 1'b1;7'd19:   scl <= 1'b0;7'd20:   sda_out <= SLAVE_ADDR[2];7'd21:   scl <= 1'b1;7'd23:   scl <= 1'b0;7'd24:   sda_out <= SLAVE_ADDR[1];7'd25:   scl <= 1'b1;7'd27:   scl <= 1'b0;7'd28:   sda_out <= SLAVE_ADDR[0];7'd29:   scl <= 1'b1;7'd31:   scl <= 1'b0;7'd32:   sda_out <= 1'b1;  //1:读7'd33:   scl <= 1'b1;7'd35:   scl <= 1'b0;7'd36: beginsda_dir <= 1'b0;sda_out <= 1'b1;end7'd37:   scl <= 1'b1;7'd38: begin  //从机应答st_done <= 1'b1;if (sda_in == 1'b1)  //高电平表示未应答i2c_ack <= 1'b1;  //拉高应答标志位    end7'd39: beginscl <= 1'b0;cnt <= 1'b0;enddefault: ;endcaseendst_data_rd: begin  //读取数据(8 bit)case (cnt)7'd0:    sda_dir <= 1'b0;7'd1: begindata_r[7] <= sda_in;scl       <= 1'b1;end7'd3:    scl <= 1'b0;7'd5: begindata_r[6] <= sda_in;scl       <= 1'b1;end7'd7:    scl <= 1'b0;7'd9: begindata_r[5] <= sda_in;scl       <= 1'b1;end7'd11:   scl <= 1'b0;7'd13: begindata_r[4] <= sda_in;scl       <= 1'b1;end7'd15:   scl <= 1'b0;7'd17: begindata_r[3] <= sda_in;scl       <= 1'b1;end7'd19:   scl <= 1'b0;7'd21: begindata_r[2] <= sda_in;scl       <= 1'b1;end7'd23:   scl <= 1'b0;7'd25: begindata_r[1] <= sda_in;scl       <= 1'b1;end7'd27:   scl <= 1'b0;7'd29: begindata_r[0] <= sda_in;scl       <= 1'b1;end7'd31:   scl <= 1'b0;7'd32: beginsda_dir <= 1'b1;sda_out <= 1'b1;end7'd33:   scl <= 1'b1;7'd34:   st_done <= 1'b1;  //非应答7'd35: beginscl <= 1'b0;cnt <= 1'b0;i2c_data_r <= data_r;enddefault: ;endcaseendst_stop: begin  //结束I2C操作case (cnt)7'd0: beginsda_dir <= 1'b1;  //结束I2Csda_out <= 1'b0;end7'd1:    scl <= 1'b1;7'd3:    sda_out <= 1'b1;7'd15:   st_done <= 1'b1;7'd16: begincnt      <= 1'b0;i2c_done <= 1'b1;  //向上层模块传递I2C结束信号enddefault: ;endcaseendendcaseendendendmodule

2.5 图像数据采集模块

`timescale 1ns / 1ps
//摄像头采集模块module cmos_capture_data (input         rst_n,             //复位信号    //摄像头接口                           input         cam_pclk,          //cmos 数据像素时钟input         cam_vsync,         //cmos 场同步信号input         cam_href,          //cmos 行同步信号input  [ 7:0] cam_data,//用户接口                              output        cmos_frame_vsync,  //帧有效信号    output        cmos_frame_href,   //行有效信号output        cmos_frame_valid,  //数据有效使能信号output [15:0] cmos_frame_data    //有效数据        
);//寄存器全部配置完成后,先等待10帧数据//待寄存器配置生效后再开始采集图像parameter WAIT_FRAME = 4'd10;  //寄存器数据稳定等待的帧个数            //reg define                     reg         cam_vsync_d0;reg         cam_vsync_d1;reg         cam_href_d0;reg         cam_href_d1;reg  [ 3:0] cmos_ps_cnt;  //等待帧数稳定计数器reg  [ 7:0] cam_data_d0;reg  [15:0] cmos_data_t;  //用于8位转16位的临时寄存器reg         byte_flag;  //16位RGB数据转换完成的标志信号reg         byte_flag_d0;reg         frame_val_flag;  //帧有效的标志 wire        pos_vsync;  //采输入场同步信号的上升沿//*****************************************************//**                    main code//*****************************************************//采输入场同步信号的上升沿assign pos_vsync = (~cam_vsync_d1) & cam_vsync_d0;//输出帧有效信号assign cmos_frame_vsync = frame_val_flag ? cam_vsync_d1 : 1'b0;//输出行有效信号assign cmos_frame_href = frame_val_flag ? cam_href_d1 : 1'b0;//输出数据使能有效信号assign cmos_frame_valid = frame_val_flag ? byte_flag_d0 : 1'b0;//输出数据assign cmos_frame_data = frame_val_flag ? cmos_data_t : 1'b0;always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) begincam_vsync_d0 <= 1'b0;cam_vsync_d1 <= 1'b0;cam_href_d0  <= 1'b0;cam_href_d1  <= 1'b0;end else begincam_vsync_d0 <= cam_vsync;cam_vsync_d1 <= cam_vsync_d0;cam_href_d0  <= cam_href;cam_href_d1  <= cam_href_d0;endend//对帧数进行计数always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) cmos_ps_cnt <= 4'd0;else if (pos_vsync && (cmos_ps_cnt < WAIT_FRAME)) cmos_ps_cnt <= cmos_ps_cnt + 4'd1;end//帧有效标志always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) frame_val_flag <= 1'b0;else if ((cmos_ps_cnt == WAIT_FRAME) && pos_vsync) frame_val_flag <= 1'b1;else;end//8位数据转16位RGB565数据        always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) begincmos_data_t <= 16'd0;cam_data_d0 <= 8'd0;byte_flag   <= 1'b0;end else if (cam_href) beginbyte_flag   <= ~byte_flag;cam_data_d0 <= cam_data;if (byte_flag) cmos_data_t <= {cam_data_d0, cam_data};else;end else beginbyte_flag   <= 1'b0;cam_data_d0 <= 8'b0;endend//产生输出数据有效信号(cmos_frame_valid)always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) byte_flag_d0 <= 1'b0;else byte_flag_d0 <= byte_flag;endendmodule

2.6 图像传输控制模块

`timescale 1ns / 1ps
//图像传输控制模块module start_transfer_ctrl (input clk,  //GMII接收时钟 input rst_n,  //复位信号,低电平有效input udp_rec_pkt_done,  //UDP单包数据接收完成信号input udp_rec_en,  //UDP接收的数据使能信号 input [31:0] udp_rec_data,  //UDP接收的数据input [15:0] udp_rec_byte_num,  //UDP接收到的字节数                                     output reg transfer_flag  //图像开始传输标志,0:开始传输 1:停止传输
);//parameter defineparameter START = "1";  //开始命令parameter STOP = "0";  //停止命令//*****************************************************//**                    main code//*****************************************************//解析接收到的数据always @(posedge clk or negedge rst_n) beginif (!rst_n) transfer_flag <= 1'b0;else if (udp_rec_pkt_done && udp_rec_byte_num == 1'b1) beginif (udp_rec_data[31:24] == START)  //开始传输transfer_flag <= 1'b1;else if (udp_rec_data[31:24] == STOP)  //停止传输transfer_flag <= 1'b0;endendendmodule

2.7 图像封装模块

`timescale 1ns / 1ps
//图像封装模块   module img_data_pkt (input        rst_n,        //复位信号,低电平有效//图像相关信号input        cam_pclk,     //像素时钟input        img_vsync,    //帧同步信号input        img_data_en,  //数据有效使能信号input [15:0] img_data,     //有效数据 input             transfer_flag,    //图像开始传输标志,0:开始传输 1:停止传输//以太网相关信号 input             eth_tx_clk,       //以太网发送时钟input             udp_tx_req,       //udp发送数据请求信号input             udp_tx_done,      //udp发送数据完成信号                               output reg        udp_tx_start_en,  //udp开始发送信号output     [31:0] udp_tx_data,      //udp发送的数据output reg [15:0] udp_tx_byte_num   //udp单包发送的有效字节数
);//parameter defineparameter CMOS_H_PIXEL = 16'd640;  //图像水平方向分辨率parameter CMOS_V_PIXEL = 16'd480;  //图像垂直方向分辨率//图像帧头,用于标志一帧数据的开始parameter IMG_FRAME_HEAD = {32'hf0_5a_a5_0f};reg         img_vsync_d0;  //帧有效信号打拍reg         img_vsync_d1;  //帧有效信号打拍reg         neg_vsync_d0;  //帧有效信号下降沿打拍reg         wr_sw;  //用于位拼接的标志reg  [15:0] img_data_d0;  //有效图像数据打拍reg         wr_fifo_en;  //写fifo使能reg  [31:0] wr_fifo_data;  //写fifo数据reg         img_vsync_txc_d0;  //以太网发送时钟域下,帧有效信号打拍reg         img_vsync_txc_d1;  //以太网发送时钟域下,帧有效信号打拍reg         tx_busy_flag;  //发送忙信号标志//wire define                   wire        pos_vsync;  //帧有效信号上升沿wire        neg_vsync;  //帧有效信号下降沿wire        neg_vsynt_txc;  //以太网发送时钟域下,帧有效信号下降沿wire [ 9:0] fifo_rdusedw;  //当前FIFO缓存的个数//*****************************************************//**                    main code//*****************************************************//信号采沿assign neg_vsync = img_vsync_d1 & (~img_vsync_d0);assign pos_vsync = ~img_vsync_d1 & img_vsync_d0;assign neg_vsynt_txc = ~img_vsync_txc_d1 & img_vsync_txc_d0;//对img_vsync信号延时两个时钟周期,用于采沿always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) beginimg_vsync_d0 <= 1'b0;img_vsync_d1 <= 1'b0;end else beginimg_vsync_d0 <= img_vsync;img_vsync_d1 <= img_vsync_d0;endend//寄存neg_vsync信号always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) neg_vsync_d0 <= 1'b0;else neg_vsync_d0 <= neg_vsync;end//对wr_sw和img_data_d0信号赋值,用于位拼接always @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) beginwr_sw <= 1'b0;img_data_d0 <= 1'b0;end else if (neg_vsync) wr_sw <= 1'b0;else if (img_data_en) beginwr_sw <= ~wr_sw;img_data_d0 <= img_data;endend//将帧头和图像数据写入FIFOalways @(posedge cam_pclk or negedge rst_n) beginif (!rst_n) beginwr_fifo_en   <= 1'b0;wr_fifo_data <= 1'b0;end else beginif (neg_vsync) beginwr_fifo_en   <= 1'b1;wr_fifo_data <= IMG_FRAME_HEAD;  //帧头end else if (neg_vsync_d0) beginwr_fifo_en   <= 1'b1;wr_fifo_data <= {CMOS_H_PIXEL, CMOS_V_PIXEL};  //水平和垂直方向分辨率end else if (img_data_en && wr_sw) beginwr_fifo_en   <= 1'b1;wr_fifo_data <= {img_data_d0, img_data};  //图像数据位拼接,16位转32位end else beginwr_fifo_en   <= 1'b0;wr_fifo_data <= 1'b0;endendend//以太网发送时钟域下,对img_vsync信号延时两个时钟周期,用于采沿always @(posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) beginimg_vsync_txc_d0 <= 1'b0;img_vsync_txc_d1 <= 1'b0;end else beginimg_vsync_txc_d0 <= img_vsync;img_vsync_txc_d1 <= img_vsync_txc_d0;endend//控制以太网发送的字节数always @(posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) udp_tx_byte_num <= 1'b0;else if (neg_vsynt_txc) udp_tx_byte_num <= {CMOS_H_PIXEL, 1'b0} + 16'd8;else if (udp_tx_done) udp_tx_byte_num <= {CMOS_H_PIXEL, 1'b0};end//控制以太网发送开始信号always @(posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) beginudp_tx_start_en <= 1'b0;tx_busy_flag <= 1'b0;end  //上位机未发送"开始"命令时,以太网不发送图像数据else if (transfer_flag == 1'b0) beginudp_tx_start_en <= 1'b0;tx_busy_flag <= 1'b0;end else beginudp_tx_start_en <= 1'b0;//当FIFO中的个数满足需要发送的字节数时if (tx_busy_flag == 1'b0 && fifo_rdusedw >= udp_tx_byte_num[15:2]) beginudp_tx_start_en <= 1'b1;  //开始控制发送一包数据tx_busy_flag    <= 1'b1;end else if (udp_tx_done || neg_vsynt_txc) tx_busy_flag <= 1'b0;endend//异步FIFOasync_fifo_1024x32b async_fifo_1024x32b_inst (.rst          (pos_vsync | (~transfer_flag)),  // input wire rst.wr_clk       (cam_pclk),                      // input wire wr_clk.rd_clk       (eth_tx_clk),                    // input wire rd_clk.din          (wr_fifo_data),                  // input wire [31 : 0] din.wr_en        (wr_fifo_en),                    // input wire wr_en.rd_en        (udp_tx_req),                    // input wire rd_en.dout         (udp_tx_data),                   // output wire [31 : 0] dout.full         (),                              // output wire full.empty        (),                              // output wire empty.rd_data_count(fifo_rdusedw),                  // output wire [9 : 0] rd_data_count.wr_rst_busy  (),                              // output wire wr_rst_busy.rd_rst_busy  ()                               // output wire rd_rst_busy);endmodule

 

2.8 以太网顶层模块

`timescale 1ns / 1ps
//以太网UDP通信顶层模块module eth_top (input        sys_rst_n,   //系统复位信号,低电平有效 //以太网RGMII接口            input        eth_rxc,     //RGMII接收数据时钟input        eth_rx_ctl,  //RGMII输入数据有效信号input  [3:0] eth_rxd,     //RGMII输入数据output       eth_txc,     //RGMII发送数据时钟    output       eth_tx_ctl,  //RGMII输出数据有效信号output [3:0] eth_txd,     //RGMII输出数据          input         gmii_tx_clk,      //GMII发送时钟input         udp_tx_start_en,  //以太网开始发送信号   input  [31:0] tx_data,          //以太网待发送数据     input  [15:0] tx_byte_num,      //以太网发送的有效字节数 单位:byte output        udp_tx_done,      //UDP发送完成信号  output        tx_req,           //读数据请求信号    output        gmii_rx_clk,   //GMII接收时钟 output        rec_pkt_done,  //UDP单包数据接收完成信号 output        rec_en,        //UDP接收的数据使能信号          output [31:0] rec_data,      //UDP接收的数据output [15:0] rec_byte_num   //UDP接收到的字节数
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};//wire define          wire        gmii_rx_dv;  //GMII接收数据有效信号wire [ 7:0] gmii_rxd;  //GMII接收数据wire        gmii_tx_en;  //GMII发送数据使能信号wire [ 7:0] gmii_txd;  //GMII发送数据     wire        arp_gmii_tx_en;  //ARP GMII输出数据有效信号 wire [ 7:0] arp_gmii_txd;  //ARP GMII输出数据wire        arp_rx_done;  //ARP接收完成信号wire        arp_rx_type;  //ARP接收类型 0:请求  1:应答wire [47:0] src_mac;  //接收到目的MAC地址wire [31:0] src_ip;  //接收到目的IP地址    wire        arp_tx_en;  //ARP发送使能信号wire        arp_tx_type;  //ARP发送类型 0:请求  1:应答wire [47:0] des_mac;  //发送的目标MAC地址wire [31:0] des_ip;  //发送的目标IP地址   wire        arp_tx_done;  //ARP发送完成信号wire        udp_gmii_tx_en;  //UDP GMII输出数据有效信号 wire [ 7:0] udp_gmii_txd;  //UDP GMII输出数据//*****************************************************//**                    main code//*****************************************************assign des_mac = src_mac;assign des_ip  = src_ip;assign eth_txc = clk_125m_deg;clk_wiz u_clk_wiz (// Clock out ports.clk_out1(clk_125m_deg),  // output clk_out1// Status and control signals.reset   (~sys_rst_n),    // input reset.locked  (locked),        // output locked// Clock in ports.clk_in1 (rgmii_txc)      // input clk_in1);//GMII接口转RGMII接口gmii_to_rgmii u_gmii_to_rgmii (.gmii_rx_clk(gmii_rx_clk),.gmii_rx_dv (gmii_rx_dv),.gmii_rxd   (gmii_rxd),.gmii_tx_clk(gmii_tx_clk),.gmii_tx_en (gmii_tx_en),.gmii_txd   (gmii_txd),.rgmii_rxc   (eth_rxc),.rgmii_rx_ctl(eth_rx_ctl),.rgmii_rxd   (eth_rxd),.rgmii_txc   (rgmii_txc),.rgmii_tx_ctl(eth_tx_ctl),.rgmii_txd   (eth_txd));//ARP通信arp_top #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP),.DES_MAC  (DES_MAC),.DES_IP   (DES_IP)) u_arp_top (.rst_n(sys_rst_n),.gmii_rx_clk(gmii_rx_clk),.gmii_rx_dv (gmii_rx_dv),.gmii_rxd   (gmii_rxd),.gmii_tx_clk(gmii_tx_clk),.gmii_tx_en (arp_gmii_tx_en),.gmii_txd   (arp_gmii_txd),.arp_rx_done(arp_rx_done),.arp_rx_type(arp_rx_type),.src_mac    (src_mac),.src_ip     (src_ip),.arp_tx_en  (arp_tx_en),.arp_tx_type(arp_tx_type),.des_mac    (des_mac),.des_ip     (des_ip),.tx_done    (arp_tx_done));//UDP通信udp_top #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP),.DES_MAC  (DES_MAC),.DES_IP   (DES_IP)) u_udp_top (.rst_n(sys_rst_n),.gmii_rx_clk(gmii_rx_clk),.gmii_rx_dv (gmii_rx_dv),.gmii_rxd   (gmii_rxd),.gmii_tx_clk(gmii_tx_clk),.gmii_tx_en (udp_gmii_tx_en),.gmii_txd   (udp_gmii_txd),.rec_pkt_done(rec_pkt_done),.rec_en      (rec_en),.rec_data    (rec_data),.rec_byte_num(rec_byte_num),.tx_start_en (udp_tx_start_en),.tx_data     (tx_data),.tx_byte_num (tx_byte_num),.des_mac     (des_mac),.des_ip      (des_ip),.tx_done     (udp_tx_done),.tx_req      (tx_req));//以太网控制模块eth_ctrl u_eth_ctrl (.clk  (gmii_rx_clk),.rst_n(sys_rst_n),.arp_rx_done   (arp_rx_done),.arp_rx_type   (arp_rx_type),.arp_tx_en     (arp_tx_en),.arp_tx_type   (arp_tx_type),.arp_tx_done   (arp_tx_done),.arp_gmii_tx_en(arp_gmii_tx_en),.arp_gmii_txd  (arp_gmii_txd),.udp_gmii_tx_en(udp_gmii_tx_en),.udp_gmii_txd  (udp_gmii_txd),.gmii_tx_en(gmii_tx_en),.gmii_txd  (gmii_txd));endmodule

2.9 GMII接口转RGMII接口模块

`timescale 1ns / 1ps
//GMII接口转RGMII接口模块module gmii_to_rgmii (//以太网GMII接口output       gmii_rx_clk,   //GMII接收时钟output       gmii_rx_dv,    //GMII接收数据有效信号output [7:0] gmii_rxd,      //GMII接收数据input        gmii_tx_clk,   //GMII发送时钟input        gmii_tx_en,    //GMII发送数据使能信号input  [7:0] gmii_txd,      //GMII发送数据//以太网RGMII接口   input        rgmii_rxc,     //RGMII接收时钟input        rgmii_rx_ctl,  //RGMII接收数据控制信号input  [3:0] rgmii_rxd,     //RGMII接收数据output       rgmii_txc,     //RGMII发送时钟    output       rgmii_tx_ctl,  //RGMII发送数据控制信号output [3:0] rgmii_txd      //RGMII发送数据          
);//*****************************************************//**                    main code//*****************************************************assign gmii_tx_clk = gmii_rx_clk;//RGMII接收rgmii_rx u_rgmii_rx (.gmii_rx_clk (gmii_rx_clk),.rgmii_rxc   (rgmii_rxc),.rgmii_rx_ctl(rgmii_rx_ctl),.rgmii_rxd   (rgmii_rxd),.gmii_rx_dv(gmii_rx_dv),.gmii_rxd  (gmii_rxd));//RGMII发送rgmii_tx u_rgmii_tx (.gmii_tx_clk(gmii_tx_clk),.gmii_tx_en (gmii_tx_en),.gmii_txd   (gmii_txd),.rgmii_txc   (rgmii_txc),.rgmii_tx_ctl(rgmii_tx_ctl),.rgmii_txd   (rgmii_txd));endmodule

2.10 RGMII接收模块

`timescale 1ns / 1ps
//RGMII接收模块module rgmii_rx (//以太网RGMII接口input       rgmii_rxc,     //RGMII接收时钟input       rgmii_rx_ctl,  //RGMII接收数据控制信号input [3:0] rgmii_rxd,     //RGMII接收数据  //以太网GMII接口output       gmii_rx_clk,  //GMII接收时钟output       gmii_rx_dv,   //GMII接收数据有效信号output [7:0] gmii_rxd      //GMII接收数据
);//wire definewire       rgmii_rxc_bufg;  //全局时钟缓存wire       rgmii_rxc_bufio;  //全局时钟IO缓存wire [1:0] gmii_rxdv_t;  //两位GMII接收有效信号 //*****************************************************//**                    main code//*****************************************************assign gmii_rx_clk = rgmii_rxc_bufg;assign gmii_rx_dv  = gmii_rxdv_t[0] & gmii_rxdv_t[1];//全局时钟缓存BUFG BUFG_inst (.I(rgmii_rxc),      // 1-bit input: Clock input.O(rgmii_rxc_bufg)  // 1-bit output: Clock output);//全局时钟IO缓存BUFIO BUFIO_inst (.I(rgmii_rxc),       // 1-bit input: Clock input.O(rgmii_rxc_bufio)  // 1-bit output: Clock output);//将输入的上下边沿DDR信号,转换成两位单边沿SDR信号IDDRE1 #(.DDR_CLK_EDGE     ("SAME_EDGE_PIPELINED"),// IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED).IS_CB_INVERTED(1'b0),  // Optional inversion for CB.IS_C_INVERTED(1'b0)  // Optional inversion for C) IDDRE1_inst (.Q1(gmii_rxdv_t[0]),    // 1-bit output: Registered parallel output 1.Q2(gmii_rxdv_t[1]),    // 1-bit output: Registered parallel output 2.C (rgmii_rxc_bufio),   // 1-bit input: High-speed clock.CB(~rgmii_rxc_bufio),  // 1-bit input: Inversion of High-speed clock C.D (rgmii_rx_ctl),      // 1-bit input: Serial Data Input.R (1'b0)               // 1-bit input: Active High Async Reset);genvar i;generatefor (i = 0; i < 4; i = i + 1) begin : rxdata_busIDDRE1 #(.DDR_CLK_EDGE      ("SAME_EDGE_PIPELINED"),  // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED).IS_CB_INVERTED(1'b0),  // Optional inversion for CB.IS_C_INVERTED(1'b0)  // Optional inversion for C) IDDRE1_inst (.Q1(gmii_rxd[i]),       // 1-bit output: Registered parallel output 1.Q2(gmii_rxd[4+i]),     // 1-bit output: Registered parallel output 2.C (rgmii_rxc_bufio),   // 1-bit input: High-speed clock.CB(~rgmii_rxc_bufio),  // 1-bit input: Inversion of High-speed clock C.D (rgmii_rxd[i]),      // 1-bit input: Serial Data Input.R (1'b0)               // 1-bit input: Active High Async Reset);endendgenerateendmodule

2.11 RGMII发送模块

`timescale 1ns / 1ps
//RGMII发送模块module rgmii_tx (//GMII发送端口input       gmii_tx_clk,  //GMII发送时钟    input       gmii_tx_en,   //GMII输出数据有效信号input [7:0] gmii_txd,     //GMII输出数据        //RGMII发送端口output       rgmii_txc,     //RGMII发送数据时钟    output       rgmii_tx_ctl,  //RGMII输出数据有效信号output [3:0] rgmii_txd      //RGMII输出数据     
);//*****************************************************//**                    main code//*****************************************************assign rgmii_txc = gmii_tx_clk;//输出双沿采样寄存器 (rgmii_tx_ctl)ODDRE1 #(.IS_C_INVERTED(1'b0),  // Optional inversion for C.IS_D1_INVERTED(1'b0),  // Unsupported, do not use.IS_D2_INVERTED(1'b0),  // Unsupported, do not use.SIM_DEVICE        ("ULTRASCALE"),    // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2).SRVAL(1'b0)  // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)) ODDRE1_tx_ctl (.Q (rgmii_tx_ctl),  // 1-bit output: Data output to IOB.C (gmii_tx_clk),   // 1-bit input: High-speed clock input.D1(gmii_tx_en),    // 1-bit input: Parallel data input 1.D2(gmii_tx_en),    // 1-bit input: Parallel data input 2.SR(1'b0)           // 1-bit input: Active High Async Reset);genvar i;generatefor (i = 0; i < 4; i = i + 1) begin : txdata_busODDRE1 #(.IS_C_INVERTED(1'b0),  // Optional inversion for C.IS_D1_INVERTED(1'b0),  // Unsupported, do not use.IS_D2_INVERTED(1'b0),  // Unsupported, do not use.SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2).SRVAL(1'b0)  // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)) ODDRE1_inst (.Q (rgmii_txd[i]),   // 1-bit output: Data output to IOB.C (gmii_tx_clk),    // 1-bit input: High-speed clock input.D1(gmii_txd[i]),    // 1-bit input: Parallel data input 1.D2(gmii_txd[4+i]),  // 1-bit input: Parallel data input 2.SR(1'b0)            // 1-bit input: Active High Async Reset);endendgenerateendmodule

2.12 arp顶层模块

`timescale 1ns / 1ps
//arp顶层模块module arp_top (input        rst_n,        //复位信号,低电平有效//GMII接口input        gmii_rx_clk,  //GMII接收数据时钟input        gmii_rx_dv,   //GMII输入数据有效信号input  [7:0] gmii_rxd,     //GMII输入数据input        gmii_tx_clk,  //GMII发送数据时钟output       gmii_tx_en,   //GMII输出数据有效信号output [7:0] gmii_txd,     //GMII输出数据          //用户接口output        arp_rx_done,  //ARP接收完成信号output        arp_rx_type,  //ARP接收类型 0:请求  1:应答output [47:0] src_mac,      //接收到目的MAC地址output [31:0] src_ip,       //接收到目的IP地址    input         arp_tx_en,    //ARP发送使能信号input         arp_tx_type,  //ARP发送类型 0:请求  1:应答input  [47:0] des_mac,      //发送的目标MAC地址input  [31:0] des_ip,       //发送的目标IP地址output        tx_done       //以太网发送完成信号    
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};//wire definewire        crc_en;  //CRC开始校验使能wire        crc_clr;  //CRC数据复位信号 wire [ 7:0] crc_d8;  //输入待校验8位数据wire [31:0] crc_data;  //CRC校验数据wire [31:0] crc_next;  //CRC下次校验完成数据//*****************************************************//**                    main code//*****************************************************assign crc_d8 = gmii_txd;//ARP接收模块    arp_rx #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP)) u_arp_rx (.clk  (gmii_rx_clk),.rst_n(rst_n),.gmii_rx_dv (gmii_rx_dv),.gmii_rxd   (gmii_rxd),.arp_rx_done(arp_rx_done),.arp_rx_type(arp_rx_type),.src_mac    (src_mac),.src_ip     (src_ip));//ARP发送模块arp_tx #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP),.DES_MAC  (DES_MAC),.DES_IP   (DES_IP)) u_arp_tx (.clk  (gmii_tx_clk),.rst_n(rst_n),.arp_tx_en  (arp_tx_en),.arp_tx_type(arp_tx_type),.des_mac    (des_mac),.des_ip     (des_ip),.crc_data   (crc_data),.crc_next   (crc_next[31:24]),.tx_done    (tx_done),.gmii_tx_en (gmii_tx_en),.gmii_txd   (gmii_txd),.crc_en     (crc_en),.crc_clr    (crc_clr));//以太网发送CRC校验模块crc32_d8 u_crc32_d8 (.clk     (gmii_tx_clk),.rst_n   (rst_n),.data    (crc_d8),.crc_en  (crc_en),.crc_clr (crc_clr),.crc_data(crc_data),.crc_next(crc_next));endmodule

2.13 arp接收模块

`timescale 1ns / 1ps
//arp接收模块module arp_rx (input clk,   //时钟信号input rst_n, //复位信号,低电平有效input             gmii_rx_dv,   //GMII输入数据有效信号input      [ 7:0] gmii_rxd,     //GMII输入数据output reg        arp_rx_done,  //ARP接收完成信号output reg        arp_rx_type,  //ARP接收类型 0:请求  1:应答output reg [47:0] src_mac,      //接收到的源MAC地址output reg [31:0] src_ip        //接收到的源IP地址
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10   parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};localparam st_idle = 5'b0_0001;  //初始状态,等待接收前导码localparam st_preamble = 5'b0_0010;  //接收前导码状态 localparam st_eth_head = 5'b0_0100;  //接收以太网帧头localparam st_arp_data = 5'b0_1000;  //接收ARP数据localparam st_rx_end = 5'b1_0000;  //接收结束localparam ETH_TPYE = 16'h0806;  //以太网帧类型 ARP//reg definereg [ 4:0] cur_state;reg [ 4:0] next_state;reg        skip_en;  //控制状态跳转使能信号reg        error_en;  //解析错误使能信号reg [ 4:0] cnt;  //解析数据计数器reg [47:0] des_mac_t;  //接收到的目的MAC地址reg [31:0] des_ip_t;  //接收到的目的IP地址reg [47:0] src_mac_t;  //接收到的源MAC地址reg [31:0] src_ip_t;  //接收到的源IP地址reg [15:0] eth_type;  //以太网类型reg [15:0] op_data;  //操作码//*****************************************************//**                    main code//*****************************************************//(三段式状态机)同步时序描述状态转移always @(posedge clk or negedge rst_n) beginif (!rst_n) cur_state <= st_idle;else cur_state <= next_state;end//组合逻辑判断状态转移条件always @(*) beginnext_state = st_idle;case (cur_state)st_idle: begin  //等待接收前导码if (skip_en) next_state = st_preamble;else next_state = st_idle;endst_preamble: begin  //接收前导码if (skip_en) next_state = st_eth_head;else if (error_en) next_state = st_rx_end;else next_state = st_preamble;endst_eth_head: begin  //接收以太网帧头if (skip_en) next_state = st_arp_data;else if (error_en) next_state = st_rx_end;else next_state = st_eth_head;endst_arp_data: begin  //接收ARP数据if (skip_en) next_state = st_rx_end;else if (error_en) next_state = st_rx_end;else next_state = st_arp_data;endst_rx_end: begin  //接收结束if (skip_en) next_state = st_idle;else next_state = st_rx_end;enddefault: next_state = st_idle;endcaseend//时序电路描述状态输出,解析以太网数据always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;src_mac_t <= 48'd0;src_ip_t <= 32'd0;eth_type <= 16'd0;op_data <= 16'd0;arp_rx_done <= 1'b0;arp_rx_type <= 1'b0;src_mac <= 48'd0;src_ip <= 32'd0;end else beginskip_en <= 1'b0;error_en <= 1'b0;arp_rx_done <= 1'b0;case (next_state)st_idle: begin  //检测到第一个8'h55if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;endst_preamble: beginif (gmii_rx_dv) begin  //解析前导码cnt <= cnt + 5'd1;if ((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55  error_en <= 1'b1;else if (cnt == 5'd6) begincnt <= 5'd0;if (gmii_rxd == 8'hd5)  //1个8'hd5skip_en <= 1'b1;else error_en <= 1'b1;endendendst_eth_head: beginif (gmii_rx_dv) begincnt <= cnt + 5'b1;if (cnt < 5'd6) des_mac_t <= {des_mac_t[39:0], gmii_rxd};else if (cnt == 5'd6) begin//判断MAC地址是否为开发板MAC地址或者公共地址if ((des_mac_t != BOARD_MAC) && (des_mac_t != 48'hff_ff_ff_ff_ff_ff))error_en <= 1'b1;end else if (cnt == 5'd12) eth_type[15:8] <= gmii_rxd;  //以太网协议类型else if (cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;if (eth_type[15:8] == ETH_TPYE[15:8]  //判断是否为ARP协议&& gmii_rxd == ETH_TPYE[7:0])skip_en <= 1'b1;else error_en <= 1'b1;endendendst_arp_data: beginif (gmii_rx_dv) begincnt <= cnt + 5'd1;if (cnt == 5'd6) op_data[15:8] <= gmii_rxd;  //操作码       else if (cnt == 5'd7) op_data[7:0] <= gmii_rxd;else if (cnt >= 5'd8 && cnt < 5'd14)  //源MAC地址src_mac_t <= {src_mac_t[39:0], gmii_rxd};else if (cnt >= 5'd14 && cnt < 5'd18)  //源IP地址src_ip_t <= {src_ip_t[23:0], gmii_rxd};else if (cnt >= 5'd24 && cnt < 5'd28)  //目标IP地址des_ip_t <= {des_ip_t[23:0], gmii_rxd};else if (cnt == 5'd28) begincnt <= 5'd0;if (des_ip_t == BOARD_IP) begin  //判断目的IP地址和操作码if ((op_data == 16'd1) || (op_data == 16'd2)) beginskip_en <= 1'b1;arp_rx_done <= 1'b1;src_mac <= src_mac_t;src_ip <= src_ip_t;src_mac_t <= 48'd0;src_ip_t <= 32'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;if (op_data == 16'd1) arp_rx_type <= 1'b0;  //ARP请求else arp_rx_type <= 1'b1;  //ARP应答end else error_en <= 1'b1;end else error_en <= 1'b1;endendendst_rx_end: begincnt <= 5'd0;//单包数据接收完成   if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;enddefault: ;endcaseendendendmodule

2.14 arp发送模块

`timescale 1ns / 1ps
//arp发送模块module arp_tx (input clk,   //时钟信号input rst_n, //复位信号,低电平有效input             arp_tx_en,    //ARP发送使能信号input             arp_tx_type,  //ARP发送类型 0:请求  1:应答input      [47:0] des_mac,      //发送的目标MAC地址input      [31:0] des_ip,       //发送的目标IP地址input      [31:0] crc_data,     //CRC校验数据input      [ 7:0] crc_next,     //CRC下次校验完成数据output reg        tx_done,      //以太网发送完成信号output reg        gmii_tx_en,   //GMII输出数据有效信号output reg [ 7:0] gmii_txd,     //GMII输出数据output reg        crc_en,       //CRC开始校验使能output reg        crc_clr       //CRC数据复位信号 
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};localparam st_idle = 5'b0_0001;  //初始状态,等待开始发送信号localparam st_preamble = 5'b0_0010;  //发送前导码+帧起始界定符localparam st_eth_head = 5'b0_0100;  //发送以太网帧头localparam st_arp_data = 5'b0_1000;  //localparam st_crc = 5'b1_0000;  //发送CRC校验值localparam ETH_TYPE = 16'h0806;  //以太网帧类型 ARP协议localparam HD_TYPE = 16'h0001;  //硬件类型 以太网localparam PROTOCOL_TYPE = 16'h0800;  //上层协议为IP协议//以太网数据最小为46个字节,不足部分填充数据localparam MIN_DATA_NUM = 16'd46;//reg definereg  [4:0] cur_state;reg  [4:0] next_state;reg  [7:0] preamble                                  [ 7:0];  //前导码+SFDreg  [7:0] eth_head                                  [13:0];  //以太网首部reg  [7:0] arp_data                                  [27:0];  //ARP数据reg        tx_en_d0;  //arp_tx_en信号延时reg        tx_en_d1;reg        skip_en;  //控制状态跳转使能信号reg  [5:0] cnt;reg  [4:0] data_cnt;  //发送数据个数计数器reg        tx_done_t;//wire define                   wire       pos_tx_en;  //arp_tx_en信号上升沿//*****************************************************//**                    main code//*****************************************************assign pos_tx_en = (~tx_en_d1) & tx_en_d0;//对arp_tx_en信号延时打拍两次,用于采arp_tx_en的上升沿always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_en_d0 <= 1'b0;tx_en_d1 <= 1'b0;end else begintx_en_d0 <= arp_tx_en;tx_en_d1 <= tx_en_d0;endend//(三段式状态机)同步时序描述状态转移always @(posedge clk or negedge rst_n) beginif (!rst_n) cur_state <= st_idle;else cur_state <= next_state;end//组合逻辑判断状态转移条件always @(*) beginnext_state = st_idle;case (cur_state)st_idle: begin  //空闲状态if (skip_en) next_state = st_preamble;else next_state = st_idle;endst_preamble: begin  //发送前导码+帧起始界定符if (skip_en) next_state = st_eth_head;else next_state = st_preamble;endst_eth_head: begin  //发送以太网首部if (skip_en) next_state = st_arp_data;else next_state = st_eth_head;endst_arp_data: begin  //发送ARP数据                      if (skip_en) next_state = st_crc;else next_state = st_arp_data;endst_crc: begin  //发送CRC校验值if (skip_en) next_state = st_idle;else next_state = st_crc;enddefault: next_state = st_idle;endcaseend//时序电路描述状态输出,发送以太网数据always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en      <= 1'b0;cnt          <= 6'd0;data_cnt     <= 5'd0;crc_en       <= 1'b0;gmii_tx_en   <= 1'b0;gmii_txd     <= 8'd0;tx_done_t    <= 1'b0;//初始化数组    //前导码 7个8'h55 + 1个8'hd5 preamble[0]  <= 8'h55;preamble[1]  <= 8'h55;preamble[2]  <= 8'h55;preamble[3]  <= 8'h55;preamble[4]  <= 8'h55;preamble[5]  <= 8'h55;preamble[6]  <= 8'h55;preamble[7]  <= 8'hd5;//以太网帧头 eth_head[0]  <= DES_MAC[47:40];  //目的MAC地址eth_head[1]  <= DES_MAC[39:32];eth_head[2]  <= DES_MAC[31:24];eth_head[3]  <= DES_MAC[23:16];eth_head[4]  <= DES_MAC[15:8];eth_head[5]  <= DES_MAC[7:0];eth_head[6]  <= BOARD_MAC[47:40];  //源MAC地址eth_head[7]  <= BOARD_MAC[39:32];eth_head[8]  <= BOARD_MAC[31:24];eth_head[9]  <= BOARD_MAC[23:16];eth_head[10] <= BOARD_MAC[15:8];eth_head[11] <= BOARD_MAC[7:0];eth_head[12] <= ETH_TYPE[15:8];  //以太网帧类型eth_head[13] <= ETH_TYPE[7:0];//ARP数据                           arp_data[0]  <= HD_TYPE[15:8];  //硬件类型arp_data[1]  <= HD_TYPE[7:0];arp_data[2]  <= PROTOCOL_TYPE[15:8];  //上层协议类型arp_data[3]  <= PROTOCOL_TYPE[7:0];arp_data[4]  <= 8'h06;  //硬件地址长度,6arp_data[5]  <= 8'h04;  //协议地址长度,4arp_data[6]  <= 8'h00;  //OP,操作码 8'h01:ARP请求 8'h02:ARP应答arp_data[7]  <= 8'h01;arp_data[8]  <= BOARD_MAC[47:40];  //发送端(源)MAC地址arp_data[9]  <= BOARD_MAC[39:32];arp_data[10] <= BOARD_MAC[31:24];arp_data[11] <= BOARD_MAC[23:16];arp_data[12] <= BOARD_MAC[15:8];arp_data[13] <= BOARD_MAC[7:0];arp_data[14] <= BOARD_IP[31:24];  //发送端(源)IP地址arp_data[15] <= BOARD_IP[23:16];arp_data[16] <= BOARD_IP[15:8];arp_data[17] <= BOARD_IP[7:0];arp_data[18] <= DES_MAC[47:40];  //接收端(目的)MAC地址arp_data[19] <= DES_MAC[39:32];arp_data[20] <= DES_MAC[31:24];arp_data[21] <= DES_MAC[23:16];arp_data[22] <= DES_MAC[15:8];arp_data[23] <= DES_MAC[7:0];arp_data[24] <= DES_IP[31:24];  //接收端(目的)IP地址arp_data[25] <= DES_IP[23:16];arp_data[26] <= DES_IP[15:8];arp_data[27] <= DES_IP[7:0];end else beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case (next_state)st_idle: beginif (pos_tx_en) beginskip_en <= 1'b1;//如果目标MAC地址和IP地址已经更新,则发送正确的地址if ((des_mac != 48'b0) || (des_ip != 32'd0)) begineth_head[0]  <= des_mac[47:40];eth_head[1]  <= des_mac[39:32];eth_head[2]  <= des_mac[31:24];eth_head[3]  <= des_mac[23:16];eth_head[4]  <= des_mac[15:8];eth_head[5]  <= des_mac[7:0];arp_data[18] <= des_mac[47:40];arp_data[19] <= des_mac[39:32];arp_data[20] <= des_mac[31:24];arp_data[21] <= des_mac[23:16];arp_data[22] <= des_mac[15:8];arp_data[23] <= des_mac[7:0];arp_data[24] <= des_ip[31:24];arp_data[25] <= des_ip[23:16];arp_data[26] <= des_ip[15:8];arp_data[27] <= des_ip[7:0];endif (arp_tx_type == 1'b0) arp_data[7] <= 8'h01;  //ARP请求 else arp_data[7] <= 8'h02;  //ARP应答endendst_preamble: begin  //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd   <= preamble[cnt];if (cnt == 6'd7) beginskip_en <= 1'b1;cnt <= 1'b0;end else cnt <= cnt + 1'b1;endst_eth_head: begin  //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 6'd13) beginskip_en <= 1'b1;cnt <= 1'b0;end else cnt <= cnt + 1'b1;endst_arp_data: begin  //发送ARP数据  crc_en <= 1'b1;gmii_tx_en <= 1'b1;//至少发送46个字节if (cnt == MIN_DATA_NUM - 1'b1) beginskip_en <= 1'b1;cnt <= 1'b0;data_cnt <= 1'b0;end else cnt <= cnt + 1'b1;if (data_cnt <= 6'd27) begindata_cnt <= data_cnt + 1'b1;gmii_txd <= arp_data[data_cnt];end else gmii_txd <= 8'd0;  //Padding,填充0endst_crc: begin  //发送CRC校验值gmii_tx_en <= 1'b1;cnt <= cnt + 1'b1;if (cnt == 6'd0)gmii_txd <= {~crc_next[0],~crc_next[1],~crc_next[2],~crc_next[3],~crc_next[4],~crc_next[5],~crc_next[6],~crc_next[7]};else if (cnt == 6'd1)gmii_txd <= {~crc_data[16],~crc_data[17],~crc_data[18],~crc_data[19],~crc_data[20],~crc_data[21],~crc_data[22],~crc_data[23]};else if (cnt == 6'd2) begingmii_txd <= {~crc_data[8],~crc_data[9],~crc_data[10],~crc_data[11],~crc_data[12],~crc_data[13],~crc_data[14],~crc_data[15]};end else if (cnt == 6'd3) begingmii_txd <= {~crc_data[0],~crc_data[1],~crc_data[2],~crc_data[3],~crc_data[4],~crc_data[5],~crc_data[6],~crc_data[7]};tx_done_t <= 1'b1;skip_en <= 1'b1;cnt <= 1'b0;endenddefault: ;endcaseendend//发送完成信号及crc值复位信号always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;end else begintx_done <= tx_done_t;crc_clr <= tx_done_t;endendendmodule

 2.15 CRC32校验模块

`timescale 1ns / 1ps
//CRC32校验模块module crc32_d8 (input             clk,       //时钟信号input             rst_n,     //复位信号,低电平有效input      [ 7:0] data,      //输入待校验8位数据input             crc_en,    //crc使能,开始校验标志input             crc_clr,   //crc数据复位信号            output reg [31:0] crc_data,  //CRC校验数据output     [31:0] crc_next   //CRC下次校验完成数据
);//*****************************************************//**                    main code//*****************************************************//输入待校验8位数据,需要先将高低位互换wire [7:0] data_t;assign data_t = {data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]};//CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 //+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6] ^ data_t[7];assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] ^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4] ^ data_t[6];assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29] ^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[7];assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]^ data_t[6] ^ data_t[7];assign crc_next[15] =  crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29] ^ data_t[0] ^ data_t[4] ^ data_t[5];assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30] ^ data_t[1] ^ data_t[5] ^ data_t[6];assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[6] ^ data_t[7];assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ data_t[0] ^ data_t[1] ^ data_t[6];assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[7];assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28] ^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29] ^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30] ^ data_t[2] ^ data_t[5] ^ data_t[6];assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31] ^ data_t[3] ^ data_t[6] ^ data_t[7];assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];always @(posedge clk or negedge rst_n) beginif (!rst_n) crc_data <= 32'hff_ff_ff_ff;else if (crc_clr)  //CRC校验值复位crc_data <= 32'hff_ff_ff_ff;else if (crc_en) crc_data <= crc_next;endendmodule

2.16 udp顶层模块

`timescale 1ns / 1ps
//udp顶层模块module udp_top (input         rst_n,         //复位信号,低电平有效//GMII接口input         gmii_rx_clk,   //GMII接收数据时钟input         gmii_rx_dv,    //GMII输入数据有效信号input  [ 7:0] gmii_rxd,      //GMII输入数据input         gmii_tx_clk,   //GMII发送数据时钟    output        gmii_tx_en,    //GMII输出数据有效信号output [ 7:0] gmii_txd,      //GMII输出数据 //用户接口output        rec_pkt_done,  //以太网单包数据接收完成信号output        rec_en,        //以太网接收的数据使能信号output [31:0] rec_data,      //以太网接收的数据output [15:0] rec_byte_num,  //以太网接收的有效字节数 单位:byte     input         tx_start_en,   //以太网开始发送信号input  [31:0] tx_data,       //以太网待发送数据  input  [15:0] tx_byte_num,   //以太网发送的有效字节数 单位:byte  input  [47:0] des_mac,       //发送的目标MAC地址input  [31:0] des_ip,        //发送的目标IP地址    output        tx_done,       //以太网发送完成信号output        tx_req         //读数据请求信号    
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10     parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};//wire definewire        crc_en;  //CRC开始校验使能wire        crc_clr;  //CRC数据复位信号 wire [ 7:0] crc_d8;  //输入待校验8位数据wire [31:0] crc_data;  //CRC校验数据wire [31:0] crc_next;  //CRC下次校验完成数据//*****************************************************//**                    main code//*****************************************************assign crc_d8 = gmii_txd;//以太网接收模块    udp_rx #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP)) u_udp_rx (.clk         (gmii_rx_clk),.rst_n       (rst_n),.gmii_rx_dv  (gmii_rx_dv),.gmii_rxd    (gmii_rxd),.rec_pkt_done(rec_pkt_done),.rec_en      (rec_en),.rec_data    (rec_data),.rec_byte_num(rec_byte_num));//以太网发送模块udp_tx #(.BOARD_MAC(BOARD_MAC),  //参数例化.BOARD_IP (BOARD_IP),.DES_MAC  (DES_MAC),.DES_IP   (DES_IP)) u_udp_tx (.clk        (gmii_tx_clk),.rst_n      (rst_n),.tx_start_en(tx_start_en),.tx_data    (tx_data),.tx_byte_num(tx_byte_num),.des_mac    (des_mac),.des_ip     (des_ip),.crc_data   (crc_data),.crc_next   (crc_next[31:24]),.tx_done    (tx_done),.tx_req     (tx_req),.gmii_tx_en (gmii_tx_en),.gmii_txd   (gmii_txd),.crc_en     (crc_en),.crc_clr    (crc_clr));//以太网发送CRC校验模块crc32_d8 u_crc32_d8 (.clk     (gmii_tx_clk),.rst_n   (rst_n),.data    (crc_d8),.crc_en  (crc_en),.crc_clr (crc_clr),.crc_data(crc_data),.crc_next(crc_next));endmodule

2.17 udp数据接收模块

`timescale 1ns / 1ps
//udp数据接收模块module udp_rx (input clk,   //时钟信号input rst_n, //复位信号,低电平有效input             gmii_rx_dv,    //GMII输入数据有效信号input      [ 7:0] gmii_rxd,      //GMII输入数据output reg        rec_pkt_done,  //以太网单包数据接收完成信号output reg        rec_en,        //以太网接收的数据使能信号output reg [31:0] rec_data,      //以太网接收的数据output reg [15:0] rec_byte_num   //以太网接收的有效字数 单位:byte     
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};localparam st_idle = 7'b000_0001;  //初始状态,等待接收前导码localparam st_preamble = 7'b000_0010;  //接收前导码状态 localparam st_eth_head = 7'b000_0100;  //接收以太网帧头localparam st_ip_head = 7'b000_1000;  //接收IP首部localparam st_udp_head = 7'b001_0000;  //接收UDP首部localparam st_rx_data = 7'b010_0000;  //接收有效数据localparam st_rx_end = 7'b100_0000;  //接收结束localparam ETH_TYPE = 16'h0800;  //以太网协议类型 IP协议//reg definereg [ 6:0] cur_state;reg [ 6:0] next_state;reg        skip_en;  //控制状态跳转使能信号reg        error_en;  //解析错误使能信号reg [ 4:0] cnt;  //解析数据计数器reg [47:0] des_mac;  //目的MAC地址reg [15:0] eth_type;  //以太网类型reg [31:0] des_ip;  //目的IP地址reg [ 5:0] ip_head_byte_num;  //IP首部长度reg [15:0] udp_byte_num;  //UDP长度reg [15:0] data_byte_num;  //数据长度reg [15:0] data_cnt;  //有效数据计数    reg [ 1:0] rec_en_cnt;  //8bit转32bit计数器//*****************************************************//**                    main code//*****************************************************//(三段式状态机)同步时序描述状态转移always @(posedge clk or negedge rst_n) beginif (!rst_n) cur_state <= st_idle;else cur_state <= next_state;end//组合逻辑判断状态转移条件always @(*) beginnext_state = st_idle;case (cur_state)st_idle: begin  //等待接收前导码if (skip_en) next_state = st_preamble;else next_state = st_idle;endst_preamble: begin  //接收前导码if (skip_en) next_state = st_eth_head;else if (error_en) next_state = st_rx_end;else next_state = st_preamble;endst_eth_head: begin  //接收以太网帧头if (skip_en) next_state = st_ip_head;else if (error_en) next_state = st_rx_end;else next_state = st_eth_head;endst_ip_head: begin  //接收IP首部if (skip_en) next_state = st_udp_head;else if (error_en) next_state = st_rx_end;else next_state = st_ip_head;endst_udp_head: begin  //接收UDP首部if (skip_en) next_state = st_rx_data;else next_state = st_udp_head;endst_rx_data: begin  //接收有效数据if (skip_en) next_state = st_rx_end;else next_state = st_rx_data;endst_rx_end: begin  //接收结束if (skip_en) next_state = st_idle;else next_state = st_rx_end;enddefault: next_state = st_idle;endcaseend//时序电路描述状态输出,解析以太网数据always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac <= 48'd0;eth_type <= 16'd0;des_ip <= 32'd0;ip_head_byte_num <= 6'd0;udp_byte_num <= 16'd0;data_byte_num <= 16'd0;data_cnt <= 16'd0;rec_en_cnt <= 2'd0;rec_en <= 1'b0;rec_data <= 32'd0;rec_pkt_done <= 1'b0;rec_byte_num <= 16'd0;end else beginskip_en <= 1'b0;error_en <= 1'b0;rec_en <= 1'b0;rec_pkt_done <= 1'b0;case (next_state)st_idle: beginif ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;endst_preamble: beginif (gmii_rx_dv) begin  //解析前导码cnt <= cnt + 5'd1;if ((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55  error_en <= 1'b1;else if (cnt == 5'd6) begincnt <= 5'd0;if (gmii_rxd == 8'hd5)  //1个8'hd5skip_en <= 1'b1;else error_en <= 1'b1;endendendst_eth_head: beginif (gmii_rx_dv) begincnt <= cnt + 5'b1;if (cnt < 5'd6) des_mac <= {des_mac[39:0], gmii_rxd};  //目的MAC地址else if (cnt == 5'd12) eth_type[15:8] <= gmii_rxd;  //以太网协议类型else if (cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;//判断MAC地址是否为开发板MAC地址或者公共地址if(((des_mac == BOARD_MAC) ||(des_mac == 48'hff_ff_ff_ff_ff_ff))&& eth_type[15:8] == ETH_TYPE[15:8] && gmii_rxd == ETH_TYPE[7:0])skip_en <= 1'b1;else error_en <= 1'b1;endendendst_ip_head: beginif (gmii_rx_dv) begincnt <= cnt + 5'd1;if (cnt == 5'd0) ip_head_byte_num <= {gmii_rxd[3:0], 2'd0};else if ((cnt >= 5'd16) && (cnt <= 5'd18))des_ip <= {des_ip[23:0], gmii_rxd};  //目的IP地址else if (cnt == 5'd19) begindes_ip <= {des_ip[23:0], gmii_rxd};//判断IP地址是否为开发板IP地址if ((des_ip[23:0] == BOARD_IP[31:8]) && (gmii_rxd == BOARD_IP[7:0])) beginif (cnt == ip_head_byte_num - 1'b1) beginskip_en <= 1'b1;cnt <= 5'd0;endend else begin//IP错误,停止解析数据                        error_en <= 1'b1;cnt <= 5'd0;endend else if (cnt == ip_head_byte_num - 1'b1) beginskip_en <= 1'b1;  //IP首部解析完成cnt     <= 5'd0;endendendst_udp_head: beginif (gmii_rx_dv) begincnt <= cnt + 5'd1;if (cnt == 5'd4) udp_byte_num[15:8] <= gmii_rxd;  //解析UDP字节长度 else if (cnt == 5'd5) udp_byte_num[7:0] <= gmii_rxd;else if (cnt == 5'd7) begin//有效数据字节长度,(UDP首部8个字节,所以减去8)data_byte_num <= udp_byte_num - 16'd8;skip_en <= 1'b1;cnt <= 5'd0;endendendst_rx_data: begin//接收数据,转换成32bit            if (gmii_rx_dv) begindata_cnt   <= data_cnt + 16'd1;rec_en_cnt <= rec_en_cnt + 2'd1;if (data_cnt == data_byte_num - 16'd1) beginskip_en      <= 1'b1;  //有效数据接收完成data_cnt     <= 16'd0;rec_en_cnt   <= 2'd0;rec_pkt_done <= 1'b1;rec_en       <= 1'b1;rec_byte_num <= data_byte_num;end//先收到的数据放在了rec_data的高位,所以当数据不是4的倍数时,//低位数据为无效数据,可根据有效字节数来判断(rec_byte_num)if (rec_en_cnt == 2'd0) rec_data[31:24] <= gmii_rxd;else if (rec_en_cnt == 2'd1) rec_data[23:16] <= gmii_rxd;else if (rec_en_cnt == 2'd2) rec_data[15:8] <= gmii_rxd;else if (rec_en_cnt == 2'd3) beginrec_en <= 1'b1;rec_data[7:0] <= gmii_rxd;endendendst_rx_end: begin  //单包数据接收完成   if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;enddefault: ;endcaseendendendmodule

2.18 udp数据发送模块

`timescale 1ns / 1ps
//udp数据发送模块module udp_tx (input clk,   //时钟信号input rst_n, //复位信号,低电平有效input             tx_start_en,  //以太网开始发送信号input      [31:0] tx_data,      //以太网待发送数据  input      [15:0] tx_byte_num,  //以太网发送的有效字节数input      [47:0] des_mac,      //发送的目标MAC地址input      [31:0] des_ip,       //发送的目标IP地址    input      [31:0] crc_data,     //CRC校验数据input      [ 7:0] crc_next,     //CRC下次校验完成数据output reg        tx_done,      //以太网发送完成信号output reg        tx_req,       //读数据请求信号output reg        gmii_tx_en,   //GMII输出数据有效信号output reg [ 7:0] gmii_txd,     //GMII输出数据output reg        crc_en,       //CRC开始校验使能output reg        crc_clr       //CRC数据复位信号 
);//parameter define//开发板MAC地址 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55;//开发板IP地址 192.168.1.123     parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd123};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102     parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};localparam st_idle = 7'b000_0001;  //初始状态,等待开始发送信号localparam st_check_sum = 7'b000_0010;  //IP首部校验和localparam st_preamble = 7'b000_0100;  //发送前导码+帧起始界定符localparam st_eth_head = 7'b000_1000;  //发送以太网帧头localparam st_ip_head = 7'b001_0000;  //发送IP首部+UDP首部localparam st_tx_data = 7'b010_0000;  //发送数据localparam st_crc = 7'b100_0000;  //发送CRC校验值localparam ETH_TYPE = 16'h0800;  //以太网协议类型 IP协议//以太网数据最小46个字节,IP首部20个字节+UDP首部8个字节//所以数据至少46-20-8=18个字节localparam MIN_DATA_NUM = 16'd18;//reg definereg [6:0] cur_state;reg [6:0] next_state;reg [7:0] preamble[7:0];  //前导码reg [7:0] eth_head[13:0];  //以太网首部reg [31:0] ip_head[6:0];  //IP首部 + UDP首部reg start_en_d0;reg start_en_d1;reg [15:0] tx_data_num;  //发送的有效数据字节个数reg [15:0] total_num;  //总字节数reg trig_tx_en;reg [15:0] udp_num;  //UDP字节数reg skip_en;  //控制状态跳转使能信号reg [4:0] cnt;reg [31:0] check_buffer;  //首部校验和reg [1:0] tx_bit_sel;reg [15:0] data_cnt;  //发送数据个数计数器reg tx_done_t;reg [4:0] real_add_cnt;  //以太网数据实际多发的字节数//wire define                       wire pos_start_en;  //开始发送数据上升沿wire [15:0] real_tx_data_num;  //实际发送的字节数(以太网最少字节要求)//*****************************************************//**                    main code//*****************************************************assign pos_start_en = (~start_en_d1) & start_en_d0;assign real_tx_data_num = (tx_data_num >= MIN_DATA_NUM) ? tx_data_num : MIN_DATA_NUM;//采tx_start_en的上升沿always @(posedge clk or negedge rst_n) beginif (!rst_n) beginstart_en_d0 <= 1'b0;start_en_d1 <= 1'b0;end else beginstart_en_d0 <= tx_start_en;start_en_d1 <= start_en_d0;endend//寄存数据有效字节always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_data_num <= 16'd0;total_num <= 16'd0;udp_num <= 16'd0;end else beginif (pos_start_en && cur_state == st_idle) begin//数据长度tx_data_num <= tx_byte_num;//IP长度:有效数据+IP首部长度            total_num <= tx_byte_num + 16'd28;//UDP长度:有效数据+UDP首部长度            udp_num <= tx_byte_num + 16'd8;endendend//触发发送信号always @(posedge clk or negedge rst_n) beginif (!rst_n) trig_tx_en <= 1'b0;else trig_tx_en <= pos_start_en;endalways @(posedge clk or negedge rst_n) beginif (!rst_n) cur_state <= st_idle;else cur_state <= next_state;endalways @(*) beginnext_state = st_idle;case (cur_state)st_idle: begin  //等待发送数据if (skip_en) next_state = st_check_sum;else next_state = st_idle;endst_check_sum: begin  //IP首部校验if (skip_en) next_state = st_preamble;else next_state = st_check_sum;endst_preamble: begin  //发送前导码+帧起始界定符if (skip_en) next_state = st_eth_head;else next_state = st_preamble;endst_eth_head: begin  //发送以太网首部if (skip_en) next_state = st_ip_head;else next_state = st_eth_head;endst_ip_head: begin  //发送IP首部+UDP首部               if (skip_en) next_state = st_tx_data;else next_state = st_ip_head;endst_tx_data: begin  //发送数据                  if (skip_en) next_state = st_crc;else next_state = st_tx_data;endst_crc: begin  //发送CRC校验值if (skip_en) next_state = st_idle;else next_state = st_crc;enddefault: next_state = st_idle;endcaseend//发送数据always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en <= 1'b0;cnt <= 5'd0;check_buffer <= 32'd0;ip_head[1][31:16] <= 16'd0;tx_bit_sel <= 2'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;gmii_txd <= 8'd0;tx_req <= 1'b0;tx_done_t <= 1'b0;data_cnt <= 16'd0;real_add_cnt <= 5'd0;//初始化数组    //前导码 7个8'h55 + 1个8'hd5preamble[0] <= 8'h55;preamble[1] <= 8'h55;preamble[2] <= 8'h55;preamble[3] <= 8'h55;preamble[4] <= 8'h55;preamble[5] <= 8'h55;preamble[6] <= 8'h55;preamble[7] <= 8'hd5;//目的MAC地址eth_head[0] <= DES_MAC[47:40];eth_head[1] <= DES_MAC[39:32];eth_head[2] <= DES_MAC[31:24];eth_head[3] <= DES_MAC[23:16];eth_head[4] <= DES_MAC[15:8];eth_head[5] <= DES_MAC[7:0];//源MAC地址eth_head[6] <= BOARD_MAC[47:40];eth_head[7] <= BOARD_MAC[39:32];eth_head[8] <= BOARD_MAC[31:24];eth_head[9] <= BOARD_MAC[23:16];eth_head[10] <= BOARD_MAC[15:8];eth_head[11] <= BOARD_MAC[7:0];//以太网类型eth_head[12] <= ETH_TYPE[15:8];eth_head[13] <= ETH_TYPE[7:0];end else beginskip_en <= 1'b0;tx_req <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case (next_state)st_idle: beginif (trig_tx_en) beginskip_en <= 1'b1;//版本号:4 首部长度:5(单位:32bit,20byte/4=5)ip_head[0] <= {8'h45, 8'h00, total_num};//16位标识,每次发送累加1      ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;//bit[15:13]: 010表示不分片ip_head[1][15:0] <= 16'h4000;//协议:17(udp)                  ip_head[2] <= {8'h40, 8'd17, 16'h0};//源IP地址               ip_head[3] <= BOARD_IP;//目的IP地址    if (des_ip != 32'd0) ip_head[4] <= des_ip;else ip_head[4] <= DES_IP;//16位源端口号:1234  16位目的端口号:1234                      ip_head[5] <= {16'd1234, 16'd1234};//16位udp长度,16位udp校验和              ip_head[6] <= {udp_num, 16'h0000};//更新MAC地址if (des_mac != 48'b0) begin//目的MAC地址eth_head[0] <= des_mac[47:40];eth_head[1] <= des_mac[39:32];eth_head[2] <= des_mac[31:24];eth_head[3] <= des_mac[23:16];eth_head[4] <= des_mac[15:8];eth_head[5] <= des_mac[7:0];endendendst_check_sum: begin  //IP首部校验cnt <= cnt + 5'd1;if (cnt == 5'd0) begincheck_buffer <= ip_head[0][31:16] + ip_head[0][15:0]+ ip_head[1][31:16] + ip_head[1][15:0]+ ip_head[2][31:16] + ip_head[2][15:0]+ ip_head[3][31:16] + ip_head[3][15:0]+ ip_head[4][31:16] + ip_head[4][15:0];end else if (cnt == 5'd1)  //可能出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];else if (cnt == 5'd2) begin  //可能再次出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];end else if (cnt == 5'd3) begin  //按位取反 skip_en <= 1'b1;cnt <= 5'd0;ip_head[2][15:0] <= ~check_buffer[15:0];endendst_preamble: begin  //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd   <= preamble[cnt];if (cnt == 5'd7) beginskip_en <= 1'b1;cnt <= 5'd0;end else cnt <= cnt + 5'd1;endst_eth_head: begin  //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 5'd13) beginskip_en <= 1'b1;cnt <= 5'd0;end else cnt <= cnt + 5'd1;endst_ip_head: begin  //发送IP首部 + UDP首部crc_en <= 1'b1;gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 2'd1;if (tx_bit_sel == 3'd0) gmii_txd <= ip_head[cnt][31:24];else if (tx_bit_sel == 3'd1) gmii_txd <= ip_head[cnt][23:16];else if (tx_bit_sel == 3'd2) begingmii_txd <= ip_head[cnt][15:8];if (cnt == 5'd6) begin//提前读请求数据,等待数据有效时发送tx_req <= 1'b1;endend else if (tx_bit_sel == 3'd3) begingmii_txd <= ip_head[cnt][7:0];if (cnt == 5'd6) beginskip_en <= 1'b1;cnt <= 5'd0;end else cnt <= cnt + 5'd1;endendst_tx_data: begin  //发送数据crc_en <= 1'b1;gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 3'd1;if (data_cnt < tx_data_num - 16'd1) data_cnt <= data_cnt + 16'd1;else if (data_cnt == tx_data_num - 16'd1) begin//如果发送的有效数据少于18个字节,在后面填补充位//补充的值为最后一次发送的有效数据gmii_txd <= 8'd0;if (data_cnt + real_add_cnt < real_tx_data_num - 16'd1)real_add_cnt <= real_add_cnt + 5'd1;else beginskip_en <= 1'b1;data_cnt <= 16'd0;real_add_cnt <= 5'd0;tx_bit_sel <= 3'd0;endendif (tx_bit_sel == 1'b0) gmii_txd <= tx_data[31:24];else if (tx_bit_sel == 3'd1) gmii_txd <= tx_data[23:16];else if (tx_bit_sel == 3'd2) begingmii_txd <= tx_data[15:8];if (data_cnt != tx_data_num - 16'd1) tx_req <= 1'b1;end else if (tx_bit_sel == 3'd3) gmii_txd <= tx_data[7:0];endst_crc: begin  //发送CRC校验值gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 3'd1;if (tx_bit_sel == 3'd0)gmii_txd <= {~crc_next[0],~crc_next[1],~crc_next[2],~crc_next[3],~crc_next[4],~crc_next[5],~crc_next[6],~crc_next[7]};else if (tx_bit_sel == 3'd1)gmii_txd <= {~crc_data[16],~crc_data[17],~crc_data[18],~crc_data[19],~crc_data[20],~crc_data[21],~crc_data[22],~crc_data[23]};else if (tx_bit_sel == 3'd2) begingmii_txd <= {~crc_data[8],~crc_data[9],~crc_data[10],~crc_data[11],~crc_data[12],~crc_data[13],~crc_data[14],~crc_data[15]};end else if (tx_bit_sel == 3'd3) begingmii_txd <= {~crc_data[0],~crc_data[1],~crc_data[2],~crc_data[3],~crc_data[4],~crc_data[5],~crc_data[6],~crc_data[7]};tx_done_t <= 1'b1;skip_en <= 1'b1;endenddefault: ;endcaseendend//发送完成信号及crc值复位信号always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;end else begintx_done <= tx_done_t;crc_clr <= tx_done_t;endendendmodule

2.19 以太网控制模块

`timescale 1ns / 1ps
//以太网控制模块module eth_ctrl (input        clk,             //系统时钟input        rst_n,           //系统复位信号,低电平有效 //ARP相关端口信号                                  input        arp_rx_done,     //ARP接收完成信号input        arp_rx_type,     //ARP接收类型 0:请求  1:应答output       arp_tx_en,       //ARP发送使能信号output       arp_tx_type,     //ARP发送类型 0:请求  1:应答input        arp_tx_done,     //ARP发送完成信号input        arp_gmii_tx_en,  //ARP GMII输出数据有效信号 input  [7:0] arp_gmii_txd,    //ARP GMII输出数据//UDP相关端口信号input        udp_gmii_tx_en,  //UDP GMII输出数据有效信号  input  [7:0] udp_gmii_txd,    //UDP GMII输出数据   //GMII发送引脚output       gmii_tx_en,      //GMII输出数据有效信号 output [7:0] gmii_txd         //UDP GMII输出数据 
);//reg definereg protocol_sw;  //协议切换信号//*****************************************************//**                    main code//*****************************************************assign arp_tx_en = arp_rx_done && (arp_rx_type == 1'b0);assign arp_tx_type = 1'b1;  //ARP发送类型固定为ARP应答                                   assign gmii_tx_en = protocol_sw ? udp_gmii_tx_en : arp_gmii_tx_en;assign gmii_txd = protocol_sw ? udp_gmii_txd : arp_gmii_txd;//根据ARP发送使能/完成信号,切换GMII引脚always @(posedge clk or negedge rst_n) beginif (!rst_n) protocol_sw <= 1'b1;else if (arp_tx_en) protocol_sw <= 1'b0;else if (arp_tx_done) protocol_sw <= 1'b1;endendmodule

3 上位机验证

使用正点原子以太网视频传输上位机即可显示画面

这篇关于FPGA ov5640视频以太网传输的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972370

相关文章

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

树莓派5_opencv笔记27:Opencv录制视频(无声音)

今日继续学习树莓派5 8G:(Raspberry Pi,简称RPi或RasPi)  本人所用树莓派5 装载的系统与版本如下:  版本可用命令 (lsb_release -a) 查询: Opencv 与 python 版本如下: 今天就水一篇文章,用树莓派摄像头,Opencv录制一段视频保存在指定目录... 文章提供测试代码讲解,整体代码贴出、测试效果图 目录 阶段一:录制一段

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是:

PC与android平板通过浏览器监控Verybot的视频

下面这个视频是PC与android平板通过浏览器监控Verybot的视频:           http://v.youku.com/v_show/id_XNjYzNzYyMTIw.html

Verybot的几个视频

1、Verybot的运动控制                 http://v.youku.com/v_show/id_XNjYxNjg4MTM2.html           2、Verybot比较初步的网络视频监控           http://v.youku.com/v_show/id_XNjYxNjkyMjg0.html           3、V

java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频)

这是什么系统? 资源获取方式在最下方 java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频) 停车管理信息系统是为了提升停车场的运营效率和管理水平而设计的综合性平台。系统涵盖用户信息管理、车位管理、收费管理、违规车辆处理等多个功能模块,旨在实现对停车场资源的高效配置和实时监控。此外,系统还提供了资讯管理和统计查询功能,帮助管理者及时发布信息并进行数据分析,为停车场的科学

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬