RT_Thead 中断

一、什么是中断?

中断有两种,一种是CPU本身在执行程序的过程中产生的,一种是由CPU外部产生的。 cpu外部中断,就是通常所讲的“中断”(interrupt)。对于执行程序来说,这种“中断”的发生完全是异步的,因为不知道什么时候会发生。CPU对其的响应也完全是被动的, 可以通过“关中断”指令关闭对其的响应。 然而由软件产生的中断一般是由专设的指令,如X86中的“INT n”在程序中有意产生的, 是主动的,同步的。只要CPU执行一条INT指令,在开始执行下一条指令之前一定会进入中 断服务程序。这种主动的中断称为“陷阱”(trap)

从物理学的角度看,中断是一种电信号,由硬件设备产生,并直接送入中断控制器的输入引脚上,然后再由中断控制器向处理器发送相应的信号。处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。此后,处理器会通知 OS 已经产生中断。这样,OS 就可以对这个中断进行适当的处理。不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标识,这些值通常被称为中断请求线(IRQ)。

中断可分为同步(synchronous)中断和异步(asynchronous)中断:

1. 同步中断是当指令执行时由 CPU 控制单元产生,之所以称为同步,是因为只有在一条指令执行完毕后 CPU 才会发出中断,而不是发生在代码指令执行期间,比如系统调用。

2. 异步中断是指由其他硬件设备依照 CPU 时钟信号随机产生,即意味着中断能够在指令之间发生,例如键盘中断。

二、什么是异常?

同步中断又称为异常(exception);异步中断则被称为中断(interrupt)。我们通常讲的中断指的都是异步中断,即cpu外部中断。

1.中断可分为可屏蔽中断(Maskable interrupt)和非屏蔽中断(Nomaskable interrupt)。

2.异常可分为故障(fault)、陷阱(trap)、终止(abort)三类。

这些类别之间的异同点如下:

类别             原因                   异步/同步                   返回行为

中断      来自I/O设备的信号          异步                 总是返回到下一条指令

陷阱      有意的异常                    同步                 总是返回到下一条指令

故障      潜在可恢复的错误           同步                 返回到当前指令

终止      不可恢复的错误              同步                 不会返回

三、中断处理过程

当中断产生时,处理器将按如下的顺序执行:

? 保存当前处理机状态信息

? 载入异常或中断处理函数到PC寄存器

? 把控制权转交给处理函数并开始执行

? 当处理函数执行完成时,恢复处理器状态信息

? 从异常或中断中返回到前一个程序执行点

中断使得CPU可以在事件发生时才予以处理,而不必让CPU连续不断地查询是否有相应的事件发生。通过两条特殊指令:关中断和开中断可以让处理器不响应或响应中断(在关闭中断期间,通常处理器会把新产生的中断挂起,当中断打开时立刻进行响应)。在执行中断服务例程的过程中,如果有更高优先级别的中断源触发中断,由于当前处于中断处理上下文环境中,根据不同的处理器构架可能有不同的处理方式:比如新的中断等待挂起直到当前中断处理离开后再行响应,但这在硬实时环境中不允许发生;或者新的高优先级中断打断当前中断处理过程,而去直接响应这个更高优先级的新中断源,这称为中断嵌套,而中断是否能够嵌套,一般由MCU处理器的中断机制决定,如stm32中只有新中断的抢占优先级比当前中断高时,才能打断当前中断进入新的中断服务函数。

在系统响应中断前,软件代码(或处理器)需要把当前线程的上下文保存下来(通常保存在当前线程的线程栈中),再调用中断服务例程进行中断响应、处理。在进行中断处理时(实质是调用用户的中断服务例程函数),中断处理函数中很可能会有自己的局部变量,这些都需要相应的栈空间来保存,所以中断响应依然需要一个栈空间来做为上下文运行中断处理函数。中断栈可以保存在打断的线程栈中,当从中断中退出时,返回相应的线程继续执行。中断栈也可以与打断线程栈完全分离开来,即每次进入中断时,在保存完被打断的线程上下文后,切换到新的中断栈中独立运行;在中断退出时,再做相应的上下文恢复。

使用独立中断栈相对来说更容易实现,并且对于线程栈使用情况也比较容易了解掌握(否则必须要为中断栈预留空间,如果系统支持中断嵌套,还需要考虑应该为嵌套中断预留多大的空间)。RT-Thread采用的方式是提供独立的中断栈,即中断发生时,中断的前期处理程序会将用户的栈指针更换到系统事先留出的中断栈空间中,等中断退出时再恢复用户的栈指针。这样中断就不会占用线程的栈空间,从而提高了内存空间的利用率,且随着任务的增加,这种减少内存占用的的效果也越明显。以stm32的cotex-M3/M4为例,cotex-M3/M4中拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个:

主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核,以及异常与中断处理。

进程堆栈指针(PSP):由用户的应用程序代码(如线程切换)使用。堆栈指针的最低两位永远是0,这意味着堆栈总是4 字节对齐的。

由此可以看出,在一个实际运行系统里有两大部分:一是操作系统和中断,一是用户应用程序。它们使用的资源是不一样的,从中断(线程调度时产生的中断)返回到用户应用程序线程时,系统使用的堆栈指针也从MSP变成PSP。

四、与操作系统相关的中断接口:在src/irq.c中

void rt_interrupt_enter(void);
void rt_interrupt_leave(void);
当整个系统被中断打断,进入中断处理函数时,OS需要知道当前已经进入到中断状态。
rt_interrupt_enter函数用于通知OS,当前已经进入了中断状态;rt_interrupt_leave函数用于通知OS,已经离开中断状态。通常来说,OS需要知道这样的运行状态,这样在中断服务例程中,如果调用了OS相关的调用,OS好及时调整相应的行为,例如进行任务切换时应该采取中断中任务切换的策略,而不是立即进行切换。但是如果中断服务例程很显然、很必然地不会去调用OS相关的函数,此时也可以不调用rt_interrupt_enter/leave函数。

