• List item

上一篇教程介绍了NEXYS4 开发板中DDR2的使用方式,这一篇介绍不可或缺的网络接口RJ45在FPGA开发板中的使用

FPGA基础入门【10】开发板Ethernet PHY局域网配置

  • 板载局域网芯片
    • 网络层级模型
    • 芯片简介
      • 引脚定义
      • 数据通路
      • 芯片复位
      • 控制寄存器
      • 收发时序
  • 逻辑设计
    • 状态机设计
    • 顶层代码设计
  • 模拟仿真
    • Testbench
    • 仿真脚本
    • 仿真结果
  • 编译烧写
  • 总结

板载局域网芯片

NEXYS 4上的局域网接口RJ45使用常见的LAN8720A物理层芯片,支持10兆网和100兆网,使用RMII(Reduced Media Independent Interface)。它的文档在此:LAN8720A

NEXYS 4文档中介绍说,使用EDK(Embedded Development Kit)的工程可以用axi_ethernetlit或者axi_ethernet IP访问物理层芯片。使用EDK的意思是利用FPGA内自带的ARM核,放入一个小型的Linux核心,比如Microblaze或Zynq,然后用软件编程的形式收发数据。

网络层级模型

网络传输TCP/IP五层模型如下,最顶层的用户产生数据,经过层层包装到最底层的物理层传输出去,到接收端在经过层层拆包验收后传到接收端的用户,各层负责把数据包往下传(实线),但实际上是在和另一端的相对应层互相握手沟通(虚线)。这个过程包含很多的细节,除了物理层是由LAN8720A芯片和RJ45接口完成的以外,其他都是由FPGA内部逻辑或者ARM核中的软件逻辑完成的。

这个系列的教程还没有到将各种接口综合到Linux核心的阶段,EDK先向后放,我们优先用PL(programmable logic)部分测试其基础功能,以此学习加强理解

芯片简介

LAN8720A的外部连接应该如下,我们需要做的是写一个简单的10/100 Ethernet MAC,其他部分在开发板上已经存在

芯片内部结构如下,下面慢慢介绍

引脚定义

在开发板上和FPGA的连接如下

相关引脚简介:

  • TXD1, TXD0,MAC层输出到物理层的信号
  • TXEN,表示TXD[1:0]上有有效信号
  • RXD1, RXD0,物理层传给MAC层的信号
  • RXERR,接收错误信号,该信号升高表示物理层收到了错误信号
  • PHYAD0,物理层地址配置引脚,不拉低时则默认拉高
  • MODE2, MODE1, MODE0,物理层模式配置引脚
  • CRS_DV,有效信息接收信号,该信号升高表示物理层收到了有效信号
  • MDIO,物理层SMI(Serial Management Interface)数据出入,不用时被拉高
  • MDC,物理层SMI(Serial Management Interface)时钟信号
  • RESET#,低电平激发的硬件复位引脚,不用时被拉高
  • INT#,中断输出
  • REFCLKO,50MHz参考时钟输出
  • CLKIN,50MHz时钟输入
  • LED1,有效链接指示灯,RJ45接口上的绿灯,表示建立了有效连接,当CRS为高时会闪烁
  • LED2,连接速度指示灯,RJ45接口上的黄灯,亮起表示在使用百兆网,灭表示在使用十兆网

在右侧的信号是在RESET#信号拉低,也就是复位状态是有效的,当复位结束,RESET#拉高,相应信号就被读入芯片内部。这种模式被称为configuration strap,不知道该怎么翻译

在configuration strap时MODE引脚的配置就可以调配寄存器中相应位数的默认值,这样常见的配置模式就不需要写寄存器来配置,还是很方便的

数据通路

数据信号在芯片内部流通过程我们并不关心,不过还是简单介绍一下。

发送端如下

  1. 50MHz的时钟,每个时钟带2bit信号,共100Mbit/s,在RMII转成25MHz * 4bit
  2. 4b/5b编码,让0和1平均,并不会长时间持续出现,4bit数据被编码成5bit,125Mbit/s
  3. 经过扰码(数据包互相交织,将可能全部出错的数据包分摊到多个数据包中)和PISO (并行进入串行输出 Parallel in Serial out)
  4. NRZI编码和MLT-3编码,NRZI简单说是1变0不变,MLT-3把正负1的信号变成正负1加上个0的三阶信号
  5. 发送端驱动Tx Driver将数据转化成模拟信号输出

    接收端相反,只是需要多一个时钟恢复电路,利用传输的信号本身,提取连续变化的部分经过反馈电路形成和信号同步的时钟

