0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA之HDMI与以太网篇分享

FPGA技术江湖 来源:FPGA技术江湖 2023-04-06 09:22 次阅读

一、HDMI

1.1 、HDMI介绍

高清多媒体接口(High Definition Multimedia Interface)是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。HDMI可用于机顶盒、DVD播放机、个人计算机、电视、游戏主机、综合扩大机、数字音响与电视机等设备。HDMI可以同时发送音频和视频信号,由于音频和视频信号采用同一条线材,大大简化系统线路的安装难度。

HDMI是被设计来取代较旧的模拟信号影音发送接口如SCART或RCA等端子的。它支持各类电视与计算机视频格式,包括SDTV、HDTV视频画面,再加上多声道数字音频。HDMI与去掉音频传输功能的UDI都继承DVI的核心技术“传输最小化差分信号”TMDS,从本质上来说仍然是DVI的扩展。DVI、HDMI、UDI的视频内容都以即时、专线方式进行传输,这可以保证视频流量大时不会发生堵塞的现象。每个像素数据量为24位。信号的时序与VGA极为类似。

1.1.1、HDMI接口

HDMI 1.0版本于2002年发布,最高数据传输速度为5Gbps;而2017年发布的HDMI 2.1标准的理论带宽可达48Gbps。HDMI的规格书中规定了四种HDMI接口。HDMI向下兼容DVI,但是DVI(数字视频接口)只能用于传输视频,而不能同时传输音频,这是两者最大的区别。此外,DVI接口的尺寸明显大于HDMI接口,

右侧是最常见的A型HDMI接口,其引脚定义如下图:

53ec8df6-d418-11ed-bfe3-dac502259ad0.png

图1.2.2HDMI接口引脚图

DVI和HDMI接口协议在物理层使用TMDS标准传输音视频数据。

1.1.2 、TMDS介绍

TMDS(Transition Minimized Differential Signaling,最小化传输差分信号)是美国Silicon Image公司开发的一项高速数据传输技术,在DVI和HDMI视频接口中使用差分信号传输高速串行数据。TMDS差分传输技术使用两个引脚(如图21.1.2中的“数据2+”和“数据2-”)来传输一路信号,利用这两个引脚间的电压差的正负极性和大小来决定传输数据的数值(0或1)。

DVI或HDMI视频传输所使用的TMDS连接通过四个串行通道实现。对于DVI来说,其中三个通道分别用于传输视频中每个像素点的红、绿、蓝三个颜色分量(RGB4:4:4格式)。HDMI默认也是使用三个RGB通道,但是它同样可以选择传输像素点的亮度和色素信息(YCrCb44或YCrCb42格式)。第四个通道是时钟通道,用于传输像素时钟。独立的TMDS时钟通道为接收端提供接收的参考频率,保证数据在接收端能够正确恢复。

540ade8c-d418-11ed-bfe3-dac502259ad0.png

图1.3.1 、TMDS连接示意图

如果每个像素点的颜色深度为24位,即RGB每个颜色分量各占8位,那么每个通道上的颜色数据将通过一个8B/10B的编码器(Encoder)来转换成一个10位的像素字符。然后这个10位的字符通过并串转换器(Serializer)转换成串行数据,最后由TMDS数据通道发送出去。这个10:1的并转串过程所生成的串行数据速率是实际像素时钟速率的10倍。

在传输视频图像的过程中,数据通道上传输的是编码后的有效像素字符。而在每一帧图像的行与行之间,以及视频中不同帧之间的时间间隔(消隐期)内,数据通道上传输的则是控制字符。每个通道上有两位控制信号的输入接口,共对应四种不同的控制字符。这些控制字符提供了视频的行同步(HZYNC)以及帧同步(VSYNC)信息,也可以用来指定所传输数据的边界(用于同步)。

对于DVI传输,整个视频的消隐期都用来传输控制字符。而HDMI传输的消隐期除了控制字符之外,还可以用于传输音频或者其他附加数据,比如字幕信息等。这就是DVI和HDMI协议之间最主要的差别。从图1.3.1中也可以看出这一差别,即“Auxiliary Data”接口标有“HDMI Olny”,即它是HDMI所独有的接口。

