引 言
在VxWorlks中,定时器机制的实现是建立在时钟基础之上的。可根据不同的要求选用不同的定时机制,如taskDelay()、WatchDog、辅助时钟。前两种定时都是基于系统时钟的。
taskDelay()是最简单的延时方法。它的单位是tick,所以其延时精度并不高,但对于延时10 ms以上的系统足够了。利用taskDelay(),可以将调用的任务从就绪态转到睡眠态,但是不能用于中断服务程序中。另外,可以通过调用taskDelay(0),将CPU交给系统中其他相同优先级的任务。
看门狗定时器作为系统时钟中断服务程序的一部分来维护。因此,与看门狗定时器相联系的函数运行在系统时钟中断级,延时单位为tick。如果应用程序需要多个看门狗函数,则可使用wdCreate()为每个需求产生独立的看门狗ID,因为对于给定的看门狗ID,只有最近的wdStart()有效。利用看门狗定时器,调用的任务不会被阻塞,因为wdStart()调用是立即返回的。但它也一般只适用于延时10ms以上的系统。
如果在实际时需要更高精度的定时(如1 ms),那么采用辅助时钟就是非常可取的一种方法。一般在VxWorks系统的BSP中,都没有配置辅助时钟,本文详细介绍辅助时钟的配置及使用方法,以便在实际中灵活运用。
1 AT91RM9200工业平台的时钟和定时器
本文的研究是基于AT91RM9200工业平台的,因此首先需要对此平台下的时钟及定时器进行介绍。
AT91RM9200提供了2个3通道16位定时器/计数器(TC)。3个通道虽然独立,但操作相同,每个通道均为用户可配置,包括3个外部时钟输入(XC0、XCl或XC2),5个内部时钟输入(TIMER_CLOCKl、TIMER_CLOCK2、TIMER CLOCK3、TIMER_CL0CK4、TIMER_CLOCK5),以及2个可由用户配置的多功能输入/输出信号。另外,每个通道可工作在两种不同模式下,即捕获模式和波形模式。其中,捕获模式提供信号测量,波形模式用来产生波形,可由TC通道模式寄存器的WAVE位编程设定。定时器/计数器框图如图1所示。
其中,如果选择通道信号时,XCO、XCl、XC2表示3个外部时钟输入;TIOA、TIOB表示作用于每个通道的2个多功能输入/输出信号;INT表示中断信号输出;SYNC表示同步输入信号。如果选择块信号时,TCLKO、TCLKl、TCLK2表示3个外部时钟输入;TIOAO~TIOA2,表示通道0~2的TIOA信号,TIOB0~TIOB2表示通道0~2的TI0B信号。
其中,5个内部时钟输入与主时钟(MCK)、慢速时钟(SLCK)及主时钟分频后时钟相关,如表1所列。
2 在VxWorks中辅助时钟的配置
在VxWorks操作系统中如果要使用辅助时钟,必须经过一定的配置才能使用。首先,需要在Vxworks组件或config.h中进行定义:
#define INCLUDE_AUX_CLK
如果不定义,那么辅助时钟是无法使用的。另外,在sysLib.C的sysHwlnit2函数中需要进行辅助时钟的初始化,即中断连接配置:
(void)intConnect(AUX_TIMER_INT_VEC,sysAuxClkInt,O)
辅助时钟和系统时钟的区别是:辅助时钟必须由用户提供ISR,但不允许在ISR中调用tickAnnounce(),否则会扰乱系统时钟的机制。
辅助时钟的配置可以按照installDir/target/drv/tim—er/templateTimer.C中的函数模板来进行修改,在本文中使用的驱动程序是At91Rm9200timer.c,头文件为At91Rm9200timer.h。在此文件中进行的修改需要根据所依赖的具体芯片来进行,即需要参考AT91RM9200芯片数据手册。
与辅助时钟相关的函数有:sysAuxClkInt()、sysAux—ClkConnect()、sysAuxClkDisable()、sysAuxClkEnable()、sysAuxClkRateGet()和sysAuxClkRateSet()。其中,sysAuxClkRateGet()可以和sysAuxClkRateSet()视为一组。sysAuxClkRateGet()是通过sysAuxClkRateSet()函数设定的时钟频率进行读取的,而sysAuxClkRateSet()函数中时钟频率的设定则受AUX_CLK_RATE_MIN和AUX_CLK_RATE_MAX的限制。这个最大值和最小值需要进行定义,定义的位置可能不同,有的放在eonfig.h中,有的放在bsp.h中,本文的最大值和最小值放在Inte—grator.h中定义。接下来需要重点讨论的是sysAux-ClkInt()和sysAuxClkEnabel()这两个函数。
sysAuxClkInt()函数调用用户定义的中断处理函数,而用户调用的中断处理函数是由sysAuxClkConnect()函数来连接的。在调用中断处理函数之前,一定要先进行清除中断操作,如:
AMBA_TIMER_READ(AMBA_TIMER_T2SR(AMBA_TIMER_BASE),temp);
不然,CPU将一直陷入中断,不能做别的事情了。
其他大量的工作都是放在sysAuxClkEnble()函数中进行的。根据AT91RM9200的具体情况,选择5个内部时钟的其中之一,在此选择TIMER_CLOCK2;根据前面所提到的通道概念,选取第2个通道。必须和系统时钟区分开,不能同时选择一个内部时钟和同一个通道。
首先,需要判断电源管理对辅助时钟是否进行了配置,可以查看相关文件。如果没有进行配置,则需要如进行如下配置:
AT9l_SYS→PMC_PCER=l<<AT9lC_ID_TCl;
其次,必须先对AIC编程,再配置TC。
然后,需要对具体的寄存器进行控制操作,首先需要选择内部时钟,如图2所示。
对通道模式寄存器进行控制:
AMBA_TIMER_WRITE(AMBA_TIMER_T2MR(AMBA_TIMER_BASE),TIMER_CLOCK2| TC_CPCTRG);
通过TCCLKS位选择第2个内部时钟,并根据写入RC寄存器的定时器值进行RC比较触发使能。同时,需要对TC通道控制寄存器进行控制,写入计数器时钟使能命令和软件触发命令,如:
AMBA_TIMER_WRITE(AMBA_TIMER_T2CR(AMBA_TIMER_BASE),TC_CLKEN);
AMBA_TIMER_WRITE(AMBA_TIMER_T2CR(AMBA_TIMER_BASE),TC_SWTRG);
另外,由于采用RC寄存器触发使能,因此还需要对TC中断使能寄存器进行控制,写入RC比较中断使能信号,如:
AMBA_TIMER_WRITE(AMBA_TIMER_T2IER(AMBA_TIMER_BASE),TC_CPCS);
最后,需要执行中断使能操作,如:
AMBA_TIMER_INT_ENABLE(AUX_TIMER_INT_LVL);
一切配置好后,重新编译bootroFll和VxWorks镜像,启动VxWorks镜像;然后编写测试程序进行测试,验证辅助时钟是否配置成功。另外,可以通过逻辑分析仪查看辅助时钟的中断情况。辅助时钟驱动后,在应用程序中可以用sysAuxClkRateSet()函数动态设置系统辅助时钟每秒的中断数;sysAuxClkConnect()函数为系统辅助时钟中断指定ISR,并且由sysAuxClkEnable()函数使能时钟中断,去调用指定的ISR。
结 语
VxWorks提供系统辅助时钟机制的主要目的,是使用户在系统时钟之外多一种定时资源选择,并提供了管理手段。另外,VxWorks的某些辅助调试工具也可能要求使用系统辅助时钟。
辅助时钟的使用是通过提高节拍率来实现的,而提高节拍率意味着时钟中断产生得更加频繁,所以中断处理程序也会更频繁地执行。如此一来会给整个系统带来如下好处:
①更高的时钟中断解析度(resolution)可提高时间驱动事件的解析度;
②提高了时间驱动事件的准确度(accuracy)。