vue做的网站大全,wordpress添加打赏,学做网站论坛插件,wordpress获取站点链接1 实验任务
使用DFZU4EV MPSoC 开发板及双目OV5640摄像头其中一个摄像头实现图像采集#xff0c;并通过开发板上的以太网接口发送给上位机实时显示。
2 Verilog代码
2.1 顶层模块
timescale 1ns / 1ps
//以太网传输视频顶层模块module ov5640_udp_pc (input sys_cl…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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};parameter H_CMOS_DISP 11d640; //CMOS分辨率--行parameter V_CMOS_DISP 11d480; //CMOS分辨率--列 parameter TOTAL_H_PIXEL H_CMOS_DISP 12d1216; //水平总像素大小parameter TOTAL_V_PIXEL V_CMOS_DISP 12d504; //垂直总像素大小//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));endmodule2.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 7h3c; //OV5640的器件地址7h3cparameter BIT_CTRL 1b1; //OV5640的字节地址为16位 0:8位 1:16位parameter CLK_FREQ 27d100_000_000; //i2c_dri模块的驱动时钟频率 parameter I2C_FREQ 18d250_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 1b0;assign cam_rst_n 1b1;//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) //有效数据 );endmodule2.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 8d250; //总共需要配置的寄存器个数//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 1b0;else if (start_init_cnt 15d20000) beginstart_init_cnt start_init_cnt 1b1;endend//寄存器配置个数计数 always (posedge clk or negedge rst_n) beginif (!rst_n) init_reg_cnt 8d0;else if (i2c_exec) init_reg_cnt init_reg_cnt 8b1;end//i2c触发执行信号 always (posedge clk or negedge rst_n) beginif (!rst_n) i2c_exec 1b0;else if (start_init_cnt 15d20000 - 1b1) i2c_exec 1b1;else if (i2c_done (init_reg_cnt REG_NUM)) i2c_exec 1b1;else i2c_exec 1b0;end//配置I2C读写控制信号always (posedge clk or negedge rst_n) beginif (!rst_n) i2c_rh_wl 1b1;else if (init_reg_cnt 8d2) i2c_rh_wl 1b0;end//初始化完成信号always (posedge clk or negedge rst_n) beginif (!rst_n) init_done 1b0;else if ((init_reg_cnt REG_NUM) i2c_done) init_done 1b1;end//配置寄存器地址与数据always (posedge clk or negedge rst_n) beginif (!rst_n) i2c_data 24b0;else begincase (init_reg_cnt)//先读OV5640 ID8d0: i2c_data {16h300a, 8h0}; //8d1: i2c_data {16h300b, 8h0}; //8d2: i2c_data {16h3008, 8h82}; //Bit[7]:复位 Bit[6]:电源休眠8d3: i2c_data {16h3008, 8h02}; //正常工作模式8d4: i2c_data {16h3103, 8h02}; //Bit[1]:1 PLL Clock//引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]8d5: i2c_data {8h30, 8h17, 8hff};//引脚输入/输出控制 D[5:0]/GPIO1/GPIO0 8d6: i2c_data {16h3018, 8hff};8d7: i2c_data {16h3037, 8h13}; //PLL分频控制8d8: i2c_data {16h3108, 8h01}; //系统根分频器8d9: i2c_data {16h3630, 8h36};8d10: i2c_data {16h3631, 8h0e};8d11: i2c_data {16h3632, 8he2};8d12: i2c_data {16h3633, 8h12};8d13: i2c_data {16h3621, 8he0};8d14: i2c_data {16h3704, 8ha0};8d15: i2c_data {16h3703, 8h5a};8d16: i2c_data {16h3715, 8h78};8d17: i2c_data {16h3717, 8h01};8d18: i2c_data {16h370b, 8h60};8d19: i2c_data {16h3705, 8h1a};8d20: i2c_data {16h3905, 8h02};8d21: i2c_data {16h3906, 8h10};8d22: i2c_data {16h3901, 8h0a};8d23: i2c_data {16h3731, 8h12};8d24: i2c_data {16h3600, 8h08}; //VCM控制,用于自动聚焦8d25: i2c_data {16h3601, 8h33}; //VCM控制,用于自动聚焦8d26: i2c_data {16h302d, 8h60}; //系统控制8d27: i2c_data {16h3620, 8h52};8d28: i2c_data {16h371b, 8h20};8d29: i2c_data {16h471c, 8h50};8d30: i2c_data {16h3a13, 8h43}; //AEC(自动曝光控制)8d31: i2c_data {16h3a18, 8h00}; //AEC 增益上限8d32: i2c_data {16h3a19, 8hf8}; //AEC 增益上限8d33: i2c_data {16h3635, 8h13};8d34: i2c_data {16h3636, 8h03};8d35: i2c_data {16h3634, 8h40};8d36: i2c_data {16h3622, 8h01};8d37: i2c_data {16h3c01, 8h34};8d38: i2c_data {16h3c04, 8h28};8d39: i2c_data {16h3c05, 8h98};8d40: i2c_data {16h3c06, 8h00}; //light meter 1 阈值[15:8]8d41: i2c_data {16h3c07, 8h08}; //light meter 1 阈值[7:0]8d42: i2c_data {16h3c08, 8h00}; //light meter 2 阈值[15:8]8d43: i2c_data {16h3c09, 8h1c}; //light meter 2 阈值[7:0]8d44: i2c_data {16h3c0a, 8h9c}; //sample number[15:8]8d45: i2c_data {16h3c0b, 8h40}; //sample number[7:0]8d46: i2c_data {16h3810, 8h00}; //Timing Hoffset[11:8]8d47: i2c_data {16h3811, 8h10}; //Timing Hoffset[7:0]8d48: i2c_data {16h3812, 8h00}; //Timing Voffset[10:8]8d49: i2c_data {16h3708, 8h64};8d50: i2c_data {16h4001, 8h02}; //BLC(黑电平校准)补偿起始行号8d51: i2c_data {16h4005, 8h1a}; //BLC(黑电平校准)补偿始终更新8d52: i2c_data {16h3000, 8h00}; //系统块复位控制8d53: i2c_data {16h3004, 8hff}; //时钟使能控制8d54: i2c_data {16h4300, 8h61}; //格式控制 RGB5658d55: i2c_data {16h501f, 8h01}; //ISP RGB8d56: i2c_data {16h440e, 8h00};8d57: i2c_data {16h5000, 8ha7}; //ISP控制8d58: i2c_data {16h3a0f, 8h30}; //AEC控制;stable range in high8d59: i2c_data {16h3a10, 8h28}; //AEC控制;stable range in low8d60: i2c_data {16h3a1b, 8h30}; //AEC控制;stable range out high8d61: i2c_data {16h3a1e, 8h26}; //AEC控制;stable range out low8d62: i2c_data {16h3a11, 8h60}; //AEC控制; fast zone high8d63: i2c_data {16h3a1f, 8h14}; //AEC控制; fast zone low//LENC(镜头校正)控制 16h5800~16h583d8d64: i2c_data {16h5800, 8h23};8d65: i2c_data {16h5801, 8h14};8d66: i2c_data {16h5802, 8h0f};8d67: i2c_data {16h5803, 8h0f};8d68: i2c_data {16h5804, 8h12};8d69: i2c_data {16h5805, 8h26};8d70: i2c_data {16h5806, 8h0c};8d71: i2c_data {16h5807, 8h08};8d72: i2c_data {16h5808, 8h05};8d73: i2c_data {16h5809, 8h05};8d74: i2c_data {16h580a, 8h08};8d75: i2c_data {16h580b, 8h0d};8d76: i2c_data {16h580c, 8h08};8d77: i2c_data {16h580d, 8h03};8d78: i2c_data {16h580e, 8h00};8d79: i2c_data {16h580f, 8h00};8d80: i2c_data {16h5810, 8h03};8d81: i2c_data {16h5811, 8h09};8d82: i2c_data {16h5812, 8h07};8d83: i2c_data {16h5813, 8h03};8d84: i2c_data {16h5814, 8h00};8d85: i2c_data {16h5815, 8h01};8d86: i2c_data {16h5816, 8h03};8d87: i2c_data {16h5817, 8h08};8d88: i2c_data {16h5818, 8h0d};8d89: i2c_data {16h5819, 8h08};8d90: i2c_data {16h581a, 8h05};8d91: i2c_data {16h581b, 8h06};8d92: i2c_data {16h581c, 8h08};8d93: i2c_data {16h581d, 8h0e};8d94: i2c_data {16h581e, 8h29};8d95: i2c_data {16h581f, 8h17};8d96: i2c_data {16h5820, 8h11};8d97: i2c_data {16h5821, 8h11};8d98: i2c_data {16h5822, 8h15};8d99: i2c_data {16h5823, 8h28};8d100: i2c_data {16h5824, 8h46};8d101: i2c_data {16h5825, 8h26};8d102: i2c_data {16h5826, 8h08};8d103: i2c_data {16h5827, 8h26};8d104: i2c_data {16h5828, 8h64};8d105: i2c_data {16h5829, 8h26};8d106: i2c_data {16h582a, 8h24};8d107: i2c_data {16h582b, 8h22};8d108: i2c_data {16h582c, 8h24};8d109: i2c_data {16h582d, 8h24};8d110: i2c_data {16h582e, 8h06};8d111: i2c_data {16h582f, 8h22};8d112: i2c_data {16h5830, 8h40};8d113: i2c_data {16h5831, 8h42};8d114: i2c_data {16h5832, 8h24};8d115: i2c_data {16h5833, 8h26};8d116: i2c_data {16h5834, 8h24};8d117: i2c_data {16h5835, 8h22};8d118: i2c_data {16h5836, 8h22};8d119: i2c_data {16h5837, 8h26};8d120: i2c_data {16h5838, 8h44};8d121: i2c_data {16h5839, 8h24};8d122: i2c_data {16h583a, 8h26};8d123: i2c_data {16h583b, 8h28};8d124: i2c_data {16h583c, 8h42};8d125: i2c_data {16h583d, 8hce};//AWB(自动白平衡控制) 16h5180~16h519e8d126: i2c_data {16h5180, 8hff};8d127: i2c_data {16h5181, 8hf2};8d128: i2c_data {16h5182, 8h00};8d129: i2c_data {16h5183, 8h14};8d130: i2c_data {16h5184, 8h25};8d131: i2c_data {16h5185, 8h24};8d132: i2c_data {16h5186, 8h09};8d133: i2c_data {16h5187, 8h09};8d134: i2c_data {16h5188, 8h09};8d135: i2c_data {16h5189, 8h75};8d136: i2c_data {16h518a, 8h54};8d137: i2c_data {16h518b, 8he0};8d138: i2c_data {16h518c, 8hb2};8d139: i2c_data {16h518d, 8h42};8d140: i2c_data {16h518e, 8h3d};8d141: i2c_data {16h518f, 8h56};8d142: i2c_data {16h5190, 8h46};8d143: i2c_data {16h5191, 8hf8};8d144: i2c_data {16h5192, 8h04};8d145: i2c_data {16h5193, 8h70};8d146: i2c_data {16h5194, 8hf0};8d147: i2c_data {16h5195, 8hf0};8d148: i2c_data {16h5196, 8h03};8d149: i2c_data {16h5197, 8h01};8d150: i2c_data {16h5198, 8h04};8d151: i2c_data {16h5199, 8h12};8d152: i2c_data {16h519a, 8h04};8d153: i2c_data {16h519b, 8h00};8d154: i2c_data {16h519c, 8h06};8d155: i2c_data {16h519d, 8h82};8d156: i2c_data {16h519e, 8h38};//Gamma(伽马)控制 16h5480~16h54908d157: i2c_data {16h5480, 8h01};8d158: i2c_data {16h5481, 8h08};8d159: i2c_data {16h5482, 8h14};8d160: i2c_data {16h5483, 8h28};8d161: i2c_data {16h5484, 8h51};8d162: i2c_data {16h5485, 8h65};8d163: i2c_data {16h5486, 8h71};8d164: i2c_data {16h5487, 8h7d};8d165: i2c_data {16h5488, 8h87};8d166: i2c_data {16h5489, 8h91};8d167: i2c_data {16h548a, 8h9a};8d168: i2c_data {16h548b, 8haa};8d169: i2c_data {16h548c, 8hb8};8d170: i2c_data {16h548d, 8hcd};8d171: i2c_data {16h548e, 8hdd};8d172: i2c_data {16h548f, 8hea};8d173: i2c_data {16h5490, 8h1d};//CMX(彩色矩阵控制) 16h5381~16h538b8d174: i2c_data {16h5381, 8h1e};8d175: i2c_data {16h5382, 8h5b};8d176: i2c_data {16h5383, 8h08};8d177: i2c_data {16h5384, 8h0a};8d178: i2c_data {16h5385, 8h7e};8d179: i2c_data {16h5386, 8h88};8d180: i2c_data {16h5387, 8h7c};8d181: i2c_data {16h5388, 8h6c};8d182: i2c_data {16h5389, 8h10};8d183: i2c_data {16h538a, 8h01};8d184: i2c_data {16h538b, 8h98};//SDE(特殊数码效果)控制 16h5580~16h558b8d185: i2c_data {16h5580, 8h06};8d186: i2c_data {16h5583, 8h40};8d187: i2c_data {16h5584, 8h10};8d188: i2c_data {16h5589, 8h10};8d189: i2c_data {16h558a, 8h00};8d190: i2c_data {16h558b, 8hf8};8d191: i2c_data {16h501d, 8h40}; //ISP MISC//CIP(颜色插值)控制 (16h5300~16h530c)8d192: i2c_data {16h5300, 8h08};8d193: i2c_data {16h5301, 8h30};8d194: i2c_data {16h5302, 8h10};8d195: i2c_data {16h5303, 8h00};8d196: i2c_data {16h5304, 8h08};8d197: i2c_data {16h5305, 8h30};8d198: i2c_data {16h5306, 8h08};8d199: i2c_data {16h5307, 8h16};8d200: i2c_data {16h5309, 8h08};8d201: i2c_data {16h530a, 8h30};8d202: i2c_data {16h530b, 8h04};8d203: i2c_data {16h530c, 8h06};8d204: i2c_data {16h5025, 8h00};//系统时钟分频 Bit[7:4]:系统时钟分频 input clock 24Mhz, PCLK 48Mhz8d205: i2c_data {16h3035, 8h11};8d206: i2c_data {16h3036, 8h3c}; //PLL倍频8d207: i2c_data {16h3c07, 8h08};//时序控制 16h3800~16h38218d208: i2c_data {16h3820, 8h46};8d209: i2c_data {16h3821, 8h01};8d210: i2c_data {16h3814, 8h31};8d211: i2c_data {16h3815, 8h31};8d212: i2c_data {16h3800, 8h00};8d213: i2c_data {16h3801, 8h00};8d214: i2c_data {16h3802, 8h00};8d215: i2c_data {16h3803, 8h04};8d216: i2c_data {16h3804, 8h0a};8d217: i2c_data {16h3805, 8h3f};8d218: i2c_data {16h3806, 8h07};8d219: i2c_data {16h3807, 8h9b};//设置输出像素个数//DVP 输出水平像素点数高4位8d220: i2c_data {16h3808, {4d0, cmos_h_pixel[11:8]}};//DVP 输出水平像素点数低8位8d221: i2c_data {16h3809, cmos_h_pixel[7:0]};//DVP 输出垂直像素点数高3位8d222: i2c_data {16h380a, {5d0, cmos_v_pixel[10:8]}};//DVP 输出垂直像素点数低8位8d223: i2c_data {16h380b, cmos_v_pixel[7:0]};//水平总像素大小高5位8d224: i2c_data {16h380c, {3d0, total_h_pixel[12:8]}};//水平总像素大小低8位 8d225: i2c_data {16h380d, total_h_pixel[7:0]};//垂直总像素大小高5位 8d226: i2c_data {16h380e, {3d0, total_v_pixel[12:8]}};//垂直总像素大小低8位 8d227: i2c_data {16h380f, total_v_pixel[7:0]};8d228: i2c_data {16h3813, 8h06};8d229: i2c_data {16h3618, 8h00};8d230: i2c_data {16h3612, 8h29};8d231: i2c_data {16h3709, 8h52};8d232: i2c_data {16h370c, 8h03};8d233: i2c_data {16h3a02, 8h17}; //60Hz max exposure8d234: i2c_data {16h3a03, 8h10}; //60Hz max exposure8d235: i2c_data {16h3a14, 8h17}; //50Hz max exposure8d236: i2c_data {16h3a15, 8h10}; //50Hz max exposure8d237: i2c_data {16h4004, 8h02}; //BLC(背光) 2 lines8d238: i2c_data {16h4713, 8h03}; //JPEG mode 38d239: i2c_data {16h4407, 8h04}; //量化标度8d240: i2c_data {16h460c, 8h22};8d241: i2c_data {16h4837, 8h22}; //DVP CLK divider8d242: i2c_data {16h3824, 8h02}; //DVP CLK divider8d243: i2c_data {16h5001, 8ha3}; //ISP 控制8d244: i2c_data {16h3b07, 8h0a}; //帧曝光模式 //彩条测试使能 8d245: i2c_data {16h503d, 8h00}; //8h00:正常模式 8h80:彩条显示//测试闪光灯功能8d246: i2c_data {16h3016, 8h02};8d247: i2c_data {16h301c, 8h02};8d248: i2c_data {16h3019, 8h02}; //打开闪光灯8d249: i2c_data {16h3019, 8h00}; //关闭闪光灯//只读存储器,防止在case中没有列举的情况之前的寄存器被重复改写default: i2c_data {16h300a, 8h00}; //器件ID高8位endcaseendendendmodule2.4 iic驱动模块
timescale 1ns / 1ps
//IIC驱动模块module i2c_dri #(parameter SLAVE_ADDR 7b1010000 , //EEPROM从机地址parameter CLK_FREQ 26d50_000_000, //模块输入的时钟频率parameter I2C_FREQ 18d250_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 8b0000_0001; //空闲状态localparam st_sladdr 8b0000_0010; //发送器件地址(slave address)localparam st_addr16 8b0000_0100; //发送16位字地址localparam st_addr8 8b0000_1000; //发送8位字地址localparam st_data_wr 8b0001_0000; //写数据(8 bit)localparam st_addr_rd 8b0010_0000; //发送器件地址读localparam st_data_rd 8b0100_0000; //读数据(8 bit)localparam st_stop 8b1000_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 : 1bz; //SDA数据输出或高阻assign sda_in sda; //SDA数据输入assign clk_divide (CLK_FREQ / I2C_FREQ) 2d2; //模块驱动时钟的分频系数//生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作always (posedge clk or negedge rst_n) beginif (!rst_n) begindri_clk 1b0;clk_cnt 10d0;end else if (clk_cnt clk_divide[8:1] - 1d1) beginclk_cnt 10d0;dri_clk ~dri_clk;end else clk_cnt clk_cnt 1b1;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 1b0) //读写判断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 1b1;sda_out 1b1;sda_dir 1b1;i2c_done 1b0;i2c_ack 1b0;cnt 1b0;st_done 1b0;data_r 1b0;i2c_data_r 1b0;wr_flag 1b0;addr_t 1b0;data_wr_t 1b0;end else beginst_done 1b0;cnt cnt 1b1;case (cur_state)st_idle: begin //空闲状态scl 1b1;sda_out 1b1;sda_dir 1b1;i2c_done 1b0;cnt 7b0;if (i2c_exec) beginwr_flag i2c_rh_wl ;addr_t i2c_addr ;data_wr_t i2c_data_w;i2c_ack 1b0;endendst_sladdr: begin //写地址(器件地址和字地址)case (cnt)7d1: sda_out 1b0; //开始I2C7d3: scl 1b0;7d4: sda_out SLAVE_ADDR[6]; //传送器件地址7d5: scl 1b1;7d7: scl 1b0;7d8: sda_out SLAVE_ADDR[5];7d9: scl 1b1;7d11: scl 1b0;7d12: sda_out SLAVE_ADDR[4];7d13: scl 1b1;7d15: scl 1b0;7d16: sda_out SLAVE_ADDR[3];7d17: scl 1b1;7d19: scl 1b0;7d20: sda_out SLAVE_ADDR[2];7d21: scl 1b1;7d23: scl 1b0;7d24: sda_out SLAVE_ADDR[1];7d25: scl 1b1;7d27: scl 1b0;7d28: sda_out SLAVE_ADDR[0];7d29: scl 1b1;7d31: scl 1b0;7d32: sda_out 1b0; //0:写7d33: scl 1b1;7d35: scl 1b0;7d36: beginsda_dir 1b0;sda_out 1b1;end7d37: scl 1b1;7d38: begin //从机应答 st_done 1b1;if (sda_in 1b1) //高电平表示未应答i2c_ack 1b1; //拉高应答标志位 end7d39: beginscl 1b0;cnt 1b0;enddefault: ;endcaseendst_addr16: begincase (cnt)7d0: beginsda_dir 1b1;sda_out addr_t[15]; //传送字地址end7d1: scl 1b1;7d3: scl 1b0;7d4: sda_out addr_t[14];7d5: scl 1b1;7d7: scl 1b0;7d8: sda_out addr_t[13];7d9: scl 1b1;7d11: scl 1b0;7d12: sda_out addr_t[12];7d13: scl 1b1;7d15: scl 1b0;7d16: sda_out addr_t[11];7d17: scl 1b1;7d19: scl 1b0;7d20: sda_out addr_t[10];7d21: scl 1b1;7d23: scl 1b0;7d24: sda_out addr_t[9];7d25: scl 1b1;7d27: scl 1b0;7d28: sda_out addr_t[8];7d29: scl 1b1;7d31: scl 1b0;7d32: beginsda_dir 1b0;sda_out 1b1;end7d33: scl 1b1;7d34: begin //从机应答st_done 1b1;if (sda_in 1b1) //高电平表示未应答i2c_ack 1b1; //拉高应答标志位 end7d35: beginscl 1b0;cnt 1b0;enddefault: ;endcaseendst_addr8: begincase (cnt)7d0: beginsda_dir 1b1;sda_out addr_t[7]; //字地址end7d1: scl 1b1;7d3: scl 1b0;7d4: sda_out addr_t[6];7d5: scl 1b1;7d7: scl 1b0;7d8: sda_out addr_t[5];7d9: scl 1b1;7d11: scl 1b0;7d12: sda_out addr_t[4];7d13: scl 1b1;7d15: scl 1b0;7d16: sda_out addr_t[3];7d17: scl 1b1;7d19: scl 1b0;7d20: sda_out addr_t[2];7d21: scl 1b1;7d23: scl 1b0;7d24: sda_out addr_t[1];7d25: scl 1b1;7d27: scl 1b0;7d28: sda_out addr_t[0];7d29: scl 1b1;7d31: scl 1b0;7d32: beginsda_dir 1b0;sda_out 1b1;end7d33: scl 1b1;7d34: begin //从机应答st_done 1b1;if (sda_in 1b1) //高电平表示未应答i2c_ack 1b1; //拉高应答标志位 end7d35: beginscl 1b0;cnt 1b0;enddefault: ;endcaseendst_data_wr: begin //写数据(8 bit)case (cnt)7d0: beginsda_out data_wr_t[7]; //I2C写8位数据sda_dir 1b1;end7d1: scl 1b1;7d3: scl 1b0;7d4: sda_out data_wr_t[6];7d5: scl 1b1;7d7: scl 1b0;7d8: sda_out data_wr_t[5];7d9: scl 1b1;7d11: scl 1b0;7d12: sda_out data_wr_t[4];7d13: scl 1b1;7d15: scl 1b0;7d16: sda_out data_wr_t[3];7d17: scl 1b1;7d19: scl 1b0;7d20: sda_out data_wr_t[2];7d21: scl 1b1;7d23: scl 1b0;7d24: sda_out data_wr_t[1];7d25: scl 1b1;7d27: scl 1b0;7d28: sda_out data_wr_t[0];7d29: scl 1b1;7d31: scl 1b0;7d32: beginsda_dir 1b0;sda_out 1b1;end7d33: scl 1b1;7d34: begin //从机应答st_done 1b1;if (sda_in 1b1) //高电平表示未应答i2c_ack 1b1; //拉高应答标志位 end7d35: beginscl 1b0;cnt 1b0;enddefault: ;endcaseendst_addr_rd: begin //写地址以进行读数据case (cnt)7d0: beginsda_dir 1b1;sda_out 1b1;end7d1: scl 1b1;7d2: sda_out 1b0; //重新开始7d3: scl 1b0;7d4: sda_out SLAVE_ADDR[6]; //传送器件地址7d5: scl 1b1;7d7: scl 1b0;7d8: sda_out SLAVE_ADDR[5];7d9: scl 1b1;7d11: scl 1b0;7d12: sda_out SLAVE_ADDR[4];7d13: scl 1b1;7d15: scl 1b0;7d16: sda_out SLAVE_ADDR[3];7d17: scl 1b1;7d19: scl 1b0;7d20: sda_out SLAVE_ADDR[2];7d21: scl 1b1;7d23: scl 1b0;7d24: sda_out SLAVE_ADDR[1];7d25: scl 1b1;7d27: scl 1b0;7d28: sda_out SLAVE_ADDR[0];7d29: scl 1b1;7d31: scl 1b0;7d32: sda_out 1b1; //1:读7d33: scl 1b1;7d35: scl 1b0;7d36: beginsda_dir 1b0;sda_out 1b1;end7d37: scl 1b1;7d38: begin //从机应答st_done 1b1;if (sda_in 1b1) //高电平表示未应答i2c_ack 1b1; //拉高应答标志位 end7d39: beginscl 1b0;cnt 1b0;enddefault: ;endcaseendst_data_rd: begin //读取数据(8 bit)case (cnt)7d0: sda_dir 1b0;7d1: begindata_r[7] sda_in;scl 1b1;end7d3: scl 1b0;7d5: begindata_r[6] sda_in;scl 1b1;end7d7: scl 1b0;7d9: begindata_r[5] sda_in;scl 1b1;end7d11: scl 1b0;7d13: begindata_r[4] sda_in;scl 1b1;end7d15: scl 1b0;7d17: begindata_r[3] sda_in;scl 1b1;end7d19: scl 1b0;7d21: begindata_r[2] sda_in;scl 1b1;end7d23: scl 1b0;7d25: begindata_r[1] sda_in;scl 1b1;end7d27: scl 1b0;7d29: begindata_r[0] sda_in;scl 1b1;end7d31: scl 1b0;7d32: beginsda_dir 1b1;sda_out 1b1;end7d33: scl 1b1;7d34: st_done 1b1; //非应答7d35: beginscl 1b0;cnt 1b0;i2c_data_r data_r;enddefault: ;endcaseendst_stop: begin //结束I2C操作case (cnt)7d0: beginsda_dir 1b1; //结束I2Csda_out 1b0;end7d1: scl 1b1;7d3: sda_out 1b1;7d15: st_done 1b1;7d16: begincnt 1b0;i2c_done 1b1; //向上层模块传递I2C结束信号enddefault: ;endcaseendendcaseendendendmodule2.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 4d10; //寄存器数据稳定等待的帧个数 //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 : 1b0;//输出行有效信号assign cmos_frame_href frame_val_flag ? cam_href_d1 : 1b0;//输出数据使能有效信号assign cmos_frame_valid frame_val_flag ? byte_flag_d0 : 1b0;//输出数据assign cmos_frame_data frame_val_flag ? cmos_data_t : 1b0;always (posedge cam_pclk or negedge rst_n) beginif (!rst_n) begincam_vsync_d0 1b0;cam_vsync_d1 1b0;cam_href_d0 1b0;cam_href_d1 1b0;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 4d0;else if (pos_vsync (cmos_ps_cnt WAIT_FRAME)) cmos_ps_cnt cmos_ps_cnt 4d1;end//帧有效标志always (posedge cam_pclk or negedge rst_n) beginif (!rst_n) frame_val_flag 1b0;else if ((cmos_ps_cnt WAIT_FRAME) pos_vsync) frame_val_flag 1b1;else;end//8位数据转16位RGB565数据 always (posedge cam_pclk or negedge rst_n) beginif (!rst_n) begincmos_data_t 16d0;cam_data_d0 8d0;byte_flag 1b0;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 1b0;cam_data_d0 8b0;endend//产生输出数据有效信号(cmos_frame_valid)always (posedge cam_pclk or negedge rst_n) beginif (!rst_n) byte_flag_d0 1b0;else byte_flag_d0 byte_flag;endendmodule2.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 1b0;else if (udp_rec_pkt_done udp_rec_byte_num 1b1) beginif (udp_rec_data[31:24] START) //开始传输transfer_flag 1b1;else if (udp_rec_data[31:24] STOP) //停止传输transfer_flag 1b0;endendendmodule2.7 图像封装模块
timescale 1ns / 1ps
//图像封装模块
//用网口传输图像数据时一次发送一行图像数据
//在发送一帧图像的第一行数据时在一行数据的开头添加图像的帧头和图像的行场分辨率共8个字节
//图像的帧头是32hf0_5a_a5_0f共占用4个字节图像的行场分辨率占用4个字节本次实验传输的图像分辨率为640*480module 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 16d640; //图像水平方向分辨率parameter CMOS_V_PIXEL 16d480; //图像垂直方向分辨率//图像帧头,用于标志一帧数据的开始parameter IMG_FRAME_HEAD {32hf0_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 1b0;img_vsync_d1 1b0;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 1b0;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 1b0;img_data_d0 1b0;end else if (neg_vsync) wr_sw 1b0;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 1b0;wr_fifo_data 1b0;end else beginif (neg_vsync) beginwr_fifo_en 1b1;wr_fifo_data IMG_FRAME_HEAD; //帧头end else if (neg_vsync_d0) beginwr_fifo_en 1b1;wr_fifo_data {CMOS_H_PIXEL, CMOS_V_PIXEL}; //水平和垂直方向分辨率end else if (img_data_en wr_sw) begin//隔一个使能信号将两个16位数据拼接成32位数据wr_fifo_en 1b1;wr_fifo_data {img_data_d0, img_data}; //图像数据位拼接,16位转32位end else beginwr_fifo_en 1b0;wr_fifo_data 1b0;endendend//以太网发送时钟域下,对img_vsync信号延时两个时钟周期,用于采沿always (posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) beginimg_vsync_txc_d0 1b0;img_vsync_txc_d1 1b0;end else beginimg_vsync_txc_d0 img_vsync;img_vsync_txc_d1 img_vsync_txc_d0;endend//控制以太网发送的字节数//只在一帧的第一行添加了帧头和行场分辨率因此只有在发送第一行图像数据时发送的UDP字节数为1288640*28//而其余行单包发送的字节数为1280。always (posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) udp_tx_byte_num 1b0;else if (neg_vsynt_txc) udp_tx_byte_num {CMOS_H_PIXEL, 1b0} 16d8;else if (udp_tx_done) udp_tx_byte_num {CMOS_H_PIXEL, 1b0};end//控制以太网发送开始信号always (posedge eth_tx_clk or negedge rst_n) beginif (!rst_n) beginudp_tx_start_en 1b0;tx_busy_flag 1b0;end //上位机未发送开始命令时,以太网不发送图像数据else if (transfer_flag 1b0) beginudp_tx_start_en 1b0;tx_busy_flag 1b0;end else beginudp_tx_start_en 1b0;//当FIFO中的个数每个代表四字节满足需要发送的字节数时if (tx_busy_flag 1b0 fifo_rdusedw udp_tx_byte_num[15:2]) beginudp_tx_start_en 1b1; //开始控制发送一包数据tx_busy_flag 1b1;end else if (udp_tx_done || neg_vsynt_txc) tx_busy_flag 1b0;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);endmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};//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));endmodule2.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));endmodule2.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(1b0), // Optional inversion for CB.IS_C_INVERTED(1b0) // 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 (1b0) // 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(1b0), // Optional inversion for CB.IS_C_INVERTED(1b0) // Optional inversion for C) IDDRE1_inst (.Q1(gmii_rxd[i]), // 1-bit output: Registered parallel output 1.Q2(gmii_rxd[4i]), // 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 (1b0) // 1-bit input: Active High Async Reset);endendgenerateendmodule2.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(1b0), // Optional inversion for C.IS_D1_INVERTED(1b0), // Unsupported, do not use.IS_D2_INVERTED(1b0), // Unsupported, do not use.SIM_DEVICE (ULTRASCALE), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2).SRVAL(1b0) // Initializes the ODDRE1 Flip-Flops to the specified value (1b0, 1b1)) 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(1b0) // 1-bit input: Active High Async Reset);genvar i;generatefor (i 0; i 4; i i 1) begin : txdata_busODDRE1 #(.IS_C_INVERTED(1b0), // Optional inversion for C.IS_D1_INVERTED(1b0), // Unsupported, do not use.IS_D2_INVERTED(1b0), // Unsupported, do not use.SIM_DEVICE(ULTRASCALE), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2).SRVAL(1b0) // Initializes the ODDRE1 Flip-Flops to the specified value (1b0, 1b1)) 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[4i]), // 1-bit input: Parallel data input 2.SR(1b0) // 1-bit input: Active High Async Reset);endendgenerateendmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};//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));endmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};localparam st_idle 5b0_0001; //初始状态等待接收前导码localparam st_preamble 5b0_0010; //接收前导码状态 localparam st_eth_head 5b0_0100; //接收以太网帧头localparam st_arp_data 5b0_1000; //接收ARP数据localparam st_rx_end 5b1_0000; //接收结束localparam ETH_TPYE 16h0806; //以太网帧类型 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 1b0;error_en 1b0;cnt 5d0;des_mac_t 48d0;des_ip_t 32d0;src_mac_t 48d0;src_ip_t 32d0;eth_type 16d0;op_data 16d0;arp_rx_done 1b0;arp_rx_type 1b0;src_mac 48d0;src_ip 32d0;end else beginskip_en 1b0;error_en 1b0;arp_rx_done 1b0;case (next_state)st_idle: begin //检测到第一个8h55if ((gmii_rx_dv 1b1) (gmii_rxd 8h55)) skip_en 1b1;endst_preamble: beginif (gmii_rx_dv) begin //解析前导码cnt cnt 5d1;if ((cnt 5d6) (gmii_rxd ! 8h55)) //7个8h55 error_en 1b1;else if (cnt 5d6) begincnt 5d0;if (gmii_rxd 8hd5) //1个8hd5skip_en 1b1;else error_en 1b1;endendendst_eth_head: beginif (gmii_rx_dv) begincnt cnt 5b1;if (cnt 5d6) des_mac_t {des_mac_t[39:0], gmii_rxd};else if (cnt 5d6) begin//判断MAC地址是否为开发板MAC地址或者公共地址if ((des_mac_t ! BOARD_MAC) (des_mac_t ! 48hff_ff_ff_ff_ff_ff))error_en 1b1;end else if (cnt 5d12) eth_type[15:8] gmii_rxd; //以太网协议类型else if (cnt 5d13) begineth_type[7:0] gmii_rxd;cnt 5d0;if (eth_type[15:8] ETH_TPYE[15:8] //判断是否为ARP协议 gmii_rxd ETH_TPYE[7:0])skip_en 1b1;else error_en 1b1;endendendst_arp_data: beginif (gmii_rx_dv) begincnt cnt 5d1;if (cnt 5d6) op_data[15:8] gmii_rxd; //操作码 else if (cnt 5d7) op_data[7:0] gmii_rxd;else if (cnt 5d8 cnt 5d14) //源MAC地址src_mac_t {src_mac_t[39:0], gmii_rxd};else if (cnt 5d14 cnt 5d18) //源IP地址src_ip_t {src_ip_t[23:0], gmii_rxd};else if (cnt 5d24 cnt 5d28) //目标IP地址des_ip_t {des_ip_t[23:0], gmii_rxd};else if (cnt 5d28) begincnt 5d0;if (des_ip_t BOARD_IP) begin //判断目的IP地址和操作码if ((op_data 16d1) || (op_data 16d2)) beginskip_en 1b1;arp_rx_done 1b1;src_mac src_mac_t;src_ip src_ip_t;src_mac_t 48d0;src_ip_t 32d0;des_mac_t 48d0;des_ip_t 32d0;if (op_data 16d1) arp_rx_type 1b0; //ARP请求else arp_rx_type 1b1; //ARP应答end else error_en 1b1;end else error_en 1b1;endendendst_rx_end: begincnt 5d0;//单包数据接收完成 if (gmii_rx_dv 1b0 skip_en 1b0) skip_en 1b1;enddefault: ;endcaseendendendmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};localparam st_idle 5b0_0001; //初始状态等待开始发送信号localparam st_preamble 5b0_0010; //发送前导码帧起始界定符localparam st_eth_head 5b0_0100; //发送以太网帧头localparam st_arp_data 5b0_1000; //localparam st_crc 5b1_0000; //发送CRC校验值localparam ETH_TYPE 16h0806; //以太网帧类型 ARP协议localparam HD_TYPE 16h0001; //硬件类型 以太网localparam PROTOCOL_TYPE 16h0800; //上层协议为IP协议//以太网数据最小为46个字节,不足部分填充数据localparam MIN_DATA_NUM 16d46;//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 1b0;tx_en_d1 1b0;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 1b0;cnt 6d0;data_cnt 5d0;crc_en 1b0;gmii_tx_en 1b0;gmii_txd 8d0;tx_done_t 1b0;//初始化数组 //前导码 7个8h55 1个8hd5 preamble[0] 8h55;preamble[1] 8h55;preamble[2] 8h55;preamble[3] 8h55;preamble[4] 8h55;preamble[5] 8h55;preamble[6] 8h55;preamble[7] 8hd5;//以太网帧头 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] 8h06; //硬件地址长度,6arp_data[5] 8h04; //协议地址长度,4arp_data[6] 8h00; //OP,操作码 8h01ARP请求 8h02:ARP应答arp_data[7] 8h01;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 1b0;crc_en 1b0;gmii_tx_en 1b0;tx_done_t 1b0;case (next_state)st_idle: beginif (pos_tx_en) beginskip_en 1b1;//如果目标MAC地址和IP地址已经更新,则发送正确的地址if ((des_mac ! 48b0) || (des_ip ! 32d0)) 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 1b0) arp_data[7] 8h01; //ARP请求 else arp_data[7] 8h02; //ARP应答endendst_preamble: begin //发送前导码帧起始界定符gmii_tx_en 1b1;gmii_txd preamble[cnt];if (cnt 6d7) beginskip_en 1b1;cnt 1b0;end else cnt cnt 1b1;endst_eth_head: begin //发送以太网首部gmii_tx_en 1b1;crc_en 1b1;gmii_txd eth_head[cnt];if (cnt 6d13) beginskip_en 1b1;cnt 1b0;end else cnt cnt 1b1;endst_arp_data: begin //发送ARP数据 crc_en 1b1;gmii_tx_en 1b1;//至少发送46个字节if (cnt MIN_DATA_NUM - 1b1) beginskip_en 1b1;cnt 1b0;data_cnt 1b0;end else cnt cnt 1b1;if (data_cnt 6d27) begindata_cnt data_cnt 1b1;gmii_txd arp_data[data_cnt];end else gmii_txd 8d0; //Padding,填充0endst_crc: begin //发送CRC校验值gmii_tx_en 1b1;cnt cnt 1b1;if (cnt 6d0)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 6d1)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 6d2) 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 6d3) 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 1b1;skip_en 1b1;cnt 1b0;endenddefault: ;endcaseendend//发送完成信号及crc值复位信号always (posedge clk or negedge rst_n) beginif (!rst_n) begintx_done 1b0;crc_clr 1b0;end else begintx_done tx_done_t;crc_clr tx_done_t;endendendmodule2.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 32hff_ff_ff_ff;else if (crc_clr) //CRC校验值复位crc_data 32hff_ff_ff_ff;else if (crc_en) crc_data crc_next;endendmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};//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));endmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.10 parameter BOARD_IP {8d192, 8d168, 8d1, 8d10};localparam st_idle 7b000_0001; //初始状态等待接收前导码localparam st_preamble 7b000_0010; //接收前导码状态 localparam st_eth_head 7b000_0100; //接收以太网帧头localparam st_ip_head 7b000_1000; //接收IP首部localparam st_udp_head 7b001_0000; //接收UDP首部localparam st_rx_data 7b010_0000; //接收有效数据localparam st_rx_end 7b100_0000; //接收结束localparam ETH_TYPE 16h0800; //以太网协议类型 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 1b0;error_en 1b0;cnt 5d0;des_mac 48d0;eth_type 16d0;des_ip 32d0;ip_head_byte_num 6d0;udp_byte_num 16d0;data_byte_num 16d0;data_cnt 16d0;rec_en_cnt 2d0;rec_en 1b0;rec_data 32d0;rec_pkt_done 1b0;rec_byte_num 16d0;end else beginskip_en 1b0;error_en 1b0;rec_en 1b0;rec_pkt_done 1b0;case (next_state)st_idle: beginif ((gmii_rx_dv 1b1) (gmii_rxd 8h55)) skip_en 1b1;endst_preamble: beginif (gmii_rx_dv) begin //解析前导码cnt cnt 5d1;if ((cnt 5d6) (gmii_rxd ! 8h55)) //7个8h55 error_en 1b1;else if (cnt 5d6) begincnt 5d0;if (gmii_rxd 8hd5) //1个8hd5skip_en 1b1;else error_en 1b1;endendendst_eth_head: beginif (gmii_rx_dv) begincnt cnt 5b1;if (cnt 5d6) des_mac {des_mac[39:0], gmii_rxd}; //目的MAC地址else if (cnt 5d12) eth_type[15:8] gmii_rxd; //以太网协议类型else if (cnt 5d13) begineth_type[7:0] gmii_rxd;cnt 5d0;//判断MAC地址是否为开发板MAC地址或者公共地址if(((des_mac BOARD_MAC) ||(des_mac 48hff_ff_ff_ff_ff_ff)) eth_type[15:8] ETH_TYPE[15:8] gmii_rxd ETH_TYPE[7:0])skip_en 1b1;else error_en 1b1;endendendst_ip_head: beginif (gmii_rx_dv) begincnt cnt 5d1;if (cnt 5d0) ip_head_byte_num {gmii_rxd[3:0], 2d0};else if ((cnt 5d16) (cnt 5d18))des_ip {des_ip[23:0], gmii_rxd}; //目的IP地址else if (cnt 5d19) 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 - 1b1) beginskip_en 1b1;cnt 5d0;endend else begin//IP错误停止解析数据 error_en 1b1;cnt 5d0;endend else if (cnt ip_head_byte_num - 1b1) beginskip_en 1b1; //IP首部解析完成cnt 5d0;endendendst_udp_head: beginif (gmii_rx_dv) begincnt cnt 5d1;if (cnt 5d4) udp_byte_num[15:8] gmii_rxd; //解析UDP字节长度 else if (cnt 5d5) udp_byte_num[7:0] gmii_rxd;else if (cnt 5d7) begin//有效数据字节长度UDP首部8个字节所以减去8data_byte_num udp_byte_num - 16d8;skip_en 1b1;cnt 5d0;endendendst_rx_data: begin//接收数据转换成32bit if (gmii_rx_dv) begindata_cnt data_cnt 16d1;rec_en_cnt rec_en_cnt 2d1;if (data_cnt data_byte_num - 16d1) beginskip_en 1b1; //有效数据接收完成data_cnt 16d0;rec_en_cnt 2d0;rec_pkt_done 1b1;rec_en 1b1;rec_byte_num data_byte_num;end//先收到的数据放在了rec_data的高位,所以当数据不是4的倍数时,//低位数据为无效数据可根据有效字节数来判断(rec_byte_num)if (rec_en_cnt 2d0) rec_data[31:24] gmii_rxd;else if (rec_en_cnt 2d1) rec_data[23:16] gmii_rxd;else if (rec_en_cnt 2d2) rec_data[15:8] gmii_rxd;else if (rec_en_cnt 2d3) beginrec_en 1b1;rec_data[7:0] gmii_rxd;endendendst_rx_end: begin //单包数据接收完成 if (gmii_rx_dv 1b0 skip_en 1b0) skip_en 1b1;enddefault: ;endcaseendendendmodule2.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 48h00_11_22_33_44_55;//开发板IP地址 192.168.1.123 parameter BOARD_IP {8d192, 8d168, 8d1, 8d123};//目的MAC地址 ff_ff_ff_ff_ff_ffparameter DES_MAC 48hff_ff_ff_ff_ff_ff;//目的IP地址 192.168.1.102 parameter DES_IP {8d192, 8d168, 8d1, 8d102};localparam st_idle 7b000_0001; //初始状态等待开始发送信号localparam st_check_sum 7b000_0010; //IP首部校验和localparam st_preamble 7b000_0100; //发送前导码帧起始界定符localparam st_eth_head 7b000_1000; //发送以太网帧头localparam st_ip_head 7b001_0000; //发送IP首部UDP首部localparam st_tx_data 7b010_0000; //发送数据localparam st_crc 7b100_0000; //发送CRC校验值localparam ETH_TYPE 16h0800; //以太网协议类型 IP协议//以太网数据最小46个字节IP首部20个字节UDP首部8个字节//所以数据至少46-20-818个字节localparam MIN_DATA_NUM 16d18;//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 1b0;start_en_d1 1b0;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 16d0;total_num 16d0;udp_num 16d0;end else beginif (pos_start_en cur_state st_idle) begin//数据长度tx_data_num tx_byte_num;//IP长度有效数据IP首部长度 total_num tx_byte_num 16d28;//UDP长度有效数据UDP首部长度 udp_num tx_byte_num 16d8;endendend//触发发送信号always (posedge clk or negedge rst_n) beginif (!rst_n) trig_tx_en 1b0;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 1b0;cnt 5d0;check_buffer 32d0;ip_head[1][31:16] 16d0;tx_bit_sel 2b0;crc_en 1b0;gmii_tx_en 1b0;gmii_txd 8d0;tx_req 1b0;tx_done_t 1b0;data_cnt 16d0;real_add_cnt 5d0;//初始化数组 //前导码 7个8h55 1个8hd5preamble[0] 8h55;preamble[1] 8h55;preamble[2] 8h55;preamble[3] 8h55;preamble[4] 8h55;preamble[5] 8h55;preamble[6] 8h55;preamble[7] 8hd5;//目的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 1b0;tx_req 1b0;crc_en 1b0;gmii_tx_en 1b0;tx_done_t 1b0;case (next_state)st_idle: beginif (trig_tx_en) beginskip_en 1b1;//版本号4 首部长度5(单位:32bit,20byte/45)ip_head[0] {8h45, 8h00, total_num};//16位标识每次发送累加1 ip_head[1][31:16] ip_head[1][31:16] 1b1;//bit[15:13]: 010表示不分片ip_head[1][15:0] 16h4000;//协议17(udp) ip_head[2] {8h40, 8d17, 16h0};//源IP地址 ip_head[3] BOARD_IP;//目的IP地址 if (des_ip ! 32d0) ip_head[4] des_ip;else ip_head[4] DES_IP;//16位源端口号1234 16位目的端口号1234 ip_head[5] {16d1234, 16d1234};//16位udp长度16位udp校验和 ip_head[6] {udp_num, 16h0000};//更新MAC地址if (des_mac ! 48b0) 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 5d1;if (cnt 5d0) 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 5d1) //可能出现进位,累加一次check_buffer check_buffer[31:16] check_buffer[15:0];else if (cnt 5d2) begin //可能再次出现进位,累加一次check_buffer check_buffer[31:16] check_buffer[15:0];end else if (cnt 5d3) begin //按位取反 skip_en 1b1;cnt 5d0;ip_head[2][15:0] ~check_buffer[15:0];endendst_preamble: begin //发送前导码帧起始界定符gmii_tx_en 1b1;gmii_txd preamble[cnt];if (cnt 5d7) beginskip_en 1b1;cnt 5d0;end else cnt cnt 5d1;endst_eth_head: begin //发送以太网首部gmii_tx_en 1b1;crc_en 1b1;gmii_txd eth_head[cnt];if (cnt 5d13) beginskip_en 1b1;cnt 5d0;end else cnt cnt 5d1;endst_ip_head: begin //发送IP首部 UDP首部crc_en 1b1;gmii_tx_en 1b1;tx_bit_sel tx_bit_sel 2d1;if (tx_bit_sel 3d0) gmii_txd ip_head[cnt][31:24];else if (tx_bit_sel 3d1) gmii_txd ip_head[cnt][23:16];else if (tx_bit_sel 3d2) begingmii_txd ip_head[cnt][15:8];if (cnt 5d6) begin//提前读请求数据等待数据有效时发送tx_req 1b1;endend else if (tx_bit_sel 3d3) begingmii_txd ip_head[cnt][7:0];if (cnt 5d6) beginskip_en 1b1;cnt 5d0;end else cnt cnt 5d1;endendst_tx_data: begin //发送数据crc_en 1b1;gmii_tx_en 1b1;tx_bit_sel tx_bit_sel 3d1;if (data_cnt tx_data_num - 16d1) data_cnt data_cnt 16d1;else if (data_cnt tx_data_num - 16d1) begin//如果发送的有效数据少于18个字节在后面填补充位//补充的值为最后一次发送的有效数据gmii_txd 8d0;if (data_cnt real_add_cnt real_tx_data_num - 16d1)real_add_cnt real_add_cnt 5d1;else beginskip_en 1b1;data_cnt 16d0;real_add_cnt 5d0;tx_bit_sel 3d0;endendif (tx_bit_sel 1b0) gmii_txd tx_data[31:24];else if (tx_bit_sel 3d1) gmii_txd tx_data[23:16];else if (tx_bit_sel 3d2) begingmii_txd tx_data[15:8];if (data_cnt ! tx_data_num - 16d1) tx_req 1b1;end else if (tx_bit_sel 3d3) gmii_txd tx_data[7:0];endst_crc: begin //发送CRC校验值gmii_tx_en 1b1;tx_bit_sel tx_bit_sel 3d1;if (tx_bit_sel 3d0)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 3d1)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 3d2) 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 3d3) 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 1b1;skip_en 1b1;endenddefault: ;endcaseendend//发送完成信号及crc值复位信号always (posedge clk or negedge rst_n) beginif (!rst_n) begintx_done 1b0;crc_clr 1b0;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 1b0);assign arp_tx_type 1b1; //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 1b1;else if (arp_tx_en) protocol_sw 1b0;else if (arp_tx_done) protocol_sw 1b1;endendmodule3 上位机验证
使用正点原子以太网视频传输上位机即可显示画面