xilinx 以太网验证方案简介
说明:基于Microblaze+Lwip+perf建立测试工程验证以太网通信
以太网接口:MII/RMII/GMII/RGMII/SGMII(本次主要使用MII/RMII接口)
-------------------------------------------------------------------------------------------------------------------------------------------------
第一部分:建立vivado工程
1、我们可以通过vivado自带的官方example来生成一个microblaze的以太网参考设计:
这个设计时基于官方board的,我们可以选择一个相近的板卡作为参考,我们只需要网口部分,不需要的都不选,简化设计:
参照这个设计,新建一个工程对应到自己的板卡,以及自己的以太网PHY
2、对于mii/gmii/rgmii接口ethernet subsystem ip核是很好支持的,sgmii接口复杂点,目前还我没有找到正确的操作方法
注意microblaze默认高电平复位,但我们外部信号一般是低电平复位的(点到这个引脚,Ctrl+E在属性里面设置下):
以太网对内存有一定要求,我们尽可能把LBM设置大点:
LMB容量最大可以选择4MBytes,在Address Editor更新后,重新生成block里面会同步更新!
同时注意不要有悬空net没有连接:
3、当你有多个Microblaze以及对应的Ethernet Subsytem时:当你只有一个 ETH核时,选第一个,把共享逻辑放在核里;当你有多个ETH核时,保留一个选第一个(共享逻辑放在核里),其它都选第二个(在设计里共享),同时“把共享逻辑放在核里”作为时钟输出将信号给到其它核{此处的区别实际上主要是避免idelayctrl实例多个}
4、Ethernet ip需要license,可以在官网上自行申请:
https://www.xilinx.com/products/intellectual-property/ip-evaluation.html
copy license需要不同的名字否则会把原来的覆盖,同时工程需要重新生成!
5、适配管脚,生成bit,以太网接口需要放到同一Bank
同时要注意clk引脚不能放在bank的boundary位置:【此处为了实现大于1.25ns延时,将idelay和odelay做了级联,使用级联时不能将管脚适配到byte boundary,注意一个bank是4个byte,每个byte有2个nibble,每个nibble一个idelaycrtl(实际一个工程我们只用一个idelaycrtl,在布局布线时应该会自动拷贝)】
参考:https://www.xilinx.com/support/answers/67641.html
关于引脚信息请参考:ug575-ultrascale-pkg-pinout.pdf
http://www.xilinx.com/support/packagefiles/usapackages/usaall.zip
--------------------------------------------------------------------------------------------------------------
第二步:成功生成bit后需要进入SDK中进行后面的软件生成及调试操作:
1、新建Tcp Appllication/选择tcp perf server
2、虽然LBM已经设置到了最大,但编译lwip还是会make error,我们需要配置下lwip的参数:
3、debug
备注:
-------------------------------------------------------------------------------------------------------------------------------------------------------
第三部分:适配自己的phy及网络调试
1、以太网调试首先是要适配自己的phy,xilinx提供的参考例程只是适配了自己的官方板卡的phy,其它型号的phy需要自己适配:
以太网PHY的SMI接口属于总线接口,类似于I2C,每个PHY都是有地址的,lwip不关心这个地址时多少,它会扫描查找31-1(0地址没有查找)
SMI接口频率设置:
unsigned int get_phy_speed_88E1514(XAxiEthernet *xaxiemacp, u32 phy_addr)
{
u16 phy_val;
u16 control;
u16 status;
u16 partner_capabilities;
u16 temp;
//mode select:sgmii reg20_18
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 18);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 20, &temp);
xil_printf("phy_addr:%d mode:%x \r\n",phy_addr,temp);
temp |= 0x0001;
temp &= 0xfff9;
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, 20, temp);
xil_printf("phy_addr:%d mode:%x \r\n",phy_addr,temp);
//reset phy
temp |= 0x8000;
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, 20, temp);
//will add:
//reg:0_1 sgmii negotiation
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 1);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 0, &temp);
xil_printf("phy_addr:%d auto negotiation:%x \r\n",phy_addr,temp);
temp |= 1<<12;//auto negotiation
temp |= 1<<9;//restart auto negotiation
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, 0, temp);
xil_printf("phy_addr:%d auto negotiation:%x \r\n",phy_addr,temp);
//reg:26_1 sgmii negotiation
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 1);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, 26, &temp);
xil_printf("phy_addr:%d auto negotiation:%x \r\n",phy_addr,temp);
temp &= (~(1<<6));//auto negotiation
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, 26, temp);
xil_printf("phy_addr:%d auto negotiation:%x \r\n",phy_addr,temp);
//-----------------------------------------------------------------
xil_printf("Start PHY autonegotiation \r\n");
//reg:21_2(page)
XAxiEthernet_PhyWrite(xaxiemacp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_MAC, control);
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
//reg:4_0(page)
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
control |= IEEE_PAUSE_MASK;
control |= ADVERTISE_100;
control |= ADVERTISE_10;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
////reg:9_0(page) 1000 BASE-T FUll-Duplex/Half-Duplex Advertise
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
&control);
control |= ADVERTISE_1000;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
control);
//reg:16_0(page) Not for 88e1514
//XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
//XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,&control);
//control |= (7 << 12); /* max number of gigabit atphy_valts */
//control |= (1 << 11); /* enable downshift */
//XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,control);
//reg:0_0(page)
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
//reset the phy
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
control |= IEEE_CTRL_RESET_MASK;
XAxiEthernet_PhyWrite(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
while (1) {
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
if (control & IEEE_CTRL_RESET_MASK)
continue;
else
break;
}
//
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
xil_printf("\r\n----------------------------------------\r\n");
//reg:1_0(page)
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
xil_printf("IEEE_STATUS_REG:%x\r\n",status);
AxiEthernetUtilPhyDelay(1);
//reg:19_0(page)
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
&phy_val);
if (phy_val & IEEE_AUTONEG_ERROR_MASK) {
xil_printf("Auto negotiation error \r\n");
}
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_STATUS_REG_OFFSET,
&status);
}
xil_printf("IEEE_STATUS_REG:%x\r\n",status);
xil_printf("autonegotiation complete \r\n");
XAxiEthernet_PhyRead(xaxiemacp, phy_addr, IEEE_SPECIFIC_STATUS_REG,
&partner_capabilities);
if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
return 1000;
else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
return 100;
else /* 10Mbps */
return 10;
}
2、网络报文
ila中抓取到的包:
同时我们也可以在代码里将报文通过串口打印出来分析:
在low_level_input/low_level_ouput函数中将buf数据打印数出来
3、PC端监控:单独将PC和板卡通过一根网线连接,通过抓包软件对PC端网卡进行抓包可以分析两边的通信数据,同时通过wifi连接网络,这时PC端的有线网卡数据比较干净主要是和子卡之间的数据便于调试。
4、perf测试
当dhcp成功给我们的板卡分配一个ip后,便可以进行perf测试,该软件有windows及linux两个版本,也可以通过命令行操作: