0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

LwIP的帶操作系統(tǒng)基本移植

CHANBAEK ? 來(lái)源:木南創(chuàng)智 ? 作者:尹家軍 ? 2022-12-14 15:35 ? 次閱讀

現(xiàn)在,TCP/IP協(xié)議的應(yīng)用無(wú)處不在。隨著物聯(lián)網(wǎng)的火爆,嵌入式領(lǐng)域使用TCP/IP協(xié)議進(jìn)行通訊也越來(lái)越廣泛。在我們的相關(guān)產(chǎn)品中,也都有應(yīng)用,所以我們結(jié)合應(yīng)用實(shí)際對(duì)相關(guān)應(yīng)用作相應(yīng)的總結(jié)。

1 、技術(shù)準(zhǔn)備

我們采用的開(kāi)發(fā)平臺(tái)是STM32F407和LwIP協(xié)議棧。在開(kāi)始之前,我們需要做必要的準(zhǔn)備工作。

首先要獲得LwIP的源碼,在網(wǎng)上有很多,不同版本及不同平臺(tái)的都有,不過(guò)我們還是建議直接從官方網(wǎng)站獲得。

其次,需要硬件平臺(tái),我們采用了STM32F407ZG+DM9161的網(wǎng)絡(luò)接口方式,這并不是必須的,其他硬件平臺(tái)也是一樣的。

最后,因?yàn)槲覀兒竺嬉?a href="http://srfitnesspt.com/v/tag/527/" target="_blank">操作系統(tǒng)下移植,采用的操作系統(tǒng)是FreeRTOS,所以還需下載FreeRTOS的源碼。

2 LwIP****簡(jiǎn)要說(shuō)明

LwIP是一款免費(fèi)的TCP/IP協(xié)議棧,但它的功能趨勢(shì)十分完備。LwIP 具有三種應(yīng)用編程接口 (API):

  • Raw API :為原始的 LwIP API。它通過(guò)事件回調(diào)機(jī)制進(jìn)行應(yīng)用開(kāi)發(fā)。該 API 提供了最好的性能和優(yōu)化的代碼長(zhǎng)度,但增加了應(yīng)用開(kāi)發(fā)的復(fù)雜性。
  • Netconn API :為高層有序 API,需要實(shí)時(shí)操作系統(tǒng) (RTOS)的支持 (提供進(jìn)程間通訊的方法)。 Netconn API 支持多線程工作。
  • BSD Socket API :類(lèi)似 Berkeley 的套接字 API (開(kāi)發(fā)于 Netconn API 之上) 。

對(duì)于以上三種接口,前一種只需要裸機(jī)即可調(diào)用,后兩種需要操作系統(tǒng)才能調(diào)用。所以據(jù)此LwIP存在兩種移植方式:一是,只移植內(nèi)核,此時(shí)應(yīng)用程序的編寫(xiě)只能基于RAW/Callback API進(jìn)行。二是,移植內(nèi)核和上層API,此時(shí)應(yīng)用程序編寫(xiě)可以使用3種API,即:RAW/Callback API、Sequential API和Socket API。

3 、 LwIP****的帶操作系統(tǒng)基本移植

帶操作系統(tǒng)的移植首先是建立在無(wú)操作系統(tǒng)移植基礎(chǔ)之上的。在無(wú)操作系統(tǒng)移植時(shí),定義的數(shù)據(jù)類(lèi)型和宏都是有效的,只需要對(duì)lwipopts.h配置文件做簡(jiǎn)單修改,并根據(jù)sys_arch.txt移植說(shuō)明文件編寫(xiě)sys_arch.c和sys_arch.h兩個(gè)文件以實(shí)現(xiàn)操作系統(tǒng)模擬層就可以了。

操作系統(tǒng)模擬層的功能再以為協(xié)議棧提供郵箱、信號(hào)量、互斥量等機(jī)制,用以保證內(nèi)核與上層API的通訊。這些操作系統(tǒng)模擬層函數(shù)均在sys.h中已經(jīng)聲明,我們一般在sys_arch.c文件中完成其定義。所以,我們很清楚,帶操作系統(tǒng)的移植就是在無(wú)操作系統(tǒng)的基礎(chǔ)上添加操作系統(tǒng)模擬層。在接下來(lái)我們就看看操作系統(tǒng)模擬層的編寫(xiě)。

在操作系統(tǒng)已經(jīng)正確移植的基礎(chǔ)上,我們根據(jù)sys_arch.txt移植說(shuō)明文件的描述,還需要移植的宏定義及函數(shù)等如下:

