发 帖  
原厂入驻New
[资料] 【正点原子FPGA连载】第三十三章基于lwip的echo server实验-领航者 ZYNQ 之嵌入式开发
2020-9-8 11:02:37  207 正点原子FPGA
分享
1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/FPGA/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
5)关注正点原子公众号,获取最新资料


第三十三章基于lwip的echo server实验

随着物联网的兴起,万物互联需要一个强大而又灵活的协议体系,TCP/IP协议得天独厚,而在嵌入式网络设备中,由于硬件资源的限制,需要特殊的实现方式。LWIP作为TCP/IP协议的一种轻量级实现方式,满足了这一要求。本章我们利用SDK软件自带的lwIP Echo Server例程模板,初步了解lwip的使用。本章包括以下几个部分:
3333.1简介
33.2实验任务
33.3硬件设计
33.4软件设计
33.5下载验证
33.1简介
1)TCP/IP协议简介
TCP/IP协议中文名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。TCP/IP定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的协议来完成自己的需求。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。
TCP/IP协议不是TCP和IP这两个协议的合称,而是指因特网整个TCP/IP协议族。从协议分层模型方面来讲,TCP/IP由四个层次组成:网络接口层、网络层、传输层、应用层。OSI(Open System Interconnection)是开放式系统互连参考模型,该模型将TCP/IP分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。TCP/IP模型与OSI模型对比如表1.1.1所示。

表 33.1.1 OSI模型与TCP/IP模块



2)LWIP简介
LWIP是瑞典计算机科学院(SICS)的Adam Dunkels等开发的一个小型开源的TCP/IP协议栈,是TCP/IP的一种实现方式。LWIP是轻量级IP协议,有无操作系统的支持都可以运行。LWIP实现的重点是在保持TCP协议主要功能的基础上减少对 RAM的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LWIP协议栈适合在低端的嵌入式系统中使用。关于LWIP的详细信息大家可以去http://savannah.nongnu.org/projects/lwip/这个网站去查阅。
LWIP 的主要特性如下:
•IGMP 协议,用于网络组管理,可以实现多播数据的接收
•Internet协议(IP),包括 ipv4 和 IPv6,支持 IP 分片与重装,包括通过多个网络接口的数据包转发
•用于网络维护和调试的Internet控制消息协议(ICMP)
•用户数据报协议(UDP)
•传输控制协议(TCP)拥塞控制,往返时间(RTT)估计,快速恢复和重传
•DNS,域名解析
•SNMP,简单网络管理协议
•动态主机配置协议(DHCP)
•以太网地址解析协议(ARP)
•AUTOIP,IP 地址自动配置
•PPP,点对点协议,支持 PPPoE
我们本次使用的lwip202_v1_2是一个基于开源lwIP库版本2.0.2构建的SDK库(Vivado 2018.3版本)。lwip202_v1_2库为Ethernetlite(axi_ethernetlite)、TEMAC(axi_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)。
lwip202_v1_2提供二种用户编程接口方式:raw API和socket API。
Raw API:是为高性能和低内存开销而定制的。这种类型的API把网络协议栈和应用程序放在一个进程里,连接网络协议和应用程序的纽带是回调函数,回调函数实际上是一个普通的C函数。为了接收数据,应用程序会首先向协议栈注册一个回调函数,当关联的连接有一个信息到达时,该回调函数就被协议栈调用。这种实现方式即有优点也有缺点。优点是数据的接收和发送不会导致进程的切换,提供了最好的性能,执行速度快,而且消耗的内存资源少;缺点是应用程序无法进行连续运算,因为网络协议的处理和运算是在同一进程中完成的,二者无法并行发生。Raw API是资源较少的嵌入式系统的首选方法,也是在没有操作系统的情况下运行lwIP时唯一可用的API。
Socket API:提供了一个基于open-read-write-close 模块的BSD socket-style接口,需要操作系统。此接口在性能和内存要求方面不如Raw API高效,不适用于小型嵌入式系统,但移植性更好。
本章我们使用无需操作系统(standalone)的RAW API编程接口。
3)PS的千兆以太网控制器
在介绍PS的千兆以太网控制器之前,我们首先了解下MAC与PHY芯片及GMII与RGMII接口。
以太网卡工作在OSI模型的最后两层,物理层和数据链路层,物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。物理层的芯片称之为 PHY。此外PHY还提供了和对端设备连接的重要功能并通过LED灯显示出当前的连接的状态和工作状态。当我们给网卡接入网€€线的时候,PHY不断发出的脉冲信号检测到对端有设备,它们通过一套标准的语言交流,互相协商并确定连接速度、工作模式、是否采用流控等。通常情况下,协商的结果是两个设备中能同时支持的最大速度和最好的双工模式。这个技术被称为AutoNegotiation,即自协商。
数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。以太网卡中数据链路层的芯片称之为MAC控制器。
MAC控制器与PHY通过MII(Medium Independent InteRFace)接口进行连接。MII接口有很多类型,千兆以太网多使用GMII(Gigabit Medium Independent Interface)或RGMII(Reduced Gigabit Media Independent Interface)接口进行连接。



图 33.1.1 GMII接口

GMII接口提供了8位数据通道,125MHz的时钟速率,从而具有1000Mbps的数据传输速率。除MDC和MDIO外,有24根接口信号线,如图 33.1.1所示。
GMII接口主要包括四个部分。一是从MAC层到物理层(PHY)的发送数据接口,二是从物理层到MAC层的接收数据接口,三是从物理层到MAC层的状态指示信号,四是MAC 层和物理层之间传送控制和状态信息的MDIO接口。各部分接口信号说明见下表:

表 33.1.2 GMII接口信号



RGMII接口即Reduced GMII,是GMII接口的简化版本。RGMII采用4位数据接口,工作时钟125MHz,并且在上升沿和下降沿同时传输数据,因此传输速率可达1000Mbps。采用 RGMII的目的是降低电路成本,使实现这种接口的器件的引脚数从24个减少到14个(不包括MDC和MDIO),接口信号如下图所示:



图 33.1.2 RGMII接口

可以看到RGMII接口相对于GMII 接口,在TXD和RXD上总共减少8根数据线。TX_CTL信号线上传送TX_EN和TX_ER两种信息,在TX_CLK的上升沿发送TX_EN,下降沿发送TX_ER;同样的,RX_CTL信号线上传送RX_DV和RX_ER两种信息,在RX_CLK的上升沿发送RX_DV,下降沿发送RX_ER。进一步减少了2根数据线。其他信号同GMII接口。
现在我们来看下PS的千兆以太网控制器(GEM)。PS的千兆以太网控制器实现了与IEEE 802.3-2008标准兼容的10/100/1000 Mb/s以太网MAC,能够以上述三种速度在半双工或全双工模式下运行。PS配备两个千兆以太网控制器。每个控制器都可以独立配置,其内部原理图如下:



图 33.1.3 以太网控制器

DMA控制器通过AHB总线接口连接到存储器。MAC控制器与FIFO接口的连接为嵌入式处理系统中的分组数据存储提供scatter-gather类型的功能。另外从图 33.1.3中可以看到,如果通过MIO连接至PS端的以太网PHY芯片,则每个控制器使用RGMII接口以节省引脚。如果通过EMIO连接至PL端的以太网PHY芯片,则每个控制器使用GMII接口。
可以通过APB总线访问千兆以太网控制器的寄存器。寄存器用于配置MAC的功能、选择不同的操作模式、以及启用和监控网络管理统计信息。控制器为管理PHY芯片提供MDIO接口,可以从MDIO接口控制PHY芯片。
33.2实验任务
本章的实验任务是建立PS的以太网的硬件环境,使用SDK软件自带的Lwip Echo Server模板了解LWIP的使用。
33.3硬件设计
领航者ZYNQ底板上有一个RJ45以太网接口,用于连接以太网线,其原理图如图 33.3.1所示:



图 33.3.1 RJ45接口原理图

以太网的数据传输离不开以太网PHY(物理层)芯片的支持。我们的领航者ZYNQ开发板上使用的PHY芯片为Realtek公司的RTL8211E,其原理图如图 33.3.2所示:



图 33.3.2 RTL8211E原理图

Realtek RTL8211E是高度集成的以太网收发器,符合 10Base-T、100Base-TX和1000Base-T IEEE 802.3标准,提供了所有必要的物理层功能。RTL8211E采用最先进的 DSP 技术和模拟前端(AFE),实现了交叉检测和自动校正、极性校正、自适应均衡、串音消除、回声消除、定时恢复和纠错等功能,以提供10Mbps、100Mbps或1000Mbps的强大传输和接收能力。
在图 33.3.2中,RTL8211E右侧引脚连接到底板的RJ45接口,左侧引脚通过RGMII接口与PS端相连接。MDC/MDIO接口用来配置RTL8211E。其复位信号与PS的PS_POR_B相连接,在PS的上电复位时同时复位RTL8211E,不需要通过MIO来控制。RTL8211E与PS的MIO引脚的连接如图 33.3.3所示。从图 33.3.3可以看到,RTL8211E的RGMII接口通过MIO16-27引脚与PS相连接,MDC/MDIO连接到PS的MIO52-53引脚。



图 33.3.3 RTL8821E同PS的接口

根据实验任务我们可以画出本次实验的系统框图,如下图所示:



图 33.3.4 系统框图

在图 33.3.4中,UART用于打印程序相关的信息,千兆以太网控制器和MAC(GigE)内核通过MIO与外部以太网进行连接。
step1:创建Vivado工程
本次实验的硬件设计可以在《第一章 Hello World》实验的基础上进行。
1-1 我们先打开《第一章 Hello World》实验的Vivado工程,打开后将工程另存为 “lwip_echo_server”工程,如下图所示,然后点击“OK”按钮。



图 33.3.5 另存为工程为lwip_echo

step2:使用IP Integrator创建Processing System
2-1 在Flow Navigator中,点击IP INTEGRATOR下的Open Block Design,如下图所示:



图 33.3.6 打开Block Design

2-2 在打开的下图Diagram窗口,双击打开ZYNQ7 Processing System重定义窗口。



图 33.3.7 重定义ZYNQ7 Processing System

2-3 在打开的重定义窗口中,点击左侧的MIO Configuration,在右侧的界面中展开“I/O Peripherals”。勾选“ENET 0”和其下的“MDIO”,在“IO”列选择ENET 0的IO为MIO16…27,MDIO的IO为MIO52…53。因为MIO的Bank1即原理图中的BANK501为1.8V,所以我们选择Bank1 I/O Voltage为LVCOMS 1.8V。另外设置Speed列的速度为“fast”,如下图所示,完成后,点击右下角的“OK”。



图 33.3.8 PS以太网接口配置界面

2-4 由于不需要添加其它IP,按Ctrl+S快捷键保存Diagram。此时我们的第二步完成,进入第三步
step3:生成顶层HDL
在sources面板中,右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。
step4:生成Bitstream文件并导出到SDK
由于本实验未用到PL部分,所以无需生成Bitstream文件,只需导出到SDK即可。如果使用到PL,则需要添加引脚约束以及对该系统进行综合、实现并生成Bitstream文件。
4-1 导出硬件。
在菜单栏中选择 File > Export > Export hardware。
并在弹出的对话框中,取消勾选“Include bitstream”,直接点击“OK”按钮。
因为是在前一工程的基础上建立的,还保留着前一工程的结果,所以会弹出“Module Already Exported”对话框,我们点击“Yes”按钮。
4-2 硬件导出完成后,选择菜单File->Launch SDK,启动SDK开发环境。
33.4软件设计
首先删除前一实验的工程。下面我们开始第五步——创建应用工程。
step5:在SDK中创建应用工程
5-1 在菜单栏中选择File->New->Application Project, 新建一个SDK应用工程。
5-2 在弹出的图 33.4.1所示界面中,输入工程名“lwip_echo_server”。
在该页面中,我们需要确认Hardware Platform一栏中选择的是本次实验所导出的硬件平台system_wrapper_hw_platform_1。另外,为了方便以后能在此工程的基础上创建其他工程,我们将创建的BSP工程名称修改为一个不与应用工程相关的名称,此处修改“Create New”后面的方框内容为“lwip _server_bsp”,其它选项保持默认,点击“Next”。



图 33.4.1 创建工程

5-3 选择“lwIP Echo Server”工程模版,然后点击“Finish”按钮,如图 33.4.2所示。
lwIP Echo Server应用程序提供了如何使用轻量级IP堆栈(lwIP)的简单演示。此应用程序将领航者开发板MAC地址设置为00:0a:35:00:01:02,默认使用DHCP获取动态IP地址,如果DHCP失败,则使用默认设置的静态IPv4地址192.168.1.10或IPv6地址FE80:0:0:0:20​A:35FF:FE00:102。服务器在端口7处侦听输入,并简单地回传发送到该端口的任何数据。
这里简单的介绍下DHCP。DHCP(Dynamic Host Configuration Protocol)即动态主机配置协议,通常应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。



图 33.4.2 选择“lwIP Echo Server”模版

5-4 展开lwip_echo_server应用工程目录下的src目录,可以看到很多源文件,如图 33.4.4所示,其中大多是平台相关的文件(platform开头的文件)。下面我们简单的介绍下各文件的作用。
echo.c:Echo服务的的主要实现代码。
i2c_access.c:IIC访问PHY的功能实现,本实验不用。
iic_phyreset.c:IIC复位PHY,本使用不用。
main.c:main函数所在文件。
platform_config.h:平台配置相关文件,主要是宏定义所使用的平台。
我们打开“platform_config.h”文件,内容如下:



图 33.4.3 platform_config.h文件内容

可以看到宏定义了 PLATFORM_ZYNQ,也就是说本实验是与ZYNQ平台相关的。所以本实验需要的是platform_zynq.c文件,而以下的与其它平台相关的platform_mb.c、platform_ppc.c、platform_zynqmp.c、platform.c都无需使用。
platform_config.h是基于硬件设计生成的。
sfp.c和si5324.c分别用于sfp PHY和si5324芯片,用于官方特定的开发板,与我们使用的领航者开发板不相关。



图 33.4.4 src目录

5-5 为了方便分析,我们将src文件夹与本实验不相关的平台文件删除,删除后的src文件夹内容如下图所示:



图 33.4.5 删除不相关文件后的src文件夹内容

5-6 现在我们打开main.c文件,为了方便分析源代码,在main.c文件中将带有下图箭头所指的预编译指令删除。



图 33.4.6 删除不需要的预编译指令

