实时系统RTX之理解一

文献来源:http://wzhyblog.yo2.cn/articles/%e5%ae%9e%e6%97%b6%e7%b3%bb%e7%bb%9frtx%e5%ae%98%e6%96%b9%e6%96%87%e6%a1%a3%e4%b8%ad%e6%96%87%e7%bf%bb%e8%af%91.html#comment-26472

 

首先对且歌且行 表示感谢!

新手看这个文档,可以按以下顺序阅读:Welcome to IntervalZero-->Using the RTX SDK-->Using RTX Runtine-->Using RTX Tools-->Developing RTSS Applications-->Debugging RTSS Applications,这样比较好理解一些,本中文翻译也是按照这个顺序发布。

 

 

实时系统RTX官方文档中文翻译_2

Using the RTX SDK_1

本文档包括以下内容:

=======================================================

理解RTX特点

RTX介绍

RTX所定义的“实时”为硬实时(hard real-time)。

尽管RTX给Windows带来了无与伦比的实时性,但有两个方面需要全面认识清楚:

1. 因为最坏响应时间这个指标非常有意义,开发者和用户必须仔细选择他们的系统。不同的板卡经销商,尤其是视频卡经销商,在价格、各部分和确定性动作之间作了不同的权衡。使用RTX性能分析工具,开发者和用户可以选择能够满足他们需求的系统。

2. 开发者必须在应用中合理使用RTX。否则RTX可能会提升很少的功能,也可能影响其他Windows程序的运行,甚至会导致系统回环不稳定。


RTX架构

RTX向Windows添加一个实时子系统,即RTSS(见上图)。RTSS从概念上类似于其他Windows子系统(如Win32、POSIX、WOW、DOS),支持自己的运行环境和API。但是RTSS在一个方面有点重要区别:不是使用Windows调度器,RTSS执行它自己的实时线程调度。更进一步,在一个单处理器环境中,所有的RTSS线程调度都发生在所有Windows调度之前,包括Windows管理的中断和延迟过程调用Deferred Procedure Calls (DPCs)。

实时进程间通讯

RTSS支持可以被其他RTSS或Win32进程控制的IPC对象;这使得实时程序与非实时程序之间可以简单和标准的进行通讯和同步。最后,RTX为RTSS程序提供了其他严格时序的服务——如时钟、定时器和中断管理。

HAL扩展

RTX包括一个有实时功能的HAL扩展。此扩展保持了RTSS和Windows之间的中断隔离。Windows不能接管由RTSS负责的中断(在中断控制器层),而在RTSS运行时Windows中断被接管。这个实时HAL扩展支持高分辨率的时钟和定时器,同时也支持Windows的非实时时钟和定时器。其他的一些特性包括:RTSS和Windows之间的软件中断机制、基本异常管理和大量确定性任务的增强。

单处理器和多处理器系统

多处理器系统上的RTX运行时,设计了一个独占处理器模型。在此模型中,RTSS在一个处理器上运行,而其余的处理器继续运行Windows。当Windows启动过程中,多处理器HAL获取最后一个逻辑处理器的控制,并为RTSS所保留。RTSS程序就可以被加载和运行于此独占的处理器之上。

不管是单处理器还是多处理器系统,软件的编写都是一样的。


RTX API

RTX API基于Win32。使得开发者可以借鉴Win32经验、基础代码和开发工具以加速硬实时程序的开发。Win32和RTSS程序都支持全部的RTX API,但是有不同的响应时间和性能特点。

1. Win32 and Real-Time API

RTX支持Win32 API的一个子集,加附加了一个特殊的实时函数集,即RTAPI(实时API)。RTAPI函数在函数名的最前面都有标识“Rt”,一些RTAPI函数只是在标识头方面与Win32不同,而有一些则是RTX所特有的,如中断管理函数。RTX API仔细挑选了对实时应用有关的函数,而刻意忽略了一些对实时编程用处不大的函数(如GUI相关的函数调用)。一个期望的目标是大多数程序包含至少两个同时工作的部分——一个是基于Win32的进程(利用GUI和其他的Win32-only函数),另一个是执行实时处理的基于RTSS的进程。

2. RTX可执行映像

RTX提供了三种类型的可执行映像:RTSS程序,RTSS DLL和RTDLL。RTSS程序等同于Win32程序。RTSS DLL是用来链接以提供一个导出函数库供其他RTSS程序使用的RTSS程序。RTSS DLL是纯RTSS程序,并且必须在调用它的RTSS程序之前被手工运行。RTDLL是被动的代码容器,在功能上与Win32 DLL类似,但在RTSS中运行。

