当前位置:首页 > 单片机 > 单片机
[导读]0.前言 去年(2013年)的整理了LwIP相关代码,并在STM32上“裸奔”成功。一直没有时间深入整理,在这里借博文整理总结。LwIP的移植过程细节很多,博文也不可能一一详解个别部分只能点到为止。 【本文要点】 【1】

0.前言

去年(2013年)的整理了LwIP相关代码,并在STM32上“裸奔”成功。一直没有时间深入整理,在这里借博文整理总结。LwIP的移植过程细节很多,博文也不可能一一详解个别部分只能点到为止。

【本文要点】

【1】不带操作系统的LwIP移植,LwIP版本为1.4.1。

【2】MCU为STM32F103VE,网卡为ENC28J60。

【3】移植过程重点描述ethernetif.c和LwIP宏配置等。

【4】一个简单的TCP echo例子。

【5】力求简单,没有DHCP功能,甚至没有用到网卡中断。

【代码仓库】

代码仓库位于Bitbucket(要源代码请点击这里)。博文中不能把每个细节描述清楚,更多内容请参考代码仓库中的具体代码。

【硬件说明】

测试平台使用奋斗版,原理图请参考代码仓库中的DOC目录。


【参考博文】

学习嵌入式网络是一个循序渐进的过程,从浅入深从简单到复杂。

【1】ENC28J60学习笔记——学习网卡

【2】STM32NET学习笔记——索引——理解TCPIP协议栈

【3】uIP学习笔记——初次应用协议栈

【4】Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32——更加实用的做法

1.ethernetif.c的相关修改

虽然LwIP移植过程比较复杂,但是只要结合网卡具体功能,耐心修改ethernetif.c即可。ethernetif.c重点实现网卡的三个功能,初始化,发送和接收。

为了更好的配合lwIP,修改了ENC28J60学习笔记中部分驱动函数。(换句话说,想要从0开始移植LwIP必须对操作网卡非常熟悉)

【1】初始化


staticvoid

low_level_init(structnetif*netif)

{

structethernetif*ethernetif=netif->state;

/*setMAChardwareaddresslength*/

netif->hwaddr_len=ETHARP_HWADDR_LEN;

/*setMAChardwareaddress*/

netif->hwaddr[0]='A';

netif->hwaddr[1]='R';

netif->hwaddr[2]='M';

netif->hwaddr[3]='N';

netif->hwaddr[4]='E';

netif->hwaddr[5]='T';

/*maximumtransferunit*/

netif->mtu=1500;

/*devicecapabilities*/

/*don'tsetNETIF_FLAG_ETHARPifthisdeviceisnotanethernetone*/

netif->flags=NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP;

/*Dowhateverelseisneededtoinitializeinterface.*/

enc28j60_init(netif->hwaddr);//【1】

}

【说明】

【1】enc28j60_init(netif->hwaddr); low_level_init中指定了enc28j60中的网卡地址。

【2】发送


staticerr_t

low_level_output(structnetif*netif,structpbuf*p)

{

structethernetif*ethernetif=netif->state;

structpbuf*q;

enc28j60_init_send(p->tot_len);//【1】initiatetransfer();

#ifETH_PAD_SIZE

pbuf_header(p,-ETH_PAD_SIZE);/*dropthepaddingword*/

#endif

for(q=p;q!=NULL;q=q->next){

/*Sendthedatafromthepbuftotheinterface,onepbufata

time.Thesizeofthedataineachpbufiskeptinthe->len

variable.*/

enc28j60_writebuf(q->payload,q->len);//【2】senddatafrom(q->payload,q->len);

}

enc28j60_start_send();//【3】signalthatpacketshouldbesent();

#ifETH_PAD_SIZE

pbuf_header(p,ETH_PAD_SIZE);/*reclaimthepaddingword*/

#endif

LINK_STATS_INC(link.xmit);

returnERR_OK;

}

【说明】

【1】enc28j60_init_send(p->tot_len);初始化发送缓冲区大小,pbuf结构为一个链表,第一个pbuf结构体中的tot_len字段代表整个以太网数据包的大小。

【2】enc28j60_writebuf( q->payload, q->len ); 通过遍历链表把内容填入ENC28J60的缓冲区中。

【3】enc28j60_start_send();启动网卡发送。

【3】接收


staticstructpbuf*

low_level_input(structnetif*netif)

{

structethernetif*ethernetif=netif->state;

structpbuf*p,*q;

u16_tlen;

len=enc28j60_packet_getlen();//【1】

#ifETH_PAD_SIZE

len+=ETH_PAD_SIZE;/*allowroomforEthernetpadding*/

#endif

/*Weallocateapbufchainofpbufsfromthepool.*/

p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL);

if(p!=NULL){

#ifETH_PAD_SIZE

pbuf_header(p,-ETH_PAD_SIZE);/*dropthepaddingword*/

#endif

for(q=p;q!=NULL;q=q->next){

enc28j60_readbuf(q->payload,q->len);//【2】readdatainto(q->payload,q->len);

}

enc28j60_finish_receive();//【3】acknowledgethatpackethasbeenread();

#ifETH_PAD_SIZE

pbuf_header(p,ETH_PAD_SIZE);/*reclaimthepaddingword*/

#endif

LINK_STATS_INC(link.recv);

}else{

enc28j60_finish_receive();//【4】droppacket();

LINK_STATS_INC(link.memerr);

LINK_STATS_INC(link.drop);

}

returnp;

}

【说明】

【1】len = enc28j60_packet_getlen(); 获得网卡中数据包的长度。

【2】enc28j60_readbuf (q->payload, q->len);把网卡中的内容复制到内存池中。

【3】enc28j60_finish_receive();接收完成,移动网卡中缓冲区指针。

【4】应用

【1】LwIP网卡硬件初始化调用ethernetif_init即可,该函数中调用了low_level_init,并指定了网卡输出函数low_level_output。

【2】一旦网卡有数据进入,应立即代用ethernetif_input函数。可以使用中断方法或查询方法。

2.lwipopt.h配置简述

lwip中的配置选项非常的多,了解所有的配置非常不容易。本博文参考STM32官方的两个例子总结得到。


#ifndef__LWIPOPTS_H__

#define__LWIPOPTS_H__

#defineSYS_LIGHTWEIGHT_PROT0

#defineNO_SYS1

#defineNO_SYS_NO_TIMERS1

/*----------Memoryoptions----------*/

/*MEM_ALIGNMENT:shouldbesettothealignmentoftheCPUforwhich

lwIPiscompiled.4bytealignment->defineMEM_ALIGNMENTto4,2

bytealignment->defineMEM_ALIGNMENTto2.*/

#defineMEM_ALIGNMENT4

/*MEM_SIZE:thesizeoftheheapmemory.Iftheapplicationwillsend

a lot of data that needs to be copied, this

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