名稱(chēng) 屬性 功能
sys_mbox_t 數(shù)據(jù)類(lèi)型 指針類(lèi)型,指向系統(tǒng)郵箱
sys_sem_t 數(shù)據(jù)類(lèi)型 指針類(lèi)型,指向系統(tǒng)信號(hào)量
sys_mutex_t 數(shù)據(jù)類(lèi)型 指針類(lèi)型,指向系統(tǒng)互斥量
sys_thread_t 數(shù)據(jù)類(lèi)型 系統(tǒng)任務(wù)標(biāo)識(shí)
SYS_MBOX_NULL 郵箱指針指向的空值
SYS_SEM_NULL 信號(hào)量指針指向的空值
sys_init 函數(shù) 初始化系統(tǒng)模擬層
sys_sem_new 函數(shù) 生成一個(gè)信號(hào)量
sys_sem_free 函數(shù) 刪除一個(gè)信號(hào)量
sys_sem_signal 函數(shù) 釋放一個(gè)信號(hào)量
sys_arch_sem_wait 函數(shù) 等待一個(gè)信號(hào)量
sys_sem_valid 函數(shù) 判斷一個(gè)信號(hào)量是否有效
sys_sem_set_invalid 函數(shù) 將一個(gè)信號(hào)量置為無(wú)效
sys_mutex_new 函數(shù) 生成一個(gè)新的互斥量
sys_mutex_free 函數(shù) 刪除一個(gè)互斥量
sys_mutex_lock 函數(shù) 鎖住一個(gè)互斥量
sys_mutex_unlock 函數(shù) 解鎖一個(gè)互斥量
sys_mutex_valid 函數(shù) 判斷一個(gè)互斥量是否有效
sys_mutex_set_invalid 函數(shù) 將一個(gè)互斥量置為無(wú)效
sys_mbox_new 函數(shù) 新建一個(gè)郵箱
sys_mbox_free 函數(shù) 刪除一個(gè)郵箱
sys_mbox_post 函數(shù) 向郵箱投遞消息,阻塞
sys_mbox_trypost 函數(shù) 嘗試向郵箱投遞消息,不阻塞
sys_arch_mbox_fetch 函數(shù) 從郵箱獲取消息,阻塞
sys_arch_mbox_tryfetch 函數(shù) 嘗試從郵箱獲取消息,不阻塞
sys_mbox_valid 函數(shù) 判斷一個(gè)郵箱是否有效
sys_mbox_set_invalid 函數(shù) 將一個(gè)郵箱設(shè)置為無(wú)效
sys_thread_new 函數(shù) 創(chuàng)建新進(jìn)程
sys_arch_protect 函數(shù) 臨界區(qū)保護(hù)
sys_arch_unprotect 函數(shù) 退出臨界區(qū)保護(hù)

從上表中我們可以發(fā)現(xiàn),這些變量和函數(shù)主要是面向信號(hào)量、互斥量及郵箱,包括新建、刪除、釋放、獲取等各類(lèi)操作,我們需要根據(jù)操作系統(tǒng)的規(guī)定來(lái)實(shí)現(xiàn)這些函數(shù),我們?cè)谶@里使用的FreeRTOS,所以我根據(jù)FreeRTOS對(duì)信號(hào)量、互斥量及郵箱的操作來(lái)實(shí)現(xiàn)這些函數(shù)。我們列舉郵箱的各操作函數(shù)實(shí)現(xiàn)如下:

