STM32F2x系统需要2个网络接口,怎么做

STM32F2―系列概览_图文_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
STM32F2―系列概览
&&STM32F2官方培训资料
阅读已结束,下载本文需要
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩9页未读,
定制HR最喜欢的简历
你可能喜欢STM32407 网络通信模块
早在还没有毕业前,就调试过STM32F407+DP83848,这次又调试了一次,居然花了2天时间。STM32支持两种工业级标准的接口,来与外部物理层 PHY模块相连,分别是独立于介质的接口(MII)和简化的独立于接口的接口(RMII)。之前PHY芯片使用的MII模式,现在的这次调试是使用的RMII模式(参考了各方原理图,主要还是以官方开发板的MB786为主)。我还是以一个ST官方手册上的图来说说我的使用情况吧。
如果我们按照这个图上来画原理图,这个肯定没有错,但是对于一般使用(我们用的都是全双工的),CRS和COL这两根线使用的不多,至于为什么,我也说的不是很清楚,了解的同学们,可以补充下。
对于连接和stm32时,在电路上是否要串行电阻,串接多大的问题。借网友的回答是这样的:串接电阻这是用来做阻抗匹配,防止信号反射的。一般PCB走线控制为50欧姆,在这样接收端高阻的情况时,可以通过源端串联50欧姆来做匹配,将终端反射回来的信号吸收,防止在源端再次发生发射。至于,串接多大的电阻,由信号驱动的内阻(大约20欧)决定,与PCB走线匹配。所以这个电阻在PCB上的位置要和信号驱动端靠近。要不要做匹配就取决于信号的速度和走线长度,规则一般是走线长度大于信号波长的1/10就要匹配了,50M的时钟最好是接一下了,不然会看到明显的过冲。参考各方资料,一般接上33欧到50欧的电阻都可以接受。
这里对于MII模式加以说明哪些引脚需要上拉和下拉。
MDIO需要1.5K的上拉电阻,MDC不需要上拉电阻,DP83848的LED_ACT、LED_SPEED、LED_LINK都需要2.2K的上拉电阻;
DP83848的RD-、RD+、TD-、TD+需要上拉49.9欧1%的电阻,并且还需要两个0.1uf的电容接地;
DP8引脚RESERVED必须要接2.2K上拉电阻,和24引脚RBIAS需要一个4.87欧1%的电阻接地,引脚18、23、37需要电容接地,这些都需要严格按照DP83848的手册来连接电路。
另外,39引脚不需要上拉电阻,如果是RMII模式,就需要2.2K的电阻,这样就选择了我们是使用的RMII模式。
其中,有个重要的信号一定要注意,这个也是我在使用RMII模式没有注意的,stm32 的ETH_RMII_REF_CLK / ETH_MII_RX_CLK 信号线PA1 没有连接,使用RMII模式的时候,PA1应该连接到时钟源上面。
最后,DP83848的7引脚,一般还是建议上拉2.2K电阻,并且,将其连接到STM32的IO引脚,因为我们一般还是需要使用一些中断来处理事件,比如,网线热插拔问题。
在硬件调试过程中,stm32的外部时钟是否起振,DP83848的25引脚应该能输出25MHz(MII)或50MHz(RMII)的信号,在RMII模式,TX_CLK应该有25MHz的信号。注意,PHY的复位信号最好不要与stm32的复位信号连接到一起,因为当PHY没有通电使用时,stm32的复位引脚一直会被拉低,导致stm32不能正常使用。
在软件调试过程中,这里以官方例程来说。首先,stm32的外部时钟频率要设置正确;然后,考虑使用哪种模式,相应开启哪种模式的宏定义;再则,如果使用MCO提供DP83848的时钟信号,需要注意stm32 的PA8引脚的初始化,如果是使用的外部时钟源,可以不用考虑MCO信号(但是不用连接PHY),在软件GPIO初始化的时候,要注意,注释PA8的初始化部分,只需要注释该引脚的初始化,引脚状态初始化不要注释,因为后面的引脚初始化都会用到。
没有更多推荐了,单片机、电路板
连接器、接插件
其他元器件
STM32-F2 MCU在工厂自动化中的应用
STM32-F2 MCU在工厂自动化中的应用
工业环境正在对嵌入式控制系统开发人员构成日益严峻的挑战,究其主要原因,当前系统和通信协议栈变得越来越复杂,系统实时性和安全要求越来越严格,同时,这种趋势直接影响到半导体元器件的特性和技术规格。为克服这些挑战,意法半导体在今年初发布了STM32-F2系列微控制器,以帮助开发人员实现要求苛刻的工业应用。新系列产品诞生于深受市场欢迎的STM32产品家族,拥有更高的性能、更大的存储容量和针对工业应用优化的
工业环境正在对嵌入式控制系统开发人员构成日益严峻的挑战,究其主要原因,当前系统和通信协议栈变得越来越复杂,系统实时性和安全要求越来越严格,同时,这种趋势直接影响到半导体元器件的特性和技术规格。为克服这些挑战,意法半导体在今年初发布了STM32-F2系列微控制器,以帮助开发人员实现要求苛刻的工业应用。新系列产品诞生于深受市场欢迎的STM32产品家族,拥有更高的性能、更大的存储容量和针对工业应用优化的外设。F2系列产品在一颗芯片上集成了多种功能,例如,控制/调整功能和复杂的通信协议栈。高集成度的优点是,缩小印刷电路板空间,避免在不同的控制器之间存在易受到电磁兼容性影响的连接电路,优化应用成本。工业自动化市场的特点是多个通信协议并存,实时应用需要高效的操作系统。因此,软件栈和操作系统成为选择微控制器的首要参数。 STM32微控制器基于受到市场广泛支持的Cortex M3内核,因此,有20多家实时操作系统和通信协议提供商供用户选择。为使STM32微控制器更加完美,意法半导体还增加了一个兼容CMSIS的硬件抽象层和其它固件库,例如,支持永磁同步电机(PMSM)的磁场定向控制 (FOC) .本文将介绍两个第三方专门为STM32F-2研发的工厂自动化软件: IXXAT开发的支持PTP的IEEE1588协议软件包和PORT开发的Profinet通信协议栈。STM32-F2针对工厂自动化的改进的性能与上一代产品STM32-F1相比,STM32-F2在很多方面加以改进,特别是性能更加出色,外设接口更加丰富。STM32-F2采用90nm光刻技术,处理速度达到120MHz,并使运行功耗保持在合理水平(300uA/MHz)。这项光刻技术的另一个好处是集成度更高,有助于降低应用的系统级成本。为了充分发挥Cortex-M3内核的优异性能,意法半导体重新评估了产品架构。新产品在120MHz下释放150DMIP的强劲性能(Dhrystone 2.1),CoreMark测试成绩取得254高分(2.120 CoreMark/MHz 通过EEMBC 认证), STM32F-2因而进入Cortex-M微控制器的第一阵营,这个成绩归功于自适应实时存储器加速器(ARTTM),采用这项闪存访问管理技术后,应用代码执行不再会受闪存本身固有的等待状态的影响。虽然闪存的速度比内核本身慢三倍,但是,在代码执行过程中不会出现等待状态,即便处理速度达到120MHz时也是零等待状态。因此,新系列产品可大幅缩减设计尺寸,降低功耗和闪存的EMC影响,确保最高的产品性能。STM32-F2的主要特性如下: 最高1MB的闪存、128kB RAM、6个UART(7.5Mbps)、3个SPI接口 (30Mbps)、支持IEE1588 PTP V2的以太网媒体访问控制器(MAC)、4kB备用RAM、512字节的一次性可编程存储器(OTP)。总线矩阵除单纯的内核计算能力外,微控制器设计人员还必须考虑总线设计,在微控制器不同单元之间实现并行访存和数据传输,例如,内核和通信外设需要同时访问不同的存储器。因此,主要总线最终被设计成一个多层AHB总线矩阵,最多支持6个同步数据流。STM32-F2系列微控制器共有5个总线主控制器:●有3条内核总线的ARM Cortex-M3内核●2个DMA控制器●高速USB主设备控制器●10/100以太网MAC控制器上图中的黑点代表在这个7层总线结构中总线主控制器与从控制器的全部接口。为提高系统的能效,SRAM存储器被分成两个存储区SRAM1和SRAM2,SRAM1用于保存基本协议栈和变量,而SRAM2则用作通信外设的帧缓冲区。以太网和USB外设都占用了几千字节的FIFO存储空间,而且分别拥有一个各自专用的DMA控制器。除多个SRAM分区外,该系统还有两个AHB总线从控制器。同样地,这样的配置准许不同的总线主控制器并行处理和同步访问不同的高速外设,例如,加密处理器和通用输入输出端口。AHB从控制器和DMA控制器都是双端口,这样设计准许在AHB总线上直接连接DMA控制器与高速外设,避免在总线矩阵和二级高速至低速桥上因延迟而降低性能。外部存储器接口又称"静态存储控制器",可直接连接不同的异步和同步存储器、NOR/NAND闪存、SRAM、伪SRAM,甚至还能连接一个液晶显示器控制器,外存接口总线频率最高60MHz,还能通过指令总线(I-bus)获取CPU内核指令。存储器加速器意法半导体的自适应实时(ART)存储器加速器(如下图所示)可让Cortex-M3内核释放最高的处理性能,虽然闪存本身需要等待状态,但是,引入这项技术后,STM32-F2以120 MHz的速度从闪存执行代码无等待状态。存储器接口是128位宽,每次可取4-8条THUMB2指令。如果执行线性代码,因为预取指功能,即便闪存速度只是内核的四分之一,代码执行也不会出现等待状态。然而,如果执行转移或跳转指令,需要立即取出转移或跳转目标地址的数据,这样,存储器的等待状态会增加系统开销,这就是ART及其64项高速指令缓存发挥作用的地方。如果非顺序指令第一次出现,这条指令将从存储器中取出并保存在64项高速缓存的一个存储项内。在下一次出现时,该指令将从高速缓存中直接取出,没有等待状态。这个指令高速缓存还有一个LRU即最近不常用机制,因此,假如一个应用软件的转移指令超过64条,最近常用的新指令将取代最近不常用的指令。这个架构的优点是,即便中断服务处理程序被加速器覆盖,这个机制仍然能够支持各种转移指令。最常用的8行数据项目像高速指令缓存一样,但是用于暂存最常用的数据库,可以使D-bus总线立即充满数据。工业协议栈和固件IXXAT为 STM32开发的IEEE 1588 PTP协议测量系统、电信设备、自动化系统或汽车系统等分布式应用设备对精确时序机制的要求越来越高。IEEE 1588的精确时序协议(PTP)通过以太网使分布式设备的时序同步精度达到纳秒级,从而满足分布式应用系统的要求。IXXAT自动化技术有限公司开发的IEEE 1588协议软件让设备厂商能够轻松、快速地开发IEEE 1588兼容设备,这款软件的源代码采用C语言,可实现在任何平台上。为了在意法半导体的STM32-F2系列微控制器上实现IEEE 1588协议,IXXAT为STM32-F2用户提供一个定制版协议软件,该解决方案大幅简化并加快了协议的实现过程。STM32-F2专用协议软件需要与一个有组播功能的TCP/IP协议栈配合使用,有无操作系统均可。因为功能丰富,连续升级,占有率高,IXXAT的IEEE 1588协议软件已成为1588协议软件市场的主要参考标准。最新的1.03版IEEE 1588已支持新的IPv6标准,该标准将逐渐被新系统所采用。这个解决方案的模块化软件结构包含基本包和可选扩展文件,例如,用于IPv6、IEEE 802.3和Unicast的文件,让包与专门应用及其资源能够实现最佳匹配。用户可以动态设置多种功能,例如,延迟机制(对等/端到端)和通信技术(IPv4, IPv6, 802.3),因此,设计人员开发设备时无需考虑网络结构,用户使用设备时无需修改固件,这样设计可以降低研制成本,让客户提出更吸引人的价值主张。STM32-F2系列微控制器在以太网媒体访问控制器MAC内整合了支持IEEE 1588 (PTP V2)的硬件,具有实现一个高精度时序同步协议所需的全部资源。我们做了一个长时间的背对背连接同步测试, 采用了1个精确的主控制器(2ppm晶振),测试条件是0.125秒同步间隔,测试结果显示,该平台最大同步偏差为±70纳秒,标准同步偏差大约是15纳秒。在上电后,IXXAT的IEEE 1588协议软件同步平均需要大约20个同步间隔。在一个STM32微控制器上实现的IEEE 1588软件,取得1个有IPv4、端到端 (E2E)和对等(P2P)延迟机制和主控制器的通用普通时钟的典型功能,需要47KB空间保存程序代码,7KB空间保存只读数据,23KB空间保存读写数据。除IEEE 1588协议软件外,IXXAT的服务还包括定制软硬件开发和系统设计,以及技术研讨会和代码推介会服务。STM3210C-EVAL 评估板用户可以从下面的网址下载IXXAT与意法半导体合作开发的免费版IEEE 1588软件:http://www.ixxat.de/evaluation_kit_stm3210c_de.html.PORT Profinet软件栈Port公司是市场领先的CAN/CANopen、DeviceNet现场总线解决方案提供商,公司加强了硬件和固件开发能力,扩大了业务组合,加强了协议栈和POWERLINK、PROFINET、EtherNet/IP和EtherCAT开发工具产品组合。PROFINET是工业以太网版PROFIBUS总线,而这项技术被业界公认为极其耗费资源。意法半导体与Port合作为STM32 F-2系列研发了一款只需128KB SRAM存储容量的PROFINET软件,让意法半导体的微控制器步入一个新的应用领域。STM32 F-2与Port PROFINET组合不仅适用于工业自动化应用,例如,工业编码器(定位)、工业驱动附件,而且还适用于内置以太网控制功能的安全系统。PROFINET的 STM32 F-2版协议栈为用户提供符合IEC 61158和IEC 61784标准的PROFINET IO兼容通信所需的全部服务功能,帮助用户轻松快速地开发PROFINET IO设备。该解决方案是是通过一个硬件抽象层访问硬件,并为用户提供能够连接意法半导体的不同微控制器的驱动程序,有无操作系统均可。为了快速获得总线使用权限,符合PROFINET的技术规范,该解决方案对底层以太网驱动软件进行了优化。STM32 F-2支持PROFINET Conformance Class A,还可以支持PROFINET Realtime Class 1.为了帮助设计人员轻松快速地开发项目,Port还提供一个PROFINET设计工具。意法半导体的电机矢量控制库因为集成两个先进的定时器外设、3个快速数模转换器(0.5MSps)和DMA直接访存功能,STM32F2x特别适合需要1个或2个电机控制驱动器的应用。即便驱动两个电机时,150DMIPS的性能让STM32F2x有充足后备动力驱动其它复杂的应用任务。STM32F-2配备STM32 PMSM FOC软件开发工具,实现了磁场定向控制(FOC)驱动3相永磁同步表面安装电机(SM-PMSM)和内部安装电机(I-PMSM),最新的3.1版STM32 PMSM FOC开发工具套件包含STM32F-2微控制器,预计2011年7月上市。STM32 PMSM FOC开发工具套件可用于快速评估STM32微控制器的各种应用和完整的应用平台,当开发在意法半导体微控制器上运行的电机控制算法时,这套开发工具有助于缩短的应用的开发周期。PMSM FOC固件的源代码采用C语言,实现了电机控制内核算法(参考系转换、电流调整、速度调整、空间矢量调制、能效优化)以及传感器检测算法、解码算法(3个并联电阻、意法半导体专利单直流链路并联电阻、隔离型电流传感器、增量编码器、霍尔传感器)和转子位置重构无传感器算法。为了让大家了解STM32F-2出色的计算性能,我们做了一个性能测试。在使用两个并联电阻检测电机电流的无传感器配置中,用一个STM32F-2驱动两个PMSM电机,按照标准双矢量控制性能(以10kHz运行FOC算法)测试,CPU负荷在35%的范围内;按照高级双矢量控制性能(以16kHz运行FOC算法)测试,CPU负荷在50%的范围内。这些性能为STM32F-2系列微控制器在工厂自动化领域开启了广泛的应用空间。结语要求严格的工业通信协议软件栈显然能够充分利用STM32F-2系列微控制器高于同级产品的优异性能。当执行高性能应用软件和算法时,STM32F-2执行速度比上一代产品STM32F-1提高1倍多。STM32-F2系列产品已通过客户检测验证,目前正在提升产量。大多数固件和协议栈已经上市,未上市的也准备今年夏季发布。STM32-F2系列产品的升级产品目前正在设计阶段,新一代产品包括基于Cortex-M4内核的微控制器,能够更好地支持需要数字信号处理器的应用。
下一篇:已经是最后一篇
型号/产品名
深圳优耐检测技术有限公司
深圳优耐检测技术有限公司
深圳优耐检测技术有限公司
深圳优耐检测技术有限公司
深圳优耐检测技术有限公司第39章 &&&&ETH&Lwip以太网通信
全套集视频教程和页教程请到秉火论坛下载:
野火视频教程优酷观看网址:
互联网技术对人类社会的影响不言而喻。当今大部分电子设备都能以不同的方式接入互联网,在家庭中常见的互联网接入方式是使用路由器组建小型局域网,利用互联网专线或者调制调解器经过电话线网络,连接到互联网服务提供商,由互联网服务提供商把用户的局域网接入互联网。而企业或学校的局域网规模较大,常使用交换机组成局域网,经过路由以不同的方式接入到互联网中。
39.1 互联网模型
通信至少是两个设备的事,需要相互兼容的硬件和软件支持,我们称之为通信协议。以太网通信在结构比较复杂,国际标准组织将整个以太网通信结构制定了模型,总共分层七个层,分别为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层,每个层功能不同,通信中各司其职,整个模型包括硬件和软件定义。模型是理想分层,一般的网络系统只是涉及其中几层。
是互联网最基本的协议,是互联网通信使用的网络协议,由网络层的协议和传输层的协议组成。只有四个分层,分别为应用层、传输层、网络层以及网络访问层。虽然分层少了,但与模型是不冲突的,它把模型一些层次整合一起的,本质上可以实现相同功能。
实际上,还有一个混合模型,分为五个层,参考图,它实际与四层模型是相通的,只是把网络访问层拆成数据链路层和物理层。这种分层方法对我们学习理解更容易。
图 391 TCP/IP混合参考模型
设计网络时,为了降低网络设计的复杂性,对组成网络的硬件、软件进行封装、分层,这些分层即构成了网络体系模型。在两个设备相同层之间的对话、通信约定,构成了层级协议。设备中使用的所有协议加起来统称协议栈。在这个网络模型中,每一层完成不同的任务,都提供接口供上一层访问。而在每层的内部,可以使用不同的方式来实现接口,因而内部的改变不会影响其它层。
在混合参考模型中,数据链路层又被分为层逻辑链路层和层媒体介质访问层。目前,对于普通的接入网络终端的设备,层和层是软、硬件的分界线。如的网卡主要负责实现参考模型中的子层和物理层,在的软件系统中则有一套庞大程序实现了层及以上的所有网络层次的协议。
由硬件实现的物理层和子层在不同的网络形式有很大的区别,如以太网和,这是由物理传输方式决定的。但由软件实现的其它网络层次通常不会有太大区别,在上也许能实现完整的功能,一般支持所有协议,而在嵌入式领域则按需要进行裁剪。
39.2 以太网
以太网是互联网技术的一种,由于它是在组网技术中占的比例最高,很多人直接把以太网理解为互联网。
以太网是指遵守标准组成的局域网,由标准规定的主要是位于参考模型的物理层和数据链路层中的介质访问控制子层。在家庭、企业和学校所组建的局域网形式一般也是以太网,其标志是使用水晶头网线来连接当然还有其它形式。还有其它局域网标准,如是无线局域网,俗称。是个人域网,即蓝牙技术,其中的标准则是技术。
现阶段,工业控制、环境监测、智能家居的嵌入式设备产生了接入互联网的需求,利用以太网技术,嵌入式设备可以非常容易地接入到现有的计算机网络中。
39.2.1 PHY层
在物理层,由标准规定了以太网使用的传输介质、传输速度、数据编码方式和冲突检测机制,物理层一般是通过一个芯片实现其功能的。
1.&&&&传输介质
传输介质包括同轴电缆、双绞线水晶头网线是一种双绞线、光纤。根据不同的传输速度和距离要求,基于这三类介质的信号线又衍生出很多不同的种类。最常用的是"五类线"适用于和的网络,它们的网络速率分别为和。
2.&&&&编码
为了让接收方在没有外部时钟参考的情况也能确定每一位的起始、结束和中间位置,在传输信号时不直接采用二进制编码。在的传输方式中采用曼彻斯特编码,在中则采用编码。
曼彻斯特编码把每一个二进制位的周期分为两个间隔,在表示""时,以前半个周期为高电平,后半个周期为低电平。表示""时则相反,见图
图 392 曼彻斯特编码
采用曼彻斯特码在每个位周期都有电压变化,便于同步。但这样的编码方式效率太低,只有。
在采用的编码是把待发送数据位流的每位分为一组,以特定的位编码来表示,这些特定的位编码能使数据流有足够多的跳变,达到同步的目的,而且效率也从曼彻斯特编码的提高到了。
3.&&&&CSMA/CD冲突检测
早期的以太网大多是多个节点连接到同一条网络总线上总线型网络,存在信道竞争问题,因而每个连接到以太网上的节点都必须具备冲突检测功能。以太网具备冲突检测机制,如果多个节点同时利用同一条总线发送数据,则会产生冲突,总线上的节点可通过接收到的信号与原始发送的信号的比较检测是否存在冲突,若存在冲突则停止发送数据,随机等待一段时间再重传。
现在大多数局域网组建的时候很少采用总线型网络,大多是一个设备接入到一个独立的路由或交换机接口,组成星型网络,不会产生冲突。但为了兼容,新出的产品还是带有冲突检测机制。
39.2.2 MAC子层
1.&&&&MAC的功能
子层是属于数据链路层的下半部分,它主要负责与物理层进行数据交接,如是否可以发送数据,发送的数据是否正确,对数据流进行控制等。它自动对来自上层的数据包加上一些控制信号,交给物理层。接收方得到正常数据时,自动去除控制信号,把该数据包交给上层。
2.&&&&MAC数据包
对以太网上传输的数据包格式也进行了统一规定,见图。该数据包被称为数据包。
图 393 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字节会被认为发生冲突,数据包被自动丢弃),当数据段的字节少于46字节时,在填充域会自动填上无效数据,以使数据包符合长度要求。
?&&&&校验和域:MAC数据包的尾部是校验和域,它保存了CRC校验序列,用于检错。
以上是标准的数据包,同时还规定了扩展的数据包,它是在标准的数据包的和数据包类型之间添加个字节的前缀字段,用于获取标志的帧。前个字节固定为,用于识别前缀的存在;后两个字节内容分别为个位的用户优先级、个位的标准格式指示符和一个位的标识符。
39.3 TCP/IP协议栈
标准协议是用于计算机通信的一组协议,通常称为协议栈,通俗讲就是符合以太网通信要求的代码集合,一般要求它可以实现图中每个层对应的协议,比如应用层的、、、协议,传输层的、协议、网络层的、协议等等。关于协议详细内容推荐阅读《详解》和《用进行网际互连》理解。
操作系统、类操作系统都有自己的一套方法来实现通信协议,它们都提供非常完整的协议。对于一般的嵌入式设备,受制于硬件条件没办法支持使用在或类操作系统的运行的协议栈,一般只能使用简化版本的协议栈,目前开源的适合嵌入式的有、、、等等。其中是目前在嵌入式网络领域被讨论和使用广泛的协议栈。本章内容其中一个目的就是移植到开发板上运行。
39.3.1 为什么需要协议栈
物理层主要定义物理介质性质,子层负责与物理层进行数据交接,这两部分是与硬件紧密联系的,就嵌入式控制芯片来说,很多都内部集成了控制器,完成子层功能,所以依靠这部分功能是可以实现两个设备数据交换,而时间传输的数据就是数据包,发送端封装好数据包,接收端则解封数据包得到可用数据,这样的一个模型与使用控制器实现数据传输是非常类似的。但如果将以太网运用在如此基础的功能上,完全是大材小用,因为以太网具有传输速度快、可传输距离远、支持星型拓扑设备连接等等强大功能。功能强大的东西一般都会用高级的应用,这也是设计者的初衷。
使用以太网接口的目的就是为了方便与其它设备互联,如果所有设备都约定使用一种互联方式,在软件上加一些层次来封装,这样不同系统、不同的设备通讯就变得相对容易了。而且只要新加入的设备也使用同一种方式,就可以直接与之前存在于网络上的其它设备通讯。这就是为什么产生了在之上的其它层次的网络协议及为什么要使用协议栈的原因。又由于在各种协议栈中协议栈得到了最广泛使用,所有接入互联网的设备都遵守协议。所以,想方便地与其它设备互联通信,需要提供对协议的支持。
39.3.2 各网络层的功能
用以太网和作例子,它们的子层和物理层有较大的区别,但在之上的层、网络层、传输层和应用层的协议,是基本上同的,这几层协议由软件实现,并对各层进行封装。根据协议,各层的要实现的功能如下:
层:处理传输错误;调节数据流,协调收发数据双方速度,防止发送方发送得太快而接收方丢失数据。主要使用数据链路协议。
网络层:本层也被称为层。层负责把数据从线的一端传输到另一端,但很多时候不同的设备位于不同的网络中并不是简单的网线的两头。此时就需要网络层来解决子网路由拓扑问题、路径选择问题。在这一层主要有协议、协议。
传输层:由网络层处理好了网络传输的路径问题后,端到端的路径就建立起来了。传输层就负责处理端到端的通讯。在这一层中主要有、协议
应用层:经过前面三层的处理,通讯完全建立。应用层可以通过调用传输层的接口来编写特定的应用程序。而协议一般也会包含一些简单的应用程序如远程登录、文件传输、邮件传输协议。
实际上,在发送数据时,经过网络协议栈的每一层,都会给来自上层的数据添加上一个数据包的头,再传递给下一层。在接收方收到数据时,一层层地把所在层的数据包的头去掉,向上层递交数据,参考图。
图 394 数据经过每一层的封装和还原
39.4 以太网外设(ETH)
系列控制器内部集成了一个以太网外设,它实际是一个通过控制器进行介质访问控制,它的功能就是实现层的任务。借助以太网外设,控制器可以通过外设按照标准发送和接收数据包。内部自带专用的控制器用于,支持两个工业标准接口介质独立接口和简化介质独立接口用于与外部芯片连接。和接口用于数据包传输,还集成了站管理接口接口专门用于与外部通信,用于访问芯片寄存器。
物理层定义了以太网使用的传输介质、传输速度、数据编码方式和冲突检测机制,芯片是物理层功能实现的实体,生活中常用水晶头网线水晶头插座组合构成了物理层。
有专用的控制器,它通过主从接口与内核和存储器相连,主接口用于控制数据传输,而从接口用于访问"控制与状态寄存器"空间。在进行数据发送是,先将数据有存储器以传输到发送进行缓冲,然后由内核发送;接收数据时,先接收以太网数据帧,再由传输至存储器。系统功能框图见图。
图 395 ETH功能框图
39.4.1 SMI接口
是内核访问寄存器标志接口,它由两根线组成,数据线和时钟线。支持访问个,这在设备需要多个网口时非常有用,不过一般设备都只使用一个。芯片内部一般都有个位的寄存器,用于配置芯片属性、工作环境、状态指示等等,当然很多芯片并没有使用到所有寄存器位。内核就是通过向的寄存器写入数据或从寄存器读取状态,一次只能对一个的其中一个寄存器进行访问。最大通信频率为,通过控制以太网地址寄存器的位可选择时钟频率。
1.&&&&SMI帧格式
是通过数据帧方式与通信的,帧格式如表,数据位传输顺序从左到右。
表 391 SMI帧格式
管理帧字段
用于指定地址,每个都有一个地址,一般由硬件设计决定,所以是固定不变的。用于指定寄存器地址。为状态转换域,若为读操作,输出两个位高阻态,而芯片则在第一位时输出高阻态,第二位时输出""。若为写操作,输出"",芯片则输出高阻态。数据段有位,对应寄存器每个位,先发送或接收到的位对应以太网数据寄存器寄存器的位。
2.&&&&SMI读写操作
当以太网地址寄存器的写入位和繁忙位被置时,将向指定的芯片指定寄存器写入中的数据。写操作时序见图。
图 396 SMI写操作
当以太网地址寄存器的写入位为并且繁忙位被置时,将从向指定的芯片指定寄存器读取数据到内。读操作时序见图。
图 397 SMI读操作
39.4.2 MII和RMII接口
介质独立接口用于理解控制器和芯片,提供数据传输路径。接口是接口的简化版本,需要根通信线,只需根通信,在功能上是相同的。图为接口连接示意图,图为接口连接示意图。
图 398 MII接口连接
图 399 RMII接口连接
?&&&&TX_CLK:数据发送时钟线。标称速率为10Mbit/s时为2.5MHz;速率为100Mbit/s时为25MHz。RMII接口没有该线。
?&&&&RX_CLK:数据接收时钟线。标称速率为10Mbit/s时为2.5MHz;速率为100Mbit/s时为25MHz。RMII接口没有该线。
?&&&&TX_EN:数据发送使能。在整个数据发送过程保存有效电平。
?&&&&TXD[3:0]或TXD[1:0]:数据发送数据线。对于MII有4位,RMII只有2位。只有在TX_EN处于有效电平数据线才有效。
?&&&&CRS:载波侦听信号,由PHY芯片负责驱动,当发送或接收介质处于非空闲状态时使能该信号。在全双工模式该信号线无效。
?&&&&COL:冲突检测信号,由PHY芯片负责驱动,检测到介质上存在冲突后该线被使能,并且保持至冲突解除。在全双工模式该信号线无效。
?&&&&RXD[3:0]或RXD[1:0]:数据接收数据线,由PHY芯片负责驱动。对于MII有4位,RMII只有2位。在MII模式,当RX_DV禁止、RX_ER使能时,特定的RXD[3:0]值用于传输来自PHY的特定信息。
?&&&&RX_DV:接收数据有效信号,功能类似TX_EN,只不过用于数据接收,由PHY芯片负责驱动。对于RMII接口,是把CRS和RX_DV整合成CRS_DV信号线,当介质处于不同状态时会自切换该信号状态。
?&&&&RX_ER:接收错误信号线,由PHY驱动,向MAC控制器报告在帧某处检测到错误。
?&&&&REF_CLK:仅用于RMII接口,由外部时钟源提供50MHz参考时钟。
因为要达到传输速度,和数据线数量不同,使用和在时钟线的设计是完全不同的。对于接口,一般是外部为提供时钟源,再由提供和时钟。对于接口,一般需要外部直接提供时钟源,同时接入和。
开发板板载的芯片型号为,该芯片只支持接口,电路设计时参考图。
相关硬件在控制器分布参考表。
表 392 ETH复用引脚
其中,是定义的一个时钟同步机制。
39.4.3 MAC数据包发送和接收
外设负责数据包发送和接收。利用从系统寄存器得到数据包数据内容,外设自动填充完成数据包封装,然后通过发送出去。在检测到有数据包需要接收时,外设控制数据接收,并解封数据包得到解封后数据通过传输到系统寄存器内。
1.&&&&MAC数据包发送
数据帧发送全部由控制,从系统存储器读取的以太网帧由推入,然后将帧弹出并传输到内核。帧传输结束后,从内核获取发送状态并传回。在检测到时,接收数据并开始发送。在传输到内核后,内核将完成正常的发送,然后将发送状态返回给。如果在发送过程中发送常规冲突,内核将使发送状态有效,然后接受并丢弃所有后续数据,直至收到下一。检测到来自的重试请求时,应从重新发送同一帧。如果发送期间未连续提供数据,将发出下溢状态。在帧的正常传输期间,如果在未获得前一帧的的情况下接收到,则将忽略该并将新的帧视为前一帧的延续。
控制数据包的发送操作,它会自动生成前导字段和以及发送帧状态返回给,在半双工模式下自动生成阻塞信号,控制看门狗定时器用于在传输字节超过字节时切断数据包发送。在半双工模式下,使用延迟机制进行流量控制,程序通过将寄存器的位置来请求流量控制。包含符合的时间戳快照逻辑。数据包发送时序参考图。
图 3910 MAC数据包发送时序(无冲突)
2.&&&&MAC数据包接收
接收到的数据包填充,达到设定阈值后请求传输。在默认直通模式下,当接收到个字节使用寄存器中的位配置或完整的数据包时,数据将弹出,其可用性将通知给。向接口发起传输后,数据传输将从持续进行,直到传输完整个数据包。完成帧的传输后,状态字将弹出并发送到控制器。在存储转发模式通过寄存器中的位配置下,仅在帧完全写入后才可读出帧。
当在上检测到时,将启动接收操作。内核将去除报头和,然后再继续处理帧。检查报头字段以进行过滤,字段用于验证帧的如果帧未通过地址滤波器,则在内核中丢弃该帧。数据包接收时序参考图。
图 3911 MAC数据包接收时序(无错误)
39.4.4 MAC过滤
过滤功能可以选择性的过滤设定目标地址或源地址的帧。它将检查所有接收到的数据帧的目标地址和源地址,根据过滤选择设定情况,检测后报告过滤状态。针对目标地址过滤可以有三种,分别是单播、多播和广播目标地址过滤;针对源地址过滤就只有单播源地址过滤。
单播目标地址过滤是将接收的相应字段与预设的以太网地址寄存器内容比较,最高可预设个过滤地址。多播目标地址过滤是根据帧过滤寄存器中的位执行对多播地址的过滤,是对地址寄存器进行比较来实现的。单播和多播目标地址过滤都还支持过滤模式。广播目标地址过滤通过将帧过滤寄存器的位置使能,这使得丢弃所有广播帧。
单播源地址过滤是将接收的字段与寄存器内容进行比较过滤。
过滤还具备反向过滤操作功能,即让过滤结构求补集。
39.5 PHY:LAN8720A
是公司已被公司收购设计的一个体积小、功耗低、全能型的以太网物理层收发器。它是针对消费类电子和企业应用而设计的。总共只有,仅支持接口。由它组成的网络结构见图。
图 3912 由LAN8720A组成的网络系统结构
通过与连接。是网络插座,在与连接之间还需要一个变压器,所以一般使用带电压转换和指示灯的型号的插座。一般来说,必须为使用接口的提供的时钟源输入到引脚,不过内部集成,可以将的时钟源陪频到并在指定引脚输出该时钟,所以我们可以直接使其与连接达到提供时钟效果。
内部系统结构见图。
图 3913 LAN8720A内部系统结构
有各个不同功能模块组成,最重要的要数接收控制器和发送控制器,其它的基本上都是与外部引脚挂钩,实现信号传输。部分引脚是具有双重功能的,比如与引脚是共用的,在系统上电后会马上读取这部分共用引脚的电平,以确定系统的状态并保存在相关寄存器内,之后则自动转入作为另一功能引脚。
引脚用于配置通信的地址,在芯片内部该引脚已经自带下拉电阻,默认认为即使外部悬空不接,在系统上电时会检测该引脚获取得到的地址为或者,并保存在特殊模式寄存器的位中,该寄存器的有个位,在需要超过个时可以通过软件设置不同通信地址。是与引脚共用。
引脚用于选择网络通信速率和工作模式,可选或通信速度,半双工或全双工工作模式,另外支持自动翻转功能,即可自动识别直连或交叉网线并自适应。一般将引脚都设置为,可以让启动自适应功能,它会自动寻找最优工作方式。与引脚共用、与引脚共用、与引脚共用。
引脚用于接口中信号线,当引脚为低电平是,它也可以被设置成时钟输出,这样可以直接与的引脚连接为其提供时钟源,这种模式要求为与之间或为提供时钟,由内部电路陪频得到时钟,此时引脚的中断功能不可用,用于时钟输出。当引脚为高电平时,被设置为时钟输入,即外部时钟源直接提供时钟接入的引脚和的引脚,此时可用于中断功能。与引脚共用,一般使用下拉
引脚用于配置内部电压源,内部需要电压,可以通过引脚输入电压提供,也可以直接利用内部稳压器提供。当引脚为低电平时选择内部稳压器。与引脚共用。
支持寻址个寄存器,只用到其中个,参考表。
表 393 LAN8720A寄存器列表
寄存器名称
序号与数据帧中的是对应的,这在编写驱动时非常重要,本文将它们标记为。寄存器可规划为三个组:、和。是要求的,是基本控制寄存器,其位为位,向该位写启动软件复位,还包括速度、自适应、低功耗等等功能设置。是基本状态寄存器。是扩展寄存器,包括的号、制造商、版本号等等信息。是供应商自定义寄存器,是特殊控制状态寄存器,指示速度类型和自适应功能。
39.6 LwIP:轻型TCP/IP协议栈
是的缩写,是由瑞士计算机科学院等开发的适用于嵌入式领域的开源轻量级协议栈。它可以移植到含有操作系统的平台中,也可以在无操作系统的平台下运行。由于它开源、占用的和比较少、支持较为完整的协议、且十分便于裁剪、调试,被广泛应用在中低端的位控制器平台。可以访问网站:获取更多信息。
目前,最新更新到版本,我们在上述网站可找到相应的源码下载通道。我们下载两个压缩包:和,包括了的实现代码,包含了不同平台移植的驱动代码和使用实现的一些应用实例测试。
但是,遗憾的是并没有为平台提供实例,这对于初学者想要移植来说难度还是非常大的。公司也是认识到在嵌入式领域的重要性,所以他们针对应用开发了测试平台,其中有一个是在系列控制器运行的文件编号为:,虽然我们的开发板平台是控制器,但经测试发现关于驱动部分以及接口函数部分是可以通用的。为减少移植工作量,我们选择使用官方例程相关文件,特别是底层驱动部分函数,这样我们也可以花更多精力在理解代码实现方法上。
本章的一个重点内容就是介绍移植至我们的开发平台,详细的操作步骤参考下文介绍。
39.7 ETH初始化结构体详解
一般情况下,标准库都会为外设建立一个外设对应的文件存放外设相关库函数的实现,比如、等等,然而标准库并没有为外设建立相关的文件,这样我们根本没有标准库函数可以使用,究其原因是驱动函数与芯片连续较为紧密,很难使用一套通用的代码实现兼容。难道要我们自己写寄存器实现?实际情况还没有这么糟糕,正如上文所说的官方有提供方面的测试平台,特别是基于控制器的测试平台是非常合适我们参考的。我们在解压压缩包之后,在其文件目录下可找到、和三个文件,其中的和就是类似是关于外设的驱动,我们在以太网通信实现实验中会使用到这三个文件,和两个文件内容不用修改不过修改了文件名称。
有定义了一个外设初始化结构体,理解结构体成员可以帮助我们使用功能。初始化结构体成员用于设置工作环境参数,并由相应初始化配置函数或功能函数调用,这些设定参数将会设置相应的寄存器,达到配置工作环境的目的。
代码清单 391 ETH_InitTypeDef
1 typedef struct {
* @brief / * MAC
uint32_t ETH_AutoN // 自适应功能
uint32_t ETH_W // 以太网看门狗
uint32_t ETH_J // jabber定时器功能
uint32_t ETH_InterFrameG // 发送帧间间隙
uint32_t ETH_CarrierS // 载波侦听
uint32_t ETH_S // 以太网速度
uint32_t ETH_ReceiveO // 接收自身
uint32_t ETH_LoopbackM // 回送模式
uint32_t ETH_M // 模式
uint32_t ETH_ChecksumO // 校验和减荷
uint32_t ETH_RetryT // 传输重试
uint32_t ETH_AutomaticPadCRCS // 自动去除PAD和FCS字段
uint32_t ETH_BackOffL // 后退限制
uint32_t ETH_DeferralC // 检查延迟
uint32_t ETH_ReceiveA // 接收所有MAC帧
uint32_t ETH_SourceAddrF // 源地址过滤
uint32_t ETH_PassControlF // 传送控制帧
uint32_t ETH_BroadcastFramesR // 广播帧接收
uint32_t ETH_DestinationAddrF // 目标地址过滤
uint32_t ETH_PromiscuousM // 混合模式
uint32_t ETH_MulticastFramesF // 多播源地址过滤
uint32_t ETH_UnicastFramesF // 单播源地址过滤
uint32_t ETH_HashTableH // 散列表高位
uint32_t ETH_HashTableL // 散列表低位
uint32_t ETH_PauseT // 暂停时间
uint32_t ETH_ZeroQuantaP // 零时间片暂停
uint32_t ETH_PauseLowT // 暂停阈值下限
uint32_t ETH_UnicastPauseFrameD // 单播暂停帧检测
uint32_t ETH_ReceiveFlowC // 接收流控制
uint32_t ETH_TransmitFlowC // 发送流控制
uint32_t ETH_VLANTagC // VLAN标记比较
uint32_t ETH_VLANTagI // VLAN标记标识符
* @brief / * DMA
uint32_t ETH_DropTCPIPChecksumErrorF // 丢弃TCP/IP校验错误帧
uint32_t ETH_ReceiveStoreF // 接收存储并转发
uint32_t ETH_FlushReceivedF // 刷新接收帧
uint32_t ETH_TransmitStoreF // 发送存储并并转发
uint32_t ETH_TransmitThresholdC // 发送阈值控制
uint32_t ETH_ForwardErrorF // 转发错误帧
uint32_t ETH_ForwardUndersizedGoodF // 转发过小的好帧
uint32_t ETH_ReceiveThresholdC // 接收阈值控制
uint32_t ETH_SecondFrameO // 处理第二个帧
uint32_t ETH_AddressAlignedB // 地址对齐节拍
uint32_t ETH_FixedB // 固定突发
uint32_t ETH_RxDMABurstL // DMA突发接收长度
uint32_t ETH_TxDMABurstL // DMA突发发送长度
uint32_t ETH_DescriptorSkipL // 描述符跳过长度
uint32_t ETH_DMAA // DMA仲裁
55 } ETH_InitTypeD
?&&&&:自适应功能选择,可选使能或禁止,一般选择使能自适应功能,系统会自动寻找最优工作方式,包括选择或者的以太网速度以及全双工模式或半双工模式。
?&&&&:以太网看门狗功能选择,可选使能或禁止,它设定以太网配置寄存器的位的值。如果设置为,使能看门狗,在接收帧超过字节时自动切断后面数据,一般选择使能看门狗。如果设置为,禁用看门狗,最长可接收字节的帧。
?&&&&:定时器功能选择,可选使能或禁止,与看门狗功能类似,只是看门狗用于接收帧,定时器用于发送帧,它设定寄存器的位的值。如果设置为,使能定时器,在发送帧超过字节时自动切断后面数据,一般选择使能定时器。
?&&&&:控制发送帧间的最小间隙,可选时间、时间、、时间,他设定寄存器的位的值,一般设置时间。
?&&&&:载波侦听功能选择,可选使能或禁止,它设定寄存器的位的值。当被设置为低电平时,发送器会生成载波侦听错误,一般使能载波侦听功能。
?&&&&:以太网速度选择,可选或,它设定寄存器的位的值,一般设置,但在使能自适应功能之后该位设置无效。
?&&&&:接收自身帧功能选择,可选使能或禁止,它设定寄存器的位的值,当设置为时,接收发送时提供的所有包,如果设置为,禁止在半双工模式下接收帧。一般使能接收。
?&&&&:回送模式选择,可选使能或禁止,它设定寄存器的位的值,当设置为时,使能在回送模式下工作。
?&&&&:以太网工作模式选择,可选全双工模式或半双工模式,它设定寄存器位的值。一般选择全双工模式,在使能了自适应功能后该成员设置无效。
?&&&&:校验和减荷功能选择,可选使能或禁止,它设定寄存器位的值,当该位被置时使能接收的帧有效载荷的标头的校验和检查。一般选择禁用,此时和状态位总是为。
?&&&&:传输重试功能,可选使能或禁止,它设定寄存器位的值,当被设置为时,仅尝试发送一次,设置为时,会尝试根据的设置进行重试。一般选择使能重试。
?&&&&:自动去除和字段功能,可选使能或禁用,它设定寄存器位的值。当设置为时,在长度字段值小于或等于自己是去除传入帧上的和字段。一般禁止自动去除和字段功能。
?&&&&:后退限制,在发送冲突后重新安排发送的延迟时间,可选、、、,它设定寄存器位的值。一般设置为。
?&&&&:检查延迟,可选使能或禁止,它设定寄存器位的值,当设置为时,禁止延迟检查功能,发送延迟,直到信号变成无效信号。
?&&&&:接收所有帧,可选使能或禁用,它设定以太网帧过滤寄存器位的值。当设置为时,接收器将所有接收的帧传送到应用程序,不过滤地址。当设置为是,接收会自动过滤不与匹配的帧。一般选择不接收所有。
?&&&&:源地址过滤,可选源地址过滤、源地址反向过滤或禁用源地址过滤,它设定寄存器位和位的值。一般选择禁用源地址过滤。
?&&&&:传送控制帧,控制所有控制帧的转发,可选阻止所有控制帧到达应用程序、转发所有控制帧、转发通过地址过滤的控制帧,它设定寄存器位的值。一般选择禁止转发控制帧。
?&&&&:广播帧接收,可选使能或禁止,它设定寄存器位的值。当设置为时,使能广播帧接收,一般设置接收广播帧。
?&&&&:目标地址过滤功能选择,可选正常过滤或目标地址反向过滤,它设定寄存器位的值。一般设置为正常过滤。
?&&&&:混合模式,可选使能或禁用,它设定寄存器位的值。当设置为时,不论目标或源地址,地址过滤器都传送所有传入的帧。一般禁用混合模式。
?&&&&:多播源地址过滤,可选完美散列表过滤、散列表过滤、完美过滤或禁用过滤,它设定寄存器位、位和位的值。一般选择完美过滤。
?&&&&:单播源地址过滤,可选完美散列表过滤、散列表过滤或完美过滤,它设定寄存器位和位的值。一般选择完美过滤。
?&&&&:散列表高位,和组成位散列表用于组地址过滤,它设定以太网散列表高位寄存器的值。
?&&&&:散列表低位,和组成位散列表用于组地址过滤,它设定以太网散列表低位寄存器的值。
?&&&&:暂停时间,保留发送控制帧中暂停时间字段要使用的值,可设置至,它设定以太网流控制寄存器位的值。
?&&&&:零时间片暂停,可选使用或禁止,它设定寄存器位的值。当设置为时,当来自层的流控制信号去断言后,此位会禁止自动生成零时间片暂停控制帧。一般选择禁止。
?&&&&:暂停阈值下限,配置暂停定时器的阈值,达到该值值时,会自动程序传输暂停帧,可选暂停时间减去个间隙、个间隙、个间隙或个间隙,它设定寄存器位的值。一般选择暂停时间减去个间隙。
?&&&&:单播暂停帧检测,可选使能或禁止,它设定寄存器位的值。当设置为时,除了检测具有唯一多播地址的暂停帧外,还会检测具有和寄存器所指定的站单播地址的暂停帧。一般设置为禁止。
?&&&&:接收流控制,可选使能或禁止,它设定寄存器位的值。当设定为时,对接收到的暂停帧进行解码,并禁止其在指定时间(暂停时间)内发送;当设置为时,将禁止暂停帧的解码功能,一般设置为禁止。
?&&&&:发送流控制,可选使能或禁止,它设定寄存器位的值。在全双工模式下,当设置为时,将使能流控制操作来发送暂停帧;为时,将禁止中的流控制操作,不会传送任何暂停帧。在半双工模式下,当设置为时,将使能背压操作;为时,将禁止背压功能。
?&&&&:标记比较,可选位或位,它设定以太网标记寄存器位的值。当设置为时,使用位标识符而不是完整的位标记进行比较和过滤;为时,使用全部位进行比较,一般选择位。
?&&&&:标记标识符,包含用于标识帧的标记,并与正在接收的帧的第十五和第十六字节进行比较。位是用户优先级,位是标准格式指示符,位是标记的标识符字段。位置时,仅使用(位)进行比较。
?&&&&:丢弃校验错误帧,可选使能或禁止,它设定以太网工作模式寄存器位的值,当设置为时,如果帧中仅存在由接收校验和减荷引擎检测出来的错误,则内核不会丢弃它;为时,如果为进行了复位,则会丢弃所有错误帧。
?&&&&:接收存储并转发,可选使能或禁止,它设定以太网工作模式寄存器位的值,当设置为时,向写入完整帧后可以从中读取一帧,同时忽略接收阈值控制位;当设置为时,在直通模式下工作,取决于位的阈值。一般选择使能。
?&&&&:刷新接收帧,可选使能或禁止,它设定寄存器位的值,当设置为时,发送控制器逻辑会恢复到缺省值,中的所有数据均会丢失刷新,刷新结束后改为自动清零。
?&&&&:发送存储并并转发,可选使能或禁止,它设定寄存器位的值,当设置为时,如果有一个完整的帧则发送会启动,会忽略值;为时,值才会有效。一般选择使能。
?&&&&:发送阈值控制,有多个阈值可选,它设定寄存器位的值,当中帧大小大于该阈值时发送会自动,对于小于阈值的全帧也会发送。
?&&&&:转发错误帧,可选使能或禁止,它设定寄存器位的值,当设置为时,除了段错误帧之外所有帧都会转发到;为时,会丢弃滴啊有错误状态的帧。一般选择禁止。
?&&&&:转发过小的好帧,可选使能或禁止,它设定寄存器位的值,当设置为时,会转发包括和字段的过小帧;为时,会丢弃小于字节的帧,除非接收阈值被设置为更低。
?&&&&:接收阈值控制,当中的帧大小大于阈值时启动传输请求,可选字节、字节、字节或字节,它设定寄存器位的值。
?&&&&:处理第二个帧,可选使能或禁止,它设定寄存器位的值,当设置为时会命令处理第二个发送数据帧。
?&&&&:地址对齐节拍,可选使能或禁止,它设定以太网总线模式寄存器位的值,当设置为并且固定突发位也为时,接口会生成与起始地址位对齐的所有突发;如果位为,则第一个突发不对齐,但后续的突发与地址对齐。一般选择使能。
?&&&&:固定突发,控制主接口是否执行固定突发传输,可选使能或禁止,它设定寄存器位的值,当设置为时,在正常突发传输开始期间使用、、或;为时,使用和突发传输操作。
?&&&&:突发接收长度,有多个值可选,一般选择,可实现突发长度,它设定寄存器位和位的值。
?&&&&:突发发送长度,有多个值可选,一般选择,可实现突发长度,它设定寄存器位和位的值。
?&&&&:描述符跳过长度,指定两个未链接描述符之间跳过的字数,地址从当前描述符结束处开始跳到下一个描述符起始处,可选,它设定寄存器位的值。
?&&&&:仲裁,控制和优先级,可选优先级比为、、、或者优先于,它设定寄存器位和位的值,当设置为时,优先于;为时,循环调度,优先级比由位给出。
39.8 以太网通信实验:无操作系统LwIP移植
可以在带操作系统上运行,亦可在无操作系统上运行,这一实验我们讲解在无操作系统的移植步骤,并实现简单的传输代码,后续章节会讲解在带操作系统移植过程,一般都是在无操作系统基础上修改而来的。
39.8.1 硬件设计
在讲解移植步骤之前,有必须先介绍我们的实验硬件设计,主要是通过和接口与控制器连接,见图。
图 3914 PHY硬件设计
电路设计时,将引脚通过下拉电阻拉低,设置为输出时钟,当然前提是在和接入了的时钟源。另外也把引脚通过下拉电阻拉低,使能使用内部稳压器。
39.8.2 移植步骤
之前已经介绍了源代码和官方测试平台资料下载,我们移植步骤是基于这两份资料进行的。
无操作系统移植需要的文件参考图,图中只显示了文件,还需要用到对应的文件。
图 3915 LwIP移植实验文件结构
接下来,我们就根据图中文件结构详解移植过程。实验例程有需要用到系统滴答定时器、调试串口、独立按键、灯功能,对这些功能实现不做具体介绍,可以参考相关章节理解。
第一步:相关文件拷贝
首先,解压和两个压缩包,把整个文件夹拷贝到文件夹下,特别说明,在整个移植过程中,不会对文件下的文件内容进行修改。然后,在文件夹找到文件夹路径:,把整个文件夹拷贝文件夹中,在文件夹下的文件中把和两个文件夹直接剪切到文件夹中,即此时文件夹有三个、和文件夹,最后把文件夹删除,最终的文件结构见图,存放与开发平台相关头文件,文件夹是无操作系统移植时外设与连接的底层驱动函数。
图 3916 LwIP相关文件拷贝
文件夹下的文件夹存放版权、移植、使用等等说明文件,移植之前有必须认真浏览一遍;文件夹存放的实现代码,也是我们工程代码真正需要的文件;文件夹存放部分功能测试例程;另外,还有一些无后缀名的文件,都是一些说明性文件,可用记事本直接打开浏览。文件夹存放与平台连接的相关文件,正如上面所说包含了不同平台移植代码,不过遗憾地是没有平台的,所以我们需要从官方提供的测试平台找到这部分连接代码,也就是文件夹的内容。
接下来,在文件下新建一个文件夹,用于存放与相关驱动文件,包括两个部分文件,其中一个是外设驱动文件,在文件夹中找到和两个文件路径:,将这两个文件拷贝到文件夹中,对应改名为和,这两个文件是驱动文件,类似标准库中外设驱动代码实现文件,在移植过程中我们几乎不过文件的内容。这部分函数由文件夹相关代码调用。另外一部分是相关初始化、外设初始化、状态获取等等函数的实现,在文件夹中找到、和三个文件路径:,将这三个文件拷贝到文件夹中,对应改名为、和。因为,官方测试平台使用的型号不是使用,所以这三个文件需要我们进行修改。
最后,是测试代码实现,为测试移植是否成功和检查功能,我们编写通信实现代码,设置开发板为从机,电脑端为主机。在文件夹中找到、、、和五个文件路径:,直接拷贝到文件夹自己新建中,文件代码实现初始化函数、周期调用函数、功能函数等等,文件实现通信参数代码,包含功能选项。
第二部:为工程添加文件
第一步已经把相关的文件拷贝到对应的文件夹中,接下来就可以把需要用到的文件添加到工程中。图已经指示出来工程需要用到的文件,所以最终工程文件结构见图,图中、和都包含了对应文件夹下的所有文件。
图 3917 工程文件结构
接下来,还需要在工程选择中添加相关头文件路径,参考图。
图 3918 添加相关头文件路径
第三步:文件修改
文件是无操作系统时网络接口函数,该文件在移植是只需修改相关头文件名,函数实现部分无需修改。该文件主要有三个部分函数,一个是,用于初始化相关工作环境、初始化描述符链表,并使能和;一个是,它是最底层发送一帧数据函数;最后一个是,它是最底层接收一帧数据函数。
和两个文件用于驱动函数实现,它是通过直接操作寄存器方式实现,这两个文件我们无需修改。文件包含了一些功能选项的宏定义,我们对部分内容进行了修改。
代码清单 392 stm32f429_eth_conf.h文件宏定义
1 #ifdef USE_Delay
2 #include "Bsp/systick/bsp_SysTick.h"
3 #define _eth_delay_ Delay_10ms
5 #define _eth_delay_ ETH_Delay
8 #ifdef USE_Delay
9 /* LAN8742A Reset delay */
10 #define LAN8742A_RESET_DELAY ((uint32_t)0x)
12 /* LAN8742A Reset delay */
13 #define LAN8742A_RESET_DELAY ((uint32_t)0x00FFFFFF)
16 /* The LAN8742A PHY status register */
17 /* PHY status register Offset */
18 #define PHY_SR ((uint16_t)0x001F)
19 /* PHY Speed mask 1:10Mb/s 0:100Mb/s*/
20 #define PHY_SPEED_STATUS ((uint16_t)0x0004)
21 /* PHY Duplex mask 1:Full duplex 0:Half duplex*/
22 #define PHY_DUPLEX_STATUS ((uint16_t)0x0010)
通过宏定义可选是否使用自定义的延时函数,函数是通过系统滴答定时器实现的延时函数,函数是驱动自带的简单循环延时函数,延时函数实现方法不同,对形参要求不同。因为官方例程是基于型号的,而开发板的型号是。复位时需要一段延时时间,这里需要定义延时时间长度,大约。驱动代码中需要获取的速度和工作模式,的是特殊控制状态寄存器,包括指示以太网速度和工作模式的状态位。
和两个文件是外设相关的底层配置,包括接口初始化、接口初始化、控制器工作环境配置,还有一些的状态获取和控制修改函数。官方例程文件包含了中断引脚的相关配置,主要用于指示接收到以太网帧,我们这里不需要使用,采用无限轮询方法检测接收状态。文件存放相关宏定义,包含和引脚信息等宏定义,其中要特别说明的有一个宏,定义了地址:,这里根据硬件设计设置为,这在通信是非常重要的。
代码清单 393 ETH_GPIO_Config函数
1 void ETH_GPIO_Config(void)
GPIO_InitTypeDef GPIO_InitS
/* Enable GPIOs clocks */
RCC_AHB1PeriphClockCmd(ETH_MDIO_GPIO_CLK | ETH_MDC_GPIO_CLK |
ETH_RMII_REF_CLK_GPIO_CLK|ETH_RMII_CRS_DV_GPIO_CLK|
ETH_RMII_RXD0_GPIO_CLK | ETH_RMII_RXD1_GPIO_CLK |
ETH_RMII_TX_EN_GPIO_CLK | ETH_RMII_TXD0_GPIO_CLK |
ETH_RMII_TXD1_GPIO_CLK | ETH_NRST_GPIO_CLK, ENABLE);
/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* MII/RMII Media interface selection ------------------------------*/
16 #ifdef MII_MODE /* Mode MII with STM324xx-EVAL */
17 #ifdef PHY_CLOCK_MCO
/* Output HSE clock (25MHz) on MCO pin (PA8) to clock the PHY */
RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1);
20 #endif /* PHY_CLOCK_MCO */
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);
23 #elif defined RMII_MODE /* Mode RMII with STM324xx-EVAL */
SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
/* Ethernet pins configuration *************************************/
ETH_MDIO -------------------------& PA2
ETH_MDC --------------------------& PC1
ETH_MII_RX_CLK/ETH_RMII_REF_CLK---& PA1
ETH_MII_RX_DV/ETH_RMII_CRS_DV ----& PA7
ETH_MII_RXD0/ETH_RMII_RXD0 -------& PC4
ETH_MII_RXD1/ETH_RMII_RXD1 -------& PC5
ETH_MII_TX_EN/ETH_RMII_TX_EN -----& PB11
ETH_MII_TXD0/ETH_RMII_TXD0 -------& PG13
ETH_MII_TXD1/ETH_RMII_TXD1 -------& PG14
ETH_NRST -------------------------& PI1
GPIO_InitStructure.GPIO_Pin = ETH_NRST_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(ETH_NRST_PORT, &GPIO_InitStructure);
ETH_NRST_PIN_LOW();
_eth_delay_(LAN8742A_RESET_DELAY);
ETH_NRST_PIN_HIGH();
_eth_delay_(LAN8742A_RESET_DELAY);
/* Configure ETH_MDIO */
GPIO_InitStructure.GPIO_Pin = ETH_MDIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(ETH_MDIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(ETH_MDIO_PORT, ETH_MDIO_SOURCE, ETH_MDIO_AF);
/* Configure ETH_MDC */
GPIO_InitStructure.GPIO_Pin = ETH_MDC_PIN;
GPIO_Init(ETH_MDC_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(ETH_MDC_PORT, ETH_MDC_SOURCE, ETH_MDC_AF);
/**************************************/
/** 省略部分引脚初始化 ***/
/**************************************/
/* Configure ETH_RMII_TXD1 */
GPIO_InitStructure.GPIO_Pin = ETH_RMII_TXD1_PIN;
GPIO_Init(ETH_RMII_TXD1_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(ETH_RMII_TXD1_PORT, ETH_RMII_TXD1_SOURCE,
ETH_RMII_TXD1_AF);
控制器支持和接口,通过程序控制使用接口,同时需要使能时钟,函数后部分就是接口初始化实现,这里我们还连接了的复位引脚,通过拉低一段时间让芯片硬件复位。
代码清单 394 ETH_MACDMA_Config函数
1 static void ETH_MACDMA_Config(void)
/* Enable ETHERNET clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC |
RCC_AHB1Periph_ETH_MAC_Tx|RCC_AHB1Periph_ETH_MAC_Rx,ENABLE);
/* Reset ETHERNET on AHB Bus */
ETH_DeInit();
/* Software reset */
ETH_SoftwareReset();
/* Wait for software reset */
while (ETH_GetSoftwareResetStatus() == SET);
/* ETHERNET Configuration ------------------------------*/
/* 缺省配置ETH_InitStructure */
ETH_StructInit(&ETH_InitStructure);
/* Fill ETH_InitStructure parametrs */
/*-------------------- MAC ----------------------------*/
/* 开启网络自适应功能,速度和工作模式无需配置 */
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_E
22 // ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_D
23 // ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
24 // ETH_InitStructure.ETH_Mode = ETH_Mode_FullD
/* 关闭反馈 */
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_D
/* 关闭重传功能 */
ETH_InitStructure.ETH_RetryTransmission=ETH_RetryTransmission_D
/* 关闭自动去除PDA/CRC功能 */
ETH_InitStructure.ETH_AutomaticPadCRCStrip =
ETH_AutomaticPadCRCStrip_D
/* 关闭接收所有的帧 */
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_D
/* 允许接收所有广播帧 */
ETH_InitStructure.ETH_BroadcastFramesReception =
ETH_BroadcastFramesReception_E
/* 关闭混合模式的地址过滤 */
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_D
/* 对于组播地址使用完美地址过滤 */
ETH_InitStructure.ETH_MulticastFramesFilter =
ETH_MulticastFramesFilter_P
/* 对单播地址使用完美地址过滤 */
ETH_InitStructure.ETH_UnicastFramesFilter =
ETH_UnicastFramesFilter_P
45 #ifdef CHECKSUM_BY_HARDWARE
/* 开启ipv4和TCP/UDP/ICMP的帧校验和卸载 */
ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_E
/*------------------------ DMA -------------------------------*/
/*当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储
52 转发模式中要保证整个帧存储在FIFO中, 这样MAC能插入/识别出帧校验
53 值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧*/
/* 开启丢弃TCP/IP错误帧 */
ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame =
ETH_DropTCPIPChecksumErrorFrame_E
/* 开启接收数据的存储转发模式 */
ETH_InitStructure.ETH_ReceiveStoreForward =
ETH_ReceiveStoreForward_E
/* 开启发送数据的存储转发模式 */
ETH_InitStructure.ETH_TransmitStoreForward =
ETH_TransmitStoreForward_E
/* 禁止转发错误帧 */
ETH_InitStructure.ETH_ForwardErrorFrames =
ETH_ForwardErrorFrames_D
/* 不转发过小的好帧 */
ETH_InitStructure.ETH_ForwardUndersizedGoodFrames =
ETH_ForwardUndersizedGoodFrames_D
/* 打开处理第二帧功能 */
ETH_InitStructure.ETH_SecondFrameOperate =
ETH_SecondFrameOperate_E
/* 开启DMA传输的地址对齐功能 */
ETH_InitStructure.ETH_AddressAlignedBeats =
ETH_AddressAlignedBeats_E
/* 开启固定突发功能 */
ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_E
/* DMA发送的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32B
/*DMA接收的最大突发长度为32个节拍 */
ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32B
ETH_InitStructure.ETH_DMAArbitration =
ETH_DMAArbitration_RoundRobin_RxTx_2_1;
/* 配置ETH */
EthStatus = ETH_Init(&ETH_InitStructure, ETHERNET_PHY_ADDRESS);
首先是使能时钟,复位配置。函数用于初始化结构体变量,会给每个成员赋予缺省值。接下来就是根据需要配置结构体变量,关于结构体各个成员意义已在"初始化结构体详解"作了分析。最后调用函数完成配置,函数有两个形参,一个是结构体变量指针,第二个是地址,函数还有一个返回值,用于指示初始化配置是否成功。
代码清单 395 ETH_BSP_Config函数
1 #define GET_PHY_LINK_STATUS()
2 (ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS,PHY_BSR)&0x)
4 void ETH_BSP_Config(void)
/* Configure the GPIO ports for ethernet pins */
ETH_GPIO_Config();
/* Configure the Ethernet MAC/DMA */
ETH_MACDMA_Config();
/* Get Ethernet link status*/
if (GET_PHY_LINK_STATUS()) {
EthStatus |= ETH_LINK_FLAG;
是定义获取链路状态的宏,如果连接正常那么整个宏定义为,如果不正常则为,它是通过函数读取的基本状态寄存器并检测其位得到的。
函数分别调用和函数完成初始化配置,最后调用来判断状态,并保存在变量中。函数一般在函数中优先函数调用。
代码清单 396 ETH_CheckLinkStatus函数
1 void ETH_CheckLinkStatus(uint16_t PHYAddress)
static uint8_t status = 0;
uint32_t t = GET_PHY_LINK_STATUS();
/* If we have link and previous check was not yet */
if (t && !status) {
/* Set link up */
netif_set_link_up(&gnetif);
status = 1;
/* If we don't have link and it was on previous check */
if (!t && status) {
EthLinkStatus = 1;
/* Set link down */
netif_set_link_down(&gnetif);
status = 0;
函数用于获取状态,实际上也是通过宏定义获取得到的,函数还根据状态通知当前链路状态,是一个结构体类型变量,定义了结构体类型,用于指示某一网卡相关信息,是支持多个网卡设备,使用时需要为每个网卡设备定义一个类型变量。无操作系统时函数被无限循环调用。
代码清单 397 ETH_link_callback函数
1 void ETH_link_callback(struct netif *netif)
__IO uint32_t timeout = 0;
uint16_t RegV
struct ip_
struct ip_
struct ip_
if (netif_is_link_up(netif)) {
/* Restart the auto-negotiation */
if (ETH_InitStructure.ETH_AutoNegotiation !=
ETH_AutoNegotiation_Disable) {
/* Reset Timeout counter */
timeout = 0;
/* Enable auto-negotiation */
ETH_WritePHYRegister(ETHERNET_PHY_ADDRESS, PHY_BCR,
PHY_AutoNegotiation);
/* Wait until the auto-negotiation will be completed */
timeout++;
} while (!(ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_BSR)
&PHY_AutoNego_Complete)&&(timeout&(uint32_t)PHY_READ_TO));
/* Reset Timeout counter */
timeout = 0;
/* Read the result of the auto-negotiation */
RegValue = ETH_ReadPHYRegister(ETHERNET_PHY_ADDRESS, PHY_SR);
if ((RegValue & PHY_DUPLEX_STATUS) != (uint16_t)RESET) {
ETH_InitStructure.ETH_Mode = ETH_Mode_FullD
ETH_InitStructure.ETH_Mode = ETH_Mode_HalfD
if (RegValue & PHY_SPEED_STATUS) {
/* Set Ethernet speed to 10M following the auto-negotiation */
ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
/* Set Ethernet speed to 100M following the auto-negotiation */
ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
/*------------ ETHERNET MACCR Re-Configuration -------------*/
/* Get the ETHERNET MACCR value */
tmpreg = ETH-&MACCR;
/* Set the FES bit according to ETH_Speed value */
/* Set the DM bit according to ETH_Mode value */
tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Speed |
ETH_InitStructure.ETH_Mode);
/* Write to ETHERNET MACCR */
ETH-&MACCR = (uint32_t)
_eth_delay_(ETH_REG_WRITE_DELAY);
tmpreg = ETH-&MACCR;
ETH-&MACCR =
/* Restart MAC interface */
ETH_Start();
63 #ifdef USE_DHCP
ipaddr.addr = 0;
netmask.addr = 0;
gw.addr = 0;
DHCP_state = DHCP_START;
IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 ,
NETMASK_ADDR2, NETMASK_ADDR3);
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
73 #endif /* USE_DHCP */
netif_set_addr(&gnetif, &ipaddr , &netmask, &gw);
/* When the netif is fully configured this function must be called.*/
netif_set_up(&gnetif);
EthLinkStatus = 0;
ETH_Stop();
83 #ifdef USE_DHCP
DHCP_state = DHCP_LINK_DOWN;
dhcp_stop(netif);
86 #endif /* USE_DHCP */
/* When the netif link is down this function must be called.*/
netif_set_down(&gnetif);
函数被调用,当链路状态发送改变时该函数就被调用,用于状态改变后处理相关事务。首先调用函数判断新状态是否是链路启动状态,如果是启动状态就进入语句,接下来会判断是否被设置为自适应模式,如果不是自适应模式需要使用函数使能工作为自适应模式,然后函数读取相关寄存器,获取当前支持的以太网速度和工作模式,并保存到结构体变量中。函数用于使能外设,之后就是配置的地址、子网掩码、网关,如果是定义了动态主机配置协议功能则启动。最后就是调用函数在层次配置启动功能。
如果检测到是链路关闭状态,调用函数关闭,如果定义了功能则需关闭,最后调用函数在层次关闭功能。
以上对文件修改部分更多涉及到硬件底层驱动,一些是芯片驱动函数、一些是外设与连接函数。接下来要讲解的文件代码更多是与应用相关的。
和文件用于存放配置相关代码。定义了相关宏。
代码清单 398 LwIP配置相关宏定义
1 /* DHCP状态 */
2 #define DHCP_START 1
3 #define DHCP_WAIT_ADDRESS 2
4 #define DHCP_ADDRESS_ASSIGNED 3
5 #define DHCP_TIMEOUT 4
6 #define DHCP_LINK_DOWN 5
8 //#define USE_DHCP /* enable DHCP, if disabled static address is used */
10 /* 调试信息输出 */
11 #define SERIAL_DEBUG
12 /* 远端IP地址和端口 */
13 #define DEST_IP_ADDR0 192
14 #define DEST_IP_ADDR1 168
15 #define DEST_IP_ADDR2 1
16 #define DEST_IP_ADDR3 105
17 #define DEST_PORT 6000
19 /* MAC地址:网卡地址 */
20 #define MAC_ADDR0 2
21 #define MAC_ADDR1 0
22 #define MAC_ADDR2 0
23 #define MAC_ADDR3 0
24 #define MAC_ADDR4 0
25 #define MAC_ADDR5 0
27 /*静态IP地址 */
28 #define IP_ADDR0 192
29 #define IP_ADDR1 168
30 #define IP_ADDR2 1
31 #define IP_ADDR3 122
33 /* 子网掩码 */
34 #define NETMASK_ADDR0 255
35 #define NETMASK_ADDR1 255
36 #define NETMASK_ADDR2 255
37 #define NETMASK_ADDR3 0
39 /* 网关 */
40 #define GW_ADDR0 192
41 #define GW_ADDR1 168
42 #define GW_ADDR2 1
43 #define GW_ADDR3 1
45 /* 检测PHY链路状态的实际间隔(单位:ms) */
46 #ifndef LINK_TIMER_INTERVAL
47 #define LINK_TIMER_INTERVAL 1000
50 /* MII and RMII mode selection ***********/
51 #define RMII_MODE
52 //#define MII_MODE
54 /* 在MII模式时,使能MCO引脚输出25MHz脉冲 */
55 #ifdef MII_MODE
56 #define PHY_CLOCK_MCO
宏用于定义是否使用功能,如果不定义该宏,直接使用静态的地址,如果定义该宏,则使用功能,获取动态的地址,这里有个需要注意的地方,电脑是没办法提供服务功能的,路由器才有服务功能,使用当开发板直连电脑时不能定义该宏。
宏是定义是否使能串口定义相关调试信息功能,一般选择使能,所以在函数中需要添加串口初始化函数。
接下来,定义了远端和端口、地址、静态地址、子网掩码、网关相关宏,可以根据实际情况修改。
仅支持接口,根据硬件设计这里定义使用。
代码清单 399 LwIP_Init函数
1 void LwIP_Init(void)
struct ip_
struct ip_
struct ip_
/* Initializes the dynamic memory heap defined by MEM_SIZE.*/
mem_init();
/* Initializes the memory pools defined by MEMP_NUM_x.*/
memp_init();
12 #ifdef USE_DHCP
ipaddr.addr = 0;
netmask.addr = 0;
gw.addr = 0;
IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 ,
NETMASK_ADDR2,NETMASK_ADDR3);
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
/* 添加以太网设备 */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL,
&ethernetif_init, &ethernet_input);
/* 设置以太网设备为默认网卡 */
netif_set_default(&gnetif);
if (EthStatus == (ETH_INIT_FLAG | ETH_LINK_FLAG)) {
gnetif.flags |= NETIF_FLAG_LINK_UP;
/* 配置完成网卡后启动网卡*/
netif_set_up(&gnetif);
33 #ifdef USE_DHCP
DHCP_state = DHCP_START;
36 #ifdef SERIAL_DEBUG
printf("\n Static IP address \n");
printf("IP: %d.%d.%d.%d\n",IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3);
printf("NETMASK: %d.%d.%d.%d\n",NETMASK_ADDR0,NETMASK_ADDR1,
NETMASK_ADDR2,NETMASK_ADDR3);
printf("Gateway:%d.%d.%d.%d\n",GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3);
42 #endif /* SERIAL_DEBUG */
43 #endif /* USE_DHCP */
/* 当网络链路关闭时关闭网卡设备 */
netif_set_down(&gnetif);
47 #ifdef USE_DHCP
DHCP_state = DHCP_LINK_DOWN;
49 #endif /* USE_DHCP */
50 #ifdef SERIAL_DEBUG
printf("\n Network Cable is \n");
printf(" not connected \n");
53 #endif /* SERIAL_DEBUG */
/* 设置链路回调函数,用于获取链路状态 */
netif_set_link_callback(&gnetif, ETH_link_callback);
函数用于初始化协议栈,一般在函数中调用。首先是内存相关初始化,函数是动态内存堆初始化,函数是存储池初始化,是实现内存的高效利用,内部需要不同形式的内存管理模式。
接下来为、和结构体变量赋值,设置本地地址、子网掩码和网关,如果使用功能直接赋值为即可。是以太网设备添加函数,即向协议栈申请添加一个网卡设备,函数有个形参,第一个为结构体类型变量指针,这里赋值为地址,该网卡设备属性就存放在变量中;第二个为结构体类型变量指针,用于设置网卡地址;第三个结构体类型变量指针,用于设置子网掩码;第四个为结构体类型变量指针,用于设置网关;第五个为变量,用户自定义字段,一般不用直接赋值;第六个为类型函数指针,用于指向网卡设备初始化函数,这里赋值为指向函数,该函数在文件定义,初始化与外设连接函数;最后一个参数为类型函数指针,用于指向以太网帧接收函数,这里赋值为指向函数,该函数定义在文件中。
函数用于设置指定网卡为默认的网络通信设备。
在无硬件连接错误时,调用优先函数被调用时会将变量对应的位使能,所以在函数中会执行判断语句代码,置位网卡设备标志位以及运行函数启动网卡设备。否则执行函数停止网卡设备。
最后,根据需要调用函数实在当链路状态发生改变时需要调用的回调函数配置。
代码清单 3910 LwIP_Pkt_Handle函数
1 void LwIP_Pkt_Handle(void)
/* 从以太网存储器读取一个以太网帧并将其发送给LwIP */
ethernetif_input(&gnetif);
函数用于从以太网存储器读取一个以太网帧并将其发送给,它在接收到以太网帧时被调用,它是直接调用函数实现的,该函数定义在文件中。
代码清单 3911 LwIP_Periodic_Handle函数
1 void LwIP_Periodic_Handle(__IO uint32_t localtime)
3 #if LWIP_TCP
/* TCP periodic process every 250 ms */
if (localtime - TCPTimer &= TCP_TMR_INTERVAL) {
TCPTimer =
tcp_tmr();
/* ARP periodic process every 5s */
if ((localtime - ARPTimer) &= ARP_TMR_INTERVAL) {
ARPTimer =
etharp_tmr();
/* Check link status periodically */
if ((localtime - LinkTimer) &= LINK_TIMER_INTERVAL) {
ETH_CheckLinkStatus(ETHERNET_PHY_ADDRESS);
LinkTimer=
23 #ifdef USE_DHCP
/* Fine DHCP periodic process every 500ms */
if (localtime - DHCPfineTimer &= DHCP_FINE_TIMER_MSECS) {
DHCPfineTimer =
dhcp_fine_tmr();
if ((DHCP_state != DHCP_ADDRESS_ASSIGNED) &&
(DHCP_state != DHCP_TIMEOUT) &&
(DHCP_state != DHCP_LINK_DOWN)) {
31 #ifdef SERIAL_DEBUG
LED1_TOGGLE;
printf("\nFine DHCP periodic process every 500ms\n");
34 #endif /* SERIAL_DEBUG */
/* process DHCP state machine */
LwIP_DHCP_Process_Handle();
/* DHCP Coarse periodic process every 60s */
if (localtime - DHCPcoarseTimer &= DHCP_COARSE_TIMER_MSECS) {
DHCPcoarseTimer =
dhcp_coarse_tmr();
函数是一个必须被无限循环调用的支持函数,一般在函数的无限循环中调用,主要功能是为各个模块提供时间并查询链路状态,该函数有一个形参,用于指示当前时间,单位为。
对于功能,每执行一次函数;对于地址解析协议,每执行一次函数;对于链路状态检测,每执行一次函数;对于功能,每执行一次函数,如果处于或状态就执行函数,对于功能,还有每执行一次函数。
代码清单 3912 LwIP_DHCP_Process_Handle函数
1 void LwIP_DHCP_Process_Handle(void)
struct ip_
struct ip_
struct ip_
switch (DHCP_state) {
case DHCP_START: {
DHCP_state = DHCP_WAIT_ADDRESS;
dhcp_start(&gnetif);
/* IP address should be set to 0
every time we want to assign a new DHCP address */
IPaddress = 0;
14 #ifdef SERIAL_DEBUG
printf("\n Looking for \n");
printf(" DHCP server \n");
printf(" please wait... \n");
18 #endif /* SERIAL_DEBUG */
case DHCP_WAIT_ADDRESS: {
/* Read the new IP address */
IPaddress = gnetif.ip_addr.
if (IPaddress!=0) {
DHCP_state = DHCP_ADDRESS_ASSIGNED;
/* Stop DHCP */
dhcp_stop(&gnetif);
30 #ifdef SERIAL_DEBUG
printf("\n IP address assigned \n");
printf(" by a DHCP server \n");
printf("IP: %d.%d.%d.%d\n",(uint8_t)(IPaddress),
(uint8_t)(IPaddress && 8),(uint8_t)(IPaddress && 16),
(uint8_t)(IPaddress && 24));
printf("NETMASK: %d.%d.%d.%d\n",NETMASK_ADDR0,NETMASK_ADDR1,
NETMASK_ADDR2,NETMASK_ADDR3);
printf("Gateway: %d.%d.%d.%d\n",GW_ADDR0,GW_ADDR1,
GW_ADDR2,GW_ADDR3);
41 #endif /* SERIAL_DEBUG */
/* DHCP timeout */
if (gnetif.dhcp-&tries & MAX_DHCP_TRIES) {
DHCP_state = DHCP_TIMEOUT;
/* Stop DHCP */
dhcp_stop(&gnetif);
/* Static address used */
IP4_ADDR(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1,
NETMASK_ADDR2, NETMASK_ADDR3);
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
netif_set_addr(&gnetif, &ipaddr , &netmask, &gw);
54 #ifdef SERIAL_DEBUG
printf("\n DHCP timeout \n");
printf(" Static IP address \n");
printf("IP: %d.%d.%d.%d\n",IP_ADDR0,IP_ADDR1,
IP_ADDR2,IP_ADDR3);
printf("NETMASK: %d.%d.%d.%d\n",NETMASK_ADDR0,NETMASK_ADDR1,
NETMASK_ADDR2,NETMASK_ADDR3);
printf("Gateway: %d.%d.%d.%d\n",GW_ADDR0,GW_ADDR1,
GW_ADDR2,GW_ADDR3);
64 #endif /* SERIAL_DEBUG */
函数用于执行功能,当状态为时,执行函数启动功能,会向服务器申请分配请求,并进入等待分配状态。当状态为时,先判断地址是否为,如果不为说明已经有地址,功能已经完成可以停止它;如果地址总是为,就需要判断是否超过最大等待时间,并提示出错。
文件存放一些宏定义,用于剪切功能,比如有无操作系统、内存空间分配、存储池分配、功能、功能、功能选择等等。这里使用与官方例程相同配置即可。
为使用者提供了两种应用程序接口函数来实现协议栈,一种是低水平、基于回调函数的,称为,另外一种是高水平、连续的,称为,又有两种函数结构,一种是,一种是,它与在电脑端使用的标准的结构和原理是非常相似的。
接下来内容我们使用实现一个简单的通信测试,官方有提供相关的例程,我们对其内容稍作调整。代码内容存放在文件中。在各个层次处理过程见图。
图 3919 TCP处理过程
网络接口层的netif-&output和netif-&input是在ethernetif.c文件中实现的,网络层和传输层有LwIP协议栈实现,应用层代码就是用户使用LwIP函数实现网络功能。
代码清单 3913 tcp_echoclient_connect函数
1 void tcp_echoclient_connect(void)
struct ip_addr DestIP
/* create new tcp pcb */
echoclient_pcb = tcp_new();
if (echoclient_pcb != NULL) {
IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1,
DEST_IP_ADDR2, DEST_IP_ADDR3 );
/* connect to destination address/port */
tcp_connect(echoclient_pcb,&DestIPaddr,
DEST_PORT,tcp_echoclient_connected);
/* deallocate the pcb */
memp_free(MEMP_TCP_PCB, echoclient_pcb);
18 #ifdef SERIAL_DEBUG
printf("\n\r can not create tcp pcb");
函数用于创建从设备并启动与服务器连接。函数创建一个新协议控制块,主要是必要的内存申请,返回一个未初始化的协议控制块指针。如果返回值不了就可以使用函数连接到服务器,函数用于从设备连接至指定地址和端口的服务器,它有四个形参,第一个为协议控制块指针,第二个为服务器地址,第三个为服务器端口,第四个为函数指针,当连接正常建立时或连接错误时函数被调用,这里赋值函数名。如果返回值为说明创建协议控制块失败,调用函数释放相关内容。
代码清单 3914 tcp_echoclient_disconnect函数
1 struct echoclient {
enum echoclient_ /* connection status */
struct tcp_pcb * /* pointer on the current tcp_pcb */
struct pbuf *p_ /* pointer on pbuf to be transmitted */
7 void tcp_echoclient_disconnect(void)
/* close connection */
tcp_echoclient_connection_close(echoclient_pcb,echoclient_es);
11 #ifdef SERIAL_DEBUG
printf("\n\r close TCP connection");
是自定义的一个结构体类型,包含了从设备的状态、协议控制块指针和发送数据指针。函数用于断开连接,通过调用函数实现,它有两个形参,一个是协议控制块,一个是类型指针。
代码清单 3915 tcp_echoclient_connected函数
1 static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb,
err_t err)
struct echoclient *es = NULL;
if (err == ERR_OK) {
/* allocate structure es to maintain tcp connection informations */
es = (struct echoclient *)mem_malloc(sizeof(struct echoclient));
echoclient_es=
if (es != NULL) {
es-&state = ES_CONNECTED;
sprintf((char*)data, "sending tcp client message %d",
message_count);
/* allocate pbuf */
es-&p_tx = pbuf_alloc(PBUF_TRANSPORT, strlen((char*)data),
PBUF_POOL);
if (es-&p_tx) {
/* copy data to pbuf */
pbuf_take(es-&p_tx, (char*)data, strlen((char*)data));
/* pass newly allocated es structure as argument to tpcb */
tcp_arg(tpcb, es);
/* initialize LwIP tcp_recv callback function */
tcp_recv(tpcb, tcp_echoclient_recv);
/* initialize LwIP tcp_sent callback function */
tcp_sent(tpcb, tcp_echoclient_sent);
/* initialize LwIP tcp_poll callback function */
tcp_poll(tpcb, tcp_echoclient_poll, 1);
/* send data */
tcp_echoclient_send(tpcb,es);
return ERR_OK;
/* close connection */
tcp_echoclient_connection_close(tpcb, es);
/* return memory allocation error */
return ERR_MEM;
/* close connection */
tcp_echoclient_connection_close(tpcb, es);
函数作为函数设置的回调函数,在建立连接时被调用,这里实现的功能是向服务器发送一段数据。使用函数申请内存空间存放结构体类型数据,并赋值给指针变量。如果内存申请失败调用函数关闭连接;确保内存申请成功后为成员赋值,

我要回帖

更多关于 F(x)=A+Be-2x 的文章

 

随机推荐