芯片复位

LAN8720A的芯片复位分为硬件复位和软件复位,硬件复位是把RESETn引脚拉低至少100us;软件复位是给控制寄存器0的最高位[15]写入1,并等待0.5s,具体操作之后就介绍。

这篇教程会在逻辑开始时先后把硬件复位和软件复位都进行一遍。

控制寄存器

SMI串行管理接口读写数据的时序图如下,MDC的频率不固定,只要周期在400ns以上就好,也就是频率在2.5MHz以下,保险起见我们选择1MHz。并且我们选择在时钟下降沿输出或者读入数据,避免上升沿的冲突

PHY Address物理层地址默认是0,在复位状态时把引脚PHYAD1拉高可以修改物理层地址到1,如果你需要更高的地址就需要配置寄存器了。当你有多个物理层芯片连在一起时就需要配置不同的物理层地址来分别访问

Register Address寄存器地址和不同寄存器有关,寄存器表如下

在这之中最重要的寄存器是前5个
基础控制寄存器,地址0,可读写:

  • [15],软件复位,默认为0,设为1即软件复位开始
  • [14],回路模式,默认为0,设为1即回路模式
  • [13],速度选择,0为十兆网,1为百兆网
  • [12],自动速度识别使能,0为关闭自动速度识别,1为开启自动速度识别
  • [11],电源关闭,默认为0,设为1关闭电源
  • [10],隔离模式,默认为0,设为1隔离物理层和RMII接口
  • [9],重启自动速度识别,默认为0,设为1重启自动速度识别
  • [8],双工模式,0为半双工,1为全双工
  • [7:0]是保留位

基础状态寄存器,地址1,仅可读

这个寄存器只要看后面几位就好,看自动速度识别是否完成,连接是否完成

物理层ID1寄存器,地址2,可读写

作为寄存器读取测试使用,看其读出默认数据是否正确

物理层ID2寄存器,地址3,可读写

同样可以作为寄存器读取测试使用

自动识别广播寄存器,地址4,可读写

这个寄存器在复位模式配置MODE时需要注意,具体可以参考上面的模式选择表

收发时序

在所有寄存器都配置完成后,我们就可以用下面这个时序图来收发数据了。可以看出LAN8720A的收发数据是在时钟下降沿发生的

逻辑设计

基础思路是,先硬件复位,配置configuration strap,再进行软件复位,读取几个寄存器以确保一切正常后等待CRS_DV引脚来读取数据。这里不打算涉及负责的网络协议,随便找个网口连接后,看到有数据即可,不涉及数据包内部内容。

状态机设计

根据上面的设计,做出如下状态机,当中加入了为ChipScope准备的辅助开关

顶层代码设计

module ethernet(input       clk,input       rst,input       switch_continue,output reg  led,// LAN8720A PHY chip portinout       MDIO,output wire MDC,output reg  RESETn,inout       RXD1_MODE1,inout       RXD0_MODE0,inout       RXERR_PHYAD0,output reg  TXD0,output reg  TXD1,output reg  TXEN,inout       CRS_DV_MODE2,inout       INT_REFCLKO,output reg  CLKIN
);

引脚定义。里面加入了一个叫switch_continue的引脚,它被连接到第二个拨动开关上,用来把状态机停在读取寄存器之前,不然我们很难在ChipScope上抓取相应数据

这里我们第一次用到了inout这种端口定义,顾名思义是出入复用的引脚,它的用法如下(不包含在最终代码中,只是示例)

双向引脚一般有一个输出使能引脚,输出时连接到相应的寄存器输出上,输入则转为高阻态1’bz,而输入信号则赋值给另一个wire,传递出去或者到另一个寄存器

module bidirec (oe, clk, inp, outp, bidir);// Port Declarationinput   oe;
input   clk;
input   [7:0] inp;
output  [7:0] outp;
inout   [7:0] bidir;reg     [7:0] a;
reg     [7:0] b;assign bidir = oe ? a : 8'bZ ;
assign outp  = b;// Always Constructalways @ (posedge clk)
beginb <= bidir;a <= inp;
endendmodule

输出50MHz到LAN8720A的CLKIN引脚

// Clock to LAN8720A is 50MHz, need to be lowered down
always @(posedge clk or posedge rst) beginif(rst) beginCLKIN <= 1'b0;endelse beginCLKIN <= ~CLKIN;end
end

双向引脚配置

// Control of the bi-directional data
reg  [2:0] MODE;
reg        PHYAD0;
reg        INTSEL;
reg        strap_oe;
wire [1:0] RXD;
(* dont_touch = "true" *)reg  [1:0] rxd_d;
wire       RXERR;
(* dont_touch = "true" *)reg        rxerr_d;
wire       CRS_DV;
(* dont_touch = "true" *)reg        crs_dv_d;
wire       INT;assign RXD1_MODE1   = (strap_oe) ? MODE[1] : 1'bz;
assign RXD0_MODE0   = (strap_oe) ? MODE[0] : 1'bz;
assign RXERR_PHYAD0 = (strap_oe) ? PHYAD0  : 1'bz;
assign CRS_DV_MODE2 = (strap_oe) ? MODE[2] : 1'bz;
assign INT_REFCLKO  = (strap_oe) ? INTSEL  : 1'bz;assign RXD = {RXD1_MODE1, RXD0_MODE0};
assign RXERR = RXERR_PHYAD0;
assign CRS_DV = CRS_DV_MODE2;
assign INT = INT_REFCLKO;

状态机定义

// State machine
parameter IDLE         = 4'd0;
parameter RESET        = 4'd1;
parameter RDPHYID1     = 4'd2;
parameter RDPHYID2     = 4'd3;
parameter RESET_SOFT   = 4'd4;
parameter UNRESET_SOFT = 4'd5;
parameter SETMODE      = 4'd6;
parameter UNRESET      = 4'd7;
parameter RD_BC0       = 4'd8;
parameter RD_BS1       = 4'd9;
parameter RX_TX        = 4'd10;(* dont_touch = "true" *)reg [3:0]  state;
(* dont_touch = "true" *)reg [3:0]  next_state;
(* dont_touch = "true" *)reg [15:0] data_from_SMI;

SMI读写模块,在后面加入子模块内容

// SMI management
reg         wrh_rdl;
reg  [4:0]  reg_addr;
reg  [15:0] wr_data;
wire [15:0] rd_data;
reg         SMI_start;
wire        SMI_complete;
wire        MDI;
wire        MDO;
wire        MD_OE;assign MDIO = (MD_OE) ? MDO : 1'bz;
assign MDI = MDIO;SMI_manage SMI_manage(.clk(clk),.rst(rst),.mdc(MDC),.mdo(MDO),.mdi(MDI),.md_oe(MD_OE),.wrh_rdl(wrh_rdl),.reg_addr(reg_addr),.wr_data(wr_data),.rd_data(rd_data),.start(SMI_start),.complete(SMI_complete)
);

状态机具体实现

