35. ETHERC——以太网通信

35.1. 互联网模型

互联网技术对人类社会的影响不言而喻。当今大部分电子设备都能以不同的方式接入互联网(Internet), 在家庭中PC常见的互联网接入方式是使用路由器(Router)组建小型局域网(LAN), 利用互联网专线或者调制调解器(modem)经过电话线网络,连接到互联网服务提供商(ISP), 由互联网服务提供商把用户的局域网接入互联网。而企业或学校的局域网规模较大,常使用交换机组成局域网, 经过路由以不同的方式接入到互联网中。

通信至少是两个设备的事,需要相互兼容的硬件和软件支持,我们称之为通信协议。 以太网通信在结构比较复杂,国际标准组织将整个以太网通信结构制定了OSI模型, 总共分层七个层,分别为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层, 每个层功能不同,通信中各司其职,整个模型包括硬件和软件定义。 OSI模型是理想分层,一般的网络系统只是涉及其中几层。

TCP/IP 是互联网最基本的协议,是互联网通信使用的网络协议,由网络层的 IP 协议和传输层的 TCP 协议组成。 TCP/IP 只有四个分层,分别为应用层、传输层、网络层以及网络访问层。 虽然 TCP/IP 分层少了,但与 OSI 模型是不冲突的,它把 OSI 模型一些层次整合一起的,本质上可以实现相同功能。

实际上,还有一个 TCP/IP 混合模型,分为五个层,参考 图34_1, 它实际与TCP/IP四层模型是相通的,只是把网络访问层拆成数据链路层和物理层。这种分层方法对我们学习理解更容易。

图 34-1 TCP/IP混合参考模型

图 34_1 TCP/IP混合参考模型

设计网络时,为了降低网络设计的复杂性,对组成网络的硬件、软件进行封装、分层,这些分层即构成了网络体系模型。 在两个设备相同层之间的对话、通信约定,构成了层级协议。设备中使用的所有协议加起来统称协议栈。 在这个网络模型中,每一层完成不同的任务,都提供接口供上一层访问。 而在每层的内部,可以使用不同的方式来实现接口,因而内部的改变不会影响其它层。

在 TCP/IP 混合参考模型中,数据链路层又被分为 LLC 层(逻辑链路层)和 MAC 层(媒体介质访问层)。 目前,对于普通的接入网络终端的设备,LLC 层和 MAC 层是软、硬件的分界线。 如 PC 的网卡主要负责实现参考模型中的 MAC 子层和物理层, 在 PC 的软件系统中则有一套庞大程序实现了 LLC 层及以上的所有网络层次的协议。

由硬件实现的物理层和 MAC 子层在不同的网络形式有很大的区别,如以太网和 WiFi,这是由物理传输方式决定的。 但由软件实现的其它网络层次通常不会有太大区别,在PC上也许能实现完整的功能,一般支持所有协议, 而在嵌入式领域则按需要进行裁剪。

35.2. 以太网

以太网(Ethernet)是互联网技术的一种,由于它是在组网技术中占的比例最高,很多人直接把以太网理解为互联网。

以太网是指遵守 IEEE 802.3 标准组成的局域网, 由 IEEE 802.3 标准规定的主要是位于参考模型的物理层(PHY)和数据链路层中的介质访问控制子层(MAC)。 在家庭、企业和学校所组建的 PC 局域网形式一般也是以太网,其标志是使用水晶头网线来连接(当然还有其它形式)。 IEEE 还有其它局域网标准,如 IEEE 802.11 是无线局域网,俗称 WiFi。 IEEE 802.15 是个人域网,即蓝牙技术,其中的 IEEE 802.15.4 标准则是 ZigBee 技术。

现阶段,工业控制、环境监测、智能家居的嵌入式设备产生了接入互联网的需求, 利用以太网技术,嵌入式设备可以非常容易地接入到现有的计算机网络中。

35.2.1. PHY层

在物理层,由IEEE 802.3 标准规定了以太网使用的传输介质、传输速度、数据编码方式和冲突检测机制, 物理层一般是通过一个 PHY 芯片实现其功能的。

35.2.1.1. 传输介质

传输介质包括同轴电缆、双绞线(水晶头网线是一种双绞线)、光纤。 根据不同的传输速度和距离要求,基于这三类介质的信号线又衍生出很多不同的种类。 最常用的是“五类线”适用于 100BASE-T 和 10BASE-T 的网络,它们的网络速率分别为 100Mbps 和 10Mbps。

35.2.1.2. 编码

为了让接收方在没有外部时钟参考的情况也能确定每一位的起始、结束和中间位置,在传输信号时不直接采用二进制编码。 在 10BASE-T 的传输方式中采用曼彻斯特编码,在 100BASE-T 中则采用 4B/5B 编码。

曼彻斯特编码把每一个二进制位的周期分为两个间隔,在表示“1”时,以前半个周期为高电平,后半个周期为低电平。 表示“0”时则相反,见 图34_2

图 34-2 曼彻斯特编码

图 34_2 曼彻斯特编码

采用曼彻斯特码在每个位周期都有电压变化,便于同步。但这样的编码方式效率太低,只有50%。

在 100BASE-T 采用的 4B/5B 编码是把待发送数据位流的每4位分为一组,以特定的5位编码来表示, 这些特定的5位编码能使数据流有足够多的跳变,达到同步的目的,而且效率也从曼彻斯特编码的50%提高到了80%。

35.2.1.3. CSMA/CD冲突检测

早期的以太网大多是多个节点连接到同一条网络总线上(总线型网络), 存在信道竞争问题,因而每个连接到以太网上的节点都必须具备冲突检测功能。 以太网具备 CSMA/CD 冲突检测机制,如果多个节点同时利用同一条总线发送数据,则会产生冲突, 总线上的节点可通过接收到的信号与原始发送的信号的比较检测是否存在冲突,若存在冲突则停止发送数据,随机等待一段时间再重传。

现在大多数局域网组建的时候很少采用总线型网络,大多是一个设备接入到一个独立的路由或交换机接口,组成星型网络,不会产生冲突。 但为了兼容,新出的产品还是带有冲突检测机制。

35.2.2. MAC子层

35.2.2.1. MAC的功能

MAC 子层是属于数据链路层的下半部分,它主要负责与物理层进行数据交接, 如是否可以发送数据,发送的数据是否正确,对数据流进行控制等。 它自动对来自上层的数据包加上一些控制信号,交给物理层。 接收方得到正常数据时,自动去除 MAC 控制信号,把该数据包交给上层。

35.2.2.2. MAC数据包

IEEE 对以太网上传输的数据包格式也进行了统一规定,见 图34_3。 该数据包被称为 MAC 数据包。

图 34-3 MAC 数据包格式

图 34_3 MAC数据包格式

