《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 嵌入式技術(shù) > 設(shè)計(jì)應(yīng)用 > 基于μC/OS-Ⅲ的LwIP協(xié)議棧的移植與實(shí)現(xiàn)
基于μC/OS-Ⅲ的LwIP協(xié)議棧的移植與實(shí)現(xiàn)
來源:電子技術(shù)應(yīng)用2013年第5期
韓德強(qiáng),楊淇善,王宗俠,高雪園
北京工業(yè)大學(xué) 計(jì)算機(jī)學(xué)院,北京100124
摘要: 以太網(wǎng)是嵌入式系統(tǒng)的一個(gè)重要模塊,討論了如何將LwIP 1.4.0版本協(xié)議棧移植到最新的實(shí)時(shí)操作系統(tǒng)μC/OS-Ⅲ中,使其具有網(wǎng)絡(luò)通信功能。詳述了在TI公司的LM3S9B95微控制器開發(fā)平臺(tái)上移植LwIP協(xié)議棧的過程,并給出了測試結(jié)果。
關(guān)鍵詞: 移植 LwIP μCOS-
中圖分類號(hào): TP393
文獻(xiàn)標(biāo)識(shí)碼: A
文章編號(hào): 0258-7998(2013)05-0018-04
Implementation of LwIP porting based on μC/OS-Ⅲ
Han Deqiang,Yang Qishan,Wang Zongxia,Gao Xueyuan
College of Computer,Beijing University of Technology,Beijing 100124,China
Abstract: Ethernet is an important module for embedded system. This paper discusses how to port LwIP 1.4.0 into the latest real-time operating system μC/OS-Ⅲ, and enable it with a network communication function. The detailed porting process of the LwIP on TI LM3S9B95 development platform is described and the experimental results are presented.
Key words : porting;LwIP;μC/OS-Ⅲ

    隨著嵌入式系統(tǒng)功能的多樣化及網(wǎng)絡(luò)在各個(gè)領(lǐng)域中的廣泛應(yīng)用,具有網(wǎng)絡(luò)功能的嵌入式終端擁有更高的使用價(jià)值和更強(qiáng)的通用性。μC/OS-Ⅲ是一個(gè)可裁剪、可固化、可剝奪型的實(shí)時(shí)內(nèi)核,管理任務(wù)的數(shù)目不受限制[1]。作為μC/OS系列的最新版本,μC/OS-Ⅲ提供了實(shí)時(shí)內(nèi)核所能提供的所有服務(wù),可保證網(wǎng)絡(luò)功能和其他諸多任務(wù)并發(fā)有序地執(zhí)行。但μC/OS-Ⅲ僅僅是一個(gè)實(shí)時(shí)操作系統(tǒng)的內(nèi)核,要實(shí)現(xiàn)網(wǎng)絡(luò)功能還需移植一款符合嵌入式系統(tǒng)要求的以太網(wǎng)協(xié)議棧。LwIP是由瑞典計(jì)算機(jī)科學(xué)研究院開發(fā)的輕量型TCP/IP協(xié)議棧,其特點(diǎn)是保持了以太網(wǎng)的基本功能,通過優(yōu)化減少了對(duì)片內(nèi)存儲(chǔ)資源的占用[2]。一般情況下,具有十幾KB SRAM和幾十KB Flash存儲(chǔ)能力的微控制器即可運(yùn)行LwIP協(xié)議棧[3]。該特點(diǎn)使其廣泛使用于數(shù)據(jù)采集、工業(yè)控制等多個(gè)應(yīng)用領(lǐng)域中。本文論述了使用LM3S9B95微控制器的嵌入式平臺(tái)實(shí)現(xiàn)LwIP 1.4.0版本在μC/OS-Ⅲ上的移植。LM3S9B95是TI公司推出的基于ARM Cortex-M3內(nèi)核的微控制器,其內(nèi)部具有以太網(wǎng)控制器模塊[4]。

1 LwIP的移植過程
    LwIP的移植主要涉及兩個(gè)方面:操作系統(tǒng)模擬層和硬件驅(qū)動(dòng)層。LwIP在設(shè)計(jì)時(shí)已考慮到在不同操作系統(tǒng)中的可移植性,其內(nèi)部使用的函數(shù)和數(shù)據(jù)結(jié)構(gòu)均為抽象定義[5]。開發(fā)者可根據(jù)不同的操作系統(tǒng)要求來具體實(shí)現(xiàn)相關(guān)的函數(shù)和數(shù)據(jù)結(jié)構(gòu)。同時(shí),硬件相關(guān)的驅(qū)動(dòng)同樣預(yù)留了接口,開發(fā)者可針對(duì)實(shí)際使用情況編寫網(wǎng)絡(luò)控制芯片驅(qū)動(dòng)函數(shù)。另外,對(duì)不同的編譯環(huán)境,開發(fā)者還需要編寫部分頭文件定義相關(guān)數(shù)據(jù)結(jié)構(gòu)和宏。LwIP在μC/OS-Ⅲ嵌入式系統(tǒng)中的結(jié)構(gòu)如圖1所示,其中的箭頭框?yàn)橐浦补ぷ餍枰獙?shí)現(xiàn)的模塊。

1.1 操作系統(tǒng)模擬層的編寫
1.1.1 編寫頭文件cc.h

    cc.h文件中包含處理器相關(guān)的變量類型、數(shù)據(jù)結(jié)構(gòu)及字節(jié)對(duì)齊的相關(guān)宏。
    LwIP中使用的基本變量類型均以位數(shù)進(jìn)行命名,為抽象的變量定義,開發(fā)者需要根據(jù)所用處理器具體定義?;咀兞康亩x有兩種方法:一種是將變量直接定義為C語言的基本類型,如unsigned char、int等;另一種是將變量定義為操作系統(tǒng)內(nèi)對(duì)應(yīng)的抽象變量。當(dāng)使用操作系統(tǒng)時(shí),應(yīng)采用第二種方法。該方法的優(yōu)點(diǎn)是變量對(duì)于處理器是“透明”的,應(yīng)用程序更換硬件平臺(tái)時(shí)無需修改操作系統(tǒng)模擬層內(nèi)的定義。μC/OS-Ⅲ中對(duì)基本變量的定義在cpu.h文件中,均以CPU為命名前綴。對(duì)于這些變量在μC/OS-Ⅲ中具體如何定義本文不做討論。LwIP要求定義8 bit、16 bit、32 bit和內(nèi)存指針型變量:
    typedef    CPU_INT08U        u8_t;
    typedef    CPU_INT08S        s8_t;
    typedef    CPU_INT16U        u16_t;
    typedef    CPU_INT16S        s16_t;
    typedef    CPU_INT32U        u32_t;
    typedef    CPU_INT32S        s32_t;
    typedef    CPU_INT32U        mem_ptr_t;
    由于ARM處理器的編譯環(huán)境默認(rèn)對(duì)變量存儲(chǔ)采取4 B對(duì)齊方式,而以太網(wǎng)數(shù)據(jù)包等結(jié)構(gòu)體要求處理器按照變量的實(shí)際大小存儲(chǔ)和訪問,因此,需要定義相關(guān)的結(jié)構(gòu)封裝宏,使得結(jié)構(gòu)體內(nèi)的成員變量不以4 B對(duì)齊的方式進(jìn)行存儲(chǔ)。移植工作采用了IAR開發(fā)環(huán)境,需根據(jù)該環(huán)境定義如下相關(guān)的宏:
    #if defined (__IAR_SYSTEMS_ICC__)
    #define  PACK_STRUCT_BEGIN
    #define  PACK_STRUCT_STRUCT
    #define  PACK_STRUCT_END
    #define  PACK_STRUCT_FIELD(x) x
    #define  PACK_STRUCT_USE_INCLUDES