always @(posedge clk) beginled <= INT;
end// State machine
always @(posedge clk or posedge rst) beginif(rst) beginstate <= IDLE;endelse beginstate <= next_state;end
endreg [25:0] wait_count;
(* dont_touch = "true" *)reg        read_phase;
(* dont_touch = "true" *)reg [3:0]  read_data;always @(posedge clk) begincase(state)IDLE: beginnext_state <= RESET;RESETn <= 1'b0;reg_addr <= 5'd0;wrh_rdl <= 1'b0;SMI_start <= 1'b0;data_from_SMI <= 16'h0000;wait_count <= 26'd0;PHYAD0 <= 1'b0; // Set PHY address to 0INTSEL <= 1'b1; // REF_CLK In ModeMODE <= 3'b111;strap_oe <= 1'b1;read_phase <= 1'b0;read_data <= 4'd0;endRESET: beginnext_state <= SETMODE;RESETn <= 1'b0;end// Need to wait for 200us, which is 20000 clock cycles in 100MHzSETMODE: beginMODE <= 3'b111;PHYAD0 <= 1'b0;INTSEL <= 1'b1;if(wait_count < 26'd20000) beginwait_count <= wait_count + 26'd1;endelse beginnext_state <= UNRESET;endendUNRESET: beginstrap_oe <= 1'b0;RESETn <= 1'b1;wait_count <= 26'd0;if(switch_continue) beginnext_state <= RESET_SOFT;endendRESET_SOFT: beginif(SMI_complete) beginnext_state <= UNRESET_SOFT;SMI_start <= 1'b0;endelse beginSMI_start <= 1'b1;wrh_rdl <= 1'b1;reg_addr <= 5'd0;wr_data <= 16'h8000;endend// Need to be kept in software reset for about 0.5sUNRESET_SOFT: beginif(wait_count < 26'd50000000) beginwait_count <= wait_count + 26'd1;endelse beginnext_state <= RDPHYID1;endendRDPHYID1: beginif(SMI_complete) begindata_from_SMI <= rd_data;next_state <= RDPHYID2;SMI_start <= 1'b0;endelse beginSMI_start <= 1'b1;wrh_rdl <= 1'b0;reg_addr <= 5'd2;endendRDPHYID2: beginif(SMI_complete) begindata_from_SMI <= rd_data;next_state <= RD_BC0;SMI_start <= 1'b0;endelse beginSMI_start <= 1'b1;wrh_rdl <= 1'b0;reg_addr <= 5'd3;endendRD_BC0: beginif(SMI_complete) begindata_from_SMI <= rd_data;next_state <= RD_BS1;SMI_start <= 1'b0;endelse beginSMI_start <= 1'b1;wrh_rdl <= 1'b0;reg_addr <= 5'd0;endendRD_BS1: beginif(SMI_complete) begindata_from_SMI <= rd_data;next_state <= RX_TX;SMI_start <= 1'b0;endelse beginSMI_start <= 1'b1;wrh_rdl <= 1'b0;reg_addr <= 5'd1;endendRX_TX: beginSMI_start <= 1'b0;rxd_d <= RXD;rxerr_d <= RXERR;crs_dv_d <= CRS_DV;if(crs_dv_d) beginread_phase <= ~read_phase;  // invert every time a new signal detectedif(read_phase) beginread_data[1:0] <= rxd_d;endelse beginread_data[3:2] <= rxd_d;endendenddefault: beginnext_state <= IDLE;endendcase
endendmodule

状态机SMI接口控制子模块

module SMI_manage(input             clk,input             rst,output reg        mdc,output reg        mdo,input             mdi,output reg        md_oe,input             wrh_rdl,input      [4:0]  reg_addr,input      [15:0] wr_data,input             start,output reg [15:0] rd_data,output reg        complete
);

接口定义

  • clk, rst是时钟和复位
  • mdc时钟,mdo输出,mdi输入,md_oe输出使能
  • wrh_rdl,高电平是写指令,低电平时读指令
  • reg_addr,寄存器地址
  • wr_data,写指令用的16位数
  • start,其上升沿作为一个指令的开始
  • rd_data,一个读指令读出来的16位数
  • complete,完成信号,表示可以开启下一个指令
