LwIP協議移植參考檔案:
- 野火LwIP應用開發實戰指南
- STM32F4 LWIP開發手冊
- lwip網址
- lwip-1.4.1.zip
- contrib-1.4.1.zip
- lwip-2.1.2.zip
- contrib-2.1.0.zip
- STSW-STM32070
LwIP協議棧的移植主要參考ST的官方參考檔案STSW-STM32070的LwIP例程實現。由於ST官方例程使用的版本為LwIP1.4.1,因此本文也實現LwIP1.4.1版本的協議棧移植,移植成功後在比較2.1版本的差異進行升級。移植成功的例程放文末。
一、LwIP的啟動流程
最開始學習LwIP的時候看了下原子和野火的相關影片,大多都是依照著移植好的工程講解的,對於其中的很多函式的使用都不明所以。之後在檢視了官方文件之後,文件中其實有明確的啟動流程。
- LwIP官方文件
文件中的system initialization 中提到了啟動LwIP所需要使用到的相關函式。
lwip_init(): 初始化lwip系統,使用作業系統的話使用tcpip_init() netif_add(struct netif *netif, ...): 向網路卡列表新增網路卡,開發板上的ETH外設+DP83848+RJ45乙太網介面 可以看作一張網路卡 netif_set_default(struct netif *netif) :設定預設的網路連線狀態,初始化程式的時候直接呼叫 netif_set_link_up(struct netif *netif) :設定鏈路的連線狀態,檢測是否插入了網線,可透過配置STM32IO中斷設定(DP83848的LED_LINK引腳觸發) netif_set_up(struct netif *netif) :配置完netif(網路卡)之後呼叫 dhcp_start(struct netif *netif) :啟用DHCP自動分配IP,手動配置netif的IP後可使用該函式 sys_check_timeouts() :系統超時檢測,在while迴圈中呼叫
以上的函式使用流程也是移植lwip協議棧的主要流程。
二、lwip原始檔
lwip檔案的具體說明就不贅述了,可以參考野火LwIP應用開發實戰指南,這裡主要說一下移植需要的檔案。
這裡是lwip1.4.1-core資料夾的檔案,也是移植需要的檔案。
api:socket和netconn程式設計使用的API,裸機RAW不會使用到。
core:lwip協議棧原始檔
include:原始碼相關的標頭檔案
netif:介面檔案
lwip相關的檔案如下,具體的檔案以及標頭檔案配置參考文末的原始碼。
LWIP_ARCH檔案裡面是我們的程式碼與系統核心的介面檔案,比如使用裸機、FreeRTOS、UCOSIII這些,我們就需要編寫相關的檔案,我們現在裸機程式設計使用到的檔案如下。
LWIP_APP資料夾就是存放我們自己編寫的檔案了,比如lwip的初始化程式碼、TCP、UDP等等應用程式碼。
三、使用者編寫的檔案
1、lwip與STM32ETH的介面檔案ethnetif.c
lwip協議棧與開發板唯一互動的外設就是ETH外設,ETH外設主要負責MAC資料鏈路層的資料收發,以及其他底層事務比如硬體幀校驗。
netif.c檔案就是網路卡的抽象,而鏈路層的資料收發需要我們自己實現。
在lwip1.4.1版本中NETIF資料夾中官方的ethnetif.c檔案的模板,底層資料收發函式的實現也主要參考此模板。
當然在ST的例程STSW-STM32070中也有寫好的ethnetif.c檔案可以參考。
這裡參考了原子的程式碼,但是使用的lwip自帶的記憶體分配策略,剛開始移植還是儘量不動lwip的原始碼。
#include "netif/ethernetif.h" #include "dp83848.h" #include "lwip_comm.h" #include "netif/etharp.h" #include "string.h" //由ethernetif_init()呼叫用於初始化硬體 //netif:網路卡結構體指標 //返回值:ERR_OK,正常 // 其他,失敗 static err_t low_level_init(struct netif *netif) { #ifdef CHECKSUM_BY_HARDWARE int i; #endif netif->hwaddr_len = ETHARP_HWADDR_LEN; //設定MAC地址長度,為6個位元組 //初始化MAC地址,設定什麼地址由使用者自己設定,但是不能與網路中其他裝置MAC地址重複 netif->hwaddr[0]=lwipdev.mac[0]; netif->hwaddr[1]=lwipdev.mac[1]; netif->hwaddr[2]=lwipdev.mac[2]; netif->hwaddr[3]=lwipdev.mac[3]; netif->hwaddr[4]=lwipdev.mac[4]; netif->hwaddr[5]=lwipdev.mac[5]; netif->mtu=1500; //最大允許傳輸單元,允許該網路卡廣播和ARP功能 //並且該網路卡允許有硬體鏈路連線 netif->flags = NETIF_FLAG_BROADCAST|NETIF_FLAG_ETHARP|NETIF_FLAG_LINK_UP; ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr); //向STM32F4的MAC地址暫存器中寫入MAC地址 /* Initialize Tx Descriptors list: Chain Mode */ ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB); /* Initialize Rx Descriptors list: Chain Mode */ ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB); #ifdef CHECKSUM_BY_HARDWARE //使用硬體幀校驗 for(i=0;i<ETH_TXBUFNB;i++) //使能TCP,UDP和ICMP的傳送幀校驗,TCP,UDP和ICMP的接收幀校驗在DMA中配置了 { ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull); } #endif ETH_Start(); //開啟MAC和DMA return ERR_OK; } //用於傳送資料包的最底層函式(lwip透過netif->linkoutput指向該函式) //netif:網路卡結構體指標 //p:pbuf資料結構體指標 //返回值:ERR_OK,傳送正常 // ERR_MEM,傳送失敗 static err_t low_level_output(struct netif *netif, struct pbuf *p) { u8 res; struct pbuf *q; int l = 0; u8 *buffer=(u8 *)ETH_GetCurrentTxBuffer(); for(q=p;q!=NULL;q=q->next) { memcpy((u8_t*)&buffer[l], q->payload, q->len); l=l+q->len; } res=ETH_Tx_Packet(l); if(res==ETH_ERROR)return ERR_MEM;//返回錯誤狀態 return ERR_OK; } //用於接收資料包的最底層函式 //neitif:網路卡結構體指標 //返回值:pbuf資料結構體指標 static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p, *q; u16_t len; int l =0; FrameTypeDef frame; u8 *buffer; p = NULL; frame=ETH_Rx_Packet(); len=frame.length;//得到包大小 buffer=(u8 *)frame.buffer;//得到包資料地址 p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL);//pbufs記憶體池分配pbuf if(p!=NULL) { for(q=p;q!=NULL;q=q->next) { memcpy((u8_t*)q->payload,(u8_t*)&buffer[l], q->len); l=l+q->len; } } frame.descriptor->Status=ETH_DMARxDesc_OWN;//設定Rx描述符OWN位,buffer重歸ETH DMA if((ETH->DMASRÐ_DMASR_RBUS)!=(u32)RESET)//當Rx Buffer不可用位(RBUS)被設定的時候,重置它.恢復傳輸 { ETH->DMASR=ETH_DMASR_RBUS;//重置ETH DMA RBUS位 ETH->DMARPDR=0;//恢復DMA接收 } return p; } //網路卡接收資料(lwip直接呼叫) //netif:網路卡結構體指標 //返回值:ERR_OK,傳送正常 //ERR_MEM,傳送失敗 err_t ethernetif_input(struct netif *netif) { err_t err; struct pbuf *p; p=low_level_input(netif); if(p==NULL) return ERR_MEM; err=netif->input(p, netif); if(err!=ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG,("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } return err; } //使用low_level_init()函式來初始化網路 //netif:網路卡結構體指標 //返回值:ERR_OK,正常 // 其他,失敗 err_t ethernetif_init(struct netif *netif) { LWIP_ASSERT("netif!=NULL",(netif!=NULL)); #if LWIP_NETIF_HOSTNAME //LWIP_NETIF_HOSTNAME netif->hostname="lwip"; //初始化名稱 #endif netif->name[0]=IFNAME0; //初始化變數netif的name欄位 netif->name[1]=IFNAME1; //在檔案外定義這裡不用關心具體值 netif->output=etharp_output;//IP層傳送資料包函式 netif->linkoutput=low_level_output;//ARP模組傳送資料包函式 low_level_init(netif); //底層硬體初始化函式 return ERR_OK; }
2、lwipopts.h檔案
lwipopts.h檔案是lwip配置的標頭檔案,是對opt.h引數的重新配置,主要配置是否使用OS、使用DHCP自動分配IP、使能RAW、NETCOON或SOCKET以及配置TCP、UDP傳送接受佇列緩衝的大小等等與使用的硬體引數密切相關的配置。
在STM32的官方例程中還配置了使用軟硬體校驗和的相關配置。
#ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ #define SYS_LIGHTWEIGHT_PROT 0 //NO_SYS==1:不使用作業系統 #define NO_SYS 1 //不使用OS //使用4位元組對齊模式 #define MEM_ALIGNMENT 4 //MEM_SIZE:heap記憶體的大小,如果在應用中有大量資料傳送的話這個值最好設定大一點 #define MEM_SIZE 16000 //記憶體堆大小 //MEMP_NUM_PBUF:memp結構的pbuf數量,如果應用從ROM或者靜態儲存區傳送大量資料時,這個值應該設定大一點 #define MEMP_NUM_PBUF 10 //MEMP_NUM_UDP_PCB:UDP協議控制塊(PCB)數量.每個活動的UDP"連線"需要一個PCB. #define MEMP_NUM_UDP_PCB 6 //MEMP_NUM_TCP_PCB:同時建立啟用的TCP數量 #define MEMP_NUM_TCP_PCB 10 //MEMP_NUM_TCP_PCB_LISTEN:能夠監聽的TCP連線數量 #define MEMP_NUM_TCP_PCB_LISTEN 6 //MEMP_NUM_TCP_SEG:最多同時在佇列中的TCP段數量 #define MEMP_NUM_TCP_SEG 15 //MEMP_NUM_SYS_TIMEOUT:能夠同時啟用的timeout個數 #define MEMP_NUM_SYS_TIMEOUT 8 /* ---------- Pbuf選項---------- */ //PBUF_POOL_SIZE:pbuf記憶體池個數. #define PBUF_POOL_SIZE 20 //PBUF_POOL_BUFSIZE:每個pbuf記憶體池大小. #define PBUF_POOL_BUFSIZE 512 /* ---------- TCP選項---------- */ #define LWIP_TCP 1 //為1是使用TCP #define TCP_TTL 255//生存時間 /*當TCP的資料段超出佇列時的控制位,當裝置的記憶體過小的時候此項應為0*/ #define TCP_QUEUE_OOSEQ 0 //最大TCP分段 #define TCP_MSS (1500 - 40) //TCP_MSS = (MTU - IP報頭大小 - TCP報頭大小 //TCP傳送緩衝區大小(bytes). #define TCP_SND_BUF (4*TCP_MSS) //TCP_SND_QUEUELEN: TCP傳送緩衝區大小(pbuf).這個值最小為(2 * TCP_SND_BUF/TCP_MSS) #define TCP_SND_QUEUELEN (2* TCP_SND_BUF/TCP_MSS) //TCP傳送視窗 #define TCP_WND (2*TCP_MSS) /* ---------- ICMP選項---------- */ #define LWIP_ICMP 1 //使用ICMP協議 /* ---------- DHCP選項---------- */ //當使用DHCP時此位應該為1,LwIP 0.5.1版本中沒有DHCP服務. #define LWIP_DHCP 0 /* ---------- UDP選項 ---------- */ #define LWIP_UDP 1 //使用UDP服務 #define UDP_TTL 255 //UDP資料包生存時間 /* ---------- Statistics options ---------- */ #define LWIP_STATS 0 #define LWIP_PROVIDE_ERRNO 1 //STM32F4x7允許透過硬體識別和計算IP,UDP和ICMP的幀校驗和 #define CHECKSUM_BY_HARDWARE //定義CHECKSUM_BY_HARDWARE,使用硬體幀校驗 #ifdef CHECKSUM_BY_HARDWARE /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 0 /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 0 /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 0 /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 0 /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 0 /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 0 /* CHECKSUM_CHECK_ICMP==0: Check checksums by hardware for incoming ICMP packets.*/ #define CHECKSUM_GEN_ICMP 0 #else /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 1 /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 1 /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 1 /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 1 /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 1 /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 1 /* CHECKSUM_CHECK_ICMP==1: Check checksums by hardware for incoming ICMP packets.*/ #define CHECKSUM_GEN_ICMP 1 #endif /* ---------------------------------------------- ---------- SequentialAPI選項---------- ---------------------------------------------- */ //LWIP_NETCONN==1:使能NETCON函式(要求使用api_lib.c) #define LWIP_NETCONN 0 /* ------------------------------------ ---------- Socket API選項---------- ------------------------------------ */ //LWIP_SOCKET==1:使能Socket API(要求使用sockets.c) #define LWIP_SOCKET 0 #define LWIP_COMPAT_MUTEX 1 #define LWIP_SO_RCVTIMEO 1 //透過定義LWIP_SO_RCVTIMEO使能netconn結構體中recv_timeout,使用recv_timeout可以避免阻塞執行緒 /* ---------------------------------------- ---------- Lwip除錯選項---------- ---------------------------------------- */ //#define LWIP_DEBUG 1 //開啟DEBUG選項 #define ICMP_DEBUG LWIP_DBG_OFF //開啟/關閉ICMPdebug #endif /* __LWIPOPTS_H__ */
3、cc.h檔案與cpu.h檔案
cc.h檔案主要是對相關編譯器移植的支援,比如使用keil、IAR的支援,和抽象變數型別定義(與STM32的uint8_t 表示為 unsigned char類似)。contrib-1.4.1中有cc.h檔案參考。
cpu.h檔案主要針對cpu使用大小端模式配置。
#ifndef __CC_H__ #define __CC_H__ #include "cpu.h" #include "stdio.h" /*-------------data type------------------------------------------------------*/ typedef unsigned char u8_t; /* Unsigned 8 bit quantity */ typedef signed char s8_t; /* Signed 8 bit quantity */ typedef unsigned short u16_t; /* Unsigned 16 bit quantity */ typedef signed short s16_t; /* Signed 16 bit quantity */ typedef unsigned long u32_t; /* Unsigned 32 bit quantity */ typedef signed long s32_t; /* Signed 32 bit quantity */ typedef u32_t mem_ptr_t; /* Unsigned 32 bit quantity */ typedef int sys_prot_t; /*-------------critical region protection (depends on uC/OS-II setting)-------*/ #if OS_CRITICAL_METHOD == 1 #define SYS_ARCH_DECL_PROTECT(lev) #define SYS_ARCH_PROTECT(lev) CPU_INT_DIS() #define SYS_ARCH_UNPROTECT(lev) CPU_INT_EN() #endif #if OS_CRITICAL_METHOD == 3 //method 3 is used in this port. #define SYS_ARCH_DECL_PROTECT(lev) u32_t lev #define SYS_ARCH_PROTECT(lev) lev = OS_CPU_SR_Save() #define SYS_ARCH_UNPROTECT(lev) OS_CPU_SR_Restore(lev) #endif /*----------------------------------------------------------------------------*/ /* define compiler specific symbols */ #if defined (__ICCARM__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #define PACK_STRUCT_USE_INCLUDES #elif defined (__CC_ARM) #define PACK_STRUCT_BEGIN __packed #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__GNUC__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__TASKING__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #endif /*---define (sn)printf formatters for these lwip types, for lwip DEBUG/STATS--*/ #define U16_F "4d" #define S16_F "4d" #define X16_F "4x" #define U32_F "8ld" #define S32_F "8ld" #define X32_F "8lx" /*--------------macros--------------------------------------------------------*/ #ifndef LWIP_PLATFORM_ASSERT #define LWIP_PLATFORM_ASSERT(x) \ do \ { printf("Assertion \"%s\" failed at line %d in %s\r\n", x, __LINE__, __FILE__); \ } while(0) #endif #ifndef LWIP_PLATFORM_DIAG #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #endif #endif /* __CC_H__ */
#ifndef __CPU_H__ #define __CPU_H__ #define BYTE_ORDER LITTLE_ENDIAN //小端模式 #endif /* __CPU_H__ */
4、pref.h檔案
系統計量相關的標頭檔案,不使用為空即可。contrib-1.4.1中可以找到,直接複製過來用。
#ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */
5、sys_arch.c、sys_arch.h檔案
使用作業系統需要實現的lwip與OS之間的c介面檔案,本文現在是裸機移植,因此不需要實現,但是不論是OS還是裸機都需要實現sys_now實現lwip系統時基訊號處理TCP、ARP定時。全域性變數lwip_localtime是定時實現的ms為單位的計數器,使用中斷每1ms更新一次數值(更新中斷也可以間隔增大比如10ms更新一次lwip內部的定時都是10ms的倍數)。
/* lwIP includes. */sys_arch.h #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "timer.h" //為LWIP提供計時 extern uint32_t lwip_localtime;//lwip本地時間計數器,單位:ms u32_t sys_now(void){ return lwip_localtime; }
#ifndef __ARCH_SYS_ARCH_H__ #define __ARCH_SYS_ARCH_H__ #include "arch/cc.h" u32_t sys_now(void); #endif
四、lwip初始化
在實現了開發板ETH MAC通訊以及上述lwip檔案的配置之後就能夠配置lwip的初始化啟動lwip了。
根據前文的lwip啟動流程呼叫相關函式。注意在初始化lwip(lwip_init())之前需要初始化lwip記憶體分配策略(程式碼中的mem_init與memp_init)和ETH硬體(ETH_BSP_Config也就是STM32的ETH外設與PHY 晶片DP83848的初始化),lwip的記憶體管理可以參考LWIP應用開發實戰指南的lwip記憶體管理章節,STM32的硬體初始化可參考之前的章節基於STM32F407MAC與DP83848實現乙太網通訊(STM32F407MAC配置以及資料收發)。這裡只給出了lwip_comm.c初始化檔案的部分程式碼,可以看出啟動流程與上文第一節中提到的一致。
//LWIP初始化(LWIP啟動的時候使用) //返回值:0,成功 // 1,記憶體錯誤 // 2,LAN8720初始化失敗 // 3,網路卡新增失敗. u8 lwip_comm_init(void) { struct netif *Netif_Init_Flag; //呼叫netif_add()函式時的返回值,用於判斷網路初始化是否成功 struct ip4_addr ipaddr; //ip地址 struct ip4_addr netmask; //子網掩碼 struct ip4_addr gw; //預設閘道器
mem_init(); memp_init(); ETH_BSP_Config(); lwip_init(); //初始化LWIP核心 lwip_comm_default_ip_set(&lwipdev); //設定預設IP等資訊 #if LWIP_DHCP //使用動態IP ipaddr.addr = 0; netmask.addr = 0; gw.addr = 0; #else //使用靜態IP IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]); IP4_ADDR(&gw,lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); printf("網路卡en的MAC地址為:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]); printf("靜態IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]); printf("子網掩碼..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]); printf("預設閘道器..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]); #endif Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input);//向網路卡列表中新增一個網口 #if LWIP_DHCP //如果使用DHCP的話 lwipdev.dhcpstatus=0; //DHCP標記為0 dhcp_start(&lwip_netif); //開啟DHCP服務 #endif if(Netif_Init_Flag==NULL)return 3;//網路卡新增失敗 else//網口新增成功後,設定netif為預設值,並且開啟netif網口 { netif_set_default(&lwip_netif); //設定netif為預設網口 netif_set_up(&lwip_netif); //開啟netif網口 } return 0;//操作OK. }
lwip_comm_default_ip_set
//lwip 預設IP設定 //lwipx:lwip控制結構體指標 void lwip_comm_default_ip_set(__lwip_dev *lwipx) { u32 sn0; sn0=*(vu32*)(0x1FFF7A10);//獲取STM32的唯一ID的前24位作為MAC地址後三位元組 //預設遠端IP為:192.168.1.100 lwipx->remoteip[0]=192; lwipx->remoteip[1]=168; lwipx->remoteip[2]=1; lwipx->remoteip[3]=104; //MAC地址設定(高三位元組固定為:2.0.0,低三位元組用STM32唯一ID) lwipx->mac[0]=2;//高三位元組(IEEE稱之為組織唯一ID,OUI)地址固定為:2.0.0 lwipx->mac[1]=0; lwipx->mac[2]=0; lwipx->mac[3]=(sn0>>16)&0XFF;//低三位元組用STM32的唯一ID lwipx->mac[4]=(sn0>>8)&0XFFF;; lwipx->mac[5]=sn0&0XFF; //預設本地IP為:192.168.1.30 lwipx->ip[0]=192; lwipx->ip[1]=168; lwipx->ip[2]=1; lwipx->ip[3]=30; //預設子網掩碼:255.255.255.0 lwipx->netmask[0]=255; lwipx->netmask[1]=255; lwipx->netmask[2]=255; lwipx->netmask[3]=0; //預設閘道器:192.168.1.1 lwipx->gateway[0]=192; lwipx->gateway[1]=168; lwipx->gateway[2]=1; lwipx->gateway[3]=1; lwipx->dhcpstatus=0;//沒有DHCP }
五、啟動lwip
啟動lwip就比較簡單了,注意DHCP的使用,網線直連電腦情況下需要失能DHCP(lwipopts.h檔案中 DHCP配置0),使用DHCP時需連結路由器或者交換機使用。
當然現在只是實現了lwip的啟動,如果要實現UDP、TCP應用的話,就要實現相應的app檔案了,當前移植的裸機例程就只能使用RAW(基於回撥函式)實現,而將lwip一直在OS上則可以使用NETCONN或者SOCKET的API程式設計實現UDP、TCP應用了,這些在後續實現。
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 中斷分組配置 delay_init(168); // 初始化延時函式 uart_init(); // 初始化串列埠 LED_Init(); // 初始化LED埠 TIM3_Int_Init(999, 839); lwip_comm_init(); printf("test"); while (1) { // lwip_periodic_handle(); sys_check_timeouts(); } }
ping一下開發板,出現以下回復說明lwip配置成功
六、lwip1.4.1更新到lwip2.1.x的配置
剛開始學習的時候看了原子的文件,使用的是lwip1.4.1但是官方已經更新到2.1.x版本了,這裡記錄一下更新到2.1.x的注意事項。後續的程式都基於lwip2.1.x版本。
1、cc.h的配置
需要將型別定義相關的配置註釋掉,因為在新的lwip2.1.2中的arch.h中已經定義了。
#ifndef __CC_H__ #define __CC_H__ #include "cpu.h" #include "stdio.h" /*-------------data type------------------------------------------------------*/ //typedef unsigned char u8_t; /* Unsigned 8 bit quantity */ //typedef signed char s8_t; /* Signed 8 bit quantity */ //typedef unsigned short u16_t; /* Unsigned 16 bit quantity */ //typedef signed short s16_t; /* Signed 16 bit quantity */ //typedef unsigned long u32_t; /* Unsigned 32 bit quantity */ //typedef signed long s32_t; /* Signed 32 bit quantity */ //typedef u32_t mem_ptr_t; /* Unsigned 32 bit quantity */ //typedef int sys_prot_t; /*-------------critical region protection (depends on uC/OS-II setting)-------*/ #if OS_CRITICAL_METHOD == 1 #define SYS_ARCH_DECL_PROTECT(lev) #define SYS_ARCH_PROTECT(lev) CPU_INT_DIS() #define SYS_ARCH_UNPROTECT(lev) CPU_INT_EN() #endif #if OS_CRITICAL_METHOD == 3 //method 3 is used in this port. #define SYS_ARCH_DECL_PROTECT(lev) u32_t lev #define SYS_ARCH_PROTECT(lev) lev = OS_CPU_SR_Save() #define SYS_ARCH_UNPROTECT(lev) OS_CPU_SR_Restore(lev) #endif /*----------------------------------------------------------------------------*/ /* define compiler specific symbols */ #if defined (__ICCARM__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #define PACK_STRUCT_USE_INCLUDES #elif defined (__CC_ARM) #define PACK_STRUCT_BEGIN __packed #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__GNUC__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT __attribute__ ((__packed__)) #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #elif defined (__TASKING__) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #endif /*---define (sn)printf formatters for these lwip types, for lwip DEBUG/STATS--*/ #define U16_F "4d" #define S16_F "4d" #define X16_F "4x" #define U32_F "8ld" #define S32_F "8ld" #define X32_F "8lx" /*--------------macros--------------------------------------------------------*/ #ifndef LWIP_PLATFORM_ASSERT #define LWIP_PLATFORM_ASSERT(x) \ do \ { printf("Assertion \"%s\" failed at line %d in %s\r\n", x, __LINE__, __FILE__); \ } while(0) #endif #ifndef LWIP_PLATFORM_DIAG #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #endif #endif /* __CC_H__ */
2、標頭檔案相關
函式實現的檔案更改了位置或名稱如下,當然還有其它檔案,如果碰到有些函式不知道在那個檔案可以使用VSCode搜尋一下程式碼,具體的1.4版本到2.1版本的更新參考官方文件。
//#include "timers.h"
#include "lwip/timeouts.h"
//#include "lwip/tcp_impl.h" #include "lwip/priv/tcp_priv.h"
3、ethnetif.c參考檔案
ethnetif.c參考檔案從lwip2.1.x中移除了,但是可以在contrib-2.1.0中找到。
4、正點原子使用的lwip原始檔修改過的問題
參考STM32 LwIP學習過程問題總結(一):LwIP ping不通,抓包發現ICMP校驗和為0x0000
七、例程檔案
連結:https://pan.baidu.com/s/1vzSDwTW0g8oausd1dKsiQg?pwd=b302
提取碼:b302