1 /*創(chuàng)建一個(gè)空的郵箱。*/
  2 err_t sys_mbox_new(sys_mbox_t *mbox, int size)
  3 {
  4   osMessageQDef(QUEUE, size, void *);
  5  
  6   *mbox = osMessageCreate(osMessageQ(QUEUE), NULL);
  7  
  8 #if SYS_STATS
  9       ++lwip_stats.sys.mbox.used;
 10       if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
 11          lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
 12          }
 13 #endif /* SYS_STATS */
 14  if (*mbox == NULL)
 15   return ERR_MEM;
 16  
 17  return ERR_OK;
 18 }
 19  
 20 /*重新分配一個(gè)郵箱。如果郵箱被釋放時(shí),郵箱中仍有消息,在lwIP中這是出現(xiàn)編碼錯(cuò)誤的指示,并通知開(kāi)發(fā)人員。*/
 21 void sys_mbox_free(sys_mbox_t *mbox)
 22 {
 23        if( osMessageWaiting(*mbox) )
 24        {
 25               portNOP();
 26 #if SYS_STATS
 27            lwip_stats.sys.mbox.err++;
 28 #endif /* SYS_STATS */
 29        }
 30  
 31        osMessageDelete(*mbox);
 32  
 33 #if SYS_STATS
 34      --lwip_stats.sys.mbox.used;
 35 #endif /* SYS_STATS */
 36 }
 37  
 38 /*發(fā)送消息到郵箱*/
 39 void sys_mbox_post(sys_mbox_t *mbox, void *data)
 40 {
 41   while(osMessagePut(*mbox, (uint32_t)data, osWaitForever) != osOK);
 42 }
 43  
 44 /*嘗試將消息發(fā)送到郵箱*/
 45 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
 46 {
 47     err_t result;
 48  
 49    if ( osMessagePut(*mbox, (uint32_t)msg, 0) == osOK)
 50    {
 51       result = ERR_OK;
 52    }
 53    else {
 54       result = ERR_MEM;
 55                     
 56 #if SYS_STATS
 57       lwip_stats.sys.mbox.err++;
 58 #endif /* SYS_STATS */
 59                     
 60    }
 61  
 62    return result;
 63 }
 64  
 65 /*阻塞進(jìn)程從郵箱獲取消息*/
 66 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
 67 {
 68   osEvent event;
 69   uint32_t starttime = osKernelSysTick();;
 70  
 71   if(timeout != 0)
 72   {
 73     event = osMessageGet (*mbox, timeout);
 74    
 75     if(event.status == osEventMessage)
 76     {
 77       *msg = (void *)event.value.v;
 78       return (osKernelSysTick() - starttime);
 79     }
 80     else
 81     {
 82       return SYS_ARCH_TIMEOUT;
 83     }
 84   }
 85   else
 86   {
 87     event = osMessageGet (*mbox, osWaitForever);
 88     *msg = (void *)event.value.v;
 89     return (osKernelSysTick() - starttime);
 90   }
 91 }
 92  
 93 /*嘗試從郵箱獲取消息*/
 94 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
 95 {
 96   osEvent event;
 97  
 98   event = osMessageGet (*mbox, 0);
 99  
100   if(event.status == osEventMessage)
101   {
102     *msg = (void *)event.value.v;
103     return ERR_OK;
104   }
105   else
106   {
107     return SYS_MBOX_EMPTY;
108   }
109 }
110  
111 /*判斷一個(gè)郵箱是否有效*/
112 int sys_mbox_valid(sys_mbox_t *mbox)         
113 {     
114   if (*mbox == SYS_MBOX_NULL)
115     return 0;
116   else
117     return 1;
118 }
119  
120 /*設(shè)置一個(gè)郵箱無(wú)效*/                                             
121 void sys_mbox_set_invalid(sys_mbox_t *mbox)  
122 {                                            
123   *mbox = SYS_MBOX_NULL;                     
124 }                                             
125 
126 //  創(chuàng)建一個(gè)新的信號(hào)量。而 "count"參數(shù)指示該信號(hào)量的初始狀態(tài)
127 err_t sys_sem_new(sys_sem_t *sem, u8_t count)
128 {
129   osSemaphoreDef(SEM);
130  
131   *sem = osSemaphoreCreate (osSemaphore(SEM), 1);
132       
133   if(*sem == NULL)
134   {
135 #if SYS_STATS
136       ++lwip_stats.sys.sem.err;
137 #endif /* SYS_STATS */ 
138               return ERR_MEM;
139   }
140       
141   if(count == 0)  // Means it can't be taken
142   {
143     osSemaphoreWait(*sem,0);
144   }
145  
146 #if SYS_STATS
147        ++lwip_stats.sys.sem.used;
148       if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
149               lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
150        }
151 #endif /* SYS_STATS */
152              
153        return ERR_OK;
154 }

此外還有一些函數(shù)也是協(xié)議棧需要的函數(shù),特別是sys_thread_new函數(shù),不但協(xié)議棧在初始化是需要用到,在后續(xù)我們實(shí)現(xiàn)各類(lèi)基于LwIP的應(yīng)用時(shí)也需要用到,其實(shí)現(xiàn)如下:

1 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread , void *arg, int stacksize, int prio)
 2 {
 3   const osThreadDef_t os_thread_def = { (char *)name, (os_pthread)thread, (osPriority)prio, 0, stacksize};
 4   return osThreadCreate(&os_thread_def, arg);
 5 }
 6 osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
 7 {
 8   TaskHandle_t handle;
 9  
10 #if( configSUPPORT_STATIC_ALLOCATION == 1 ) &&  ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
11   if((thread_def->buffer != NULL) && (thread_def->controlblock != NULL)) {
12     handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
13               thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
14               thread_def->buffer, thread_def->controlblock);
15   }
16   else {
17     if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
18               thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
19               &handle) != pdPASS)  {
20       return NULL;
21     }
22   }
23 #elif( configSUPPORT_STATIC_ALLOCATION == 1 )
24  
25     handle = xTaskCreateStatic((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
26               thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
27               thread_def->buffer, thread_def->controlblock);
28 #else
29   if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,
30                    thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),
31                    &handle) != pdPASS)  {
32     return NULL;
33   }    
34 #endif
35  
36   return handle;
37 }

至此,基于FreeRTOS操作系統(tǒng)的LwIP移植結(jié)算完成了,我們編譯下載就可以對(duì)其進(jìn)行驗(yàn)證。

4 、結(jié)論

前面已經(jīng)移植了基于操作系統(tǒng)的LwIP,那怎么知道我們的移植是否成功呢?接下來(lái)我們對(duì)它進(jìn)行必要的驗(yàn)證。

首先我們查看目標(biāo)板在網(wǎng)絡(luò)上的配置是否正確。我們打開(kāi)命令行窗口,運(yùn)行ipconfig命令,查看MAC地址和IP地址配置:

我們配置的MAC地址00:08:E1:00:00:00和IP地址192.168.2.110顯示正常。接下來(lái)我們采用ping命令測(cè)試網(wǎng)絡(luò)鏈接:

上圖顯示網(wǎng)絡(luò)連接正常,經(jīng)此測(cè)試,說(shuō)明我們的LwIP在有操作系統(tǒng)情況下移植正常。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    8869

    瀏覽量

    84966
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6617

    瀏覽量

    123040
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1337

    瀏覽量

    78871
  • LwIP
    +關(guān)注

    關(guān)注

    2

    文章

    85

    瀏覽量

    27032
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    誰(shuí)有LWIP入門(mén)例子?最好是stm32F103不帶操作系統(tǒng)的!

    誰(shuí)有LWIP入門(mén)例子?最好是stm32F103不帶操作系統(tǒng)的!自己移植沒(méi)有成功郁悶吶
    發(fā)表于 05-25 19:26

    請(qǐng)問(wèn)帶操作系統(tǒng)比沒(méi)有操作系統(tǒng)的程序的好處在哪?

    帶操作系統(tǒng)比沒(méi)有操作系統(tǒng)的程序的好處在哪?
    發(fā)表于 06-02 23:52

    請(qǐng)問(wèn)ucGUI+STM32F103不帶操作系統(tǒng)刷DEMO源碼分享嗎?

    求ucGUI+STM32F103的不帶操作系統(tǒng)刷DEMO 源碼,mini板+寄存器版本的最好,謝謝大俠了,找了好久就是找不到啊 自己移植一直刷不了demo,不知道什么原因 請(qǐng)大俠們不吝賜教啊 ,謝謝了
    發(fā)表于 08-06 04:36

    請(qǐng)問(wèn)STM32F407+Lwip一定要移植操作系統(tǒng)嗎?

    現(xiàn)在想做網(wǎng)絡(luò)產(chǎn)品的開(kāi)發(fā),需要做TCP服務(wù)器,多個(gè)TCP客戶(hù)端連接進(jìn)來(lái),進(jìn)行數(shù)據(jù)傳輸。STM32F407+Lwip一定要移植操作系統(tǒng)嗎?有無(wú)操作系統(tǒng)哪種好?不知道有
    發(fā)表于 08-16 03:25

    沒(méi)有操作系統(tǒng)真的不能使用LwIP套接字和域名解析嗎?

    裸機(jī)移植LwIP協(xié)議棧,整體感覺(jué)不錯(cuò)但是在使用套接字(Socket)功能和域名解析(lwip_gethostbyname)時(shí)發(fā)現(xiàn)編譯通不過(guò),說(shuō)是要啟用操作系統(tǒng)。如果不用
    發(fā)表于 08-22 22:25

    lwip帶freertos操作系統(tǒng)移植代碼分享!

    本人在stm32f407 探索者板子上實(shí)驗(yàn)過(guò),根據(jù)原子哥lwip帶UCOS2移植的這一節(jié)視頻,做了lwip帶FreeRTOS的移植,代碼結(jié)構(gòu)跟原子哥源代碼結(jié)構(gòu)一樣,容易理解。代碼如下
    發(fā)表于 10-18 01:45

    LWIP無(wú)操作系統(tǒng)移植不能識(shí)別jlink

    用原子的 網(wǎng)絡(luò)實(shí)驗(yàn)1 LWIP無(wú)操作系統(tǒng)移植無(wú)法識(shí)別jlink其他基礎(chǔ)例程,UCOS等例程都可以,就這一個(gè)程序無(wú)法識(shí)別,換過(guò)電腦,換jlink都一樣,配置也都一樣,請(qǐng)問(wèn)原子哥和各位大神有什么高招。
    發(fā)表于 03-11 04:36

    如何利用STM32CubeMX移植LWIP到STM32F429開(kāi)發(fā)板中

    STM32CubeMX+LAN8720+LWIP帶操作系統(tǒng)實(shí)現(xiàn)網(wǎng)絡(luò)通訊使用STM32CubeMX可以非常方便的將LWIP移植到工程中,本文就是介紹如何利用STM32CubeMX
    發(fā)表于 08-11 08:27

    為什么要做無(wú)操作系統(tǒng)LWIP

    無(wú)操作系統(tǒng)LWIP有何優(yōu)點(diǎn)?為什么要做無(wú)操作系統(tǒng)LWIP呢?
    發(fā)表于 10-29 08:11

    如何將LwIP協(xié)議棧移植到μC/OS-II實(shí)時(shí)操作系統(tǒng)上去呢

    LwIP協(xié)議是什么?什么是μC/OS-II實(shí)時(shí)操作系統(tǒng)呢?如何將LwIP協(xié)議棧移植到μC/OS-II實(shí)時(shí)操作系統(tǒng)上去呢?
    發(fā)表于 11-05 08:44

    LwIP|無(wú)操作系統(tǒng)

    LwIP無(wú)操作系統(tǒng)下的實(shí)驗(yàn) 本文詳細(xì)講述了LwIP在無(wú)操作系統(tǒng)支持環(huán)境下的API函數(shù)介紹及編程應(yīng)用。首先,介紹了RAW API的特點(diǎn)及優(yōu)缺點(diǎn),然后逐個(gè)介紹了
    發(fā)表于 04-07 16:39 ?110次下載

    LwIP無(wú)操作系統(tǒng)下的實(shí)驗(yàn)

    本文詳細(xì)講述了LwIP在無(wú)操作系統(tǒng)支持環(huán)境下的API函數(shù)介紹及編程應(yīng)用。首先,介紹了RAW API的特點(diǎn)及優(yōu)缺點(diǎn),然后逐個(gè)介紹了LwIP提供的所有的RAW API函數(shù),最后通過(guò)實(shí)例的形式介紹了
    發(fā)表于 07-19 15:33 ?107次下載

    NXPl788上lwip的無(wú)操作系統(tǒng)移植,基于Embest開(kāi)發(fā)板

    NXPl788上lwip的無(wú)操作系統(tǒng)移植,基于Embest開(kāi)發(fā)板
    發(fā)表于 03-26 15:59 ?85次下載

    lwip移植說(shuō)明及心得

    lwip是一套用于嵌入式系統(tǒng)的開(kāi)放源代碼TCP/IP協(xié)議棧。Lwip既可以移植操作系統(tǒng)上,又可以在無(wú)
    發(fā)表于 12-11 16:06 ?2w次閱讀
    <b class='flag-5'>lwip</b><b class='flag-5'>移植</b>說(shuō)明及心得

    裸機(jī)開(kāi)發(fā)和帶操作系統(tǒng)開(kāi)發(fā)的區(qū)別

    、RT-Thread 、eCos和Linux等。2.區(qū)別馬克思主義認(rèn)為,事物之間是相互聯(lián)系和相互區(qū)別的。帶操作系統(tǒng)開(kāi)發(fā)由于操作系統(tǒng)具有并發(fā)性,所以可以支持多個(gè)任務(wù)運(yùn)行,可以從本質(zhì)上認(rèn)為它是裸機(jī)開(kāi)發(fā)效...
    發(fā)表于 12-09 12:51 ?24次下載
    裸機(jī)開(kāi)發(fā)和<b class='flag-5'>帶操作系統(tǒng)</b>開(kāi)發(fā)的區(qū)別