3. 实时库

RTX也支持众多的实时库,并提供了一个基于MS VC++的C运行时库。RTSS程序可以静态链接这些库,以提供不支持的Win32函数。

4. Unicode

RTX支持Unicode程序。一个RTSS程序可以使用wmain()函数,并接受宽字节输入参数。对WCS家族函数的支持作为RTX支持的C运行时库的一部分引入进来。


中断延迟的原因和管理

中断延迟是实时系统开发人员普遍关注的问题。本小节检查其成因和RTX管理它们的技术。

软件原因

包括:

l PIC(可编程中断控制器programmable interrupt controller)或APIC(advanced programmable interrupt controller高级可编程中断控制器)级掌管(masking)中断。Windows内核和驱动通过HAL IRQL manipulation 调用来改变中断掌管。驱动从程序上掌管中断需要几个us。

l 处理器级掌管中断。Windows内核、HAL和一些系统中断可能会掌管中断最多达到100ms。

l 中断——处理overhead。

硬件原因

包括:

l 外围设备的总线“hijacking”。例如,一个视频卡可能会拖延CPU读取卡上面I/O空间寄存器的尝试。

l SCSI控制器的Burst DMA。

l Windows和应用程序引起的脏缓存(cache dirty)。

l 大多数系统,尤其是移动系统,外围设备可以在一个设定的时间之后进入低功耗状态,但是“唤醒”延迟对一个实时系统来说是无法忍受的。

l 使用SMI(System Management Interrupt系统管理中断)的电源管理特性导致最高为数百ms的延迟。

l 对于使用Intel Pentium M处理器的系统,Intel的SpeedStep技术可以根据负载的大小改变处理器速度。

RTX对中断延迟的管理

有以下几种方式:

l RTX通过隔离中断(通过RTX HAL扩展)屏蔽了PIC或者APIC级中断。

l Windows和其驱动不能禁用RTSS中断。

l 当RTSS运行时,所有Windows中断被接管。

RTX对Windows(非Vista)的电源管理

如果有RTSS程序运行在一个UP PIC系统上,包括RT-TCP/IP协议栈,RTX电源管理会阻止系统电源状态从工作状态(S0)到睡眠状态(S1-S5)的切换。一个消息会显示出来通知用户。在一个UP PIC系统上如果没有RTSS程序运行,那么这种切换将不会受到阻止。

在一个多处理器系统或者UP APIC系统中,如果RTSS被加载,则从工作状态(S0)到睡眠状态(S1-S5)的切换都将被阻止。

 

 

实时系统RTX文档中文翻译_3

Using the RTX SDK_2


进程和线程管理

进程和线程

RTSS和Win32进程和线程只能在他们自己的环境中获取进程和线程。

使用进程

以下内容讨论进程在RTSS和Win32环境中是如果运行的。

RTSS环境中的进程

一个运行在RTSS环境中的进程包括一些对象的句柄、进程地址空间、至少一个线程和一个可执行文件。当一个进程被创建时,RTSS执行以下任务:

l 像加载驱动一样加载进程的可执行文件

l 从非分页池中分配中进程堆(process heap)

l 创建主线程

一个进程可能通过以下方法中的任一一个来启动:

l 在系统启动时像加载驱动一样加载它(使用RTSSrun /b)

l 从命令行中运行RTSS可执行文件

l 从Win32程序中启动RTSS进程

以下情况任一一个发生时,进程退出:

l 最后一个线程退出

l 一个线程中调用了ExitProcess

l 使用RTSSkill或者RTSS Task Manager杀掉

Win32环境中的进程

当运行在Win32环境中的进程调用一个RTAPI时,它就开始和RTX进行交互。然后RTX可能会从此进程中分配资源、改变其优先级、执行和它Windows32进程状态相关的其他操作。可以与RTX进行交互的Win32的 进程数是动态的,取决于系统的配置和资源。

使用线程

CreateThread 函数可以创建一个RTSS或者Win32线程,这取决于当前进程运行在哪个环境。使用CreateThread可以固定的指明栈的大小。返回的句柄和线程ID只在CreateThread调用者的环境中有效。例如,一个Win32进程不能操作一个RTSS线程的优先级,因为此线程的句柄只在RTSS环境中有效。不过,你可以使用RTX IPC机制(例如mutex objectssemaphoresevents, 和 shared memory)在Win32和RTX进程与线程之间进行同步和通讯。