从前面的介绍中我们可以看出,TMDS连接从逻辑功能上可以划分成两个阶段:编码和并串转换。在编码阶段,编码器将视频源中的像素数据、HDMI的音频/附加数据,以及行同步和场同步信号分别编码成10位的字符流。然后在并串转换阶段将上述的字符流转换成串行数据流,并将其从三个差分输出通道发送出去。

DVI编码器在视频有效数据段输出像素数据,在消隐期输出控制数据,如图1.3.2所示。其中VDE(Video Data Enable)为高电平时表示视频数据有效,为低电平代表当前处于视频消隐期。

542d6826-d418-11ed-bfe3-dac502259ad0.png

图1.3.2DVI编码输出示意图

图1.3.3给出了三个通道的DVI编码器示意图。对于像素数据的RGB三个颜色通道,编码器的逻辑是完全相同的。VDE用于各个通道选择输出视频像素数据还是控制数据。HSYNC和VSYNC信号在蓝色通道进行编码得到10位字符,然后在视频消隐期传输。绿色和红色通道的控制信号C0和C1同样需要进行编码,并在消隐期输出。但是DVI规范中这两个通道的控制信号是预留的(未用到),因此将其置为2‘b00。

543ee736-d418-11ed-bfe3-dac502259ad0.png

图1.3.3 DVI编码示意图

每个通道输入的视频像素数据都要使用DVI规范中的TMDS编码算法进行编码。每个8-bit的数据都将被转换成460个特定10-bit字符中的一个。这个编码机制大致上实现了传输过程中的直流平衡,即一段时间内传输的高电平(数字“1”)的个数大致等于低电平(数字“0”)的个数。同时,每个编码后的10-bit字符中状态跳转(“由1到0”或者“由0到1”)的次数将被限制在五次以内。

除了视频数据之外,每个通道2-bit控制信号的状态也要进行编码,编码后分别对应四个不同的10-bit控制字符,分别是10'b1101010100,10'b0010101011,10'b0101010100,和10'b1010101011。可以看出,每个控制字符都有七次以上的状态跳转。视频字符和控制字符状态跳转次数的不同将会被用于发送和接收设备的同步。

HDMI协议与DVI协议在很多方面都是相同的,包括物理连接(TMDS)、有效视频编码算法以及控制字符的定义等。但是相比于DVI,HDMI在视频的消隐期会传输更多的数据,包括音频数据和附加数据。4-bit音频和附加数据将通过TERC4编码机制转换成10-bit TERC4字符,然后在绿色和红色通道上传输。

HDMI在输入附加数据的同时,还需要输入ADE(Aux/Audio Data Enable)信号,其作用和VDE是类似的:当ADE为高电平时,表明输入端的附加数据或者音频数据有效。如果大家想了解更多有关HDMI的细节,可以参考开发板资料(A盘)/8_FPGA参考资料/HDMI/《HDMI Specification 13a》。为了简单起见,我们在这里把HDMI接口当作DVI接口进行驱动。

在编码之后,3个通道的10-bit字符将进行并串转换,这一过程是使用7系列FPGA中专用的硬件资源来实现的。7系列的FPGA提供了专用的并串转换器——OSERDESE2。单一的OSERDESE2模块可以实现8:1的并串转换,通过位宽扩展可以实现10:1和14:1的转换率。

5451ef20-d418-11ed-bfe3-dac502259ad0.png

5466ebdc-d418-11ed-bfe3-dac502259ad0.png

548a92e4-d418-11ed-bfe3-dac502259ad0.png

1.2 HDMI设计思路

对于HDMI,和之前VGA项目差不多,可以通过修改VGA的驱动代码,来实现HDMI的驱动,修改其中的分辨率和时钟,即可完成。

对于HDMI来说,需要将信号转为差分对,再将并转为串。

1.3 代码

modulehdmi_driver(

inputwireclk,
inputwirerst_n,
outputwireVSYNC,
outputwireHSYNC,
outputwire[23:0]RGB,
outputwireen_display
);

parameterH_A=40;
parameterH_B=220;
parameterH_C=1280;
parameterH_D=110;
parameterH_E=1650;

parameterV_A=5;
parameterV_B=20;
parameterV_C=720;
parameterV_D=5;
parameterV_E=750;