1.1.2 編寫頭文件sys_arch.h
    sys_arch.h文件要求定義操作系統(tǒng)相關(guān)的數(shù)據(jù)結(jié)構(gòu)和宏。
    LwIP多線程功能需要信號(hào)量和郵箱等結(jié)構(gòu)體,用于多個(gè)任務(wù)的同步和消息的傳遞。μC/OS-Ⅲ中的信號(hào)量OS_SEM和消息隊(duì)列OS_Q可實(shí)現(xiàn)相應(yīng)的功能。LwIP 1.4.0版本中使用了互斥信號(hào)量管理共享的資源,而有些嵌入式操作系統(tǒng)中不包含互斥信號(hào)量的變量類型。為了適應(yīng)不同的操作系統(tǒng),LwIP定義了宏LWIP_COMPAT_MUTEX。LWIP_COMPAT_MUTEX的值定義為1,則LwIP使用二值信號(hào)量代替互斥信號(hào)量以及相關(guān)的功能函數(shù)。雖然μC/OS-Ⅲ包含了互斥信號(hào)量OS_MUTEX,但LwIP中兩種數(shù)據(jù)結(jié)構(gòu)可相互替換,選擇使用二值信號(hào)量可以減少一定的移植工作。
    #define  LWIP_COMPAT_MUTEX        1
    typedef  OS_SEM                    sys_sem_t;
    typedef  OS_Q                         sys_mbox_t;
    LwIP中包含有必須完整執(zhí)行而不可被打斷的代碼,因此需要使用臨界段代碼保護(hù)的功能。μC/OS-Ⅲ中提供了關(guān)閉中斷和鎖定調(diào)度器兩種臨界段代碼保護(hù)方法。LwIP中的臨界段代碼保護(hù)宏可直接定義為μC/OS-Ⅲ關(guān)閉中斷的對(duì)應(yīng)臨界段代碼保護(hù)宏。
   #define  SYS_ARCH_DECL_PROTECT() CPU_SR_ALLOC()
   #define  SYS_ARCH_PROTECT()  OS_CRITICAL_ENTER()
   #define  SYS_ARCH_UNPROTECT() OS_CRITICAL_EXIT()
1.1.3 編寫源文件sys_arch.c
    sys_arch.c文件要求實(shí)現(xiàn)操作系統(tǒng)模擬層的接口函數(shù),主要包括對(duì)信號(hào)量和郵箱等數(shù)據(jù)結(jié)構(gòu)的操作以及LwIP線程的操作。
    LwIP的信號(hào)量用于進(jìn)程間的通信,相關(guān)操作主要包括以下幾個(gè)函數(shù):
    sys_sem_new()            //新建信號(hào)量
    sys_sem_free()            //釋放信號(hào)量
    sys_sem_signal()        //發(fā)送信號(hào)量
    sys_arch_sem_wait()        //阻塞進(jìn)程,等待指定信號(hào)量
    sys_sem_valid()        //檢查信號(hào)量可用性
    sys_sem_set_invalid()    //設(shè)置信號(hào)量不可用
    LwIP的郵箱用于緩存和傳遞數(shù)據(jù)報(bào)文,相關(guān)操作主要包括以下幾個(gè)函數(shù):
    sys_mbox_new()        //新建郵箱
    sys_mbox_free()        //刪除郵箱
    sys_mbox_post()        //阻塞進(jìn)程,投遞消息至郵箱
    sys_mbox_trypost()        //投遞消息至郵箱,僅一次操作
    sys_arch_mbox_fetch()    //阻塞進(jìn)程,從郵箱中提取消息
    sys_arch_mbox_tryfetch()    //從郵箱中提取消息,僅一次操作
    sys_mbox_valid()        //檢查郵箱可用性
    sys_mbox_set_invalid()    //設(shè)置郵箱不可用
    LwIP使用了μC/OS-Ⅲ中的信號(hào)量OS_SEM和消息隊(duì)列OS_Q結(jié)構(gòu),以上函數(shù)的實(shí)現(xiàn)調(diào)用了μC/OS-Ⅲ的操作函數(shù),包括OS?Create()、OS?Del()、OS?Post()和OS?Pend()。在實(shí)現(xiàn)sys_?_new()和sys_?_free()函數(shù)時(shí),需加入臨界段代碼保護(hù)以確保OS?Create()和OS?Del()在執(zhí)行時(shí)不被打斷,可避免出現(xiàn)系統(tǒng)資源管理錯(cuò)誤。
   err_t  sys_?_new(……)
   {
    OS_ERR err;
    CPU_SR_ALLOC();            //臨界代碼保護(hù)開始
    CPU_CRITICAL_ENTER();
    OS?Create(……,&err);
    CPU_CRITICAL_EXIT();        //臨界代碼保護(hù)結(jié)束
    return err;
   }
   void  sys_?_free(……)
   {
    OS_ERR err;
    CPU_SR_ALLOC();            //臨界代碼保護(hù)開始
    CPU_CRITICAL_ENTER();
    OS?Del(……, &err );
    CPU_CRITICAL_EXIT();        //臨界代碼保護(hù)結(jié)束
   }
    LwIP 1.4.0版本新添加了sys_?_valid()和sys_?_set_
