
设备管理
中断
实时系统需要频繁地响应外部设备。为达此目的,经常期望有一个实时进程直接响应由这些设备产生的中断信号。RTX允许一个进程直接与设备进行接口,而不需要通过Windows驱动。
中断管理
RTX中断管理机制提供了使程序满足硬件设备的中断请求的接口。这些接口让你可以向一个中断添加一个处理函数,就像RTX定时器机制允许你在一个给定的定时器截止时间时执行一个处理函数一样。
Win32 和 RTSS进程可以通过以下API来添加一个中断处理函数:
- RTSS 程序应使用 RtAttachInterrupt.
- Win32 程序应使用 RtAttachInterruptVectorEx 或 RtAttachInterruptVector. (提示: RtAttachInterruptVectorEx 包括更多功能并会取代RtAttachInterruptVector.)
在RTSS和Win32环境中,都是由分配给中断处理线程的优先级决定中断处理函数的优先次序。
当一个中断处理函数被添加到一个特定的中断时,一个线程就会被创建来响应此中断。这个线程与Interrupt Service Thread (IST)类似。当中断发生时,中断源被屏蔽;中断信号的线程恢复;并且,如果它的优先级比当前执行的线程的优先级要高,它就会变成当前执行的那个线程。中断处理函数返回以后,中断源取消屏蔽,线程被暂停。
RTSS有12个中断级别。同所有RTAPI调用一样,调用RtAttachInterruptVector会将RTSS优先级映射到这12个中断级别。即有递增的硬件优先级:
0-117, 118, 119, ...127
例如,中断要求最高硬件优先级时,用户应该在添加中断时分配其RTSS优先级127。对于低一些的硬件优先级,用户可以选择118-126之间的优先级。对最低的硬件优先级,可使用117或更低的数字。
API
添加中断的API:
- RtAttachInterrupt 为指定中断添加IST和(或)ISR(Interrupt Service Routine)。中断可以是line-based或者是message-based (MSI/MSI-X)类型。你还可以通过此API在RTSS环境中共享添加的独占式中断。在RTSS环境中使用本API添加中断。
- RtAttachInterruptVectorEx 为指定中断添加IST和(或)ISR(Interrupt Service Routine)。你还可以通过此API在RTSS或Win32环境(但不能同时)中共享添加的独占式中断。在Win32进程中使用本API添加中断。
- RtAttachInterruptVector 为指定中断添加IST。在Win32进程中使用本API添加中断,但是RtAttachInterruptVectorEx包含更多的功能,推荐添加Win32进程时使用RtAttachInterruptVectorEx。
释放中断的API:
- RtReleaseInterrupt 释放由RtAttachInterrupt添加的中断。像RtAttachInterrupt一样,RTReleaseInterrupt只支持在RTSS环境中使用。
- RtReleaseInterruptVector 释放由RtAttachInterruptVectorEx或RtAttachInterruptVector添加的中断。此API可以在RTSS或Windows环境中使用。
其他API:
- RtQueryPciMsiCapability 允许用户查询一个PCI设备,并确定该设备是否有MSI或MSI-X兼容。只支持在RTSS环境中使用。
- RtDisableInterrupts 在Win32环境中禁止添加到程序中所有中断的中断处理程序。在RTSS环境中,所有中断在处理器级别被禁止。
- RtEnableInterrupts 使能被RtDisableInterrupts禁用的所有中断。
一般编程时的考虑
- 同任何线程一样,中断线程可以被更高优先级的线程在任何时刻抢占。
- 如果有时间量子集设置在IST,时间片分片会影响IST的运行。
- 中断处理可以通过提高当前运行的线程的优先级来禁用。这个优先级必须比所有RTSS中断服务线程的级别都高。传递一个对象的中断处理程序可满足更高优先级线程的等待条件。恢复更高优先级的线程将会延迟中断处理的完成,并延迟中断源被屏蔽的时间。高优先级线程永远不会屏蔽定时器中断;因此,定时器中断是最高优先级的中断。
Win32环境编程时的考虑
所有运行在RTSS环境的任务的优先级都高于在Win32环境中的任务。因此,任何时间要求严格的中断处理必须在RTSS进程中工作,而不是在Win32进程中。在Win32环境中,Windows调度器为RTX中断线程服务。对于工作中的接收和处理中断的线程来说,这会导致非确定性的调度延迟。
还有,记得在Win32进程中使用RtAttachInterruptVectorEx或者RtAttachInterruptVector。Win32并不支持使用RtAttachInterrupt。
代码例程
使用RtAttachInterrupt的例子:see the IntelPro1000 section of the Code ad File Examples > SDK Samples topic
使用RtAttachInterruptVector的例子:see Interrupt Management and Port I/O Calls Programming Example in Code and File Examples
端口IO
实时系统需要有能力对硬件设备进行控制、读写数据操作。RTX端口IO编程接口允许一个用户程序直接对处理器的IO空间进行数据移动,而无须切换到内核模式的代码。这项功能避免了对每个设备创建一个设备驱动。另外,也避免了通过请求设备驱动访问设备带来的延迟问题。
端口IO提供了直接同硬件进行通讯的一种方式。IO地址空间是一项Intel处理器上的特性,每个地址代表一个8bit的“端口”。每个端口实际上对应硬件设备上的一个8bit的控制寄存器。当顺序地址可以代表一个多字节端口的字节时,硬件设计者通常使用单字节端口的设计,然后多字节值就会当作顺序输入的单字节写入到端口地址中。对一个特定的设备,你应该查阅其编程参考文档。
必须在任何数据传输之前先使能对端口IO设备的访问。这由RtEnablePortIo函数输入将要访问的端口IO地址范围来完成。随后使用RtWrite* 和 RtRead* 函数来从使能的端口IO空间中传输数据。
端口IO控制API
RtEnablePortIo 使能指定的IO地址范围的直接端口IO访问。
RtDisablePortIo 禁用指定的IO地址范围的直接端口IO访问。
端口IO数据传输API
RtReadPortUchar,RtReadPortUshort,RtReadPortUlong 直接从指定的IO端口读1,2或4字节数据
RtWritePortUchar,RtWritePortUshort,RtWritePortUlong 直接向指定的IO端口写1,2或4字节数据
RtReadPortBufferUchar,RtReadPortBufferUshort,RtReadPortBufferUlong 从指定的IO端口拷贝一系列的1,2或4字节数据到缓冲区RtWritePortBufferUchar,RtWritePortBufferUshort,RtWritePortBufferUlong 从指定的IO端口拷贝1,2或4字节数据到缓冲区
一般编程考虑
RTX接口的代码使用汇编语言,并使用__stdcall调用约定,指示子程序处理对堆栈的清理。不能使用其他的调用约定。
代码例程
See Interrupt Managemet and Port I/O Calls Programming Example in Code and File Examples.
物理内存映射
一个IO空间的存在依赖于处理器的架构。一些Windows支持的架构基于没有独立IO空间的处理器。相反,它们的端口映射到内存地址。这些架构可使用内存映射函数来使能对控制器和其他硬件设备的物理内存访问。
物理内存映射也可以被用来访问在CPU地址空间中的物理地址范围。
RTX物理内存映射接口将一段物理内存映射到一个程序的虚拟地址空间,这使得应用程序可以直接访问一段物理内存,就好像它是程序中的一个缓冲区。一些程序需要访问映射到CPU物理地址空间的设备存储器或寄存器,这个接口对于这种程序非常有用。
API
RtMapMemory 将一个物理内存地址范围映射至程序的虚拟地址空间
RtUnmapMemory 删除先前映射至程序的虚拟地址空间的映射处理内存对象
一般编程考虑
对于映射的内存区域没有任何限制或保护。如果成功,映射操作将提供指定的基地址和长度。应注意不能将Windows地址空间进行映射和修改,因为这样可能会导致操作系统的崩溃。
代码例程
See the RTX Memory Mapping Calls Programming Example in Code and File Examples.
连续内存映射
有一些设备,特别是有DMA功能的设备,要求它们的缓冲分布在CPU地址空间中的连续的物理内存中。另外,这些设备必须使用真实的物理地址才能访问内存缓冲,而不是被Win32或RTSS程序所使用的虚拟地址。
RtAllocateContiguousMemory 和 RtGetPhysicalAddress 这两个函数用来分配连续的物理内存,并将内存的虚拟地址转换为实际的物理地址。
API
RtAllocateContiguousMemory 分配物理的连续内存地址范围,并将内存映射到程序的虚拟地址空间
RtFreeContiguousMemory 释放先前分配的物理连续内存区域
RtGetPhysicalAddress 返回先前分配的物理连续内存区域的虚拟地址的物理地址
编程考虑
连续内存通常从由Windows维护的非分页内存池中分配。这个内存池相当小,并且会在Windows启动后不久就会被其他驱动和子系统搞的充满碎片。为避免大容量根本失败,你应该最小化它们的使用,并确保它们在系统启动后很快就完成分配。
在Win32环境,RtGetPhysicalAddress只能操作由RtAllocateContiguousMemory返回的地址。
代码例程
See the RTX Contiguous Memory Allocation Calls Programming Example in Code and File Examples.
总线IO
RtGetBusDataByOffset, RtTranslateBusAddress 和 RtSetBusDataByOffset 简化了RTSS硬件驱动的开发,每个函数都减少了收集指定硬件信息和设置硬件的工作量。
RtGetBusDataByOffset 主要用来通过获取输入RtAttachInterruptVector这个函数中的设备信息,如总线号、中断级别和中断向量,来提供向一个硬件设备添加驱动时的支持。例如,调用RtGetBusDataByOffset,会扫描PCI总线,检测一个特定的设备,然后返回此设备安装的总线号、总线中断级别和中断向量。
更多信息,可以参看RtAttachInterruptVector 和 RtAttachInterruptVectorEx的详细文档。
设置硬件时以调用一次RtSetBusDataByOffset结束。当设备初始化需要清理或设置状态寄存器、槽(slot)这些信息时,这个函数会很有用。
RtTranslateBusAddress用来将一个指定设备的内存地址范围翻译成一个驱动的逻辑地址空间。
代码例程
See the Bus I/O Programming Example in Code and File Examples.
文件IO
对文件输入/输出(I/O),RTX有两个选项。可以用Win32 API写入支持的文件I/O函数,或者C运行时库支持的文件I/O函数。RTX API带来了对使用标准API的Windows文件I/O的低开支、快速获取。一个CteateFile标志的子集得到了支持。更多细节请参考《参考手册》。文件I/O函数不支持同步文件操作。
因为RTSS程序没有当前路径的概念,RTSS文件I/O请求必须使用完整路径各,如:
c:/temp/MyFile.txt (对一个文件系统对象而言)
//./MyDevice0 (对一个设备而言)
RTX文件I/O函数调用来自Windows内核环境:RTX事实上将一个诸如c:/MyFile.txt 或 //./MyDevice0的Win32名字转换成对应的Windows内部名称/??/c:/MyFile.txt 和 /Device/MyDevice0。因此,你可以在RTSS程序中使用Windows内部名称,尽管这种调用在Win32环境中是失败的。使用内部Windows名称使你可以获取一个Win32没有符号连接的设备对象,如 /Device/beep or /Device/Harddisk0/Partition1/testfile.txt.。
使用启动时文件I/O(boot-time file I/O),你只能使用诸如//Device//Harddisk0//Partition1/foo.txt的路径名,因为像//??//C://foo.txt 和 C://foo.txt 这样的路径名是不受支持的。