MAC 数据包由前导字段、帧起始定界符、目标地址、源地址、数据包类型、数据域、填充域、校验和域组成。

  • 前导字段,也称报头,这是一段方波,用于使收发节点的时钟同步。 内容为连续7个字节的 0x55。字段和帧起始定界符在 MAC 收到数据包后会自动过滤掉。

  • 帧起始定界符(SFD):用于区分前导段与数据段的,内容为 0xD5。

  • MAC 地址:MAC 地址由48位数字组成,它是网卡的物理地址,在以太网传输的最底层,就是根据 MAC 地址来收发数据的。 部分 MAC 地址用于广播和多播,在同一个网络里不能有两个相同的 MAC 地址。 PC 的网卡在出厂时已经设置好了 MAC 地址,但也可以通过一些软件来进行修改, 在嵌入式的以太网控制器中可由程序进行配置。数据包中的 DA 是目标地址,SA 是源地址。

  • 数据包类型:本区域可以用来描述本 MAC 数据包是属于 TCP/IP 协议层的 IP 包、 ARP 包还是 SNMP 包,也可以用来描述本 MAC 数据包数据段的长度。 如果该值被设置大于 0x0600,不用于长度描述,而是用于类型描述功能,表示与以太网帧相关的 MAC 客户端协议的种类。

  • 数据段:数据段是 MAC 包的核心内容,它包含的数据来自 MAC 的上层。其长度可以从 0~1500 字节间变化。

  • 填充域:由于协议要求整个 MAC 数据包的长度至少为 64 字节 (接收到的数据包如果少于64字节会被认为发生冲突,数据包被自动丢弃), 当数据段的字节少于 64 字节时,在填充域会自动填上无效数据,以使数据包符合长度要求。

  • 校验和域:MAC数据包的尾部是校验和域,它保存了CRC校验序列,用于检错。

以上是标准的 MAC 数据包,IEEE 802.3 同时还规定了扩展的 MAC 数据包, 它是在标准的 MAC 数据包的 SA 和数据包类型之间添加4个字节的 QTag 前缀字段,用于获取标志的 MAC 帧。 前2个字节固定为 0x8100,用于识别 QTag 前缀的存在; 后两个字节内容分别为3个位的用户优先级、1个位的标准格式指示符(CFI)和一个12位的 VLAN 标识符。

35.3. TCP/IP协议栈

标准 TCP/IP 协议是用于计算机通信的一组协议,通常称为 TCP/IP 协议栈, 通俗讲就是符合以太网通信要求的代码集合,一般要求它可以实现互联网模型中每个层对应的协议, 比如应用层的 HTTP、FTP、DNS、SMTP 协议,传输层的 TCP、UDP 协议、网络层的 IP、ICMP 协议等等。 关于 TCP/IP 协议详细内容推荐阅读《TCP-IP详解》和《用TCP/IP进行网际互连》理解。

Windows 操作系统、UNIX 类操作系统都有自己的一套方法来实现 TCP/IP 通信协议,它们都提供非常完整的 TCP/IP 协议。 对于一般的嵌入式设备,受制于硬件条件没办法支持使用在 Window 或 UNIX 类操作系统的运行的 TCP/IP 协议栈, 一般只能使用简化版本的 TCP/IP 协议栈,目前开源的适合嵌入式的有 LwIP、FreeRTOS-Plus-TCP、uC/TCP-IP、uIP、TinyTCP 等等, 其中 LwIP 是目前在嵌入式网络领域被讨论和使用广泛的协议栈。

35.3.1. 为什么需要协议栈

物理层主要定义物理介质性质,MAC 子层负责与物理层进行数据交接,这两部分是与硬件紧密联系的, 就嵌入式控制芯片来说,很多都内部集成了 MAC 控制器,完成 MAC 子层功能, 所以依靠这部分功能是可以实现两个设备数据交换,而时间传输的数据就是 MAC 数据包, 发送端封装好数据包,接收端则解封数据包得到可用数据,这样的一个模型与使用 USART 控制器实现数据传输是非常类似的。 但如果将以太网运用在如此基础的功能上,完全是大材小用, 因为以太网具有传输速度快、可传输距离远、支持星型拓扑设备连接等等强大功能。 功能强大的东西一般都会用高级的应用,这也是设计者的初衷。

使用以太网接口的目的就是为了方便与其它设备互联,如果所有设备都约定使用一种互联方式, 在软件上加一些层次来封装,这样不同系统、不同的设备通讯就变得相对容易了。 而且只要新加入的设备也使用同一种方式,就可以直接与之前存在于网络上的其它设备通讯。 这就是为什么产生了在 MAC 之上的其它层次的网络协议及为什么要使用协议栈的原因。 又由于在各种协议栈中 TCP/IP 协议栈得到了最广泛使用,所有接入互联网的设备都遵守 TCP/IP 协议。 所以,想方便地与其它设备互联通信,需要提供对 TCP/IP 协议的支持。

35.3.2. 各网络层的功能

用以太网和 WiFi 作例子,它们的 MAC 子层和物理层有较大的区别, 但在MAC之上的LLC层、网络层、传输层和应用层的协议,是基本相同的, 这几层协议由软件实现,并对各层进行封装。根据TCP/IP协议,各层的要实现的功能如下:

  • LLC 层:处理传输错误;调节数据流,协调收发数据双方速度, 防止发送方发送得太快而接收方丢失数据。主要使用数据链路协议。

  • 网络层:本层也被称为 IP 层。LLC 层负责把数据从线的一端传输到另一端, 但很多时候不同的设备位于不同的网络中(并不是简单的网线的两头)。 此时就需要网络层来解决子网路由拓扑问题、路径选择问题。在这一层主要有IP协议、ICMP协议。

  • 传输层:由网络层处理好了网络传输的路径问题后,端到端的路径就建立起来了。 传输层就负责处理端到端的通讯。在这一层中主要有 TCP、UDP 协议

  • 应用层:经过前面三层的处理,通讯完全建立。应用层可以通过调用传输层的接口来编写特定的应用程序。 而 TCP/IP 协议一般也会包含一些简单的应用程序如 Telnet 远程登录、FTP 文件传输、SMTP 邮件传输协议。

实际上,在发送数据时,经过网络协议栈的每一层,都会给来自上层的数据添加上一个数据包的头,再传递给下一层。 在接收方收到数据时,一层层地把所在层的数据包的头去掉,向上层递交数据,如图所示。

图 数据经过每一层的封装和还原

35.4. ETHERC简介

瑞萨 RA6M5 提供一个单通道以太网控制器(ETHERC),符合以太网或 IEEE802.3 媒体访问控制(MAC)层协议。 每个 ETHERC 通道有一个 MAC 层接口通道,将 MCU 连接到物理层 LSI (PHY-LSI), 可以传输和接收符合以太网/IEEE802.3 标准的帧。 ETHERC 连接到以太网专用 DMA 控制器(EDMAC),因此可以在不使用 CPU 的情况下传输数据。