invalid(),這兩個(gè)函數(shù)的實(shí)現(xiàn)無需調(diào)用操作系統(tǒng)內(nèi)部的函數(shù),可由開發(fā)者根據(jù)實(shí)際需求實(shí)現(xiàn)。另外,二值信號(hào)量替換了互斥信號(hào)量,相關(guān)的操作函數(shù)也無需在此文件內(nèi)實(shí)現(xiàn)。在LwIP內(nèi)核中的sys.h文件給出了詳細(xì)的宏定義:
    #if    LWIP_COMPAT_MUTEX
    #define  sys_mutex_t            sys_sem_t
    #define  sys_mutex_new(mutex)    sys_sem_new(mutex, 1)
    #define  sys_mutex_lock(mutex)    sys_sem_wait(mutex)
    #define  sys_mutex_unlock(mutex)    sys_sem_signal(mutex)
    #define  sys_mutex_free(mutex)    sys_sem_free(mutex)
    #define  sys_mutex_valid(mutex)    sys_sem_valid(mutex)
    #define  sys_mutex_set_invalid(mutex)    \
             sys_sem_set_invalid(mutex)
    LwIP建立新進(jìn)程的接口函數(shù)sys_thread_new()要求成功建立一個(gè)任務(wù)并返回任務(wù)優(yōu)先級(jí)。μC/OS-Ⅲ中加入了時(shí)間片輪轉(zhuǎn)調(diào)度功能,使得同一優(yōu)先級(jí)可建立多個(gè)任務(wù),避免了優(yōu)先級(jí)重復(fù)導(dǎo)致任務(wù)建立失敗的情況。相比于使用μC/OS-Ⅱ或其他不支持同級(jí)任務(wù)的操作系統(tǒng),sys_thread_new()的實(shí)現(xiàn)僅調(diào)用OSTaskCreate()即可,省略了一些查找可用優(yōu)先級(jí)的容錯(cuò)操作。
    操作系統(tǒng)模擬層的初始化函數(shù)sys_init()由開發(fā)者根據(jù)實(shí)際情況進(jìn)行編寫,沒有固定的規(guī)范要求。該函數(shù)可不執(zhí)行任何操作,但必須在文件內(nèi)實(shí)現(xiàn)。
1.2 硬件驅(qū)動(dòng)層的編寫

 


    LwIP內(nèi)核文件中給出了驅(qū)動(dòng)文件的參考模板e(cuò)thernetif.c,開發(fā)者可根據(jù)其模板的架構(gòu)結(jié)合實(shí)際使用的網(wǎng)絡(luò)控制芯片來編寫驅(qū)動(dòng)。
    以low_level為前綴的函數(shù)均為網(wǎng)絡(luò)控制芯片相關(guān)的接口函數(shù),主要包含初始化、接收、發(fā)送等操作。LM3S9B95的以太網(wǎng)控制器模塊包含了MAC層和物理層,有別于傳統(tǒng)的MCU+PHY芯片的結(jié)構(gòu)。因此,實(shí)現(xiàn)驅(qū)動(dòng)函數(shù)時(shí)可直接對(duì)相應(yīng)的寄存器進(jìn)行操作,無需再次封裝PHY芯片的操作函數(shù)。
    以ethernetif為前綴的函數(shù)要求開發(fā)者實(shí)現(xiàn)底層硬件與上層協(xié)議間的接口函數(shù),包括底層設(shè)備描述結(jié)構(gòu)體的相關(guān)操作、LwIP主線程和以太網(wǎng)中斷服務(wù)函數(shù)等。