// MDIO input and output control
reg  mdi_d;always @(posedge clk) beginmdi_d <= mdi;
end// MDC generator, count to 50 and invert, 100MHz => 1MHz
reg  [5:0] mdc_count;
reg        mdc_en;
reg  [1:0] mdc_d;
wire       mdc_negedge;
wire       mdc_posedge;always @(posedge clk or posedge rst) beginif(rst) beginmdc_count <= 6'd0;mdc <= 1'b0;endelse if(mdc_en) beginif(mdc_count < 6'd50) beginmdc_count <= mdc_count + 6'd1;endelse beginmdc_count <= 6'd0;mdc <= ~mdc;endend
end

由使能信号控制的mdc时钟输出,每延迟50个时钟反一次,把100MHz降频到1MHz

// negative edge detection, MDIO read and write only happen at negative edge
always @(posedge clk) beginmdc_d <= {mdc_d[0], mdc};
end
assign mdc_negedge = (mdc_d == 2'b10) ? 1'b1 : 1'b0;
assign mdc_posedge = (mdc_d == 2'b01) ? 1'b1 : 1'b0;// Detect the rising edge of input signal start
reg [1:0]  start_d;
wire       start_posedge;always @(posedge clk) beginstart_d <= {start_d[0],start};
end
assign start_posedge = (start_d == 2'b01) ? 1'b1 : 1'b0;

侦测mdc的下降沿和start信号的上升沿,避免信号持续时间长短导致的逻辑错误

// State machine with three parts
reg [1:0]  state;
reg [5:0]  md_count;
reg [45:0] data1;
reg [15:0] data2;
reg        complete_d;always @(posedge clk or posedge rst) beginif(rst) beginstate <= 2'b00;complete <= 1'b0;mdc_en <= 1'b0;md_count <= 6'd0;mdo <= 1'b1;md_oe <= 1'b0;data1 <= 46'd0;data2 <= 16'd0;rd_data <= 16'd0;endelse begincase(state)// Wait for start signal2'b00: beginmd_count <= 6'd0;md_oe <= 1'b0;mdo <= 1'b1;complete <= complete_d;complete_d <= 1'b0;if(start_posedge) beginstate <= 2'b01;mdc_en <= 1'b1;data1 <= {32'hFFFFFFFF, 2'b01, (wrh_rdl)?2'b01:2'b10, 5'h00, reg_addr};data2 <= wr_data;endend// Preamble, Start of Frame, OP Code, PHY addr, reg addr// length of 462'b01: beginmd_oe <= 1'b1;if(mdc_negedge) begin{mdo,data1} <= {data1,1'b0};endif(mdc_negedge & (md_count < 6'd45)) beginmd_count <= md_count + 6'd1;endelse if(mdc_negedge) beginmd_count <= 6'd0;state <= 2'b10;endend// Turn around// length of 22'b10: beginif(mdc_negedge && (md_count == 6'd0)) beginmd_count <= 6'd1;endelse if(mdc_negedge) beginmd_count <= 6'd0;md_oe <= wrh_rdl;state <= 2'b11;endend// Data to or from PHY// length of 162'b11: beginif(mdc_negedge) begin{mdo,data2} <= {data2,1'b0};rd_data <= {rd_data[14:0], mdi_d};endif(mdc_negedge & (md_count < 6'd15)) beginmd_count <= md_count + 6'd1;endelse if(mdc_negedge) beginmd_count <= 6'd0;state <= 2'b00;complete <= 1'b1;complete_d <= 1'b1;endendendcaseend
endendmodule

SMI控制子模块内部也有一个小的状态机,用来控制SMI指令不同部分:前序、读写模式、物理层地址、寄存器地址、读写翻转、读/写数据。

大致可以分为46位的输入、翻转、读/写数据和等待四部分,分别对应这个状态机的各个部分

模拟仿真

Testbench

仿真用的testbench和前面的教程比较相似,没有包括LAN8720A的仿真模块(其实是没找到),主要以后期的ChipScope为主。代码如下

`timescale 1ns/1nsmodule tb_ethernet;reg clock;
reg reset;
wire led;initial beginclock = 1'b0;reset = 1'b0;// Reset for 1us#100 reset = 1'b1;#1000reset = 1'b0;
end// Generate 100MHz clock signal
always #5 clock <= ~clock;ethernet ethernet_top(.clk          (clock),.rst          (reset),.switch_continue (1'b1),.led          (led),// LAN8720A PHY chip port.MDIO         (),.MDC          (),.RESETn       (),.RXD1_MODE1   (),.RXD0_MODE0   (),.RXERR_PHYAD0 (),.TXD0         (),.TXD1         (),.TXEN         (),.CRS_DV_MODE2 (),.INT_REFCLKO  (),.CLKIN        ()
);endmodule

仿真脚本

写一个简单的仿真脚本sim.do,由于没有调用Xilinx的IP,不需要包含库文件和glbl.v:

vlib work
vlog ../src/ethernet.v ../src/SMI_manage.v ./tb_ethernet.v
vsim work.tb_ethernet -voptargs=+acc +notimingchecks
log -depth 7 /tb_ethernet/*
do wave.do
run 1ms

仿真结果


调用仿真脚本do sim.do后,得到如上方结果,放大可以看到SMI控制的具体细节,不过由于读取引脚悬空,没有连接任何信号,读出来的是蓝色代表的高阻态

编译烧写

新建一个叫ethernet的project,初始配置可以参考之前的教程。添加代码文件ethernet.v和SMI_manage.v。

下一步加入约束constraint文件ethernet.xdc,同样这是用标准模板取自己需要部分修改出来的(NEXYS 4 DDR Master XDC):

## This file is a general .xdc for the Nexys4 DDR Rev. C
## To use it in a project:
## - uncomment the lines corresponding to used pins
## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project## Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk]##Switchesset_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports rst]
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports switch_continue]## LEDsset_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports led]##SMSC Ethernet PHYset_property -dict {PACKAGE_PIN C9 IOSTANDARD LVCMOS33} [get_ports MDC]
set_property -dict {PACKAGE_PIN A9 IOSTANDARD LVCMOS33} [get_ports MDIO]
set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports RESETn]
set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports CRS_DV_MODE2]
set_property -dict {PACKAGE_PIN C10 IOSTANDARD LVCMOS33} [get_ports RXERR_PHYAD0]
set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports RXD0_MODE0]
set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS33} [get_ports RXD1_MODE1]
set_property -dict {PACKAGE_PIN B9 IOSTANDARD LVCMOS33} [get_ports TXEN]
set_property -dict {PACKAGE_PIN A10 IOSTANDARD LVCMOS33} [get_ports TXD0]
set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports TXD1]
set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports CLKIN]
set_property -dict {PACKAGE_PIN B8 IOSTANDARD LVCMOS33} [get_ports INT_REFCLKO]

到这里可以点击 Run Synthesis做综合,几秒钟完成后用Set Up Debug配置ChipScope:

设置观察长度为8192,因为持续时间会比较长。下面就可以Run Implementation和Generate Bitstream生成配置文件了。

和前面的教程一样,USB线连接NEXYS4板子,开启Hardware Manager,然后auto连接上板子,Program Device烧写进程序,注意Debug probes file有对应的ltx文件,完成后用网线连接任意一台主机或者猫到开发板上的RJ45接口,只要把RESET拨回到0,就可以看到它旁边的两个LED灯亮起:

下面看ChipScope抓取的结果,观察前面的代码,我们有加入一个辅助ChipScope的开关,用的是第二个开关,而复位是第一个开关。如此设计来观察不同的寄存器读取:

  1. 烧写编译好的程序
  2. Switch_continue拉低,阻止状态机前进,复位拉高进入复位状态
  3. 复位拉低,进行硬件复位和软件复位
  4. 在ChipScope中,配置trigger为state等于某个值,并点击开始抓取,可以看到ChipScope处在等待trigger的状态
  5. 拉高Switch_continue,让状态机继续前进,可以从ChipScope中看到希望的状态机的读取结果

我们读取了四个寄存器,它们在ChipScope里的结果分别如下

PHYID1读出的结果是0x0007:

PHYID2读出的结果是0xc0f1:

Basic Control基础控制寄存器的结果是0x3000

Basic Status基础状态寄存器的结果是0x7809

查阅文档可以看出读出的结果和预期是相符的。

在这之后我们就可以看看是否从网线上读出了什么数据,修改ChipScope的trigger为CRS_DV上升沿R,抓取到的数据如下:

可以清楚的看到LAN8720A接收到了一串数据包,放大可以看清具体数据,如果仔细分析甚至可以看到IP地址、MAC地址之类的信息,这个就不公开了,可以自己尝试后自己分析

总结

这篇教程介绍的是NEXYS 4开发板上局域网物理层芯片LAN8720A的用法,这块芯片因为配置简单而非常常用,市面上可以买到的嵌入式局域网模块很多都是基于这款芯片,因此这篇教程不只是针对FPGA的开发者,还可以让其他嵌入式系统的学习者借鉴,比如想用Arduino控制类似局域网模块的开发者。

NEXYS 4上已经介绍了一部分接口,剩下的有UART串口通信、USB接口、麦克风、Pmod通用接口、温度传感器、模数转换ADC、音频接口、视频接口VGA。当全部介绍过之后,一个熟练的FPGA开发者就可以综合利用板上的几乎全部资源,再加上FPGA强大的并行计算能力,能做出很多ARM架构嵌入式系统无法完成的效果。

下一篇介绍UART串口通信,利用平时烧写芯片的USB线和开发板通信

FPGA基础入门【10】开发板Ethernet PHY局域网配置相关推荐

  1. FPGA基础入门【12】开发板USB鼠标控制

    上一篇教程介绍了NEXYS4 开发板中UART串口通信的使用方式,这一篇介绍USB接口接收鼠标和键盘信号 FPGA基础入门[12]开发板USB鼠标控制 开发板USB芯片 信号时序图 鼠标初始化 逻辑设 ...

  2. FPGA基础入门【8】开发板外部存储器SPI flash访问

    前两篇教程利用数码管project介绍了chipscope和各种烧写开发板的方式,这篇开始继续探索开发板,这次关注外置存储器的控制,外置指的是芯片外部,不是开发板外部.板子上的外置存储器有DDR2和S ...

  3. FPGA基础入门【1】Vivado官方免费版安装

    本人自本科大二开始接触FPGA相关知识,现已将近五年,从这篇开始将从比较基础的角度讲述如何一步步了解FPGA.我相信动手一步步做下去是从零开始学习知识的最快方法,因此不会从最基础开始讲,而是在碰到相应 ...

  4. FPGA基础入门【3】Blink逻辑及仿真

    从这一篇开始正式介绍FPGA中的硬件逻辑,第一个目标就是从零开始在NEXYS 4开发板上实现闪烁LED. 软件编程中hello world是初学语言中实现的第一个功能,而硬件编程中blink是同等的地 ...

  5. FPGA基础入门【6】ChipScope的使用

    当FPGA设计中复杂度慢慢变高的时候,仿真的手段也要增加,目前我们仿真的手段都是在ModelSim中配置相应的testbench,给模块发送需要的信号.这种软件仿真的方式有几个缺点: 一个是软件仿真速 ...

  6. FPGA基础入门篇(四) 边沿检测电路

    FPGA基础入门篇(四)--边沿检测电路 一.边沿检测 边沿检测,就是检测输入信号,或者FPGA内部逻辑信号的跳变,即上升沿或者下降沿的检测.在检测到所需要的边沿后产生一个高电平的脉冲.这在FPGA电 ...

  7. 一期完结《一篇文章让你从HTML零基础入门前端开发》12.28

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VRcXH9FM-1672214813897)(./assets/%E7%8E%84%E5%AD%90Shaer-%E4% ...

  8. 【视频回放与课件】零基础入门AI开发

    今天上午,受广州图书馆邀请,在第一讲<零代码上手人工智能>的基础上,以<零基础入门AI开发>为主题,分四步解锁人工智能学习的概念与开发工具,让您在一小时内轻松掌握人工智能开发要 ...

  9. 零基础学习MSP430F552LP开发板,学习前期准备,Code Composer Studio(CCS)软件的安装

    零基础学习MSP430F552LP开发板 一.前言 零基础学习MSP430F552LP开发板,为电子设计竞赛做准备以及学好这一款芯片. 在选择比赛题目时,发现有的题目时规定使用ti的芯片作为控制MCU ...

  10. Linux基础入门--驱动开发--USB

    Linux基础入门--驱动开发--USB 1.基本概念 2.组成结构 2.1 设备描述符 2.2 配置描述符 2.3 接口描述符 2.4 端点描述符 2.5 字符串描述符 3.管道 4.端点分类 4. ...

最新文章

  1. R堆叠柱状图各成分连线画法:突出展示组间物种丰度变化
  2. 第19件事 财务分析
  3. iOS Provisioning Profile(Certificate)与Code Signing详解
  4. 肝!Shell 脚本编程最佳实践
  5. python之邮件发送自动化
  6. 介绍一种更方便的代理池实现方案
  7. 【Leetcode】Remove Duplicates from Sorted Array II
  8. 安装部署shipyard
  9. 会计计算机学什么软件有哪些,会计一般学什么软件有哪些
  10. Good Numbers (hard version)cf#595(Div.3)
  11. Elasticsearch.service failed after enable elasticsearch security features
  12. 艺术与科技的跨界融合 Jya美学家电品牌发布
  13. extern关键字作用
  14. 计算机开机一直无法访问,电脑开机时显示:AutoIt 错误 不能打开脚本文件 如何处理...
  15. pytho运算符练习
  16. 利用Photoshop对证件照换底且抠出头发丝
  17. Linux中修改或重置密码
  18. jmeter响应数据为空的问题
  19. 懈寄生---走出软件作坊:三五个人十来条枪 如何成为开发正规军(十四)(转载)
  20. C++案例 三只小猪称体重

热门文章

  1. 计算存储和网络是推动云计算发展的三驾马车
  2. 需求分析——需求具备哪些特征
  3. 对于计算机网络 其安全措施都有哪些,网络安全问题防范措施有哪些
  4. AppleScript+JavaScript自动认证校园网
  5. C盘用户里的文件夹改名
  6. 百度CTO李一男:未来五年电子商务是关注重点
  7. 批量删除QQ空间说说和日志的js脚本
  8. 【Unity】问题记录:Some objects were not cleaned up when closing the scene
  9. 笔记本计算机怎么进入安全模式启动,笔记本怎么进入安全模式 【使用步骤】...
  10. 如何安装linux系统步骤