RTSS环境中的线程

RTSS线程是RTSS环境中的运行单元。一个准备运行(ready-to-run )的RTSS线程在所有Windows线程之间接受调度。一个RTSS线程会在它放弃CPU之前一直运行。当以下情况时一个线程放弃CPU:

l 等待一个同步对象

l 降低自己的优先级或提高另外一个线程的优先级

l 暂停(suspend)它自己

l 从定时器或中断处理程序中返回

l 使用参数0调用了Sleep

l 当一个时间定量设定时收到一个通知

l 被一个更高优先级中断

一个进程的初始线程有8KB大小的栈。

线程优先级

RTSS环境

RTSS环境没有直接直接的优先类别(priority classes),故所有RTSS进程的线程都会使用唯一的线程优先类别来结束对CPU的使用。一个RTSS线程有128个不同的优先级。任何优先级的线程都依照优先命令和“先进先出”命令进行运行。如果一个时间量被设为0,则线程会运行结束。如果时间量被设为其他值,一个线程会运行至指定的这个时间,然后将CPU交给拥有相同优先级的另外一个线程。RTSS调度机制执行优先级反转和顺序优先级(deferred priority)降低机制来避免优先级反转。

例如,RTX互斥锁对象支持一个1级优先级提升机制。如果一个更高优先级的线程对一个低优先级的线程拥有的互斥锁对象调用了WFSO,则互斥锁对象拥有者的优先级就被提升到和那个更高优先级的线程一样的优先级。尝试降低互斥锁对象拥有者的线程的优先级会直到此线程释放了互斥锁之后才顺序执行。

Win32环境

一个与RTX联系的Win32程序以普通优先类别启动,然而,一旦此程序调用了RtGetThreadPriorityRtSetThreadPriority或其他实时优先级函数,其优先类别就会变成实时优先类别。

表1-RTSS到Win32的线程优先级映射,显示了当RtSetThreadPriority 被一个Win32程序调用时,RTSS符号优先级命令是如何转换到一个普通Windows 2000优先级请求的。

表 1. RTSS到Win32的线程优先级映射

RTSS Symbolic Priority NameRTSS ValueWindows 2000 Symbolic Priority Name for Real-Time Priority ClassWin32 Value
RT_PRIORITY_MIN0THREAD_PRIORITY_IDLE16
RT_PRIORITY_MIN + 11THREAD_PRIORITY_LOWEST22
RT_PRIORITY_MIN + 22THREAD_PRIORITY_BELOW_NORMAL23
RT_PRIORITY_MIN + 33THREAD_PRIORITY_NORMAL24
RT_PRIORITY_MIN + 44THREAD_PRIORITY_ABOVE_NORMAL25
RT_PRIORITY_MIN + 5...+ 1265...126THREAD_PRIORITY_HIGHEST26
RT_PRIORITY_MAX127THREAD_PRIORITY_TIME_CRITICAL31

表一显示,例如,RTX层面的RtSetThreadPriority(Thread, RT_PRIORITY_MIN + 1)会对应的Win32调用SetThreadPriority(Thread, THREAD_PRIORITY_LOWEST)。

从RT_PRIORITY_MIN+5 到 RT_PRIORITY_MIN+126 之间的值会将线程设置为THREAD_PRIORITY_HIGHEST,而RT_PRIORITY_MAX 则会将优先级设置成 THREAD_PRIORITY_TIME_CRITICAL。这些映射被设计为在线程优先级之间保护相近的要求。

如果一个Win32程序调用了RtGetThreadPriority,会返回调用RtSetThreadPriority指定的实时优先级。然而有一些限制。最可能困惑的一点是混合调用RtSetThreadPriority 和 SetThreadPriority(mixed)时。当使用一个双重线程句柄(a duplicated thread handle)时,函数库不一定都会理解RTSS优先级,并且为返回RT_PRIORITY_MIN+5,而不是RT_PRIORITY_MIN+6 和 RT_PRIORITY_MIN+126之间的优先级。设置和获取自己的RTSS优先级的线程(如使用GetCurrentThread来指明的线程)将会一直获得设定的RTSS优先级。

Win32程序应该为Win32线程使用Rt进行优先级调用,以在等待一个RTSS同步对象时要求不是最低的RTSS调度优先级。例如,一个拥有RTSS RT_PRIORITY_MAX优先级的Win32线程将会拥有一个互斥锁对象,而一个拥有比RT_PRIORITY_MAX优先级低的RTSS线程想要同一个互斥锁对象时就只能等待。

表2-Win32向RTSS线程优先级的映射,显示了调用Win32“设定”和“获取”线程优先级时在RTSS环境中的对应。表2的描述是表1的反转。

Table 2. Win32 to RTSS Thread Priority Mapping

Windows 2000 Symbolic Priority Name for Real-Time Priority ClassValueRTSS Symbolic Priority NameValue
THREAD_PRIORITY_IDLE16RT_PRIORITY_MIN0
THREAD_PRIORITY_LOWEST22RT_PRIORITY_MIN + 11
THREAD_PRIORITY_BELOW_NORMAL23RT_PRIORITY_MIN + 22
THREAD_PRIORITY_NORMAL24RT_PRIORITY_MIN + 33
THREAD_PRIORITY_ABOVE_NORMAL25RT_PRIORITY_MIN + 44
THREAD_PRIORITY_HIGHEST26RT_PRIORITY_MIN + 55
THREAD_PRIORITY_TIME_CRITICAL31RT_PRIORITY_MAX127

在THREAD_PRIORITY_IDLE 和 THREAD_PRIORITY_HIGHEST之间没有额外的优先级。If you need finer grain priorities, you should use the RTSS priority spectrum instead. Just as in Win32, this value specifies a thread priority that is higher than all other priorities.

Win32环境编程考虑

一个Win32 RTX 链接的程序在启动时处在普通的优先级类别,直到调用了RtGetThreadPriorityRtSetThreadPriority, 或其他实时优先级函数,则此程序的优先级类别就变成了实时优先级类别。

这是大多数应用所期待的结果,因为它给进程赋予了最大可能的实时性能。但是,当Win32线程有GUI组件时就引起了问题。当一个处在 REALTIME_PRIORITY_CLASS 优先级的线程同Windows GUI(并链接到rtapi_win32.lib)交互时,slowdowns and lock-ups occur. 在编写拥有GUI组件的Win32程序时你可以通过首先在程序中调用:

SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS)

来避免这个问题。

提示: 如果你像上面讨论的那样设定你程序的优先级,则其GUI如果不是在最上层窗口时可能不会刷新其数据。


系统内存管理

系统内存分配

进程必须频繁地分配额外的内存以保证它们的运行。RTX内存分配机制通常会分配已经锁定的内存,以避免任何可能导致页失败的延迟机会。

内存分配API

以下API可以用来获取RTX系统内存分配服务:

RtAllocateLockedMemory从物理内存后部分配内存并锁定,然后将内存映射到进程的虚拟地址空间中。

RtFreeLockedMemory释放先前分配的锁定内存区域。

RTSS和Win32编程考虑

锁定内存通常从一个非分页内存池中分配并由Windows维护。这个内存池相当小,并在系统启动后很快就会被Windows的其他驱动和子系统造成破碎。为了避免大容量分配的失败,你应该最小化它们(大容量分配)的使用,或保证它们在系统启动很短的时间内结束。

代码例程(RTX 锁内存分配函数调用)

见Code and File Examples中RTX Locked Memory Allocation Calls Programming Example。此例子证明了RTX锁内存分配函数调用的使用。

RTX Locked Memory Allocation Calls Programming Example

The following programming example demonstrates the use of RTX locked memory allocation calls.

#include <windows.h>

#include <stdio.h>

#include <rtapi.h>

static PVOID vAddress; // virtual memory address returned by RtAllocateLockedMemory

void main(void) {

ULONG size=4096; // bytes to allocate

// Allocate memory

vAddress = RtAllocateLockedMemory(size);

if (!vAddress) {

printf("/nFailure on RtAllocateLockedMemory/t");

printf("Error=%d/n", GetLastError());

break; // if this fails - no use to continue

}

else {

printf("/nSuccess on RtAllocateLockedMemory/n");

printf("Virtual memory address = 0x%08X/n", vAddress);

// Write to the memory

*vAddress= 0;

}

// Free memory

if (!RtFreeLockedMemory(vAddress)) {

printf("/nFailure on RtFreeLockedMemory(0x%08X)./t", Address);

printf("Error Code = %d/n", GetLastError());

}

else {

printf("Success on RtFreeLockedMemory(0x%X)./n", vAddress);

}

ExitProcess(0);

}

系统内存锁定

为避免页失败,并增强关键代码处的非可预见性延迟,实时程序需要锁定在内存中的数据和代码,包括在操作系统它本身的代码和数据。

进程锁定API

RtLockProcess 锁定一个进程的全部分页段到物理内存

RtUnlockProcess 解锁一个进程先前被锁定到物理内存的虚拟地址空间的所有段

RtCommitLockProcessHeap 记录并锁定进程的堆(heap)

RtCommitLockHeap记录并锁定指定的堆(heap)

RtCommitLockStack记录并锁定进程的堆栈(stack)

RTSS环境编程考虑

默认地,RTSS环境中所有进程和内存对象都被锁定到物理内存中以避免页失败。RtLock* (Process, Heap, Stack)函数在RTSS环境中会一直以成功结束,但并没有执行实际操作。

Win32环境编程考虑

除非显式的锁定到物理内存中,所有Windows进程和服务都是分页的。在Win32环境中,调用RtLockProcess函数可以避免Win32进程引起页失败。

代码例程

Code and File Examples中的RTX Process Memory Locking Calls Programming Example

RTX Process Memory Locking Calls Programming Example

The following programming example demonstrates the use of RTX process memory locking calls.

#include <windows.h>

#include <stdio.h>

#include <rtapi.h>

void main(void) {

DWORD dwSections = RT_PLOCK_ALL;

if (!RtLockProcess( dwSections)) {

printf("/nFailure on RtLockProcess./t");

printf("Error=%d/n", RtGetLastError());

}

else {

printf("/nSuccess on RtLockProcess/n");

if (!RtUnlockProcess( dwSections)) {

printf("/nFailure on RtUnlockProcess./t");

printf("Error=%d/n", RtGetLastError());

}

else {

printf("/nSuccess on RtUnlockProcess/n");

}

}

ExitProcess(0);

}

内核锁定API

以下API可以获取RTX内核内存锁服务:

RtLockKernel 将Windows 内核的分页段锁定到物理内存中

RtUnlockKernel 将上个函数的内存解锁

RTSS环境编程考虑

默认地,RTSS环境中所有进程和内存对象都被锁定到物理内存中。

Win32环境编程考虑

相当一部分Windows操作系统组件都是分页的,包括大部分的Windows内核和Win32子系统。为了避免实时程序因内核分页失败带来的延迟,可以使用RtLockKernel函数。

Windows设备驱动程序一般不分页;其在启动时时加载并不分页。为了使驱动在系统中分页,驱动开发者必须仔细地架构其驱动并手工掌管将要分页的代码。因其复杂性,较少驱动使用此方式进行架构。

锁定Windows内核和进程减少了可用物理内存池。这对非实时系统操作是有害的。必须要有足够的内存来确保非实时操作的期待性能。更多关于非分页内存池大小,请看Microsoft Knowledge Base 或 MSDN。

代码例程

Code and File Examples中的RTX Kernel Memory Locking Calls Programming Example

RTX Kernel Memory Locking Calls Programming Example

The following programming example demonstrates the use of RTX kernel memory locking calls.

Note:  Since all RTSS processes are always locked, the function RtLockKernel() has no effect in the RTSS environment.

#include <windows.h>

#include <stdio.h>

#include <rtapi.h>

void main(void) {

DWORD dwSections = RT_KLOCK_ALL;

if (!RtLockKernel( dwSections)) {

printf("/nFailure on RtLockKernel./t");

printf("Error=%d/n", RtGetLastError());

}

else {

printf("/nSuccess on RtLockKernel/n");

if (!RtUnlockKernel( dwSections)){

printf("/nFailure on RtUnlockKernel./t");

printf("Error=%d/n", RtGetLastError());

}

else {

printf("/nSuccess on RtUnlockKernel/n");

}

}

ExitProcess(0);

}


本地内存

本地内存(Local memory)是RTX用来满足所有RTSS程序内存请求的本地内存池。从本地内存池分配内存时,RTSS程序就不需要初始化SRI(Service Request Interrupt)来从Windows请求内存。当第一个RTSS程序开始时,本地内存池就被创建,并为普通的非确定性函数提供确定性的行为,同时在Windows崩溃(蓝屏)后也会有更大的弹性和功能性。

如果默认的内存分配方式不是从本地内存池请求,RTX会在第一次使用RTSSrun /l 参数时创建本地内存池或者RTSS程序中第一次调用RtAllocateLocalMemory函数时。

设置内存池大小

在RTX Properties的Memory面板中设置本地内存池的初始大小。如果RTSS程序用尽了初始化分配的所有内存,则本地池必须从Windows请求更多的内存。附加的内存将会是初始化的大小或是请求的内存大小,取决于哪一个更大。从Windows请求内存会导致SRI动作,这是非确定性的,并且不能在关机处理函数中调用。

为了避免此情况,务必考虑好你的实时程序对内存的需求并指定可以支持它们的足够大的内存。RTX函数RtQueryLocalMemory可以检查在本地内存池中是否有足够的空余内存可供使用。这在关机处理函数中是一个有用的函数调用。

如果在RTX Properties控制面板中或者使用RTSSrun使能了本地内存池,则在RTSS程序中不管是显式还是隐式分配的内存都将从本地内存池请求分配。因此,以下API就成为确定性的,可以在关机处理函数中进行调用。

RtAllocateLockedMemoryHeapFreeRtCreateMutex
RtFreeLockedMemoryHeapReAllocRtOpenMutex
RtCreateSharedMemorymallocRtCreateSemaphore
RtOpenSharedMemorycallocRtOpenSemaphore
RtOpenSharedMemoryreallocRtCloseHandle
HeapAllocfreeInitializeCriticalSection
HeapCreateRtCreateEventDeleteCriticalSection
HeapDestroyRtOpenEventCreateThread*

*CreateThread –对在本地内存池创建的线程,堆栈没有保护页。


时钟和定时器

实时系统需要操作系统时序服务。操作系统必须能够保证过去时间的精确计数,在确定时间上调度线程,以及在确定周期内暂停线程。

RTX的定时器是一个隐式的线程,当定时器中止的时候RTSS会发出通知,

线程接到通知后会调用在定时器创建时指定的处理程序。定时器和系统的时钟有关,当定时器创建时,就会测量它的停止时间。一旦定时器中止,它会自动重新启动,同时处理线程会运行,处理线程的运行不会影响定时器的重新启动。

时钟服务

函数

以下为RTX时钟服务的相关函数:

RtGetClockTime 取得指定时钟的当前值

RtSetClockTime 设置指定时钟的值

RtGetClockResolution 取回指定时钟的分辨率

RtGetClockTimerPeriod 取回指定时钟的最小时钟周期RtGetRtssTimeAsFileTime取回RTSS时间的当前值

RtSetRtssTimeAsFileTime 设置RTSS时间的当前值

时钟的值以100ns的单位(ticks)被获取和设置,并被报告从1601年1月1日12:00AM以来的ticks的数量。

时钟类型

在Win32 和RTSS环境中可用的RTX时钟包括以下几种:

CLOCK_1 (alias CLOCK_SYSTEM) —CLOCK_1由实时HAL扩展提供,分辨率为1ms。Win32 和RTSS环境中的线程可以在此时钟上以1ms的增量来调度定时器。

CLOCK_2 (alias CLOCK_FASTEST) — CLOCK_2由实时HAL扩展提供,分辨率为1us。

此时钟上的定时器可以被设置为100, 200, 500, 或 1000 µs。可以通过RTX Settings控制面板来设置HAL扩展定时器。

CLOCK_3 — CLOCK_3由实时HAL扩展提供,分辨率为1us。此时钟上的定时器时期通过可编程定时器ticks的数量来计算,一个tick周期为838.095 ns。此时钟精确度为0.001ns。

注意:CLOCK_3和 CLOCK_2都基于相同的通过RTX设置面板设置的HAL扩展定时器周期,不同之外在于如何中断和以CLOCK计算的表达(见下表)。

Specified Timer Period (unit: µS)TicksCLOCK_2 Period (unit: µS)CLOCK_3 Period (unit: 0.001 nanosecond)
10011910099,733,305
200239200200,304,705
500596500499,504,620
100011931000999,847,335

因为HAL扩展定时器在APIC系统上基于本地APIC定时器,而不是PIC系统中的可编程定时器(the Programmable Timer),上面所示CLOCK_3 和 CLOCK_2的区别公限于UP PIC系统。对于UP APIC和MP系统,CLOCK_3 和 CLOCK_2是一样的。

与Win32时钟的关系