ETHERC 特性

  • 兼容 Ethernet/IEEE802.3 标准

  • 比特率:支持 10 Mbps 和 100 Mbps

  • 操作模式:支持全双工和半双工模式

  • 接口:MII 和 RMII

  • 功能:

    • 魔术包(Magic Packet)检测

    • Wake-on-LAN (WOL) 信号输出

35.5. ETHERC框图分析

RA6M5 的 ETHERC 外设模块框图如下图所示。

图

35.5.1. 以太网总线

见图中①处。

以太网总线(ETHER bus)向上连接到外部总线控制器和 SRAM, 向下连接到 EDMAC 仲裁器。

35.5.2. EDMAC仲裁器和通道

见图中②处。

EDMAC 仲裁器用于在多个 EDMAC 通道之间进行仲裁,以确认要访问的 EDMAC 通道。 而 RA6M5 只有一个 ETHERC 通道,因此只能访问 ETHERC 通道 0(ETHERC0)。

35.5.3. ETHERC0及其MII/RMII接口

见图中③处。

ETHERC0 当中包含 MDIO、接收电路(Receive circuit)和发送电路(Transmit circuit), 它们都连接到了 MII/RMII 接口(MII interface)。

MII(Media Independent Interface)为介质独立接口。 在 IEEE802.3 中规定的 MII 接口是一种用于将不同类型的 PHY 与相同 MAC 控制器相连接的通用总线。 MAC 控制器可以用同样的硬件接口与任何 PHY 进行连接。 RMII(Reduced Media Independent Interface)为简化介质独立接口,也是标准的以太网接口之一。 在数据的收发上 RMII 比 MII 接口少了一倍的信号线,所以 RMII 一般要求是 50MHz 的时钟。

MDIO(Management Data Input/Output)接口,即管理数据输入输出接口, 也叫 SMI(Serial Management Interface)接口,即串行管理接口。 MDIO 或者 SMI 接口,是一个管理 PHY 的接口,用来读/写 PHY 的寄存器, 以控制 PHY 的行为或获取 PHY 的状态。 该接口包含 MDC 和 MDIO 两条信号线,MDIO 属于双向数据线,而 MDC 是时钟线,为 MDIO 提供时钟。

MII 接口和相关引脚

引脚

方向

说明

ET0_TX_CLK

Input

发送时钟

作为 ET0_TX_EN, ET0_ETXD[3:0], ET0_TX_ER 的时序参考信号

标称速率为10Mbit/s时为2.5MHz;速率为100Mbit/s时为25MHz

ET0_RX_CLK

Input

接收时钟

作为 ET0_RX_EN, ET0_ERXD[3:0], ET0_RX_ER 的时序参考信号

标称速率为10Mbit/s时为2.5MHz;速率为100Mbit/s时为25MHz

ET0_TX_EN

Output

发送数据有效

该信号指示 ET0_ETXD[3:0] 引脚上发送的数据有效

ET0_ETXD[3:0]

Output

4 位发送数据

ET0_TX_ER

Output

发送错误

ET0_RX_DV

Input

接收数据有效

该信号指示 ET0_ERXD[3:0] 引脚上接收的数据有效

ET0_ERXD[3:0]

Input

4 位接收数据

ET0_RX_ER

Input

接收错误

由PHY驱动,向MAC控制器报告在帧某处检测到错误。

ET0_CRS

Input

载波侦听信号

由PHY芯片负责驱动,当发送或接收介质处于非空闲状态时使能该信号

在全双工模式该信号线无效

ET0_COL

Input

冲突检测信号

由PHY芯片负责驱动,检测到介质上存在冲突后该线被使能,

并且保持至冲突解除。在全双工模式该信号线无效

ET0_MDC

Output

管理数据时钟(ET0_MDIO 的参考时钟信号)

ET0_MDIO

I/O

管理数据输入输出(双向数据信号)

ET0_LINKSTA

Input

PHY-LSI 的连接状态

ET0_EXOUT

Output

通用输出引脚

ET0_WOL

Output

Wake-on-LAN 信号(指示接收到一个魔术包)

RMII 接口和相关引脚

引脚

方向

说明

REF50CK0

Input

RMII0 接口的参考时钟信号

RMII0_TXD_EN

Output

发送数据有效

该信号指示 RMII0_TXD1 和 RMII0_TXD0 引脚上发送的数据有效

RMII0_TXD1, RMII0_TXD0

Output

2 位发送数据

RMII0_CRS_DV

Input

载波侦听信号 / 接收数据有效

该信号指示 RMII0_RXD1 和 RMII0_RXD0 引脚上接收的数据有效

在 RMII 接口中,CRS 和 RX_DV 整合成了 CRS_DV 信号引脚

RMII0_RXD1, RMII0_RXD0

Input

2 位接收数据

RMII0_RX_ER

Input

接收错误

由PHY驱动,向MAC控制器报告在帧某处检测到错误。

ET0_MDC

Output

管理数据时钟(ET0_MDIO 的参考时钟信号)

ET0_MDIO

I/O

管理数据输入输出(双向数据信号)

ET0_LINKSTA

Input

PHY-LSI 的连接状态

ET0_EXOUT

Output

通用输出引脚

ET0_WOL

Output

Wake-on-LAN 信号(指示接收到一个魔术包)

对比上面两张表格,可以发现当我们使用 RMII 接口时,会比使用 MII 接口时少了一些引脚。 具体如下:

  • MII 的 ET0_TX_CLK 和 ET0_RX_CLK 在 RMII 中用同一个参考时钟引脚 REF50CK0 替换了。

  • MII 的 4 位发送和接收数据引脚在 RMII 中变为了 2 位的,这会减小数据传输带宽。

  • RMII 少了和 MII 中的 ET0_TX_ER 相对应的引脚。

  • RMII 还少了 ET0_CRS 和 ET0_COL 引脚。这两个引脚原本用于载波检测和冲突检测, RMII 接口是把 CRS 和 RX_DV 整合成 CRS_DV 信号线,当介质处于不同状态时会自切换该信号状态。

注解

在本章后面介绍的 PHY 芯片 LAN8720A ,它使用 RMII 接口连接,但是不需要使用到 ET0_LINKSTA, ET0_EXOUT, ET0_WOL 这三个引脚。

35.5.4. ETHERC0中断信号

见图中④处。

EDMAC 是以太网专用 DMA 控制器, 就如 ETHERC0 表示的是 ETHERC 通道 0 一样,EDMAC0 表示的是 EDMAC 通道 0。 如果在 ETHERC0 和 EDMAC0 中都使能了相应的中断,当 ETHERC0 触发该中断时,会先通知到 EDMAC0, 然后再通过 EDMAC0 发送一个 ETHER_EINT0 中断请求信号到 CPU 进行进一步的处理。

35.6. PHY:LAN8720A介绍

LAN8720A 是 SMSC 公司(已被 Microchip 公司收购)设计的一个体积小、功耗低、全能型 10/100Mbps 的以太网物理层收发器。 它是针对消费类电子和企业应用而设计的。LAN8720A 总共只有24Pin,仅支持 RMII 接口。 由 LAN8720A 组成的网络系统结构如图所示。

图

在上图中:

  • LAN8720A 通过 RMII 与 MAC 连接。

  • 一般来说,必须为使用 RMII 接口的 PHY 提供 50MHz 的时钟源输入到 REF50CK0 引脚, 不过 LAN8720A 内部集成 PLL,可以将 25MHz 的时钟源倍频到 50MHz 并在指定引脚输出该时钟, 所以我们可以直接使其与 REF50CK0 连接达到提供 50MHz 时钟的效果。

  • RJ45 是网络插座,在与 LAN8720A 连接之间还需要一个变压器, 所以一般使用带电压转换和LED指示灯的 HY911105A 型号的插座。

LAN8720A 内部系统结构如图所示。

图

LAN8720A 由各个不同功能模块组成,最重要的要数接收控制器和发送控制器,其它的基本上都是与外部引脚挂钩,实现信号传输。 部分引脚是具有双重功能的,比如 PHYAD0 与 RXER 引脚是共用的,在系统上电后 LAN8720A 会马上读取这部分共用引脚的电平, 以确定系统的状态并保存在相关寄存器内,之后则自动转入作为另一功能引脚。

PHYAD0

PHYAD0 引脚用于配置 SMI 通信的 LAN8720A 地址, 在芯片内部该引脚已经自带下拉电阻,默认认为0(即使外部悬空不接), 在系统上电时会检测该引脚获取得到 LAN8720A 的地址为0或者1, 并保存在特殊模式寄存器(R18)的 PHYAD 位中,该寄存器的 PHYAD 字段有5个位, 在需要超过2个 LAN8720A 时可以通过软件设置不同 SMI 通信地址。PHYAD0 是与 RXER 引脚共用。

MODE[2:0]

MODE[2:0] 引脚用于选择 LAN8720A 网络通信速率和工作模式, 可选 10Mbps 或 100Mbps 通信速度,半双工或全双工工作模式, 另外 LAN8720A 支持 HP Auto-MDIX 自动翻转功能,即可自动识别直连或交叉网线并自适应。 一般将 MODE 引脚都设置为1,可以让 LAN8720A 启动自适应功能,它会自动寻找最优工作方式。 MODE[0] 与 RXD0 引脚共用、 MODE[1] 与 RXD1 引脚共用、MODE[2] 与 CRS_DV 引脚共用。

nINT/REFCLKO

nINT/REFCLKO 引脚用于 MCU RMII 接口中的 REF50CK0 信号线。

  • 当 nINTSEL 引脚为低电平时,它可以被设置成 50MHz 时钟输出, 这样可以直接与 MCU RMII 接口的 REF50CK0 引脚连接为其提供 50MHz 时钟源, 这种模式要求为 XTAL1 与 XTAL2 之间或为 XTAL1/CLKIN 提供 25MHz 时钟, 然后由 LAN8720A 内部 PLL 电路陪频得到 50MHz 时钟, 此时 nIN/REFCLKO 引脚用于 50MHz 时钟输出,它的中断功能不可用。

  • 当 nINTSEL 引脚为高电平时,LAN8720A 被设置为时钟输入, 即外部时钟源直接提供 50MHz 时钟接入 MCU RMII 接口的 REF_CLK 引脚和 LAN8720A 的 XTAL1/CLKIN 引脚, 此时 nINT/REFCLKO 可用于中断功能。nINTSEL 与 LED2 引脚共用,一般使用下拉。

REGOFF

REGOFF 引脚用于配置内部 +1.2V 电压源。 LAN8720A 内部需要+1.2V电压,可以通过 VDDCR 引脚输入+1.2V电压提供, 也可以直接利用 LAN8720A 内部 +1.2V 稳压器提供。当 REGOFF 引脚为低电平时选择内部 +1.2V 稳压器。 REGOFF 与 LED1 引脚共用。

SMI 支持寻址32个寄存器,LAN8720A 只用到其中14个,参考下表。

表 LAN8720A寄存器列表

序号

寄存器名称

分组

0

Basic Control Register

Basic

1

Basic Status Register

Basic

2

PHY Identifier 1

Extended

3

PHY Identifier 2

Extended

4

Auto-Negotiation Advertisement Register

Extended

5

Auto-Negotiation Link Partner Ability Register

Extended

6

Auto-Negotiation Expansion Register

Extended

17

Mode Control/Status Register

Vendor-specific

18

Special Modes

Vendor-specific

26

Symbol Error Counter Register

Vendor-specific

27

Control / Status Indication Register

Vendor-specific

29

Interrupt Source Register

Vendor-specific

30

Interrupt Mask Register

Vendor-specific

31

PHY Special Control/Status Register

Vendor-specific

序号与 SMI 数据帧中的 RADDR 是对应的,这在编写驱动时非常重要,本文将它们标记为R0~R31。 寄存器可规划为三个组:Basic、Extended 和 Vendor-specific。

  • Basic 是 IEEE 802.3 要求的,R0是基本控制寄存器,其位15为 Soft Reset 位,向该位写1启动 LAN8720A 软件复位, 还包括速度、自适应、低功耗等等功能设置。R1是基本状态寄存器。

  • Extended 是扩展寄存器,包括 LAN8720A 的ID号、制造商、版本号等等信息。

  • Vendor-specific 是供应商自定义寄存器,R31是特殊控制/状态寄存器,指示速度类型和自适应功能。

35.7. FreeRTOS+TCP移植实验

注:本实验需要读者有一定的 FreeRTOS 基础知识, 可以到 FreeRTOS 官网阅读 FreeRTOS 内核和 FreeRTOS-Plus 库的中文版入门文档。

35.7.1. 硬件设计

野火启明6M5开发板的以太网相关电路如图所示。

图

35.7.2. 软件设计

本次实验需要用到 FreeRTOS 及其自带的 TCP/IP 网络协议栈:FreeRTOS-Plus-TCP, 而前面所有章节的例程都是没有使用 FreeRTOS 的,因此不能直接拷贝以前的例程, 需要重新新建一个带有 FreeRTOS 的工程。

35.7.2.1. 新建工程

参照本教程第5章和第6章的步骤,区别是在“RTOS Selection”下拉列表里选择RTOS时选择 FreeRTOS 即可。

对于 e2 studio 开发环境:

