以太网基础⑥ ZYNQ PS端 基于LWIP的TCP例程测试

1.今日摸鱼任务

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 实现:基于 LWIP模板的TCP****回环测试 以官方模板中的 LwIP Echo Server 为例,学习使用 LwIP 模板。 |
| 小梅哥链接:【BX71】基于LWIP模板的TCP回环测试 - ACZ702开发板 - 芯路恒电子技术论坛 - Powered by Discuz! |

2. LWIP简介

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| LwIP 是一个小型开源的TCP/IP 协议栈。保持 TCP 协议主要功能的基础上减少RAM的占用。 |
| Vivado2018.3 中提供 LwIPv2.0.2 版本的 SDK 库,为 Ethernetlite ( axi_Ethernetlite )、 TEMAC ( Axii_ethernet)以及 千兆以太网控制器 和 MAC ( GigE )核提供适配。能够在 MicroBlaze 、 ARM Cortex-A9、 ARM Cortex-A53 、 ARM Cortex-R5 处理器上运行。 Ethernetlite 和 TEMAC 核适用于 MicroBlaze 系统。 千兆以太网控制器 和 MAC ( GigE )核仅适用于 ARM Cortex-A9 ( Zynq-7000 处理器设备)、ARM Cortex-A53 和 ARM Cortex-R5 ( Zynq UltraScale + MPSoC )系统。 |
| 根据 是否基于操作系统 , LwIP 提供了两套 API (术语为 A05PI ),分别如下: Raw API :事件驱动的 API, 在没有操作系统的情况下运行 lwIP 时惟一可用的 API 。 Socket API : bsd 风格的套接字 API 。线程安全,只能从非 tcpip 线程调用。 对于嵌入式而言,通常并不会使用到操作系统,因此大都是使用的 Raw API 。 |
| LwIPv2.0.2: ① 支持多网络接口下的 IP 转发; ② 支持 ICMP 协议; ③ 支持 (Dynamic Host Configuration Protocol,DHCP )协议 , 动态分配 ip 地址 ; ④ 支持 ARP 协议(以太网地址解析协议); ⑤ 支持 IGMP 协议(互联网组管理协议),可以实现多播数据的接收; ⑥ 支持 UDP 协议 ( 用户数据报协议 ) ; ⑦ 支持 TCP 协议 ( 传输控制协议 ) ,包括阻塞控制、 RTT 估算、快速恢复和快速转发。 |
| SDK 中官方模板默认使用的是 Realtek 的 RTL8211 E 芯片,开发板上是RTL8211 F-CG 要注意 PHYSR 寄存器 |
| RTL8211E PHYSR 寄存器 RTL8211E-VB-CG -PDF数据手册-参考资料-立创商城 |
| RTL8211F-CG PHYSR 寄存器 RTL8211F-CG -PDF数据手册-参考资料-立创商城 |
| 这两个寄存器无论是偏移地址 还是位分布都有很大的差异。 导致 PHY 芯片在查询 PHYSR 实时链路读取回错误值,导致自动协商一直处于失败状态。 除此之外,由于Link Speed位分布的不同,无法获取到正确的速度配置。 因此,在使用官方模板时,我们就需要修改这些相关位。 |

3. 硬件逻辑设计

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 3.1 IP核添加与配置 |
| 使用PL侧的以太网,在UG585CH16中,通过 EMIO 路由到 PL 时,其接口类型为 GMII: 所以,除了 ZYNQ 核之外,设计还需要添加一个 GMII 转 RGMII 核 ,用来实现接口类型的转换。 |
| IP 手册 pg160 pg160-gmii-to-rgmii最新说明书手册.pdf-原创力文档 对于 ZYNQ- 7000 系列器件,在使用 GMII to RGMII 核时,需要为其提供 200MHz 输入时钟 。 |
| 设计还需要添加一个 Constant 核,用来输出常量,控制以太网复位信号。 |
| #### 3.1.1 ZYNQ核 |
| #### 3.1.2 GMII to RGMII 核 PHY Address:该项不是以太网 PHY 地址,而是用于标识 MDIO 事务中core 的虚拟地址。 因此该项只需设置一个与板载 PHY 不同的地址即可。 Provide 2 ns Skew on RGMII TXC:选择为 RGMII 的 TXC 添加 2ns 的偏斜; 可以选择由外部 PHY 添加,或由 IP 核通过 MMCM 添加。 Shared Logic :选择是否需要共享时钟资源。 Include Shared Logic in the Core : 只有一个 core,或者存在多个 core 但需要一个 core 共享时钟资源,以驱动其余核时,需要勾选 。 Include Shared Logic in the Example Design: 存在多个core,且已经有一个 core共享了时钟资源用来驱动其他核时,才需要勾选 。 |
| #### 3.1.3 Constant 核 用于控制以太网复位信号,只需给一个常量 1 ,确保以太网不会被复位即可 |
| |
| ### 3.2 端口连接 |
| |
| ### 3.3 .XDC |
| //这里使用的是ACZ702系列的PL端 set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdc] set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdio_io] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[3]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[2]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[1]}] set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[0]}] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rx_ctl] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rxc] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_tx_ctl] set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_txc] set_property IOSTANDARD LVCMOS33 [get_ports {dout_0[0]}] set_property PACKAGE_PIN P14 [get_ports {RGMII_0_rd[0]}] set_property PACKAGE_PIN V15 [get_ports {RGMII_0_rd[1]}] set_property PACKAGE_PIN Y16 [get_ports {RGMII_0_rd[2]}] set_property PACKAGE_PIN P15 [get_ports {RGMII_0_rd[3]}] set_property PACKAGE_PIN N18 [get_ports RGMII_0_rxc] set_property PACKAGE_PIN Y14 [get_ports RGMII_0_rx_ctl] set_property PACKAGE_PIN R18 [get_ports {RGMII_0_td[0]}] set_property PACKAGE_PIN T19 [get_ports {RGMII_0_td[1]}] set_property PACKAGE_PIN T20 [get_ports {RGMII_0_td[2]}] set_property PACKAGE_PIN U20 [get_ports {RGMII_0_td[3]}] set_property PACKAGE_PIN P16 [get_ports RGMII_0_txc] set_property PACKAGE_PIN T17 [get_ports RGMII_0_tx_ctl] set_property PACKAGE_PIN C20 [get_ports MDIO_PHY_0_mdc] set_property PACKAGE_PIN B20 [get_ports MDIO_PHY_0_mdio_io] set_property PACKAGE_PIN B19 [get_ports {dout_0[0]}] |
| .bit .hdf |