RTX时钟由实时HAL扩展提供的服务进行更新。RTX时钟与实时HAL扩展定时器服务进行同步。然后,RTX时钟既不与Windows系统时钟也不与电池备份日时间时钟(the battery-backed time-of-day clock)进行同步。

RTX和Windows时钟Accuracy(只限于UP PIC系统)

略。

定时器服务

一个RTX定时器其实是一个有定时器截止时间的RTSS获取通知的隐式处理线程,并调用此定时器被创建时指定的处理函数。

定时器同系统中的时钟联系在一起——不是它的截止时间被测量——当它被创建时。(Timers are associated with a clock in the system - against which its expiration is measured - when it is created.)一个定时器从被设定之后开始计数到其截止时间。一旦定时器溢出,则它会自动进行重装载。处理线程就得到执行。处理程序的执行不影响定时器的重装载。重复周期被设为0的定时器只执行它们的处理程序一次,并称为“一次搞定”(one-shot)定时器。重复周期被设为固定值的定时器会不停的执行它们的处理程序,这称为“重复”或“周期”定时器。

API

以下为RTX定时器服务相关的API函数:

RtCreateTimer 使用指定的时钟创建一个定时器

RtDeleteTimer 删除先前创建的定时器

RtCancelTimer 取消指定定时器的截止时间

RtSetTimer 设置指定定时器的绝对(absolute)截止时间和重复周期

RtSetTimerRelative设置指定定时器的相对(relative)截止时间和重复周期

与Win32定时器的关系

RTX定时器不是同步对象,这意味着一个线程不能等待有RTX定时器处理函数(handle)的单个对象。这与Windows定时器(一个线程可以等待一个对象,或者反对一个可以接收通知的线程)正好对立。

Win32和RTSS编程考虑

如果你的程序需要通知其他线程一个定时器的截止时间,你应该在处理函数中使用合适的通知对象来触发此事件。

Sleep服务

Sleep服务可以暂停当前线程指定的一段时间。

API

Sleep 暂停当前线程指定的毫秒时间

RtSleepFt暂停当前线程指定的时间,以100ns为单位

编程考虑

RtSleepFt在一个Win32定时器线程中无法使用。定时器截止时间的一系列规定,包括定时器,等待函数和sleep函数,是为了截断指定的周期至定时器tick计数。如果此计数为0,则计数就被设为1。

代码例程

See RTX Timer and Sleep Calls Programming Example in Code and File Examples. It demonstrates the use of RTX timer and sleep calls.

RTX Timer and Sleep Calls Programming Example

The following example demonstrates the use of RTX timer and sleep calls.

#include "windows.h"

#include "stdio.h"

#include "rtapi.h"

//

// Local data.

//

LARGE_INTEGER Period; // Timer period

LARGE_INTEGER StartTime; // Start time of sampling run

ULONG TimerCounter = 0; // Counts entries to timer handler

//

//

VOID main(int argc, char **argv)

{

LARGE_INTEGER x;

HANDLE hTimer;

//

// Set default timer period to 500 micro seconds

//

Period.QuadPart = 5000;

//

// Set to the next to highest real-time priority.

//

if (!RtSetThreadPriority( GetCurrentThread(), T_PRIORITY_MAX-1))

printf("WARNING: Can't set to highest RTAPI priority./n");

//

// Setup and start the periodic timer.

//

if (!(hTimer = RtCreateTimer(

NULL, // Security - NULL is none

0, // Stack size - 0 is use default

TimerHandler, // Timer handler

NULL, // NULL context (argument to handler)

RT_PRIORITY_MAX, // Priority

CLOCK_2))) // RTX HAL Timer

{

printf("ERROR: Could not create the RTAPI timer./n");

ExitProcess(2);

}

if (!RtSetTimerRelative( hTimer, &Period, &Period))

{

printf("ERROR: Could not set and start the RTAPI timer./n");

ExitProcess(2);

}

//

// Wait for the sampling time.

//

Sleep(1000);

//

// Stop and delete the timer.

//

RtCancelTimer( hTimer, &x);

RtDeleteTimer( hTimer);

printf(" Value of number of timers counter is %d/n",TimerCounter);

ExitProcess(0);

}

//

// timer handler function

// - increment the tick counter

//

int RTFCNDCL TimerHandler(PVOID unused)

{

TimerCounter++;

return 0 ;

}

评论 7 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

千愚千寻

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值