在 e2 studio 工作空间中新建工程,工程名为 “34_Ethernet_FreeRTOS”。新建工程时要注意选择 FreeRTOS。

对于 Keil 开发环境:

首先在指定的路径新建文件夹: “34_Ethernet_FreeRTOS”,用于存放我们即将新建的 Keil 工程。 打开 RASC 软件来新建工程,工程路径选到“34_Ethernet_FreeRTOS”文件夹下面, 工程名为 “EBF_RA6M5” 。新建工程时要注意选择 FreeRTOS。

工程新建好之后,在工程根目录的 “src” 文件夹下面新建源文件 “ether_phy_target_lan8720.c”, 该文件是 LAN8720 的底层驱动文件。再新建源文件和头文件:“net_user_app.c” 和 “net_user_app.h”。

由于调试需要,可将LED和串口的驱动文件拷贝过来: 直接复制前面例程里面的“led”和“debug_uart”文件夹并粘贴到工程根目录的 “src” 文件夹下面。

工程文件结构如下。

文件结构
34_Ethernet_FreeRTOS
├─ ......
└─ src
   ├─ led
   │  ├─ bsp_led.c
   │  └─ bsp_led.h
   ├─ debug_uart
   │  ├─ bsp_debug_uart.c
   │  └─ bsp_debug_uart.h
   ├─ ether_phy_target_lan8720.c
   ├─ net_user_app.c
   ├─ net_user_app.h
   ├─ net_thread_entry.c
   └─ hal_entry.c

注:其中 net_thread_entry.c 该源文件若是不存在则会由软件自动生成, 若存在,软件生成代码时该文件不会被覆盖。

35.7.2.2. FSP配置

按照前面的章节来配置LED的GPIO引脚和调试串口,此处不再赘述。

使用 e2 studio 环境的用户使用 printf 注意需要对工程做如图所示的设置:

图

在FSP配置界面的BSP页面,分配主栈大小为 0x1000、堆大小为 0x2000,如下图所示:

图
35.7.2.2.1. 配置 RMII 引脚和 LAN8720 复位引脚

根据硬件原理图,我们需要配置连接 PHY LAN8720 的 RMII 引脚,以及 LAN8720 复位引脚。 LAN8720 的复位引脚为 P802,由于复位引脚是低电平有效,可直接配置为输出高电平模式即可,如下图所示。

图

RMII 引脚配置如下图所示。

图
35.7.2.2.2. 配置 FreeRTOS 和线程

首先新建一个线程:Net Thread(网络线程),该线程用于运行网络协议栈, 然后向其中添加:FreeRTOS Heap 4 和 FreeRTOS+TCP。步骤如下。

在 Threads 区域点击“New Thread”按钮,新建得到一个默认名为“New Thread”线程。

图

线程名“New Thread”会在后面对线程进行配置时更改为“Net Thread”。 现在让我们先在这个线程下面添加:FreeRTOS Heap 4 和 FreeRTOS+TCP。

添加 FreeRTOS Heap 4 步骤:“New Stack”→“RTOS”→“FreeRTOS Heap 4”。

图

添加 FreeRTOS+TCP 步骤:“New Stack”→“Networking”→“FreeRTOS+TCP”。

图

添加完成后的结果如下图所示。

图

接下来继续设置该线程的参数。 点击“New Thread”线程,如下图所示。

图

上图中出现两个区域的配置属性, 其中①是 FreeRTOS 全局的配置属性,②是“New Thread”这个线程的配置属性。

首先,按照下表的描述来配置“New Thread”线程。

FreeRTOS 配置属性:“Thread”部分

属性

描述

Symbol

net_thread

Symbol 是指C语言符号,此处设置为 net_thread,

生成代码时会自动生成一个源文件 net_thread_entry.c,

其中包含了名为 net_thread_entry 的线程入口函数。

Name

Net Thread

线程名。由于该线程运行网络协议栈,因此线程名设置为 Net Thread。

Stack size (bytes)

1024

该线程栈大小设置为 1024。

Priority

1

该线程的运行优先级设置为 1。

Thread Context

NULL

线程上下文参数指针设置为 NULL。

Memory Allocation

Static

线程的内存分配方式设置为 Static。

Allocate Secure Context

Enable

分配安全上下文。

FreeRTOS 全局的配置如下:

FreeRTOS 配置属性:“Common”部分

属性

描述

General > Custom FreeRTOSConfig.h

为自定义 FreeRTOSConfig.h 文件添加路径。

它可用于覆盖此处定义的部分或全部配置,并定义其他配置。

没有自定义文件 FreeRTOSConfig.h 的话留空即可。

General > Use Preemption

Enabled

  • Enabled:使用抢占式RTOS调度。

  • Disabled:使用协作式RTOS调度。

General > Use Port Optimised Task Selection

Disabled

启用端口优化任务选择。

General > Use Tickless Idle

Disabled

General > Cpu Clock Hz

SystemCoreClock

CPU时钟频率。

General > Tick Rate Hz

100

RTOS 滴答中断的频率。

General > Max Priorities

5

应用程序任务可用的优先级数。任意数量的任务可以共享相同的优先级。

General > Minimal Stack Size

512

空闲任务使用的堆栈的大小。单位为字,而不是字节。

General > Max Task Name Len

16

任务名称的最大允许长度。该长度包括 NULL 终止字节。

General > Use 16-bit Ticks

Disabled

使用16位Ticks将大大提高8位和16位架构的性能,

但是会大大减少任务可以延迟或阻塞的最大时间。

General > Idle Should Yield

Enabled

General > Use Task Notifications

Disabled

使用任务通知。

General > Use Mutexes

Disabled

使用互斥量。

General > Use Recursive Mutexes

Disabled

使用递归互斥量。

General > Use Counting Semaphores

Enabled

使用计数信号量。

General > Queue Registry Size

10

队列注册表大小。

General > Use Queue Sets

Disabled

使用队列集。

General > Use Time Slicing

Disabled

使用时间切片。

General > Use Newlib Reentrant

Disabled

使用Newlib可重入。

General > Enable Backward Compatibility

Disabled

使能向后兼容。

General > Num Thread Local Storage Pointers

5

设置每个任务的线程本地存储数组中的索引数。

General > Stack Depth Type

uint32_t

栈深度类型。

General > Message Buffer Length Type

size_t

FreeRTOS 消息缓冲区使用消息缓冲区长度类型的变量来存储每条消息的长度。

如果没有定义消息缓冲区长度类型,那么它将默认为 size_t。

General > Library Max Syscall Interrupt Priority

Priority 1

General > Assert

if (!(x)) {__BKPT(0);}

General > Include Application Defined Privileged Functions

Disabled

Hooks > Use Idle Hook

Enabled

