Nucleus 实时操作系统中断(上)
Nucleus 实时操作系统中断(上)
Interrupts in the Nucleus SE RTOS
所有现代微处理器和微控制器都有某种中断设施。这种能力对于提供许多应用程序所需的响应能力是必不可少的。当然,响应性和可预测性也是使用实时操作系统背后的一个关键目标,因此这两个主题确实存在轻微的冲突。使用中断可能会损害操作系统的实时完整性。这一主题,以及冲突的解决方法,目前不讲。在这里,我们将了解Nucleus SE使用的中断处理策略。
在所有情况下,中断都不是由Nucleus SE控制的,它们是在中断发生时根据优先级进行处理的,并以通常的方式进行矢量化。它们的执行时间只是从运行主线应用程序代码和调度程序的可用时间中“偷走”的。显然,这意味着所有的中断服务程序都应该简单、简短和快速。
本机中断和托管中断
Nucleus SE确实提供了两种处理中断的方法:“本机”中断服务例程没有什么特别的,并且与操作系统交互的机会有限(至少在选择优先级调度器时是这样);“托管”中断服务例程可以进行更广泛的API调用。
通过一些进入/退出宏,与Nucleus SE应用程序一起使用的中断服务例程可以被指定为本机或托管的。
本机中断
Nucleus SE本机中断是标准的中断服务例程,您可以将其视为“非托管的”。当am中断可能以很高的频率发生并且需要以非常低的开销进行服务时,通常使用它们。由于许多现代嵌入式编译器都支持通过interrupt关键字编写中断服务例程,所以这个例程很可能是用C编写的。唯一保存的上下文信息是编译器认为必要的信息。这导致本机中断例程可以执行的操作有很大的限制,我们将很快看到。
要构造Nucleus SE本机中断服务例程,只需按通常的方式编写ISR,包括在开始时调用NUSE_NISR_Enter()宏,在末尾调用NUSE_NISR_Exit()。这些宏在nuse_types.h中定义,只需将全局变量nuse_Task_State设置为nuse_NISR_CONTEXT。
托管中断
如果您需要在ISR可以执行的操作方面有更大的灵活性,Nucleus SE管理的中断可能是解决方案。与本机中断的关键区别是上下文保存。托管中断不仅仅允许编译器堆叠几个寄存器,而是在输入时保存完整的任务上下文(在上下文块中)。然后从当前任务的上下文块中加载当前任务的上下文。这考虑到了当前任务可能被ISR代码的操作改变的可能性;当优先级调度器正在使用时,这是完全可能的。包含了对Nucleus SE上下文保存和恢复的完整描述。
显然,完整的上下文保存比由本机中断执行的几个寄存器的堆栈开销更高。这是额外灵活性的代价,也是为什么可以选择处理中断的方法的原因。
托管中断是使用NUSE_managed_ISR()宏构造的,该宏在NUSE_types.h中定义。此宏构造包含以下序列的函数:
- task context save
- set NUSE_Task_State to NUSE_MISR_CONTEXT
- call user-supplied ISR code function
- restore NUSE_Task_State to previous setting
- task context restore
宏接受两个参数:中断的名称,用作构造的例程的函数名;包含用户提供的ISR逻辑的函数名。
本文后面将介绍Nucleus SE实时时钟ISR,它是受管ISR的一个示例。
中断服务例程的API调用
可以从本机或托管ISR调用的API函数的范围取决于选择了哪个调度程序。一般来说,优先级调度程序的使用为在API函数调用的结果下调用调度程序提供了许多机会,这在本机ISR中是一个问题。
使用优先级调度程序从本机ISR调用API
允许使用优先级调度程序从本机ISR调用有限范围的API函数。这一限制是由于Nucleus SE API的灵活性造成的–许多调用都会导致任务准备就绪,并且本地ISR不可能调用调度器(因为任务上下文未被保存)。如果不启用任务阻塞,则具有更大的灵活性。
始终允许以下API调用:
NUSE_Task_Current()
NUSE_Task_Check_Stack()
NUSE_Task_Information()
NUSE_Task_Count()
NUSE_Partition_Pool_Information()
NUSE_Partition_Pool_Count()
NUSE_Mailbox_Information()
NUSE_Mailbox_Count()
NUSE_Queue_Information()
NUSE_Queue_Count()
NUSE_Pipe_Information()
NUSE_Pipe_Count()
NUSE_Semaphore_Information()
NUSE_Semaphore_Count()
NUSE_Event_Group_Information()
NUSE_Event_Group_Count()
NUSE_Signals_Send()
NUSE_Timer_Control()
NUSE_Timer_Get_Remaining()
NUSE_Timer_Reset()
NUSE_Timer_Information()
NUSE_Timer_Count()
NUSE_Clock_Set()
NUSE_Clock_Retrieve()
NUSE_Release_Information()
但是,唯一真正有用的是NUSE_Signals_Send(),因为这提供了一个很好的方法来指示任务需要一些工作。
如果禁用了阻塞(这意味着许多API调用可能无法使任务就绪),则可以使用许多其他API函数:
NUSE_Partition_Allocate()
NUSE_Partition_Deallocate()
NUSE_Mailbox_Send()
NUSE_Mailbox_Receive()
NUSE_Mailbox_Reset()
NUSE_Queue_Send()
NUSE_Queue_Receive()
NUSE_Queue_Jam()
NUSE_Queue_Reset()
NUSE_Pipe_Send()
NUSE_Pipe_Receive()
NUSE_Pipe_Jam()
NUSE_Pipe_Reset()
NUSE_Semaphore_Obtain()
NUSE_Semaphore_Release()
NUSE_Semaphore_Reset()
NUSE_Event_Group_Set()
NUSE_Event_Group_Retrieve()
但是,唯一真正有用的是NUSE_Signals_Send(),因为这提供了一个很好的方法来指示任务需要一些工作。
如果禁用了阻塞(这意味着许多API调用可能无法使任务就绪),则可以使用许多其他API函数:
NUSE_Task_Suspend()
NUSE_Task_Resume()
NUSE_Task_Sleep()
NUSE_Task_Relinquish()
NUSE_Task_Reset()
NUSE_Signals_Receive()
来自托管ISR或具有非优先级调度程序的本机ISR的API调用
当使用run-to-completion、round-robin或time-sliced调度器时,可以从ISR调用范围更广的API函数。如果使用类似的ISR优先级,则受管调度器有助于提高ISR的优先级。这是因为允许调用可能导致调度不同的任务。NUSE_Reschedule()中的代码有助于此功能,该代码检测调用的上下文是ISR,并禁止上下文切换(允许它在ISR结束时发生)。调度程序操作的完整细节在前面的一篇文章中介绍过。
一个关键的要求是ISR中的API调用不能导致当前任务的挂起,例如等待一个资源。换句话说,这种调用应该在suspend选项设置为NUSE_NO_suspend的情况下进行。
鉴于此规定,可使用以下API调用:
NUSE_Task_Current()
NUSE_Task_Check_Stack()
NUSE_Task_Information()
NUSE_Task_Count()
NUSE_Task_Suspend()
NUSE_Task_Resume()
NUSE_Task_Reset()
NUSE_Partition_Allocate()
NUSE_Partition_Deallocate()
NUSE_Partition_Pool_Information()
NUSE_Partition_Pool_Count()
NUSE_Mailbox_Send()
NUSE_Mailbox_Receive()
NUSE_Mailbox_Reset()
NUSE_Mailbox_Information()
NUSE_Mailbox_Count()
NUSE_Queue_Send()
NUSE_Queue_Receive()
NUSE_Queue_Jam()
NUSE_Queue_Reset()
NUSE_Queue_Information()
NUSE_Queue_Count()
NUSE_Pipe_Send()
NUSE_Pipe_Receive()
NUSE_Pipe_Jam()
NUSE_Pipe_Reset()
NUSE_Pipe_Information()
NUSE_Pipe_Count()
NUSE_Semaphore_Obtain()
NUSE_Semaphore_Release()
NUSE_Semaphore_Reset()
NUSE_Semaphore_Information()
NUSE_Semaphore_Count()
NUSE_Event_Group_Set()
NUSE_Event_Group_Retrieve()
NUSE_Event_Group_Information()
NUSE_Event_Group_Count()
NUSE_Signals_Send()
NUSE_Timer_Control()
NUSE_Timer_Get_Remaining()
NUSE_Timer_Reset()
NUSE_Timer_Information()
NUSE_Timer_Count()
NUSE_Clock_Set()
NUSE_Clock_Retrieve()
NUSE_Release_Information()
一些API调用是不允许的,因为它们与当前任务相关:
NUSE_Task_Relinquish()
NUSE_Signals_Receive()
NUSE_Task_Sleep()
实时时钟ISR
实时时钟(RTC)ISR是Nucleus SE提供的唯一完整的中断服务例程。除了为Nucleus SE提供所有所需的定时功能外,它还可以作为如何编写受管中断的示例。
RTC ISR操作
RTC ISR提供的设施已在前面的一篇文章中概述,其中涵盖了Nucleus SE中的系统时间这一广泛主题。根据应用程序的配置方式,所有功能都是可选的。这是RTC ISR的完整代码。
#if NUSE_TIMER_NUMBER != 0
{
U8 timer;
for (timer=0; timer
<nuse_timer_number; timer++)="">
{
if
(NUSE_Timer_Status[timer])
{
if (–NUSE_Timer_Value[timer] == 0)
{
NUSE_Timer_Expirations_Counter[timer]++;
#if NUSE_TIMER_EXPIRATION_ROUTINE_SUPPORT ||
NUSE_INCLUDE_EVERYTHING
if (NUSE_Timer_Expiration_Routine_Address[timer]
!= NULL)
{
((PF1)NUSE_Timer_Expiration_Routine_Address[timer])
NUSE_Timer_Expiration_Routine_Parameter[timer]);
}
#endif
/* reschedule? */
if
(NUSE_Timer_Reschedule_Time[timer] != 0)
{
/* yes: set up time */
NUSE_Timer_Value[timer] =
NUSE_Timer_Reschedule_Time[timer];
}
else
{
/* no: disable */
NUSE_Timer_Status[timer] = FALSE;
}
}
}
}
}
#endif
#if NUSE_SYSTEM_TIME_SUPPORT || NUSE_INCLUDE_EVERYTHING
NUSE_Tick_Clock++;
#endif
#if NUSE_TASK_SLEEP || NUSE_INCLUDE_EVERYTHING
{
U8 task;
for (task=0; task
<nuse_task_number; task++)=""> {
if (NUSE_Task_Timeout_Counter[task]
!= 0)
{
NUSE_Task_Timeout_Counter[task]–;
if (NUSE_Task_Timeout_Counter[task] == 0)
{
NUSE_Wake_Task(task);
}
}
}
}
#endif
#if NUSE_SCHEDULER_TYPE == NUSE_TIME_SLICE_SCHEDULER
if (–NUSE_Time_Slice_Ticks == 0)
{
NUSE_Reschedule();
}
#endif
我们将研究RTC ISR的四个功能领域:
计时器
如果配置了任何应用程序计时器,ISR将通过递减其计数器值来循环为每个计时器提供服务。如果计时器过期(即计数器达到零),则两个操作将生效:
如果配置了计时器过期例程,并且计时器具有指向函数的有效(非空)指针(在NUSE_timer_expiration_Routine_Address[]),则执行例程,并从NUSE_timer_expiration_Routine_parameter[]接收参数。
如果计时器有一个重定时时间(即NUSE_timer_reschedule_time[]中的非零值),则计时器将重新加载该值。
应用程序计时器在上一篇文章中有更详细的描述。
系统时钟
如果配置了系统时钟,那么NUSE_Tick_clock的值只会递增。关于系统时间的进一步讨论可以在上一篇文章中找到。
任务睡眠
如果启用了任务休眠(即配置了API调用NUSE_task_sleep()),则会检查每个任务的超时计数器(NUSE_task_timeout_counter[]中的条目),如果不是零,则递减。如果任何计数器达到零,则相应的任务将被唤醒。
时间片调度
如果正在使用时间片调度程序,则时间片计数器(NUSE_time_slice_Ticks)将递减。如果达到零,则调用调度程序。对NUSE_Reschedule()的调用负责重置计数器。
有管理的中断
对RTC ISR是受管中断的原因进行一些解释可能是有用的,因为在正确的情况下,用户可能希望将其重新编码为本机中断,以减少开销。例如,如果只使用系统时间工具(即没有应用程序计时器、没有任务睡眠和时间片调度器),则本机中断就可以了。管理中断的需求如下:
如果使用了计时器并配置了过期例程,这些例程可能会(从中断上下文)进行API调用,从而导致重新调度。它们受到与从isr发出的API调用相同的限制(请参阅本章前面的部分)。
如果优先级调度程序正在使用中,任务休眠到期可能需要调度更高优先级的任务。
如果正在使用时间片调度程序,它肯定会从RTC ISR调用,因此必须使用托管中断。
Nucleus 实时操作系统中断(上)的更多相关文章
- Nucleus 实时操作系统中断(下)
Nucleus 实时操作系统中断(下) Nucleus RTOS兼容性 由于中断在Nucleus SE中的实现方式与Nucleus rto截然不同,因此不应期望有特定的兼容性.Nucleus RTOS ...
- dsp5509的中断系统
1. DSP5509有32个中断,中断分为软件中断和硬件中断,同时软件中断不可以屏蔽.软件中断由指令触发.55x在中断时DSP会自动保存ST0_55.ST1_55.ST2_55三个寄存器. 2. 其中 ...
- Nucleus PLUS的启动、执行线程和中断处理
nucleus系统是实时嵌入式操作系统,具有实时.任务抢先.多任务内核,当中95%的代码由C语言写成,极易移植.开放的源代码使得配置和裁剪方便,再加上体积小(所有二进制映像可仅20K).响应高速等特性 ...
- Nucleus PLUS简单介绍
近些年来,随着嵌入式系统飞速的发展,嵌入式实时操作系统广泛地应用在制造工业.过程控制.通讯.仪器仪表.汽车.船舶.航空航天.军事.装备.消费类产 品等方面.今天嵌入式系统带来的工业年产值超过了1万亿美 ...
- S3C2440上RTC时钟驱动开发实例讲解(转载)
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤.一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便.如有错误之处,谢请指正. 共享资源,欢迎转载:http:/ ...
- Hadoop生态上几个技术的关系与区别:hive、pig、hbase 关系与区别
初接触Hadoop技术的朋友肯定会对它体系下寄生的个个开源项目糊涂了,我敢保证Hive,Pig,HBase这些开源技术会把你搞的有些糊涂,不要紧糊涂的不止你一个,如某个菜鸟的帖子的疑问,when to ...
- 【翻译】运行于x86机器上的FreeBSD的PCI中断
来源 http://people.freebsd.org/~jhb/papers/bsdcan/2007/article/article.html 摘要 在拥有多个独立设备的计算机里一个重要的元素是一 ...
- 系统中断与SA_RESTART
今天在调试程序时,sem_timedwait居然返回了一个Interrupted system call,错误码为EINTR.系统中断这东西我一向只闻其名,不见其"人",不想今天遇 ...
- MCS-51系统中断优先级的软扩展
摘要:鉴于MCS-51系统只提供“二级中断嵌套”,提出扩展51系统中断优先级的纯软件方法.其利用51系统内建的中断允许寄存器IE和中断优先级寄存器IP,通过屏蔽字机制来实现:以C51的形式,给出这种扩 ...
随机推荐
- hdu3793 判断对称(水题)
题意: 给你一个串,问你这个串是不是关于某个字母对称的,这个串是一个首位相接的圆. 思路: 水题,直接枚举每一个为对称点试一下就行了,不解释了. #include<std ...
- 半自动二进制协议模糊工具 Peach 使用
链接:https://bbs.ichunqiu.com/thread-54487-1-1.html
- MBG:mybatis逆向工程使用
一:如果是Maven工程可在pom.xml文件中添加插件 <build> <plugins> <plugin> <groupId>org.mybatis ...
- 【前端】vue2.x 配合 bootstrapTable 动态添加元素和绑定点击事件,事件无效 解决
背景: 使用bootstrap-table 表格插件时,每一行的最后一班会加操作按钮列.如果不加入vue的话,使用插件自己的列属性formatter:function(value, row, inde ...
- Java 进行时间处理
Java 进行时间处理 一.Calendar (1).Calender介绍 Calendar的中文翻译是日历,实际上,在历史上有着许多种计时的方法.所以为了计时的统一,必需指定一个日历的选择.那现在最 ...
- 交叉编译参数--build、host和target的区别
build.host和target 在交叉编译中比较 常见 的一些参数就是build.host和target了,正确的理解这三者的含义对于交叉编译是非常重要的,下面就此进行解释 --build=编译该 ...
- java基础——数组及其应用
数组 数组时相同类型数据的有序集合 数组描述的时相同类型的若干数据,按照一个定的先后次序排列组合而成 其中,每一个数据成为数组元素,每个数组元素可以通过一个下标来访问他们 数组的声明&创建 首 ...
- [Python] tkinter 之 Listbox & Combobox
示例: 1 #用户界面 2 import os 3 os.chdir('F:\\spyder_workspace\\ColCal') 4 import Main 5 from tkinter impo ...
- tail -fn 1000 test.log | grep '关键字' 按照时间段 sed -n '/2014-12-17 16:17:20/,/2014-12-17 16:17:36/p' test.log /var/log/wtmp 该日志文件永久记录每个用户登录、注销及系统的启动、停机的事件
Linux 6种日志查看方法,不会看日志会被鄙视的 2020-02-11阅读 7.3K0 作为一名后端程序员,和Linux打交道的地方很多,不会看Linux日志,非常容易受到来自同事和面试官的嘲讽 ...
- 在Linux中通过Top运行进程查找最高内存和CPU使用率
按内存使用情况查找前15个进程,在批处理模式下为"top" 使用top命令查看有关当前状态,系统使用情况的更详细信息:正常运行时间,负载平均值和进程总数. 分类:Linux命令操作 ...