当前位置:   article > 正文

FPGA 以太网传输ov5640视频

FPGA 以太网传输ov5640视频

1 实验任务

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

2 系统框架

时钟模块用于为 I2C 驱动模块、以太网顶层模块和开始传输控制模块提供驱动时钟;I2C 驱动模块和 I2C 配置模块用于初始化 OV5640 图像传感器;摄像头采集模块负责采集摄像头图像数据,并且把图像数据连接至图像数据封装模块,图像数据封装模块将输入的图像数据进行位拼接,并添加图像的帧头和行场分辨率;以太网顶层模块实现以太网数据的收发;开始传输控制模块控制以太网顶层模块开始/ 停止发送数据。

 

FPGA 顶层模块( ov5640_udp_pc )例化了以下 7 个模块:时钟模块( clk_wiz_0 )、 I2C 配置模块(i2c_ov5640_rgb565_cfg )、 I2C 驱动模块( i2c_dri )、摄像头数据采集模块( cmos_capture_data )、开始传输控制模块(start_transfer_ctrl )、图像数据封装模块( img_data_pkt )和以太网顶层模块模块( eth_top )。时钟模块(clk_wiz_0 ):时钟 IP 核模块通过调用 MMCM IP 核来实现,总共输出 2 个时钟,频率分别为 100Mhz 200Mhz 时钟。 100Mhz 时钟 I2C 驱动模块的驱动时钟; 200Mhz 时钟作为 IDELAYCTRL 源语的参考时钟。I2C 驱动模块( i2c_dri ): I2C 驱动模块负责驱动 OV5640 SCCB 接口总线,用户可根据该模块提供的
用户接口可以很方便的对 OV5640 的寄存器进行配置,该模块和“ I2C 读写实验”章节中用到的 I2C 驱动模块为同一个模块
I2C 配置模块( i2c_ov5640_rgb565_cfg ): I2C 配置模块的驱动时钟是由 I2C 驱动模块输出的时钟提供的,这样方便了 I2C 驱动模块和 I2C 配置模块之间的数据交互。该模块寄存需要配置的寄存器地址、数据以及控制初始化的开始与结束,同时该模块输出 OV5640 的寄存器地址和数据以及控制 I2C 驱动模块开始执行的控制信号,直接连接到 I2C 驱动模块的用户接口,从而完成对 OV5640 传感器的初始化。
摄像头图像采集模块( cmos_capture_data ):摄像头采集模块在像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及 8 位数据转换成 DDR 读写控制模块的写使能信号和 16 位写数据信号,完成对OV5640 传感器图像的采集。
开始传输控制模块( start_transfer_ctrl ):该模块解析以太网顶层模块接收到的数据,如果收到 1 个字节的 ASCII 码“ 1 ”,则表示以太网开始传输图像数据;如果收到 1 个字节的 ASCII 码“ 0 ”,则表示以太网停止传输图像数据。
图像数据封装模块( img_data_pkt ):图像数据封装模块负责将输入 16 位的图像数据,拼接成 32 位数据,以及添加图像数据的帧头和行场分辨率。该模块控制着以太网发送模块发送的字节数,单次发送一行图像数据的字节数,模块内部例化了一个异步 FIFO 模块,用于缓存待发送的图像数据。
以太网顶层模块( eth_top ):该模块例化了一个时钟 ip 核,输出一个偏移 90 度的 125Mhz 时钟作为以太网顶层模块发送模块的驱动时钟,以太网顶层模块实现以太网通信的收发功能。

 3 FPGA代码

