0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

LwIP的带操作系统基本移植

CHANBAEK 来源:木南创智 作者:尹家军 2022-12-14 15:35 次阅读

现在,TCP/IP协议的应用无处不在。随着物联网的火爆,嵌入式领域使用TCP/IP协议进行通讯也越来越广泛。在我们的相关产品中,也都有应用,所以我们结合应用实际对相关应用作相应的总结。

1 、技术准备

我们采用的开发平台是STM32F407和LwIP协议栈。在开始之前,我们需要做必要的准备工作。

首先要获得LwIP的源码,在网上有很多,不同版本及不同平台的都有,不过我们还是建议直接从官方网站获得。

其次,需要硬件平台,我们采用了STM32F407ZG+DM9161的网络接口方式,这并不是必须的,其他硬件平台也是一样的。

最后,因为我们后面要在操作系统下移植,采用的操作系统是FreeRTOS,所以还需下载FreeRTOS的源码。

2 LwIP****简要说明

LwIP是一款免费的TCP/IP协议栈,但它的功能趋势十分完备。LwIP 具有三种应用编程接口 (API):

  • Raw API :为原始的 LwIP API。它通过事件回调机制进行应用开发。该 API 提供了最好的性能和优化的代码长度,但增加了应用开发的复杂性。
  • Netconn API :为高层有序 API,需要实时操作系统 (RTOS)的支持 (提供进程间通讯的方法)。 Netconn API 支持多线程工作。
  • BSD Socket API :类似 Berkeley 的套接字 API (开发于 Netconn API 之上) 。

对于以上三种接口,前一种只需要裸机即可调用,后两种需要操作系统才能调用。所以据此LwIP存在两种移植方式:一是,只移植内核,此时应用程序的编写只能基于RAW/Callback API进行。二是,移植内核和上层API,此时应用程序编写可以使用3种API,即:RAW/Callback API、Sequential API和Socket API。

3 LwIP****的带操作系统基本移植

带操作系统的移植首先是建立在无操作系统移植基础之上的。在无操作系统移植时,定义的数据类型和宏都是有效的,只需要对lwipopts.h配置文件做简单修改,并根据sys_arch.txt移植说明文件编写sys_arch.c和sys_arch.h两个文件以实现操作系统模拟层就可以了。

操作系统模拟层的功能再以为协议栈提供邮箱、信号量、互斥量等机制,用以保证内核与上层API的通讯。这些操作系统模拟层函数均在sys.h中已经声明,我们一般在sys_arch.c文件中完成其定义。所以,我们很清楚,带操作系统的移植就是在无操作系统的基础上添加操作系统模拟层。在接下来我们就看看操作系统模拟层的编写。

在操作系统已经正确移植的基础上,我们根据sys_arch.txt移植说明文件的描述,还需要移植的宏定义及函数等如下:

名称 属性 功能
sys_mbox_t 数据类型 指针类型,指向系统邮箱
sys_sem_t 数据类型 指针类型,指向系统信号量
sys_mutex_t 数据类型 指针类型,指向系统互斥量
sys_thread_t 数据类型 系统任务标识
SYS_MBOX_NULL 邮箱指针指向的空值
SYS_SEM_NULL 信号量指针指向的空值
sys_init 函数 初始化系统模拟层
sys_sem_new 函数 生成一个信号量
sys_sem_free 函数 删除一个信号量
sys_sem_signal 函数 释放一个信号量
sys_arch_sem_wait 函数 等待一个信号量
sys_sem_valid 函数 判断一个信号量是否有效
sys_sem_set_invalid 函数 将一个信号量置为无效
sys_mutex_new 函数 生成一个新的互斥量
sys_mutex_free 函数 删除一个互斥量
sys_mutex_lock 函数 锁住一个互斥量
sys_mutex_unlock 函数 解锁一个互斥量
sys_mutex_valid 函数 判断一个互斥量是否有效
sys_mutex_set_invalid 函数 将一个互斥量置为无效
sys_mbox_new 函数 新建一个邮箱
sys_mbox_free 函数 删除一个邮箱
sys_mbox_post 函数 向邮箱投递消息,阻塞
sys_mbox_trypost 函数 尝试向邮箱投递消息,不阻塞
sys_arch_mbox_fetch 函数 从邮箱获取消息,阻塞
sys_arch_mbox_tryfetch 函数 尝试从邮箱获取消息,不阻塞
sys_mbox_valid 函数 判断一个邮箱是否有效
sys_mbox_set_invalid 函数 将一个邮箱设置为无效
sys_thread_new 函数 创建新进程
sys_arch_protect 函数 临界区保护
sys_arch_unprotect 函数 退出临界区保护

从上表中我们可以发现,这些变量和函数主要是面向信号量、互斥量及邮箱,包括新建、删除、释放、获取等各类操作,我们需要根据操作系统的规定来实现这些函数,我们在这里使用的FreeRTOS,所以我根据FreeRTOS对信号量、互斥量及邮箱的操作来实现这些函数。我们列举邮箱的各操作函数实现如下:

1 /*创建一个空的邮箱。*/
  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 /*重新分配一个邮箱。如果邮箱被释放时,邮箱中仍有消息,在lwIP中这是出现编码错误的指示,并通知开发人员。*/
 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 /*发送消息到邮箱*/
 39 void sys_mbox_post(sys_mbox_t *mbox, void *data)
 40 {
 41   while(osMessagePut(*mbox, (uint32_t)data, osWaitForever) != osOK);
 42 }
 43  
 44 /*尝试将消息发送到邮箱*/
 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 /*阻塞进程从邮箱获取消息*/
 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 /*判断一个邮箱是否有效*/
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 /*设置一个邮箱无效*/                                             
121 void sys_mbox_set_invalid(sys_mbox_t *mbox)  
122 {                                            
123   *mbox = SYS_MBOX_NULL;                     
124 }                                             
125 
126 //  创建一个新的信号量。而 "count"参数指示该信号量的初始状态
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 }