rt_uint8_t rt_interrupt_get_nest(void);
获取当前中断嵌套计数值,大于0说明处于中断服务中,大于1说明存在中断嵌套

五、与MCU相关的中断接口:以stm32f4为例

关闭中断:在libcpu/arm/cotex-m4/context_rvds.S中用汇编语言实现
rt_base_t rt_hw_interrupt_disable(void);
函数返回中断前的系统中断状态。
当系统关闭了中断时,就意味着当前线程/代码不会被其他事件所打断(因为整个系统已经不再对外部事件响应),也就是当前线程不会被抢占(因为线程切换时用到了PendSV_Handler),除非这个线程主动让出处理器。

打开中断:在libcpu/arm/cotex-m4/context_rvds.S中用汇编语言实现
void rt_hw_interrupt_enable(rt_base_t level);
调用这个函数接口将恢复调用rt_hw_interrupt_disable前的中断状态,level是上一次关闭中断时返回的值。打开中断往往是和关闭中断成对使用的,用于恢复关闭中断前的状态。
注意:调用这个接口并不代表着肯定打开中断,而是恢复关闭中断前的状态,如果调用rt_hw_interrupt_disable()前是关中断状态,那么调用此函数后依然是关中断状态。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-15 06:51:51

RT_Thead 中断的相关文章

LCD实验学习笔记(八):中断控制器

s3c2440有60个中断源(其中15个为子中断源). 程序状态寄存器(PSR)的F位设为1,禁用快速中断(FRQ). 程序状态寄存器(PSR)的I位设为1,禁用普通中断(IRQ). 相反,PSR寄存器F位为0开FRQ中断,I位为0开IRQ中断. s3c2440中断控制器中有五个控制寄存器:中断源等待寄存器(SRCPND),中断模式寄存器(INTMOD),屏蔽寄存器(INTMSK),优先级寄存器(PRIORITY),中断等待寄存器(INTPND). SRCPND寄存器各位对应不同的中断,其中外部

Java阻塞中断和LockSupport

在介绍之前,先抛几个问题. Thread.interrupt()方法和InterruptedException异常的关系?是由interrupt触发产生了InterruptedException异常? Thread.interrupt()会中断线程什么状态的工作? RUNNING or BLOCKING? 一般Thread编程需要关注interrupt中断不?一般怎么处理?可以用来做什么? LockSupport.park()和unpark(),与object.wait()和notify()的区

一种Linux下共享中断的处理方法

前段时间调试一款芯片的时候,碰到一个奇怪的问题:只要在板卡上插入一个PS2键盘,启动内核时系统就可能会进入串口中断函数去执行,过一会系统就panic不往下继续执行.后来经过分析出现问题时的panic的堆栈,借助EJTAG工具,读到这个时候的串口的中断状态位,竟然发现串口并没有真正产生中断.那么,串口本身没有中断,内核怎么又会跑到串口的中断服务函数去执行呢? 我们知道Linux的中断可以分为I/O 中断 .时钟中断和处理器核间中断.其中I/O中断是Linux 系统响应外部IO事件的重要方式.尽管不

线程的中断

如果一个Java程序有不止一个执行线程,当所有线程都运行结束的时候,这个Java程序才能运行结束:更确切地说应该是所有的非守护线程运行结束时,或者其中一个线程调用了System.exit()方法时,这个Java程序才运行结束. Java提供了中断机制,我们可以使用它来结束一个线程.这种机制要求线程检查它是否被中断了,然后决定是不是响应这个中断请求.线程允许忽略中断请求并且继续执行. package concurrency; public class Generator2 extends Thre

20150218【改进】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 一.使用struct pin_desc 管理按键的值 1.定义结构体 2.将前面我们申请中断时写的(void *)1修改为 &pins_desc[n] 在ioctl中,设置中断中修改 在key_release中释放中修改 3.在中断程序中利用我们定义的struc pins_desc判断并得到按键的值 4.得到按键键值后,唤醒程序,在read函数中返回键值 附上驱动源程序: 1 /***********

20150218【改进信号量】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进信号量]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 前面我们使用POLL查询方式来实现GPIO-IRQ按键中断程序 这里我们来使用信号量,让我们的驱动同时只能有一个应用程序打开. 一.首先在前面代码的基础上来一个简单的信号 1.定义一个全局的整形变量 2.在打开函数中,每次进入打开函数canopen都自减1, 3.当我们不使用时,在realease 中canopen自加1 4.这样就实现了一个简单的信号量,我们编译,测试 当我们使用两个应用程序来

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进Poll定时查询]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值. 同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回. 我们在linux查看帮助: 从帮助中的说明得知, poll, ppoll - wait for some event on a file descrip

开关中断与cpsid/cpsie指令

在汇编代码中,CPSID   CPSIE  用于快速的开关中断. CPSID I ;PRIMASK=1, ;关中断 CPSIE I ;PRIMASK=0, ;开中断 CPSID CPSIE F F ;FAULTMASK=1, ;FAULTMASK=0 ;关异常 ;开异常 I:IRQ中断;    F:FIQ中断 最常见的这两个命令的使用处是在关中断.开中断的实现中,我们经常用的local_irq_save和local_irq_restore最终都是调用了以下两个实现,即关/开中断只是操作了CP

mysql主从中断

Mysql主从复制中断一例 收到mysql主从中断报警,马上登上服务器查看,发现是中继日志损坏. Show slave status\G,提示中继日志损坏.  Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog'