TI-RTOS Kernel User‘s Guide:5---Timing Services

本章介绍计时模块。

5.1定时概述

在SYS/BIOS和XDCtools中,有几个模块涉及计时和时钟相关服务:

(1) ti.sysbios.knl.Clock模块:负责内核用来跟踪时间的周期性系统刻度。所有需要超时参数的SYS/BIOS api都以Clock ticks的形式解释超时。时钟模块用于调度以时钟刻度指定的间隔运行的函数。

(2) ti.sysbios.hal.Timer 模块:为使用定时器外设提供了一个标准接口。它隐藏定时器外设的任何目标/设备特定特征。定时器的目标/设备特定属性由ti.sysbios.family.xxx.Timer模块(例如ti.sysbios.family.c64.Timer)支持。您可以使用Timer模块选择一个计时器,在计时器到期时调用tickFxn。

(3) ti.sysbios.hal.Seconds 模块:提供了一种维护当前时间和日期的方法,由1970年(Unix纪元)以来的秒数定义。该模块生成一个自定义time()函数,该函数调用Seconds_get(),覆盖C标准库的time()函数。详见5.4节。

(4)xdc.runtime.Timestamp 模块:为基准测试代码和向日志中添加时间戳提供了简单的时间戳服务。该模块在SYS/BIOS中使用目标/设备特定的TimestampProvider来控制时间戳的实现方式。详见5.5节。

5.2Clock

 ti.sysbios.knl.Clock模块负责内核用来跟踪时间的周期性系统刻度。所有需要超时参数的SYS/BIOS api都以Clock ticks的形式解释超时.默认情况下,Clock模块使用ti.sysbios.hal.Timer模块创建一个计时器来生成系统刻度,这基本上是对Clock_tick()的周期性调用。Clock模块可以通过以下配置语句配置为不使用定时器:

ti.sysbios.knl.Clock.tickSource = Clock.TickSource_USER
 or
ti.sysbios.knl.Clock.tickSource = Clock.TickSource_NULL

系统滴答的周期由配置参数Clock.tickPeriod设置,以微秒为单位。

Clock_tick()和tick周期的使用如下:

(1)如果 tickSource是 Clock.TickSource_TIMER (默认),Clock 用ti.sysbios.hal.Timer 创建计时器产生系统滴答,是对Clock_tick()的周期性调用。Clock 用 Clock.tickPeriod 创建计时器,使用不同计时器可改变 Clock.timerId 。

(2)如果 tickSource是 Clock.TickSource_USER,应用程序必须从用户中断中调用Clock_tick(),并将tickPeriod设置为用户中断的近似频率(以微秒为单位)。

(3)如果 tickSource是 Clock.TickSource_NULL,不能调用任何带有超时值的SYS/BIOS  APIs,也不能调用任何时钟 APIs。仍可以使用Task模块,但不能调用需要超时的 APIs,如Task_sleep()。Clock.tickPeriod 值在此配置中无效。

Clock_getTicks()获取自启动以来发生的时钟滴答数,返回值达到32位存储的最大值后归零。

Clock模块提供 APIs 去启动,停止和重新配置滴答,这些APIs运行在运行时改变频率,不可重入,需要 gates 保护。

Clock_tickStop() 调用Timer_stop()停止生成时钟滴答的计时器。

Clock_tickReconfig()在内部调用Timer_setPeriodMicroseconds()来重新配置计时器。如果在当前CPU频率上计时器不支持Clock.tickPeriod,Clock_tickReconfig()会失败。

Clock_tickStart()调用Timer_start()重新启动用于生成时钟滴答的计时器。

Clock模块允许您创建Clock对象实例,这些实例引用了当在Clock ticks中指定的超时值过期时运行的函数。

所有时钟函数都在Swi上下文中运行。Clock模块自动创建一个Swi供其使用并在该Swi中运行Clock函数。时钟使用的Swi优先级可在 Clock.swiPriority配置。

使用Clock_create()动态创建时钟实例。函数和非零超时值作为 Clock_create()参数,函数时超过超时值时调用,超时值用于计算第一个超过时间。对于单次时钟实例,超时值用于计算单个过期时间,周期为零。对于周期性时钟实例,超时值用于计算第一个过期时间;period值(参数的一部分)在第一次过期后使用。

时钟实例(一次性和周期性)可以通过调用Clock_start()和Clock_stop()来停止和重新启动。Clock_tickStop()停止用于时钟滴答生成的计时器,Clock_stop()只会停止一个时钟对象实例,调用Clock_start()时重新计算过期值。clock_start()和Clock_stop()可以在任何上下文中调用,除了main()开始之前的程序启动。Clock模块提供Clock_setPeriod(), Clock_setTimeout()和Clock_setFunc() 等 APIs来修改已经停止的时钟实例的属性。

这个C语言示例展示了如何创建一个Clock实例。该实例是动态的(重复运行)并自动启动。它每5次运行myHandler函数。将用户参数(UArg)传递给函数。

Clock_Params clockParams;
Clock_Handle myClock;
Error_Block eb;
...
Error_init(&eb);
Clock_Params_init(&clockParams);
clockParams.period = 5;
clockParams.startFlag = TRUE;
clockParams.arg = (UArg)0x5555;  //??
myClock = Clock_create(myHandler1, 5, &clockParams, &eb);
if (myClock == NULL) {
 System_abort("Clock create failed");
}

这个示例配置脚本创建一个具有与前面示例相同属性的Clock实例。

var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var clockParams = new Clock.Params();
clockParams.period = 5;
clockParams.startFlag = true;
clockParams.arg = (UArg)0x5555;
Program.global.clockInst1 = Clock.create("&myHandler1", 5, clockParams);

这个C语言示例使用了一些Clock api来打印关于Task睡眠时间的消息

UInt32 time1, time2;
. . .
System_printf("task going to sleep for 10 ticks... \n");
time1 = Clock_getTicks();
Task_sleep(10);
time2 = Clock_getTicks();
System_printf("...awake! Delta time is: %lu\n", (ULong) (time2 - time1));

这个C语言示例使用了一些Clock api来降低Clock模块的频率

BIOS_getCpuFreq(&cpuFreq);
cpuFreq.lo = cpuFreq.lo / 2;
BIOS_setCpuFreq(&cpuFreq);
key = Hwi_disable();
Clock_tickStop();
Clock_tickReconfig();
Clock_tickStart();
Hwi_restore(key);

5.3Timer Module

 ti.sysbios.hal.Timer模块提供一个使用定时器外设的标准接口,这个模块将在8.3节中详细描述,它是硬件抽象层(HAL)包的一部分。定时器可以配置为单次定时器或连续定时器,周期可以是定时器计数或微秒为单位。

5.4Seconds Module

 ti.sysbios.hal.Seconds模块提供了一种方法来设置和获取从1970年1月1日00:00:00 GMT (Unix纪元)开始经过的秒数。如果特定设备的Seconds模块不可用,使用ti.sysbios.hall.SecondsClock 模块作为Seconds委托。SecondsClock内部使用Clock模块周期性地增加秒数,如这些配置命令使Seconds模块使用ti.sysbios.hall.secondsclock模块:

Seconds = xdc.useModule('ti.sysbios.hal.Seconds');
var SecondsProxy = xdc.useModule('ti.sysbios.hal.SecondsClock'); 
// Seconds模块的APIs :
Void Seconds_set(UInt32 seconds);  //初始化seconds计数或 更新与重置
UInt32 Seconds_get(Void);  //至少执行一次Seconds_set,否则Seconds_get无意义,不可重入

Seconds模块包含一个time()函数,该函数调用Seconds_get(),这将覆盖C标准库time()函数。可以将此time()函数与C标准头文件time.h中的其他时间函数结合使用,以可读格式查看当前日期和时间。

下面的例子初始化Seconds模块,设置日期,获取当前日期,并以人类可读的格式显示当前时间和日期:

#include <time.h>
#include <ti/sysbios/hal/Seconds.h>
UInt32 t;
time_t t1;
struct tm *ltm;  //??
char *curTime;

/* set to today’s date in seconds since Jan 1, 1970 */
Seconds_set(1412800000); /* Wed, 08 Oct 2014 20:26:40 GMT */

/* retrieve current time relative to Jan 1, 1970 */
t = Seconds_get();

/* Use overridden time() function to get the current time. Use standard C RTS library
 *  functions with return from time().Assumes Seconds_set() has been called as above */
t1 = time(NULL);
ltm = localtime(&t1);
curTime = asctime(ltm);
System_printf("Time(GMT): %s\n", curTime);

一些编译器运行时库,包括TI的,time()函数返回自1900年1月1日以来经过的秒数。在这种情况下,Seconds模块的time()函数为Seconds_get()返回的值添加偏移量,以便与运行时支持库中的其他api保持一致

5.5Timestamp Module

xdc.runtime.Timestamp模块提供时间戳服务,Timestamp模块可用于对代码进行基准测试和向日志中添加时间戳。对Timestamp模块函数的调用被转发到特定于平台的TimestampProvider实现。到Timestamp模块的包路径是xdc.runtime.Timestamp,所以SYS/BIOS应用程序应该包含以下#include语句:

#include <xdc/runtime/Timestamp.h>
//配置文件应包含下面的模块
var Timestamp = xdc.useModule('xdc.runtime.Timestamp');
//SYS/BIOS中的时间撮APIs 
Timestamp_get32()     // 返回32位时间戳 
Timestamp_get64()     // 返回64位时间戳
Timestamp_getFreq()   // 以Hz为单位获取时间戳计时器的频率,可以使用此函数将时间戳值转换为实时单位

如果你想要一个独立于平台的Timestamp版本,你可以使用TimestampStd模块,它使用ANSI C的clock()函数。

特定平台的TimestampProvider模块位于ti.sysbios.family包中。如ti.sysbios.family.msp430,TimestampProvider 和 ti.sysbios.family.arm.m3.TimestampProvider。大多数TimestampProvider模块都有配置参数,可以使用这些参数来控制硬件时钟源和时间戳计数器溢出时的行为。

这个例子计算了将时间戳增量与CPU周期关联起来所需的因子:

Types_FreqHz  freq1;   /* Timestamp frequency */
Types_FreqHz  freq2;   /* BIOS frequency */
Float         factor;         /* Clock ratio cpu/timestamp */
Timestamp_getFreq(&freq1);
BIOS_getCpuFreq(&freq2);
factor = (Float)freq2.lo / freq1.lo;
System_printf("%lu\t%lu\t%lu\t Timestamp Freq, BIOS Freq, Factor\n", 
                   freq1.lo, freq2.lo, (UInt32) factor);

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值