如果希望使用空闲钩子,则将其设置为“启用”,或者“禁用”以省略空闲钩子。

Hooks > Use Malloc Failed Hook

Disabled

Hooks > Use Daemon Task Startup Hook

Disabled

Hooks > Use Tick Hook

Disabled

Hooks > Check For Stack Overflow

Disabled

Stats > Use Trace Facility

Disabled

Stats > Use Stats Formatting Functions

Disabled

Stats > Generate Run Time Stats

Disabled

Memory Allocation > Support Static Allocation

Enabled

支持静态内存分配。

Memory Allocation > Support Dynamic Allocation

Enabled

支持动态内存分配。

Memory Allocation > Total Heap Size

0x8000

FreeRTOS 堆中可用的 RAM 总量。

Memory Allocation > Application Allocated Heap

Disabled

Timers > Use Timers

Enabled

使用软件定时器功能。

Timers > Timer Task Priority

3

定时器任务优先级。

Timers > Timer Queue Length

10

定时器队列长度。

Timers > Timer Task Stack Depth

128

定时器任务栈深度。

设置分配给软件计时器服务/守护进程任务的堆栈深度。

Optional Functions > vTaskPrioritySet() Function

Enabled

包含 vTaskPrioritySet() 函数。

Optional Functions > uxTaskPriorityGet() Function

Enabled

包含 uxTaskPriorityGet() 函数。

Optional Functions > vTaskDelete() Function

Enabled

包含 vTaskDelete() 函数。

Optional Functions > vTaskSuspend() Function

Enabled

包含 vTaskSuspend() 函数。

Optional Functions > xResumeFromISR() Function

Disabled

Optional Functions > vTaskDelayUntil() Function

Enabled

包含 vTaskDelayUntil() 函数。

Optional Functions > vTaskDelay() Function

Enabled

包含 vTaskDelay() 函数。

Optional Functions > xTaskGetSchedulerState() Function

Enabled

包含 xTaskGetSchedulerState() 函数。

Optional Functions > xTaskGetCurrentTaskHandle() Function

Enabled

包含 xTaskGetCurrentTaskHandle() 函数。

Optional Functions > uxTaskGetStackHighWaterMark() Function

Disabled

Optional Functions > xTaskGetIdleTaskHandle() Function

Disabled

Optional Functions > eTaskGetState() Function

Disabled

Optional Functions > xEventGroupSetBitFromISR() Function

Enabled

包含 xEventGroupSetBitFromISR() 函数。

Optional Functions > xTimerPendFunctionCall() Function

Disabled

Optional Functions > xTaskAbortDelay() Function

Disabled

Optional Functions > xTaskGetHandle() Function

Disabled

Optional Functions > xTaskResumeFromISR() Function

Enabled

包含 xTaskResumeFromISR() 函数。

RA > Hardware Stack Monitor

Disabled

Logging > Print String Function

printf(x)

Logging > Logging Max Message Length

192

Logging > Logging Include Time and Task Name

Disabled

35.7.2.2.3. 配置 FreeRTOS+TCP

点击“FreeRTOS+TCP”模块,如下图所示。

图

FreeRTOS+TCP 的属性配置如下:

FreeRTOS+TCP 的配置属性

属性

描述

Print debug messages

Disabled

打印调试信息。

Print info messages

Disabled

打印 info 信息。

Byte order of the target MCU

pdFREERTOS_LITTLE_ENDIAN

IP/TCP/UDP checksums

Enabled

计算 IP/TCP/UDP 校验和。

Receive Block Time

2000

FreeRTOS_recv() 阻塞的时间量。可以使用 setsockopt() 设置每个套接字的超时。

Send Block Time

2000

FreeRTOS_send() 阻塞的时间量。可以使用 setsockopt() 设置每个套接字的超时。

DNS caching

Disabled

DNS 缓存。

DNS Request Attempts

5

DNS 请求尝试。

IP stack task priority

configMAX_PRIORITIES - 1

设置执行IP栈任务的优先级。

Stack size in words (not bytes)

configMINIMAL_STACK_SIZE * 10

为 FreeRTOS+TCP 设置栈大小,单位为字。

Network Events call vApplicationIPNetworkEventHook

Disabled

当网络连接或断开时,vApplicationIPNetworkEventHook 会被调用。

Max UDP send block time

15000 / portTICK_PERIOD_MS

最大 UDP 发送块时间。

Use DHCP

Enabled

使用 DHCP。

DHCP Register Hostname

Enabled

使用 DHCP 时注册主机名。

DHCP Uses Unicast

Enabled

DHCP 使用单播。

DHCP Send Discover After Auto IP

Enabled

DHCP callback function

Enabled

需提供 DHCP 回调函数:xApplicationDHCPHook。

Interval between transmissions

120000 / portTICK_PERIOD_MS

ARP Cache Entries

6

ARP 缓存条目。

ARP Request Retransmissions

5

ARP 请求重传次数。

Maximum time before ARP table entry becomes stale

150

创建或刷新 ARP 表中的条目与删除该条目之间的最长时间。

Use string for IP Address

Enabled

使用字符串表示IP地址。

Total number of available network buffers

16

网络数据包缓冲的总数

Set the maximum number of events

ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5

Enable FreeRTOS_sendto() without calling Bind

Disabled

TTL values for UDP packets

128

TTL values for TCP packets

128

Use TCP and all its features

Enabled

使用 TCP 及其所有特性。

Let TCP use windowing mechanism

Disabled

让 TCP 使用滑动窗口机制。

Maximum number of bytes the payload of a network frame can contain

1500

MTU 大小。

Basic DNS client or resolver

Enabled

基本的 DNS 客户端/解析器。

Reply to incoming ICMP echo (ping) requests

Enabled

应答 ICMP echo (ping) 请求。

FreeRTOS_SendPingRequest() is available

Enabled

允许使用 FreeRTOS_SendPingRequest()。

对应 ipconfigREPLY_TO_INCOMING_PINGS 宏配置。

FreeRTOS_select() (and associated) API function is available

Disabled

Filter out non Ethernet II frames.

Enabled

过滤掉非以太网 II 格式的以太网帧。

Responsibility of the Ethernet interface to filter out packets

Disabled

Send RST packets, when receive unknown packets.

Enabled

Access 32-bit fields in the IP packets

2

Size of the pool of TCP window descriptors

240

Size of Rx buffer for TCP sockets

3000

Size of Tx buffer for TCP sockets

3000

TCP keep-alive

Enabled

TCP keep-alive interval

120

The socket semaphore to unblock the MQTT task (USER_SEMAPHORE)

Disabled

The socket semaphore to unblock the MQTT task (WAKE_CALLBACK)

Enabled

The socket semaphore to unblock the MQTT task (USE_CALLBACKS)

Disabled

The socket semaphore to unblock the MQTT task (TX_DRIVER)

Disabled

The socket semaphore to unblock the MQTT task (RX_DRIVER)

Disabled

Possible optimisation for expert users

Disabled

35.7.2.2.4. 配置 ETHERC 和 PHY

点击“g_ether0”模块,如下图所示。

图

在左下角属性配置窗口进行配置,g_ether0 的属性配置如下:

g_ether0 的配置属性

属性

描述

Common > Parameter Checking

Default (BSP)

Common > ET0_LINKSTA Pin Status Flag

Fall -> Rise

设置 LINKSTA 状态变化。

Common > Link Signal Change Flag

Unused

使用 LINKSTA 信号检测链路状态变化。

General > Name

g_ether0

General > Channel

0

General > MAC address

00:11:22:33:44:55

General > Zero-copy Mode

Disabled

General > Flow control functionality

Disabled

Filters > Multicast Mode

Enabled

Filters > Promiscuous Mode

Disabled

Filters > Broadcast filter

0

Buffers > Number of TX buffer

4

Buffers > Number of RX buffer

4

Buffers > Allocate RX buffer

Enabled

Buffers > Buffer size

1514

Buffers > Padding size

Disabled

自动插入到接收数据包中的填充大小。

Buffers > Padding offset

1

在接收缓冲区中插入填充字节的偏移量。

Interrupts > Interrupt priority

Priority 12

选择 EDMAC 中断优先级。

Interrupts > Callback

vEtherISRCallback

该中断回调函数是固定的,无法变更。

点击“g_ether_phy0”模块,如下图所示。

图

在左下角属性配置窗口进行配置,PHY 的属性配置如下:

Common 部分

属性

描述

Parameter Checking

Default

Select PHY(DEPRECATED)

Default

KSZ8091RNZ Target

Disabled

KSZ8041 Target

Disabled

DP83620 Target

Disabled

ICS1894 Target

Disabled

Reference Clock

Default

Ethernet PHY 的配置属性

属性

描述

Name

g_ether_phy0

Channel

0

PHY-LSI Address

0

PHY-LSI Reset Completion Timeout

0x00020000

Select MII type

RMII

Phy LSI type

Kit Component

MII/RMII Register Access Wait-time

8

Flow Control

Disabled

35.7.2.3. PHY底层驱动函数

代码清单34-1:PHY底层驱动函数
 /* Access to peripherals and board defines. */
 #include "bsp_api.h"
 #include "r_ether_phy.h"

 #include "hal_data.h"
 #include "stdio.h"

 /***********************************************************************************************************************
 * Macro definitions
 ***********************************************************************************************************************/

 /***********************************************************************************************************************
 * Typedef definitions
 ***********************************************************************************************************************/


 /* LAN8720 */
 #define ETHER_PHY_REG_SPECIAL_CONTROL_INDICATION    27
 #define ETHER_PHY_AMDIXCTRL_DISABLE                 (1u<<15)
 #define ETHER_PHY_CH_SELECT                         (0u<<13)

 /* Standard PHY Registers */
 #define ETHER_PHY_REG_CONTROL                   (0)
 #define ETHER_PHY_REG_STATUS                    (1)
 #define ETHER_PHY_REG_IDENTIFIER1               (2)
 #define ETHER_PHY_REG_IDENTIFIER2               (3)
 #define ETHER_PHY_REG_AN_ADVERTISEMENT          (4)
 #define ETHER_PHY_REG_AN_LINK_PARTNER           (5)
 #define ETHER_PHY_REG_AN_EXPANSION              (6)


 /***********************************************************************************************************************
 * Exported global variables (to be accessed by other files)
 ***********************************************************************************************************************/

 /***********************************************************************************************************************
 * Exported global function
 ***********************************************************************************************************************/
 void ether_phy_targets_initialize(ether_phy_instance_ctrl_t * p_instance_ctrl);
 bool ether_phy_targets_is_support_link_partner_ability(ether_phy_instance_ctrl_t * p_instance_ctrl,
                                                       uint32_t                    line_speed_duplex);
 extern uint32_t ether_phy_read(ether_phy_instance_ctrl_t * p_instance_ctrl, uint32_t reg_addr);
 extern void     ether_phy_write(ether_phy_instance_ctrl_t * p_instance_ctrl, uint32_t reg_addr, uint32_t data);

 /***********************************************************************************************************************
 * Private global variables and functions
 ***********************************************************************************************************************/

 /***********************************************************************************************************************
 * Functions
 **********************************************************************************************************************/

 /***********************************************************************************************************************
 * Function Name: ether_phy_targets_initialize
 * Description  : PHY-LSI specific initialization processing
 * Arguments    : p_api_ctrl -
 *                    Ethernet channel number
 * Return Value : none
 ***********************************************************************************************************************/
 void ether_phy_targets_initialize (ether_phy_instance_ctrl_t * p_instance_ctrl)
 {
     uint32_t reg;

     /* HP Auto-MDIX */
     /* Read the special control/status indications register (Register Index: 27) */
     reg = ether_phy_read(p_instance_ctrl, ETHER_PHY_REG_SPECIAL_CONTROL_INDICATION);
     /* Disable Auto-MDIX and set MDI (TX=transmits, RX=receives) */
     reg |= (uint16_t) (ETHER_PHY_AMDIXCTRL_DISABLE | ETHER_PHY_CH_SELECT);
     /* Write the settings back to the special control/status indications register (Register Index: 27) */
     ether_phy_write(p_instance_ctrl, ETHER_PHY_REG_SPECIAL_CONTROL_INDICATION, reg);

 #ifdef ETHERNET_PHY_DEBUG
     //Dump PHY registers for debugging purpose
     lan8720DumpPhyReg(p_instance_ctrl);
 #endif
 }

 /***********************************************************************************************************************
 * Function Name: ether_phy_targets_is_support_link_partner_ability
 * Description  : Check if the PHY-LSI connected Ethernet controller supports link ability
 * Arguments    : p_instance_ctrl -
 *                    Ethernet control block
 *                line_speed_duplex -
 *                    Line speed duplex of link partner PHY-LSI
 * Return Value : bool
 ***********************************************************************************************************************/
 bool ether_phy_targets_is_support_link_partner_ability (ether_phy_instance_ctrl_t * p_instance_ctrl,
                                                         uint32_t                    line_speed_duplex)
 {
     FSP_PARAMETER_NOT_USED(p_instance_ctrl);
     FSP_PARAMETER_NOT_USED(line_speed_duplex);

     /* This PHY-LSI supports half and full duplex mode. */
     return true;
 }                                      /* End of function ether_phy_targets_is_support_link_partner_ability() */

35.7.2.4. 用户需要实现的函数

用户需要实现的以下函数:

用户需要实现的函数
 void updateDhcpResponseToUsr(void)

 eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase,
                                             uint32_t ulIPAddress )

 const char *pcApplicationHostnameHook(void)

 uint32_t ulRand();
 uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
                                             uint16_t usSourcePort,
                                             uint32_t ulDestinationAddress,
                                             uint16_t usDestinationPort );
 uint32_t isNetworkUp(void);
 BaseType_t vSendPing( const char *pcIPAddress);
 void print_ipconfig(void);
 void print_pingResult(void);
 void dnsQuerryFunc(char *domain_name);

限于篇幅,暂不对这些函数进行详细地讲解,读者可参考例程源代码。

35.7.2.5. net_thread_entry入口函数

在使用 RTOS 并新建了一个线程的情况下,hal_entry 已经不再需要,并且网络线程的入口函数被设置为 net_thread_entry。 net_thread_entry 入口函数如下所示。

代码清单34-3:net_thread_entry入口函数
 #include "net_thread.h"
 #include "net_user_app.h"


 extern char *domain_name;
 extern char *remote_ip_address;

 extern uint8_t ucMACAddress[ 6 ];
 extern uint8_t ucIPAddress[ 4 ];
 extern uint8_t ucNetMask[ 4 ];
 extern uint8_t ucGatewayAddress[ 4 ];
 extern uint8_t ucDNSServerAddress[ 4 ];

 extern ping_data_t ping_data;
 uint32_t  usrPingCount  = RESET_VALUE;
 static uint32_t usr_print_ability = RESET_VALUE;



 /* Net Thread entry function */
 /* pvParameters contains TaskHandle_t */
 void net_thread_entry(void * pvParameters)
 {
     FSP_PARAMETER_NOT_USED(pvParameters);

     BaseType_t status = pdFALSE;
     fsp_pack_version_t version = {RESET_VALUE};


     /* 调试串口初始化 */
     Debug_UART4_Init();
     printf("Hello! FreeRTOS-Plus-TCP\r\n"
           "这是一个以太网 DNS & Ping 示例,请把网线接到开发板和路由器进行联网\r\n");

     /* 获取 FSP 库版本 */
     R_FSP_VersionGet(&version);
     /* 打印 FSP 库版本 */
     printf("Flex Software Pack Version  %d.%d.%d\r\n",
             version.version_id_b.major, version.version_id_b.minor, version.version_id_b.patch);

     printf("\r\n预置ipconfig:");
     print_ipconfig();

     /* FreeRTOS IP Initialization: This init initializes the IP stack  */
     status = FreeRTOS_IPInit(ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress);
     if(pdFALSE == status)
     {
         printf("FreeRTOS_IPInit Failed\r\n"
               "Returned Error Code: 0x%x\r\n", status);
         __asm("BKPT #0\n"); /* trap upon the error  */
     }


     /* TODO: add your own code here */
     while(1)
     {
         /* Check if Both the Ethernet Link and IP link are UP */
         if(SUCCESS == isNetworkUp())
         {
             /* usr_print_ability is added to avoid multiple UP messages or Down Messages repeating*/
             if(!(PRINT_UP_MSG_DISABLE & usr_print_ability))
             {
                 printf("\r\nNetwork is Up\r\n");
                 usr_print_ability |= PRINT_UP_MSG_DISABLE;
             }

             if(!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
             {
 #if( ipconfigUSE_DHCP != 0 )
                 /* Display the New IP credentials obtained from the DHCP server */
                 updateDhcpResponseToUsr();
 #endif
                 /* Updated IP credentials on to the RTT console */
                 printf("更新ipconfig:");
                 print_ipconfig();
                 /* DNS lookup for the Domain name requested. This is Synchronous Activity */
                 dnsQuerryFunc(domain_name);
             }

             if(!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
             {
                 printf("\r\nPinging %s:\r\n\r\n",(char *)remote_ip_address);
             }

             while (usrPingCount < USR_PING_COUNT)
             {
                 /* Send a ICMP Ping request to the requested IP address
                 * USR_PING_COUNT (100) is used in this Example Project
                 * For Continuous testing the count can be increased to bigger number
                 */
                 status =  vSendPing((char *)remote_ip_address);
                 if(status != pdFALSE)
                 {
                     ping_data.sent++;
                     printf("!");    // Ping请求发送成功
                 }
                 else
                 {
                     ping_data.lost++;
                     printf(".");
                 }
                 usrPingCount++;
                 /* Add some delay between Pings */
                 vTaskDelay(10);
             }

             if(!(PRINT_NWK_USR_MSG_DISABLE & usr_print_ability))
             {
                 print_pingResult();
                 usr_print_ability |= PRINT_NWK_USR_MSG_DISABLE;
             }
         }
         else
         {
             if(!(PRINT_DOWN_MSG_DISABLE & usr_print_ability))
             {
                 printf("\r\nNetwork is Down");
                 usr_print_ability |= PRINT_DOWN_MSG_DISABLE;
             }
             else
             {
                 printf(".");
             }
         }
         vTaskDelay(100);
     }
 }

35.7.3. 下载验证

注解

运行此以太网例程需要先切换芯片DLM状态:从出厂的 “CM” 切换到 “SSD” 状态, 然后重要的是要设置 IDAU 边界。否则,Ethernet 和 EDMAC 将无法使用。

NOTE : On RA MCUs with TrustZone, IDAU boundaries are programmed by this project due to the use of Ethernet and EDMAC peripherals. Consequentially, it is necessary to connect the serial programming interface to meet this requirement.

可按照以下两种方法当中的其中任意一种进行操作后,即可正常使用本实验的以太网例程:

  1. 使用 Renesas Flash Programmer 软件手动切换RA6M5芯片的DLM状态,并且设置 IDAU 边界, 具体方法步骤请参考本教程第3章内容。

  2. 使用 J-Link 和 e2 studio 的用户可实现自动切换。 需要注意,这里的 J-Link 需要 J-Link V10 及后续的硬件版本,以前的版本以及 JLink EDU mini 不支持该功能。 J-Link 需要通过 JTag 接口连接到启明6M5开发板,SWD接口无法操作, 因为该操作必须在控制 P109(TDO / TXD9)和 P110(TDI / RXD9)、MD 引脚以及复位(RESET)的情况下完成。 然后在启动调试之前还需将 J17 排针上的跳线帽拔出,并插到 J23 排针上短接 SCK 和 MD 引脚, 然后使用 J-Link 在 e2 studio 环境下启动一次调试即可。

首先编译程序,并按照上述方法设置 IDAU 边界,确保能正常使用 Ethernet 和 EDMAC 外设。

将程序下载到开发板后,连接串口并打开串口助手,复位板子让程序运行。

如下图所示,可以看到程序会首先打印提示信息:

图

当连接网线到路由器上之后,稍等片刻,可以看到正常的程序运行结果如下图所示:

图