一种适用于物联网节点的高效轻量级嵌入式系统设计※*

2014-07-03 03:33楼亮亮周苗鲍星合
单片机与嵌入式系统应用 2014年11期
关键词:内核中断延时

楼亮亮,周苗,鲍星合

(1.中国科学院 上海微系统与信息技术研究所 无线传感网与通信重点实验室,上海201800;2.上海大学)

引 言

Protothread是完全基于事件驱动的操作系统,只在语言层面上做了相应的“封装”。因此,Protothreads具有一定的局限性[2]。Protothread不支持优先级抢占,阻塞的I/O只允许在主线程函数中调用等。针对上述的几个问题,本文提出的操作系统是在Protothread基础上的改进,具有低功耗、易移植、支持多任务切换、时间片调度、抢占式调度及事件同步等特点。由于本系统使用了Protothread的核心思想,这也决定了本系统具有一定的局限,在每个任务中避免与switch语句合用[5]。

1 系统架构

本系统主要由调度内核、中断管理系统及软中断系统组成,具体框架如图1所示。

1.1 任务控制块及任务优先级设计

在本系统中,每个任务都定义与该任务相关的任务控制块(TCB)。将所有任务控制块组装成一个队列,则每个任务控制块都对应于任务控制块队列中的一个节点,每个任务控制块中的数据只能由中断程序或者调度内核来修改。任务控制块中包含该任务的入口地址、支持时间片调度的服务延时、信号量及当前任务的状态。为了节省内存,其中信号量和当前任务状态采用位定义。其数据结构如下所示 :

图1 系统的架构

本系统支持优先级调度。任务的优先级对应于其任务的控制块在任务控制块队列中的位置,任务控制块在该队列中的位置越靠前,该任务就越早被调用,优先级也就越高。

1.2 任务状态与任务创建

本系统的任务状态划分为3种:空闲、就绪及运行。在任何时刻,任务的状态必定是这3种状态中的一个。本文涉及的系统与一般嵌入式操作系统(如μC/OS、FreeRTOS等)设计方式不同,本系统中的任何任务都不是无限循环,且都有返回值,任务在阻塞的时候会返回相应的状态给调度内核,任务的无限循环只能由调度内核来实现。任务的返回值为一个8位有符号数,该值的正数部分0~127留给任务申请延时服务的节拍数,而-128~-1则作为信号量、任务执行结束等其他相应操作的返回值。任务把该值返回到内核后,内核根据该值的数据作出相应操作。

OS_TASK_END_RET是用来指示当前运行的任务执行完所有操作的返回值,内核得到该返回值后会重新运行该任务,实现任务的无限循环;OS_TASK_SEM_RET用来指示当前运行的任务有信号量发出,内核得到该返回值后,根据该值把该任务TCB中的变量sem设置成指定的数据值,且把该任务置为就绪态(如果有其他任务向该任务发出信号量,则执行该任务);OS_TASK_TIME_RET用来指示当前运行的任务申请延时运行服务的返回节拍数(该值为正数),内核得到该返回值后,将其赋予该任务TCB中的变量timeout。如果每个任务TCB中的变量timeout≥0,则该值在Tick中断中实现减1操作,一旦该值减至为0,内核就会重新运行该TCB对应的任务。

1.3 内核调度算法

在系统开始调度的时候,调度内核首先检查pid是否超出了系统所定义的任务总数。如果超过任务总数,说明系统已经执行完所有用户指定的任务,则调度内核停止调度且执行空闲任务,进入低功耗模式。空闲任务的退出,只有pid数值在事件中断或Tick中断中被改变才会实现,一旦退出空闲任务,系统则重新开始调度。

如果pid小于系统所定义的任务总数,则系统开始从TCB队列中获取每个TCB中变量status的数值,该变量用于记录任务状态。如果任务状态是就绪态,则加载任务TCB中的入口函数地址到内核中执行。在任务执行的过程中,一旦任务被阻塞或执行结束,任务就会返回相应的数值到调度内核中,调度内根据该返回值,开展相应工作。

具体调度算法流程如图2所示。

图2 调度算法流程图

1.4 任务切换