1.3 LwIP功能裁剪和定制
    LwIP為開發(fā)者提供了一個(gè)功能定制的接口文件lwipopt.h,可根據(jù)系統(tǒng)實(shí)際需求定義宏的值、裁剪功能和配置參數(shù)。例如使用TCP和UDP功能,則需添加下列定義:
    #define    LWIP_TCP        1
    #define    LWIP_UDP        1
    內(nèi)核文件opt.h是lwipopt.h的設(shè)計(jì)模板,包含了所有LwIP功能配置的宏。opt.h文件對(duì)宏定義均采用了#ifndef預(yù)編譯判斷,當(dāng)開發(fā)者在lwipopt.h中沒有對(duì)某個(gè)宏給出定義時(shí),該文件會(huì)定義一個(gè)默認(rèn)值。
    雖然修改opt.h中的宏定義和在lwipopt.h中編寫宏定義均可實(shí)現(xiàn)剪裁和定制LwIP的功能,但由于修改內(nèi)核文件會(huì)破壞協(xié)議棧的封裝性,為今后的應(yīng)用程序移植和維護(hù)造成隱患,所以開發(fā)者不應(yīng)直接修改opt.h內(nèi)的宏定義。
    開發(fā)者在編寫lwipopt.h時(shí),由于每個(gè)宏的默認(rèn)值并不能保證LwIP的正確運(yùn)行,所以應(yīng)對(duì)opt.h中給出的所有宏進(jìn)行定義。例如opt.h中對(duì)于TCP的一些宏定義如下:
    #ifndef    TCPIP_THREAD_STACKSIZE
    #define    TCPIP_THREAD_STACKSIZE        0
    #endif
    #ifndef    TCPIP_MBOX_SIZE
    #define    TCPIP_MBOX_SIZE                      0
    #endif
    LwIP默認(rèn)的TCPIP進(jìn)程堆棧空間為0,TCPIP使用的郵箱空間為0。若開發(fā)者在lwipopt.h中不對(duì)這些宏進(jìn)行定義,當(dāng)tcpip_init()對(duì)LwIP進(jìn)行初始化時(shí),就會(huì)出現(xiàn)錯(cuò)誤致使LwIP無法正確運(yùn)行。
