龙源期刊网 http://www.qikan.com.cn
LwIP在嵌入式系统中的应用
作者:周一兵 刘宪鹏
来源:《科技视界》2013年第06期
【摘 要】本文以μC/OS–II为操作系统内核,利用开源TCP/IP协议栈LwIP,使其具有TCP/IP通信功能,并通过测试,实际应用效果良好。 【关键词】μC/OS–II;TCP/IP;LwIP 0 引言
嵌入式Internet是近几年随着嵌入式系统的广泛应用和计算机网络技术的发展而发展起来一项新兴概念和技术。随着Internet的发展,各种设备都产生了连接性的需求,从冰箱到电表,似乎所有电器都需要连入互联网。通过为现有嵌入式系统增加因特网接入能力来扩展其功能,以Internet为介质实现信息交互的过程,这就产生了嵌入式Internet技术。
由于嵌入式系统自身资源的限制,处理能力不如台式机强,而台式机上的TCP/IP的复杂性,使得处理通信协议成为嵌入式系统接入Internet的关键,也是嵌入式系统接入Internet的难点之一。
LwIP是一套用于嵌入式系统的开放源码的轻型TCP/IP协议栈,它实现了较为完备的IP、ICMP、 UDP、TCP协议,具有超时时间估计、快速恢复和重发、窗口调整等功能。LwIP在保持协议主要功能的基础上减少对RAM和ROM的占用,一般它只需要几十K的RAM和40K左右的ROM就可以运行,很适合同μC/OS-II相配合用在嵌入式系统中。 1 μC/OS-II操作系统的移植
μC/OS-II是一个专门用于嵌入式系统的实时操作系统,根据用户需要可以方便的进行移植、剪裁。对于μC/OS-II操作系统的移植主要是对以下几个文件进行修改: 1.1 OS_CPU.H 文件
对于这个文件的修改主要包含三部分内容:
1)由于不同的处理器有不通的字长,所以在这个文件中定义了与编译器相关的数据类型;
2)设定了堆栈的单位,以及堆栈的增长方向; 3)定义了中断开关的宏以及任务切换的宏。
龙源期刊网 http://www.qikan.com.cn
1.2 OS_CPU_C.C 文件
文件包含一个OSTaskStkInit()函数和若干hook函数,OSTaskStkInit()在创建任务时被OSTaskCreate()或OSTaskCreateExt()调用来初始化任务的堆栈结构。系统hook函数在没有特殊需求的情况下只需要将其都实现为空函数即可。 1.3 OS_CPU_A.ASM 文件
文件中包含了OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()和OSTickISR()四个函数。OSStart()多任务启动之后,负责从最高优先级任务的任务控制块(TCB)中获得该任务的堆栈指针SP,通过SP依次将CPU现场恢复。OSCtxSw()实现任务级的任务切换,OSIntCtxSw()实现中断级的任务切换。OSTickISR()实现中断定时产生功能。 2 LwIP在μC/OS-II的移植
LwIP在操作系统中的移植主要是根据sys_arch.txt文件对sys_arch.c文件进行编写。sys_arch.c文件为LwIP提供信号量(semaphores)和邮箱(mailboxes)两种进程间通信方式(IPC)。
2.1 信号量操作函数
LwIP中需要使用信号量在进程(任务)间通信,所以在sys_arch.c中,应该实现信号量的处理函数:sys_sem_new()函数、sys_sem_free()函数、sys_sem_signal()函数和sys_arch_sem_wait()函数。 2.1.1 sys_sem_new()函数
这个函数的作用是建立并返回一个新的信号量,参数count表示信号量的初始状态。由于μC/OS-II中也提供了信号量,所以只需直接调用建立信号量的相关函数就可以了。 2.1.2 sys_sem_free()函数
此函数的功能是释放一个信号量,参数sem为要释放的信号量。其实现和上个函数类似,直接调用μC/OS-II中释放信号量的函数即可。 2.1.3 sys_sem_signal()函数
此函数的功能是发送信号量,参数sem为要发送的信号量。 2.1.4 sys_arch_sem_wait()函数
龙源期刊网 http://www.qikan.com.cn
由于LwIP已经使用了函数名sys_sem_wait(),故此处采用sys_arch_sem_wait()函数名。此函数的功能是等待信号量并阻塞进程,参数sem为要等待的信号量,timeout为需要等待的时间。如果“timeout”参数非零,则进程需等待设定的时间(单位为毫秒);如果“timeout”参数为零,则进程必须等到信号量,否则它将一直阻塞。如果“timeout”参数非零,这个函数的返回值为收到信号时已经等待的时间(单位为毫秒),如果在约定的等待时间内,并没有等待到信号量,返回值将是SYS_ARCH_TIMEOUT。如果函数不需要等待信号量,其返回值将是零。
2.2 邮箱操作函数
信号量在进程之间传递消息是实时的,一个任务发送,另一个任务接收。LwIP使用消息队列(邮箱)来缓冲、传递数据信息,因此要在sys_arch.c中实现邮箱的结构sys_mbox_t。邮箱用于消息传递,用户既可以将其实现为一个队列,允许多条消息投递到这个邮箱,也可以每次只允许投递一个消息,这两种方式LwIP都可以正常运作。不过,前者更加有效。投递到邮箱中的消息只能是一个指针。其实,在μC/OS-II中已经实现了消息队列结构,但是没有提供对消息队列中消息的管理函数,因而不能直接使用,必须在此基础上重新实现。为此,定义一个新的结构如下。 struct {
OS_EVENT* QueneP;
void* QueneMes[MAX_MESSAGE]; };
这个结构包含两部分:队列指针QueneP和队列中的消息QueneMes,其中
MAX_MESSAGE表示最大消息数。这样就可以利用μC/OS-II中消息队列管理函数来管理邮箱,用μC/OS-II中对内存管理函数来实现对邮箱中消息的创建、使用、删除和回收等,从而来完成LwIP的邮箱的功能。有了sys_mbox_t,就可以建立一个sys_mbox_t类型的数组来实现邮箱。
2.3 网络驱动的设计
嵌入式Internet系统的硬件千差万别,在系统中会使用到各种各样的网络控制芯片,这些芯片的硬件驱动程序差别很大,兼容性不强。所以LwIP协议栈在设计时,网络驱动程序的编写就没有针对具体的网络芯片,只是提供了一个模板,/src/netif/ethernetif.c文件即为驱动的模板,为自己的网络设备实现驱动时应参照此模板。在LwIP中可以有多个网络接口,每个网络接口都对应了一个struct netif,这个netif包含了相应网络接口的属性、收发函数。LwIP调用netif的方法netif->input()及netif->output()进行以太网packet的收、发等操作。在驱动中主要做的,就是实现网络接口的收包、发包、初始化以及中断处理函数。