reg[10:0]cnt_h;
reg[9:0]cnt_v;
wireen_h;//显示列的C段有效标志信�?
wireen_v;//显示行的C段有效标志信�?

wireaddr_en_h;
wireaddr_en;


always@(posedgeclk,negedgerst_n)
begin
if(rst_n==1'b0)
cnt_h<= 11'd0;
    else if(cnt_h == H_E - 1)
      cnt_h <= 11'd0;
    else
      cnt_h <= cnt_h + 1'b1;
  end
  
  always @ (posedge clk, negedge rst_n)
  begin
    if(rst_n == 1'b0)
      cnt_v <= 10'd0;
    else if(cnt_h == H_E - 1)
      begin
        if(cnt_v == V_E - 1)
          cnt_v <= 10'd0;
        else
          cnt_v <= cnt_v + 1'b1;
      end
    else
      cnt_v <= cnt_v;
  end
  
  assign HSYNC = (cnt_h < H_A) ? 1'b0 : 1'b1;
  assign VSYNC = (cnt_v < V_A) ? 1'b0 : 1'b1;
 
  assign en_h = (cnt_h >=H_A+H_B&&cnt_h< H_A + H_B + H_C) ? 1'b1 : 1'b0;
  assign en_v = (cnt_v >=V_A+V_B&&cnt_v< V_A + V_B + V_C) ? 1'b1 : 1'b0;
  
//  assign en_h = (cnt_h >=566&&cnt_h< 666) ? 1'b1 : 1'b0;
//  assign en_v = (cnt_v >=277&&cnt_v< 377) ? 1'b1 : 1'b0;
  
//  assign addr_en_h = (cnt_h >=565&&cnt_h< 665) ? 1'b1 : 1'b0;
//  assign addr_en = (addr_en_h && en_v) ? 1'b1 : 1'b0;
  
  assign en_display = (en_h && en_v) ? 1'b1 : 1'b0;
  
  assign RGB = (en_display) ? 24'b11111111_11111111_11111111 : 24'd0;
/*
  always @ (posedge clk, negedge rst_n)
  begin
    if(rst_n == 1'b0)
      addr <= 14'd0;
    else if(addr_en)
      begin
        if(addr == 14'd9999)
          addr <= 14'd0;
        else
          addr <= addr + 1'b1;
      end
    else
      addr <= addr;
  end
  */
//  assign RGB = (en_display) ? q : 8'd0;

endmodule 

Top顶层模块

moduletop(

inputclk,
inputrst_n,

outputD0_P,
outputD0_N,
outputD1_P,
outputD1_N,
outputD2_P,
outputD2_N,
outputD3_P,
outputD3_N
);
wireVSYNC;
wireHSYNC;
wire[23:0]RGB;
wireen_display;
wireclk_1;
wireclk_5;
wirelocked;
wireR_b;
wireG_b;
wireB_b;
wireclk_b;
wire[9:0]G,B,R;

pllinstance_name
(
//Clockoutports
.clk_out1(clk_1),//outputclk_out1
.clk_out2(clk_5),//outputclk_out2
//Statusandcontrolsignals
.reset(~rst_n),//inputreset
.locked(locked),//outputlocked
//Clockinports
.clk_in1(clk));//inputclk_in1



vga_drivervga_driver_inst(

.clk(clk_1),
.rst_n(locked),

.VSYNC(VSYNC),
.HSYNC(HSYNC),
.RGB(RGB),
.en_display(en_display)
);

dvi_encoderdvi_encoder_inst0(
.clkin(clk_1),//pixelclockinput
.rstin(~locked),//async.resetinput(activehigh)
.din(RGB[23:16]),//datainputs:expectregistered
.c0(1'b0),//c0input
.c1(1'b0),//c1input
.de(en_display),//deinput
.dout(R)//dataoutputs
);

serializer_10_to_1serializer_10_to_1_inst0(
.reset(~locked),//
.paralell_clk(clk_1),//
.serial_clk_5x(clk_5),//
.paralell_data(R),//
.serial_data_out(R_b)//
);
OBUFDSOBUFDS_inst0(
.O(D2_P),//1-bitoutput:Diff_poutput(connectdirectlytotop-levelport)
.OB(D2_N),//1-bitoutput:Diff_noutput(connectdirectlytotop-levelport)
.I(R_b)//1-bitinput:Bufferinput
);

dvi_encoderdvi_encoder_inst1(
.clkin(clk_1),//pixelclockinput
.rstin(~locked),//async.resetinput(activehigh)
.din(RGB[15:8]),//datainputs:expectregistered
.c0(1'b0),//c0input
.c1(1'b0),//c1input
.de(en_display),//deinput
.dout(G)//dataoutputs
);

serializer_10_to_1serializer_10_to_1_inst1(
.reset(~locked),//
.paralell_clk(clk_1),//
.serial_clk_5x(clk_5),//
.paralell_data(G),//

.serial_data_out(G_b)//
);
OBUFDSOBUFDS_inst1(
.O(D1_P),//1-bitoutput:Diff_poutput(connectdirectlytotop-levelport)
.OB(D1_N),//1-bitoutput:Diff_noutput(connectdirectlytotop-levelport)
.I(G_b)//1-bitinput:Bufferinput
);


dvi_encoderdvi_encoder_inst2(
.clkin(clk_1),//pixelclockinput
.rstin(~locked),//async.resetinput(activehigh)
.din(RGB[7:0]),//datainputs:expectregistered
.c0(HSYNC),//c0input
.c1(VSYNC),//c1input
.de(en_display),//deinput
.dout(B)//dataoutputs
);

serializer_10_to_1serializer_10_to_1_inst2(
.reset(~locked),
.paralell_clk(clk_1),//
.serial_clk_5x(clk_5),//
.paralell_data(B),//

.serial_data_out(B_b)//
);
OBUFDSOBUFDS_inst2(
.O(D0_P),//
.OB(D0_N),//
.I(B_b)//
);
serializer_10_to_1serializer_10_to_1_inst3(
.reset(~locked),
.paralell_clk(clk_1),//
.serial_clk_5x(clk_5),//
.paralell_data(10'b11111_00000),

.serial_data_out(clk_b)//
);
OBUFDSOBUFDS_inst3(
.O(D3_P),//1-bitoutput:Diff_poutput(connectdirectlytotop-levelport)
.OB(D3_N),//1-bitoutput:Diff_noutput(connectdirectlytotop-levelport)
.I(clk_b)//1-bitinput:Bufferinput
);
endmodule

对于其他模块,都是进行调用,并没有自己编写,即不再简述。

二、以太网

2.1 、UDP数据包介绍

54ab43f4-d418-11ed-bfe3-dac502259ad0.png

2.2 、MAC协议

54cc2786-d418-11ed-bfe3-dac502259ad0.png

2.3 、IP协议

54ecc3e2-d418-11ed-bfe3-dac502259ad0.png

2.4 、UDP协议

550c2282-d418-11ed-bfe3-dac502259ad0.png

2.5 、代码

以下代码即为UDP发送模块。

moduleeth_tx(

inputwireclk,
inputwirerst_n,
inputwirekey,

outputreggmii_tx_en,
outputwiregmii_tx_er,
outputwiregmii_tx_clk,
outputreg[7:0]gmii_tx_data

);
//88-A4-C2-E5-D3-66{8'h8c,8'h82,8'hb9,8'h95,8'h10,8'hcc};
parameterPC_MAC={8'h88,8'ha4,8'hc2,8'he5,8'hd3,8'h66};
parameterBOARD_MAC={8'h88,8'ha4,8'hc2,8'he5,8'hd3,8'h67};
parameterPC_IP={8'd192,8'd168,8'd0,8'd2};
parameterBOARD_IP={8'd192,8'd168,8'd0,8'd3};
parameterPC_COM=16'd65533;
parameterBOARD_COM=16'd65531;



wireclk_125m;
wirelocked;
wireflag;
wireneg_edge;
regi_en;
regi_init;
wire[31:0]crc;
wire[31:0]crc_new;
reg[63:0]send_buf;
reg[4:0]state;
reg[9:0]send_cnt;
wirekey_flag;
wire[31:0]IP_HEAD1;
wire[31:0]IP_HEAD2;
wire[31:0]IP_HEAD3;
wire[15:0]DATA_LEN;
wire[15:0]UDP_LEN;
wire[15:0]IP_HEAD_LEN;
wire[15:0]IP_HEAD_SUM;
wire[31:0]IP_HEAD_SUM1;

assigngmii_tx_clk=clk_125m;
assigngmii_tx_er=1'b0;
assignDATA_LEN=16'd24;
assignUDP_LEN=DATA_LEN+16'd8;
assignIP_HEAD_LEN=UDP_LEN+16'd20;
assignIP_HEAD1={8'h45,8'd0,IP_HEAD_LEN};
assignIP_HEAD2=32'd0;
assignIP_HEAD3={8'hff,8'd17,IP_HEAD_SUM};
assignIP_HEAD_SUM1=IP_HEAD1[31:16]+IP_HEAD1[15:0]+IP_HEAD3[31:16]+PC_IP[31:16]+PC_IP[15:0]+BOARD_IP[31:16]+BOARD_IP[15:0];
assignIP_HEAD_SUM=~(IP_HEAD_SUM1[31:16]+IP_HEAD_SUM1[15:0]);

my_pllmy_pll_inst(
.areset(~rst_n),
.inclk0(clk),
.c0(clk_125m),
.locked(locked)
);

jitterjitter_inst(

.clk(clk_125m),
.rst_n(locked),
.key(key),

.flag(flag)
);

neg_edgeneg_edge_inst(

.clk(clk_125m),
.rst_n(locked),
.flag(flag),

.neg_edge(neg_edge)
);

CRC32_D8CRC32_D8_inst(
.clk(clk_125m),
.rst_n(locked),
.i_en(i_en),
.i_data(gmii_tx_data),
.i_init(i_init),

.crc(crc),
.crc_new(crc_new)
);

always@(posedgeclk_125m)
begin
if(locked==1'b0)
begin
gmii_tx_data<= 8'd0;
        gmii_tx_en <= 1'b0;
        state <= 5'd0;
        i_en <= 1'b0;
        i_init <= 1'b0;
        send_buf <= 64'd0;
        send_cnt <= 10'd0;
      end
    else
      case (state)
        5'd0 :  begin
                  if (neg_edge)
                    state <= 5'd1;
                  else
                    state <= 5'd0;
                end
        5'd1 :  begin
                  state <= 5'd2;
                  i_init <= 1'b1;
                  send_buf <= {{7{8'h55}},8'hd5};
                end 
        5'd2 :  begin
                  i_init <= 1'b0;
                  gmii_tx_en <= 1'b1;
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {PC_MAC,16'd0};
                      state <= 5'd3;
                    end
                end
        5'd3 :  begin
                    i_en <= 1'b1;
                    if(send_cnt < 10'd5)
                      begin
                        send_cnt <= send_cnt + 1'b1;
                        gmii_tx_data <= send_buf[63:56];
                        send_buf <= {send_buf[55:0],send_buf[63:56]};
                      end
                    else
                      begin
                        send_cnt <= 10'd0;
                        gmii_tx_data <= send_buf[63:56];
                        send_buf <= {BOARD_MAC,16'h0800};
                        state <= 5'd4;
                      end
                end
        5'd4  : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {IP_HEAD1,IP_HEAD2};
                      state <= 5'd5;
                    end
                end
        5'd5  : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {IP_HEAD3,BOARD_IP};
                      state <= 5'd6;
                    end
                end
        5'd6  : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {PC_IP,BOARD_COM,PC_COM};
                      state <= 5'd7;
                    end
                end
        5'd7  : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {UDP_LEN,16'd0,32'd0};
                      state <= 5'd8;
                    end
                end
        5'd8  : begin
                  if(send_cnt < 10'd3)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= "Hello!!!";
                      state <= 5'd9;
                    end
                end
        5'd9  : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= "World!!!";
                      state <= 5'd10;
                    end
                end
        5'd10 : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= "Lichuang";
                      state <= 5'd11;
                    end
                end
        5'd11 : begin
                  if(send_cnt < 10'd7)
                    begin
                      send_cnt <= send_cnt + 1'b1;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= {send_buf[55:0],send_buf[63:56]};
                    end
                  else
                    begin
                      send_cnt <= 10'd0;
                      gmii_tx_data <= send_buf[63:56];
                      send_buf <= 64'd0;
                      state <= 5'd12;
                    end
                end
        5'd12 : begin   
                  i_en <= 1'b0;
                  gmii_tx_data <= ~{crc_new[24],crc_new[25],crc_new[26],crc_new[27],crc_new[28],crc_new[29],crc_new[30],crc_new[31]};
                  state <= 5'd13;
                end
        5'd13 : begin   
                  i_en <= 1'b0;
                  gmii_tx_data <= ~{crc[16],crc[17],crc[18],crc[19],crc[20],crc[21],crc[22],crc[23]};
                  state <= 5'd14;
                end
        5'd14 : begin   
                  i_en <= 1'b0;
                  gmii_tx_data <= ~{crc[8],crc[9],crc[10],crc[11],crc[12],crc[13],crc[14],crc[15]};
                  state <= 5'd15;
                end
        5'd15 : begin   
                  i_en <= 1'b0;
                  gmii_tx_data <= ~{crc[0],crc[1],crc[2],crc[3],crc[4],crc[5],crc[6],crc[7]};
                  state <= 5'd16;
                end
        5'd16 : begin
                  gmii_tx_en <= 1'b0;
                  state <= 5'd0;
                end
        default: ;
      endcase
  end

endmodule
5526cc40-d418-11ed-bfe3-dac502259ad0.png

以下为发送模块代码:

moduleeth_rx(

inputwirerx_clk,
inputwirerst_n,
inputwirerx_er,
inputwirerx_en,
inputwire[7:0]rx_data,

outputregfifo_wr_en,
outputregfifo_data_valid,
outputregfifo_data_clr,
outputreg[7:0]fifo_data,
outputreg[15:0]data_cnt

);

parameterPC_MAC={8'h88,8'ha4,8'hc2,8'he5,8'hd3,8'h66};
parameterBOARD_MAC={8'h88,8'ha4,8'hc2,8'he5,8'hd3,8'h67};
parameterPC_IP={8'd192,8'd168,8'd0,8'd2};
parameterBOARD_IP={8'd192,8'd168,8'd0,8'd3};
parameterPC_COM=16'd65533;
parameterBOARD_COM=16'd65531;

reg[4:0]state;
regi_en;
regi_init;
wire[31:0]crc;

reg[47:0]rx_buf;
reg[9:0]rx_cnt;
reg[31:0]IP_HEAD_SUM;
reg[15:0]UDP_LEN;

CRC32_D8CRC32_D8_inst(

.clk(rx_clk),
.rst_n(rst_n),
.i_en(i_en),
.i_data(rx_data),
.i_init(i_init),

.crc(crc),
.crc_new()
);

always@(posedgerx_clk)
begin
if(rst_n==1'b0)
begin
fifo_wr_en<= 1'b0;
            fifo_data <= 8'd0;
            fifo_data_valid <= 1'b0;
            fifo_data_clr <= 1'b0;
            state <= 5'd1;
            i_en <= 1'b0;
            i_init <= 1'b0;
            rx_buf <= 48'd0;
            rx_cnt <= 10'd0;
            IP_HEAD_SUM <= PC_IP[31:16] + PC_IP[15:0] + BOARD_IP[31:16] + BOARD_IP[15:0];
            UDP_LEN <= 16'd0;
        data_cnt <= 16'd0;
        end
    else
        case (state)
            5'd0 : begin
                    fifo_wr_en <= 1'b0;
                    fifo_data <= 8'd0;
                    fifo_data_valid <= 1'b0;
                    fifo_data_clr <= 1'b0;
                    state <= 5'd1;
                    i_en <= 1'b0;
                    i_init <= 1'b0;
                    rx_buf <= 48'd0;
                    rx_cnt <= 10'd0;
                    IP_HEAD_SUM <= PC_IP[31:16] + PC_IP[15:0] + BOARD_IP[31:16] + BOARD_IP[15:0];
                    UDP_LEN <= 16'd0;
                   end 
            5'd1 : begin
                     if (rx_en && rx_er == 1'b0) 
                         begin
                             i_init <= 1'b1;
                             state <= 5'd2;
                             rx_buf <= {rx_buf[39:0],rx_data};
                         end
                     else
                         state <= 5'd1;
                   end
            5'd2 : begin
                    i_init <= 1'b0;
                    data_cnt <= 16'd0;
                    rx_buf <= {rx_buf[39:0],rx_data};
                    if (rx_buf == {{5{8'h55}},8'hd5})
                      begin 
                        state <= 5'd3;
                        i_en <= 1'd1;
                      end
                    else
                        state <= 5'd2;
                   end
            5'd3 : begin
                    i_en <= 1'b1;
                    rx_buf <= {rx_buf[39:0],rx_data};
                    if(rx_cnt < 10'd5)
                        rx_cnt <= rx_cnt + 1;
                    else
                        begin
                            rx_cnt <= 10'd0;
                            if(rx_buf == BOARD_MAC)
                                state <= 5'd4;
                            else
                                state <= 5'd20; 
                        end   
                    end
            5'd4  : begin
                     i_en <= 1'b1;
                     rx_buf <= {rx_buf[39:0],rx_data};
                     if(rx_cnt < 10'd5)
                       begin
                         rx_cnt <= rx_cnt + 1'b1;
                       end
                     else
                       begin
                         rx_cnt <= 10'd0;
                         if(rx_buf == PC_MAC)
                           state <= 5'd5;
                         else  
                           state <= 5'd18;
                       end
                    end
            5'd5  : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd5)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          IP_HEAD_SUM <= IP_HEAD_SUM + rx_buf[31:16] + rx_buf[15:0];
                          if(rx_buf[47:24] == {16'h0800,8'h45})
                            state <= 5'd6;
                          else  
                            state <= 5'd18;
                        end
                    end
            5'd6  : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          state <= 5'd7;
                          IP_HEAD_SUM <= IP_HEAD_SUM + rx_buf[31:16] + rx_buf[15:0];
                        end
                    end
            5'd7  : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          IP_HEAD_SUM <= IP_HEAD_SUM + rx_buf[31:16] + rx_buf[15:0];
                          if(rx_buf[23:16] == 8'd17)
                            state <= 5'd8;
                          else  
                            state <= 5'd18;
                        end
                    end
            5'd8  : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          if(rx_buf[31:0] == PC_IP)
                            state <= 5'd9;
                          else  
                            state <= 5'd18;
                        end
                    end
            5'd9  : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          IP_HEAD_SUM <= IP_HEAD_SUM + rx_buf[31:16] + rx_buf[15:0];
                          if(rx_buf[31:0] == BOARD_IP && (IP_HEAD_SUM[31:16] == ~IP_HEAD_SUM[15:0]))
                            state <= 5'd10;
                          else  
                            state <= 5'd18;
                        end
                    end
            5'd10 : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          if(rx_buf[31:0] == {PC_COM,BOARD_COM})
                            state <= 5'd11;
                          else  
                            state <= 5'd18;
                        end
                    end
            5'd11 : begin
                      i_en <= 1'b1;
                      rx_buf <= {rx_buf[39:0],rx_data};
                      if(rx_cnt < 10'd3)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                        end
                      else
                        begin
                          rx_cnt <= 10'd0;
                          state <= 5'd12;
                          UDP_LEN <= rx_buf[31:16];
                  data_cnt <= rx_buf[31:16] - 16'd9;
                        end
                    end
            5'd12 : begin
                      if(rx_cnt < UDP_LEN - 16'd9)
                        begin
                          rx_cnt <= rx_cnt + 1'b1;
                          fifo_wr_en <= 1'b1;
                          fifo_data <= rx_data;
                        end
                      else
                        begin
                          fifo_wr_en <= 1'b0;
                          fifo_data <= rx_data;
                          state <= 5'd13;
                        end
                    end
            5'd13 : begin
                      state <= 5'd14;
                    end
            5'd14 : begin
                      state <= 5'd15;
                    end
            5'd15 : begin
                      state <= 5'd16;
                      i_en <= 1'd0;
                    end
           
            5'd17 : begin
                      if(crc == 32'hc704dd7b)
                        begin
                          fifo_data_valid <= 1'b1;
                          state <= 5'd0;
                        end
                      else
                        begin
                          fifo_data_clr <= 1'b1;
                          state <= 5'd0;
                        end
                    end
            5'd18 : begin
                      if(rx_en == 1'b0)
                        state <= 5'd0;
                      else
                        state <= 5'd18;
                    end
              default: ;
        endcase
  end

endmodule 

其实现原理就是发送模块的逆过程。

三 、 总结

以太网实现过程基于UDP,代码思路根据每一层顺序写下来即可完成,其中需要注意的是MAC的地址需要提前准备好,因为没有写ARP协议,不可通过代码来获取MAC地址。端口号也需要提前准备好。在接收模块中需要考虑CRC获取数据的时机,不可提前也不可推迟。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1603

    文章

    21328

    浏览量

    593286
  • HDMI
    +关注

    关注

    32

    文章

    1490

    浏览量

    149766
  • 以太网
    +关注

    关注

    40

    文章

    5079

    浏览量

    166251
  • VGA
    VGA
    +关注

    关注

    5

    文章

    508

    浏览量

    62019
  • RCA
    RCA
    +关注

    关注

    0

    文章

    18

    浏览量

    8732

原文标题:就业班学员学习笔记分享:FPGA之HDMI、以太网篇

文章出处:【微信号:HXSLH1010101010,微信公众号:FPGA技术江湖】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    EtherCAT实时以太网分析仪直击痛点#以太网

    以太网ethercat
    ZLG致远电子
    发布于 :2022年12月12日 10:01:26

    EtherCAT实时以太网分析仪应用场景#以太网

    以太网ethercat
    ZLG致远电子
    发布于 :2022年12月12日 10:02:50

    以太网是什么鬼?以太网基础知识详解

    以太网
    电子学习
    发布于 :2023年02月07日 21:05:57

    「无线工程师基础知识」以太网是什么鬼?以太网的使用注意事项

    以太网
    电子学习
    发布于 :2023年02月08日 09:29:33

    车载以太网快速入门#车载以太网

    车载以太网
    北汇信息POLELINK
    发布于 :2023年09月01日 17:54:31

    车载以太网测试系统测试实例介绍#车载以太网

    车载以太网
    北汇信息POLELINK
    发布于 :2023年09月12日 17:27:48

    车载以太网基础培训——车载以太网的链路层#车载以太网

    车载以太网
    北汇信息POLELINK
    发布于 :2023年09月19日 16:25:21

    车载以太网总线基础培训——传输层#车载以太网

    车载以太网
    北汇信息POLELINK
    发布于 :2023年09月21日 10:57:36

    车载以太网基础视频——应用层#车载以太网

    车载以太网
    北汇信息POLELINK
    发布于 :2023年09月22日 09:05:01

    以太网视频传输 #FPGA

    fpga以太网
    辛一_e1e
    发布于 :2023年11月01日 06:28:18

    #电子技术 #FPGA 千兆以太网工程(项目开发能力)

    fpga以太网
    明德扬助教小易老师
    发布于 :2023年11月04日 06:42:15

    基于FPGA的万兆以太网接口的设计与实现

    基于FPGA的万兆以太网接口的设计与实现标准中万兆以太网物理层及媒质接入控制子层的相关协议以 应用物理环境为例,阐述了万兆以太网接口各个单元模块的功能和设计实现方法 仿真结果表明,该万
    发表于 08-11 15:48

    简谈基于FPGA的千兆以太网

    大家好,又到了学习时间了,学习使人快乐。今天我们来简单的聊一聊以太网以太网FPGA学习中属于比较高级的内容了,有些同学肯定会感觉以太网学习起来非常不容易。其实,我可以告诉大家,前
    发表于 02-03 15:11

    简谈基于FPGA的千兆以太网设计

    大侠带来简谈基于FPGA的千兆以太网设计,话不多说,上货。今天我们来简单的聊一聊以太网以太网FPGA学习中属于比较高级的内容了,有些大侠
    发表于 06-01 18:39

    就业班学员学习笔记分享:FPGAHDMI以太网

    并转为串。 1.3 代码 Top顶层模块 对于其他模块,都是进行调用,并没有自己编写,即不再简述。 二、以太网2.1 、UDP数据包介绍 2.2 、MAC协议 2.3 、IP协议 2.4
    发表于 06-12 18:30