本文介绍在RTL8211千兆网络模块基础上实现PS端的EMIO扩展以太网网口功能。
写在前面:
ZYNQ 网络功能可以有4种方式实现
- 一 PS端 MIO功能直接扩展以太网口
- 二 PS端通过EMIO的方式将以太网口映射到PL端口上
- 三 PL端口的硬件以太网功能 通过AXI的方式供PS端调用
- 四 PL端用逻辑跑以太网功能(不需要PS端参与)
我们这里 因为网口接到了 PL端上,所以理论上 可以实现二 三 四, 第二种和第三种方式 其实效果差不多(方式三更占用逻辑资源),而方式四是 FPGA直接控制网络,所以为了方便测试我们先用方式二 EMIO的方式来进行测试
本文在 vivado2018.3版本上 演示, 其他版本请自行研究
工程创建
1)新建一个项目,芯片型号选择按下面选择(板子生产了多个芯片型号,请根据自己板子的型号来进行选择)
- XA7Z020 (直接选择xc7z020CLG400-1,因为系统识别到的是xc7z020-1)
- XC7Z010-1 (xc7z010CLG400-1) (7010 芯片)
- XC7Z020-1 (xc7z020CLG400-1) 后续生产
- XC7Z020-2 (xc7z020CLG400-2) 后续生产
备注 (7020 车规级版在vivado2018.3识别出的是XC7Z020,如果工程选择xa7z020 ,在SDK环境下有时候会弹出警告,所以这里直接选择XC7Z020CLG400-1)
2) 创建一个BLOCK设计,并添加ZYNQ7 PROCESSING SYSTEM模块,软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-3.png)
3)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-70.png)
因为工程暂时用不到 AXI功能,所以可以先禁用AXI功能
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-131.png)
4) 这里把ENET0通过EMIO引出来 ,并且选中MDIO功能
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-125.png)
之后点选OK 来保存ZYNQ的配置
5)由于 ZYNQ的PS 调用EMIO方式 默认输出是GMII,而我们的网络部分的芯片 RTL8211是 输出RGMII的,所以这里我们需要增加一个 GMII和RGMII转换的IP模块 (Gmii to Rgmii)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-126.png)
打开 GMII TO RGMII模块 设置更改成下面
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-127.png)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-128.png)
6) 又因为GMII TO RGMII 是高电平复位 ,但是ZYNQ 是输出低电平复位的,所以这里需要增加一个反相器(搜索utility, 在检索出来的选项里 选择 utility vector logic)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-129.png)
在设置页里改成 not(反相器)将位宽改成1
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-130.png)
7) 按下图方式连接好各个模块(复位 时钟 网络)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-132.png)
8)并通过右键 然后选择Make external 的方式引出RGMII 和MDIO_PHY功能引脚
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-133.png)
9)由于我们的板上 网络部分的时钟25M单独有晶振控制了,所以这里不需要额外引出25M时钟
10)这里还要对Z7的模块进行一个修改,因为gmii to rgmii 模块的clkin 在手册上写要求是200mhz,所以我们这里需要对ZYNQ核的输出时钟频率进行修改
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-135.png)
重新双击ZYNQ的核,将FCLK_CLK0的频率改成200
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-136.png)
12)另外 因为 SDK中 网络功能的例程都需要UART功能来调试,所以这里额外在ZYNQ核心中增加串口功能(选择MIO方式,并且MIO 选择50-51)
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-82.png)
13) 所有的都完成后点选 Run Block Automation,完成后续自动布线
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-137.png)
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-83.png)
14)创建硬件描述,source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示(这一步的作用相当于将图纸转换成对应的硬件描述语言的功能)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-138.png)
15)编写好代码后 对代码进行编译
![](http://www.hellofpga.com/wp-content/uploads/2021/07/image-10.png)
16)添加约束文件 对管脚 和 电平进行约束, 尤其要注意 最下面的时序约束部分 一定要添加,不然大概率无法ping通
set_property PACKAGE_PIN C20 [get_ports {RGMII_0_td[1]}] set_property PACKAGE_PIN E19 [get_ports RGMII_0_tx_ctl] set_property PACKAGE_PIN D20 [get_ports {RGMII_0_td[3]}] set_property PACKAGE_PIN B20 [get_ports {RGMII_0_td[0]}] set_property PACKAGE_PIN D18 [get_ports {RGMII_0_rd[2]}] set_property PACKAGE_PIN F20 [get_ports MDIO_PHY_0_mdio_io] set_property PACKAGE_PIN F19 [get_ports MDIO_PHY_0_mdc] set_property PACKAGE_PIN D19 [get_ports {RGMII_0_td[2]}] set_property PACKAGE_PIN B19 [get_ports {RGMII_0_rd[3]}] set_property PACKAGE_PIN F17 [get_ports {RGMII_0_rd[0]}] set_property PACKAGE_PIN A20 [get_ports RGMII_0_txc] set_property PACKAGE_PIN J18 [get_ports RGMII_0_rxc] set_property PACKAGE_PIN E17 [get_ports RGMII_0_rx_ctl] set_property PACKAGE_PIN E18 [get_ports {RGMII_0_rd[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[1]}] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_tx_ctl] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[2]}] set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdio_io] set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdc] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[0]}] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_txc] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rxc] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rx_ctl] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[1]}] create_clock -period 8.000 -name RGMII_0_rxc -waveform {0.000 4.000} [get_ports RGMII_0_rxc] set_clock_groups -logically_exclusive -group [get_clocks -include_generated_clocks {gmii_clk_25m_out gmii_clk_2_5m_out}] -group [get_clocks -include_generated_clocks gmii_clk_125m_out] set_property SLEW FAST [get_ports {RGMII_0_td[0]}] set_property SLEW FAST [get_ports {RGMII_0_td[1]}] set_property SLEW FAST [get_ports {RGMII_0_td[2]}] set_property SLEW FAST [get_ports {RGMII_0_td[3]}] set_property SLEW FAST [get_ports RGMII_0_tx_ctl] set_property SLEW FAST [get_ports RGMII_0_txc] set_property SLEW FAST [get_ports MDIO_PHY_0_mdc] set_property SLEW FAST [get_ports MDIO_PHY_0_mdio_io]
17. 修改之后 点击 Generate Bitstream 进行综合以及生成Bit 文件
![](http://www.hellofpga.com/wp-content/uploads/2021/07/image-18.png)
等待布线综合完成
PS部分工程创建
1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-140.png)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-142.png)
2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-21.png)
系统将自动打开SDK开发环境
3)在SDK环境下创建网络工程
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-143.png)
输入一个工程名,然后点选下一步,选择 LwIP Echo Server选项,自动导入网络SDK自带的网络例程。
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-149.png)
4)对网络进行调试
硬件部分将网络模块的RJ45接上网线
将主板通过TYPEC 连接电脑(在设备管理器中查看主板的串口在系统中的串口号),并且在SDK 的终端中添加这个串口,如下图所示(波特率115200) 也可以用第三方串口助手来调试
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-156.png)
接下来点选program FPGA 对FPGA进行配置
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-154.png)
接下来点选DEBUG
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-155.png)
最好对RUN AS进行设置 勾选 Reset entire system 和Program FPGA 再下载,否则有可能不能正常访问网络(原因在最下面的备注项)里
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-90.png)
勾选 Reset entire system 和Program FPGA
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-89.png)
通过串口观察到网络已经启动,并且速度为1000M, 网络IP为192.168.1.113(板子需要连接到路由器才能分配到IP) ,如果板子是直接用网线连接PC电脑,请看文章最后的备注
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-157.png)
用相同路由器网段的 WINDOWS电脑 ping 一下这个IP 可以ping 通,说明网络连接成功了
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-158.png)
通过网络助手(百度可以下载)连接后,发送什么数据,就能通过网络接收到什么数据(设置的端口号是7,IP地址按照之前SDK 串口读到的板子IP地址设置)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-159.png)
备注:有部分客户按上述先下载PL 后debug的方法操作 出现无法自动获取路由器的IP(并且无法ping通的情况),并且路由器列表上没有检测到设备(猜测可能是因为PL单独下载后,PS还没下载的情况下,路由器和板子握手失败后,就停止了板子访问网络的权限,造成板子网络部能正常工作),这种情况下可以按下面方法勾选reset entire system,和program fpga选项(让系统每次debug 都能重新配置整个fpga)
a )右键点我们的PS工程,调试界面里 点击RUN AS 里的 设置项目,如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2022/05/image-42.png)
b)设置里勾选 复位整个工程和下载FPGA部分代码的选项 如下图所示,并点击应用和RUN
![](http://www.hellofpga.com/wp-content/uploads/2022/05/image-43.png)
c)勾选上述两个选项后,每次debug的时候,系统都会重新配置FPGA和初始化整个工程,网络功能也恢复正常了。
以上 内容仅供参考
另外,很多网站都是手动把速度设置成1000mbps 但是我这边设置了反而无法连接了,怀疑是phy芯片和demo有点冲突引起的,后续会继续研究,以及大吞吐量测试 以确定网络模块功能正常
后记: 经过IPREF测试 系统大吞吐量测试可以稳定在 940M环境下,模块工作稳定,至于上面的问题应该是PHY握手比较慢,怀疑是官方demo在手动模式下 超时引起的, 设置成自动模式连接千兆没问题(大吞吐量测试图如下, 有时间再整理下大吞吐量的测试方法,也是XILINX的官方demo)
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-50.png)
完整工程如下,SDK程序全部都是官网的例程,具体功能还没深入研究,大家自行研究
下面是网络调试助手
板子和PC 通过网线直连的注意事项
备注: 关于板子和PC 直接通过网线直连, 之前一直发现不成功 无法ping通, 或者板子先和路由器直连,获取到IP后,再拔下网线 将板子和PC 直连,此时可以ping通,但是如果一开始直接直连,就永远都无法ping通, 经过最近的调试终于发现问题了。
板子如果和PC 直连, 此工程必须要接交叉式的网线(也就是PC连PC的网线)才可以正常ping通。( 但是很奇怪当板子跑PYNQ的时候就不需要一定用交叉的网线),怀疑是官方SDK的例程没有打开MDI SWAP 功能导致的(也可能通过程序可以打开,暂时还没找到),所以,如果大家遇到直连ping不通的情况下 ,请试着更换特殊的交叉网线再进行尝试。
直连状态会无法获得IP,那系统自动分配IP 192.168.1.10, 那本地主机也记得将对应的网络口设置成192.168.1.* 的网络段, 网关设置成192.168.1.1才可以ping通
![](http://www.hellofpga.com/wp-content/uploads/2023/09/image-3.png)
![](http://www.hellofpga.com/wp-content/uploads/2023/09/image-4.png)