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 上位机验证

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8591.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++初阶]string的几道oj题

1.LCR 192. 把字符串转换成整数 (atoi) 这题难度不大,我这里采取遍历跳过空格的方式&#xff0c;我先展示出我的代码,然后慢慢讲解: class Solution { public:int myAtoi(string str) {if (str.empty()) return 0;int lengthstr.size();int i0;int symbol1;int sum0;while(i&l…

春游江淮 请来池州|一起看看石台这条“天路”有多美

自驾石台天路 石台天路位于安徽省石台县,西起杜村蓬莱仙洞,东起七都镇,全程约65公里,其中核心路段海拔均在650米以上,最高处海拔坐标位置901米,自驾其中,一路穿越山乡秘境,丛林、山脉、古村、古桥、流水、人家……扑面而来。 沿着蜿蜒的山路前行,一路上的风景如诗如画,青山如黛…

IT项目管理 选择/判断 【太原理工大学】

第一章、IT项目管理 判断题 1、搬家属于项目。&#xff08; 对 &#xff09; 2、项目是为了创造一个唯一的产品或提供一个唯一的服务而进行的永久性的努力。&#xff08; 错 &#xff09; 3、项目具有临时性的特征。&#xff08; 对 &#xff09; 4、项目开发过程…

你的计算机配置似乎是正确的,但该设备或资源DNS没有响应

方法/步骤 方法一&#xff1a; 快捷键“winr”,输入services.msc&#xff0c;进入服务界面&#xff0c;找到dnsclient&#xff0c;确保是运行状态&#xff0c;如果没有运行&#xff0c;则选中该条目&#xff0c;右键选择运行。 电脑提示“您的计算机配置似乎是正确”&#xf…

长难句打卡5.6

For H&M to offer a $5.95 knit miniskirt in all its 2,300-plus stores around the world, it must rely on low-wage overseas labor, order in volumes that strain natural resources, and use massive amounts of harmful chemicals. 翻译:H&M若要在其全球总共2…

.Net MAUI 搭建Android 开发环境

一、 安装最新版本 VS 2022 安装时候选择上 .Net MAUI 跨平台开发 二、安装成功后,创建 .Net MAUI 应用 三、使用 VS 自带的 Android SDK 下载 ,Android镜像、编译工具、加速工具 四、使用Vs 自带的 Android Avd 创建虚拟机 五、使用 Android 手机真机调试

【软考高项】三十五、资源管理基础内容

一、管理基础 项目资源管理包括识别、获取和管理所需资源以成功完成项目的各个过程&#xff0c;包括实物资源和团队资源。项目资源管理是为了降低项目成本&#xff0c;而对项目所需的人力、材料、机械、技术、资金等资源所进行的计划、组织、指挥、协调和控制等的活动。项目团…

Milvus Cloud 的RAG 的广泛应用及其独特优势

一个典型的 RAG 框架可以分为检索器(Retriever)和生成器(Generator)两块,检索过程包括为数据(如 Documents)做切分、嵌入向量(Embedding)、并构建索引(Chunks Vectors),再通过向量检索以召回相关结果,而生成过程则是利用基于检索结果(Context)增强的 Prompt 来激…

Web API之DOM

DOM 一.认识DOM二.获取元素三.事件基础四.操作元素(1).改变元素内容(2).修改元素属性(str、herf、id、alt、title&#xff09;(3).修改表单属性(4).修改样式属性操作(5).小结 五.一些思想(1).排他思想(2).自定义属性的操作 六.节点操作1.认识2.节点层级关系3.创建和添加、删除、…

leetcode91.解码方法(动态规划)

问题描述&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可…

HFSS学习-day2-T形波导的优化设计

入门实例–T形波导的内场分析和优化设计 HFSS--此实例优化设计 优化设计要求1. 定义输出变量Power31、Power21、和Power11&#xff0c;表示Port3、Port2、Port1的输出功率2.参数扫描分析添加扫描变量和输出变量进行一个小设置添加输出变量进行扫描分析 3. 优化设计&#xff0c…

卸载系统自带APP

Firefly RK3588 android 12自动多个系统软件&#xff0c;无法从UI界面进行手动删除。因此&#xff0c;考虑使用shell指令进行处理。 系统自动APP大多都安装在system/app目录下&#xff0c;且该目录多为只读。因此采用如下步骤&#xff0c; //Shell su adb shell su //重新挂载…

【Linux】线程的内核级理解详谈页表以及虚拟地址到物理地址之间的转化

一、线程的概念 对于进程来说&#xff0c;进程创建时间和空间成本较高&#xff0c;因为进程是承担分配系统资源的基本实体&#xff0c;所以线程的出现就成为了必然。Linux线程与进程非常相似&#xff0c;Linux设计者在设计之初觉得如果再为线程设计数据结构和调度算法就会使整个…

增量同步笔记

2.2.2.增量同步 全量同步需要先做RDB&#xff0c;然后将RDB文件通过网络传输个slave&#xff0c;成本太高了。因此除了第一次做全量同步&#xff0c;其它大多数时候slave与master都是做增量同步。 什么是增量同步&#xff1f;就是只更新slave与master存在差异的部分数据。如图…

kubeflow简单记录

kubeflow 13.7k star 1、Training Operator 包括PytorchJob和XGboostJob&#xff0c;支持部署pytorch的分布式训练 2、KFServing快捷的部署推理服务 3、Jupyter Notebook 基于Web的交互式工具 4、Katib做超参数优化 5、Pipeline 基于Argo Workflow提供机器学习流程的创建、编排…

JAVA系列 小白入门参考资料 接口

目录 接口 接口的概念 语法 接口使用 接口实现用例 接口特性 实现多个接口和实现用例 接口间的继承 接口 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的 USB 口&#xff0c;电源插座等。 电脑的 USB 口上&am…

【C语言】字符函数和字符串函数--超详解

前言&#xff1a; 在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了⽅便操作字符和字符串&#xff0c;C语⾔标准库中提供了 ⼀系列库函数&#xff0c;接下来我们就学习⼀下这些函数。 1. 字符分类函数 C语⾔中有⼀系列的函数是专⻔做字符分类的&#…

C++贪心算法

关于string的系统函数&#xff01; &#xff08;注&#xff1a;以下函数只可用于string&#xff0c;不适用其他类型的变量&#xff09; ① a.size(); 这个系统函数是用来获取这个string变量的长度的&#xff0c;我们通常会新建一个变量来保存他&#xff0c;以便之后使用。 …

Spring Boot | Spring Boot 整合 “RabbitMQ“ ( 消息中间件 ) 实现

目录: Spring Boot 整合 "RabbitMQ" ( 消息中间件 )实现 &#xff1a;一、Spring Boot 整合 整合实现 : Publish/Subscribe ( 发布订阅 ) 工作模式 ( "3种"整合实现方式 )1.1 基于"API"的方式 ( 实现 Publish/Subscribe "发布订阅"工作…

使用 MobaXterm 链接 Ubuntu(Windows子系统)

MobaXterm_Personal_22.1 Ubuntu&#xff08;Windows子系统&#xff09;