3.1 顶层模块

  1. `timescale 1ns / 1ps
  2. // Descriptions:OV6540以太网传输视频顶层模块
  3. module ov5640_udp_pc (
  4. input sys_clk_p, //系统时钟
  5. input sys_clk_n, //系统时钟
  6. input sys_rst_n, //系统复位信号,低电平有效
  7. //以太网接口
  8. input eth_rxc, //RGMII接收数据时钟
  9. input eth_rx_ctl, //RGMII输入数据有效信号
  10. input [3:0] eth_rxd, //RGMII输入数据
  11. output eth_txc, //RGMII发送数据时钟
  12. output eth_tx_ctl, //RGMII输出数据有效信号
  13. output [3:0] eth_txd, //RGMII输出数据
  14. //摄像头接口
  15. input cam_pclk, //cmos 数据像素时钟
  16. input cam_vsync, //cmos 场同步信号
  17. input cam_href, //cmos 行同步信号
  18. input [7:0] cam_data, //cmos 数据
  19. output cam_rst_n, //cmos 复位信号,低电平有效
  20. output cam_pwdn, //电源休眠模式选择 0:正常模式 1:电源休眠模式
  21. output cam_scl, //cmos SCCB_SCL线
  22. inout cam_sda //cmos SCCB_SDA线
  23. );
  24. //parameter define
  25. //开发板MAC地址 00-11-22-33-44-55
  26. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  27. //开发板IP地址 192.168.1.10
  28. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  29. //目的MAC地址 ff_ff_ff_ff_ff_ff
  30. parameter DES_MAC = 48'hd2_ab_d5_e9_c6_86;
  31. //目的IP地址 192.168.1.102
  32. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  33. parameter H_CMOS_DISP = 11'd640; //CMOS分辨率640行
  34. parameter V_CMOS_DISP = 11'd480; //CMOS分辨率480
  35. parameter TOTAL_H_PIXEL = H_CMOS_DISP + 12'd1216; //水平总像素大小
  36. parameter TOTAL_V_PIXEL = V_CMOS_DISP + 12'd504; //垂直总像素大小
  37. parameter SLAVE_ADDR = 7'h3c; //OV5640的器件地址7'h3c
  38. parameter BIT_CTRL = 1'b1; //OV5640的字节地址为16位 0:8位 1:16位
  39. parameter CLK_FREQ = 27'd50_000_000; //i2c_dri模块的驱动时钟频率
  40. parameter I2C_FREQ = 20'd250_000; //I2C的SCL时钟频率,不超过400KHz
  41. //wire define
  42. wire clk_100m; //100Mhz时钟
  43. wire eth_tx_clk; //以太网发送时钟
  44. wire locked;
  45. wire rst_n;
  46. wire i2c_dri_clk; //I2C操作时钟
  47. wire i2c_done; //I2C读写完成信号
  48. wire [ 7:0] i2c_data_r; //I2C读到的数据
  49. wire i2c_exec; //I2C触发信号
  50. wire [23:0] i2c_data; //I2C写地址+数据
  51. wire i2c_rh_wl; //I2C读写控制信号
  52. wire cam_init_done; //摄像头出初始化完成信号
  53. wire cmos_frame_vsync; //输出帧有效场同步信号
  54. wire img_data_en; //摄像头图像有效信号
  55. wire [15:0] img_data; //摄像头图像有效数据
  56. wire transfer_flag; //图像开始传输标志,0:开始传输 1:停止传输
  57. wire eth_rx_clk; //以太网接收时钟
  58. wire udp_tx_start_en; //以太网开始发送信号
  59. wire [15:0] udp_tx_byte_num; //以太网发送的有效字节数
  60. wire [31:0] udp_tx_data; //以太网发送的数据
  61. wire udp_rec_pkt_done; //以太网单包数据接收完成信号
  62. wire udp_rec_en; //以太网接收使能信号
  63. wire [31:0] udp_rec_data; //以太网接收到的数据
  64. wire [15:0] udp_rec_byte_num; //以太网接收到的字节个数
  65. wire udp_tx_req; //以太网发送请求数据信号
  66. wire udp_tx_done; //以太网发送完成信号
  67. //*****************************************************
  68. //** main code
  69. //*****************************************************
  70. assign rst_n = sys_rst_n & locked;
  71. //电源休眠模式选择 0:正常模式 1:电源休眠模式
  72. assign cam_pwdn = 1'b0;
  73. assign cam_rst_n = 1'b1;
  74. //例化时钟IP核
  75. clk_wiz_0 u_clk_wiz_0 (
  76. // Clock out ports
  77. .clk_out1 (clk_100m), // output clk_out1
  78. // Status and control signals
  79. .reset (~sys_rst_n), // input reset
  80. .locked (locked), // output locked
  81. // Clock in ports
  82. .clk_in1_p(sys_clk_p), // input clk_in1_p
  83. .clk_in1_n(sys_clk_n) // input clk_in1_n
  84. );
  85. //I2C配置模块
  86. i2c_ov5640_rgb565_cfg u_i2c_cfg (
  87. .clk (i2c_dri_clk),
  88. .rst_n (rst_n),
  89. .i2c_done (i2c_done),
  90. .i2c_data_r (i2c_data_r),
  91. .cmos_h_pixel (H_CMOS_DISP),
  92. .cmos_v_pixel (V_CMOS_DISP),
  93. .total_h_pixel(TOTAL_H_PIXEL),
  94. .total_v_pixel(TOTAL_V_PIXEL),
  95. .i2c_exec (i2c_exec),
  96. .i2c_data (i2c_data),
  97. .i2c_rh_wl (i2c_rh_wl),
  98. .init_done (cam_init_done)
  99. );
  100. //I2C驱动模块
  101. i2c_dri #(
  102. .SLAVE_ADDR(SLAVE_ADDR), //参数传递
  103. .CLK_FREQ (CLK_FREQ),
  104. .I2C_FREQ (I2C_FREQ)
  105. ) u_i2c_dri (
  106. .clk (clk_100m),
  107. .rst_n (rst_n),
  108. //i2c interface
  109. .i2c_exec (i2c_exec),
  110. .bit_ctrl (BIT_CTRL),
  111. .i2c_rh_wl (i2c_rh_wl),
  112. .i2c_addr (i2c_data[23:8]),
  113. .i2c_data_w(i2c_data[7:0]),
  114. .i2c_data_r(i2c_data_r),
  115. .i2c_done (i2c_done),
  116. .i2c_ack (),
  117. .scl (cam_scl),
  118. .sda (cam_sda),
  119. //user interface
  120. .dri_clk (i2c_dri_clk) //I2C操作时钟
  121. );
  122. //摄像头数据采集模块
  123. cmos_capture_data u_cmos_capture_data (
  124. .rst_n (rst_n & cam_init_done),
  125. .cam_pclk (cam_pclk),
  126. .cam_vsync (cam_vsync),
  127. .cam_href (cam_href),
  128. .cam_data (cam_data),
  129. .cmos_frame_vsync(cmos_frame_vsync),
  130. .cmos_frame_href (),
  131. .cmos_frame_valid(img_data_en),
  132. .cmos_frame_data (img_data)
  133. );
  134. //开始传输控制模块
  135. start_transfer_ctrl u_start_transfer_ctrl (
  136. .clk (eth_rx_clk),
  137. .rst_n (rst_n),
  138. .udp_rec_pkt_done(udp_rec_pkt_done),
  139. .udp_rec_en (udp_rec_en),
  140. .udp_rec_data (udp_rec_data),
  141. .udp_rec_byte_num(udp_rec_byte_num),
  142. .transfer_flag (transfer_flag) //图像开始传输标志,1:开始传输 0:停止传输
  143. );
  144. //图像封装模块
  145. img_data_pkt u_img_data_pkt (
  146. .rst_n (rst_n),
  147. .cam_pclk (cam_pclk),
  148. .img_vsync (cmos_frame_vsync),
  149. .img_data_en (img_data_en),
  150. .img_data (img_data),
  151. .transfer_flag (transfer_flag),
  152. .eth_tx_clk (eth_tx_clk),
  153. .udp_tx_req (udp_tx_req),
  154. .udp_tx_done (udp_tx_done),
  155. .udp_tx_start_en(udp_tx_start_en),
  156. .udp_tx_data (udp_tx_data),
  157. .udp_tx_byte_num(udp_tx_byte_num)
  158. );
  159. //以太网顶层模块
  160. eth_top #(
  161. .BOARD_MAC(BOARD_MAC), //参数例化
  162. .BOARD_IP (BOARD_IP),
  163. .DES_MAC (DES_MAC),
  164. .DES_IP (DES_IP)
  165. ) u_eth_top (
  166. .sys_rst_n (rst_n), //系统复位信号,低电平有效
  167. //以太网RGMII接口
  168. .eth_rxc (eth_rxc), //RGMII接收数据时钟
  169. .eth_rx_ctl(eth_rx_ctl), //RGMII输入数据有效信号
  170. .eth_rxd (eth_rxd), //RGMII输入数据
  171. .eth_txc (eth_txc), //RGMII发送数据时钟
  172. .eth_tx_ctl(eth_tx_ctl), //RGMII输出数据有效信号
  173. .eth_txd (eth_txd), //RGMII输出数据
  174. .gmii_rx_clk (eth_rx_clk),
  175. .gmii_tx_clk (eth_tx_clk),
  176. .udp_tx_start_en(udp_tx_start_en),
  177. .tx_data (udp_tx_data),
  178. .tx_byte_num (udp_tx_byte_num),
  179. .udp_tx_done (udp_tx_done),
  180. .tx_req (udp_tx_req),
  181. .rec_pkt_done (udp_rec_pkt_done),
  182. .rec_en (udp_rec_en),
  183. .rec_data (udp_rec_data),
  184. .rec_byte_num (udp_rec_byte_num)
  185. );
  186. endmodule

 

 

3.2 iic配置模块

  1. `timescale 1ns / 1ps
  2. // Descriptions: iic配置
  3. module i2c_ov5640_rgb565_cfg (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input [ 7:0] i2c_data_r, //I2C读出的数据
  7. input i2c_done, //I2C寄存器配置完成信号
  8. input [12:0] cmos_h_pixel,
  9. input [12:0] cmos_v_pixel,
  10. input [12:0] total_h_pixel, //水平总像素大小
  11. input [12:0] total_v_pixel, //垂直总像素大小
  12. output reg i2c_exec, //I2C触发执行信号
  13. output reg [23:0] i2c_data, //I2C要配置的地址与数据(高16位地址,低8位数据)
  14. output reg i2c_rh_wl, //I2C读写控制信号
  15. output reg init_done //初始化完成信号
  16. );
  17. //parameter define
  18. localparam REG_NUM = 8'd250; //总共需要配置的寄存器个数
  19. //reg define
  20. reg [14:0] start_init_cnt; //等待延时计数器
  21. reg [ 7:0] init_reg_cnt; //寄存器配置个数计数器
  22. //*****************************************************
  23. //** main code
  24. //*****************************************************
  25. SCL配置成250KHz,输入的clk时钟频率为1Mhz,周期为1us 20000*1us = 20ms
  26. //OV5640上电到开始配置SCCB至少等待20ms
  27. always @(posedge clk or negedge rst_n) begin
  28. if (!rst_n) start_init_cnt <= 1'b0;
  29. else if (start_init_cnt < 15'd20000) begin
  30. start_init_cnt <= start_init_cnt + 1'b1;
  31. end
  32. end
  33. //寄存器配置个数计数
  34. always @(posedge clk or negedge rst_n) begin
  35. if (!rst_n) init_reg_cnt <= 8'd0;
  36. else if (i2c_exec) init_reg_cnt <= init_reg_cnt + 8'b1;
  37. end
  38. //i2c触发执行信号
  39. always @(posedge clk or negedge rst_n) begin
  40. if (!rst_n) i2c_exec <= 1'b0;
  41. else if (start_init_cnt == 15'd20000 - 1'b1) i2c_exec <= 1'b1;
  42. else if (i2c_done && (init_reg_cnt < REG_NUM)) i2c_exec <= 1'b1;
  43. else i2c_exec <= 1'b0;
  44. end
  45. //配置I2C读写控制信号
  46. always @(posedge clk or negedge rst_n) begin
  47. if (!rst_n) i2c_rh_wl <= 1'b1;
  48. else if (init_reg_cnt == 8'd2) i2c_rh_wl <= 1'b0;
  49. end
  50. //初始化完成信号
  51. always @(posedge clk or negedge rst_n) begin
  52. if (!rst_n) init_done <= 1'b0;
  53. else if ((init_reg_cnt == REG_NUM) && i2c_done) init_done <= 1'b1;
  54. end
  55. //配置寄存器地址与数据
  56. always @(posedge clk or negedge rst_n) begin
  57. if (!rst_n) i2c_data <= 24'b0;
  58. else begin
  59. case (init_reg_cnt)
  60. //先读OV5640 ID
  61. 8'd0: i2c_data <= {16'h300a, 8'h0}; //
  62. 8'd1: i2c_data <= {16'h300b, 8'h0}; //
  63. 8'd2: i2c_data <= {16'h3008, 8'h82}; //Bit[7]:复位 Bit[6]:电源休眠
  64. 8'd3: i2c_data <= {16'h3008, 8'h02}; //正常工作模式
  65. 8'd4: i2c_data <= {16'h3103, 8'h02}; //Bit[1]:1 PLL Clock
  66. //引脚输入/输出控制 FREX/VSYNC/HREF/PCLK/D[9:6]
  67. 8'd5: i2c_data <= {8'h30, 8'h17, 8'hff};
  68. //引脚输入/输出控制 D[5:0]/GPIO1/GPIO0
  69. 8'd6: i2c_data <= {16'h3018, 8'hff};
  70. 8'd7: i2c_data <= {16'h3037, 8'h13}; //PLL分频控制
  71. 8'd8: i2c_data <= {16'h3108, 8'h01}; //系统根分频器
  72. 8'd9: i2c_data <= {16'h3630, 8'h36};
  73. 8'd10: i2c_data <= {16'h3631, 8'h0e};
  74. 8'd11: i2c_data <= {16'h3632, 8'he2};
  75. 8'd12: i2c_data <= {16'h3633, 8'h12};
  76. 8'd13: i2c_data <= {16'h3621, 8'he0};
  77. 8'd14: i2c_data <= {16'h3704, 8'ha0};
  78. 8'd15: i2c_data <= {16'h3703, 8'h5a};
  79. 8'd16: i2c_data <= {16'h3715, 8'h78};
  80. 8'd17: i2c_data <= {16'h3717, 8'h01};
  81. 8'd18: i2c_data <= {16'h370b, 8'h60};
  82. 8'd19: i2c_data <= {16'h3705, 8'h1a};
  83. 8'd20: i2c_data <= {16'h3905, 8'h02};
  84. 8'd21: i2c_data <= {16'h3906, 8'h10};
  85. 8'd22: i2c_data <= {16'h3901, 8'h0a};
  86. 8'd23: i2c_data <= {16'h3731, 8'h12};
  87. 8'd24: i2c_data <= {16'h3600, 8'h08}; //VCM控制,用于自动聚焦
  88. 8'd25: i2c_data <= {16'h3601, 8'h33}; //VCM控制,用于自动聚焦
  89. 8'd26: i2c_data <= {16'h302d, 8'h60}; //系统控制
  90. 8'd27: i2c_data <= {16'h3620, 8'h52};
  91. 8'd28: i2c_data <= {16'h371b, 8'h20};
  92. 8'd29: i2c_data <= {16'h471c, 8'h50};
  93. 8'd30: i2c_data <= {16'h3a13, 8'h43}; //AEC(自动曝光控制)
  94. 8'd31: i2c_data <= {16'h3a18, 8'h00}; //AEC 增益上限
  95. 8'd32: i2c_data <= {16'h3a19, 8'hf8}; //AEC 增益上限
  96. 8'd33: i2c_data <= {16'h3635, 8'h13};
  97. 8'd34: i2c_data <= {16'h3636, 8'h03};
  98. 8'd35: i2c_data <= {16'h3634, 8'h40};
  99. 8'd36: i2c_data <= {16'h3622, 8'h01};
  100. 8'd37: i2c_data <= {16'h3c01, 8'h34};
  101. 8'd38: i2c_data <= {16'h3c04, 8'h28};
  102. 8'd39: i2c_data <= {16'h3c05, 8'h98};
  103. 8'd40: i2c_data <= {16'h3c06, 8'h00}; //light meter 1 阈值[15:8]
  104. 8'd41: i2c_data <= {16'h3c07, 8'h08}; //light meter 1 阈值[7:0]
  105. 8'd42: i2c_data <= {16'h3c08, 8'h00}; //light meter 2 阈值[15:8]
  106. 8'd43: i2c_data <= {16'h3c09, 8'h1c}; //light meter 2 阈值[7:0]
  107. 8'd44: i2c_data <= {16'h3c0a, 8'h9c}; //sample number[15:8]
  108. 8'd45: i2c_data <= {16'h3c0b, 8'h40}; //sample number[7:0]
  109. 8'd46: i2c_data <= {16'h3810, 8'h00}; //Timing Hoffset[11:8]
  110. 8'd47: i2c_data <= {16'h3811, 8'h10}; //Timing Hoffset[7:0]
  111. 8'd48: i2c_data <= {16'h3812, 8'h00}; //Timing Voffset[10:8]
  112. 8'd49: i2c_data <= {16'h3708, 8'h64};
  113. 8'd50: i2c_data <= {16'h4001, 8'h02}; //BLC(黑电平校准)补偿起始行号
  114. 8'd51: i2c_data <= {16'h4005, 8'h1a}; //BLC(黑电平校准)补偿始终更新
  115. 8'd52: i2c_data <= {16'h3000, 8'h00}; //系统块复位控制
  116. 8'd53: i2c_data <= {16'h3004, 8'hff}; //时钟使能控制
  117. 8'd54: i2c_data <= {16'h4300, 8'h61}; //格式控制 RGB565
  118. 8'd55: i2c_data <= {16'h501f, 8'h01}; //ISP RGB
  119. 8'd56: i2c_data <= {16'h440e, 8'h00};
  120. 8'd57: i2c_data <= {16'h5000, 8'ha7}; //ISP控制
  121. 8'd58: i2c_data <= {16'h3a0f, 8'h30}; //AEC控制;stable range in high
  122. 8'd59: i2c_data <= {16'h3a10, 8'h28}; //AEC控制;stable range in low
  123. 8'd60: i2c_data <= {16'h3a1b, 8'h30}; //AEC控制;stable range out high
  124. 8'd61: i2c_data <= {16'h3a1e, 8'h26}; //AEC控制;stable range out low
  125. 8'd62: i2c_data <= {16'h3a11, 8'h60}; //AEC控制; fast zone high
  126. 8'd63: i2c_data <= {16'h3a1f, 8'h14}; //AEC控制; fast zone low
  127. //LENC(镜头校正)控制 16'h5800~16'h583d
  128. 8'd64: i2c_data <= {16'h5800, 8'h23};
  129. 8'd65: i2c_data <= {16'h5801, 8'h14};
  130. 8'd66: i2c_data <= {16'h5802, 8'h0f};
  131. 8'd67: i2c_data <= {16'h5803, 8'h0f};
  132. 8'd68: i2c_data <= {16'h5804, 8'h12};
  133. 8'd69: i2c_data <= {16'h5805, 8'h26};
  134. 8'd70: i2c_data <= {16'h5806, 8'h0c};
  135. 8'd71: i2c_data <= {16'h5807, 8'h08};
  136. 8'd72: i2c_data <= {16'h5808, 8'h05};
  137. 8'd73: i2c_data <= {16'h5809, 8'h05};
  138. 8'd74: i2c_data <= {16'h580a, 8'h08};
  139. 8'd75: i2c_data <= {16'h580b, 8'h0d};
  140. 8'd76: i2c_data <= {16'h580c, 8'h08};
  141. 8'd77: i2c_data <= {16'h580d, 8'h03};
  142. 8'd78: i2c_data <= {16'h580e, 8'h00};
  143. 8'd79: i2c_data <= {16'h580f, 8'h00};
  144. 8'd80: i2c_data <= {16'h5810, 8'h03};
  145. 8'd81: i2c_data <= {16'h5811, 8'h09};
  146. 8'd82: i2c_data <= {16'h5812, 8'h07};
  147. 8'd83: i2c_data <= {16'h5813, 8'h03};
  148. 8'd84: i2c_data <= {16'h5814, 8'h00};
  149. 8'd85: i2c_data <= {16'h5815, 8'h01};
  150. 8'd86: i2c_data <= {16'h5816, 8'h03};
  151. 8'd87: i2c_data <= {16'h5817, 8'h08};
  152. 8'd88: i2c_data <= {16'h5818, 8'h0d};
  153. 8'd89: i2c_data <= {16'h5819, 8'h08};
  154. 8'd90: i2c_data <= {16'h581a, 8'h05};
  155. 8'd91: i2c_data <= {16'h581b, 8'h06};
  156. 8'd92: i2c_data <= {16'h581c, 8'h08};
  157. 8'd93: i2c_data <= {16'h581d, 8'h0e};
  158. 8'd94: i2c_data <= {16'h581e, 8'h29};
  159. 8'd95: i2c_data <= {16'h581f, 8'h17};
  160. 8'd96: i2c_data <= {16'h5820, 8'h11};
  161. 8'd97: i2c_data <= {16'h5821, 8'h11};
  162. 8'd98: i2c_data <= {16'h5822, 8'h15};
  163. 8'd99: i2c_data <= {16'h5823, 8'h28};
  164. 8'd100: i2c_data <= {16'h5824, 8'h46};
  165. 8'd101: i2c_data <= {16'h5825, 8'h26};
  166. 8'd102: i2c_data <= {16'h5826, 8'h08};
  167. 8'd103: i2c_data <= {16'h5827, 8'h26};
  168. 8'd104: i2c_data <= {16'h5828, 8'h64};
  169. 8'd105: i2c_data <= {16'h5829, 8'h26};
  170. 8'd106: i2c_data <= {16'h582a, 8'h24};
  171. 8'd107: i2c_data <= {16'h582b, 8'h22};
  172. 8'd108: i2c_data <= {16'h582c, 8'h24};
  173. 8'd109: i2c_data <= {16'h582d, 8'h24};
  174. 8'd110: i2c_data <= {16'h582e, 8'h06};
  175. 8'd111: i2c_data <= {16'h582f, 8'h22};
  176. 8'd112: i2c_data <= {16'h5830, 8'h40};
  177. 8'd113: i2c_data <= {16'h5831, 8'h42};
  178. 8'd114: i2c_data <= {16'h5832, 8'h24};
  179. 8'd115: i2c_data <= {16'h5833, 8'h26};
  180. 8'd116: i2c_data <= {16'h5834, 8'h24};
  181. 8'd117: i2c_data <= {16'h5835, 8'h22};
  182. 8'd118: i2c_data <= {16'h5836, 8'h22};
  183. 8'd119: i2c_data <= {16'h5837, 8'h26};
  184. 8'd120: i2c_data <= {16'h5838, 8'h44};
  185. 8'd121: i2c_data <= {16'h5839, 8'h24};
  186. 8'd122: i2c_data <= {16'h583a, 8'h26};
  187. 8'd123: i2c_data <= {16'h583b, 8'h28};
  188. 8'd124: i2c_data <= {16'h583c, 8'h42};
  189. 8'd125: i2c_data <= {16'h583d, 8'hce};
  190. //AWB(自动白平衡控制) 16'h5180~16'h519e
  191. 8'd126: i2c_data <= {16'h5180, 8'hff};
  192. 8'd127: i2c_data <= {16'h5181, 8'hf2};
  193. 8'd128: i2c_data <= {16'h5182, 8'h00};
  194. 8'd129: i2c_data <= {16'h5183, 8'h14};
  195. 8'd130: i2c_data <= {16'h5184, 8'h25};
  196. 8'd131: i2c_data <= {16'h5185, 8'h24};
  197. 8'd132: i2c_data <= {16'h5186, 8'h09};
  198. 8'd133: i2c_data <= {16'h5187, 8'h09};
  199. 8'd134: i2c_data <= {16'h5188, 8'h09};
  200. 8'd135: i2c_data <= {16'h5189, 8'h75};
  201. 8'd136: i2c_data <= {16'h518a, 8'h54};
  202. 8'd137: i2c_data <= {16'h518b, 8'he0};
  203. 8'd138: i2c_data <= {16'h518c, 8'hb2};
  204. 8'd139: i2c_data <= {16'h518d, 8'h42};
  205. 8'd140: i2c_data <= {16'h518e, 8'h3d};
  206. 8'd141: i2c_data <= {16'h518f, 8'h56};
  207. 8'd142: i2c_data <= {16'h5190, 8'h46};
  208. 8'd143: i2c_data <= {16'h5191, 8'hf8};
  209. 8'd144: i2c_data <= {16'h5192, 8'h04};
  210. 8'd145: i2c_data <= {16'h5193, 8'h70};
  211. 8'd146: i2c_data <= {16'h5194, 8'hf0};
  212. 8'd147: i2c_data <= {16'h5195, 8'hf0};
  213. 8'd148: i2c_data <= {16'h5196, 8'h03};
  214. 8'd149: i2c_data <= {16'h5197, 8'h01};
  215. 8'd150: i2c_data <= {16'h5198, 8'h04};
  216. 8'd151: i2c_data <= {16'h5199, 8'h12};
  217. 8'd152: i2c_data <= {16'h519a, 8'h04};
  218. 8'd153: i2c_data <= {16'h519b, 8'h00};
  219. 8'd154: i2c_data <= {16'h519c, 8'h06};
  220. 8'd155: i2c_data <= {16'h519d, 8'h82};
  221. 8'd156: i2c_data <= {16'h519e, 8'h38};
  222. //Gamma(伽马)控制 16'h5480~16'h5490
  223. 8'd157: i2c_data <= {16'h5480, 8'h01};
  224. 8'd158: i2c_data <= {16'h5481, 8'h08};
  225. 8'd159: i2c_data <= {16'h5482, 8'h14};
  226. 8'd160: i2c_data <= {16'h5483, 8'h28};
  227. 8'd161: i2c_data <= {16'h5484, 8'h51};
  228. 8'd162: i2c_data <= {16'h5485, 8'h65};
  229. 8'd163: i2c_data <= {16'h5486, 8'h71};
  230. 8'd164: i2c_data <= {16'h5487, 8'h7d};
  231. 8'd165: i2c_data <= {16'h5488, 8'h87};
  232. 8'd166: i2c_data <= {16'h5489, 8'h91};
  233. 8'd167: i2c_data <= {16'h548a, 8'h9a};
  234. 8'd168: i2c_data <= {16'h548b, 8'haa};
  235. 8'd169: i2c_data <= {16'h548c, 8'hb8};
  236. 8'd170: i2c_data <= {16'h548d, 8'hcd};
  237. 8'd171: i2c_data <= {16'h548e, 8'hdd};
  238. 8'd172: i2c_data <= {16'h548f, 8'hea};
  239. 8'd173: i2c_data <= {16'h5490, 8'h1d};
  240. //CMX(彩色矩阵控制) 16'h5381~16'h538b
  241. 8'd174: i2c_data <= {16'h5381, 8'h1e};
  242. 8'd175: i2c_data <= {16'h5382, 8'h5b};
  243. 8'd176: i2c_data <= {16'h5383, 8'h08};
  244. 8'd177: i2c_data <= {16'h5384, 8'h0a};
  245. 8'd178: i2c_data <= {16'h5385, 8'h7e};
  246. 8'd179: i2c_data <= {16'h5386, 8'h88};
  247. 8'd180: i2c_data <= {16'h5387, 8'h7c};
  248. 8'd181: i2c_data <= {16'h5388, 8'h6c};
  249. 8'd182: i2c_data <= {16'h5389, 8'h10};
  250. 8'd183: i2c_data <= {16'h538a, 8'h01};
  251. 8'd184: i2c_data <= {16'h538b, 8'h98};
  252. //SDE(特殊数码效果)控制 16'h5580~16'h558b
  253. 8'd185: i2c_data <= {16'h5580, 8'h06};
  254. 8'd186: i2c_data <= {16'h5583, 8'h40};
  255. 8'd187: i2c_data <= {16'h5584, 8'h10};
  256. 8'd188: i2c_data <= {16'h5589, 8'h10};
  257. 8'd189: i2c_data <= {16'h558a, 8'h00};
  258. 8'd190: i2c_data <= {16'h558b, 8'hf8};
  259. 8'd191: i2c_data <= {16'h501d, 8'h40}; //ISP MISC
  260. //CIP(颜色插值)控制 (16'h5300~16'h530c)
  261. 8'd192: i2c_data <= {16'h5300, 8'h08};
  262. 8'd193: i2c_data <= {16'h5301, 8'h30};
  263. 8'd194: i2c_data <= {16'h5302, 8'h10};
  264. 8'd195: i2c_data <= {16'h5303, 8'h00};
  265. 8'd196: i2c_data <= {16'h5304, 8'h08};
  266. 8'd197: i2c_data <= {16'h5305, 8'h30};
  267. 8'd198: i2c_data <= {16'h5306, 8'h08};
  268. 8'd199: i2c_data <= {16'h5307, 8'h16};
  269. 8'd200: i2c_data <= {16'h5309, 8'h08};
  270. 8'd201: i2c_data <= {16'h530a, 8'h30};
  271. 8'd202: i2c_data <= {16'h530b, 8'h04};
  272. 8'd203: i2c_data <= {16'h530c, 8'h06};
  273. 8'd204: i2c_data <= {16'h5025, 8'h00};
  274. //系统时钟分频 Bit[7:4]:系统时钟分频 input clock =24Mhz, PCLK = 48Mhz
  275. 8'd205: i2c_data <= {16'h3035, 8'h11};
  276. 8'd206: i2c_data <= {16'h3036, 8'h3c}; //PLL倍频
  277. 8'd207: i2c_data <= {16'h3c07, 8'h08};
  278. //时序控制 16'h3800~16'h3821
  279. 8'd208: i2c_data <= {16'h3820, 8'h46};
  280. 8'd209: i2c_data <= {16'h3821, 8'h01};
  281. 8'd210: i2c_data <= {16'h3814, 8'h31};
  282. 8'd211: i2c_data <= {16'h3815, 8'h31};
  283. 8'd212: i2c_data <= {16'h3800, 8'h00};
  284. 8'd213: i2c_data <= {16'h3801, 8'h00};
  285. 8'd214: i2c_data <= {16'h3802, 8'h00};
  286. 8'd215: i2c_data <= {16'h3803, 8'h04};
  287. 8'd216: i2c_data <= {16'h3804, 8'h0a};
  288. 8'd217: i2c_data <= {16'h3805, 8'h3f};
  289. 8'd218: i2c_data <= {16'h3806, 8'h07};
  290. 8'd219: i2c_data <= {16'h3807, 8'h9b};
  291. //设置输出像素个数
  292. //DVP 输出水平像素点数高4位
  293. 8'd220: i2c_data <= {16'h3808, {4'd0, cmos_h_pixel[11:8]}};
  294. //DVP 输出水平像素点数低8
  295. 8'd221: i2c_data <= {16'h3809, cmos_h_pixel[7:0]};
  296. //DVP 输出垂直像素点数高3
  297. 8'd222: i2c_data <= {16'h380a, {5'd0, cmos_v_pixel[10:8]}};
  298. //DVP 输出垂直像素点数低8位
  299. 8'd223: i2c_data <= {16'h380b, cmos_v_pixel[7:0]};
  300. //水平总像素大小高5位
  301. 8'd224: i2c_data <= {16'h380c, {3'd0, total_h_pixel[12:8]}};
  302. //水平总像素大小低8
  303. 8'd225: i2c_data <= {16'h380d, total_h_pixel[7:0]};
  304. //垂直总像素大小高5
  305. 8'd226: i2c_data <= {16'h380e, {3'd0, total_v_pixel[12:8]}};
  306. //垂直总像素大小低8位
  307. 8'd227: i2c_data <= {16'h380f, total_v_pixel[7:0]};
  308. 8'd228: i2c_data <= {16'h3813, 8'h06};
  309. 8'd229: i2c_data <= {16'h3618, 8'h00};
  310. 8'd230: i2c_data <= {16'h3612, 8'h29};
  311. 8'd231: i2c_data <= {16'h3709, 8'h52};
  312. 8'd232: i2c_data <= {16'h370c, 8'h03};
  313. 8'd233: i2c_data <= {16'h3a02, 8'h17}; //60Hz max exposure
  314. 8'd234: i2c_data <= {16'h3a03, 8'h10}; //60Hz max exposure
  315. 8'd235: i2c_data <= {16'h3a14, 8'h17}; //50Hz max exposure
  316. 8'd236: i2c_data <= {16'h3a15, 8'h10}; //50Hz max exposure
  317. 8'd237: i2c_data <= {16'h4004, 8'h02}; //BLC(背光) 2 lines
  318. 8'd238: i2c_data <= {16'h4713, 8'h03}; //JPEG mode 3
  319. 8'd239: i2c_data <= {16'h4407, 8'h04}; //量化标度
  320. 8'd240: i2c_data <= {16'h460c, 8'h22};
  321. 8'd241: i2c_data <= {16'h4837, 8'h22}; //DVP CLK divider
  322. 8'd242: i2c_data <= {16'h3824, 8'h02}; //DVP CLK divider
  323. 8'd243: i2c_data <= {16'h5001, 8'ha3}; //ISP 控制
  324. 8'd244: i2c_data <= {16'h3b07, 8'h0a}; //帧曝光模式
  325. //彩条测试使能
  326. 8'd245: i2c_data <= {16'h503d, 8'h00}; //8'h00:正常模式 8'h80:彩条显示
  327. //测试闪光灯功能
  328. 8'd246: i2c_data <= {16'h3016, 8'h02};
  329. 8'd247: i2c_data <= {16'h301c, 8'h02};
  330. 8'd248: i2c_data <= {16'h3019, 8'h02}; //打开闪光灯
  331. 8'd249: i2c_data <= {16'h3019, 8'h00}; //关闭闪光灯
  332. //只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写
  333. default: i2c_data <= {16'h300a, 8'h00}; //器件ID高8位
  334. endcase
  335. end
  336. end
  337. endmodule

3.3 iic驱动模块

  1. `timescale 1ns / 1ps
  2. //IIC驱动模块
  3. module i2c_dri #(
  4. parameter SLAVE_ADDR = 7'b1010000 , //EEPROM从机地址
  5. parameter CLK_FREQ = 26'd50_000_000, //模块输入的时钟频率
  6. parameter I2C_FREQ = 18'd250_000 //IIC_SCL的时钟频率
  7. ) (
  8. input clk,
  9. input rst_n,
  10. //i2c interface
  11. input i2c_exec, //I2C触发执行信号
  12. input bit_ctrl, //字地址位控制(16b/8b)
  13. input i2c_rh_wl, //I2C读写控制信号
  14. input [15:0] i2c_addr, //I2C器件内地址
  15. input [ 7:0] i2c_data_w, //I2C要写的数据
  16. output reg [ 7:0] i2c_data_r, //I2C读出的数据
  17. output reg i2c_done, //I2C一次操作完成
  18. output reg i2c_ack, //I2C应答标志 0:应答 1:未应答
  19. output reg scl, //I2C的SCL时钟信号
  20. inout sda, //I2C的SDA信号
  21. //user interface
  22. output reg dri_clk //驱动I2C操作的驱动时钟
  23. );
  24. //localparam define
  25. localparam st_idle = 8'b0000_0001; //空闲状态
  26. localparam st_sladdr = 8'b0000_0010; //发送器件地址(slave address)
  27. localparam st_addr16 = 8'b0000_0100; //发送16位字地址
  28. localparam st_addr8 = 8'b0000_1000; //发送8位字地址
  29. localparam st_data_wr = 8'b0001_0000; //写数据(8 bit)
  30. localparam st_addr_rd = 8'b0010_0000; //发送器件地址读
  31. localparam st_data_rd = 8'b0100_0000; //读数据(8 bit)
  32. localparam st_stop = 8'b1000_0000; //结束I2C操作
  33. //reg define
  34. reg sda_dir; //I2C数据(SDA)方向控制
  35. reg sda_out; //SDA输出信号
  36. reg st_done; //状态结束
  37. reg wr_flag; //写标志
  38. reg [ 6:0] cnt; //计数
  39. reg [ 7:0] cur_state; //状态机当前状态
  40. reg [ 7:0] next_state; //状态机下一状态
  41. reg [15:0] addr_t; //地址
  42. reg [ 7:0] data_r; //读取的数据
  43. reg [ 7:0] data_wr_t; //I2C需写的数据的临时寄存
  44. reg [ 9:0] clk_cnt; //分频时钟计数
  45. //wire define
  46. wire sda_in; //SDA输入信号
  47. wire [ 8:0] clk_divide; //模块驱动时钟的分频系数
  48. //*****************************************************
  49. //** main code
  50. //*****************************************************
  51. //SDA控制
  52. assign sda = sda_dir ? sda_out : 1'bz; //SDA数据输出或高阻
  53. assign sda_in = sda; //SDA数据输入
  54. assign clk_divide = (CLK_FREQ / I2C_FREQ) >> 2'd2; //模块驱动时钟的分频系数
  55. //生成I2C的SCL的四倍频率的驱动时钟用于驱动i2c的操作
  56. always @(posedge clk or negedge rst_n) begin
  57. if (!rst_n) begin
  58. dri_clk <= 1'b0;
  59. clk_cnt <= 10'd0;
  60. end else if (clk_cnt == clk_divide[8:1] - 1'd1) begin
  61. clk_cnt <= 10'd0;
  62. dri_clk <= ~dri_clk;
  63. end else clk_cnt <= clk_cnt + 1'b1;
  64. end
  65. //(三段式状态机)同步时序描述状态转移
  66. always @(posedge dri_clk or negedge rst_n) begin
  67. if (!rst_n) cur_state <= st_idle;
  68. else cur_state <= next_state;
  69. end
  70. //组合逻辑判断状态转移条件
  71. always @(*) begin
  72. next_state = st_idle;
  73. case (cur_state)
  74. st_idle: begin //空闲状态
  75. if (i2c_exec) begin
  76. next_state = st_sladdr;
  77. end else next_state = st_idle;
  78. end
  79. st_sladdr: begin
  80. if (st_done) begin
  81. if (bit_ctrl) //判断是16位还是8位字地址
  82. next_state = st_addr16;
  83. else next_state = st_addr8;
  84. end else next_state = st_sladdr;
  85. end
  86. st_addr16: begin //写16位字地址
  87. if (st_done) begin
  88. next_state = st_addr8;
  89. end else begin
  90. next_state = st_addr16;
  91. end
  92. end
  93. st_addr8: begin //8位字地址
  94. if (st_done) begin
  95. if (wr_flag == 1'b0) //读写判断
  96. next_state = st_data_wr;
  97. else next_state = st_addr_rd;
  98. end else begin
  99. next_state = st_addr8;
  100. end
  101. end
  102. st_data_wr: begin //写数据(8 bit)
  103. if (st_done) next_state = st_stop;
  104. else next_state = st_data_wr;
  105. end
  106. st_addr_rd: begin //写地址以进行读数据
  107. if (st_done) begin
  108. next_state = st_data_rd;
  109. end else begin
  110. next_state = st_addr_rd;
  111. end
  112. end
  113. st_data_rd: begin //读取数据(8 bit)
  114. if (st_done) next_state = st_stop;
  115. else next_state = st_data_rd;
  116. end
  117. st_stop: begin //结束I2C操作
  118. if (st_done) next_state = st_idle;
  119. else next_state = st_stop;
  120. end
  121. default: next_state = st_idle;
  122. endcase
  123. end
  124. //时序电路描述状态输出
  125. always @(posedge dri_clk or negedge rst_n) begin
  126. //复位初始化
  127. if (!rst_n) begin
  128. scl <= 1'b1;
  129. sda_out <= 1'b1;
  130. sda_dir <= 1'b1;
  131. i2c_done <= 1'b0;
  132. i2c_ack <= 1'b0;
  133. cnt <= 1'b0;
  134. st_done <= 1'b0;
  135. data_r <= 1'b0;
  136. i2c_data_r <= 1'b0;
  137. wr_flag <= 1'b0;
  138. addr_t <= 1'b0;
  139. data_wr_t <= 1'b0;
  140. end else begin
  141. st_done <= 1'b0;
  142. cnt <= cnt + 1'b1;
  143. case (cur_state)
  144. st_idle: begin //空闲状态
  145. scl <= 1'b1;
  146. sda_out <= 1'b1;
  147. sda_dir <= 1'b1;
  148. i2c_done <= 1'b0;
  149. cnt <= 7'b0;
  150. if (i2c_exec) begin
  151. wr_flag <= i2c_rh_wl ;
  152. addr_t <= i2c_addr ;
  153. data_wr_t <= i2c_data_w;
  154. i2c_ack <= 1'b0;
  155. end
  156. end
  157. st_sladdr: begin //写地址(器件地址和字地址)
  158. case (cnt)
  159. 7'd1: sda_out <= 1'b0; //开始I2C
  160. 7'd3: scl <= 1'b0;
  161. 7'd4: sda_out <= SLAVE_ADDR[6]; //传送器件地址
  162. 7'd5: scl <= 1'b1;
  163. 7'd7: scl <= 1'b0;
  164. 7'd8: sda_out <= SLAVE_ADDR[5];
  165. 7'd9: scl <= 1'b1;
  166. 7'd11: scl <= 1'b0;
  167. 7'd12: sda_out <= SLAVE_ADDR[4];
  168. 7'd13: scl <= 1'b1;
  169. 7'd15: scl <= 1'b0;
  170. 7'd16: sda_out <= SLAVE_ADDR[3];
  171. 7'd17: scl <= 1'b1;
  172. 7'd19: scl <= 1'b0;
  173. 7'd20: sda_out <= SLAVE_ADDR[2];
  174. 7'd21: scl <= 1'b1;
  175. 7'd23: scl <= 1'b0;
  176. 7'd24: sda_out <= SLAVE_ADDR[1];
  177. 7'd25: scl <= 1'b1;
  178. 7'd27: scl <= 1'b0;
  179. 7'd28: sda_out <= SLAVE_ADDR[0];
  180. 7'd29: scl <= 1'b1;
  181. 7'd31: scl <= 1'b0;
  182. 7'd32: sda_out <= 1'b0; //0:写
  183. 7'd33: scl <= 1'b1;
  184. 7'd35: scl <= 1'b0;
  185. 7'd36: begin
  186. sda_dir <= 1'b0;
  187. sda_out <= 1'b1;
  188. end
  189. 7'd37: scl <= 1'b1;
  190. 7'd38: begin //从机应答
  191. st_done <= 1'b1;
  192. if (sda_in == 1'b1) //高电平表示未应答
  193. i2c_ack <= 1'b1; //拉高应答标志位
  194. end
  195. 7'd39: begin
  196. scl <= 1'b0;
  197. cnt <= 1'b0;
  198. end
  199. default: ;
  200. endcase
  201. end
  202. st_addr16: begin
  203. case (cnt)
  204. 7'd0: begin
  205. sda_dir <= 1'b1;
  206. sda_out <= addr_t[15]; //传送字地址
  207. end
  208. 7'd1: scl <= 1'b1;
  209. 7'd3: scl <= 1'b0;
  210. 7'd4: sda_out <= addr_t[14];
  211. 7'd5: scl <= 1'b1;
  212. 7'd7: scl <= 1'b0;
  213. 7'd8: sda_out <= addr_t[13];
  214. 7'd9: scl <= 1'b1;
  215. 7'd11: scl <= 1'b0;
  216. 7'd12: sda_out <= addr_t[12];
  217. 7'd13: scl <= 1'b1;
  218. 7'd15: scl <= 1'b0;
  219. 7'd16: sda_out <= addr_t[11];
  220. 7'd17: scl <= 1'b1;
  221. 7'd19: scl <= 1'b0;
  222. 7'd20: sda_out <= addr_t[10];
  223. 7'd21: scl <= 1'b1;
  224. 7'd23: scl <= 1'b0;
  225. 7'd24: sda_out <= addr_t[9];
  226. 7'd25: scl <= 1'b1;
  227. 7'd27: scl <= 1'b0;
  228. 7'd28: sda_out <= addr_t[8];
  229. 7'd29: scl <= 1'b1;
  230. 7'd31: scl <= 1'b0;
  231. 7'd32: begin
  232. sda_dir <= 1'b0;
  233. sda_out <= 1'b1;
  234. end
  235. 7'd33: scl <= 1'b1;
  236. 7'd34: begin //从机应答
  237. st_done <= 1'b1;
  238. if (sda_in == 1'b1) //高电平表示未应答
  239. i2c_ack <= 1'b1; //拉高应答标志位
  240. end
  241. 7'd35: begin
  242. scl <= 1'b0;
  243. cnt <= 1'b0;
  244. end
  245. default: ;
  246. endcase
  247. end
  248. st_addr8: begin
  249. case (cnt)
  250. 7'd0: begin
  251. sda_dir <= 1'b1;
  252. sda_out <= addr_t[7]; //字地址
  253. end
  254. 7'd1: scl <= 1'b1;
  255. 7'd3: scl <= 1'b0;
  256. 7'd4: sda_out <= addr_t[6];
  257. 7'd5: scl <= 1'b1;
  258. 7'd7: scl <= 1'b0;
  259. 7'd8: sda_out <= addr_t[5];
  260. 7'd9: scl <= 1'b1;
  261. 7'd11: scl <= 1'b0;
  262. 7'd12: sda_out <= addr_t[4];
  263. 7'd13: scl <= 1'b1;
  264. 7'd15: scl <= 1'b0;
  265. 7'd16: sda_out <= addr_t[3];
  266. 7'd17: scl <= 1'b1;
  267. 7'd19: scl <= 1'b0;
  268. 7'd20: sda_out <= addr_t[2];
  269. 7'd21: scl <= 1'b1;
  270. 7'd23: scl <= 1'b0;
  271. 7'd24: sda_out <= addr_t[1];
  272. 7'd25: scl <= 1'b1;
  273. 7'd27: scl <= 1'b0;
  274. 7'd28: sda_out <= addr_t[0];
  275. 7'd29: scl <= 1'b1;
  276. 7'd31: scl <= 1'b0;
  277. 7'd32: begin
  278. sda_dir <= 1'b0;
  279. sda_out <= 1'b1;
  280. end
  281. 7'd33: scl <= 1'b1;
  282. 7'd34: begin //从机应答
  283. st_done <= 1'b1;
  284. if (sda_in == 1'b1) //高电平表示未应答
  285. i2c_ack <= 1'b1; //拉高应答标志位
  286. end
  287. 7'd35: begin
  288. scl <= 1'b0;
  289. cnt <= 1'b0;
  290. end
  291. default: ;
  292. endcase
  293. end
  294. st_data_wr: begin //写数据(8 bit)
  295. case (cnt)
  296. 7'd0: begin
  297. sda_out <= data_wr_t[7]; //I2C写8位数据
  298. sda_dir <= 1'b1;
  299. end
  300. 7'd1: scl <= 1'b1;
  301. 7'd3: scl <= 1'b0;
  302. 7'd4: sda_out <= data_wr_t[6];
  303. 7'd5: scl <= 1'b1;
  304. 7'd7: scl <= 1'b0;
  305. 7'd8: sda_out <= data_wr_t[5];
  306. 7'd9: scl <= 1'b1;
  307. 7'd11: scl <= 1'b0;
  308. 7'd12: sda_out <= data_wr_t[4];
  309. 7'd13: scl <= 1'b1;
  310. 7'd15: scl <= 1'b0;
  311. 7'd16: sda_out <= data_wr_t[3];
  312. 7'd17: scl <= 1'b1;
  313. 7'd19: scl <= 1'b0;
  314. 7'd20: sda_out <= data_wr_t[2];
  315. 7'd21: scl <= 1'b1;
  316. 7'd23: scl <= 1'b0;
  317. 7'd24: sda_out <= data_wr_t[1];
  318. 7'd25: scl <= 1'b1;
  319. 7'd27: scl <= 1'b0;
  320. 7'd28: sda_out <= data_wr_t[0];
  321. 7'd29: scl <= 1'b1;
  322. 7'd31: scl <= 1'b0;
  323. 7'd32: begin
  324. sda_dir <= 1'b0;
  325. sda_out <= 1'b1;
  326. end
  327. 7'd33: scl <= 1'b1;
  328. 7'd34: begin //从机应答
  329. st_done <= 1'b1;
  330. if (sda_in == 1'b1) //高电平表示未应答
  331. i2c_ack <= 1'b1; //拉高应答标志位
  332. end
  333. 7'd35: begin
  334. scl <= 1'b0;
  335. cnt <= 1'b0;
  336. end
  337. default: ;
  338. endcase
  339. end
  340. st_addr_rd: begin //写地址以进行读数据
  341. case (cnt)
  342. 7'd0: begin
  343. sda_dir <= 1'b1;
  344. sda_out <= 1'b1;
  345. end
  346. 7'd1: scl <= 1'b1;
  347. 7'd2: sda_out <= 1'b0; //重新开始
  348. 7'd3: scl <= 1'b0;
  349. 7'd4: sda_out <= SLAVE_ADDR[6]; //传送器件地址
  350. 7'd5: scl <= 1'b1;
  351. 7'd7: scl <= 1'b0;
  352. 7'd8: sda_out <= SLAVE_ADDR[5];
  353. 7'd9: scl <= 1'b1;
  354. 7'd11: scl <= 1'b0;
  355. 7'd12: sda_out <= SLAVE_ADDR[4];
  356. 7'd13: scl <= 1'b1;
  357. 7'd15: scl <= 1'b0;
  358. 7'd16: sda_out <= SLAVE_ADDR[3];
  359. 7'd17: scl <= 1'b1;
  360. 7'd19: scl <= 1'b0;
  361. 7'd20: sda_out <= SLAVE_ADDR[2];
  362. 7'd21: scl <= 1'b1;
  363. 7'd23: scl <= 1'b0;
  364. 7'd24: sda_out <= SLAVE_ADDR[1];
  365. 7'd25: scl <= 1'b1;
  366. 7'd27: scl <= 1'b0;
  367. 7'd28: sda_out <= SLAVE_ADDR[0];
  368. 7'd29: scl <= 1'b1;
  369. 7'd31: scl <= 1'b0;
  370. 7'd32: sda_out <= 1'b1; //1:读
  371. 7'd33: scl <= 1'b1;
  372. 7'd35: scl <= 1'b0;
  373. 7'd36: begin
  374. sda_dir <= 1'b0;
  375. sda_out <= 1'b1;
  376. end
  377. 7'd37: scl <= 1'b1;
  378. 7'd38: begin //从机应答
  379. st_done <= 1'b1;
  380. if (sda_in == 1'b1) //高电平表示未应答
  381. i2c_ack <= 1'b1; //拉高应答标志位
  382. end
  383. 7'd39: begin
  384. scl <= 1'b0;
  385. cnt <= 1'b0;
  386. end
  387. default: ;
  388. endcase
  389. end
  390. st_data_rd: begin //读取数据(8 bit)
  391. case (cnt)
  392. 7'd0: sda_dir <= 1'b0;
  393. 7'd1: begin
  394. data_r[7] <= sda_in;
  395. scl <= 1'b1;
  396. end
  397. 7'd3: scl <= 1'b0;
  398. 7'd5: begin
  399. data_r[6] <= sda_in;
  400. scl <= 1'b1;
  401. end
  402. 7'd7: scl <= 1'b0;
  403. 7'd9: begin
  404. data_r[5] <= sda_in;
  405. scl <= 1'b1;
  406. end
  407. 7'd11: scl <= 1'b0;
  408. 7'd13: begin
  409. data_r[4] <= sda_in;
  410. scl <= 1'b1;
  411. end
  412. 7'd15: scl <= 1'b0;
  413. 7'd17: begin
  414. data_r[3] <= sda_in;
  415. scl <= 1'b1;
  416. end
  417. 7'd19: scl <= 1'b0;
  418. 7'd21: begin
  419. data_r[2] <= sda_in;
  420. scl <= 1'b1;
  421. end
  422. 7'd23: scl <= 1'b0;
  423. 7'd25: begin
  424. data_r[1] <= sda_in;
  425. scl <= 1'b1;
  426. end
  427. 7'd27: scl <= 1'b0;
  428. 7'd29: begin
  429. data_r[0] <= sda_in;
  430. scl <= 1'b1;
  431. end
  432. 7'd31: scl <= 1'b0;
  433. 7'd32: begin
  434. sda_dir <= 1'b1;
  435. sda_out <= 1'b1;
  436. end
  437. 7'd33: scl <= 1'b1;
  438. 7'd34: st_done <= 1'b1; //非应答
  439. 7'd35: begin
  440. scl <= 1'b0;
  441. cnt <= 1'b0;
  442. i2c_data_r <= data_r;
  443. end
  444. default: ;
  445. endcase
  446. end
  447. st_stop: begin //结束I2C操作
  448. case (cnt)
  449. 7'd0: begin
  450. sda_dir <= 1'b1; //结束I2C
  451. sda_out <= 1'b0;
  452. end
  453. 7'd1: scl <= 1'b1;
  454. 7'd3: sda_out <= 1'b1;
  455. 7'd15: st_done <= 1'b1;
  456. 7'd16: begin
  457. cnt <= 1'b0;
  458. i2c_done <= 1'b1; //向上层模块传递I2C结束信号
  459. end
  460. default: ;
  461. endcase
  462. end
  463. endcase
  464. end
  465. end
  466. endmodule

3.4 摄像头数据采集模块

  1. `timescale 1ns / 1ps
  2. //摄像头数据采集模块
  3. module cmos_capture_data (
  4. input rst_n, //复位信号
  5. //摄像头接口
  6. input cam_pclk, //cmos 数据像素时钟
  7. input cam_vsync, //cmos 场同步信号
  8. input cam_href, //cmos 行同步信号
  9. input [ 7:0] cam_data,
  10. //用户接口
  11. output cmos_frame_vsync, //帧有效信号
  12. output cmos_frame_href, //行有效信号
  13. output cmos_frame_valid, //数据有效使能信号
  14. output [15:0] cmos_frame_data //有效数据
  15. );
  16. //寄存器全部配置完成后,先等待10帧数据
  17. //待寄存器配置生效后再开始采集图像
  18. parameter WAIT_FRAME = 4'd10; //寄存器数据稳定等待的帧个数
  19. //reg define
  20. reg cam_vsync_d0;
  21. reg cam_vsync_d1;
  22. reg cam_href_d0;
  23. reg cam_href_d1;
  24. reg [ 3:0] cmos_ps_cnt; //等待帧数稳定计数器
  25. reg [ 7:0] cam_data_d0;
  26. reg [15:0] cmos_data_t; //用于8位转16位的临时寄存器
  27. reg byte_flag; //16位RGB数据转换完成的标志信号
  28. reg byte_flag_d0;
  29. reg frame_val_flag; //帧有效的标志
  30. wire pos_vsync; //采输入场同步信号的上升沿
  31. //*****************************************************
  32. //** main code
  33. //*****************************************************
  34. //采输入场同步信号的上升沿
  35. assign pos_vsync = (~cam_vsync_d1) & cam_vsync_d0;
  36. //输出帧有效信号
  37. assign cmos_frame_vsync = frame_val_flag ? cam_vsync_d1 : 1'b0;
  38. //输出行有效信号
  39. assign cmos_frame_href = frame_val_flag ? cam_href_d1 : 1'b0;
  40. //输出数据使能有效信号
  41. assign cmos_frame_valid = frame_val_flag ? byte_flag_d0 : 1'b0;
  42. //输出数据
  43. assign cmos_frame_data = frame_val_flag ? cmos_data_t : 1'b0;
  44. always @(posedge cam_pclk or negedge rst_n) begin
  45. if (!rst_n) begin
  46. cam_vsync_d0 <= 1'b0;
  47. cam_vsync_d1 <= 1'b0;
  48. cam_href_d0 <= 1'b0;
  49. cam_href_d1 <= 1'b0;
  50. end else begin
  51. cam_vsync_d0 <= cam_vsync;
  52. cam_vsync_d1 <= cam_vsync_d0;
  53. cam_href_d0 <= cam_href;
  54. cam_href_d1 <= cam_href_d0;
  55. end
  56. end
  57. //对帧数进行计数
  58. always @(posedge cam_pclk or negedge rst_n) begin
  59. if (!rst_n) cmos_ps_cnt <= 4'd0;
  60. else if (pos_vsync && (cmos_ps_cnt < WAIT_FRAME)) cmos_ps_cnt <= cmos_ps_cnt + 4'd1;
  61. end
  62. //帧有效标志
  63. always @(posedge cam_pclk or negedge rst_n) begin
  64. if (!rst_n) frame_val_flag <= 1'b0;
  65. else if ((cmos_ps_cnt == WAIT_FRAME) && pos_vsync) frame_val_flag <= 1'b1;
  66. else;
  67. end
  68. //8位数据转16位RGB565数据
  69. always @(posedge cam_pclk or negedge rst_n) begin
  70. if (!rst_n) begin
  71. cmos_data_t <= 16'd0;
  72. cam_data_d0 <= 8'd0;
  73. byte_flag <= 1'b0;
  74. end else if (cam_href) begin
  75. byte_flag <= ~byte_flag;
  76. cam_data_d0 <= cam_data;
  77. if (byte_flag) cmos_data_t <= {cam_data_d0, cam_data};
  78. else;
  79. end else begin
  80. byte_flag <= 1'b0;
  81. cam_data_d0 <= 8'b0;
  82. end
  83. end
  84. //产生输出数据有效信号(cmos_frame_valid)
  85. always @(posedge cam_pclk or negedge rst_n) begin
  86. if (!rst_n) byte_flag_d0 <= 1'b0;
  87. else byte_flag_d0 <= byte_flag;
  88. end
  89. endmodule

3.5 图像开始传输控制模块

  1. `timescale 1ns / 1ps
  2. //图像开始传输控制模块
  3. module start_transfer_ctrl (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input udp_rec_pkt_done, //GMII接收时钟
  7. input udp_rec_en, //UDP单包数据接收完成信号
  8. input [31:0] udp_rec_data, //UDP接收的数据使能信号
  9. input [15:0] udp_rec_byte_num, //UDP接收的数据
  10. //UDP接收到的字节数
  11. output reg transfer_flag //图像开始传输标志,0:开始传输 1:停止传输
  12. );
  13. //parameter define
  14. parameter START = "1"; //开始命令
  15. parameter STOP = "0"; //停止命令
  16. //*****************************************************
  17. //** main code
  18. //*****************************************************
  19. //解析接收到的数据
  20. always @(posedge clk or negedge rst_n) begin
  21. if (!rst_n) transfer_flag <= 1'b0;
  22. else if (udp_rec_pkt_done && udp_rec_byte_num == 1'b1) begin
  23. if (udp_rec_data[31:24] == START) //开始传输
  24. transfer_flag <= 1'b1;
  25. else if (udp_rec_data[31:24] == STOP) //停止传输
  26. transfer_flag <= 1'b0;
  27. end
  28. end
  29. endmodule

3.6 图像封装模块

  1. `timescale 1ns / 1ps
  2. //图像封装模块(添加帧头)
  3. module img_data_pkt (
  4. input rst_n, //复位信号,低电平有效
  5. //图像相关信号
  6. input cam_pclk, //像素时钟
  7. input img_vsync, //帧同步信号
  8. input img_data_en, //数据有效使能信号
  9. input [15:0] img_data, //有效数据
  10. input transfer_flag, //图像开始传输标志,0:开始传输 1:停止传输
  11. //以太网相关信号
  12. input eth_tx_clk, //以太网发送时钟
  13. input udp_tx_req, //udp发送数据请求信号
  14. input udp_tx_done, //udp发送数据完成信号
  15. output reg udp_tx_start_en, //udp开始发送信号
  16. output [31:0] udp_tx_data, //udp发送的数据
  17. output reg [15:0] udp_tx_byte_num //udp单包发送的有效字节数
  18. );
  19. //parameter define
  20. parameter CMOS_H_PIXEL = 16'd640; //图像水平方向分辨率
  21. parameter CMOS_V_PIXEL = 16'd480; //图像垂直方向分辨率
  22. //图像帧头,用于标志一帧数据的开始
  23. parameter IMG_FRAME_HEAD = {32'hf0_5a_a5_0f};
  24. reg img_vsync_d0; //帧有效信号打拍
  25. reg img_vsync_d1; //帧有效信号打拍
  26. reg neg_vsync_d0; //帧有效信号下降沿打拍
  27. reg wr_sw; //用于位拼接的标志
  28. reg [15:0] img_data_d0; //有效图像数据打拍
  29. reg wr_fifo_en; //写fifo使能
  30. reg [31:0] wr_fifo_data; //写fifo数据
  31. reg img_vsync_txc_d0; //以太网发送时钟域下,帧有效信号打拍
  32. reg img_vsync_txc_d1; //以太网发送时钟域下,帧有效信号打拍
  33. reg tx_busy_flag; //发送忙信号标志
  34. //wire define
  35. wire pos_vsync; //帧有效信号上升沿
  36. wire neg_vsync; //帧有效信号下降沿
  37. wire neg_vsynt_txc; //以太网发送时钟域下,帧有效信号下降沿
  38. wire [ 9:0] fifo_rdusedw; //当前FIFO缓存的个数
  39. //*****************************************************
  40. //** main code
  41. //*****************************************************
  42. //信号采沿
  43. assign neg_vsync = img_vsync_d1 & (~img_vsync_d0);
  44. assign pos_vsync = ~img_vsync_d1 & img_vsync_d0;
  45. assign neg_vsynt_txc = ~img_vsync_txc_d1 & img_vsync_txc_d0;
  46. //对img_vsync信号延时两个时钟周期,用于采沿
  47. always @(posedge cam_pclk or negedge rst_n) begin
  48. if (!rst_n) begin
  49. img_vsync_d0 <= 1'b0;
  50. img_vsync_d1 <= 1'b0;
  51. end else begin
  52. img_vsync_d0 <= img_vsync;
  53. img_vsync_d1 <= img_vsync_d0;
  54. end
  55. end
  56. //寄存neg_vsync信号
  57. always @(posedge cam_pclk or negedge rst_n) begin
  58. if (!rst_n) neg_vsync_d0 <= 1'b0;
  59. else neg_vsync_d0 <= neg_vsync;
  60. end
  61. //对wr_sw和img_data_d0信号赋值,用于位拼接
  62. always @(posedge cam_pclk or negedge rst_n) begin
  63. if (!rst_n) begin
  64. wr_sw <= 1'b0;
  65. img_data_d0 <= 1'b0;
  66. end else if (neg_vsync) wr_sw <= 1'b0;
  67. else if (img_data_en) begin
  68. wr_sw <= ~wr_sw;
  69. img_data_d0 <= img_data;
  70. end
  71. end
  72. //将帧头和图像数据写入FIFO
  73. always @(posedge cam_pclk or negedge rst_n) begin
  74. if (!rst_n) begin
  75. wr_fifo_en <= 1'b0;
  76. wr_fifo_data <= 1'b0;
  77. end else begin
  78. if (neg_vsync) begin
  79. wr_fifo_en <= 1'b1;
  80. wr_fifo_data <= IMG_FRAME_HEAD; //帧头
  81. end else if (neg_vsync_d0) begin
  82. wr_fifo_en <= 1'b1;
  83. wr_fifo_data <= {CMOS_H_PIXEL, CMOS_V_PIXEL}; //水平和垂直方向分辨率
  84. end else if (img_data_en && wr_sw) begin
  85. wr_fifo_en <= 1'b1;
  86. wr_fifo_data <= {img_data_d0, img_data}; //图像数据位拼接,16位转32
  87. end else begin
  88. wr_fifo_en <= 1'b0;
  89. wr_fifo_data <= 1'b0;
  90. end
  91. end
  92. end
  93. //以太网发送时钟域下,对img_vsync信号延时两个时钟周期,用于采沿
  94. always @(posedge eth_tx_clk or negedge rst_n) begin
  95. if (!rst_n) begin
  96. img_vsync_txc_d0 <= 1'b0;
  97. img_vsync_txc_d1 <= 1'b0;
  98. end else begin
  99. img_vsync_txc_d0 <= img_vsync;
  100. img_vsync_txc_d1 <= img_vsync_txc_d0;
  101. end
  102. end
  103. //控制以太网发送的字节数
  104. always @(posedge eth_tx_clk or negedge rst_n) begin
  105. if (!rst_n) udp_tx_byte_num <= 1'b0;
  106. else if (neg_vsynt_txc) udp_tx_byte_num <= {CMOS_H_PIXEL, 1'b0} + 16'd8;
  107. else if (udp_tx_done) udp_tx_byte_num <= {CMOS_H_PIXEL, 1'b0};
  108. end
  109. //控制以太网发送开始信号
  110. always @(posedge eth_tx_clk or negedge rst_n) begin
  111. if (!rst_n) begin
  112. udp_tx_start_en <= 1'b0;
  113. tx_busy_flag <= 1'b0;
  114. end //上位机未发送"开始"命令时,以太网不发送图像数据
  115. else if (transfer_flag == 1'b0) begin
  116. udp_tx_start_en <= 1'b0;
  117. tx_busy_flag <= 1'b0;
  118. end else begin
  119. udp_tx_start_en <= 1'b0;
  120. //当FIFO中的个数满足需要发送的字节数时
  121. if (tx_busy_flag == 1'b0 && fifo_rdusedw >= udp_tx_byte_num[15:2]) begin
  122. udp_tx_start_en <= 1'b1; //开始控制发送一包数据
  123. tx_busy_flag <= 1'b1;
  124. end else if (udp_tx_done || neg_vsynt_txc) tx_busy_flag <= 1'b0;
  125. end
  126. end
  127. //异步FIFO
  128. async_fifo_1024x32b async_fifo_1024x32b_inst (
  129. .rst (pos_vsync | (~transfer_flag)), // input wire rst
  130. .wr_clk (cam_pclk), // input wire wr_clk
  131. .rd_clk (eth_tx_clk), // input wire rd_clk
  132. .din (wr_fifo_data), // input wire [31 : 0] din
  133. .wr_en (wr_fifo_en), // input wire wr_en
  134. .rd_en (udp_tx_req), // input wire rd_en
  135. .dout (udp_tx_data), // output wire [31 : 0] dout
  136. .full (), // output wire full
  137. .empty (), // output wire empty
  138. .rd_data_count(fifo_rdusedw), // output wire [9 : 0] rd_data_count
  139. .wr_rst_busy (), // output wire wr_rst_busy
  140. .rd_rst_busy () // output wire rd_rst_busy
  141. );
  142. endmodule

 

3.7 以太网通信UDP通信顶层模块

  1. `timescale 1ns / 1ps
  2. //以太网通信UDP通信顶层模块
  3. module eth_top (
  4. input sys_rst_n, //系统复位信号,低电平有效
  5. //以太网RGMII接口
  6. input eth_rxc, //RGMII接收数据时钟
  7. input eth_rx_ctl, //RGMII输入数据有效信号
  8. input [3:0] eth_rxd, //RGMII输入数据
  9. output eth_txc, //RGMII发送数据时钟
  10. output eth_tx_ctl, //RGMII输出数据有效信号
  11. output [3:0] eth_txd, //RGMII输出数据
  12. input gmii_tx_clk, //GMII发送时钟
  13. input udp_tx_start_en, //以太网开始发送信号
  14. input [31:0] tx_data, //以太网待发送数据
  15. input [15:0] tx_byte_num, //以太网发送的有效字节数 单位:byte
  16. output udp_tx_done, //UDP发送完成信号
  17. output tx_req, //读数据请求信号
  18. output gmii_rx_clk, //GMII接收时钟
  19. output rec_pkt_done, //UDP单包数据接收完成信号
  20. output rec_en, //UDP接收的数据使能信号
  21. output [31:0] rec_data, //UDP接收的数据
  22. output [15:0] rec_byte_num //UDP接收到的字节数
  23. );
  24. //parameter define
  25. //开发板MAC地址 00-11-22-33-44-55
  26. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  27. //开发板IP地址 192.168.1.10
  28. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  29. //目的MAC地址 ff_ff_ff_ff_ff_ff
  30. parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
  31. //目的IP地址 192.168.1.102
  32. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  33. //wire define
  34. wire gmii_rx_dv; //GMII接收数据有效信号
  35. wire [ 7:0] gmii_rxd; //GMII接收数据
  36. wire gmii_tx_en; //GMII发送数据使能信号
  37. wire [ 7:0] gmii_txd; //GMII发送数据
  38. wire arp_gmii_tx_en; //ARP GMII输出数据有效信号
  39. wire [ 7:0] arp_gmii_txd; //ARP GMII输出数据
  40. wire arp_rx_done; //ARP接收完成信号
  41. wire arp_rx_type; //ARP接收类型 0:请求 1:应答
  42. wire [47:0] src_mac; //接收到目的MAC地址
  43. wire [31:0] src_ip; //接收到目的IP地址
  44. wire arp_tx_en; //ARP发送使能信号
  45. wire arp_tx_type; //ARP发送类型 0:请求 1:应答
  46. wire [47:0] des_mac; //发送的目标MAC地址
  47. wire [31:0] des_ip; //发送的目标IP地址
  48. wire arp_tx_done; //ARP发送完成信号
  49. wire udp_gmii_tx_en; //UDP GMII输出数据有效信号
  50. wire [ 7:0] udp_gmii_txd; //UDP GMII输出数据
  51. //*****************************************************
  52. //** main code
  53. //*****************************************************
  54. assign des_mac = src_mac;
  55. assign des_ip = src_ip;
  56. assign eth_txc = clk_125m_deg;
  57. clk_wiz u_clk_wiz (
  58. // Clock out ports
  59. .clk_out1(clk_125m_deg), // output clk_out1
  60. // Status and control signals
  61. .reset (~sys_rst_n), // input reset
  62. .locked (locked), // output locked
  63. // Clock in ports
  64. .clk_in1 (rgmii_txc) // input clk_in1
  65. );
  66. //GMII接口转RGMII接口
  67. gmii_to_rgmii u_gmii_to_rgmii (
  68. .gmii_rx_clk(gmii_rx_clk),
  69. .gmii_rx_dv (gmii_rx_dv),
  70. .gmii_rxd (gmii_rxd),
  71. .gmii_tx_clk(gmii_tx_clk),
  72. .gmii_tx_en (gmii_tx_en),
  73. .gmii_txd (gmii_txd),
  74. .rgmii_rxc (eth_rxc),
  75. .rgmii_rx_ctl(eth_rx_ctl),
  76. .rgmii_rxd (eth_rxd),
  77. .rgmii_txc (rgmii_txc),
  78. .rgmii_tx_ctl(eth_tx_ctl),
  79. .rgmii_txd (eth_txd)
  80. );
  81. //ARP通信
  82. arp #(
  83. .BOARD_MAC(BOARD_MAC), //参数例化
  84. .BOARD_IP (BOARD_IP),
  85. .DES_MAC (DES_MAC),
  86. .DES_IP (DES_IP)
  87. ) u_arp (
  88. .rst_n(sys_rst_n),
  89. .gmii_rx_clk(gmii_rx_clk),
  90. .gmii_rx_dv (gmii_rx_dv),
  91. .gmii_rxd (gmii_rxd),
  92. .gmii_tx_clk(gmii_tx_clk),
  93. .gmii_tx_en (arp_gmii_tx_en),
  94. .gmii_txd (arp_gmii_txd),
  95. .arp_rx_done(arp_rx_done),
  96. .arp_rx_type(arp_rx_type),
  97. .src_mac (src_mac),
  98. .src_ip (src_ip),
  99. .arp_tx_en (arp_tx_en),
  100. .arp_tx_type(arp_tx_type),
  101. .des_mac (des_mac),
  102. .des_ip (des_ip),
  103. .tx_done (arp_tx_done)
  104. );
  105. //UDP通信
  106. udp #(
  107. .BOARD_MAC(BOARD_MAC), //参数例化
  108. .BOARD_IP (BOARD_IP),
  109. .DES_MAC (DES_MAC),
  110. .DES_IP (DES_IP)
  111. ) u_udp (
  112. .rst_n(sys_rst_n),
  113. .gmii_rx_clk(gmii_rx_clk),
  114. .gmii_rx_dv (gmii_rx_dv),
  115. .gmii_rxd (gmii_rxd),
  116. .gmii_tx_clk(gmii_tx_clk),
  117. .gmii_tx_en (udp_gmii_tx_en),
  118. .gmii_txd (udp_gmii_txd),
  119. .rec_pkt_done(rec_pkt_done),
  120. .rec_en (rec_en),
  121. .rec_data (rec_data),
  122. .rec_byte_num(rec_byte_num),
  123. .tx_start_en (udp_tx_start_en),
  124. .tx_data (tx_data),
  125. .tx_byte_num (tx_byte_num),
  126. .des_mac (des_mac),
  127. .des_ip (des_ip),
  128. .tx_done (udp_tx_done),
  129. .tx_req (tx_req)
  130. );
  131. //以太网控制模块
  132. eth_ctrl u_eth_ctrl (
  133. .clk (gmii_rx_clk),
  134. .rst_n(sys_rst_n),
  135. .arp_rx_done (arp_rx_done),
  136. .arp_rx_type (arp_rx_type),
  137. .arp_tx_en (arp_tx_en),
  138. .arp_tx_type (arp_tx_type),
  139. .arp_tx_done (arp_tx_done),
  140. .arp_gmii_tx_en(arp_gmii_tx_en),
  141. .arp_gmii_txd (arp_gmii_txd),
  142. .udp_gmii_tx_en(udp_gmii_tx_en),
  143. .udp_gmii_txd (udp_gmii_txd),
  144. .gmii_tx_en(gmii_tx_en),
  145. .gmii_txd (gmii_txd)
  146. );
  147. endmodule

 

3.8 GMII接口转RGMII接口模块

  1. `timescale 1ns / 1ps
  2. //GMII接口转RGMII接口模块
  3. module gmii_to_rgmii (
  4. //以太网GMII接口
  5. output gmii_rx_clk, //GMII接收时钟
  6. output gmii_rx_dv, //GMII接收数据有效信号
  7. output [7:0] gmii_rxd, //GMII接收数据
  8. input gmii_tx_clk, //GMII发送时钟
  9. input gmii_tx_en, //GMII发送数据使能信号
  10. input [7:0] gmii_txd, //GMII发送数据
  11. //以太网RGMII接口
  12. input rgmii_rxc, //RGMII接收时钟
  13. input rgmii_rx_ctl, //RGMII接收数据控制信号
  14. input [3:0] rgmii_rxd, //RGMII接收数据
  15. output rgmii_txc, //RGMII发送时钟
  16. output rgmii_tx_ctl, //RGMII发送数据控制信号
  17. output [3:0] rgmii_txd //RGMII发送数据
  18. );
  19. //*****************************************************
  20. //** main code
  21. //*****************************************************
  22. assign gmii_tx_clk = gmii_rx_clk;
  23. //RGMII接收
  24. rgmii_rx u_rgmii_rx (
  25. .gmii_rx_clk (gmii_rx_clk),
  26. .rgmii_rxc (rgmii_rxc),
  27. .rgmii_rx_ctl(rgmii_rx_ctl),
  28. .rgmii_rxd (rgmii_rxd),
  29. .gmii_rx_dv(gmii_rx_dv),
  30. .gmii_rxd (gmii_rxd)
  31. );
  32. //RGMII发送
  33. rgmii_tx u_rgmii_tx (
  34. .gmii_tx_clk(gmii_tx_clk),
  35. .gmii_tx_en (gmii_tx_en),
  36. .gmii_txd (gmii_txd),
  37. .rgmii_txc (rgmii_txc),
  38. .rgmii_tx_ctl(rgmii_tx_ctl),
  39. .rgmii_txd (rgmii_txd)
  40. );
  41. endmodule

3.8.1 RGMII接收模块

  1. `timescale 1ns / 1ps
  2. //RGMII接收模块
  3. module rgmii_rx (
  4. //以太网RGMII接口
  5. input rgmii_rxc, //RGMII接收时钟
  6. input rgmii_rx_ctl, //RGMII接收数据控制信号
  7. input [3:0] rgmii_rxd, //RGMII接收数据
  8. //以太网GMII接口
  9. output gmii_rx_clk, //GMII接收时钟
  10. output gmii_rx_dv, //GMII接收数据有效信号
  11. output [7:0] gmii_rxd //GMII接收数据
  12. );
  13. //wire define
  14. wire rgmii_rxc_bufg; //全局时钟缓存
  15. wire rgmii_rxc_bufio; //全局时钟IO缓存
  16. wire [1:0] gmii_rxdv_t; //两位GMII接收有效信号
  17. //*****************************************************
  18. //** main code
  19. //*****************************************************
  20. assign gmii_rx_clk = rgmii_rxc_bufg;
  21. assign gmii_rx_dv = gmii_rxdv_t[0] & gmii_rxdv_t[1];
  22. //全局时钟缓存
  23. BUFG BUFG_inst (
  24. .I(rgmii_rxc), // 1-bit input: Clock input
  25. .O(rgmii_rxc_bufg) // 1-bit output: Clock output
  26. );
  27. //全局时钟IO缓存
  28. BUFIO BUFIO_inst (
  29. .I(rgmii_rxc), // 1-bit input: Clock input
  30. .O(rgmii_rxc_bufio) // 1-bit output: Clock output
  31. );
  32. //将输入的上下边沿DDR信号,转换成两位单边沿SDR信号
  33. IDDRE1 #(
  34. .DDR_CLK_EDGE ("SAME_EDGE_PIPELINED"),// IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
  35. .IS_CB_INVERTED(1'b0), // Optional inversion for CB
  36. .IS_C_INVERTED(1'b0) // Optional inversion for C
  37. ) IDDRE1_inst (
  38. .Q1(gmii_rxdv_t[0]), // 1-bit output: Registered parallel output 1
  39. .Q2(gmii_rxdv_t[1]), // 1-bit output: Registered parallel output 2
  40. .C (rgmii_rxc_bufio), // 1-bit input: High-speed clock
  41. .CB(~rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C
  42. .D (rgmii_rx_ctl), // 1-bit input: Serial Data Input
  43. .R (1'b0) // 1-bit input: Active High Async Reset
  44. );
  45. genvar i;
  46. generate
  47. for (i = 0; i < 4; i = i + 1) begin : rxdata_bus
  48. IDDRE1 #(
  49. .DDR_CLK_EDGE ("SAME_EDGE_PIPELINED"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
  50. .IS_CB_INVERTED(1'b0), // Optional inversion for CB
  51. .IS_C_INVERTED(1'b0) // Optional inversion for C
  52. ) IDDRE1_inst (
  53. .Q1(gmii_rxd[i]), // 1-bit output: Registered parallel output 1
  54. .Q2(gmii_rxd[4+i]), // 1-bit output: Registered parallel output 2
  55. .C (rgmii_rxc_bufio), // 1-bit input: High-speed clock
  56. .CB(~rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C
  57. .D (rgmii_rxd[i]), // 1-bit input: Serial Data Input
  58. .R (1'b0) // 1-bit input: Active High Async Reset
  59. );
  60. end
  61. endgenerate
  62. endmodule

3.8.2 RGMII发送模块

  1. `timescale 1ns / 1ps
  2. //RGMII发送模块
  3. module rgmii_tx (
  4. //GMII发送端口
  5. input gmii_tx_clk, //GMII发送时钟
  6. input gmii_tx_en, //GMII输出数据有效信号
  7. input [7:0] gmii_txd, //GMII输出数据
  8. //RGMII发送端口
  9. output rgmii_txc, //RGMII发送数据时钟
  10. output rgmii_tx_ctl, //RGMII输出数据有效信号
  11. output [3:0] rgmii_txd //RGMII输出数据
  12. );
  13. //*****************************************************
  14. //** main code
  15. //*****************************************************
  16. assign rgmii_txc = gmii_tx_clk;
  17. //输出双沿采样寄存器 (rgmii_tx_ctl)
  18. ODDRE1 #(
  19. .IS_C_INVERTED(1'b0), // Optional inversion for C
  20. .IS_D1_INVERTED(1'b0), // Unsupported, do not use
  21. .IS_D2_INVERTED(1'b0), // Unsupported, do not use
  22. .SIM_DEVICE ("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2)
  23. .SRVAL(1'b0) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
  24. ) ODDRE1_tx_ctl (
  25. .Q (rgmii_tx_ctl), // 1-bit output: Data output to IOB
  26. .C (gmii_tx_clk), // 1-bit input: High-speed clock input
  27. .D1(gmii_tx_en), // 1-bit input: Parallel data input 1
  28. .D2(gmii_tx_en), // 1-bit input: Parallel data input 2
  29. .SR(1'b0) // 1-bit input: Active High Async Reset
  30. );
  31. genvar i;
  32. generate
  33. for (i = 0; i < 4; i = i + 1) begin : txdata_bus
  34. ODDRE1 #(
  35. .IS_C_INVERTED(1'b0), // Optional inversion for C
  36. .IS_D1_INVERTED(1'b0), // Unsupported, do not use
  37. .IS_D2_INVERTED(1'b0), // Unsupported, do not use
  38. .SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,ULTRASCALE_PLUS_ES2)
  39. .SRVAL(1'b0) // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
  40. ) ODDRE1_inst (
  41. .Q (rgmii_txd[i]), // 1-bit output: Data output to IOB
  42. .C (gmii_tx_clk), // 1-bit input: High-speed clock input
  43. .D1(gmii_txd[i]), // 1-bit input: Parallel data input 1
  44. .D2(gmii_txd[4+i]), // 1-bit input: Parallel data input 2
  45. .SR(1'b0) // 1-bit input: Active High Async Reset
  46. );
  47. end
  48. endgenerate
  49. endmodule

3.9 arp模块

  1. `timescale 1ns / 1ps
  2. //arp模块
  3. module arp (
  4. input rst_n, //复位信号,低电平有效
  5. //GMII接口
  6. input gmii_rx_clk, //GMII接收数据时钟
  7. input gmii_rx_dv, //GMII输入数据有效信号
  8. input [7:0] gmii_rxd, //GMII输入数据
  9. input gmii_tx_clk, //GMII发送数据时钟
  10. output gmii_tx_en, //GMII输出数据有效信号
  11. output [7:0] gmii_txd, //GMII输出数据
  12. //用户接口
  13. output arp_rx_done, //ARP接收完成信号
  14. output arp_rx_type, //ARP接收类型 0:请求 1:应答
  15. output [47:0] src_mac, //接收到目的MAC地址
  16. output [31:0] src_ip, //接收到目的IP地址
  17. input arp_tx_en, //ARP发送使能信号
  18. input arp_tx_type, //ARP发送类型 0:请求 1:应答
  19. input [47:0] des_mac, //发送的目标MAC地址
  20. input [31:0] des_ip, //发送的目标IP地址
  21. output tx_done //以太网发送完成信号
  22. );
  23. //parameter define
  24. //开发板MAC地址 00-11-22-33-44-55
  25. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  26. //开发板IP地址 192.168.1.10
  27. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  28. //目的MAC地址 ff_ff_ff_ff_ff_ff
  29. parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
  30. //目的IP地址 192.168.1.102
  31. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  32. //wire define
  33. wire crc_en; //CRC开始校验使能
  34. wire crc_clr; //CRC数据复位信号
  35. wire [ 7:0] crc_d8; //输入待校验8位数据
  36. wire [31:0] crc_data; //CRC校验数据
  37. wire [31:0] crc_next; //CRC下次校验完成数据
  38. //*****************************************************
  39. //** main code
  40. //*****************************************************
  41. assign crc_d8 = gmii_txd;
  42. //ARP接收模块
  43. arp_rx #(
  44. .BOARD_MAC(BOARD_MAC), //参数例化
  45. .BOARD_IP (BOARD_IP)
  46. ) u_arp_rx (
  47. .clk (gmii_rx_clk),
  48. .rst_n(rst_n),
  49. .gmii_rx_dv (gmii_rx_dv),
  50. .gmii_rxd (gmii_rxd),
  51. .arp_rx_done(arp_rx_done),
  52. .arp_rx_type(arp_rx_type),
  53. .src_mac (src_mac),
  54. .src_ip (src_ip)
  55. );
  56. //ARP发送模块
  57. arp_tx #(
  58. .BOARD_MAC(BOARD_MAC), //参数例化
  59. .BOARD_IP (BOARD_IP),
  60. .DES_MAC (DES_MAC),
  61. .DES_IP (DES_IP)
  62. ) u_arp_tx (
  63. .clk (gmii_tx_clk),
  64. .rst_n(rst_n),
  65. .arp_tx_en (arp_tx_en),
  66. .arp_tx_type(arp_tx_type),
  67. .des_mac (des_mac),
  68. .des_ip (des_ip),
  69. .crc_data (crc_data),
  70. .crc_next (crc_next[31:24]),
  71. .tx_done (tx_done),
  72. .gmii_tx_en (gmii_tx_en),
  73. .gmii_txd (gmii_txd),
  74. .crc_en (crc_en),
  75. .crc_clr (crc_clr)
  76. );
  77. //以太网发送CRC校验模块
  78. crc32_d8 u_crc32_d8 (
  79. .clk (gmii_tx_clk),
  80. .rst_n (rst_n),
  81. .data (crc_d8),
  82. .crc_en (crc_en),
  83. .crc_clr (crc_clr),
  84. .crc_data(crc_data),
  85. .crc_next(crc_next)
  86. );
  87. endmodule

3.9.1 arp接收模块

  1. `timescale 1ns / 1ps
  2. //arp接收模块
  3. module arp_rx #(
  4. //开发板MAC地址 00-11-22-33-44-55
  5. parameter BOARD_MAC = 48'h00_11_22_33_44_55,
  6. //开发板IP地址 192.168.1.10
  7. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10}
  8. ) (
  9. input clk, //时钟信号
  10. input rst_n, //复位信号,低电平有效
  11. input gmii_rx_dv, //GMII输入数据有效信号
  12. input [ 7:0] gmii_rxd, //GMII输入数据
  13. output reg arp_rx_done, //ARP接收完成信号
  14. output reg arp_rx_type, //ARP接收类型 0:请求 1:应答
  15. output reg [47:0] src_mac, //接收到的源MAC地址
  16. output reg [31:0] src_ip //接收到的源IP地址
  17. );
  18. //parameter define
  19. localparam st_idle = 5'b0_0001; //初始状态,等待接收前导码
  20. localparam st_preamble = 5'b0_0010; //接收前导码状态
  21. localparam st_eth_head = 5'b0_0100; //接收以太网帧头
  22. localparam st_arp_data = 5'b0_1000; //接收ARP数据
  23. localparam st_rx_end = 5'b1_0000; //接收结束
  24. localparam ETH_TPYE = 16'h0806; //以太网帧类型 ARP
  25. //reg define
  26. reg [ 4:0] cur_state;
  27. reg [ 4:0] next_state;
  28. reg skip_en; //控制状态跳转使能信号
  29. reg error_en; //解析错误使能信号
  30. reg [ 4:0] cnt; //解析数据计数器
  31. reg [47:0] des_mac_t; //接收到的目的MAC地址
  32. reg [31:0] des_ip_t; //接收到的目的IP地址
  33. reg [47:0] src_mac_t; //接收到的源MAC地址
  34. reg [31:0] src_ip_t; //接收到的源IP地址
  35. reg [15:0] eth_type; //以太网类型
  36. reg [15:0] op_data; //操作码
  37. //*****************************************************
  38. //** main code
  39. //*****************************************************
  40. //(三段式状态机)同步时序描述状态转移
  41. always @(posedge clk or negedge rst_n) begin
  42. if (!rst_n) cur_state <= st_idle;
  43. else cur_state <= next_state;
  44. end
  45. //组合逻辑判断状态转移条件
  46. always @(*) begin
  47. next_state = st_idle;
  48. case (cur_state)
  49. st_idle: begin //等待接收前导码
  50. if (skip_en) next_state = st_preamble;
  51. else next_state = st_idle;
  52. end
  53. st_preamble: begin //接收前导码
  54. if (skip_en) next_state = st_eth_head;
  55. else if (error_en) next_state = st_rx_end;
  56. else next_state = st_preamble;
  57. end
  58. st_eth_head: begin //接收以太网帧头
  59. if (skip_en) next_state = st_arp_data;
  60. else if (error_en) next_state = st_rx_end;
  61. else next_state = st_eth_head;
  62. end
  63. st_arp_data: begin //接收ARP数据
  64. if (skip_en) next_state = st_rx_end;
  65. else if (error_en) next_state = st_rx_end;
  66. else next_state = st_arp_data;
  67. end
  68. st_rx_end: begin //接收结束
  69. if (skip_en) next_state = st_idle;
  70. else next_state = st_rx_end;
  71. end
  72. default: next_state = st_idle;
  73. endcase
  74. end
  75. //时序电路描述状态输出,解析以太网数据
  76. always @(posedge clk or negedge rst_n) begin
  77. if (!rst_n) begin
  78. skip_en <= 1'b0;
  79. error_en <= 1'b0;
  80. cnt <= 5'd0;
  81. des_mac_t <= 48'd0;
  82. des_ip_t <= 32'd0;
  83. src_mac_t <= 48'd0;
  84. src_ip_t <= 32'd0;
  85. eth_type <= 16'd0;
  86. op_data <= 16'd0;
  87. arp_rx_done <= 1'b0;
  88. arp_rx_type <= 1'b0;
  89. src_mac <= 48'd0;
  90. src_ip <= 32'd0;
  91. end else begin
  92. skip_en <= 1'b0;
  93. error_en <= 1'b0;
  94. arp_rx_done <= 1'b0;
  95. case (next_state)
  96. st_idle: begin //检测到第一个8'h55
  97. if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;
  98. end
  99. st_preamble: begin
  100. if (gmii_rx_dv) begin //解析前导码
  101. cnt <= cnt + 5'd1;
  102. if ((cnt < 5'd6) && (gmii_rxd != 8'h55)) //78'h55
  103. error_en <= 1'b1;
  104. else if (cnt == 5'd6) begin
  105. cnt <= 5'd0;
  106. if (gmii_rxd == 8'hd5) //1个8'hd5
  107. skip_en <= 1'b1;
  108. else error_en <= 1'b1;
  109. end
  110. end
  111. end
  112. st_eth_head: begin
  113. if (gmii_rx_dv) begin
  114. cnt <= cnt + 5'b1;
  115. if (cnt < 5'd6) des_mac_t <= {des_mac_t[39:0], gmii_rxd};
  116. else if (cnt == 5'd6) begin
  117. //判断MAC地址是否为开发板MAC地址或者公共地址
  118. if ((des_mac_t != BOARD_MAC) && (des_mac_t != 48'hff_ff_ff_ff_ff_ff))
  119. error_en <= 1'b1;
  120. end else if (cnt == 5'd12) eth_type[15:8] <= gmii_rxd; //以太网协议类型
  121. else if (cnt == 5'd13) begin
  122. eth_type[7:0] <= gmii_rxd;
  123. cnt <= 5'd0;
  124. if (eth_type[15:8] == ETH_TPYE[15:8] //判断是否为ARP协议
  125. && gmii_rxd == ETH_TPYE[7:0])
  126. skip_en <= 1'b1;
  127. else error_en <= 1'b1;
  128. end
  129. end
  130. end
  131. st_arp_data: begin
  132. if (gmii_rx_dv) begin
  133. cnt <= cnt + 5'd1;
  134. if (cnt == 5'd6) op_data[15:8] <= gmii_rxd; //操作码
  135. else if (cnt == 5'd7) op_data[7:0] <= gmii_rxd;
  136. else if (cnt >= 5'd8 && cnt < 5'd14) //源MAC地址
  137. src_mac_t <= {src_mac_t[39:0], gmii_rxd};
  138. else if (cnt >= 5'd14 && cnt < 5'd18) //源IP地址
  139. src_ip_t <= {src_ip_t[23:0], gmii_rxd};
  140. else if (cnt >= 5'd24 && cnt < 5'd28) //目标IP地址
  141. des_ip_t <= {des_ip_t[23:0], gmii_rxd};
  142. else if (cnt == 5'd28) begin
  143. cnt <= 5'd0;
  144. if (des_ip_t == BOARD_IP) begin //判断目的IP地址和操作码
  145. if ((op_data == 16'd1) || (op_data == 16'd2)) begin
  146. skip_en <= 1'b1;
  147. arp_rx_done <= 1'b1;
  148. src_mac <= src_mac_t;
  149. src_ip <= src_ip_t;
  150. src_mac_t <= 48'd0;
  151. src_ip_t <= 32'd0;
  152. des_mac_t <= 48'd0;
  153. des_ip_t <= 32'd0;
  154. if (op_data == 16'd1) arp_rx_type <= 1'b0; //ARP请求
  155. else arp_rx_type <= 1'b1; //ARP应答
  156. end else error_en <= 1'b1;
  157. end else error_en <= 1'b1;
  158. end
  159. end
  160. end
  161. st_rx_end: begin
  162. cnt <= 5'd0;
  163. //单包数据接收完成
  164. if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;
  165. end
  166. default: ;
  167. endcase
  168. end
  169. end
  170. endmodule

3.9.2 arp发送模块

  1. `timescale 1ns / 1ps
  2. //arp发送模块
  3. module arp_tx (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input arp_tx_en, //ARP发送使能信号
  7. input arp_tx_type, //ARP发送类型 0:请求 1:应答
  8. input [47:0] des_mac, //发送的目标MAC地址
  9. input [31:0] des_ip, //发送的目标IP地址
  10. input [31:0] crc_data, //CRC校验数据
  11. input [ 7:0] crc_next, //CRC下次校验完成数据
  12. output reg tx_done, //以太网发送完成信号
  13. output reg gmii_tx_en, //GMII输出数据有效信号
  14. output reg [ 7:0] gmii_txd, //GMII输出数据
  15. output reg crc_en, //CRC开始校验使能
  16. output reg crc_clr //CRC数据复位信号
  17. );
  18. //parameter define
  19. //开发板MAC地址 00-11-22-33-44-55
  20. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  21. //开发板IP地址 192.168.1.10
  22. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  23. //目的MAC地址 ff_ff_ff_ff_ff_ff
  24. parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
  25. //目的IP地址 192.168.1.102
  26. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  27. localparam st_idle = 5'b0_0001; //初始状态,等待开始发送信号
  28. localparam st_preamble = 5'b0_0010; //发送前导码+帧起始界定符
  29. localparam st_eth_head = 5'b0_0100; //发送以太网帧头
  30. localparam st_arp_data = 5'b0_1000; //
  31. localparam st_crc = 5'b1_0000; //发送CRC校验值
  32. localparam ETH_TYPE = 16'h0806; //以太网帧类型 ARP协议
  33. localparam HD_TYPE = 16'h0001; //硬件类型 以太网
  34. localparam PROTOCOL_TYPE = 16'h0800; //上层协议为IP协议
  35. //以太网数据最小为46个字节,不足部分填充数据
  36. localparam MIN_DATA_NUM = 16'd46;
  37. //reg define
  38. reg [4:0] cur_state;
  39. reg [4:0] next_state;
  40. reg [7:0] preamble [ 7:0]; //前导码+SFD
  41. reg [7:0] eth_head [13:0]; //以太网首部
  42. reg [7:0] arp_data [27:0]; //ARP数据
  43. reg tx_en_d0; //arp_tx_en信号延时
  44. reg tx_en_d1;
  45. reg skip_en; //控制状态跳转使能信号
  46. reg [5:0] cnt;
  47. reg [4:0] data_cnt; //发送数据个数计数器
  48. reg tx_done_t;
  49. //wire define
  50. wire pos_tx_en; //arp_tx_en信号上升沿
  51. //*****************************************************
  52. //** main code
  53. //*****************************************************
  54. assign pos_tx_en = (~tx_en_d1) & tx_en_d0;
  55. //对arp_tx_en信号延时打拍两次,用于采arp_tx_en的上升沿
  56. always @(posedge clk or negedge rst_n) begin
  57. if (!rst_n) begin
  58. tx_en_d0 <= 1'b0;
  59. tx_en_d1 <= 1'b0;
  60. end else begin
  61. tx_en_d0 <= arp_tx_en;
  62. tx_en_d1 <= tx_en_d0;
  63. end
  64. end
  65. //(三段式状态机)同步时序描述状态转移
  66. always @(posedge clk or negedge rst_n) begin
  67. if (!rst_n) cur_state <= st_idle;
  68. else cur_state <= next_state;
  69. end
  70. //组合逻辑判断状态转移条件
  71. always @(*) begin
  72. next_state = st_idle;
  73. case (cur_state)
  74. st_idle: begin //空闲状态
  75. if (skip_en) next_state = st_preamble;
  76. else next_state = st_idle;
  77. end
  78. st_preamble: begin //发送前导码+帧起始界定符
  79. if (skip_en) next_state = st_eth_head;
  80. else next_state = st_preamble;
  81. end
  82. st_eth_head: begin //发送以太网首部
  83. if (skip_en) next_state = st_arp_data;
  84. else next_state = st_eth_head;
  85. end
  86. st_arp_data: begin //发送ARP数据
  87. if (skip_en) next_state = st_crc;
  88. else next_state = st_arp_data;
  89. end
  90. st_crc: begin //发送CRC校验值
  91. if (skip_en) next_state = st_idle;
  92. else next_state = st_crc;
  93. end
  94. default: next_state = st_idle;
  95. endcase
  96. end
  97. //时序电路描述状态输出,发送以太网数据
  98. always @(posedge clk or negedge rst_n) begin
  99. if (!rst_n) begin
  100. skip_en <= 1'b0;
  101. cnt <= 6'd0;
  102. data_cnt <= 5'd0;
  103. crc_en <= 1'b0;
  104. gmii_tx_en <= 1'b0;
  105. gmii_txd <= 8'd0;
  106. tx_done_t <= 1'b0;
  107. //初始化数组
  108. //前导码 78'h55 + 1个8'hd5
  109. preamble[0] <= 8'h55;
  110. preamble[1] <= 8'h55;
  111. preamble[2] <= 8'h55;
  112. preamble[3] <= 8'h55;
  113. preamble[4] <= 8'h55;
  114. preamble[5] <= 8'h55;
  115. preamble[6] <= 8'h55;
  116. preamble[7] <= 8'hd5;
  117. //以太网帧头
  118. eth_head[0] <= DES_MAC[47:40]; //目的MAC地址
  119. eth_head[1] <= DES_MAC[39:32];
  120. eth_head[2] <= DES_MAC[31:24];
  121. eth_head[3] <= DES_MAC[23:16];
  122. eth_head[4] <= DES_MAC[15:8];
  123. eth_head[5] <= DES_MAC[7:0];
  124. eth_head[6] <= BOARD_MAC[47:40]; //源MAC地址
  125. eth_head[7] <= BOARD_MAC[39:32];
  126. eth_head[8] <= BOARD_MAC[31:24];
  127. eth_head[9] <= BOARD_MAC[23:16];
  128. eth_head[10] <= BOARD_MAC[15:8];
  129. eth_head[11] <= BOARD_MAC[7:0];
  130. eth_head[12] <= ETH_TYPE[15:8]; //以太网帧类型
  131. eth_head[13] <= ETH_TYPE[7:0];
  132. //ARP数据
  133. arp_data[0] <= HD_TYPE[15:8]; //硬件类型
  134. arp_data[1] <= HD_TYPE[7:0];
  135. arp_data[2] <= PROTOCOL_TYPE[15:8]; //上层协议类型
  136. arp_data[3] <= PROTOCOL_TYPE[7:0];
  137. arp_data[4] <= 8'h06; //硬件地址长度,6
  138. arp_data[5] <= 8'h04; //协议地址长度,4
  139. arp_data[6] <= 8'h00; //OP,操作码 8'h01:ARP请求 8'h02:ARP应答
  140. arp_data[7] <= 8'h01;
  141. arp_data[8] <= BOARD_MAC[47:40]; //发送端(源)MAC地址
  142. arp_data[9] <= BOARD_MAC[39:32];
  143. arp_data[10] <= BOARD_MAC[31:24];
  144. arp_data[11] <= BOARD_MAC[23:16];
  145. arp_data[12] <= BOARD_MAC[15:8];
  146. arp_data[13] <= BOARD_MAC[7:0];
  147. arp_data[14] <= BOARD_IP[31:24]; //发送端(源)IP地址
  148. arp_data[15] <= BOARD_IP[23:16];
  149. arp_data[16] <= BOARD_IP[15:8];
  150. arp_data[17] <= BOARD_IP[7:0];
  151. arp_data[18] <= DES_MAC[47:40]; //接收端(目的)MAC地址
  152. arp_data[19] <= DES_MAC[39:32];
  153. arp_data[20] <= DES_MAC[31:24];
  154. arp_data[21] <= DES_MAC[23:16];
  155. arp_data[22] <= DES_MAC[15:8];
  156. arp_data[23] <= DES_MAC[7:0];
  157. arp_data[24] <= DES_IP[31:24]; //接收端(目的)IP地址
  158. arp_data[25] <= DES_IP[23:16];
  159. arp_data[26] <= DES_IP[15:8];
  160. arp_data[27] <= DES_IP[7:0];
  161. end else begin
  162. skip_en <= 1'b0;
  163. crc_en <= 1'b0;
  164. gmii_tx_en <= 1'b0;
  165. tx_done_t <= 1'b0;
  166. case (next_state)
  167. st_idle: begin
  168. if (pos_tx_en) begin
  169. skip_en <= 1'b1;
  170. //如果目标MAC地址和IP地址已经更新,则发送正确的地址
  171. if ((des_mac != 48'b0) || (des_ip != 32'd0)) begin
  172. eth_head[0] <= des_mac[47:40];
  173. eth_head[1] <= des_mac[39:32];
  174. eth_head[2] <= des_mac[31:24];
  175. eth_head[3] <= des_mac[23:16];
  176. eth_head[4] <= des_mac[15:8];
  177. eth_head[5] <= des_mac[7:0];
  178. arp_data[18] <= des_mac[47:40];
  179. arp_data[19] <= des_mac[39:32];
  180. arp_data[20] <= des_mac[31:24];
  181. arp_data[21] <= des_mac[23:16];
  182. arp_data[22] <= des_mac[15:8];
  183. arp_data[23] <= des_mac[7:0];
  184. arp_data[24] <= des_ip[31:24];
  185. arp_data[25] <= des_ip[23:16];
  186. arp_data[26] <= des_ip[15:8];
  187. arp_data[27] <= des_ip[7:0];
  188. end
  189. if (arp_tx_type == 1'b0) arp_data[7] <= 8'h01; //ARP请求
  190. else arp_data[7] <= 8'h02; //ARP应答
  191. end
  192. end
  193. st_preamble: begin //发送前导码+帧起始界定符
  194. gmii_tx_en <= 1'b1;
  195. gmii_txd <= preamble[cnt];
  196. if (cnt == 6'd7) begin
  197. skip_en <= 1'b1;
  198. cnt <= 1'b0;
  199. end else cnt <= cnt + 1'b1;
  200. end
  201. st_eth_head: begin //发送以太网首部
  202. gmii_tx_en <= 1'b1;
  203. crc_en <= 1'b1;
  204. gmii_txd <= eth_head[cnt];
  205. if (cnt == 6'd13) begin
  206. skip_en <= 1'b1;
  207. cnt <= 1'b0;
  208. end else cnt <= cnt + 1'b1;
  209. end
  210. st_arp_data: begin //发送ARP数据
  211. crc_en <= 1'b1;
  212. gmii_tx_en <= 1'b1;
  213. //至少发送46个字节
  214. if (cnt == MIN_DATA_NUM - 1'b1) begin
  215. skip_en <= 1'b1;
  216. cnt <= 1'b0;
  217. data_cnt <= 1'b0;
  218. end else cnt <= cnt + 1'b1;
  219. if (data_cnt <= 6'd27) begin
  220. data_cnt <= data_cnt + 1'b1;
  221. gmii_txd <= arp_data[data_cnt];
  222. end else gmii_txd <= 8'd0; //Padding,填充0
  223. end
  224. st_crc: begin //发送CRC校验值
  225. gmii_tx_en <= 1'b1;
  226. cnt <= cnt + 1'b1;
  227. if (cnt == 6'd0)
  228. gmii_txd <= {
  229. ~crc_next[0],
  230. ~crc_next[1],
  231. ~crc_next[2],
  232. ~crc_next[3],
  233. ~crc_next[4],
  234. ~crc_next[5],
  235. ~crc_next[6],
  236. ~crc_next[7]
  237. };
  238. else if (cnt == 6'd1)
  239. gmii_txd <= {
  240. ~crc_data[16],
  241. ~crc_data[17],
  242. ~crc_data[18],
  243. ~crc_data[19],
  244. ~crc_data[20],
  245. ~crc_data[21],
  246. ~crc_data[22],
  247. ~crc_data[23]
  248. };
  249. else if (cnt == 6'd2) begin
  250. gmii_txd <= {
  251. ~crc_data[8],
  252. ~crc_data[9],
  253. ~crc_data[10],
  254. ~crc_data[11],
  255. ~crc_data[12],
  256. ~crc_data[13],
  257. ~crc_data[14],
  258. ~crc_data[15]
  259. };
  260. end else if (cnt == 6'd3) begin
  261. gmii_txd <= {
  262. ~crc_data[0],
  263. ~crc_data[1],
  264. ~crc_data[2],
  265. ~crc_data[3],
  266. ~crc_data[4],
  267. ~crc_data[5],
  268. ~crc_data[6],
  269. ~crc_data[7]
  270. };
  271. tx_done_t <= 1'b1;
  272. skip_en <= 1'b1;
  273. cnt <= 1'b0;
  274. end
  275. end
  276. default: ;
  277. endcase
  278. end
  279. end
  280. //发送完成信号及crc值复位信号
  281. always @(posedge clk or negedge rst_n) begin
  282. if (!rst_n) begin
  283. tx_done <= 1'b0;
  284. crc_clr <= 1'b0;
  285. end else begin
  286. tx_done <= tx_done_t;
  287. crc_clr <= tx_done_t;
  288. end
  289. end
  290. endmodule

3.9.3 CRC32校验模块

  1. `timescale 1ns / 1ps
  2. //CRC32校验模块
  3. module crc32_d8 (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input [ 7:0] data, //输入待校验8位数据
  7. input crc_en, //crc使能,开始校验标志
  8. input crc_clr, //crc数据复位信号
  9. output reg [31:0] crc_data, //CRC校验数据
  10. output [31:0] crc_next //CRC下次校验完成数据
  11. );
  12. //*****************************************************
  13. //** main code
  14. //*****************************************************
  15. //输入待校验8位数据,需要先将高低位互换
  16. wire [7:0] data_t;
  17. assign data_t = {data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]};
  18. //CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11
  19. //+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  20. assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];
  21. assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31]
  22. ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];
  23. assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30]
  24. ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6]
  25. ^ data_t[7];
  26. assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31]
  27. ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];
  28. assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]
  29. ^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4]
  30. ^ data_t[6];
  31. assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28]
  32. ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0]
  33. ^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6]
  34. ^ data_t[7];
  35. assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29]
  36. ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4]
  37. ^ data_t[5] ^ data_t[6] ^ data_t[7];
  38. assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29]
  39. ^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5]
  40. ^ data_t[7];
  41. assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]
  42. ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
  43. assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28]
  44. ^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];
  45. assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27]
  46. ^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];
  47. assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]
  48. ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
  49. assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26]
  50. ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0]
  51. ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];
  52. assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27]
  53. ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1]
  54. ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];
  55. assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]
  56. ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]
  57. ^ data_t[6] ^ data_t[7];
  58. assign crc_next[15] = crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]
  59. ^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];
  60. assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29]
  61. ^ data_t[0] ^ data_t[4] ^ data_t[5];
  62. assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30]
  63. ^ data_t[1] ^ data_t[5] ^ data_t[6];
  64. assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31]
  65. ^ data_t[2] ^ data_t[6] ^ data_t[7];
  66. assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];
  67. assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];
  68. assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];
  69. assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];
  70. assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30]
  71. ^ data_t[0] ^ data_t[1] ^ data_t[6];
  72. assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31]
  73. ^ data_t[1] ^ data_t[2] ^ data_t[7];
  74. assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];
  75. assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28]
  76. ^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];
  77. assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29]
  78. ^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];
  79. assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30]
  80. ^ data_t[2] ^ data_t[5] ^ data_t[6];
  81. assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31]
  82. ^ data_t[3] ^ data_t[6] ^ data_t[7];
  83. assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];
  84. assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];
  85. always @(posedge clk or negedge rst_n) begin
  86. if (!rst_n) crc_data <= 32'hff_ff_ff_ff;
  87. else if (crc_clr) //CRC校验值复位
  88. crc_data <= 32'hff_ff_ff_ff;
  89. else if (crc_en) crc_data <= crc_next;
  90. end
  91. endmodule

