赞
踩
- `timescale 1ns / 1ps
- // Descriptions:OV6540以太网传输视频顶层模块
-
-
- 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-55
- parameter 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_ff
- parameter DES_MAC = 48'hd2_ab_d5_e9_c6_86;
- //目的IP地址 192.168.1.102
- parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
-
- parameter H_CMOS_DISP = 11'd640; //CMOS分辨率640行
- parameter V_CMOS_DISP = 11'd480; //CMOS分辨率480列
- parameter TOTAL_H_PIXEL = H_CMOS_DISP + 12'd1216; //水平总像素大小
- parameter TOTAL_V_PIXEL = V_CMOS_DISP + 12'd504; //垂直总像素大小
-
- parameter SLAVE_ADDR = 7'h3c; //OV5640的器件地址7'h3c
- parameter BIT_CTRL = 1'b1; //OV5640的字节地址为16位 0:8位 1:16位
- parameter CLK_FREQ = 27'd50_000_000; //i2c_dri模块的驱动时钟频率
- parameter I2C_FREQ = 20'd250_000; //I2C的SCL时钟频率,不超过400KHz
- //wire define
- wire clk_100m; //100Mhz时钟
- wire eth_tx_clk; //以太网发送时钟
- wire locked;
- wire rst_n;
- wire i2c_dri_clk; //I2C操作时钟
- wire i2c_done; //I2C读写完成信号
- wire [ 7:0] i2c_data_r; //I2C读到的数据
- wire i2c_exec; //I2C触发信号
- wire [23:0] i2c_data; //I2C写地址+数据
- wire i2c_rh_wl; //I2C读写控制信号
- wire cam_init_done; //摄像头出初始化完成信号
- 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
- //*****************************************************
- assign rst_n = sys_rst_n & locked;
- //电源休眠模式选择 0:正常模式 1:电源休眠模式
- assign cam_pwdn = 1'b0;
- assign cam_rst_n = 1'b1;
- //例化时钟IP核
- clk_wiz_0 u_clk_wiz_0 (
- // Clock out ports
- .clk_out1 (clk_100m), // output clk_out1
- // Status and control signals
- .reset (~sys_rst_n), // input reset
- .locked (locked), // output locked
- // Clock in ports
- .clk_in1_p(sys_clk_p), // input clk_in1_p
- .clk_in1_n(sys_clk_n) // input clk_in1_n
- );
- //I2C配置模块
- i2c_ov5640_rgb565_cfg u_i2c_cfg (
- .clk (i2c_dri_clk),
- .rst_n (rst_n),
- .i2c_done (i2c_done),
- .i2c_data_r (i2c_data_r),
- .cmos_h_pixel (H_CMOS_DISP),
- .cmos_v_pixel (V_CMOS_DISP),
- .total_h_pixel(TOTAL_H_PIXEL),
- .total_v_pixel(TOTAL_V_PIXEL),
- .i2c_exec (i2c_exec),
- .i2c_data (i2c_data),
- .i2c_rh_wl (i2c_rh_wl),
- .init_done (cam_init_done)
- );
- //I2C驱动模块
- i2c_dri #(
- .SLAVE_ADDR(SLAVE_ADDR), //参数传递
- .CLK_FREQ (CLK_FREQ),
- .I2C_FREQ (I2C_FREQ)
- ) u_i2c_dri (
- .clk (clk_100m),
- .rst_n (rst_n),
- //i2c interface
- .i2c_exec (i2c_exec),
- .bit_ctrl (BIT_CTRL),
- .i2c_rh_wl (i2c_rh_wl),
- .i2c_addr (i2c_data[23:8]),
- .i2c_data_w(i2c_data[7:0]),
- .i2c_data_r(i2c_data_r),
- .i2c_done (i2c_done),
- .i2c_ack (),
- .scl (cam_scl),
- .sda (cam_sda),
- //user interface
- .dri_clk (i2c_dri_clk) //I2C操作时钟
- );
- //摄像头数据采集模块
- 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_valid(img_data_en),
- .cmos_frame_data (img_data)
- );
- //开始传输控制模块
- start_transfer_ctrl u_start_transfer_ctrl (
- .clk (eth_rx_clk),
- .rst_n (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 (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 (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
- `timescale 1ns / 1ps
- // Descriptions: iic配置
-
-
- 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 define
- localparam REG_NUM = 8'd250; //总共需要配置的寄存器个数
- //reg define
- reg [14:0] start_init_cnt; //等待延时计数器
- reg [ 7:0] init_reg_cnt; //寄存器配置个数计数器
- //*****************************************************
- //** main code
- //*****************************************************
- SCL配置成250KHz,输入的clk时钟频率为1Mhz,周期为1us 20000*1us = 20ms
- //OV5640上电到开始配置SCCB至少等待20ms
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) start_init_cnt <= 1'b0;
- else if (start_init_cnt < 15'd20000) begin
- start_init_cnt <= start_init_cnt + 1'b1;
- end
- end
-
- //寄存器配置个数计数
- always @(posedge clk or negedge rst_n) begin
- if (!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) begin
- if (!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) begin
- if (!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) begin
- if (!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) begin
- if (!rst_n) i2c_data <= 24'b0;
- else begin
- case (init_reg_cnt)
- //先读OV5640 ID
- 8'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}; //格式控制 RGB565
- 8'd55: i2c_data <= {16'h501f, 8'h01}; //ISP RGB
- 8'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 high
- 8'd59: i2c_data <= {16'h3a10, 8'h28}; //AEC控制;stable range in low
- 8'd60: i2c_data <= {16'h3a1b, 8'h30}; //AEC控制;stable range out high
- 8'd61: i2c_data <= {16'h3a1e, 8'h26}; //AEC控制;stable range out low
- 8'd62: i2c_data <= {16'h3a11, 8'h60}; //AEC控制; fast zone high
- 8'd63: i2c_data <= {16'h3a1f, 8'h14}; //AEC控制; fast zone low
- //LENC(镜头校正)控制 16'h5800~16'h583d
- 8'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'h519e
- 8'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'h5490
- 8'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'h538b
- 8'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'h558b
- 8'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 = 48Mhz
- 8'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'h3821
- 8'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 exposure
- 8'd234: i2c_data <= {16'h3a03, 8'h10}; //60Hz max exposure
- 8'd235: i2c_data <= {16'h3a14, 8'h17}; //50Hz max exposure
- 8'd236: i2c_data <= {16'h3a15, 8'h10}; //50Hz max exposure
- 8'd237: i2c_data <= {16'h4004, 8'h02}; //BLC(背光) 2 lines
- 8'd238: i2c_data <= {16'h4713, 8'h03}; //JPEG mode 3
- 8'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 divider
- 8'd242: i2c_data <= {16'h3824, 8'h02}; //DVP CLK divider
- 8'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位
- endcase
- end
- end
- endmodule
- `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 define
- localparam 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 define
- reg 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 define
- wire 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) begin
- if (!rst_n) begin
- dri_clk <= 1'b0;
- clk_cnt <= 10'd0;
- end else if (clk_cnt == clk_divide[8:1] - 1'd1) begin
- clk_cnt <= 10'd0;
- dri_clk <= ~dri_clk;
- end else clk_cnt <= clk_cnt + 1'b1;
- end
- //(三段式状态机)同步时序描述状态转移
- always @(posedge dri_clk or negedge rst_n) begin
- if (!rst_n) cur_state <= st_idle;
- else cur_state <= next_state;
- end
- //组合逻辑判断状态转移条件
- always @(*) begin
- next_state = st_idle;
- case (cur_state)
- st_idle: begin //空闲状态
- if (i2c_exec) begin
- next_state = st_sladdr;
- end else next_state = st_idle;
- end
- st_sladdr: begin
- if (st_done) begin
- if (bit_ctrl) //判断是16位还是8位字地址
- next_state = st_addr16;
- else next_state = st_addr8;
- end else next_state = st_sladdr;
- end
- st_addr16: begin //写16位字地址
- if (st_done) begin
- next_state = st_addr8;
- end else begin
- next_state = st_addr16;
- end
- end
- st_addr8: begin //8位字地址
- if (st_done) begin
- if (wr_flag == 1'b0) //读写判断
- next_state = st_data_wr;
- else next_state = st_addr_rd;
- end else begin
- next_state = st_addr8;
- end
- end
- st_data_wr: begin //写数据(8 bit)
- if (st_done) next_state = st_stop;
- else next_state = st_data_wr;
- end
- st_addr_rd: begin //写地址以进行读数据
- if (st_done) begin
- next_state = st_data_rd;
- end else begin
- next_state = st_addr_rd;
- end
- end
- st_data_rd: begin //读取数据(8 bit)
- if (st_done) next_state = st_stop;
- else next_state = st_data_rd;
- end
- st_stop: begin //结束I2C操作
- if (st_done) next_state = st_idle;
- else next_state = st_stop;
- end
- default: next_state = st_idle;
- endcase
- end
-
- //时序电路描述状态输出
- always @(posedge dri_clk or negedge rst_n) begin
- //复位初始化
- if (!rst_n) begin
- scl <= 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 begin
- st_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) begin
- wr_flag <= i2c_rh_wl ;
- addr_t <= i2c_addr ;
- data_wr_t <= i2c_data_w;
- i2c_ack <= 1'b0;
- end
- end
- st_sladdr: begin //写地址(器件地址和字地址)
- case (cnt)
- 7'd1: sda_out <= 1'b0; //开始I2C
- 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'b0; //0:写
- 7'd33: scl <= 1'b1;
- 7'd35: scl <= 1'b0;
- 7'd36: begin
- sda_dir <= 1'b0;
- sda_out <= 1'b1;
- end
- 7'd37: scl <= 1'b1;
- 7'd38: begin //从机应答
- st_done <= 1'b1;
- if (sda_in == 1'b1) //高电平表示未应答
- i2c_ack <= 1'b1; //拉高应答标志位
- end
- 7'd39: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- end
- default: ;
- endcase
- end
- st_addr16: begin
- case (cnt)
- 7'd0: begin
- sda_dir <= 1'b1;
- sda_out <= addr_t[15]; //传送字地址
- end
- 7'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: begin
- sda_dir <= 1'b0;
- sda_out <= 1'b1;
- end
- 7'd33: scl <= 1'b1;
- 7'd34: begin //从机应答
- st_done <= 1'b1;
- if (sda_in == 1'b1) //高电平表示未应答
- i2c_ack <= 1'b1; //拉高应答标志位
- end
- 7'd35: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- end
- default: ;
- endcase
- end
- st_addr8: begin
- case (cnt)
- 7'd0: begin
- sda_dir <= 1'b1;
- sda_out <= addr_t[7]; //字地址
- end
- 7'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: begin
- sda_dir <= 1'b0;
- sda_out <= 1'b1;
- end
- 7'd33: scl <= 1'b1;
- 7'd34: begin //从机应答
- st_done <= 1'b1;
- if (sda_in == 1'b1) //高电平表示未应答
- i2c_ack <= 1'b1; //拉高应答标志位
- end
- 7'd35: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- end
- default: ;
- endcase
- end
- st_data_wr: begin //写数据(8 bit)
- case (cnt)
- 7'd0: begin
- sda_out <= data_wr_t[7]; //I2C写8位数据
- sda_dir <= 1'b1;
- end
- 7'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: begin
- sda_dir <= 1'b0;
- sda_out <= 1'b1;
- end
- 7'd33: scl <= 1'b1;
- 7'd34: begin //从机应答
- st_done <= 1'b1;
- if (sda_in == 1'b1) //高电平表示未应答
- i2c_ack <= 1'b1; //拉高应答标志位
- end
- 7'd35: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- end
- default: ;
- endcase
- end
- st_addr_rd: begin //写地址以进行读数据
- case (cnt)
- 7'd0: begin
- sda_dir <= 1'b1;
- sda_out <= 1'b1;
- end
- 7'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: begin
- sda_dir <= 1'b0;
- sda_out <= 1'b1;
- end
- 7'd37: scl <= 1'b1;
- 7'd38: begin //从机应答
- st_done <= 1'b1;
- if (sda_in == 1'b1) //高电平表示未应答
- i2c_ack <= 1'b1; //拉高应答标志位
- end
- 7'd39: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- end
- default: ;
- endcase
- end
- st_data_rd: begin //读取数据(8 bit)
- case (cnt)
- 7'd0: sda_dir <= 1'b0;
- 7'd1: begin
- data_r[7] <= sda_in;
- scl <= 1'b1;
- end
- 7'd3: scl <= 1'b0;
- 7'd5: begin
- data_r[6] <= sda_in;
- scl <= 1'b1;
- end
- 7'd7: scl <= 1'b0;
- 7'd9: begin
- data_r[5] <= sda_in;
- scl <= 1'b1;
- end
- 7'd11: scl <= 1'b0;
- 7'd13: begin
- data_r[4] <= sda_in;
- scl <= 1'b1;
- end
- 7'd15: scl <= 1'b0;
- 7'd17: begin
- data_r[3] <= sda_in;
- scl <= 1'b1;
- end
- 7'd19: scl <= 1'b0;
- 7'd21: begin
- data_r[2] <= sda_in;
- scl <= 1'b1;
- end
- 7'd23: scl <= 1'b0;
- 7'd25: begin
- data_r[1] <= sda_in;
- scl <= 1'b1;
- end
- 7'd27: scl <= 1'b0;
- 7'd29: begin
- data_r[0] <= sda_in;
- scl <= 1'b1;
- end
- 7'd31: scl <= 1'b0;
- 7'd32: begin
- sda_dir <= 1'b1;
- sda_out <= 1'b1;
- end
- 7'd33: scl <= 1'b1;
- 7'd34: st_done <= 1'b1; //非应答
- 7'd35: begin
- scl <= 1'b0;
- cnt <= 1'b0;
- i2c_data_r <= data_r;
- end
- default: ;
- endcase
- end
- st_stop: begin //结束I2C操作
- case (cnt)
- 7'd0: begin
- sda_dir <= 1'b1; //结束I2C
- sda_out <= 1'b0;
- end
- 7'd1: scl <= 1'b1;
- 7'd3: sda_out <= 1'b1;
- 7'd15: st_done <= 1'b1;
- 7'd16: begin
- cnt <= 1'b0;
- i2c_done <= 1'b1; //向上层模块传递I2C结束信号
- end
- default: ;
- endcase
- end
- endcase
- end
- end
-
- endmodule
- `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) begin
- if (!rst_n) begin
- cam_vsync_d0 <= 1'b0;
- cam_vsync_d1 <= 1'b0;
- cam_href_d0 <= 1'b0;
- cam_href_d1 <= 1'b0;
- end else begin
- cam_vsync_d0 <= cam_vsync;
- cam_vsync_d1 <= cam_vsync_d0;
- cam_href_d0 <= cam_href;
- cam_href_d1 <= cam_href_d0;
- end
- end
- //对帧数进行计数
- always @(posedge cam_pclk or negedge rst_n) begin
- if (!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) begin
- if (!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) begin
- if (!rst_n) begin
- cmos_data_t <= 16'd0;
- cam_data_d0 <= 8'd0;
- byte_flag <= 1'b0;
- end else if (cam_href) begin
- byte_flag <= ~byte_flag;
- cam_data_d0 <= cam_data;
- if (byte_flag) cmos_data_t <= {cam_data_d0, cam_data};
- else;
- end else begin
- byte_flag <= 1'b0;
- cam_data_d0 <= 8'b0;
- end
- end
-
- //产生输出数据有效信号(cmos_frame_valid)
- always @(posedge cam_pclk or negedge rst_n) begin
- if (!rst_n) byte_flag_d0 <= 1'b0;
- else byte_flag_d0 <= byte_flag;
- end
- endmodule
- `timescale 1ns / 1ps
- //图像开始传输控制模块
-
-
- module start_transfer_ctrl (
- input clk, //时钟信号
- input rst_n, //复位信号,低电平有效
- input udp_rec_pkt_done, //GMII接收时钟
- input udp_rec_en, //UDP单包数据接收完成信号
- input [31:0] udp_rec_data, //UDP接收的数据使能信号
- input [15:0] udp_rec_byte_num, //UDP接收的数据
- //UDP接收到的字节数
- output reg transfer_flag //图像开始传输标志,0:开始传输 1:停止传输
- );
-
- //parameter define
- parameter START = "1"; //开始命令
- parameter STOP = "0"; //停止命令
-
- //*****************************************************
- //** main code
- //*****************************************************
-
- //解析接收到的数据
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) transfer_flag <= 1'b0;
- else if (udp_rec_pkt_done && udp_rec_byte_num == 1'b1) begin
- if (udp_rec_data[31:24] == START) //开始传输
- transfer_flag <= 1'b1;
- else if (udp_rec_data[31:24] == STOP) //停止传输
- transfer_flag <= 1'b0;
- end
- end
-
- endmodule
- `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 define
- parameter 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) begin
- if (!rst_n) begin
- img_vsync_d0 <= 1'b0;
- img_vsync_d1 <= 1'b0;
- end else begin
- img_vsync_d0 <= img_vsync;
- img_vsync_d1 <= img_vsync_d0;
- end
- end
- //寄存neg_vsync信号
- always @(posedge cam_pclk or negedge rst_n) begin
- if (!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) begin
- if (!rst_n) begin
- wr_sw <= 1'b0;
- img_data_d0 <= 1'b0;
- end else if (neg_vsync) wr_sw <= 1'b0;
- else if (img_data_en) begin
- wr_sw <= ~wr_sw;
- img_data_d0 <= img_data;
- end
- end
- //将帧头和图像数据写入FIFO
- always @(posedge cam_pclk or negedge rst_n) begin
- if (!rst_n) begin
- wr_fifo_en <= 1'b0;
- wr_fifo_data <= 1'b0;
- end else begin
- if (neg_vsync) begin
- wr_fifo_en <= 1'b1;
- wr_fifo_data <= IMG_FRAME_HEAD; //帧头
- end else if (neg_vsync_d0) begin
- wr_fifo_en <= 1'b1;
- wr_fifo_data <= {CMOS_H_PIXEL, CMOS_V_PIXEL}; //水平和垂直方向分辨率
- end else if (img_data_en && wr_sw) begin
- wr_fifo_en <= 1'b1;
- wr_fifo_data <= {img_data_d0, img_data}; //图像数据位拼接,16位转32位
- end else begin
- wr_fifo_en <= 1'b0;
- wr_fifo_data <= 1'b0;
- end
- end
- end
-
- //以太网发送时钟域下,对img_vsync信号延时两个时钟周期,用于采沿
- always @(posedge eth_tx_clk or negedge rst_n) begin
- if (!rst_n) begin
- img_vsync_txc_d0 <= 1'b0;
- img_vsync_txc_d1 <= 1'b0;
- end else begin
- img_vsync_txc_d0 <= img_vsync;
- img_vsync_txc_d1 <= img_vsync_txc_d0;
- end
- end
-
- //控制以太网发送的字节数
- always @(posedge eth_tx_clk or negedge rst_n) begin
- if (!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) begin
- if (!rst_n) begin
- udp_tx_start_en <= 1'b0;
- tx_busy_flag <= 1'b0;
- end //上位机未发送"开始"命令时,以太网不发送图像数据
- else if (transfer_flag == 1'b0) begin
- udp_tx_start_en <= 1'b0;
- tx_busy_flag <= 1'b0;
- end else begin
- udp_tx_start_en <= 1'b0;
- //当FIFO中的个数满足需要发送的字节数时
- if (tx_busy_flag == 1'b0 && fifo_rdusedw >= udp_tx_byte_num[15:2]) begin
- udp_tx_start_en <= 1'b1; //开始控制发送一包数据
- tx_busy_flag <= 1'b1;
- end else if (udp_tx_done || neg_vsynt_txc) tx_busy_flag <= 1'b0;
- end
- end
-
- //异步FIFO
- async_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
- `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-55
- parameter 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_ff
- parameter 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 #(
- .BOARD_MAC(BOARD_MAC), //参数例化
- .BOARD_IP (BOARD_IP),
- .DES_MAC (DES_MAC),
- .DES_IP (DES_IP)
- ) u_arp (
- .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 #(
- .BOARD_MAC(BOARD_MAC), //参数例化
- .BOARD_IP (BOARD_IP),
- .DES_MAC (DES_MAC),
- .DES_IP (DES_IP)
- ) u_udp (
- .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
- `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
- `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 define
- wire 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;
- generate
- for (i = 0; i < 4; i = i + 1) begin : rxdata_bus
- 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_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
- );
- end
- endgenerate
-
- endmodule
- `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;
- generate
- for (i = 0; i < 4; i = i + 1) begin : txdata_bus
- 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_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
- );
- end
- endgenerate
-
- endmodule
- `timescale 1ns / 1ps
- //arp模块
-
-
- module arp (
- 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-55
- parameter 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_ff
- parameter 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 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
- `timescale 1ns / 1ps
- //arp接收模块
-
-
- module arp_rx #(
- //开发板MAC地址 00-11-22-33-44-55
- parameter 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}
- ) (
- 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
- 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 define
- reg [ 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) begin
- if (!rst_n) cur_state <= st_idle;
- else cur_state <= next_state;
- end
- //组合逻辑判断状态转移条件
- always @(*) begin
- next_state = st_idle;
- case (cur_state)
- st_idle: begin //等待接收前导码
- if (skip_en) next_state = st_preamble;
- else next_state = st_idle;
- end
- st_preamble: begin //接收前导码
- if (skip_en) next_state = st_eth_head;
- else if (error_en) next_state = st_rx_end;
- else next_state = st_preamble;
- end
- st_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;
- end
- st_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;
- end
- st_rx_end: begin //接收结束
- if (skip_en) next_state = st_idle;
- else next_state = st_rx_end;
- end
- default: next_state = st_idle;
- endcase
- end
- //时序电路描述状态输出,解析以太网数据
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- skip_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 begin
- skip_en <= 1'b0;
- error_en <= 1'b0;
- arp_rx_done <= 1'b0;
- case (next_state)
- st_idle: begin //检测到第一个8'h55
- if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;
- end
- st_preamble: begin
- if (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) begin
- cnt <= 5'd0;
- if (gmii_rxd == 8'hd5) //1个8'hd5
- skip_en <= 1'b1;
- else error_en <= 1'b1;
- end
- end
- end
- st_eth_head: begin
- if (gmii_rx_dv) begin
- cnt <= 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) begin
- eth_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;
- end
- end
- end
- st_arp_data: begin
- if (gmii_rx_dv) begin
- cnt <= 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) begin
- cnt <= 5'd0;
- if (des_ip_t == BOARD_IP) begin //判断目的IP地址和操作码
- if ((op_data == 16'd1) || (op_data == 16'd2)) begin
- skip_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;
- end
- end
- end
- st_rx_end: begin
- cnt <= 5'd0;
- //单包数据接收完成
- if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;
- end
- default: ;
- endcase
- end
- end
-
- endmodule
- `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-55
- parameter 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_ff
- parameter 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 define
- reg [4:0] cur_state;
- reg [4:0] next_state;
- reg [7:0] preamble [ 7:0]; //前导码+SFD
- reg [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) begin
- if (!rst_n) begin
- tx_en_d0 <= 1'b0;
- tx_en_d1 <= 1'b0;
- end else begin
- tx_en_d0 <= arp_tx_en;
- tx_en_d1 <= tx_en_d0;
- end
- end
- //(三段式状态机)同步时序描述状态转移
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) cur_state <= st_idle;
- else cur_state <= next_state;
- end
- //组合逻辑判断状态转移条件
- always @(*) begin
- next_state = st_idle;
- case (cur_state)
- st_idle: begin //空闲状态
- if (skip_en) next_state = st_preamble;
- else next_state = st_idle;
- end
- st_preamble: begin //发送前导码+帧起始界定符
- if (skip_en) next_state = st_eth_head;
- else next_state = st_preamble;
- end
- st_eth_head: begin //发送以太网首部
- if (skip_en) next_state = st_arp_data;
- else next_state = st_eth_head;
- end
- st_arp_data: begin //发送ARP数据
- if (skip_en) next_state = st_crc;
- else next_state = st_arp_data;
- end
- st_crc: begin //发送CRC校验值
- if (skip_en) next_state = st_idle;
- else next_state = st_crc;
- end
- default: next_state = st_idle;
- endcase
- end
- //时序电路描述状态输出,发送以太网数据
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- skip_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; //硬件地址长度,6
- arp_data[5] <= 8'h04; //协议地址长度,4
- arp_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 begin
- skip_en <= 1'b0;
- crc_en <= 1'b0;
- gmii_tx_en <= 1'b0;
- tx_done_t <= 1'b0;
- case (next_state)
- st_idle: begin
- if (pos_tx_en) begin
- skip_en <= 1'b1;
- //如果目标MAC地址和IP地址已经更新,则发送正确的地址
- if ((des_mac != 48'b0) || (des_ip != 32'd0)) begin
- 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];
- 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];
- end
- if (arp_tx_type == 1'b0) arp_data[7] <= 8'h01; //ARP请求
- else arp_data[7] <= 8'h02; //ARP应答
- end
- end
- st_preamble: begin //发送前导码+帧起始界定符
- gmii_tx_en <= 1'b1;
- gmii_txd <= preamble[cnt];
- if (cnt == 6'd7) begin
- skip_en <= 1'b1;
- cnt <= 1'b0;
- end else cnt <= cnt + 1'b1;
- end
- st_eth_head: begin //发送以太网首部
- gmii_tx_en <= 1'b1;
- crc_en <= 1'b1;
- gmii_txd <= eth_head[cnt];
- if (cnt == 6'd13) begin
- skip_en <= 1'b1;
- cnt <= 1'b0;
- end else cnt <= cnt + 1'b1;
- end
- st_arp_data: begin //发送ARP数据
- crc_en <= 1'b1;
- gmii_tx_en <= 1'b1;
- //至少发送46个字节
- if (cnt == MIN_DATA_NUM - 1'b1) begin
- skip_en <= 1'b1;
- cnt <= 1'b0;
- data_cnt <= 1'b0;
- end else cnt <= cnt + 1'b1;
- if (data_cnt <= 6'd27) begin
- data_cnt <= data_cnt + 1'b1;
- gmii_txd <= arp_data[data_cnt];
- end else gmii_txd <= 8'd0; //Padding,填充0
- end
- st_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) begin
- gmii_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) begin
- gmii_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;
- end
- end
- default: ;
- endcase
- end
- end
-
- //发送完成信号及crc值复位信号
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- tx_done <= 1'b0;
- crc_clr <= 1'b0;
- end else begin
- tx_done <= tx_done_t;
- crc_clr <= tx_done_t;
- end
- end
-
- endmodule
- `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 + 1
-
- assign 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) begin
- if (!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;
- end
-
- endmodule
- `timescale 1ns / 1ps
- //udp模块
-
-
- module udp (
- 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-55
- parameter 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_ff
- parameter 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 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
- `timescale 1ns / 1ps
- //以太网数据接收模块
-
-
- 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-55
- parameter 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 define
- reg [ 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) begin
- if (!rst_n) cur_state <= st_idle;
- else cur_state <= next_state;
- end
- //组合逻辑判断状态转移条件
- always @(*) begin
- next_state = st_idle;
- case (cur_state)
- st_idle: begin //等待接收前导码
- if (skip_en) next_state = st_preamble;
- else next_state = st_idle;
- end
- st_preamble: begin //接收前导码
- if (skip_en) next_state = st_eth_head;
- else if (error_en) next_state = st_rx_end;
- else next_state = st_preamble;
- end
- st_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;
- end
- st_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;
- end
- st_udp_head: begin //接收UDP首部
- if (skip_en) next_state = st_rx_data;
- else next_state = st_udp_head;
- end
- st_rx_data: begin //接收有效数据
- if (skip_en) next_state = st_rx_end;
- else next_state = st_rx_data;
- end
- st_rx_end: begin //接收结束
- if (skip_en) next_state = st_idle;
- else next_state = st_rx_end;
- end
- default: next_state = st_idle;
- endcase
- end
- //时序电路描述状态输出,解析以太网数据
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- skip_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 begin
- skip_en <= 1'b0;
- error_en <= 1'b0;
- rec_en <= 1'b0;
- rec_pkt_done <= 1'b0;
- case (next_state)
- st_idle: begin
- if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;
- end
- st_preamble: begin
- if (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) begin
- cnt <= 5'd0;
- if (gmii_rxd == 8'hd5) //1个8'hd5
- skip_en <= 1'b1;
- else error_en <= 1'b1;
- end
- end
- end
- st_eth_head: begin
- if (gmii_rx_dv) begin
- cnt <= 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) begin
- eth_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;
- end
- end
- end
- st_ip_head: begin
- if (gmii_rx_dv) begin
- cnt <= 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) begin
- des_ip <= {des_ip[23:0], gmii_rxd};
- //判断IP地址是否为开发板IP地址
- if ((des_ip[23:0] == BOARD_IP[31:8]) && (gmii_rxd == BOARD_IP[7:0])) begin
- if (cnt == ip_head_byte_num - 1'b1) begin
- skip_en <= 1'b1;
- cnt <= 5'd0;
- end
- end else begin
- //IP错误,停止解析数据
- error_en <= 1'b1;
- cnt <= 5'd0;
- end
- end else if (cnt == ip_head_byte_num - 1'b1) begin
- skip_en <= 1'b1; //IP首部解析完成
- cnt <= 5'd0;
- end
- end
- end
- st_udp_head: begin
- if (gmii_rx_dv) begin
- cnt <= 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;
- end
- end
- end
- st_rx_data: begin
- //接收数据,转换成32bit
- if (gmii_rx_dv) begin
- data_cnt <= data_cnt + 16'd1;
- rec_en_cnt <= rec_en_cnt + 2'd1;
- if (data_cnt == data_byte_num - 16'd1) begin
- skip_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) begin
- rec_en <= 1'b1;
- rec_data[7:0] <= gmii_rxd;
- end
- end
- end
- st_rx_end: begin //单包数据接收完成
- if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;
- end
- default: ;
- endcase
- end
- end
- endmodule
- `timescale 1ns / 1ps
- //以太网数据发送模块
-
-
- 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-55
- parameter 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_ff
- parameter 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 define
- reg [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) begin
- if (!rst_n) begin
- start_en_d0 <= 1'b0;
- start_en_d1 <= 1'b0;
- end else begin
- start_en_d0 <= tx_start_en;
- start_en_d1 <= start_en_d0;
- end
- end
- //寄存数据有效字节
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- tx_data_num <= 16'd0;
- total_num <= 16'd0;
- udp_num <= 16'd0;
- end else begin
- if (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;
- end
- end
- end
-
- //触发发送信号
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) trig_tx_en <= 1'b0;
- else trig_tx_en <= pos_start_en;
- end
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) cur_state <= st_idle;
- else cur_state <= next_state;
- end
- always @(*) begin
- next_state = st_idle;
- case (cur_state)
- st_idle: begin //等待发送数据
- if (skip_en) next_state = st_check_sum;
- else next_state = st_idle;
- end
- st_check_sum: begin //IP首部校验
- if (skip_en) next_state = st_preamble;
- else next_state = st_check_sum;
- end
- st_preamble: begin //发送前导码+帧起始界定符
- if (skip_en) next_state = st_eth_head;
- else next_state = st_preamble;
- end
- st_eth_head: begin //发送以太网首部
- if (skip_en) next_state = st_ip_head;
- else next_state = st_eth_head;
- end
- st_ip_head: begin //发送IP首部+UDP首部
- if (skip_en) next_state = st_tx_data;
- else next_state = st_ip_head;
- end
- st_tx_data: begin //发送数据
- if (skip_en) next_state = st_crc;
- else next_state = st_tx_data;
- end
- st_crc: begin //发送CRC校验值
- if (skip_en) next_state = st_idle;
- else next_state = st_crc;
- end
- default: next_state = st_idle;
- endcase
- end
- //发送数据
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- skip_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'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;
- //目的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 begin
- skip_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: begin
- if (trig_tx_en) begin
- skip_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];
- end
- end
- end
- st_check_sum: begin //IP首部校验
- cnt <= cnt + 5'd1;
- if (cnt == 5'd0) begin
- check_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];
- end
- end
- st_preamble: begin //发送前导码+帧起始界定符
- gmii_tx_en <= 1'b1;
- gmii_txd <= preamble[cnt];
- if (cnt == 5'd7) begin
- skip_en <= 1'b1;
- cnt <= 5'd0;
- end else cnt <= cnt + 5'd1;
- end
- st_eth_head: begin //发送以太网首部
- gmii_tx_en <= 1'b1;
- crc_en <= 1'b1;
- gmii_txd <= eth_head[cnt];
- if (cnt == 5'd13) begin
- skip_en <= 1'b1;
- cnt <= 5'd0;
- end else cnt <= cnt + 5'd1;
- end
- st_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) begin
- gmii_txd <= ip_head[cnt][15:8];
- if (cnt == 5'd6) begin
- //提前读请求数据,等待数据有效时发送
- tx_req <= 1'b1;
- end
- end else if (tx_bit_sel == 3'd3) begin
- gmii_txd <= ip_head[cnt][7:0];
- if (cnt == 5'd6) begin
- skip_en <= 1'b1;
- cnt <= 5'd0;
- end else cnt <= cnt + 5'd1;
- end
- end
- st_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 begin
- skip_en <= 1'b1;
- data_cnt <= 16'd0;
- real_add_cnt <= 5'd0;
- tx_bit_sel <= 3'd0;
- end
- end
- if (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) begin
- gmii_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];
- end
- st_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) begin
- gmii_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) begin
- gmii_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;
- end
- end
- default: ;
- endcase
- end
- end
- //发送完成信号及crc值复位信号
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- tx_done <= 1'b0;
- crc_clr <= 1'b0;
- end else begin
- tx_done <= tx_done_t;
- crc_clr <= tx_done_t;
- end
- end
- endmodule
- `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 + 1
-
- assign 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) begin
- if (!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;
- end
-
- endmodule
- `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 define
- reg 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) begin
- if (!rst_n) protocol_sw <= 1'b1;
- else if (arp_tx_en) protocol_sw <= 1'b0;
- else if (arp_tx_done) protocol_sw <= 1'b1;
- end
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。