2 測試
    測試工作使用LM3S9B95嵌入式平臺(tái)作為TCP客戶端,一臺(tái)PC作為TCP主機(jī)端。測試程序中,嵌入式平臺(tái)的IP地址設(shè)為172.21.28.250,主機(jī)IP為172.21.28.253,端口為1020。測試程序中創(chuàng)建了兩個(gè)任務(wù):一個(gè)是LwIP主線程,一個(gè)是測試任務(wù)。LwIP主線程處理以太網(wǎng)協(xié)議的數(shù)據(jù)包,測試任務(wù)負(fù)責(zé)接收主機(jī)端的數(shù)據(jù)并回傳至主機(jī)端。
    測試任務(wù)首先初始化底層硬件和協(xié)議棧,包括使能LM3S9B95以太網(wǎng)硬件模塊和中斷、調(diào)用協(xié)議棧內(nèi)核初始化函數(shù)tcpip_init()、初始化網(wǎng)絡(luò)接口的結(jié)構(gòu)體。
   void  My_LwIP_Init(void)
   {
    /* 調(diào)用StellarisWare庫函數(shù)進(jìn)行硬件初始化 */
    ……
    /* 調(diào)用內(nèi)核初始化函數(shù) */
    tcpip_init();
    /* 初始化netif,設(shè)置本機(jī)的IP、子網(wǎng)掩碼、網(wǎng)關(guān),綁定netif的回調(diào)函數(shù) */
    netif_add(……);
    netif_set_default(……);
    netif_set_up(……);
   }
    第二步是初始化客戶端。首先創(chuàng)建一個(gè)網(wǎng)絡(luò)連接結(jié)構(gòu)體,再將其綁定至端口并連接到指定的服務(wù)器。
   void  TCP_Client_Init(void)
   {
    pstNetconn = netconn_new(NETCONN_TCP);    //新建連接
    netconn_bind(……);            //綁定端口
    netconn_connect(……);        //連接主機(jī)
   }
    任務(wù)的主循環(huán)中調(diào)用了LwIP具有進(jìn)程阻塞功能的函數(shù)netconn_recv()以接收來自主機(jī)的數(shù)據(jù)。若數(shù)據(jù)接收正確,則將數(shù)據(jù)發(fā)送回主機(jī)端的PC;若接收不正確,則刪除當(dāng)前的連接,重新連接到主機(jī)。
   while(1)
   {
    err = netconn_recv(……);    // 接收數(shù)據(jù)
    if(err == ERR_OK)        // 數(shù)據(jù)正確
    {
        netconn_write(……);    // 發(fā)送數(shù)據(jù)
        netbuf_delete(……);    // 刪除數(shù)據(jù)緩沖區(qū)
    }
    else
    {
        netconn_delete(……);    // 刪除當(dāng)前連接
        /* 重新連接 */
        ……
    }
   }
    PC主機(jī)端使用了銘心軟體工作室的網(wǎng)絡(luò)調(diào)試助手,通過該軟件向LM3S9B95客戶端發(fā)送測試數(shù)據(jù),客戶端的回傳數(shù)據(jù)也在該軟件內(nèi)顯示。測試結(jié)果如圖2所示。

    LwIP是一款專為嵌入式系統(tǒng)設(shè)計(jì)的以太網(wǎng)協(xié)議棧,具有占用資源小、基本功能完備和便于移植等特點(diǎn)。其擁有很高的通用性,適用于多種嵌入式操作系統(tǒng)和硬件平臺(tái)[6]。在運(yùn)行實(shí)時(shí)操作系統(tǒng)的應(yīng)用環(huán)境中,移植工作要求開發(fā)者實(shí)現(xiàn)操作系統(tǒng)模擬層和硬件驅(qū)動(dòng)層兩個(gè)部分。協(xié)議棧的主進(jìn)程可作為實(shí)時(shí)操作系統(tǒng)的一個(gè)任務(wù),完整地執(zhí)行網(wǎng)絡(luò)通信功能。μC/OS-Ⅲ是μC/OS系列的最新產(chǎn)品,同樣是一款實(shí)時(shí)操作系統(tǒng)的內(nèi)核,并不具備網(wǎng)絡(luò)通信功能。LwIP移植到μC/OS-Ⅲ中,可使得運(yùn)行該實(shí)時(shí)內(nèi)核的嵌入式終端擁有網(wǎng)絡(luò)通信功能,符合當(dāng)今產(chǎn)品發(fā)展的趨勢,具有更廣泛的應(yīng)用領(lǐng)域和更高的市場價(jià)值。
參考文獻(xiàn)
[1] LABROSSE J J著.嵌入式實(shí)時(shí)操作系統(tǒng)μC/OS-Ⅲ[M]. 邵貝貝,譯.北京:北京航空航天大學(xué)出版社,2012.
[2] DUNKELS A.Design and implementation of the LwIP TCP/ IP Stack[Z].Sweden:Swedish Institute of Computer Science,2001:21-30.
[3] 熊海泉.μC/OS II下LwIP協(xié)議的移植實(shí)現(xiàn)[J].科技廣場,2005(2):78-79.
[4] Texas Instruments.Stellaris?誖LM3S9B95 microcontroller data sheet[Z].2011.
[5] 程明,余中華,蘇艷蘋,等.μC/OS II下LwIP協(xié)議棧的移植和測試[J].微計(jì)算機(jī)信息,2008(23):79-81.
[6] 余坤杰.LWIP網(wǎng)口通訊協(xié)議在LM3S8962網(wǎng)口上的移植實(shí)現(xiàn)[J].設(shè)計(jì)與分析,2011(27):155-156.

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。