3.10 udp模块

  1. `timescale 1ns / 1ps
  2. //udp模块
  3. module udp (
  4. input rst_n, //复位信号,低电平有效
  5. //GMII接口
  6. input gmii_rx_clk, //GMII接收数据时钟
  7. input gmii_rx_dv, //GMII输入数据有效信号
  8. input [ 7:0] gmii_rxd, //GMII输入数据
  9. input gmii_tx_clk, //GMII发送数据时钟
  10. output gmii_tx_en, //GMII输出数据有效信号
  11. output [ 7:0] gmii_txd, //GMII输出数据
  12. //用户接口
  13. output rec_pkt_done, //以太网单包数据接收完成信号
  14. output rec_en, //以太网接收的数据使能信号
  15. output [31:0] rec_data, //以太网接收的数据
  16. output [15:0] rec_byte_num, //以太网接收的有效字节数 单位:byte
  17. input tx_start_en, //以太网开始发送信号
  18. input [31:0] tx_data, //以太网待发送数据
  19. input [15:0] tx_byte_num, //以太网发送的有效字节数 单位:byte
  20. input [47:0] des_mac, //发送的目标MAC地址
  21. input [31:0] des_ip, //发送的目标IP地址
  22. output tx_done, //以太网发送完成信号
  23. output tx_req //读数据请求信号
  24. );
  25. //parameter define
  26. //开发板MAC地址 00-11-22-33-44-55
  27. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  28. //开发板IP地址 192.168.1.10
  29. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  30. //目的MAC地址 ff_ff_ff_ff_ff_ff
  31. parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
  32. //目的IP地址 192.168.1.102
  33. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  34. //wire define
  35. wire crc_en; //CRC开始校验使能
  36. wire crc_clr; //CRC数据复位信号
  37. wire [ 7:0] crc_d8; //输入待校验8位数据
  38. wire [31:0] crc_data; //CRC校验数据
  39. wire [31:0] crc_next; //CRC下次校验完成数据
  40. //*****************************************************
  41. //** main code
  42. //*****************************************************
  43. assign crc_d8 = gmii_txd;
  44. //以太网接收模块
  45. udp_rx #(
  46. .BOARD_MAC(BOARD_MAC), //参数例化
  47. .BOARD_IP (BOARD_IP)
  48. ) u_udp_rx (
  49. .clk (gmii_rx_clk),
  50. .rst_n (rst_n),
  51. .gmii_rx_dv (gmii_rx_dv),
  52. .gmii_rxd (gmii_rxd),
  53. .rec_pkt_done(rec_pkt_done),
  54. .rec_en (rec_en),
  55. .rec_data (rec_data),
  56. .rec_byte_num(rec_byte_num)
  57. );
  58. //以太网发送模块
  59. udp_tx #(
  60. .BOARD_MAC(BOARD_MAC), //参数例化
  61. .BOARD_IP (BOARD_IP),
  62. .DES_MAC (DES_MAC),
  63. .DES_IP (DES_IP)
  64. ) u_udp_tx (
  65. .clk (gmii_tx_clk),
  66. .rst_n (rst_n),
  67. .tx_start_en(tx_start_en),
  68. .tx_data (tx_data),
  69. .tx_byte_num(tx_byte_num),
  70. .des_mac (des_mac),
  71. .des_ip (des_ip),
  72. .crc_data (crc_data),
  73. .crc_next (crc_next[31:24]),
  74. .tx_done (tx_done),
  75. .tx_req (tx_req),
  76. .gmii_tx_en (gmii_tx_en),
  77. .gmii_txd (gmii_txd),
  78. .crc_en (crc_en),
  79. .crc_clr (crc_clr)
  80. );
  81. //以太网发送CRC校验模块
  82. crc32_d8 u_crc32_d8 (
  83. .clk (gmii_tx_clk),
  84. .rst_n (rst_n),
  85. .data (crc_d8),
  86. .crc_en (crc_en),
  87. .crc_clr (crc_clr),
  88. .crc_data(crc_data),
  89. .crc_next(crc_next)
  90. );
  91. endmodule

3.10.1 以太网数据接收模块

  1. `timescale 1ns / 1ps
  2. //以太网数据接收模块
  3. module udp_rx (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input gmii_rx_dv, //GMII输入数据有效信号
  7. input [ 7:0] gmii_rxd, //GMII输入数据
  8. output reg rec_pkt_done, //以太网单包数据接收完成信号
  9. output reg rec_en, //以太网接收的数据使能信号
  10. output reg [31:0] rec_data, //以太网接收的数据
  11. output reg [15:0] rec_byte_num //以太网接收的有效字数 单位:byte
  12. );
  13. //parameter define
  14. //开发板MAC地址 00-11-22-33-44-55
  15. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  16. //开发板IP地址 192.168.1.10
  17. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd10};
  18. localparam st_idle = 7'b000_0001; //初始状态,等待接收前导码
  19. localparam st_preamble = 7'b000_0010; //接收前导码状态
  20. localparam st_eth_head = 7'b000_0100; //接收以太网帧头
  21. localparam st_ip_head = 7'b000_1000; //接收IP首部
  22. localparam st_udp_head = 7'b001_0000; //接收UDP首部
  23. localparam st_rx_data = 7'b010_0000; //接收有效数据
  24. localparam st_rx_end = 7'b100_0000; //接收结束
  25. localparam ETH_TYPE = 16'h0800; //以太网协议类型 IP协议
  26. //reg define
  27. reg [ 6:0] cur_state;
  28. reg [ 6:0] next_state;
  29. reg skip_en; //控制状态跳转使能信号
  30. reg error_en; //解析错误使能信号
  31. reg [ 4:0] cnt; //解析数据计数器
  32. reg [47:0] des_mac; //目的MAC地址
  33. reg [15:0] eth_type; //以太网类型
  34. reg [31:0] des_ip; //目的IP地址
  35. reg [ 5:0] ip_head_byte_num; //IP首部长度
  36. reg [15:0] udp_byte_num; //UDP长度
  37. reg [15:0] data_byte_num; //数据长度
  38. reg [15:0] data_cnt; //有效数据计数
  39. reg [ 1:0] rec_en_cnt; //8bit转32bit计数器
  40. //*****************************************************
  41. //** main code
  42. //*****************************************************
  43. //(三段式状态机)同步时序描述状态转移
  44. always @(posedge clk or negedge rst_n) begin
  45. if (!rst_n) cur_state <= st_idle;
  46. else cur_state <= next_state;
  47. end
  48. //组合逻辑判断状态转移条件
  49. always @(*) begin
  50. next_state = st_idle;
  51. case (cur_state)
  52. st_idle: begin //等待接收前导码
  53. if (skip_en) next_state = st_preamble;
  54. else next_state = st_idle;
  55. end
  56. st_preamble: begin //接收前导码
  57. if (skip_en) next_state = st_eth_head;
  58. else if (error_en) next_state = st_rx_end;
  59. else next_state = st_preamble;
  60. end
  61. st_eth_head: begin //接收以太网帧头
  62. if (skip_en) next_state = st_ip_head;
  63. else if (error_en) next_state = st_rx_end;
  64. else next_state = st_eth_head;
  65. end
  66. st_ip_head: begin //接收IP首部
  67. if (skip_en) next_state = st_udp_head;
  68. else if (error_en) next_state = st_rx_end;
  69. else next_state = st_ip_head;
  70. end
  71. st_udp_head: begin //接收UDP首部
  72. if (skip_en) next_state = st_rx_data;
  73. else next_state = st_udp_head;
  74. end
  75. st_rx_data: begin //接收有效数据
  76. if (skip_en) next_state = st_rx_end;
  77. else next_state = st_rx_data;
  78. end
  79. st_rx_end: begin //接收结束
  80. if (skip_en) next_state = st_idle;
  81. else next_state = st_rx_end;
  82. end
  83. default: next_state = st_idle;
  84. endcase
  85. end
  86. //时序电路描述状态输出,解析以太网数据
  87. always @(posedge clk or negedge rst_n) begin
  88. if (!rst_n) begin
  89. skip_en <= 1'b0;
  90. error_en <= 1'b0;
  91. cnt <= 5'd0;
  92. des_mac <= 48'd0;
  93. eth_type <= 16'd0;
  94. des_ip <= 32'd0;
  95. ip_head_byte_num <= 6'd0;
  96. udp_byte_num <= 16'd0;
  97. data_byte_num <= 16'd0;
  98. data_cnt <= 16'd0;
  99. rec_en_cnt <= 2'd0;
  100. rec_en <= 1'b0;
  101. rec_data <= 32'd0;
  102. rec_pkt_done <= 1'b0;
  103. rec_byte_num <= 16'd0;
  104. end else begin
  105. skip_en <= 1'b0;
  106. error_en <= 1'b0;
  107. rec_en <= 1'b0;
  108. rec_pkt_done <= 1'b0;
  109. case (next_state)
  110. st_idle: begin
  111. if ((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;
  112. end
  113. st_preamble: begin
  114. if (gmii_rx_dv) begin //解析前导码
  115. cnt <= cnt + 5'd1;
  116. if ((cnt < 5'd6) && (gmii_rxd != 8'h55)) //78'h55
  117. error_en <= 1'b1;
  118. else if (cnt == 5'd6) begin
  119. cnt <= 5'd0;
  120. if (gmii_rxd == 8'hd5) //1个8'hd5
  121. skip_en <= 1'b1;
  122. else error_en <= 1'b1;
  123. end
  124. end
  125. end
  126. st_eth_head: begin
  127. if (gmii_rx_dv) begin
  128. cnt <= cnt + 5'b1;
  129. if (cnt < 5'd6) des_mac <= {des_mac[39:0], gmii_rxd}; //目的MAC地址
  130. else if (cnt == 5'd12) eth_type[15:8] <= gmii_rxd; //以太网协议类型
  131. else if (cnt == 5'd13) begin
  132. eth_type[7:0] <= gmii_rxd;
  133. cnt <= 5'd0;
  134. //判断MAC地址是否为开发板MAC地址或者公共地址
  135. if(((des_mac == BOARD_MAC) ||(des_mac == 48'hff_ff_ff_ff_ff_ff))
  136. && eth_type[15:8] == ETH_TYPE[15:8] && gmii_rxd == ETH_TYPE[7:0])
  137. skip_en <= 1'b1;
  138. else error_en <= 1'b1;
  139. end
  140. end
  141. end
  142. st_ip_head: begin
  143. if (gmii_rx_dv) begin
  144. cnt <= cnt + 5'd1;
  145. if (cnt == 5'd0) ip_head_byte_num <= {gmii_rxd[3:0], 2'd0};
  146. else if ((cnt >= 5'd16) && (cnt <= 5'd18))
  147. des_ip <= {des_ip[23:0], gmii_rxd}; //目的IP地址
  148. else if (cnt == 5'd19) begin
  149. des_ip <= {des_ip[23:0], gmii_rxd};
  150. //判断IP地址是否为开发板IP地址
  151. if ((des_ip[23:0] == BOARD_IP[31:8]) && (gmii_rxd == BOARD_IP[7:0])) begin
  152. if (cnt == ip_head_byte_num - 1'b1) begin
  153. skip_en <= 1'b1;
  154. cnt <= 5'd0;
  155. end
  156. end else begin
  157. //IP错误,停止解析数据
  158. error_en <= 1'b1;
  159. cnt <= 5'd0;
  160. end
  161. end else if (cnt == ip_head_byte_num - 1'b1) begin
  162. skip_en <= 1'b1; //IP首部解析完成
  163. cnt <= 5'd0;
  164. end
  165. end
  166. end
  167. st_udp_head: begin
  168. if (gmii_rx_dv) begin
  169. cnt <= cnt + 5'd1;
  170. if (cnt == 5'd4) udp_byte_num[15:8] <= gmii_rxd; //解析UDP字节长度
  171. else if (cnt == 5'd5) udp_byte_num[7:0] <= gmii_rxd;
  172. else if (cnt == 5'd7) begin
  173. //有效数据字节长度,(UDP首部8个字节,所以减去8
  174. data_byte_num <= udp_byte_num - 16'd8;
  175. skip_en <= 1'b1;
  176. cnt <= 5'd0;
  177. end
  178. end
  179. end
  180. st_rx_data: begin
  181. //接收数据,转换成32bit
  182. if (gmii_rx_dv) begin
  183. data_cnt <= data_cnt + 16'd1;
  184. rec_en_cnt <= rec_en_cnt + 2'd1;
  185. if (data_cnt == data_byte_num - 16'd1) begin
  186. skip_en <= 1'b1; //有效数据接收完成
  187. data_cnt <= 16'd0;
  188. rec_en_cnt <= 2'd0;
  189. rec_pkt_done <= 1'b1;
  190. rec_en <= 1'b1;
  191. rec_byte_num <= data_byte_num;
  192. end
  193. //先收到的数据放在了rec_data的高位,所以当数据不是4的倍数时,
  194. //低位数据为无效数据,可根据有效字节数来判断(rec_byte_num)
  195. if (rec_en_cnt == 2'd0) rec_data[31:24] <= gmii_rxd;
  196. else if (rec_en_cnt == 2'd1) rec_data[23:16] <= gmii_rxd;
  197. else if (rec_en_cnt == 2'd2) rec_data[15:8] <= gmii_rxd;
  198. else if (rec_en_cnt == 2'd3) begin
  199. rec_en <= 1'b1;
  200. rec_data[7:0] <= gmii_rxd;
  201. end
  202. end
  203. end
  204. st_rx_end: begin //单包数据接收完成
  205. if (gmii_rx_dv == 1'b0 && skip_en == 1'b0) skip_en <= 1'b1;
  206. end
  207. default: ;
  208. endcase
  209. end
  210. end
  211. endmodule

3.10.2 以太网数据发送模块

  1. `timescale 1ns / 1ps
  2. //以太网数据发送模块
  3. module udp_tx (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input tx_start_en, //以太网开始发送信号
  7. input [31:0] tx_data, //以太网待发送数据
  8. input [15:0] tx_byte_num, //以太网发送的有效字节数
  9. input [47:0] des_mac, //发送的目标MAC地址
  10. input [31:0] des_ip, //发送的目标IP地址
  11. input [31:0] crc_data, //CRC校验数据
  12. input [ 7:0] crc_next, //CRC下次校验完成数据
  13. output reg tx_done, //以太网发送完成信号
  14. output reg tx_req, //读数据请求信号
  15. output reg gmii_tx_en, //GMII输出数据有效信号
  16. output reg [ 7:0] gmii_txd, //GMII输出数据
  17. output reg crc_en, //CRC开始校验使能
  18. output reg crc_clr //CRC数据复位信号
  19. );
  20. //parameter define
  21. //开发板MAC地址 00-11-22-33-44-55
  22. parameter BOARD_MAC = 48'h00_11_22_33_44_55;
  23. //开发板IP地址 192.168.1.123
  24. parameter BOARD_IP = {8'd192, 8'd168, 8'd1, 8'd123};
  25. //目的MAC地址 ff_ff_ff_ff_ff_ff
  26. parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
  27. //目的IP地址 192.168.1.102
  28. parameter DES_IP = {8'd192, 8'd168, 8'd1, 8'd102};
  29. localparam st_idle = 7'b000_0001; //初始状态,等待开始发送信号
  30. localparam st_check_sum = 7'b000_0010; //IP首部校验和
  31. localparam st_preamble = 7'b000_0100; //发送前导码+帧起始界定符
  32. localparam st_eth_head = 7'b000_1000; //发送以太网帧头
  33. localparam st_ip_head = 7'b001_0000; //发送IP首部+UDP首部
  34. localparam st_tx_data = 7'b010_0000; //发送数据
  35. localparam st_crc = 7'b100_0000; //发送CRC校验值
  36. localparam ETH_TYPE = 16'h0800; //以太网协议类型 IP协议
  37. //以太网数据最小46个字节,IP首部20个字节+UDP首部8个字节
  38. //所以数据至少46-20-8=18个字节
  39. localparam MIN_DATA_NUM = 16'd18;
  40. //reg define
  41. reg [6:0] cur_state;
  42. reg [6:0] next_state;
  43. reg [7:0] preamble[7:0]; //前导码
  44. reg [7:0] eth_head[13:0]; //以太网首部
  45. reg [31:0] ip_head[6:0]; //IP首部 + UDP首部
  46. reg start_en_d0;
  47. reg start_en_d1;
  48. reg [15:0] tx_data_num; //发送的有效数据字节个数
  49. reg [15:0] total_num; //总字节数
  50. reg trig_tx_en;
  51. reg [15:0] udp_num; //UDP字节数
  52. reg skip_en; //控制状态跳转使能信号
  53. reg [4:0] cnt;
  54. reg [31:0] check_buffer; //首部校验和
  55. reg [1:0] tx_bit_sel;
  56. reg [15:0] data_cnt; //发送数据个数计数器
  57. reg tx_done_t;
  58. reg [4:0] real_add_cnt; //以太网数据实际多发的字节数
  59. //wire define
  60. wire pos_start_en; //开始发送数据上升沿
  61. wire [15:0] real_tx_data_num; //实际发送的字节数(以太网最少字节要求)
  62. //*****************************************************
  63. //** main code
  64. //*****************************************************
  65. assign pos_start_en = (~start_en_d1) & start_en_d0;
  66. assign real_tx_data_num = (tx_data_num >= MIN_DATA_NUM) ? tx_data_num : MIN_DATA_NUM;
  67. //采tx_start_en的上升沿
  68. always @(posedge clk or negedge rst_n) begin
  69. if (!rst_n) begin
  70. start_en_d0 <= 1'b0;
  71. start_en_d1 <= 1'b0;
  72. end else begin
  73. start_en_d0 <= tx_start_en;
  74. start_en_d1 <= start_en_d0;
  75. end
  76. end
  77. //寄存数据有效字节
  78. always @(posedge clk or negedge rst_n) begin
  79. if (!rst_n) begin
  80. tx_data_num <= 16'd0;
  81. total_num <= 16'd0;
  82. udp_num <= 16'd0;
  83. end else begin
  84. if (pos_start_en && cur_state == st_idle) begin
  85. //数据长度
  86. tx_data_num <= tx_byte_num;
  87. //IP长度:有效数据+IP首部长度
  88. total_num <= tx_byte_num + 16'd28;
  89. //UDP长度:有效数据+UDP首部长度
  90. udp_num <= tx_byte_num + 16'd8;
  91. end
  92. end
  93. end
  94. //触发发送信号
  95. always @(posedge clk or negedge rst_n) begin
  96. if (!rst_n) trig_tx_en <= 1'b0;
  97. else trig_tx_en <= pos_start_en;
  98. end
  99. always @(posedge clk or negedge rst_n) begin
  100. if (!rst_n) cur_state <= st_idle;
  101. else cur_state <= next_state;
  102. end
  103. always @(*) begin
  104. next_state = st_idle;
  105. case (cur_state)
  106. st_idle: begin //等待发送数据
  107. if (skip_en) next_state = st_check_sum;
  108. else next_state = st_idle;
  109. end
  110. st_check_sum: begin //IP首部校验
  111. if (skip_en) next_state = st_preamble;
  112. else next_state = st_check_sum;
  113. end
  114. st_preamble: begin //发送前导码+帧起始界定符
  115. if (skip_en) next_state = st_eth_head;
  116. else next_state = st_preamble;
  117. end
  118. st_eth_head: begin //发送以太网首部
  119. if (skip_en) next_state = st_ip_head;
  120. else next_state = st_eth_head;
  121. end
  122. st_ip_head: begin //发送IP首部+UDP首部
  123. if (skip_en) next_state = st_tx_data;
  124. else next_state = st_ip_head;
  125. end
  126. st_tx_data: begin //发送数据
  127. if (skip_en) next_state = st_crc;
  128. else next_state = st_tx_data;
  129. end
  130. st_crc: begin //发送CRC校验值
  131. if (skip_en) next_state = st_idle;
  132. else next_state = st_crc;
  133. end
  134. default: next_state = st_idle;
  135. endcase
  136. end
  137. //发送数据
  138. always @(posedge clk or negedge rst_n) begin
  139. if (!rst_n) begin
  140. skip_en <= 1'b0;
  141. cnt <= 5'd0;
  142. check_buffer <= 32'd0;
  143. ip_head[1][31:16] <= 16'd0;
  144. tx_bit_sel <= 2'b0;
  145. crc_en <= 1'b0;
  146. gmii_tx_en <= 1'b0;
  147. gmii_txd <= 8'd0;
  148. tx_req <= 1'b0;
  149. tx_done_t <= 1'b0;
  150. data_cnt <= 16'd0;
  151. real_add_cnt <= 5'd0;
  152. //初始化数组
  153. //前导码 7个8'h55 + 18'hd5
  154. preamble[0] <= 8'h55;
  155. preamble[1] <= 8'h55;
  156. preamble[2] <= 8'h55;
  157. preamble[3] <= 8'h55;
  158. preamble[4] <= 8'h55;
  159. preamble[5] <= 8'h55;
  160. preamble[6] <= 8'h55;
  161. preamble[7] <= 8'hd5;
  162. //目的MAC地址
  163. eth_head[0] <= DES_MAC[47:40];
  164. eth_head[1] <= DES_MAC[39:32];
  165. eth_head[2] <= DES_MAC[31:24];
  166. eth_head[3] <= DES_MAC[23:16];
  167. eth_head[4] <= DES_MAC[15:8];
  168. eth_head[5] <= DES_MAC[7:0];
  169. //源MAC地址
  170. eth_head[6] <= BOARD_MAC[47:40];
  171. eth_head[7] <= BOARD_MAC[39:32];
  172. eth_head[8] <= BOARD_MAC[31:24];
  173. eth_head[9] <= BOARD_MAC[23:16];
  174. eth_head[10] <= BOARD_MAC[15:8];
  175. eth_head[11] <= BOARD_MAC[7:0];
  176. //以太网类型
  177. eth_head[12] <= ETH_TYPE[15:8];
  178. eth_head[13] <= ETH_TYPE[7:0];
  179. end else begin
  180. skip_en <= 1'b0;
  181. tx_req <= 1'b0;
  182. crc_en <= 1'b0;
  183. gmii_tx_en <= 1'b0;
  184. tx_done_t <= 1'b0;
  185. case (next_state)
  186. st_idle: begin
  187. if (trig_tx_en) begin
  188. skip_en <= 1'b1;
  189. //版本号:4 首部长度:5(单位:32bit,20byte/4=5)
  190. ip_head[0] <= {8'h45, 8'h00, total_num};
  191. //16位标识,每次发送累加1
  192. ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;
  193. //bit[15:13]: 010表示不分片
  194. ip_head[1][15:0] <= 16'h4000;
  195. //协议:17(udp)
  196. ip_head[2] <= {8'h40, 8'd17, 16'h0};
  197. //源IP地址
  198. ip_head[3] <= BOARD_IP;
  199. //目的IP地址
  200. if (des_ip != 32'd0) ip_head[4] <= des_ip;
  201. else ip_head[4] <= DES_IP;
  202. //16位源端口号:1234 16位目的端口号:1234
  203. ip_head[5] <= {16'd1234, 16'd1234};
  204. //16位udp长度,16位udp校验和
  205. ip_head[6] <= {udp_num, 16'h0000};
  206. //更新MAC地址
  207. if (des_mac != 48'b0) begin
  208. //目的MAC地址
  209. eth_head[0] <= des_mac[47:40];
  210. eth_head[1] <= des_mac[39:32];
  211. eth_head[2] <= des_mac[31:24];
  212. eth_head[3] <= des_mac[23:16];
  213. eth_head[4] <= des_mac[15:8];
  214. eth_head[5] <= des_mac[7:0];
  215. end
  216. end
  217. end
  218. st_check_sum: begin //IP首部校验
  219. cnt <= cnt + 5'd1;
  220. if (cnt == 5'd0) begin
  221. check_buffer <= ip_head[0][31:16] + ip_head[0][15:0]
  222. + ip_head[1][31:16] + ip_head[1][15:0]
  223. + ip_head[2][31:16] + ip_head[2][15:0]
  224. + ip_head[3][31:16] + ip_head[3][15:0]
  225. + ip_head[4][31:16] + ip_head[4][15:0];
  226. end else if (cnt == 5'd1) //可能出现进位,累加一次
  227. check_buffer <= check_buffer[31:16] + check_buffer[15:0];
  228. else if (cnt == 5'd2) begin //可能再次出现进位,累加一次
  229. check_buffer <= check_buffer[31:16] + check_buffer[15:0];
  230. end else if (cnt == 5'd3) begin //按位取反
  231. skip_en <= 1'b1;
  232. cnt <= 5'd0;
  233. ip_head[2][15:0] <= ~check_buffer[15:0];
  234. end
  235. end
  236. st_preamble: begin //发送前导码+帧起始界定符
  237. gmii_tx_en <= 1'b1;
  238. gmii_txd <= preamble[cnt];
  239. if (cnt == 5'd7) begin
  240. skip_en <= 1'b1;
  241. cnt <= 5'd0;
  242. end else cnt <= cnt + 5'd1;
  243. end
  244. st_eth_head: begin //发送以太网首部
  245. gmii_tx_en <= 1'b1;
  246. crc_en <= 1'b1;
  247. gmii_txd <= eth_head[cnt];
  248. if (cnt == 5'd13) begin
  249. skip_en <= 1'b1;
  250. cnt <= 5'd0;
  251. end else cnt <= cnt + 5'd1;
  252. end
  253. st_ip_head: begin //发送IP首部 + UDP首部
  254. crc_en <= 1'b1;
  255. gmii_tx_en <= 1'b1;
  256. tx_bit_sel <= tx_bit_sel + 2'd1;
  257. if (tx_bit_sel == 3'd0) gmii_txd <= ip_head[cnt][31:24];
  258. else if (tx_bit_sel == 3'd1) gmii_txd <= ip_head[cnt][23:16];
  259. else if (tx_bit_sel == 3'd2) begin
  260. gmii_txd <= ip_head[cnt][15:8];
  261. if (cnt == 5'd6) begin
  262. //提前读请求数据,等待数据有效时发送
  263. tx_req <= 1'b1;
  264. end
  265. end else if (tx_bit_sel == 3'd3) begin
  266. gmii_txd <= ip_head[cnt][7:0];
  267. if (cnt == 5'd6) begin
  268. skip_en <= 1'b1;
  269. cnt <= 5'd0;
  270. end else cnt <= cnt + 5'd1;
  271. end
  272. end
  273. st_tx_data: begin //发送数据
  274. crc_en <= 1'b1;
  275. gmii_tx_en <= 1'b1;
  276. tx_bit_sel <= tx_bit_sel + 3'd1;
  277. if (data_cnt < tx_data_num - 16'd1) data_cnt <= data_cnt + 16'd1;
  278. else if (data_cnt == tx_data_num - 16'd1) begin
  279. //如果发送的有效数据少于18个字节,在后面填补充位
  280. //补充的值为最后一次发送的有效数据
  281. gmii_txd <= 8'd0;
  282. if (data_cnt + real_add_cnt < real_tx_data_num - 16'd1)
  283. real_add_cnt <= real_add_cnt + 5'd1;
  284. else begin
  285. skip_en <= 1'b1;
  286. data_cnt <= 16'd0;
  287. real_add_cnt <= 5'd0;
  288. tx_bit_sel <= 3'd0;
  289. end
  290. end
  291. if (tx_bit_sel == 1'b0) gmii_txd <= tx_data[31:24];
  292. else if (tx_bit_sel == 3'd1) gmii_txd <= tx_data[23:16];
  293. else if (tx_bit_sel == 3'd2) begin
  294. gmii_txd <= tx_data[15:8];
  295. if (data_cnt != tx_data_num - 16'd1) tx_req <= 1'b1;
  296. end else if (tx_bit_sel == 3'd3) gmii_txd <= tx_data[7:0];
  297. end
  298. st_crc: begin //发送CRC校验值
  299. gmii_tx_en <= 1'b1;
  300. tx_bit_sel <= tx_bit_sel + 3'd1;
  301. if (tx_bit_sel == 3'd0)
  302. gmii_txd <= {
  303. ~crc_next[0],
  304. ~crc_next[1],
  305. ~crc_next[2],
  306. ~crc_next[3],
  307. ~crc_next[4],
  308. ~crc_next[5],
  309. ~crc_next[6],
  310. ~crc_next[7]
  311. };
  312. else if (tx_bit_sel == 3'd1)
  313. gmii_txd <= {
  314. ~crc_data[16],
  315. ~crc_data[17],
  316. ~crc_data[18],
  317. ~crc_data[19],
  318. ~crc_data[20],
  319. ~crc_data[21],
  320. ~crc_data[22],
  321. ~crc_data[23]
  322. };
  323. else if (tx_bit_sel == 3'd2) begin
  324. gmii_txd <= {
  325. ~crc_data[8],
  326. ~crc_data[9],
  327. ~crc_data[10],
  328. ~crc_data[11],
  329. ~crc_data[12],
  330. ~crc_data[13],
  331. ~crc_data[14],
  332. ~crc_data[15]
  333. };
  334. end else if (tx_bit_sel == 3'd3) begin
  335. gmii_txd <= {
  336. ~crc_data[0],
  337. ~crc_data[1],
  338. ~crc_data[2],
  339. ~crc_data[3],
  340. ~crc_data[4],
  341. ~crc_data[5],
  342. ~crc_data[6],
  343. ~crc_data[7]
  344. };
  345. tx_done_t <= 1'b1;
  346. skip_en <= 1'b1;
  347. end
  348. end
  349. default: ;
  350. endcase
  351. end
  352. end
  353. //发送完成信号及crc值复位信号
  354. always @(posedge clk or negedge rst_n) begin
  355. if (!rst_n) begin
  356. tx_done <= 1'b0;
  357. crc_clr <= 1'b0;
  358. end else begin
  359. tx_done <= tx_done_t;
  360. crc_clr <= tx_done_t;
  361. end
  362. end
  363. endmodule

3.10.3 CRC32校验模块

  1. `timescale 1ns / 1ps
  2. //CRC32校验模块
  3. module crc32_d8 (
  4. input clk, //时钟信号
  5. input rst_n, //复位信号,低电平有效
  6. input [ 7:0] data, //输入待校验8位数据
  7. input crc_en, //crc使能,开始校验标志
  8. input crc_clr, //crc数据复位信号
  9. output reg [31:0] crc_data, //CRC校验数据
  10. output [31:0] crc_next //CRC下次校验完成数据
  11. );
  12. //*****************************************************
  13. //** main code
  14. //*****************************************************
  15. //输入待校验8位数据,需要先将高低位互换
  16. wire [7:0] data_t;
  17. assign data_t = {data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]};
  18. //CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11
  19. //+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
  20. assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];
  21. assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31]
  22. ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];
  23. assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30]
  24. ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6]
  25. ^ data_t[7];
  26. assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31]
  27. ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];
  28. assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]
  29. ^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4]
  30. ^ data_t[6];
  31. assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28]
  32. ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0]
  33. ^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6]
  34. ^ data_t[7];
  35. assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29]
  36. ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4]
  37. ^ data_t[5] ^ data_t[6] ^ data_t[7];
  38. assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29]
  39. ^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5]
  40. ^ data_t[7];
  41. assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]
  42. ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
  43. assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28]
  44. ^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];
  45. assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27]
  46. ^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];
  47. assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]
  48. ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
  49. assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26]
  50. ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0]
  51. ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];
  52. assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27]
  53. ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1]
  54. ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];
  55. assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]
  56. ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]
  57. ^ data_t[6] ^ data_t[7];
  58. assign crc_next[15] = crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]
  59. ^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];
  60. assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29]
  61. ^ data_t[0] ^ data_t[4] ^ data_t[5];
  62. assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30]
  63. ^ data_t[1] ^ data_t[5] ^ data_t[6];
  64. assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31]
  65. ^ data_t[2] ^ data_t[6] ^ data_t[7];
  66. assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];
  67. assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];
  68. assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];
  69. assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];
  70. assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30]
  71. ^ data_t[0] ^ data_t[1] ^ data_t[6];
  72. assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31]
  73. ^ data_t[1] ^ data_t[2] ^ data_t[7];
  74. assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];
  75. assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28]
  76. ^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];
  77. assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29]
  78. ^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];
  79. assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30]
  80. ^ data_t[2] ^ data_t[5] ^ data_t[6];
  81. assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31]
  82. ^ data_t[3] ^ data_t[6] ^ data_t[7];
  83. assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];
  84. assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];
  85. always @(posedge clk or negedge rst_n) begin
  86. if (!rst_n) crc_data <= 32'hff_ff_ff_ff;
  87. else if (crc_clr) //CRC校验值复位
  88. crc_data <= 32'hff_ff_ff_ff;
  89. else if (crc_en) crc_data <= crc_next;
  90. end
  91. endmodule