删除不适用的预编译指令后的main.c代码如下:

  • 1 #include <stdio.h>
  • 2 #include "xparameters.h"
  • 3 #include "netif/xadapter.h"
  • 4 #include "platform.h"
  • 5 #include "platform_config.h"
  • 6 #include "xil_printf.h"
  • 7 #include "lwip/tcp.h"
  • 8 #include "xil_cache.h"
  • 9 #if LWIP_IPV6==1
  • 10 #include "lwip/ip.h"
  • 11 #else
  • 12 #if LWIP_DHCP==1
  • 13 #include "lwip/dhcp.h"
  • 14 #endif
  • 15 #endif
  • 16
  • 17 //函数声明
  • 18 void print_app_header();
  • 19 int start_application();
  • 20 int transfer_data();
  • 21 void tcp_fasttmr(void);
  • 22 void tcp_slowtmr(void);
  • 23 void lwip_init();
  • 24
  • 25 #if LWIP_IPV6==0
  • 26 #if LWIP_DHCP==1
  • 27 extern volatile int dhcp_timoutcntr;
  • 28 err_t dhcp_start(struct netif *netif);
  • 29 #endif
  • 30 #endif
  • 31
  • 32 extern volatile int TcpFastTmrFlag;
  • 33 extern volatile int TcpSlowTmrFlag;
  • 34 static struct netif server_netif;
  • 35 struct netif *echo_netif;
  • 36
  • 37 #if LWIP_IPV6==1
  • 38 void print_ip6(char *msg, ip_addr_t *ip)
  • 39 {
  • 40 print(msg);
  • 41 xil_printf(" %x:%x:%x:%x:%x:%x:%x:%x\n\r",
  • 42 IP6_ADDR_BLOCK1(&ip->u_addr.ip6),
  • 43 IP6_ADDR_BLOCK2(&ip->u_addr.ip6),
  • 44 IP6_ADDR_BLOCK3(&ip->u_addr.ip6),
  • 45 IP6_ADDR_BLOCK4(&ip->u_addr.ip6),
  • 46 IP6_ADDR_BLOCK5(&ip->u_addr.ip6),
  • 47 IP6_ADDR_BLOCK6(&ip->u_addr.ip6),
  • 48 IP6_ADDR_BLOCK7(&ip->u_addr.ip6),
  • 49 IP6_ADDR_BLOCK8(&ip->u_addr.ip6));
  • 50 }
  • 51 #else
  • 52 void print_ip(char *msg, ip_addr_t *ip)
  • 53 {
  • 54 print(msg);
  • 55 xil_printf("%d.%d.%d.%d\n\r", ip4_addr1(ip), ip4_addr2(ip),
  • 56 ip4_addr3(ip), ip4_addr4(ip));
  • 57 }
  • 58
  • 59 void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
  • 60 {
  • 61 print_ip("Board IP: ", ip);
  • 62 print_ip("Netmask : ", mask);
  • 63 print_ip("Gateway : ", gw);
  • 64 }
  • 65 #endif
  • 66
  • 67 int main()
  • 68 {
  • 69 #if LWIP_IPV6==0
  • 70 ip_addr_t ipaddr, netmask, gw;
  • 71 #endif
  • 72 //设置领航者开发板的MAC地址
  • 73 unsigned char mac_ethernet_address[] =
  • 74 { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
  • 75
  • 76 echo_netif = &server_netif;
  • 77
  • 78 init_platform();
  • 79
  • 80 #if LWIP_IPV6==0
  • 81 #if LWIP_DHCP==1
  • 82 ipaddr.addr = 0;
  • 83 gw.addr = 0;
  • 84 netmask.addr = 0;
  • 85 #else
  • 86 //设置静态IP地址
  • 87 IP4_ADDR(&ipaddr, 192, 168, 1, 10);
  • 88 IP4_ADDR(&netmask, 255, 255, 255, 0);
  • 89 IP4_ADDR(&gw, 192, 168, 1, 1);
  • 90 #endif
  • 91 #endif
  • 92 print_app_header();
  • 93 lwip_init();
  • 94
  • 95 #if (LWIP_IPV6 == 0)
  • 96 //添加以太网MAC
  • 97 if (!xemac_add(echo_netif, &ipaddr, &netmask,
  • 98 &gw, mac_ethernet_address,
  • 99 PLATFORM_EMAC_BASEADDR)) {
  • 100 xil_printf("Error adding N/W interface\n\r");
  • 101 return -1;
  • 102 }
  • 103 #else
  • 104 if (!xemac_add(echo_netif, NULL, NULL, NULL, mac_ethernet_address,
  • 105 PLATFORM_EMAC_BASEADDR)) {
  • 106 xil_printf("Error adding N/W interface\n\r");
  • 107 return -1;
  • 108 }
  • 109 echo_netif->ip6_autoconfig_enabled = 1;
  • 110 netif_create_ip6_linklocal_address(echo_netif, 1);
  • 111 netif_ip6_addr_set_state(echo_netif, 0, IP6_ADDR_VALID);
  • 112 print_ip6("\n\rBoard IPv6 address ", &echo_netif->ip6_addr[0].u_addr.ip6);
  • 113 #endif
  • 114 netif_set_default(echo_netif);
  • 115
  • 116 //启用中断
  • 117 platform_enable_interrupts();
  • 118
  • 119 //指定网络是否已启动
  • 120 netif_set_up(echo_netif);
  • 121
  • 122 #if (LWIP_IPV6 == 0)
  • 123 #if (LWIP_DHCP==1)
  • 124 //创建新的DHCP客户端。
  • 125 dhcp_start(echo_netif);
  • 126 dhcp_timoutcntr = 24;
  • 127
  • 128 while(((echo_netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
  • 129 xemacif_input(echo_netif);
  • 130
  • 131 if (dhcp_timoutcntr <= 0) {
  • 132 if ((echo_netif->ip_addr.addr) == 0) {
  • 133 xil_printf("DHCP Timeout\r\n");
  • 134 xil_printf("Configuring default IP of 192.168.1.10\r\n");
  • 135 IP4_ADDR(&(echo_netif->ip_addr), 192, 168, 1, 10);
  • 136 IP4_ADDR(&(echo_netif->netmask), 255, 255, 255, 0);
  • 137 IP4_ADDR(&(echo_netif->gw), 192, 168, 1, 1);
  • 138 }
  • 139 }
  • 140
  • 141 ipaddr.addr = echo_netif->ip_addr.addr;
  • 142 gw.addr = echo_netif->gw.addr;
  • 143 netmask.addr = echo_netif->netmask.addr;
  • 144 #endif
  • 145 print_ip_settings(&ipaddr, &netmask, &gw);
  • 146 #endif
  • 147 //启动应用程序
  • 148 start_application();
  • 149
  • 150 //接收和处理数据包
  • 151 while (1) {
  • 152 if (TcpFastTmrFlag) {
  • 153 tcp_fasttmr();
  • 154 TcpFastTmrFlag = 0;
  • 155 }
  • 156 if (TcpSlowTmrFlag) {
  • 157 tcp_slowtmr();
  • 158 TcpSlowTmrFlag = 0;
  • 159 }
  • 160 xemacif_input(echo_netif);
  • 161 transfer_data();
  • 162 }
  • 163 cleanup_platform();
  • 164 return 0;
  • 165 }
复制代码

可以看到代码中有很多的#if LWIP_IPV6==0和#if LWIP_DHCP==1这类预编译指令,这是因为lwip即支持IPv4也支持IPv6,IPv4和DHCP默认支持。如果想重新配置lwip如取消DHCP,可以通过以下方式重配置lwip。
鼠标右键点击“lwip_server_bsp”,在弹出的菜单中选择“Board Support Package Settings”,如下图所示:



图 33.4.7 Board Support Package Settings

在弹出的界面中点击左侧standalone下的lwip202,右侧就是lwip的配置面板。如下图所示,箭头所指的两处分别是配置启用DHCP和使能IPv6,可以看到,dhcp默认为true,ipv6默认为false。



图 33.4.8 lwip的配置面板

main函数可以说是使用lwip的一个标准函数,可以在不修改main函数的情况下就可实现其它的应用功能。main函数主要完成以下功能:
1)在代码的73行设置领航者开发板的MAC地址为00:0a:35:00:01:02。
2)通过调用init_platform函数配置定时器和建立中断以初始化平台,定时器产生周期性中断,周期为250ms。
3)调用lwip_init函数完成对lwip协议栈的初始化,代码第93行。
4)初始化lwIP后,使用xemac_add函数添加以太网MAC到协议栈中。
5)使用platform_enable_interrupts函数使能中断和启动定时器。
6)从代码第125~139行,启动DHCP服务获取动态IP地址,如果超时未获取到动态IP地址,则使用默认的静态IP设置:
IP Address: 192.168.1.10
Netmask : 255.255.255.0
Gateway : 192.168.1.1
我们也可以根据需要修改代码第135~137行的值,从而使用不同的静态IP地址。
7)start_application函数是用户应用函数,当我们使用lwip实现不同的应用功能时,可以在保持main函数不变的情况下,修改start_application函数的实现即可。本实验的start_application函数在echo.c文件中定义,该函数创建了一个TCP服务并设定了对应该服务的回调函数。当一个TCP连接请求被接收时,回调函数对客户端发送来的数据原封不动的发送回去,从而实现echo服务器的功能。由于本实验的目的在于初步了解lwip的使用,对于涉及到的TCP协议的使用,我们将在下一章讲解,本实验我们不多做介绍。
8)程序进入while(1)循环执行数据包接收操作,以及它需要执行的任何其他特定于应用程序的操作。TcpFastTmrFlag和TcpSlowTmrFlag是TCP TX处理所必需的,定时器中断分别以250ms和500ms的周期来改变这两个标志位。数据包接收函数xemacif_input处理由中断处理程序接收的数据包,并将它们传递给lwIP,然后lwIP为每个接收到的数据包调用适当的回调处理程序。transfer_data函数无实际意义,可以删除。
5-7 程序修改完成后,按快捷键Ctrl+S保存main.c文件,工具会自动进行编译。编译完成后控制台(Console)中会出现提示信息“Build Finished”,同时在应用工程的Binaries目录下可以看到生成的elf文件。
33.5下载验证
首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将USB UART接口与电脑连接,用于串口通信。使用网线一端连接领航者开发板的以太网接口,另一端与电脑或路由器连接。最后连接开发板的电源,并打开电源开关。如下图所示:



图 33.5.1领航者ZYNQ开发板实物图

现在进入最后一步。
step6:板级验证
6-1 在SDK软件的下方的SDK Terminal窗口中点击右上角的加号连接串口。
6-2 下载程序。
6-3 可以看到串口打印的结果如下:



图 33.5.2 显示打印结果

在打印出“link speed for phy address 1: 1000”后要等一段时间进行DHCP服务。因为我们将领航者开发板的以太网接口与电脑进行连接,所以出现了DHCP Timeout,开发板的IP地址为默认设置的静态IP地址192.168.1.10。如果和路由器进行连接,开发板的IP则是由DHCP获取的动态IP设置。TCP应答服务的端口号为7。另外需要说明的是串口打印的“TCP packets sent to port 6001 will be echoed back”可能是该模板最初版本使用的是6001端口,后面更新的时候使用了端口7,而该语句没有修改或删除,所以这是无意义的语句,可以找到print_app_header函数从而删除该语句。
在使用静态IP地址时,需要确保同网段内没有主机使用192.168.1.10 的IP地址,否则会造成IP冲突。可以在开发板未上电前或未下载程序前在CMD里输入“ping 192.168.1.10”命令查看是否能ping通,如果能ping通,说明网络中有此IP地址,此时需要更改静态IP地址为其他值,如192.168.1.123等。
6-4 我们在电脑端打开网络调试助手,设置协议类型为:TCP Client,服务器IP地址为串口打印的地址,此处为:192.168.1.10,服务器端口号为:7,然后点击连接,即可连上开发板的 TCP Sever,如下图所示:



