RTX_Config.c 宏定义详解

设置RTX内核
RTX内核可以轻松地适应设计者创建的每一个运用程序。这个部分介绍如何为运用程序配置
RTX内核,包括: 
„RTX基础配置 
„RTX高级配置 
Copyright © Keil, An ARM Company. All rights reserved. 
RTX基础配置
在使用RTX的嵌入式应用程序中,必须对RTX内核进行基础配置。在文件夹
\Keil\ARM\Startup 中可以找到 RTX_Config.c ,它包含了所有的配置设置,并且
可随着不同的ARM设备而不同。在RTX_Config.c 中的配置选项可以:
„指定当前运行任务的数目; 
„指定使用用户自定堆栈任务的数目; 
„指定为每个任务分配堆栈的大小; 
„开启或是禁止堆栈校核; 
„指定CPU定时器作为系统定时器; 
„为选中的定时器指定输入的时钟频率;;  
„指定定时器节拍间隔; 
„开启或是禁止轮转任务调度; 
„为轮转任务调度指定时间片; 
„定义空闲任务操作; 
„指定用户定时器的数目; 
„为用户定时器回调函数指定代码; 
在RL-RTX库中没有默认的配置,因此,必须为每一个工程添加 RTX_Config.c配置文
件。
为了适应RTX内核的特性,必须修改RTX_Config.c 中的配置。
Copyright © Keil, An ARM Company. All rights reserved. 
任务
下面 #define说明RTX内核任务是如何设置的:
„OS_TASKCNT 标识同时处于活跃状态任务的最大数目,这包括了除了停止外的所有
状态(运行,等待或是就绪)。 
RTX内核利用该信息来为任务控制的变量预留存储池。在确保创建和运行的任务数不会
超过 OS_TASKCNT 的前提下,数目可以高于或是低于运用程序中定义的任务数目
(一个任务可在多个多个实例中运行)。
#define OS_TASKCNT 6 
„OS_PRIVCNT 标识带有用户提供栈的任务数目。 
默认情况下,RTX内核给每个任务分配一个固定大小的堆栈。然而,任务对堆栈
的需求是非常广泛的。例如,如果一个任务的局部变量包含大块的缓冲区,队列或是复
杂的结构,那么任务就需要更多的堆栈。如果有像这样的任务,需要的比分配的更多堆
栈,就有可能造成越界写入到相邻的任务了。这是因为任务的固定大小堆栈是公共系统
堆的一部分,而且是相互比邻的。这样就导致RTX内核的故障,并且很可能导致系统瘫
痪。显而易见的解决办法是增加固定的堆栈大小。然而,这样就给其他每一个任务都增
加了的大小,也许有些并不需要。为了避免这样的资源浪费,一个好的解决办法是,给
需要额外多堆栈的任务分配一个单独的用户设定堆栈。
在这种情况下,用户设定就意味着任务创建时,用户自己设定任务需要的堆栈存
储空间,而不是由内核自动分配。RTX内核采用 OS_PRIVCNT 使存储空间的利用最
优化。内核不会保留堆栈空间给用户设定堆栈大小的任务。
#define OS_PRIVCNT 0 
注意
„加上 OS_TASKCNT 用户任务,系统创建了两个系统任务 os_clock_demon 和 
os_idle_demon. 这两个任务经常是RTX内核所必需的。当前运行的任务总数是
OS_TASKCNT+2(用户任务的数量加上两个系统任务).。 
Copyright © Keil, An ARM Company. All rights reserved. 
堆栈大小
一个特殊任务的堆栈用法依赖于局部自动变量数量和子程序的数量。中断函数不使用
中断任务的堆栈。
„OS_STKSIZE 标识分配给每个任务的RAM数量。堆栈大小用U32(无符号整型)定
义。同时,系统转换定义的大小,并以字节为单位显示。以下的堆栈大小定义为400字
节。 
#define OS_STKSIZE 100 
在所有的上下任务的转换中,RTX内核在堆栈中存储所有的ARM寄存器。所有任务内
容的保存需要64K的堆栈空间。 
Copyright © Keil, An ARM Company. All rights reserved. 
堆栈检查
由于很多嵌套子程序的调用或是大量的自动变量的广泛使用,有可能导致堆栈资源耗
尽。
如果堆栈检查激活,内核可以发现堆栈耗尽问题并且运行os_stk_overflow() 堆栈
出错函数。运用程序将会在堆栈出错函数内挂起一个无止境的循环。变量 task_id 将会保
存出现堆栈问题的任务ID。可以通过活动任务调试对话框来查询任务名字。
解决这个问题的办法是通过在 配置文件中为所有的任务增加堆栈大小。如果只有一个
任务需要大堆栈并且RAM有限,可以通过 创建带有用户设定堆栈空间的任务。
„OS_STKCHECK 激活堆栈检查算法,1表示激活,0表示禁止,默认是激活。
#define OS_STKCHECK 1 
„激活堆栈检查会轻微地降低内核的性能,因为当每进行任务切换时,内核需要运行额外
的代码进行堆栈检查。 
Copyright © Keil, An ARM Company. All rights reserved. 
硬件时钟
以下的 #defines 说明RTX内核的硬件时钟是如何被设置的:
„S_TIMER 指定芯片时钟作为实时系统的基本时钟。其发送了一个周期的中断来唤醒
时间纪录系统任务。用户可以选择使用哪个计时器来实现这个目的,0表示计时器0,
而1则表示选择计时器1。
#define OS_TIMER 1 
„OS_CLOCK 为选中的时钟指定输入时钟频率。值的计算是: f(xtal) / VPBDIV.在
CPU时钟为60 MHz 并且 VPBDIV = 4 时是 15 MHz。
#define OS_CLOCK 15000000 
„OS_TICK 指定时钟脉冲间隔,单位是µsec。建议值是1000 到 100000。产生的间
隔为1 ms 到 100 ms,默认的设置为10ms。. 
#define OS_CLOCK 10000 
Copyright © Keil, An ARM Company. All rights reserved. 
多任务轮转
以下的 #define 指定RTX内核的 多任务轮转如何被设置:
„OS_ROBIN 激活多任务轮转,1表示运行,0表示禁止,默认是激活。
#define OS_ROBIN 1 
„OS_ROBINTOUT 标识轮转时间片。这是分配给当前运行任务的时间片。当时间片
用完,当前运行任务被中止,下一个就绪任务被重新开始。OS_ROBINTOUT  被用
来表示系统的节拍数。. 
#define OS_ROBINTOUT 5

空闲任务
当没有任务就绪,RTX内核执行 idle task 。空闲任务是一个简单的循环,不执行
任何操作,只等待时钟中断来选择就绪的任务。
„os_idle_demon() 标识IDLE 指令是否在空闲任务中运行,默认设置是OFF,禁止
CPU进入空闲任务。可以在这儿添加代码,当没有任务就绪时就可以执行这段代码。 
以下是包含在库中的os_idle_demon() 默认函数代码的一个示例:
/*--------------------------- os_idle_demon ------------------------void os_idle_demon (void) __task { 
/* The idle demon is a system task. It is running when no other t
/* ready to run (idle situation). It must not terminate. Therefor
/* should contain at least an endless loop. 
for (;;) { 
/* HERE: include here optional user code to be executed when no t

} /* end of os_idle_demon */ 
注意
„如果使用ULINK进行调试,就不能使用IDLE模式。在一些ARM设备中,空闲模式可以
阻塞JTAG接口。 
Copyright © Keil, An ARM Company. All rights reserved. 
用户定时器
在运行时间时,可以创建或是结束 用户定时器,但必须指定运行的用户定时器的最
大值以及os_tmr_call() 函数的代码。
„OS_TIMERCNT创建用户定时器时将指定定时数目。如果用户定时器没有被采用,
设置其值为0。这个消息被RTX内核用来为时钟控制块保留存储空间。
#define OS_TIMERCNT 5 
„当用户定时器终止时,回调函数os_tmr_call()被调用,其作为一个空函数由 
RTX_Config.c 配置文件提供,使用时必须依据需要进行修改。 
当定时器被创建时,info 作为参数传递给 os_tmr_create()函数。
/*--------------------------- os_tmr_call ----------------------void os_tmr_call (U16 info) { 
/* This function is called when the user timer has expired. 
/* Parameter "info" is the parameter defined when the timer w
/* HERE: include here optional user code to be executed on ti
info = info; 
} /* end of os_tmr_call */ 

硬件资源需求 
为了运行运行RTX内核,需要从ARM设备中获取以下硬件资源:
„外围时钟 产生周期脉冲,最好是使用具有自动重载功能的外围时钟。RTX也提供具
有手动重载时钟(计数)的计时器。然而,在长时间的运行中,这将导致隐忧和错误。
RTX需要一个向上计时时钟. 如果使用时向下计时的时钟,必须进行转换。 
„时钟中断  中断一个任务的运行并启动系统任务调 os_clock_demon()。 
„强制中断  当 isr_ 函数运行时,强制一个时钟中断。如果 isr_ 函数被调用,当调用
中断结束后,内核立即强制产生一个时钟中断。强制时钟中断激活任务调度。此时一个
任务可能已经就绪,如果其比当前运行的任务有较高的优先级,则抢占就会产生。 
Copyright © Keil, An ARM Company. All rights reserved. 
配置宏
所有硬件相关的配置选项都被用配置宏来描述。其中,一些仅被用于简化代码( 如:
OS_TID_和OS_TIM_)。这些宏并不都在所有的配置文件中使用。使用配置宏可以轻松
地定制ARM设备提供的不同外围设备定时器的配置文件。
以下的配置宏包括:(以Philips LPC21xx设备定时器0为例) 
„OS_TRV: 该宏定义了外围计时器的重装值。外围计时器计算出一个重装值,当达到
0时,就产生一个中断。重装值被用于计算一个要求的间隔长度(比如10ms)。
#define OS_TRV ((U32)(((double)OS_CLOCK*(double)OS_TICK)/1E
„OS_TVAL:该宏被用于为一个 count-up计时器读取当前的计时器值。RTX内核用
其来确定一个中断是否是周期计时中断,还是软件强制中断。. 
#define OS_TVAL T0TC /* Timer Value */ 
对于一个减法数计时器,用户必须转换其返回值。以下是一个16位减法数计时器的例
子:: 
#define OS_TVAL (0xFFFF - T0VAL) /* Timer Value */ 
„OS_TOVF :定于一个计时器溢出标志。RTX内核将其同OS_TVAL宏一起使用,用
来区别周期计时中断和强制计时中断。
#define OS_TOVF (T0IR & 1) /* Overflow Flag */ 
„OS_TREL() :当计时器溢出的 时候,该宏定义一个代码系列来重装周期计时器。而
当一个周期计时器有自动重装功能的时候,该宏不起作用。
#define OS_TREL() ; /* Timer Reload */ 
„OS_TFIRQ() :定义一个代码系列来执行强制计时中断。如果周期计时器不允许手
动设置溢出标志时,则必须是个软件触发中断。如果可以进行手动设置,该宏必须设定
一个外围计时器溢出标志,用来产生计时中断。 
#define OS_TFIRQ() VICSoftInt |= OS_TIM_; /* Force Interrupt
„OS_TIACK() :应答来自计时中断函数产生的中断,释放计时器中断逻辑。. 
#define OS_TIACK() T0IR = 1; /* Interrupt Ack */ \
VICSoftIntClr = OS_TIM_; \
VICVectAddr = 0; 
„OS_TINIT() :该宏用于初始化外围计时器/计数器,设置计时模式并设定计时器重
装功能。时钟中断也可被外设时钟中断激活。代码在 os_sys_init() 函数中执行。 
#define OS_TINIT() T0MR0 = OS_TRV; /* Initialization */ \
T0MCR = 3; \
T0TCR = 1; \
VICDefVectAddr = (U32)os_def_interrupt; \
VICVectAddr15 = (U32)os_clock_interrupt; \
VICVectCntl15 = 0x20 | OS_TID_; 
„OS_LOCK() :该宏禁止计时中断,被用于避免中断系统任务调度,包括周期计时中
断和强制中断都被屏蔽。代码在 tsk_lock() 函数中执行。
#define OS_LOCK() VICIntEnClr = OS_TIM_; /* Task Lock */ 
„OS_UNLOCK() :该宏允许计时中断,包括周期计时中断和强制中断。代码在 
tsk_unlock() 函数中执行。 
#define OS_UNLOCK() VICIntEnable |= OS_TIM_; /* Task Unlock */

你可能感兴趣的:(linux,rtx)