3.11 以太网控制模块

  1. `timescale 1ns / 1ps
  2. //以太网控制模块
  3. module eth_ctrl (
  4. input clk, //系统时钟
  5. input rst_n, //系统复位信号,低电平有效
  6. //ARP相关端口信号
  7. input arp_rx_done, //ARP接收完成信号
  8. input arp_rx_type, //ARP接收类型 0:请求 1:应答
  9. output arp_tx_en, //ARP发送使能信号
  10. output arp_tx_type, //ARP发送类型 0:请求 1:应答
  11. input arp_tx_done, //ARP发送完成信号
  12. input arp_gmii_tx_en, //ARP GMII输出数据有效信号
  13. input [7:0] arp_gmii_txd, //ARP GMII输出数据
  14. //UDP相关端口信号
  15. input udp_gmii_tx_en, //UDP GMII输出数据有效信号
  16. input [7:0] udp_gmii_txd, //UDP GMII输出数据
  17. //GMII发送引脚
  18. output gmii_tx_en, //GMII输出数据有效信号
  19. output [7:0] gmii_txd //UDP GMII输出数据
  20. );
  21. //reg define
  22. reg protocol_sw; //协议切换信号
  23. //*****************************************************
  24. //** main code
  25. //*****************************************************
  26. assign arp_tx_en = arp_rx_done && (arp_rx_type == 1'b0);
  27. assign arp_tx_type = 1'b1; //ARP发送类型固定为ARP应答
  28. assign gmii_tx_en = protocol_sw ? udp_gmii_tx_en : arp_gmii_tx_en;
  29. assign gmii_txd = protocol_sw ? udp_gmii_txd : arp_gmii_txd;
  30. //根据ARP发送使能/完成信号,切换GMII引脚
  31. always @(posedge clk or negedge rst_n) begin
  32. if (!rst_n) protocol_sw <= 1'b1;
  33. else if (arp_tx_en) protocol_sw <= 1'b0;
  34. else if (arp_tx_done) protocol_sw <= 1'b1;
  35. end
  36. endmodule

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/505277
推荐阅读
相关标签
  

闽ICP备14008679号