本文轉(zhuǎn)自公眾號歡迎關(guān)注
基于DWC_ether_qos的以太網(wǎng)驅(qū)動開發(fā)-無OS環(huán)境移植LWIP (qq.com)
https://mp.weixin.qq.com/s/u1Bv6s_oh7jZ3sjS3nxbEA
一.前言
前面我們實現(xiàn)了數(shù)據(jù)的收發(fā),現(xiàn)在我們就可以移植協(xié)議棧了。LWIP是一個適合嵌入式平臺的著名的輕量級協(xié)議棧,我們這一篇就來無OS環(huán)境移植LWIP,下一篇再基于RTOS移植LWIP。
二.源碼
LWIP官網(wǎng)如下
https://savannah.nongnu.org/projects/lwip/
下載源碼git clone https://git.savannah.nongnu.org/git/lwip.git
LWIP的代碼可移植性非常好src下的源碼完全可移植不需要任何修改,移植參考contribports下的模板即可,已經(jīng)有了unix,freertos,win32的移植可參考。
三.NONEOS移植
3.1添加文件
將src復(fù)制到自己的工程路徑
然后添加一個port文件夾和src并列,無OS移植就添加一個noneos子目錄。
.
其中port如下,相關(guān)的文件可以從其他port下復(fù)制過來修改。
ports/
添加源文件
將src文件夾復(fù)制到自己的工程,添加源碼
src/api下所有c
src/core下所有c
src/core/ipv4下所有c
src/core/ipv6下所有c
src/netif/ethernet.c,netif下還有其他很多接口實現(xiàn),用到可以使用對應(yīng)的,我們這里只需要使用ethernet.c
頭文件路徑
將目錄src/include,ports/noneos/include添加到頭文件包含路徑。
3.2 移植文件
修改修改的文件
Ports下文件是需要修改的
ports/
lwipopts.h
配置文件,使用宏對LWIP進行配置。
Cc.h
必須位于arch目錄下
Perf.h/perf.c
portethif.h/portethif.c
sys_arch.c
錯誤碼
lwipopts.h中定義#define LWIP_PROVIDE_ERRNO 1則
src/include/lwip/errno.h中定義錯誤編碼和變量errno。
(我們這里使用該方式)
否則cc.h中需要include 或者自己實現(xiàn)錯誤碼宏定義和errno變量。
src/include/lwip/errno.h中可知,如果已經(jīng)有了對應(yīng)的頭文件則
可以定義LWIP_ERRNO_STDINCLUDE則自動#include
否則錯誤頭文件由LWIP_ERRNO_INCLUDE定義。
隨機數(shù)產(chǎn)生接口
如果有stdint.h則直接使用庫函數(shù),否則自行實現(xiàn)
Cc.h中
#include
extern unsigned int lwip_port_rand(void);
#define LWIP_RAND() (lwip_port_rand())
portethif.c中實現(xiàn)
#include
uint32_t lwip_port_rand(void)
{
return (uint32_t)rand();
}
斷言
不使用斷言,Cc.h中定義
#define LWIP_NOASSERT 1
如果定義了LWIP_NOASSERT則LWIP_ASSERT為空
如果使用斷言,沒有定義LWIP_NOASSERT
則src/lib/lwip/lwip/src/include/lwip/debug.h中
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) {
LWIP_PLATFORM_ASSERT(message); }} while(0)
此時需要實現(xiàn)LWIP_PLATFORM_ASSERT宏,
如果沒有定義LWIP_PLATFORM_ASSERT宏則默認(rèn)使用printf
則src/lib/lwip/lwip/src/include/lwip/arch.h中
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion "%s" failed at line %d in %sn",
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
atoi
Stdlib.h中有實現(xiàn),如果沒有該庫可以如下源碼實現(xiàn)
/*----------------------------------------------*/
lwip/ports/noneos/sys_arch.c下實現(xiàn)
u32_t sys_now(void)返回mS的全局時間。
存儲管理
lwip/ports/noneos/include/lwipopts.h中配置
堆管理
LWIP_RAM_HEAP_POINTER定義堆地址,必須要空間足夠大。
未定義則mem.c中定義大數(shù)組ram_heap
MEM_ALIGNMENT設(shè)置堆對齊
MEM_SIZE設(shè)置堆字節(jié)大小
lwip_init->mem_init時初始化,代碼位于mem.c
內(nèi)存池
pbuf.c調(diào)用memp.的接口
lwip_init->memp_init時初始化,代碼位于memp.c
lwip/priv/memp_priv.h中定義各個組件需要的內(nèi)存池
lwip/ports/noneos/include/lwipopts.h中MEMP_NUM_xxx定義大小。
性能測試接口
lwipopts.h中如果配置LWIP_PERF宏則
arch/perf.h需要實現(xiàn)兩個宏
PERF_START
PERF_STOP
在perf.c/perf.h中具體實現(xiàn)
否則這兩個宏自動置空。
一個參考實現(xiàn)如下
Perf.h
#ifndef LWIP_ARCH_PERF_H
perf.c
#include
可以看到指定接口執(zhí)行時間打印如下
系統(tǒng)層接口
無OS時不需要實現(xiàn)相關(guān)接口
src/lib/lwip/ports/noneos/include/lwipopts.h中
#define NO_SYS 1
NO_SYS=1時不能使用socket相關(guān)接口
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
以太網(wǎng)收發(fā)接口相關(guān)
實現(xiàn)以下幾個函數(shù)即可
實現(xiàn)初始化函數(shù)lwip_port_eth_init
在netif_add(&netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &lwip_port_eth_init, eernet_input);時調(diào)用執(zhí)行l(wèi)wip_port_eth_init
實現(xiàn)low_level_output,在執(zhí)行l(wèi)wip_port_eth_init時綁定到回調(diào)函數(shù)
netif->linkoutput = low_level_output;
收到一包數(shù)據(jù)時調(diào)用
lwip_port_eth_input
Portethif.h
#ifndef LWIP_TAPIF_H
Portethif.c
#include
四.測試
以下忽略了平臺相關(guān)的操作,比如以太網(wǎng)驅(qū)動初始化等,僅保留lwip相關(guān)內(nèi)容。
#include "lwip/netif.h"
收到包時調(diào)用
lwip_port_eth_input(&netif, p_data, len);
初始化與主循環(huán)
/* 在PHY初始化后,尤其是RXC輸出之后才調(diào)用,因為GMAC復(fù)位需要RXC */
使用網(wǎng)口調(diào)試工具,發(fā)送數(shù)據(jù)收到后原樣返回。
五.總結(jié)
LWIP代碼移植性非常好,無OS支持也非常好,移植只需要實現(xiàn)平臺相關(guān)的配置和宏,實現(xiàn)網(wǎng)口收發(fā)接口即可。
審核編輯 黃宇
-
以太網(wǎng)
+關(guān)注
關(guān)注
40文章
5424瀏覽量
171699 -
LwIP
+關(guān)注
關(guān)注
2文章
86瀏覽量
27168 -
驅(qū)動開發(fā)
+關(guān)注
關(guān)注
0文章
130瀏覽量
12077
發(fā)布評論請先 登錄
相關(guān)推薦
評論