此外还有一些函数也是协议栈需要的函数,特别是sys_thread_new函数,不但协议栈在初始化是需要用到,在后续我们实现各类基于LwIP的应用时也需要用到,其实现如下:

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操作系统的LwIP移植结算完成了,我们编译下载就可以对其进行验证。

4 、结论

前面已经移植了基于操作系统的LwIP,那怎么知道我们的移植是否成功呢?接下来我们对它进行必要的验证。

首先我们查看目标板在网络上的配置是否正确。我们打开命令行窗口,运行ipconfig命令,查看MAC地址和IP地址配置:

我们配置的MAC地址00:08:E1:00:00:00和IP地址192.168.2.110显示正常。接下来我们采用ping命令测试网络链接:

上图显示网络连接正常,经此测试,说明我们的LwIP在有操作系统情况下移植正常。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    8986

    浏览量

    85122
  • 操作系统
    +关注

    关注

    37

    文章

    6707

    浏览量

    123163
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1348

    浏览量

    78955
  • LwIP
    +关注

    关注

    2

    文章

    85

    浏览量

    27061
收藏 人收藏

    评论

    相关推荐

    谁有LWIP入门例子?最好是stm32F103不带操作系统的!

    谁有LWIP入门例子?最好是stm32F103不带操作系统的!自己移植没有成功郁闷呐
    发表于 05-25 19:26

    请问带操作系统比没有操作系统的程序的好处在哪?

    带操作系统比没有操作系统的程序的好处在哪?
    发表于 06-02 23:52

    请问ucGUI+STM32F103不带操作系统刷DEMO源码分享吗?

    求ucGUI+STM32F103的不带操作系统刷DEMO 源码,mini板+寄存器版本的最好,谢谢大侠了,找了好久就是找不到啊 自己移植一直刷不了demo,不知道什么原因 请大侠们不吝赐教啊 ,谢谢了
    发表于 08-06 04:36

    请问STM32F407+Lwip一定要移植操作系统吗?

    现在想做网络产品的开发,需要做TCP服务器,多个TCP客户端连接进来,进行数据传输。STM32F407+Lwip一定要移植操作系统吗?有无操作系统哪种好?不知道有
    发表于 08-16 03:25

    没有操作系统真的不能使用LwIP套接字和域名解析吗?

    裸机移植LwIP协议栈,整体感觉不错但是在使用套接字(Socket)功能和域名解析(lwip_gethostbyname)时发现编译通不过,说是要启用操作系统。如果不用
    发表于 08-22 22:25

    lwip带freertos操作系统移植代码分享!

    本人在stm32f407 探索者板子上实验过,根据原子哥lwip带UCOS2移植的这一节视频,做了lwip带FreeRTOS的移植,代码结构跟原子哥源代码结构一样,容易理解。代码如下
    发表于 10-18 01:45

    LWIP操作系统移植不能识别jlink

    用原子的 网络实验1 LWIP操作系统移植无法识别jlink其他基础例程,UCOS等例程都可以,就这一个程序无法识别,换过电脑,换jlink都一样,配置也都一样,请问原子哥和各位大神有什么高招。
    发表于 03-11 04:36

    如何利用STM32CubeMX移植LWIP到STM32F429开发板中

    STM32CubeMX+LAN8720+LWIP带操作系统实现网络通讯使用STM32CubeMX可以非常方便的将LWIP移植到工程中,本文就是介绍如何利用STM32CubeMX
    发表于 08-11 08:27

    为什么要做无操作系统LWIP

    操作系统LWIP有何优点?为什么要做无操作系统LWIP呢?
    发表于 10-29 08:11

    如何将LwIP协议栈移植到μC/OS-II实时操作系统上去呢

    LwIP协议是什么?什么是μC/OS-II实时操作系统呢?如何将LwIP协议栈移植到μC/OS-II实时操作系统上去呢?
    发表于 11-05 08:44

    LwIP|无操作系统

    LwIP操作系统下的实验 本文详细讲述了LwIP在无操作系统支持环境下的API函数介绍及编程应用。首先,介绍了RAW API的特点及优缺点,然后逐个介绍了
    发表于 04-07 16:39 110次下载

    LwIP操作系统下的实验

    本文详细讲述了LwIP在无操作系统支持环境下的API函数介绍及编程应用。首先,介绍了RAW API的特点及优缺点,然后逐个介绍了LwIP提供的所有的RAW API函数,最后通过实例的形式介绍了
    发表于 07-19 15:33 107次下载

    NXPl788上lwip的无操作系统移植,基于Embest开发板

    NXPl788上lwip的无操作系统移植,基于Embest开发板
    发表于 03-26 15:59 85次下载

    lwip移植说明及心得

    lwip是一套用于嵌入式系统的开放源代码TCP/IP协议栈。Lwip既可以移植操作系统上,又可以在无
    发表于 12-11 16:06 2w次阅读
    <b class='flag-5'>lwip</b><b class='flag-5'>移植</b>说明及心得

    裸机开发和带操作系统开发的区别

    、RT-Thread 、eCos和Linux等。2.区别马克思主义认为,事物之间是相互联系和相互区别的。带操作系统开发由于操作系统具有并发性,所以可以支持多个任务运行,可以从本质上认为它是裸机开发效...
    发表于 12-09 12:51 24次下载
    裸机开发和<b class='flag-5'>带操作系统</b>开发的区别