4. 软件程序设计

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| SDK,选择模板: |
| 该模板工程会将开发板的 IP 设置为 192.168.1.10 ,并在端口 7 监听数据,对接收到的数据进行回发。 |
| 修改以下参数: |
| xemacpsif_physpeed.c #include "netif/xemacpsif.h" #include "lwipopts.h" #include "xparameters_ps.h" #include "xparameters.h" #include "xemac_ieee_reg.h" #if defined (aarch64) #include "bspconfig.h" #include "xil_smc.h" #endif //此处为了兼容 RTL8211FDI 重定义寄存器地址和掩码 #undef IEEE_SPECIFIC_STATUS_REG #undef IEEE_SPEED_MASK #undef IEEE_SPEED_1000 #undef IEEE_SPEED_100 #define IEEE_SPECIFIC_STATUS_REG 0X1A #define IEEE_SPEED_MASK 0x30 #define IEEE_SPEED_1000 0x20 #define IEEE_SPEED_100 0x10 ******************************************************************** static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr) { u16_t control; u16_t status; u16_t status_speed; u32_t timeout_counter = 0; u32_t temp_speed; xil_printf("Start PHY autonegotiation \r\n"); //开灯 #if 1 XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0D08); XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x11, 0x0009); XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0000); #endif #if 1 //参考 uboot 启动 XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0D04); XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x10, 0x617F); XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, 0x0000); #endif XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control); control |= IEEE_ASYMMETRIC_PAUSE_MASK; control |= IEEE_PAUSE_MASK; control |= ADVERTISE_100; control |= ADVERTISE_10; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &control); control |= ADVERTISE_1000; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE; control |= IEEE_STAT_AUTONEGOTIATE_RESTART; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); control |= IEEE_CTRL_RESET_MASK; XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); while (1) { XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); if (control & IEEE_CTRL_RESET_MASK) continue; else break; } XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); xil_printf("Waiting for PHY to complete autonegotiation.\r\n"); while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { sleep(1); timeout_counter++; if (timeout_counter == 30) { xil_printf("Auto negotiation error \r\n"); return XST_FAILURE; } XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); } xil_printf("autonegotiation complete \r\n"); XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG, &status_speed); if (status_speed & 0x4) { temp_speed = status_speed & IEEE_SPEED_MASK; if (temp_speed == IEEE_SPEED_1000) return 1000; else if(temp_speed == IEEE_SPEED_100) return 100; else return 10; } return XST_FAILURE; } |
| main.c int main() { #if LWIP_IPV6==0 ip_addr_t ipaddr, netmask, gw; #endif /* the mac address of the board. this should be unique per board */ unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x01, 0xfe, 0xc0 }; echo_netif = &server_netif; #if defined (arm) && !defined (ARMR5) #if XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1 || XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 ProgramSi5324(); ProgramSfpPhy(); #endif #endif /* Define this board specific macro in order perform PHY reset on ZCU102 */ #ifdef XPS_BOARD_ZCU102 if(IicPhyReset()) { xil_printf("Error performing PHY reset \n\r"); return -1; } #endif init_platform(); #if LWIP_IPV6==0 #if LWIP_DHCP==1 ipaddr.addr = 0; gw.addr = 0; netmask.addr = 0; #else /* initliaze IP addresses to be used */ IP4_ADDR(&ipaddr, 192, 168, 0, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 0, 1); #endif #endif print_app_header(); lwip_init(); #if (LWIP_IPV6 == 0) /* Add network interface to the netif_list, and set it as default */ if (!xemac_add(echo_netif, &ipaddr, &netmask, &gw, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) { xil_printf("Error adding N/W interface\n\r"); return -1; } #else /* Add network interface to the netif_list, and set it as default */ if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address, PLATFORM_EMAC_BASEADDR)) { xil_printf("Error adding N/W interface\n\r"); return -1; } echo_netif->ip6_autoconfig_enabled = 1; netif_create_ip6_linklocal_address(echo_netif, 1); netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID); print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6); #endif netif_set_default(echo_netif); /* now enable interrupts */ platform_enable_interrupts(); /* specify that the network if is up */ netif_set_up(echo_netif); #if (LWIP_IPV6 == 0) #if (LWIP_DHCP==1) /* Create a new DHCP client for this interface. * Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at * the predefined regular intervals after starting the client. */ dhcp_start(echo_netif); dhcp_timoutcntr = 24; while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0)) xemacif_input(echo_netif); if (dhcp_timoutcntr <= 0) { if ((echo_netif->ip_addr.addr) == 0) { xil_printf("DHCP Timeout\r\n"); xil_printf("Configuring default IP of 192.168.0.2\r\n"); IP4_ADDR(&(echo_netif->ip_addr), 192, 168, 0, 2); IP4_ADDR(&(echo_netif->netmask), 255, 255, 255, 0); IP4_ADDR(&(echo_netif->gw), 192, 168, 0, 1); } } ipaddr.addr = echo_netif->ip_addr.addr; gw.addr = echo_netif->gw.addr; netmask.addr = echo_netif->netmask.addr; #endif print_ip_settings(&ipaddr, &netmask, &gw); #endif /* start the application (web server, rxtest, txtest, etc..) */ start_application(); /* receive and process packets */ while (1) { if (TcpFastTmrFlag) { tcp_fasttmr(); TcpFastTmrFlag = 0; } if (TcpSlowTmrFlag) { tcp_slowtmr(); TcpSlowTmrFlag = 0; } xemacif_input(echo_netif); transfer_data(); } /* never reached */ cleanup_platform(); return 0; } |
| echo.c void print_app_header() { #if (LWIP_IPV6==0) xil_printf("\n\r\n\r-----lwIP TCP echo server ------\n\r"); #else xil_printf("\n\r\n\r-----lwIPv6 TCP echo server ------\n\r"); #endif xil_printf("TCP packets sent to port 5000 will be echoed back\n\r"); } int start_application() { struct tcp_pcb *pcb; err_t err; unsigned port = 5000; /* create new TCP PCB structure */ pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); if (!pcb) { xil_printf("Error creating PCB. Out of Memory\n\r"); return -1; } /* bind to specified @port */ err = tcp_bind(pcb, IP_ANY_TYPE, port); if (err != ERR_OK) { xil_printf("Unable to bind to port %d: err = %d\n\r", port, err); return -2; } /* we do not need any arguments to callback functions */ tcp_arg(pcb, NULL); /* listen for connections */ pcb = tcp_listen(pcb); if (!pcb) { xil_printf("Out of memory while tcp_listen\n\r"); return -3; } /* specify callback to use for incoming connections */ tcp_accept(pcb, accept_callback); xil_printf("TCP echo server started @ port %d\n\r", port); return 0; } |
| 开发板的 MAC 地址 00_0a_35_01_fe_c0 , IP 地址 192.168.0.2 ,监听端口号 5000 。 |

5. 板级验证

//具体的验证步骤就不重复啦,链接的PDF比较详细

//主要是参数修改要看清楚位置,橙色是文件,红色要修改或者复制

相关推荐
两圆相切1 分钟前
ICMPv6报文类型详解表
网络
极地星光10 分钟前
TCP/IP 网络编程面试题及解答
网络·网络协议·tcp/ip
誰能久伴不乏2 小时前
Linux 系统调用详解:操作文件的常用系统调用
服务器·网络·servlet
Lucky高2 小时前
HTTP和HTTPS复习
网络协议·http·https
呉師傅3 小时前
佳能iR-ADV C5560复印机如何扫描文件到电脑
运维·网络·windows·计算机外设·电脑
半梦半醒*4 小时前
Linux网络管理
linux·运维·网络·centos·运维开发
神秘人X7074 小时前
Linux网络配置全攻略:IP、路由与双机通信
linux·网络·tcp/ip
小白iP代理4 小时前
动态IP+AI反侦测:新一代爬虫如何绕过生物行为验证?
人工智能·爬虫·tcp/ip
Lfsd4 小时前
根据ip获取地址库
网络·网络协议·tcp/ip