为了支持一级任务优先的抢占式调度功能,本系统采用了软中断模式,利用中断来自动压栈与出栈,把高优先级的任务安排在软中断服务程序中运行。由于软件中断优先级比较低,系统运行基本不受影响。例如在Tick中断中,有高优先级任务就绪,如果直接在Tick中断中运行,由于任务运行带来时间的不确定性,会严重影响Tick的定时精度。而采用软中断的模式,由于中断优先级比较低,在其服务程序中运行高优先级的任务时,其他中断(如Tick中断)不会受到影响。

这将带来两个方面的好处:①如果高优先级任务在中断服务中直接执行,将会影响Tick定时器的定时精度或者是其他中断的响应时间。②利用软中断自动压栈出栈功能,可以减少上下文切换,降低RAM的需要,从而提高了效率,降低了系统的整体功耗。

1.5 时间管理

本系统和其他内核一样,需要时钟节拍来实现时间片调度和延时服务。在本系统中实现上述服务的函数为OS_TIME_DLY()。调用该函数之后,该任务会返回延时的节拍数到调度内核中,内核会把返回的节拍数写入该任务TCB中的变量timeout,内核实现一次调度,执行下一个就绪态任务。具体实现如下所示:

#define OS_TIME_DLY(ticks)do{_lc=__LINE__;return ticks;}while(0);case__LINE__:

为了实现时间片调度,需要在Tick中断中调用OS_TIME_UPDATE(),来更新每个任务TCB中变量timeout的数据值。如果该变量数据≥0,则在每次中断中进行减1操作,否则不做任何处理。当任务TCB中变量timeout减至0,则把对应的任务置为就绪态,内核在调度的时候就会执行就绪态的任务,从而实现时间片调度和延时服务功能。该函数的具体流程如图3(a)所示。

1.6 事件同步

本系统中事件同步采用了信号量设计方式,涉及到该项服务的有两个函数:等待信号量与发送信号量。若一个任务等待一个信号量,则调用OS_SEM_PEND()阻塞该任务并返回OS_TASK_SEM_RET到调度内核,调度内核根据该返回值把相应状态写入该任务TCB中的变量sem,并把该任务置为就绪状态。具体实现如下所示:

#define OS_SEM_PEND()do{_lc=__LINE__;return OS_TASK_SEM_RET ;}while(0);case__LINE__:

发送一个信号量函数,实现相对等待信号量比较复杂,需要涉及到任务的切换。当某个任务或者中断中调用OS_SEM_POST()时,该函数在执行结束后返回要发送信号量的任务ID号到内核中,调度内核会判断该任务TCB中R变量sem是否在等待该信号量。如果是,则执行任务切换,即开启软中断。涉及到的函数如下:

INT8S OS_SEM_POST(INT8S (*ptask)(void))

其中:ptask为要发送信号量到的任务名。基本流程如图3(b)所示。

2 系统分析

2.1 ROM与RAM资源评估

本文涉及的系统是在IAR FOR MSP430 V5.30.1执行,采用的编译模式为:Release、优化等级为Level high balanced。表1略——编者注。

综上所述,本系统所带来的RAM额外消耗可由以下式计算得出:

RAMoverhead=任务数×5字节+1字节

2.2 系统正确性评估

图3 时间片调度算法流程与信号量发送流程

本系统在MSP430F149平台上验证其正确性及可靠性。在实验中采用定时器A作为系统的Tick时钟,为了测量每个任务的运行时间及切换时间,本系统中Tick定时周期为16μs。在实际应用中,用户可以根据系统的实际应用场合而定,系统Tick周期越短则系统负荷越大。由于MSP430系统微处理器没有相关软中断指令,故采用定时器B作为软中断来实现任务的切换,其优先级相对定时器A与其他中断来说比较低。

为了验证其正确性,本文在该系统平台上建立了两个任务。同时系统会自动增加一个空闲任务,两个任务都不需要执行的时候,系统就会自动进入空闲模式(即休眠模式),降低了功耗。

任务1优先级最高,创建的时候设置其为就绪状态,所以在任务调度开始的时候就开始运行任务1,并关闭延时调度服务。其功能是等待任务2发出的信号量,在等待信号量的时候挂起自身任务。为了便于测试,在任务1中通过函数SystemClockSave()记录某些关键步骤的系统时间,用于任务运行时间的测量。具体实现如下所示:

OS_CREATE_TASK(Task1,0,OS_TASK_STATUS_RDY,-1);

任务2功能是周期性发出信号量给任务1,任务2每隔10个节拍后发送信号量给任务1,随后挂起自身任务。同时,在任务2中通过函数SystemClockSave()记录某些关键步骤的系统时间,用于任务运行时间的测量。具体实现如下所示:

OS_CREATE_TASK(Task2,1,OS_TASK_STATUS_RDY,10);任务1与任务2的具体实现如图4所示。系统实际运行的状况如图5所示。

图4 任务1与任务2的具体实现

图5 系统运行状态图

任务2在等待延时服务的时候释放CPU控制权,返回要延时的节拍数到调度内核中。调度内核把该任务返回的节拍数写入任务2的TCB中的变量timeout,在Tick中断服务程序中对变量timeout实行减1操作。此时系统没有任务运行,系统自动进入空闲模式,降低系统的功耗。一旦任务2 TCB的timeout值减至为零,则内核重新调用任务2。紧接着任务2发送信号量到任务1,因为任务1优先级高于任务2,任务2又被挂起,在调用OS_SEM_POST()之后实现任务的切换,任务1得到优先运行。只有在任务1释放CPU控制权的时候,任务2才得以运行。接下来任务1与任务2重复交替执行,系统的正确性得到验证。

3 研究的创新点

本文提出了一种基于Protothread思想的嵌入式系统,提供了一种类似于操作系统的编程方式,支持抢占式调度,具有代码量小、容易移植及低功耗管理等特性,使得程序的设计、维护和调试更加便捷。每个任务利用编译器__LINE__来记录阻塞点的行号,实现任务的阻塞,并返回相应状态到调度内核中,实现任务状态的切换或阻塞点的重运行。下面举一个例子说明,物联网传感器采集节点都集成无线收发模块,与后台系统进行数据交互,为了保证无线数据传输的可靠性,一般都采用“发送-应答”机制。在此系统中,如果采用状态机的模型,具体代码流程如图6所示。

如果采用本文提供的系统编程模式,上面程序可以修改成如图7所示。

结 语

本文提出的基于Protothread思想的多任务抢占式系统设计方案为事件驱动程序设计提供了一种有效的处理方法,使得程序的设计、维护和调试更加便捷,对于嵌入式软件开发有较大的参考价值。

图6 基于状态机模型下无线收发架构

图7 基于本文设计系统架构下的无线收发架构

编者注:本文为期刊缩略版,全文见本刊网站www.mesnet.com.cn。

[1]陈浩杰.面向微小卫星的Smart-OSEK OS设计与实现[D].杭州:浙江大学,2013.

[2]董玮.面向无线传感网络的嵌入式操作系统设计[D].杭州:浙江大学,2010.

[3]Dunkels A,Schmidt O,Voigt T,et al.Protothreads:simplifying event-driven programming of memory-constrained embedded systems[C]//Proceedings of the 4th international conference on Embedded networked sensor systems,Acm,2006:29-42.

[4]Dunkels A,Schmidt O.Protothreads-lightweight stackless threads in c[EB/OL].[2014-05].http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.2455&rep=rep1&type=pdf.

[5]闫石,马潮.时间触发模式下的Protothreads设计应用[J].单片机与嵌入式系统应用,2009(1):15-17.

[6]罗光平.使用Protothread简化嵌入式系统中的顺序流控制[J].单片机与嵌入式系统应用,2007(11):19-21.

猜你喜欢
内核中断延时
多内核操作系统综述①
强化『高新』内核 打造农业『硅谷』
基于级联步进延时的顺序等效采样方法及实现
日光灯断电关闭及自动延时开关设计
基于嵌入式Linux内核的自恢复设计
Linux内核mmap保护机制研究
基于FPGA的中断控制器设计*
跟踪导练(二)(5)
千里移防,卫勤保障不中断
Two-dimensional Eulerian-Lagrangian Modeling of Shocks on an Electronic Package Embedded in a Projectile with Ultra-high Acceleration