一种时间触发的多任务调度器设计
时间:06-07
来源:中电网
点击:
引 言
目前,嵌入式系统的硬件核心大致有两大类:一类是功能强大的嵌入式微处理器,使用这类产品的系统一般功能强大,多数使用嵌入式操作系统,往往与无线通信、互联网访问以及多媒体处理等复杂而强大的功能联系在一起;另一类是微控制器,它通常以某一种微控制器内核为核心,芯片内部集成ROM、RAM、定时器、串行口等各种必要功能和外设。出于成本和技术上的考虑,这类系统的软件开发还是基于处理器直接编写,没有配备多任务操作系统作为开发平台,也不需要将系统软件和应用软件完全分开处理。但在实际的应用中,很多时候也会面临同时应付多种外设、处理多个任务的要求,这就需要安排一个调度器来完成多任务的处理。
本文设计并实现了一种基于时间触发的多任务调度器。该调度器使用传递消息(message)的方式使得控制器在多个任务之间进行切换。因为消息和任务一一对应,一个消息触发一个任务,所以本文对两者不做详细区分。
1 嵌入式软件的两种触发方式
嵌入式系统中,通常采用两种本质上不同的调度方式:事件触发和时间触发。事件触发方式往往使用多级中断实现,其发生时间具有随机性;而时间触发方式则不同,它是通过一个全局时钟进行驱动的,系统的行为不仅在功能上确定,而且在时间上也是确定的。
1.1 事件触发方式存在的问题
如果多个中断源在随机的时间间隔内产生中断,则需要处理同时发生的多个事件。这样不但增加了系统复杂性,而且降低了对事件触发系统在所有情况下行为的预计能力。实际上,在同时有几个有效中断源的情况下,几乎不可能创建代码来正确处理所有可能的中断组合。中断事件不会丢失是存在于绝大多数嵌入式系统开发人员头脑中的一种错误观念,这往往给所开发的产品带来灾难性的后果。事件触发系统的开销是人们经常忽略的另一个问题。Alexander Metzner专门讨论了这种问题并得出结论:一个包含27个任务、采用RM调度算法的事件触发系统,CPU的实际利用率仅为18%。
1.2 时间触发方式的优点
Kopetz首先提出:使用基于时间触发的合作式调度器会使得系统有非常好的可预测性。因此,在某些与安全相关的应用系统中选用时间触发方式,设计人员能预先安排可控的顺序,保证一次只处理一个事件,提高系统的可靠性并减轻CPU的负荷。
2 时间触发调度器的设计
调度器的设计主要包括3个方面:消息队列、定时器和周期性任务调度。在调度器的实现中,将定时器的设置分离出来,并且定义不依赖于编译器的数据类型,通过修改这一部分可以轻松地将该调度器移植到多种硬件平台上使用。
2.1 消息队列的设计
图1中,消息队列MsgQue[]和定时队列TmrQue[]是调度器的核心数据结构。为了减少时钟中断中对它们的处理时间,还设置了2个队列--就绪索引队列RdIdx[]和定时索引队列TmrIdx[]。这4个队列都由静态数组实现。
消息队列存放应用程序发送的单次消息和延时处理的消息。消息的数据结构是:
定时队列TmrQue[]和定时索引队列TmrIdx[]一一对应。其中,定时队列中存放定时消息的延时时间;而相对应的TmrIdx[]项则指向定时消息在消息队列中的位置。
要发送消息时,使用函数vdStrtTmrTsk(INT16UTmValue,struct Msg*pOutMsg),将pOutMsg指向的消息结构放入队列MsgQue[]中。具体的做法是:从数组的第一项开始查找,找到空闲项放入新消息并将该项的状态设置成BUFF-USED;然后将此消息项对应的索引值放入RdIdx[]的第一个空闲项中等待调度。如果发送的是延时消息,则要使用vdStrtTmrTsk(INT16U TmValue,structMsg*pOutMsg)将延时时间放入TmrQue[]中,并使用对应的TmrIdx[]项指向对应的消息。
图1中MSG5对应的任务正在执行,MSG9是刚到期的定时消息,当前任务结束后就可以处理该消息。MSG7是未到期的定时消息,其他2个都是已就绪待处理的消息。
2.2 定时器的设计
调度器必须先设定一个默认的时间片,这并不是件简单的事。时间片过长会导致系统对交互行为的响应表现欠佳;时间片太短又会明显地增大调度器处理耗时,而留给任务运行的时间却很短。根据V850处理器在车载音响上的实际需要,选择4 ms作为时间片。
在V850处理器中使用TM0定时器来实现4 ms定时功能,可以计算出CR70的初值为156,程序实现如下:
在定时器的中断服务程序中,扫描定时队列TmrQue口。如果有延时到期的任务,则将其从定时队列中删除并放在就绪索引队列RdIdx[]中去。对定时器相关的操作涉及具体的平台,在不同平台上移植调度器时需要修改这一部分。
2.3 周期性任务的处理方法
对于该系统,周期长度必须是4 ms的整数倍。在每次时钟中断以后执行下面的函数,通过将要周期性执行的任务放入函数数组TskPatt[]()中就可以执行周期为8 ms、16 ms、32 ms、64 ms等周期性任务。
目前,嵌入式系统的硬件核心大致有两大类:一类是功能强大的嵌入式微处理器,使用这类产品的系统一般功能强大,多数使用嵌入式操作系统,往往与无线通信、互联网访问以及多媒体处理等复杂而强大的功能联系在一起;另一类是微控制器,它通常以某一种微控制器内核为核心,芯片内部集成ROM、RAM、定时器、串行口等各种必要功能和外设。出于成本和技术上的考虑,这类系统的软件开发还是基于处理器直接编写,没有配备多任务操作系统作为开发平台,也不需要将系统软件和应用软件完全分开处理。但在实际的应用中,很多时候也会面临同时应付多种外设、处理多个任务的要求,这就需要安排一个调度器来完成多任务的处理。
本文设计并实现了一种基于时间触发的多任务调度器。该调度器使用传递消息(message)的方式使得控制器在多个任务之间进行切换。因为消息和任务一一对应,一个消息触发一个任务,所以本文对两者不做详细区分。
1 嵌入式软件的两种触发方式
嵌入式系统中,通常采用两种本质上不同的调度方式:事件触发和时间触发。事件触发方式往往使用多级中断实现,其发生时间具有随机性;而时间触发方式则不同,它是通过一个全局时钟进行驱动的,系统的行为不仅在功能上确定,而且在时间上也是确定的。
1.1 事件触发方式存在的问题
如果多个中断源在随机的时间间隔内产生中断,则需要处理同时发生的多个事件。这样不但增加了系统复杂性,而且降低了对事件触发系统在所有情况下行为的预计能力。实际上,在同时有几个有效中断源的情况下,几乎不可能创建代码来正确处理所有可能的中断组合。中断事件不会丢失是存在于绝大多数嵌入式系统开发人员头脑中的一种错误观念,这往往给所开发的产品带来灾难性的后果。事件触发系统的开销是人们经常忽略的另一个问题。Alexander Metzner专门讨论了这种问题并得出结论:一个包含27个任务、采用RM调度算法的事件触发系统,CPU的实际利用率仅为18%。
1.2 时间触发方式的优点
Kopetz首先提出:使用基于时间触发的合作式调度器会使得系统有非常好的可预测性。因此,在某些与安全相关的应用系统中选用时间触发方式,设计人员能预先安排可控的顺序,保证一次只处理一个事件,提高系统的可靠性并减轻CPU的负荷。
2 时间触发调度器的设计
调度器的设计主要包括3个方面:消息队列、定时器和周期性任务调度。在调度器的实现中,将定时器的设置分离出来,并且定义不依赖于编译器的数据类型,通过修改这一部分可以轻松地将该调度器移植到多种硬件平台上使用。
2.1 消息队列的设计
图1中,消息队列MsgQue[]和定时队列TmrQue[]是调度器的核心数据结构。为了减少时钟中断中对它们的处理时间,还设置了2个队列--就绪索引队列RdIdx[]和定时索引队列TmrIdx[]。这4个队列都由静态数组实现。
消息队列存放应用程序发送的单次消息和延时处理的消息。消息的数据结构是:
定时队列TmrQue[]和定时索引队列TmrIdx[]一一对应。其中,定时队列中存放定时消息的延时时间;而相对应的TmrIdx[]项则指向定时消息在消息队列中的位置。
要发送消息时,使用函数vdStrtTmrTsk(INT16UTmValue,struct Msg*pOutMsg),将pOutMsg指向的消息结构放入队列MsgQue[]中。具体的做法是:从数组的第一项开始查找,找到空闲项放入新消息并将该项的状态设置成BUFF-USED;然后将此消息项对应的索引值放入RdIdx[]的第一个空闲项中等待调度。如果发送的是延时消息,则要使用vdStrtTmrTsk(INT16U TmValue,structMsg*pOutMsg)将延时时间放入TmrQue[]中,并使用对应的TmrIdx[]项指向对应的消息。
图1中MSG5对应的任务正在执行,MSG9是刚到期的定时消息,当前任务结束后就可以处理该消息。MSG7是未到期的定时消息,其他2个都是已就绪待处理的消息。
2.2 定时器的设计
调度器必须先设定一个默认的时间片,这并不是件简单的事。时间片过长会导致系统对交互行为的响应表现欠佳;时间片太短又会明显地增大调度器处理耗时,而留给任务运行的时间却很短。根据V850处理器在车载音响上的实际需要,选择4 ms作为时间片。
在V850处理器中使用TM0定时器来实现4 ms定时功能,可以计算出CR70的初值为156,程序实现如下:
在定时器的中断服务程序中,扫描定时队列TmrQue口。如果有延时到期的任务,则将其从定时队列中删除并放在就绪索引队列RdIdx[]中去。对定时器相关的操作涉及具体的平台,在不同平台上移植调度器时需要修改这一部分。
2.3 周期性任务的处理方法
对于该系统,周期长度必须是4 ms的整数倍。在每次时钟中断以后执行下面的函数,通过将要周期性执行的任务放入函数数组TskPatt[]()中就可以执行周期为8 ms、16 ms、32 ms、64 ms等周期性任务。
- 高性能嵌入式ARM MPU在医疗电子系统中的设计应用(05-12)
- 嵌入式技巧:ARM的三种中断调试方法的介绍(05-13)
- 关于嵌入式系统的软硬件协同设计(05-13)
- 多路嵌入式H.264视频服务器的设计详解(06-04)
- 基于ARM7的轨道检测仪的嵌入式系统设计(06-22)
- 针对复杂嵌入式应用的创新处理器实现方法(07-11)