图 33.5.3 电脑端网络调试助手TCP Client测试界面

6-5 本实验除了可以使用网络调试助手软件外,还可以使用telnet。
我们打开电脑的CMD(按win+r键后输入cmd),输入“telnet 192.168.1.10 7”,如下图所示:



图 33.5.4 进行telnet连接

回车后,进入下图所示界面:



图 33.5.5 连接成功后的界面

如果回车后出现像下图所示界面所示“telnet不是内部或外部命令,也不是可运行的程序或批处理文件”,则表明未开启Windows的telnet客户端功能,开启方式见6-5。



图 33.5.6 未启用telnet客户端时的界面

此时我们按键盘上的字母和数字键,如123abc,控制台显示如下:



图 33.5.7 控制台显示

可以看到除了1只有一个外,其它字符都显示两个,一个是我们按下的,另一个是开发板的lwip echo server应答的。可见功能基本正确,不过从使用上看还是有问题的,一是第一次按下的字符没有回显;二是不能输入字符串,这些问题主要是windows自带的telnet的问题。如果使用第三方提供的telnet工具,例如使用Win10系统的读者可以开启WSL,从而使用linux系统提供的telnet功能进行连接,如下图(通过WSL使用ubuntu系统):



图 33.5.8 功能完全正常

可以看到一点问题也没有。按“Ctrl+]”可以退出输入界面,然后输入“quit”即可退出telnet连接。
注:Telnet 协议是TCP/IP 协议族中的一员,是 Internet 远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet 程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。
6-6 下面我们介绍一下如何开启Windows的telnet客户端功能。在Win10或Win7系统中,按“Win+r”快捷键后,在下图所示界面中输入“control”。



图 33.5.9 打开控制面板界面

进入下图所示控制面板界面,将查看方式设置为“类别”,单击“程序”下的“卸载程序”,如下图所示:



图 33.5.10 点击进入“程序和功能”界面

在弹出的界面中,单击“启用或关闭Windows功能”,如下图所示:



图 33.5.11 点击“启用或关闭Windows功能”

在弹出的“Windows功能”界面中,找到“Telnet Client”,并勾选,如下图所示:



图 33.5.12 勾选telnet client

单击确定后,如果出现“Windows需要重启电脑才能完成安装所请求的更改”字样,重新启动电脑即可,至此,Windows的telnet客户端服务已启用。
此时我们进行telnet连接会连接成功,但也有部分电脑会出现下图所示现象:



图 33.5.13 无法连接

出现这种情况是因为本地连接(Win10为以太网)设置有问题,需要重新设置。在控制面板界面,单击“网络和Internet”下的“查看网络状态和任务”,如下图所示:



图 33.5.14 打开“查看网络和状态”

进入下图所示界面:



图 33.5.15 更改适配器设置

点击箭头所指的“更改适配器设置”,进入下图所示界面:



图 33.5.16 打开属性界面

点击“以太网”(或者本地连接,如果有)后出现“更改此连接的设置”,点击“更改此连接的设置”,进入“属性”界面,点击“Internet协议版本4(TCP/IPv4)”,如下图所示:



图 33.5.17 进入IPv4设置

进入下图所示界面后,按下图的设置进行修改。



图 33.5.18 设置IPv4

经过这些设置后,基本上就可以使用telnet了。
至此,本实验完成。


0
分享淘帖 显示全部楼层

评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发资料
关闭

站长推荐 上一条 /8 下一条

快速回复 返回顶部 返回列表