精华内容
下载资源
问答
  • 一种基于FPGA的以太网高速传输平台 一种基于FPGA的以太网高速传输平台
  • 给出了基于FPGA的以太网系统设计图,在EDK10.1的环境中实现,通过chipscope观察发送数据包波形,并使用Etherpeek抓包工具观察发送的数据包。实验结果证明此以太网系统能够正常工作,满足多光谱成像仪数据传输要求,...
  • 基于FPGA与以太网的探地雷达数据采集与传输系统,方亮,杨峰,探地雷达数据的采集与传输是探地雷达的关键技术之一。本文基于FPGA与W5500设计了一种可传输24位探地雷达数据的以太网系统,可以实现�
  • 本文基于FPGA实现了ARP和UDP传输协议。 开发环境:Win7 开发软件:Quartus17.1、Modelsim SE-64 10.2c、Gvim编辑器、小兵以太网测试仪、Wireshark 开发硬件:小梅哥AC6102_V2开发板 注意:本工程都假设FPGA设备...

    本文基于FPGA实现了ARP和UDP传输协议。
    开发环境:Win7
    开发软件:Quartus17.1、Modelsim SE-64 10.2c、Gvim编辑器、小兵以太网测试仪、Wireshark
    开发硬件:小梅哥AC6102_V2开发板
    注意:本工程都假设FPGA设备IP地址为192.168.0.2(即0xc0_a8_00_02),MAC地址为0x00_0a_35_01_fe_c0,PC端IP地址为192.168.0.3(即0xc0_a8_00_03)

    1 以太网原理介绍

    1.1 以太网帧

    在以太网链路上的数据包称作以太网帧。以太网帧起始部分由前导码和帧开始符组成。后面紧跟着一个以太网报头,以MAC地址说明目的地址和源地址。帧的中部是该帧负载的包含其他协议报头的数据包(例如IP协议、ARP协议)。以太帧由一个32位冗余校验码结尾。它用于检验数据传输是否出现损坏。以太网帧格式如下图所示。
    在这里插入图片描述
    1.前导码和帧开始符是固定的,为7个0x55紧跟着1个0xd5
    2.目的MAC地址指明帧的接受者
    3.源MAC地址指明帧的发送者
    4.以太网类型,指示帧的类型,比如0x0800表示该帧是IP数据包,0x0806表示该帧是ARP协议数据包
    5.数据和填充就是所承载的数据包,跟前面以太网类型对应。
    6.帧校验序列是一个32位的循环校验码(FCS)。
      每一个设备都有一个不同的MAC地址,当一个设备A发送一个以太网帧,源MAC地址是自己的MAC地址,目的MAC地址如果是0xffffff,此时就是广播,所有与之连接的设备都会收到该帧,如果目的MAC地址是一个独特的MAC地址,那么本地MAC地址与之相同的设备将会接收到该以太网帧,然后通过判断以太网帧类型,进行下一步数据包解析。

    1.2 ARP协议

    ARP协议,全称为Address Resolution Protocol,即地址解析协议,ARP协议属于以太网帧的一种,前面以太网帧介绍中有说到,我们如果从设备A发送以太网帧到设备B,我们不可能每次都进行广播,那么设备A如何知道设备B的物理地址呢?ARP协议就是为了解决这个问题。
      首先设备A广播,发送ARP请求,等收到设备B的ARP应答以后就能知道设备B的MAC地址。ARP帧格式如下图所示
      在这里插入图片描述
    ARP字段就是前面以太网帧待填充的数据。
    硬件类型、上层协议类型、MAC地址长度、IP地址长度均固定不变。
    假设设备A的IP地址为192.168.0.2,MAC地址为0x00_0a_35_01_fe_c0,我们知道目的IP地址为192.168.0.3,不知道该IP地址对应的MAC地址,如果设备A想要和IP地址为192.168.0.3的设备B进行通信(如UDP或者IP通信),就必须知道它的MAC地址。此时设备A就需要广播发送ARP请求,接收方MAC地址填0xff_ff_ff_ff_ff_ff。这样IP地址为192.168.0.3的设备就会解析出这是一个ARP请求,它询问自身的MAC地址,此时它就会做出ARP应答,将自身的MAC地址发送给对应IP地址的设备A。
    注意发送ARP请求时,操作码为0x0001,应答时操作码为0x0002。

    1.3 IP协议

    TCP/IP协议定义了一个在因特网上传输的包,称为IP数据包,而IP数据报(IP Datagram)是个比较抽象的内容,是对数据包的结构进行分析。 由首部和数据两部分组成,其格式如下图图所示。首部的前一部分是固定长度,共20字节,是所有IP数据报必须具有的。在首部的固定部分的后面是一些可选字段,其长度是可变的。首部中的源地址和目的地址都是IP协议地址。
    在这里插入图片描述

    1.4 UDP协议

    UDP 协议是一种不可靠传输,发送方只负责将数据发送出去,而不管接收方是否正确的接收。 非常类似于 UART 串口传输。 但是,在很多场合,是可以接受这种潜在的不可靠性的,例如视频实时传输显示。 在这类系统中,由于数据并不需要进行运算并得到非常精确的结果用于其他功能,而仅仅是显示在屏幕上,因此可以接受一定程度的丢包或者误码。此类应用在 LED 大屏显示系统中应用非常广泛。UDP帧组成如下图所示
    在这里插入图片描述

    2 GMII接口介绍

    在芯航线 AC6102 开发板上,设计了一路 GMII 接口的千兆以太网电路,通过该以太网电路,用户可以将 FPGA 采集或运算得到的数据传递给其他设备如 PC 或服务器,或者接收其他设备传输过来的数据并进行处理。首先介绍一下GMII接口。
    在这里插入图片描述
    gmii_rx_clk是PHY发送过来的时钟,FPGA通过该时钟进行采样
    gmii_rx_dv是接收数据有效标志,与gmii_rx_data对齐
    gmii_rx_er是错误标志,当它有效时,说明发送帧错误
    gmii_rx_data是PHY发送过来的数据
    phy_rst_n是低电平复位信号
    gmii_tx_clk是FPGA发送时钟,这里直接使用gmii_rx_clk即可
    gmii_tx_en发送数据有效标志,与gmii_tx_data对齐
    gmii_tx_er是错误标志
    gmii_tx_data是FPGA发送给PHY的数据
    以上就是GMII接口所有的信号。
    在发送数据时,只需要按以下时序发送。
    在这里插入图片描述

    3 ARP协议实现

    在本工程中,ARP实现分两部分,一是由FPGA发送ARP请求,二是对发送过来的ARP应答进行解析,得到目的IP地址对应的MAC地址。
    这样我们就可以知道,发送ARP请求完整的帧内容了。如下图所示。(数据格式为16进制)
    在这里插入图片描述
    除了CRC32校验值之外,其他都是固定的,CRC32需要进行计算。关于CRC32的8位并行计算,大家可以参考下面这篇论文。千兆以太网MAC中CRC算法的设计与实现
    用CRC计算软件可以算出,也可以用FPGA实现。
    在这里插入图片描述
    由计算软件看出crc32校验结果为0x63f9a3ca,在发送时,按7-0、15-8、23-16、31-24的顺序发送。
    下面给出CRC32的FPGA实现代码:

    module  crc(
        input                       clk                             ,
        input                       rst_n                           ,
        input         [ 7: 0]       din                             ,
        input                       crc_en                          ,
        input                       crc_init                        ,
        output  reg   [31: 0]       crc                            
    );
    //======================================================================\
    //************** Define Parameter and Internal Signals *****************
    //======================================================================/
    wire    [ 7: 0]                 data                            ;
    wire    [31: 0]                 crc_next                        ;
    //======================================================================\
    //**************************** Main Code *******************************
    //======================================================================/
    assign data={din[0],din[1],din[2],din[3],din[4],din[5],din[6],din[7]};
    
    assign crc_next[0]  = crc[24] ^ crc[30] ^ data[0] ^ data[6];
    assign crc_next[1]  = crc[24] ^ crc[25] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[6] ^ data[7];
    assign crc_next[2]  = crc[24] ^ crc[25] ^ crc[26] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[2] ^ data[6] ^ data[7];
    assign crc_next[3]  = crc[25] ^ crc[26] ^ crc[27] ^ crc[31] ^ data[1] ^ data[2] ^ data[3] ^ data[7];
    assign crc_next[4]  = crc[24] ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ data[0] ^ data[2] ^ data[3] ^ data[4] ^ data[6];
    assign crc_next[5]  = crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[0] ^ data[1] ^ data[3] ^ data[4] ^ data[5] ^ data[6] ^ data[7];
    assign crc_next[6]  = crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6] ^ data[7];
    assign crc_next[7]  = crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[31] ^ data[0] ^ data[2] ^ data[3] ^ data[5] ^ data[7];
    assign crc_next[8]  = crc[0]  ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data[0] ^ data[1] ^ data[3] ^ data[4];
    assign crc_next[9]  = crc[1]  ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ data[1] ^ data[2] ^ data[4] ^ data[5];
    assign crc_next[10] = crc[2]  ^ crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ data[0] ^ data[2] ^ data[3] ^ data[5];
    assign crc_next[11] = crc[3]  ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data[0] ^ data[1] ^ data[3] ^ data[4];
    assign crc_next[12] = crc[4]  ^ crc[24] ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6];
    assign crc_next[13] = crc[5]  ^ crc[25] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[30] ^ crc[31] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6] ^ data[7];
    assign crc_next[14] = crc[6]  ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ crc[31] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[7];
    assign crc_next[15] = crc[7]  ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[31] ^ data[3] ^ data[4] ^ data[5] ^ data[7];
    assign crc_next[16] = crc[8]  ^ crc[24] ^ crc[28] ^ crc[29] ^ data[0] ^ data[4] ^ data[5];
    assign crc_next[17] = crc[9]  ^ crc[25] ^ crc[29] ^ crc[30] ^ data[1] ^ data[5] ^ data[6];
    assign crc_next[18] = crc[10] ^ crc[26] ^ crc[30] ^ crc[31] ^ data[2] ^ data[6] ^ data[7];
    assign crc_next[19] = crc[11] ^ crc[27] ^ crc[31] ^ data[3] ^ data[7];
    assign crc_next[20] = crc[12] ^ crc[28] ^ data[4];
    assign crc_next[21] = crc[13] ^ crc[29] ^ data[5];
    assign crc_next[22] = crc[14] ^ crc[24] ^ data[0];
    assign crc_next[23] = crc[15] ^ crc[24] ^ crc[25] ^ crc[30] ^ data[0] ^ data[1] ^ data[6];
    assign crc_next[24] = crc[16] ^ crc[25] ^ crc[26] ^ crc[31] ^ data[1] ^ data[2] ^ data[7];
    assign crc_next[25] = crc[17] ^ crc[26] ^ crc[27] ^ data[2] ^ data[3];
    assign crc_next[26] = crc[18] ^ crc[24] ^ crc[27] ^ crc[28] ^ crc[30] ^ data[0] ^ data[3] ^ data[4] ^ data[6];
    assign crc_next[27] = crc[19] ^ crc[25] ^ crc[28] ^ crc[29] ^ crc[31] ^ data[1] ^ data[4] ^ data[5] ^ data[7];
    assign crc_next[28] = crc[20] ^ crc[26] ^ crc[29] ^ crc[30] ^ data[2] ^ data[5] ^ data[6];
    assign crc_next[29] = crc[21] ^ crc[27] ^ crc[30] ^ crc[31] ^ data[3] ^ data[6] ^ data[7];
    assign crc_next[30] = crc[22] ^ crc[28] ^ crc[31] ^ data[4] ^ data[7];
    assign crc_next[31] = crc[23] ^ crc[29] ^ data[5];
    
    //crc 这里用下降沿采集,是为了crc能提前半拍送到eth_mac_send模块中,这个很重要
    //否则crc高8位会发送出错,自己可以修改代码试试看
    always  @(negedge clk or negedge rst_n)begin
        if(rst_n == 1'b0)begin
            crc <=  {32{1'b1}};
        end
        else if(crc_init)begin
            crc <=  {32{1'b1}};
        end
        else if(crc_en)begin
            crc <=  crc_next;
        end
    end
    
    
    endmodule
    
    

    下面是用SignalTap抓取到的信号,如下图所示。
    帧头部分:
    在这里插入图片描述
    帧尾FCS部分:
    在这里插入图片描述
    可以看出发送的校验码为0xca_a3_f9_63与CRC计算机软件计算结果一致。

    3.1 ARP请求

    FPGA实现ARP请求非常简单。首先定义模块信号。

    module  arp_request(
            input                   clk                             ,//125M
            input                   rst_n                           ,
            input         [31: 0]   src_ip_addr                     ,
            input         [31: 0]   dest_ip_addr                    ,
            input         [47: 0]   src_mac_addr                    ,
            input         [47: 0]   dest_mac_addr                   ,
            input         [31: 0]   crc                             ,
            output  reg             crc_init                        ,
            output  reg             crc_en                          ,
            //gmii 
            output  reg             gmii_tx_en                      ,
            output  reg   [ 7: 0]   gmii_tx_data                            
    );
    

    用计数器,在计数变化时,将每一个字节通过gmii_tx_data发送即可。具体请看工程源码。

    3.2 ARP应答解析

    在FPGA发送ARP请求后,对应IP地址将会做出APR应答发送其对应MAC地址,此时通过FPGA的ARP应答解析模块即可正确解析出目标MAC地址,从而为UDP协议传输奠定基础。
    具体实现:
    ①判断目标MAC地址是否是FPGA设备的MAC地址
    ②判断操作码是否是0x0002
    ③判断PC端IP地址是否是192.168.0.3
    ④判断目的IP地址是否是192.168.0.2
    只有以上条件均满足时,我们认为这是一条ARP应答包,从而更新IP为192.168.0.3对应的MAC地址。具体请看工程源码

    4 UDP协议传输实现

    在这里,我通过按键,生成1200个字节的数据,从0-255循环变化,然后封装成UDP包发送到PC端。从而实现UDP协议传输。
    由上面UDP介绍,我们可以知道发送一个UDP包的主要构成,如下图所示:
    在这里插入图片描述
    IP数据包的报头校验和:
    0x4500+0x04cc+0x0000+0x0000+0x4011+0xc0a8+0x0002+0xc0a8+0x0003 = 0x20b32
    0x0002+0x0b32 = 0x0b34
    checksum = ~(0x0b34) = 0xf4cb
    同样的,我们使用计数器来发送对应数据。
    UDP发送模块如下:

    module  udp_send(
            input                   clk                             ,
            input                   clk_50m                         ,
            input                   rst_n                           ,
            input         [31: 0]   src_ip_addr                     ,    
            input         [31: 0]   dest_ip_addr                    ,
            input         [47: 0]   src_mac_addr                    ,
            input         [47: 0]   dest_mac_addr                   ,
            //fifo
            input         [10: 0]   fifo_rdusedw                    ,
            input         [ 7: 0]   fifo_rd_data                    ,
            output  reg             fifo_rdreq                      ,
            //crc
            input         [31: 0]   crc                             ,
            output  reg             crc_init                        ,
            output  reg             crc_en                          ,
            //gmii
            output  reg             gmii_tx_en                      ,
            output  reg   [ 7: 0]   gmii_tx_data                     
    );
    //======================================================================\
    //************** Define Parameter and Internal Signals *****************
    //======================================================================/
    parameter   DATA_LEN        =   16'd1200                        ;//发送的UDP数据长度
    
    parameter   PREAMBLE        =   8'h55                           ;
    parameter   SFD             =   8'hd5                           ;
    parameter   LEN_TYPE        =   16'h0800                        ;
    
    parameter   VER_HDR_LEN     =   8'h45                           ;
    parameter   TOS             =   8'h00                           ;
    parameter   TOTAL_LEN       =   DATA_LEN+28                     ;
    parameter   ID              =   16'h0000                        ;
    parameter   RSV_DF          =   8'h00                           ;
    parameter   MF_FRAG_OFFSET  =   8'h00                           ;
    parameter   TTL             =   8'h40                           ;
    parameter   PROTOCOL        =   8'h11                           ;
    
    parameter   SRC_PORT        =   16'd5000                        ;
    parameter   DST_PORT        =   16'd6000                        ;
    parameter   UDP_LEN         =   DATA_LEN+8                      ;
    parameter   UDP_CHECKSUM    =   16'h0000                        ;
    
    
    wire    [19: 0]                 ip_check_sum1                   ;
    wire    [19: 0]                 ip_check_sum2                   ;
    wire    [15: 0]                 ip_check_sum                    ;
    
    
    reg                             trig_udp_send                   ;
    reg                             flag_udp_send                   ;
    
    reg     [10: 0]                 udp_byte_cnt                    ;
    wire                            add_udp_byte_cnt                ;
    wire                            end_udp_byte_cnt                ;
    
    reg     [ 7: 0]                 udp_data                        ;
    //======================================================================\
    //**************************** Main Code *******************************
    //======================================================================/
    //check_sum1 进位为17'hxff这种情况时,check_sum1,前16与后16位相加可能还会在第
    //17位进1
    assign  ip_check_sum1  =   {VER_HDR_LEN, 8'h00} + TOTAL_LEN + {TTL, PROTOCOL} + src_ip_addr[31:16] + src_ip_addr[15:0] + dest_ip_addr[31:16] + dest_ip_addr[15:0];//width<=20
    
    //check_sum2
    assign  ip_check_sum2   =   ip_check_sum1[19:16] + ip_check_sum1[15:0];//width<=17
    assign  ip_check_sum    =   ~(ip_check_sum2[19:16] + ip_check_sum2[15:0]);//width<=16
    
    
    //trig_udp_send
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            trig_udp_send   <=  1'b0;
        end
        else if(fifo_rdusedw == DATA_LEN-1)begin//
            trig_udp_send   <=  1'b1;
        end
        else begin
            trig_udp_send   <=  1'b0;
        end
    end
    
    //flag_udp_send
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            flag_udp_send   <=  1'b0;
        end
        else if(trig_udp_send)begin
            flag_udp_send   <=  1'b1;
        end
        else if(end_udp_byte_cnt)begin
            flag_udp_send   <=  1'b0;
        end
    end
    
    //udp_byte_cnt
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            udp_byte_cnt <= 0;
        end
        else if(add_udp_byte_cnt)begin
            if(end_udp_byte_cnt)
                udp_byte_cnt <= 0;
            else
                udp_byte_cnt <= udp_byte_cnt + 1;
        end
    end
    
    assign  add_udp_byte_cnt    =       flag_udp_send;       
    assign  end_udp_byte_cnt    =       add_udp_byte_cnt && udp_byte_cnt == DATA_LEN+54-1;//前导码+分隔符8个,MAC帧头14,CRC校验4   
    
    //fifo_rdreq
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            fifo_rdreq   <=  1'b0; 
        end
        else if(udp_byte_cnt == 50-1)begin
            fifo_rdreq   <=  1'b1;  
        end
        else if(udp_byte_cnt == DATA_LEN+50-1)begin//校验码之前
            fifo_rdreq   <=  1'b0; 
        end
    end
    
    //--------------------------------------------------------------------\\
    //gmii_tx_en
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            gmii_tx_en  <=  1'b0;
        end
        else if(flag_udp_send)begin
            gmii_tx_en  <=  1'b1;
        end
        else begin
            gmii_tx_en  <=  1'b0;
        end
    end
    
    //gmii_tx_data
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            gmii_tx_data    <=  8'h00;
        end
        else if(flag_udp_send)begin
            case(udp_byte_cnt)
                0,1,2,3,4,5,6:  gmii_tx_data    <=  PREAMBLE;
                7:              gmii_tx_data    <=  SFD;
                //帧头
                8:              gmii_tx_data    <=  dest_mac_addr[47:40];
                9:              gmii_tx_data    <=  dest_mac_addr[39:32];
                10:             gmii_tx_data    <=  dest_mac_addr[31:24];
                11:             gmii_tx_data    <=  dest_mac_addr[23:16];
                12:             gmii_tx_data    <=  dest_mac_addr[15: 8];
                13:             gmii_tx_data    <=  dest_mac_addr[ 7: 0];
                14:             gmii_tx_data    <=  src_mac_addr[47:40];
                15:             gmii_tx_data    <=  src_mac_addr[39:32];
                16:             gmii_tx_data    <=  src_mac_addr[31:24];
                17:             gmii_tx_data    <=  src_mac_addr[23:16];
                18:             gmii_tx_data    <=  src_mac_addr[15: 8];
                19:             gmii_tx_data    <=  src_mac_addr[ 7: 0];
                20:             gmii_tx_data    <=  LEN_TYPE[15: 8];
                21:             gmii_tx_data    <=  LEN_TYPE[ 7: 0];
                //IP
                22:             gmii_tx_data    <=  VER_HDR_LEN;//8'h45    
                23:             gmii_tx_data    <=  TOS;           
                24:             gmii_tx_data    <=  TOTAL_LEN[15: 8];     
                25:             gmii_tx_data    <=  TOTAL_LEN[ 7: 0];  
                26:             gmii_tx_data    <=  ID[15: 8];            
                27:             gmii_tx_data    <=  ID[ 7: 0];       
                28:             gmii_tx_data    <=  RSV_DF;        
                29:             gmii_tx_data    <=  MF_FRAG_OFFSET;
                30:             gmii_tx_data    <=  TTL;           
                31:             gmii_tx_data    <=  PROTOCOL;
                32:             gmii_tx_data    <=  ip_check_sum[15: 8];           
                33:             gmii_tx_data    <=  ip_check_sum[ 7: 0]; 
                34:             gmii_tx_data    <=  src_ip_addr[31:24];           
                35:             gmii_tx_data    <=  src_ip_addr[23:16];
                36:             gmii_tx_data    <=  src_ip_addr[15: 8];           
                37:             gmii_tx_data    <=  src_ip_addr[ 7: 0];
                38:             gmii_tx_data    <=  dest_ip_addr[31:24];           
                39:             gmii_tx_data    <=  dest_ip_addr[23:16]; 
                40:             gmii_tx_data    <=  dest_ip_addr[15: 8];           
                41:             gmii_tx_data    <=  dest_ip_addr[ 7: 0]; 
                //udp    
                42:             gmii_tx_data    <=  SRC_PORT[15: 8];
                43:             gmii_tx_data    <=  SRC_PORT[7 : 0];    
                44:             gmii_tx_data    <=  DST_PORT[15: 8];    
                45:             gmii_tx_data    <=  DST_PORT[7 : 0];     
                46:             gmii_tx_data    <=  UDP_LEN[15: 8];
                47:             gmii_tx_data    <=  UDP_LEN[7 : 0];
                48:             gmii_tx_data    <=  UDP_CHECKSUM[15: 8]; 
                49:             gmii_tx_data    <=  UDP_CHECKSUM[7 : 0];           
                //crc         
                DATA_LEN+50:    gmii_tx_data    <=  ~{crc[24], crc[25], crc[26], crc[27], crc[28], crc[29], crc[30], crc[31]};
                DATA_LEN+51:    gmii_tx_data    <=  ~{crc[16], crc[17], crc[18], crc[19], crc[20], crc[21], crc[22], crc[23]};
                DATA_LEN+52:    gmii_tx_data    <=  ~{crc[8], crc[9], crc[10], crc[11], crc[12], crc[13], crc[14], crc[15]};
                DATA_LEN+53:    gmii_tx_data    <=  ~{crc[0], crc[1], crc[2], crc[3], crc[4], crc[5], crc[6], crc[7]};
                
                default:        gmii_tx_data    <=  fifo_rd_data; 
            endcase
        end 
        else begin
            gmii_tx_data    <=  8'h00;
        end
    end
    
    //---------------------------CRC-----------------------------------\\
    //crc_init
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            crc_init    <=  1'b0;
        end
        else if(udp_byte_cnt == (8-1))begin
            crc_init    <=  1'b1;
        end
        else begin
            crc_init    <=  1'b0;
        end
    end
    
    //crc_en    
    always  @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            crc_en  <=  1'b0;
        end
        else if(udp_byte_cnt == (9-1))begin//9-1
            crc_en  <=  1'b1;
        end
        else if(udp_byte_cnt == (DATA_LEN+51-1))begin//1251-1
            crc_en  <=  1'b0;
        end
    end
    endmodule
    
    

    下面是用SignalTap抓取信号示意图
    帧头部分,rdreq就是从fifp读取的数据然后通过封装成UDP发送
    在这里插入图片描述
    帧尾部分,可以看到,发送数据最后一个为175,的确发送了1200个数据(1199-1024=175)。
    在这里插入图片描述
    具体请看工程源码,然后自己下载跑一下就能理解了。
    下面是工程源码下载链接基于FPGA的千兆以太网传输实例——ARP和UDP的实现

    展开全文
  • 本工程基于小梅哥AC620 FPGA开发板开发,支持OV7670、OV7725、OV5640摄像头模块,不要纠结于工程名称叫OV7670 使用时,只需要在cmos_init这个文件中把 ·define OV7670 改为 ·define OV5640 即可使用OV5640摄像头,...

    本文由FPGA爱好者小梅哥编写,未经作者许可,本文仅允许网络论坛复制转载,且转载时请标明原作者。

     

     

    本工程基于小梅哥AC620 FPGA开发板开发,支持OV7670、OV7725、OV5640摄像头模块,不要纠结于工程名称叫OV7670
    使用时,只需要在cmos_init这个文件中把
    ·define OV7670
    改为
    ·define OV5640
    即可使用OV5640摄像头,
    改为
    ·define OV7725
    即可使用OV7725摄像头,

    本次修改重点优化了工程结构,去掉了之前的VGA显示模块,改为直接自动从SDRAM读数据并发送
    整个工程结构更加清晰,而且由于架构的优化,以太网发送帧率也得以提升,已经基本达到了百
    兆以太网发送RGB565图像数据的极限帧率15帧,不会再像之前的版本一样有明显的卡顿。

     

    基本数据流向:


    数据输入:OV7670摄像头采集图像数据,存入SDRAM
    数据输出:使用UDP协议将从SDRAM中读取到的图像数据发送到PC端

    使用时


    1、将OV7670摄像头连接到开发板
    2、使用网线将开发板网卡和用户的电脑网卡直连
    3、设置PC端有线网卡的IP地址为192.168.0.3
    4、关闭PC机防火墙
    5、打开“小梅哥UDP摄像头V2.exe”软件,参数按照默认设置
    6、下载工程的sof文件到开发板中
    7、点击“小梅哥UDP摄像头V2.exe”软件上的连接按钮,即可在软件上看到试试采集的图像数据

     

    展开全文
  • 基于FPGA和以太网的数据采集系统的研究与设计,叶树栋,,结合FPGA和以太网传输的特点,设计了一套数据采集系统,应用FPGA的内部逻辑实现对ADC、SDRAM、网卡控制芯片DM9000的时序控制,以FPGA作为�
  • 很不错的FPGA ucos II 开发教程,需要下载,只要2分
  • 基于FPGA的千兆以太网CMOS图像数据传输系统设计
  • 本文所设计的基于FPGA百兆以太网数据传输,是博主自己绘制pcb制作百兆以太网模块,是通过一片 Realtek RTL8201 以太网 PHY 提供对以太网连接支持,RTL8201 是一片 10M/100M 自适应以太网收发器,提供 MII/SNI...

    文章部分内容参考了相关论坛中的内容:
    对文章中内容感兴趣或者有不懂的可以咨询QQ:2859340499

    B站对应讲解本文视频链接
    本文所设计的基于FPGA百兆以太网数据传输,是博主自己绘制pcb制作的百兆以太网模块,是通过一片 Realtek 的 RTL8201 以太网 PHY 提供对以太网连接的支持,RTL8201 是一片 10M/100M 自适应以太网收发器,提供 MII/SNI 接口的 MAC 连接。所设计的百兆以太网模块如下图所示:
    在这里插入图片描述
    原理图附上:
    在这里插入图片描述

    通过所设计的以太网电路,可以将 FPGA 采集或运算得到的数据传递给其他设备如 PC 或服务器,或者接收其他设备传输过来的数据并进行处理。

    下面介绍如何控制以太网模块并进行数据的传输(写程序了):

    控制以太网两种方式:
    (1)在Cyclone IV E 器件中,调用三速以太网 IP 核(MAC),实现完整的以太网连接。
    (2)用户使用 Verilog 编写的自定义用户逻辑来实现以太网连接。下图为 RTL8201 与 Cyclone IV E的连接关系。

    如下图所示为FPGA和百兆以太网的连接图(参照网上图片):
    在这里插入图片描述
    协议
    对于以太网有了解的肯定知道使用以太网需要协议支撑,最常听说的是 TCP/IP 协议,在 电脑端TCP/IP 协议应用非常广泛。但是 FPGA 控制以太网接口时,使用 TCP/IP 协议也是可以的,但是,直接使用 Verilog 编写协议层代码来实现却是十分困难的(可以通过SOPC技术实现)。所以大部分使用 Verilog实现以太网传输都是基于常简单的 UDP 协议的。
    基于FPGA使用UDP协议来控制以太网比较简单,所以本文所设计的数据传输是以太网基于UDP协议的。下面简单介绍一下UDP协议,UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。(UDP的解释有很多,这里就不做详细解释了,如果感兴趣的话可以百度就行)。
    当然使用以太网不止只需要知道UDP就可以了,还需要了解CRC校验,ARP等一系列知识,这里就不展开介绍了,可以联系博主分享资料。

    挑重点的说,本文主要是让大家明白FPGA使用以太网的过程,所以本次设计的程序是-------------:
    设计实例: UDP 数据报发送实验
    关于用户数据、UDP、IP、MAC 四个报文的关系(参考网上小梅哥):
    用户数据是打包在 UDP 协议中、UDP 协议又是基于 IP 协议之上的,IP 协议又是走MAC 层发送的,即从包含关系来说:MAC 帧中的数据段为 IP 数据报,IP 报文中的数据段为 UDP 报文,UDP 报文中的数据段为用户希望传输的数据内容,如“hello world!”。下图为使用 UDP 协议发送“hello world!”的数据层层打包示意图:
    在这里插入图片描述
    即使用 UDP 协议发送“hello world!”,按照以下顺序进行:

    1. 将“hello world!”内容打包进 UDP 数据报
    2. 将 UDP 协议打包成 IP 数据报
    3. 将 IP 数据报送入以太网帧发送单元(MAC 层),组织成标准 MAC 帧后发送。

    根据以上的每一个层之间的层层嵌套就可以编写程序了(程序具体怎么编写这里就不细致展开了,可以联系博主),本次程序是AD模块(点击这里)采集到的数据传输给FPGA,其中程序的RTL视图如图所示:
    在这里插入图片描述
    FPGA将数据通过百兆以太网传输到电脑的上位机中(wireshark):
    在这里插入图片描述
    并且也可以自己编写上位机,利用上位机来进行数据的显示,进行数据的实时传输。
    关于以太网就先说这么多,以太网的各种知识很多,已经将博主设计的以太网硬件电路pcb文件,程序,说明文档等打包好,有兴趣的可以联系博主分享,这里是以太网,如果对USB数据传输感兴趣的可以点击这里:USB2.0高速数据传输

    如果对文章中内容有不懂的,文中涉及的软件等,欢迎骚扰,或者对博主设计的USB2.0电路图以及程序等所有资料,可以联系博主QQ分享(所有的软件固件,说明文档,程序,模块pcb文件):2859340499.

    展开全文
  •  本文给出了完全用FPGA的控制逻辑来实现嵌入式系统Internet接人中的底层以太网控制器的设计方法。并最终设计出符合IEEE 802.3标准的控制器,从而实现了10 Mbps和100 Mbps两种传输速率以及半双工和全双工两种工作...
  • 本文以“基于FPGA的温度采集与以太网传输”这个课题为核心展开讨论系统设计的方法,一方面巩固上一篇介绍的设计思想,另一方面会看到一些新产生的问题。系统结构框图如下图所示。温度传感器如模拟式的PT100,FPGA...

    概述

    接着上一篇博文的主题,继续讨论FPGA数据采集-传输-显示系统的设计方法。本文以“基于FPGA的温度采集与以太网传输”这个课题为核心展开讨论系统设计的方法,一方面巩固上一篇介绍的设计思想,另一方面会看到一些新产生的问题。

    系统结构框图如下图所示。

    这里写图片描述

    温度传感器如模拟式的PT100,FPGA可以用ADC模块来采集,这种对采集速率要求不高的应用就不需要用上一篇中那样的高速并行ADC,用普通的串行ADC采集即可,这种ADC大多采用的是SPI总线驱动方式。数字式温度传感器如DS18B20、HDC1050,FPGA需要用总线通信的方式来读取温度数据,前者采用的是单总线,后者采用的是IIC通信。

    以太网传输目前按速率分有10M、100M和1G(1000M)等,支持哪种速率需要看网卡芯片。以太网传输时可以按UDP或TCP协议来传输数据,前者因为不受控所以不太安全,可能会丢包,但数据传输速度快,只要设计合理也可以避免数据丢失的问题。

    本文设计选择使用FPGA通过单总线读取DS18B20的温度数据,通过千兆以太网端口按UDP协议将温度数据发送到网络调试助手中显示。


    环境与设备

    1. 黑金AX515开发板(Cyclone IV代)和板载Realtek TL8211EG以太网PHY芯片;
    2. Quartus II软件;
    3. 网络调试助手v3.8。

    基于FPGA的温度采集和以太网传输

    按照上一篇文章的设计思想,我们可以想到,DS18B20的温度采集速度和以太网发送数据的速度是不一样的,而且差距很大。如果我们在FPGA设计时直接将DS18B20的温度数据接口与以太网模块的接口相连接,上位机上我们会接收到大量的“老数据”,也就是采集一次温度数据而被发送了多次。避免这个问题的方法就是在两个模块之间加一级存储器,上次我们用了FIFO,这次体验一下双口RAM。双口RAM比起FIFO的优势是可以在读出端口随意的读取RAM中存储的任意一个数据,而FIFO只能按顺序读出,两者在不同的地方有不同的应用。

    因此FPGA程序的模块划分设计如下。

    这里写图片描述

    单总线通信可以用有限状态机的方式实现,读出温度数据按符号位、十位、个位、小数点位拆分开,这里不得提一下,DS18B20的精度虽然不高,但是分辨率很高,小数点可以推到后面很多位,但是使用时完全不需要这么高的分辨率,根据需求提取数据即可。

    以太网在传输过程中需要按ASIIC码来传输,这样传到上位机中的数字和字符就可以直接显示出来。因此在把温度数据写入RAM的时候转换为ASIIC码后再写入。

    按照上述方法完成FPGA的设计,在UDP模块中指定好要传入的网卡MAC地址和IP地址,在PC上把IP地址做出对应的修改。经过测试确发现接收到的数据全是0,这让博主百思不得其解,一开始一位是总线程序设计出错,导致读取不到正确的数据,后来无意间的按了一下复位键,确发现接收到了正确的温度数据,只是温度数据是一个固定值,不会随环境改变。而重新下载后才会收到新的温度数据。

    思考一下就会发现,该问题很明显是由于双口RAM的状态设计上出错造成的。可以收到温度数据表示总线模块和UDP模块应该是都没有问题,而UDP模块是从RAM中读取的数据,很显然UDP读取的是固定的一个温度值,也就是表明RAM中存储的数据没有被刷新。再简单点讲,在总线通信还没有完成的时候,RAM中就已经被写入了0,而总线通信完成后,新的温度数据没有写到RAM中,UDP模块读到的就一直是0。

    找到了问题便有了解决思路,重新检查下RAM的设计状态,在RAM读满后将地址移向RAM的开头位置,让温度数据覆盖最早的旧数据,保持数据的不断更新。修改后再进行测试结果正确,效果如下图所示。


    总结

    其实在1.2/50μs脉冲电压采集的设计中也有类似的问题,就是在FIFO为满时该怎么操作,FIFO为空时该做出什么反应?如果上一节的实验在FIFO满时不刷新FIFO中的数据同样会有本文遇到的问题。而FIFO为空时就应该禁止数据的传输,以避免传输错误的数据。

    如果您发现本文中有错别字、言语混论、逻辑不通或难以理解的地方,请评论留言,谢谢!

    完整的Quartus工程可以在这里下载:https://download.csdn.net/download/fpgadesigner/10475428

    展开全文
  • 为了满足网络传输、可触发控制和多路信号采集需求,设计和实现了基于FPGA以太网接口数据采集 系统,其中以FPGA 为核心,实现了AD 驱动、触发控制、串并转换、FIFO 缓冲和MAC 配置。实验结果表明系 统...
  • 要:本文介绍了基于FPGA、功能经过扩展的以太网MII接口的硬件实现方法。硬件结构上由控制信号模块、分频器、异步FIFO缓冲和4b/5b编解码器4个部分组成。  关键词:100M以太网MII;FPGA;奇偶分频器;4b/5b编解码...
  • 摘要: 本文介绍了基于现场可编程门阵列(FPGA) 的以太网MAC 子层协议的硬件实现方法. 硬件结构上由控制模 块、发送模块和接收模块3个部分组成,发送模块和接收模块采用状态机控制数据发送和接收的过程,完成数据的封装...
  • FPGA驱动DS18B20,温度数据用双口RAM缓存,通过以太网发送温度到PC,可用网络调试工具显示,Quartus工程;具体说明可参考本人博客。CSDN博客搜索:FPGADesigner
  • 为了满足某战术通信系统终端IP化接入的发展要求,提出了一种基于FPGA的EoPDH(Ethernet over PDH)传输系统;该系统采用逻辑编程的方式实现接口协议、数据格式转换等主要处理环节,融合既有功能组件实现话音业务的...
  • W5300的目标是在高性能的嵌入式领域,如多媒体数据流服务。与WIZnet现有的芯片方案相比较,...通过一个集成有TCP/IP协议和10/100M的以太网MAC和PHY的单芯片可以非常简单和快捷地实现Internet连接。 W5300与主机(MC...
  • 随着技术的迅速发展,越来越多的工程应用对以太网...本文研究的方法结合了FPGA的强大处理能力和PHY 芯片的驱动能力,比常规CPU+MAC层模块+PHY芯片的方式有更高的效率。本文通过实验测试验证了设计的可靠性与快速性。
  • 在上一文中介绍了以太网的各层协议;链接:https://blog.csdn.net/weixin_41838250/article/details/114686428?spm=1001.2014.3001.5502 本文主要介绍一下我项目中使用10G-BASE-R和MAC层具体应用;因为项目需求...
  • 本文中主要是介绍基于 FPGA 的以太网音频传输。主要包括音频模拟信号的转换以及以太网的传输
  • 目前,随着多媒体应用普及,千兆位以太网已经发展成为主流网络技术。大到成千上万人大型企业,小到几十人中小型企业,在建设企业局域网时都会把千兆位以太网技术作为高速网络技术。千兆位以太网技术甚至正在...
  • 摘 要:本文介绍了基于FPGA、功能经过扩展的以太网MII接口的硬件实现方法。硬件结构上由控制信号模块、分频器、异步FIFO缓冲和4b/5b编×××4个部分组成。 关键词:100M以太网MII;FPGA;奇偶分频器;4b/5b编解码...
  • 基于FPGA的千兆以太网的实现(1)

    千次阅读 2020-03-21 23:01:49
    基于FPGA的以太网图片接收项目简述UDP协议讲解V3学院的上位机传送图像数据的数据流项目的实验框图跨时钟域处理时序图Image_ctrl时序图工程代码测试模块的代码测试结果总结 项目简述 本次实验我们将完成千兆以太网...
  • 目前,随着多媒体应用普及,千兆位以太网已经发展成为主流网络技术。大到成千上万人大型企业,小到几十人中小型企业,在建设企业局域网时都会把千兆位以太网技术作为首选高速网络技术。千兆位以太网技术甚
  • 基于以太网的组网技术是工业...但每个标准都采用不同的技术来提供实时性能,一些采用定制硬件,一些利用定制软件,还有的采用完全标准的以太网/TCP/IP实现。结果就出现了众多不同等级性能、不同成本的互不兼容标准。
  • 基于FPGA的千兆以太网开发(1)和基于FPGA的千兆以太网开发(2)中介绍了以太网的基本信息和接口介绍,本节将下板一步步调试。 1 RGMII接口 在 千兆以太网模式下,TXC和RXC的时钟为125MHZ,TXC由MAC产生,RXC由PHY...
  • 基于FPGA实现网络传输协议系统,赵振廷,张刚,在FPGA上实现了传输TCP协议和UDP协议、网络层IP协议、链路层地址解析协议和以太网MAC协议,并提供标准MII接口。在ISE中进行软件
  • 目前,随着多媒体应用普及,千兆位以太网已经发展成为主流网络技术。大到成千上万人大型企业,小到几十人中小型企业,在建设企业局域网时都会把千兆位以太网技术作为首选高速网络技术。千兆位以太网技术甚至...
  • 88E1111属于TCP/IP协议栈中的物理层器件,支持不同形式的数据转换为以太网所支持的传输媒介,例如支持1000BASE-T、100BASE-T、10BASE-T类型的以太网传输。支持CAT-5类非屏蔽双绞线上的数据收发。可以直接连接到MAC/...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 178
精华内容 71
关键字:

基于fpga的以太网传输