精华内容
下载资源
问答
  • 初学zigbee--IO口中断产生配置条件

    千次阅读 2015-07-25 23:57:46
    IO口中断产生配置条件    中断概述;CC2530CPU有18个中断源,每个中断请求可以通过设置中断使能 SFR 寄存器中断使能位 IEN0,IEN1 或者 IEN2 使能或禁止    1. CPU中断开关打开

     

     

    IO口中断产生配置条件

     

             中断概述;CC2530的CPU有18个中断源,每个中断请求可以通过设置中断使能 SFR 寄存器的中断使能位 IEN0,IEN1 或者 IEN2 使能或禁止

            

             1.      CPU中断开关打开                                              

                       EA=1//打开CPU总中断

             2.      组(P0 P1 P2)中断开关打开

                       IO口中断的中断使能位分别位于IEN1,IEN2, 0为中断禁止(不允许中断),1为中断使能(允许中断)

                       P0的中断使能位(即中断开关)在IEN1(共8位,0~7)的第5位

                       P1的中断使能位(即中断开关)在IEN2(共8位,0~7)的第4位

                       P2的中断使能位(即中断开关)在IEN2(共8位,0~7)的第1位


             3.      组内引脚开关打开(P0组有8个引脚 P1组有8个引脚 P2组有5个引脚)

                       0为中断禁止,1为中断使能

                       P0IEN(7:0)对应P0组的8个引脚           //>_<  7:0意为第7位到第0位

                       P1IEN(7:0)对应P1组的8个引脚 

                       P2IEN(7:0)对应P2组的8个引脚 


             4.      配置什么时候中断:上升沿产生中断还是下降沿产生中断

                       0表示上升沿,1表示下降沿

                       通过配置PICTL

            

    中断处理函数

             格式

         

        <pre name="code" class="cpp">#pragma vector =PxINT_VECTOR    //#pragma vector =中断向量
    	__interrupt void fun()             //中断函数 
    	{
    	/*
    			函数
    	*/
    	/*
    	中断函数的最后要有清中断标志,否者将一直中断,即一直执行中断函数
    	*/
    
    	PxIFG=0; 		//清中断标志
    
    	/*
    	PxIFG寄存器有8位表示每个组的各个引脚,在产生中断的时候该组的该位将产生置位,例如P0_0产生中断,P0IFG的第0位将由0变成1
    	*/
    	
    	PxIF=0;         //清中断标志  
    
    	/*
    		PxIF为一个标志位,每一组对应一个PxIF 例如P0_0产生中断,则P0IF将产生置位
    	*/
    	}

    
    

     

     

     

    展开全文
  • (生产者)消息发送线程拿到队列锁,当队列未满时候写入消息,释放锁,当队列满时候,释放锁,等待队列空条件。 (消费者)刷盘线程拿到队列锁,当队列有数据时候,取数据清空队列,释放锁,再把取出来消息...

    最近在一次压测过程中暴露出notify client的一个死锁问题,发生死锁的场景是消息的可靠异步发送,具体过程是:

    (生产者)消息发送线程拿到队列锁,当队列未满的时候写入消息,释放锁,当队列满的时候,释放锁,等待队列空条件。

    (消费者)刷盘线程拿到队列锁,当队列有数据的时候,取数据清空队列,释放锁,再把取出来的消息数据刷盘持久化;没数据的时候,释放锁,等待队列非空条件。

    这是一个典型的多生产者-单消费者的问题。起初我们通过review代码来看,都觉得不会发生死锁,因为在临界区域里面只用到了一把锁,不会出现deadly embrace类型的死锁。

    后来进一步了解到用户对notify client的使用方式,发现他们的用法比较特殊,用户会把N ms之内没有完成消息发送的任务,强行cancel掉。也就是说生产者可能会在某个时刻检测到interrupt标记位,响应interrupt,是否会产生死锁必须把interrupt的因素也给考虑进去。

    一般来说,当捕获到InterruptedException之后,比较规范的做法是把InterruptedException抛给上层调用者;或者调用Thread.currentThread().interrupt(),重新把线程中断标记置为true(因为阻塞方法在抛出InterruptedException,会清除中断标记位),暂不处理中断,把中断留给线程后续处理。基本原则就是要让任务能够优雅地在一个合适的时机响应中断,而不能对中断毫不作为。

    在这个案例里面,生产者选择了后者,暂不处理,通过Thread.currentThread().interrupt()重新设置中断标记。

    在大部分情况下,这么做是不会有问题的,但是在这种情况下,问题很大。因为在enqueue里面,会响应中断的代码是this.notEmpty.await(),并且是在一个循环里,this.notEmpty.await()会在方法入口处检测是否有中断标记,如果有那么就抛InterruptedException,这样一来一旦抛出第一个InterruptedException,在catch方法块里执行Thread.currentThread().interrupt(),会导致在下一次循环里继续抛出InterruptedException。如果运气好的话,可能在某个时刻this.nextWriteBatch != null条件不成立,跳出循环。如果运气不好的话,可能就是一个死循环。

    在这次死锁案例中,是属于运气不好的情况,因为InterruptedException是在this.notEmpty.await()Condition.await()会在执行过程中释放关联的锁)释放锁enqueueLock之前发生的也就是说生产者在释放锁之前陷入中断循环。唯一能让this.nextWriteBatch != null不成立的线程是消费者线程,消费者线程没拿到锁,没机会执行this.nextWriteBatch = null。这样一来这个中断循环就成了死循环了,他永远不会释放锁,其他线程会一直阻塞等待锁。

     

    锁定义,以下代码都在同一个实例里

    privatefinal Lock enqueueLock = new ReentrantLock();

    privatefinal Condition notEmpty = this.enqueueLock.newCondition();

    privatefinal Condition empty = this.enqueueLock.newCondition();

    生产者代码

    private WriteBatch enqueue(WriteCommand writeCommand, boolean sync) throws IOException {

            WriteBatch result = null;

            this.enqueueLock.lock();

            try {

                // 如果没有启动,则先启动appender线程

                this.startAppendThreadIfNessary();

                if (this.nextWriteBatch == null) {

                    result = this.newWriteBatch(writeCommand);

                    this.empty.signalAll();

                }

                else {

                    if (this.nextWriteBatch.canAppend(writeCommand)) {

                        this.nextWriteBatch.append(writeCommand);

                        result = this.nextWriteBatch;

                    }

                    else {

                        while (this.nextWriteBatch != null) {

                            try {

                                this.notEmpty.await();

                            }

                            catch (InterruptedException e) {

                                Thread.currentThread().interrupt();

                            }

                        }

                        result = this.newWriteBatch(writeCommand);

                        this.empty.signalAll();

                    }

                }

                if (!sync) {

                    InflyWriteData inflyWriteData = this.inflyWrites.get(writeCommand.bytesKey);

                    switch (writeCommand.opItem.op) {

                    case OpItem.OP_ADD:

                        if (inflyWriteData == null) {

                            this.inflyWrites.put(writeCommand.bytesKey, new InflyWriteData(writeCommand.data));

                       }

                        else {

                            // update and increase reference count;

                            inflyWriteData.data = writeCommand.data;

                            inflyWriteData.count++;

                        }

                        break;

                    case OpItem.OP_DEL:

                        // 无条件删除

                        if (inflyWriteData != null) {

                            this.inflyWrites.remove(writeCommand.bytesKey);

                        }

                    }

                }

                return result;

            }

            finally {

                this.enqueueLock.unlock();

            }

    }

    消费者代码

        publicvoid processQueue() {

            while (true) {

                WriteBatch batch = null;

                this.enqueueLock.lock();

                try {

                    while (true) {

                        if (this.nextWriteBatch != null) {

                            batch = this.nextWriteBatch;

                            this.nextWriteBatch = null;

                            break;

                        }

                        if (this.shutdown) {

                            return;

                        }

                        try {

                            this.empty.await();

                        }

                        catch (InterruptedException e) {

                            break;

                        }

                    }

                    this.notEmpty.signalAll();

                }

                finally {

                    this.enqueueLock.unlock();

                }

                if (batch != null) {

                    final DataFile dataFile = batch.dataFile;

                    final LogFile logFile = batch.logFile;

                    final List<WriteCommand> cmdList = batch.cmdList;

                    try {

                        this.writeDataAndLog(batch, dataFile, logFile, cmdList);

                        this.processRemove(batch, dataFile, logFile);

                    }

                    finally {

                        batch.latch.countDown();

                    }

                }

            }

    }

     

    其实在java技术规范里面,并不推崇,也不提供简单粗暴的任务中断机制,强制要求一个任务立马停止。因为如果一个任务在执行过程中,被非正常取消的话,有可能会导致数据结构被破坏,数据不一致的情况发生。所以java推崇的是通过协作的方式来终止一个任务,一个线程可以向另外一个线程发起终止信号,但是具体如何终止,应该由被终止的线程来决定。被终止的线程可以通过检查终止信号,在一个合适的时机优雅退出。

    比如一个任务可以设置一个volatilecancel标记,当要终止这个任务的时候,我们把cancel标记设置为true,告诉任务我们要终止了。任务在某个时候检查到这个终止标记,知道要终止的,把数据结构维护好,在合适的时机退出。

    尽管可以通过设置用户自定义的cancel标记来取消任务,但是也有可能任务调用了一些阻塞方法,比如Condition.await(),一旦阻塞可能就没机会去检测用户自定义的cancel标记,这样一来任务也就不能及时响应用户的取消操作。因此jdk提供了线程内置的interrupt标记,可以通过Thread.currentThread().interrupt()来设置,并且大部分的类库阻塞方法都能会检查这个中断标记位,在中断的时候抛出异常,以便让任务及时响应用户中断。

    当然也有一种可能是任务没有使用自定义cancel标记,也没有调用能够抛出InterruptedException的方法,如果对这类任务调用Thread.currentThread().interrupt(),是不会产生预期效果的。因此调用方不应该随意调用Thread.currentThread().interrupt()来取消任务,除非他知道这个任务的中断策略。而作为任务代码编写者,要保证程序健壮,应该考虑一个合适的中断策略,能够在被中断的时候,尽可能及时响应中断,优雅的退出。

    重新回到上面的例子,结合业务场景,当用户调用中断的时候,是想取消发送消息任务。任务代码在this.notEmpty.await()检查到线程中断标记,抛出InterruptedException。因为数据结构还没有被破坏,数据状态是一致的,所以无需捕获异常,直接往上层抛出InterruptedException,释放锁,以消息发送失败告终;

    private WriteBatch enqueue(WriteCommand writeCommand, boolean sync) throws IOException, InterruptedException {

            WriteBatch result = null;

            this.enqueueLock.lock();

            try {

                // 如果没有启动,则先启动appender线程

                this.startAppendThreadIfNessary();

                if (this.nextWriteBatch == null) {

                    result = this.newWriteBatch(writeCommand);

                    this.empty.signalAll();

                }

                else {

                    if (this.nextWriteBatch.canAppend(writeCommand)) {

                        this.nextWriteBatch.append(writeCommand);

                        result = this.nextWriteBatch;

                    }

                    else {

                        while (this.nextWriteBatch != null) {

                                this.notEmpty.await();

                        }

                        result = this.newWriteBatch(writeCommand);

                        this.empty.signalAll();

                    }

                }

                if (!sync) {

                    InflyWriteData inflyWriteData = this.inflyWrites.get(writeCommand.bytesKey);

                    switch (writeCommand.opItem.op) {

                    case OpItem.OP_ADD:

                        if (inflyWriteData == null) {

                            this.inflyWrites.put(writeCommand.bytesKey, new InflyWriteData(writeCommand.data));

                        }

                        else {

                            // update and increase reference count;

                            inflyWriteData.data = writeCommand.data;

                            inflyWriteData.count++;

                        }

                        break;

                    case OpItem.OP_DEL:

                        // 无条件删除

                        if (inflyWriteData != null) {

                            this.inflyWrites.remove(writeCommand.bytesKey);

                        }

                    }

                }

                return result;

            }

            finally {

                this.enqueueLock.unlock();

            }

    }

    如果在抛出中断异常的时候,数据结构处于不一致的状态,那么可以先把中断状态保存下来,等数据结构维护好之后再退出。比如下面的任务,子任务A和子任务B必须都执行才能保证数据结构不被破坏。

    策略1: process声明中断异常,上层调用者必须考虑如何处理中断异常。Process执行完A之后被中断,直接撤销A,抛出中断异常,让调用者来处理中断。

        publicvoid process() throws InterruptedException{

                  doA();

                  try {

                         Thread.sleep(1000);

                  } catch (InterruptedException e) {

                         undoA();

                         throw e;

                  }

                  doB();

           }

    策略2process没有声明中断异常,当中断发生时,选择一不做二不休的策略。先保存中断状态,把AB都做完了。然后重新标记中断,把中断信号传递下去,让线程后面的逻辑来响应中断。

        publicvoid process() {

                  boolean cancel=false;

                  doA();

                  try {

                         Thread.sleep(1000);

                  } catch (InterruptedException e) {

                         cancel=true;

                  }

                  doB();

                  if (cancel) {

                         Thread.currentThread().interrupt();

                  }

     

           }

    展开全文
  • 信号产生的条件

    2012-08-01 22:08:00
    在终端上按DELETE键通常产生中断信号(SIGINT),这是停止一个已失去控制程序方法; 2.硬件异常产生信号:除数为0,无效储存访问等等。这些条件通常由硬件检测到,并将其通知内核。然后内核为该条件发生时正在...

    1.用户按下某些终端键时,产生信号。在终端上按DELETE键通常产生中断信号(SIGINT),这是停止一个已失去控制程序的方法;

    2.硬件异常产生信号:除数为0,无效的储存访问等等。这些条件通常由硬件检测到,并将其通知内核。然后内核为该条件发生时正在运行的进程产生适当的信号。例如: 对执行一个无效储存访问的进程产生一个SIGSEGV;

    3.用户可用kill(1)命令将信号发送给其他进程。常用此命令终止一个失控的后台进程

    4.进程用kill(2)函数可将信号发送给另外一个进程或进程组。自然,有些限制:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户; 

    5.当检测到某种软件条件已经发生,并将其通知有关进程时也产生信号。例如SIGURG(在网络连接上传来非规定波特率的数据),SIGPIPE(在管道的读进程已经终止后一个进程写此管道),SIGALRM(进程所设置的闹钟已经超时)。

    转载于:https://www.cnblogs.com/liujiangyi/archive/2012/08/01/2619096.html

    展开全文
  • 一、中断概念操作系统中,中断是很重要组成部分。出现某些意外情况需主机干预时,机器能自动停止正在运行程序并转入处理...其中模块通常由寄存器控制是否使能中断中断触发条件等;中断控制器可以管理中断的优...

    019bc2861ad708d4cdd102e5a9c4955b.png

    一、中断概念

    操作系统中,中断是很重要的组成部分。出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。

    有了中断系统才可以不用一直轮询(polling)是否有事件发生,系统效率才得以提高。

    一般在系统中,中断控制分为三个部分:「模块、中断控制器和处理器」

    其中模块通常由寄存器控制是否使能中断和中断触发条件等;中断控制器可以管理中断的优先级等,而处理器则由寄存器设置用来响应中断。

    二、GIC

    作为 ARM 系统中通用中断控制器的是 GIC(Generic Interrupt Controller),目前有四个版本,V1~V4(V2最多支持8个ARM core,V3/V4支持更多的ARM core,主要用于ARM64系统结构)。

    【注意】对于一些老的ARM处理器,比如ARM11,Cortex-A8,中断控制器一般是VIC(向量中断控制器)。

    1. GIC-400

    下面以GIC-400为例,它更适合嵌入式系统,符合v2版本的GIC architecture specification。GIC-400通过AMBA(Advanced Microcontroller Bus Architecture)片上总线连接到一个或者多个ARM处理器上。

    24146f950c8e3590ea70581bebf5348d.png

    从上图可以看出, GIC 是联系外设中断和 CPU 的桥梁,也是各 CPU 之间中断互联的通道(也带有管理功能),它负责检测、管理、分发中断,可以做到:

    1. 使能或禁止中断;
    2. 把中断分组到Group0还是Group1(Group0作为安全模式使用连接FIQ ,Group1 作为非安全模式使用,连接IRQ );
    3. 多核系统中将中断分配到不同处理器上;
    4. 设置电平触发还是边沿触发方式(不等于外设的触发方式);
    5. 虚拟化扩展。

    ARM CPU 对外的连接只有2 个中断: 「IRQ和FIQ」 ,相对应的处理模式分别是一般中断(IRQ )处理模式和快速中断(FIQ )处理模式。所以GIC 最后要把中断汇集成2 条线,与CPU 对接。

    0ee0263fc4bd219899eb34aed5bdba40.png

    分发器:负责各个子中断使能,设置触发方式,优先级排序,分发到哪个 CPU 上; 接口:负责总的中断的使能,状态的维护。

    2. 分发器功能

    分发器的主要的作用是检测各个中断源的状态,控制各个中断源的行为,分发各个中断源产生的中断事件到指定的一个或者多个CPU接口上。虽然分发器可以管理多个中断源,但是它总是把优先级最高的那个中断请求送往CPU接口。分发器对中断的控制包括:

    • (a)中断使能或禁能控制。分发器对中断的控制分成两个级别,一个是全局中断的控制(GIC_DIST_CTRL),一旦禁能了全局的中断,那么任何的中断源产生的中断事件都不会被传递到CPU接口;另外一个级别是对针对各个中断源进行控制(GIC_DIST_ENABLE_CLEAR),禁能某一个中断源会导致该中断事件不会分发到CPU接口,但不影响其他中断源产生中断事件的分发。
    • (b)控制将当前优先级最高的中断事件分发到一个或者一组CPU接口。
    • (c)优先级控制。
    • (d)中断属性设定,例如是电平触发还是边沿触发。
    • (e)中断的设定。

    分发器可以管理若干个中断源,这些中断源用ID来标识,我们称之interrupt ID。

    3. CPU接口功能

    CPU接口主要用于和CPU进行接口。

    主要功能包括:

    • (a)使能或者禁能CPU接口向连接的CPU提交中断事件。对于ARM,CPU接口和CPU之间的中断信号线是nIRQCPU和nFIQCPU。如果禁能了中断,那么即便是分发器分发了一个中断事件到CPU接口,但是也不会提交指定的nIRQ或者nFIQ通知CPU。
    • (b)ackowledging中断。CPU会向CPU接口应答中断,中断一旦被应答,分发器就会把该中断的状态从pending状态修改成active,如果没有后续pending的中断,那么CPU 接口就会deassert nIRQCPU和nFIQCPU信号线。如果在这个过程中又产生了新的中断,那么分发器就会把该中断的状态从pending状态修改成pending and active。此时,CPU接口仍然会保持nIRQ或者nFIQ信号的asserted状态,也就是向CPU通知下一个中断。
    • (c)中断处理完毕的通知。当中断处理器处理完了一个中断的时候,会向写CPU 接口的寄存器从而通知GIC已经处理完该中断。做这个动作一方面是通知分发器将中断状态修改为deactive,另外一方面,可以允许其他的pending的中断向CPU接口提交。
    • (d)设定优先级掩码。通过优先级掩码可以mask掉一些优先级比较低的中断,这些中断不会通知到CPU。
    • (e)设定中断抢占的策略。
    • (f)在多个中断事件同时到来的时候,选择一个优先级最高的通知CPU。

    48b1e57341a5293d55b80b7687242f28.png

    以上图为例,该图是按键产生的中断信号要到达cpu所要经过的路径。

    1. 外设中断源有很多,通常芯片厂商会设计若干个第一级中断控制器,进行第一次处理,key连接的是GPX1中断控制器,寄存器EXT_INT41_MASK用于使能该中断;
    2. GIC主要包括分排气和cpu interface;
    3. ICDISER用于使能分派器,ICDIPTR用于将中断信号分发给对应的cpu interface;
    4. ICCICR用于使能CPU interface;
    5. CPU上有两个引脚irq、fiq,gic最终会连接到CPU的irq,所有寄存器配置完毕后,按键一旦按下,那么就会给CPU的irq发送一个中断信号,cpu紧接着就会执行“4大步3小步”,进入中断异常处理流程。

    三、中断分类

    1. 中断源

    硬件中断(Hardware Interrupt)

    1. 可屏蔽中断(maskable interrupt)。硬件中断的一类,可通过在中断屏蔽寄存器中设定位掩码来关闭。
    2. 非可屏蔽中断(non-maskable interrupt,NMI)。硬件中断的一类,无法通过在中断屏蔽寄存器中设定位掩码来关闭。典型例子是时钟中断(一个硬件时钟以恒定频率—如50Hz—发出的中断)。
    3. 处理器间中断(interprocessor interrupt)。一种特殊的硬件中断。由处理器发出,被其它处理器接收。仅见于多处理器系统,以便于处理器间通信或同步。
    4. 伪中断(spurious interrupt)。一类不希望被产生的硬件中断。发生的原因有很多种,如中断线路上电气信号异常,或是中断请求设备本身有问题。

    软件中断(Software Interrupt)

    软件中断SWI,是一条CPU指令,用以自陷一个中断。由于软中断指令通常要运行一个切换CPU至内核态的子例程,它常被用作实现系统调用(System call)。

    外部中断

    1. I/O设备:如显示器、键盘、打印机、A / D转换器等。
    2. 数据通道:软盘、硬盘、光盘等。 数据通道中断也称直接存储器存取(DMA)操作中断,如磁盘、磁带机或CRT等直接与存储器交换数据所要求的中断。
    3. 实时时钟:如外部的定时电路等。在控制中遇到定时检测和控制,为此常采用一个外部时钟电路(可编程)控制其时间间隔。需要定时时,CPU发出命令使时钟电路开始工作,一旦到达规定时间,时钟电路发出中断请求,由CPU转去完成检测和控制工作。
    4. 用户故障源:如掉电、奇偶校验错误、外部设备故障等。

    产生于CPU内部的中断源

    1. 由CPU得运行结果产生:如除数为0、结果溢出、断点中断、单步中断、存储器读出出错等。
    2. 执行中断指令swi
    3. 非法操作或指令引起异常处理。

    2. 中断类型

    GIC 中断类型有3种:SGI(Software-generated interrupt)、PPI(Private peripheral interrupt )、SPI(Shared peripheral interrupt)。

    1. SGI: SGI为软件可以触发的中断,统一编号为0~15(ID0-ID7是不安全中断,ID8-ID15是安全中断),用于各个core之间的通信。该类中断通过相关联的中断号和产生该中断的处理器的CPUID来标识。 通常为边沿触发。
    2. PPI: PPI为每个 core 的私有外设中断,统一编号为 16-31 。例如每个 CPU 的 local timer 即 Arch Timer 产生的中断就是通过 PPI 发送给 CPU 的(安全为29,非安全为30)。

    通常为边沿触发和电平触发。

    1. SPI: SPI 是系统的外设产生的中断,为各个 core 公用的中断,统一编号为 32~1019 ,如 global timer 、uart 、gpio 产生的中断。 通常为边沿触发和电平触发。

    Note:电平触发是在高或低电平保持的时间内触发, 而边沿触发是由高到低或由低到高这一瞬间触发;在GIC中PPI和SGI类型的中断可以有相同的中断ID。

    3. 中断分派模式

    1. 1-N mode (SPIs using the GIC 1-N model) 表示中断可以发给所有的CPU,但只能由一个CPU来处理中断;换句话说,这种类型的中断有N个目标CPU,但只能由其中一个来处理;当某一个处理器应答了该中断,便会清除在所有目标处理器上该中断的挂起状态。
    2. N-N mode (PPIs and SGIs using the GIC N-N model) 表示中断可以发给所有CPU,每个CPU可以同时处理该中断。当该中断被某一个处理器应答了,这不会影响该中断在其他CPU接口上的状态。

    举两个例子说明:

    1)UART 接收到一包数据,产生了一个中断给GIC,GIC可以将该中断分配给CPU0-7中任何一个处理;假设该中断分配给CPU0处理了,那么在中断处理函数里面会把接收到的数据从UART FIFO读出。可以想象一下,如果CPU0在读数据时,另外一个CPU也在处理该中断,恰巧也在读数据,那么CPU0读到的数据是不全的。这就是1-N model中断,或者说SPI中断。

    2)比如CPU0给CPU1-7发送中断,想告知对方自己正在处理某个进程A。这种场景下,CPU1-7都接收到中断,都进入中断处理函数,CPU1-7获取到CPU0的信息后,在进程调度时,就可以绕开进程A,而自己调度其他进程。

    注:这个例子只是说明N-N model,实际上进程调度不都全是这样的。

    4. 通用中断处理

    当GIC接收到一个中断请求,将其状态设置为Pending。重新产生一个挂起状态的中断不影响该中断状态。中断处理顺序: ① GIC决定该中断是否使能,若没有被使能对GIC没有影响; ② 对于每个Pending中断,GIC决定目标处理器; ③ 对于每个处理器 ,Distributor根据它拥有的每个中断优先级信息决定最高优先级的挂起中断,将该中断传递给目标CPU Interface; ④ GIC Distributor将一个中断传递给CPU Interface后,该CPU Interface决定该中断是否有足够的优先级将中断请求发给CPU; ⑤ 当CPU开始处理该异常中断,它读取GICC_IAR应答中断。读取的GICC_IAR获取到中断ID,对于SGI,还有源处理器ID。中断ID被用来查找正确的中断处理程序。

    GIC识别读过程后,将改变该中断的状态: a) 当中断状态变为active时,如果该中断挂起状态持续存在或者中断再次产生,中断状态将从Pending转化为pending & active b) 否则,中断状态将从pending状态变为active

    ⑥ 当中断完成中断处理后,它需要通知GIC处理已经完成。这个过程称为 priority drop and interrupt deactivation: a) 总是需要向EOIR寄存器写入一个有效的值(end of interrupt register) b) 也需要接着向GICC_DIR写入值(deactivate interrupt register)

    5. 中断优先级

    软件可以通过给每一个中断源分配优先级值来配置中断优先级。优先级的值是个8位的无符号二进制数,GIC支持最小16和最大256的优先级级别。如果GIC实现的优先级少于256,那么优先级字段的低阶位为RAZ/WI。这就意味着实现的优先级字段个数范围是4~8,如下图所示:

    0d249a1255d43b2f2c0139ea954fb620.png

    Note: 1)、如何确定优先级字段所支持的优先级位? 通过软件往可写GICD_IPRIORITYn优先级字段写入0XFF,然后回读出该字段的值便可以确定优先级字段所支持的优先级位(因为有些位没实现是RAZ/WI) 2)、ARM 推荐在检查中断优先级范围之前先: • 对于外设中断,软件先禁用该中断 • 对于SGI,软件先检查该中断确定为inactive

    6. 中断抢占

    在一个active中断处理完之前,CPU interface支持发送更高优先级的挂起中断到目标处理器。这种情况必要条件如下:

    • 该中断的优先级高于当前CPU interface 被屏蔽的优先级
    • 该中断的组优先级高于正在当前CPU interface处理的中断优先级

    7. 中断屏蔽

    CPU interface的GICC_PMR寄存器定义了目标处理器的优先级阀值,GIC仅上报优先级高于阀值的pending中断给目标处理器。寄存器初始值为0,屏蔽所有的中断。

    四、FS4412中断外设-key

    下面我们来分析FS4412开发板的第一个中断设备按键。

    1. 电路图

    8f8031b38e23a563dbaba5c6633fe49a.png

    由该电路图可得:

    1. 按键k2 连接在GPX1_1引脚
    2. 控制逻辑 k2 按下 ---- K2闭合 ---- GPX1_1 低电压 k2 常态 ---- K2打开 ---- GPX1_1 高电压

    以下是key2与soc的连接,

    4d83c5f70f9db636cff5111757e43a4e.png

    可以看到key2复用了GPIX1_1这个引脚,同时该引脚还可以作为中断【XEINT9】使用。

    顺便看下GPXCON寄存器的配置

    9674c1c0a498dc80e3c6ea857fcb140d.png

    由上图所示,

    1. GPX1CON地址为0x1100C20;
    2. key2如果要做为输入设备,只需要将GPX1CON[7:4]设置为0x0;
    3. key2如果要做为中断信号,只需要将GPX1CON[7:4]设置为0xf。

    2. key中断处理

    中断配置

    key与soc的关系图如下图所示:

    dc2724e1450ec325ea14155c61fdc4d3.png

    由上图所示:

    1. 按键是直接连到GPIO控制器的
    2. EXT_INT_CON用来设置按键中断的触发方式,下降沿触发
    3. GPX1CON寄存器用于设置该GPIO位中断信号输入
    4. EXT_INT_MASK用于使能该中断
    5. ICDISER用于使能相应中断到分配器
    6. ICDDCR分配器开关
    7. ICDIPTR选择CPU接口
    8. ICCPMR设置中断屏蔽优先级
    9. ICCICR打开CPU开关,把CPU接口内的中断能够送到相应的CPU

    清中断

    CPU处理完中断,需要清除中断,对于按键来说,有3个寄存器需要操作:

    baa1e0656025ff60a560c39a68d17b8f.png

    由上图所示:

    1. EXT_INT41_PEND清相应的中断源
    2. ICDICPR中断结束后,清相应中断标志位,此标志位由硬件置位
    3. ICCEOIR中断执行结束,清cpu内相应的中断号,由硬件填充

    3. 寄存器汇总

    前面分析了按键连接的是GPX1_1,现在我们来看下对应的寄存器应该如何配置

    【1】、GPIO控制器

    1. GPX1PUD

    3a4fd6b1dbd42fd6c62f83337ab02e32.png

    将GPX1_1引脚的上拉和下拉禁止

      GPX1PUD[3:2]= 0b00;
    
    1. GPX1CON

    92cb392d8e672dee8e78946bb813b5f3.png

    将GPX1_1引脚功能设置为中断功能

    GPX1CON[7:4] = 0xf
    
    1. EXT_INT41CON

    2953517995acb53f0bdfdb66a5428e1a.png

    配置成成下降沿触发:

       EXT_INT41CON[6:4] = 0x2
    
    1. EXT_INT41_MASK

    dc23a9cb5cecc6c254585d33473c25cd.png

    中断使能寄存器

    EXT_INT41_MASK[1] = 0b0
    
    1. EXT_INT41_PEND 中断状态寄存器

    fc22c2264c3278636f9a4f1fab31b79b.png

    当GPX1_1引脚接收到中断信号,中断发生,中断状态寄存器EXT_INT41_PEND 相应位会自动置1 注意:中断处理完成的时候,需要清除相应状态位。置1清0.

    EXT_INT41_PEND[1] =0b1 
    

    【2】GIC

    根据外设中断名称EINT9来查看该中断对应的GIC中维护的HW id。【所有的中断源在芯片厂商设计的时候都分配了唯一的一个ID,GIC通过该ID来驱动中断源】

    查看芯片手册(datasheet -- 9.2表)

    65ed7a2ddfb4fb58f339d4f92ff3534e.png

    通过【9.2中断源表】找到和外设中断标示对应的中断控制器中断标识(GPIO有32个可被唤醒寄存器)其对应「EINT[9],中断ID为57」,这是非常重要的,在后面的寄存器设置中起很大作用;

    1) ICDISER使能相应中断到分配器

    7c9d75d8abb18ae704b19f2c593f77a1.png

    ICDISER用于使能相应中断到分配器,一个bit控制一个中断源,一个ICDISER可以控制32个中断源,这里INT[9] 对应的中断ID为57,所以在ICDSER1中进行设置,57/32 =1余25,所以这里在ICDISER1第25位置一。

      ICDISER.ICDISER1 |= (0x1 << 25);    //57/32 =1...25 取整数(那个寄存器) 和余数(哪位)
    
    1. ICDIPTR选择CPU接口

    b3585b729f97dfd68cad77b689ccb155.png

    c932ec9cc178c64e0e870e0004103815.png

    bb34f23e140c7b14523fa2b7685cc86a.png

    ICDIPTR寄存器每8个bit 控制一个中断源,其中CPU0可以处理160个中断源,所以需要40个寄存器。要选择cpu0第一个bit必须是1。

    设置SPI[25]/ID[57]由cpu0处理,57/4=16余1 所以选择寄存器ICDIPTR14的第2个字节[15:8]。

    //SPI 25 interrupts are sent to processor 0   
     //57/4 = 14..1 14号寄存器的[15:8]
    ICDIPTR.ICDIPTR14 |= 0x01<<8;
    
    1. ICDDCR使能分配器

    4e5b4db84701f5fe5ab8baeaad20cd50.png


    还寄存器用于使能分配器。

    ICDDCR =1;
    
    1. ICCPMR 优先级屏蔽寄存器,设置cpu0能处理所有的中断。 比如中断屏蔽优先级为255,该值表示优先级最低,所有的中断都能响应。

    843438e53a99e5cbff07e59215f4260f.png
    CPU0.ICCPMR = 0xFF;//设置cpu0 中断屏蔽优先级为255  最低,所有中断都能响应)
    
    1. ICCICR 全局使能cpu0中断处理

    1daf8c1db91eddb5b9de1fb229d6ebd1.png

    EXYNOS 4412一共有4个cpu,用4个寄存器分别来控制4个cpu,每个寄存器的bit[0]用于全局控制对应的cpu。我们选择cpu0处理中断,将bit[0]置1即可。

       CPU0.ICCICR |= 0x1;
       使能中断到CPU。
    
    1. ICCIAR

    77277d7c106ed3b2ffe1a0735712e4b1.png

    当中断发生之后,中断的HW id值会由硬件写入到寄存器ICCIAR[9:0]中;对于SGIs来说,多处理器环境下,CPU的interface值写入到[12:10]中。

    读取HW id:

     int irq_num;
     irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号
    

    五、代码实现

    要处理中断异常,必须安装异常向量表,异常的处理流程可以参考前面的文章《6. 从0开始学ARM-异常、异常向量表、swi》

    1. 异常向量表基址

    异常向量表地址是可以修改的,比如uboot在启动的时候,会从flash中搬运代码到RAM中,而flash的异常向量表地址和ram的地址肯定不一样,所以搬运完代码后,就必须要修改对应的异常向量表地址。

    修改异常向量表的地址的需要借助协处理器指令mcr:

    ldr r0,=0x40008000
    mcr p15,0,r0,c12,c0,0  @ Vector Base Address Register
    

    上述命令是将地址0x40008000设置为异常向量表的地址,关于mcr指令,我们没有必要深究,知道即可。

    RAM中异常向量表地址我们选用的是0x40008000,以下是exynos4412 地址空间分布。

    0972ea1736b43849ac31df5869a814d0.png

    2. 异常向量表安装

    .text
    .global _start
    _start:
      b  reset
      ldr  pc,_undefined_instruction
      ldr  pc,_software_interrupt
      ldr  pc,_prefetch_abort
      ldr  pc,_data_abort
      ldr  pc,_not_used
      ldr  pc,=irq_handler
      ldr  pc,_fiq
    reset:
    
     ldr r0,=0x40008000
     mcr p15,0,r0,c12,c0,0  @ Vector Base Address Register
    init_stack:
    //初始化栈
    ……
    b main //跳转至c的main函数
    
    irq_handler: //中断入口函数
    
     sub  lr,lr,#4
     stmfd sp!,{r0-r12,lr}
     .weak do_irq
     bl do_irq
     ldmfd sp!,{r0-r12,pc}^
    
    stacktop:    .word   stack+4*512//栈顶
    .data
    stack:  .space  4*512 //栈空间
    

    中断入口函数do_irq()

    void do_irq(void)
    {
     static int a = 1;
     int irq_num;
     irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号
     switch(irq_num)
     {
      case 57:
       printf("in the irq_handlern");
       //清GPIO中断标志位
       EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); 
       //清GIC中断标志位
       ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); 
      break;
     }
      //清cpu中断标志
     CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num;位
    }
    

    实现按键中断的初始化函数key_init():

    void key_init(void)  
    {  
        GPX1.CON =GPX1.CON & (~(0xf << 4)) |(0xf << 4); //配置引脚功能为外部中断  
        GPX1.PUD = GPX1.PUD & (~(0x3 << 2));  //关闭上下拉电阻  
        EXT_INT41_CON = EXT_INT41_CON &(~(0xf << 4))|(0x2 << 4); //外部中断触发方式  
        EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1 << 1));  //使能中断  
        ICDDCR = 1;  //使能分配器  
        ICDISER.ICDISER1 = ICDISER.ICDISER1 | (0x1 << 25); //使能相应中断到分配器  
        ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xff << 8))|(0x1 << 8); //选择CPU接口  
        CPU0.ICCPMR = 255; //中断屏蔽优先级  
        CPU0.ICCICR = 1;   //使能中断到CPU  
       return ;  
    } 
    
    

    六、轮询方式

    除了中断方式之外我们还可以通过轮询方式读取按键的信息,原理如下:

    循环检测GPX1_1引脚输入的电平,为低电压时,按键按下,为高电平时,按键抬起。
    
    1. 配置GPX1_1引脚功能为输入,设置内部上拉下拉禁止。
     GPX1.CON = GPX1.CON &(~(0xf<<4)) ;
     GPX1.PUD = GPX1.PUD & ~(0x3 << 2);
    
    1. 按键消抖: 按键按下后由于机械特性,会在极短的时间内出现电平忽0忽1,所以我们检测到按键按下后,需要给一个延时,然后再判断按键是不是仍然按下。
    2. 代码实现
    int main (void)
    {
     led_init();
     pwm_init();
     GPX1.CON = GPX1.CON &(~(0xf<<4))|0x0<<4;
     while(1)
     {
         if(!(GPX1.DAT & (0x1<<1)))  // 返回为真,按键按下
         {
          delay_ms(10);
             if(!(GPX1.DAT & (0x1<<1))) //二次检测,去抖
             {
                 GPX2.DAT |= 0x1 << 7;  //Turn on LED2
                 delay_ms(500);
                 beep_on();
                 GPX2.DAT &= ~(0x1<<7);  //Turn off LED2
    
                 delay_ms(500);
    
                 while(!(GPX1.DAT & (0x1<<1)));
                 beep_off();
             }
         }
     }
       return 0;
    }
    

    更多 ARM Linux干货,请关注 一口Linux

    展开全文
  • EXTINT0寄存器可以设置这四个引脚的中断产生的条件,需要注意的是EINT0~2都有自己的中断向量,而EINT4~7则共用一个中断向量。 因此使用EINT4时还要在EINTMASK寄存器开相应中断允许位,进入EINT4中断后还要清...
  • 发现此时计数器TBCTR到死区计数器值就清零了,重新计数,永远到不了PRD寄存器值,所以中断条件一直到不了。 寻找原因中 ...spm=1001.2101.3001.4242C2000中ePWM模块间同步延时问题 ...
  • 1. 概述 NIOS2 支持32个内部硬件中断,且有32级别的中断请求(irq0-irq31)。 软件通过ienable控制寄存器使...硬件中断产生的条件: status寄存器的PIE位为1 一个中断请求输入申请irq<n> 在ienable寄存器...
  • 我眼中Linux设备树(四 中断)

    千次阅读 2016-05-19 14:21:14
    中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中一个中断,这种情况中断产生设备中断源称之为中断控制器中对应中断子中断。一般情况中断产生设备数量要多于中断控制器,多个中断产生设备中断...
  • 1、用户按某些终端键时,引发终端产生的信号。如在终端按Ctrl+c将产生中断信号SIGINT. 2、硬件产生信号,如除数为0,无效的内存引用等。这些条件通常由硬件检测到传给内核,然后内核通知进程。 3、进程调用kill函数...
  • 中断

    2014-05-20 10:27:54
    内部中断是系统内预设异常处理,当满足预设条件时,就会产生软件中断。如:除0,debug,页错误等。 外部中断时来自外设,当外设与CPU交互式时,就会产生一个中断;外部中断是不可预测,随时都
  • -- Liran Haimovitch(作者)整段故事讲是我们在 Rookout 公司团队为 Python 调试器开发不中断断点经历,以及开发过程中得到经验。我将在本月于旧金山举办 PyBay 2019 上介绍有关 Python 调试过程更多细节...
  • 异常和中断的区别

    2020-06-17 12:53:20
    异常和中断的区别异常异常产生的原因异常产生的目的异常的产生和处理中断中断的原因中断的产生和处理 转载至:https://www.cnblogs.com/pengdonglin137/p/3308972.html 异常 是指CPU内部出现的中断,即在CPU执行特定...
  • 中断与异常区别

    2020-11-22 15:41:11
    硬件中断完全是随机产生的, 与处理器的执行并不同步。 当中断发生时, 处理器要先执行完当前的指令, 然后才对中断进行处理。 软中断是由 int n 指令引发的中断处理, n是中断号或者叫类型码。根据中断号在中断向量表中...
  • 中断系统基本知识

    2021-01-05 12:32:53
    对于51单片机而言,中断系统有5个中断源,它们符号、名称、产生 条件如下所示。 INT0:外部中断0,中断请求信号由P3.2输入,低电平或下降沿引起。 INT1:外部中断1,中断请求信号由P3.3输入,低电平或下降沿引起...
  • arm的中断

    2009-03-26 08:59:00
    保存处理器当前状态,中断屏蔽为以及条件标志位。即保存CPSR内容相应SPSR寄存器。各异常中断有自己SPSR2.设置CPSR值。设置CPSR位,使处理器进入相应执行模式,并禁止IRQ中断或FIQ中断3.将寄存器lr_mode...
  • 中断的睡眠状态的进程会睡眠直到某个条件变为真,如产生一个硬件中断、释放进程正在等待的系统资源或是传递一个信号都可以是唤醒进程的条件。 不可中断睡眠状态与可中断睡眠状态类似,但是它有一个例外,那就是.....
  • DSP中对中断的理解

    千次阅读 2017-07-28 16:00:04
    中断的理解:中断的执行过程是这样,当符合中断条件时,外设自发地产生(不需要用户设置)一个中断标志位(通常是置位),例如SCI中RXDY,这是不需要用户设置.外设响应这个中断,也称为使能中断。如SCI 中RX/...
  • 如何在程序中产生单步中断

    千次阅读 2010-10-18 19:51:00
    <br /> 各标志在标志寄存器中位置 条件标志:CF(Carry Flag)进位标志:用于反映运算是否产生进位或借位。如果运算结果最高位产生一个进位或借位,则CF置1,否则置0。运算结果最高位
  • 基于S5PV210的中断处理的过程和代码分析 ...3、相应的中断所有的条件使能 第二部分:当硬件产生中断后是如何执行ISR的? 1、第一步:经过异常向量表跳转入IRQ入口 2、第二步:做中断的现场保护,然后跳入ISR_handler
  • 单片机中断简介52单片机一共有6个中断源,它们的符号,名称以及各产生的条件分别如下:INT0 - 外部中断0,由P3.2端口线引入,低电平或下降沿引起INT1 - 外部中断1,由P3.3端口线引入,低电平或下降沿引起T0 - 定时器...
  • 使用软中断,首先要有硬件指令支持.ARM有条指令是SWI.SWI 指令格式为:SWI {条件} 24 位立即数SWI 指令用于产生软件中断,以便用户程序能调用操作系统系统例程。操作系统在 SWI 异常处理程序中提供相应...
  • 单片机中断简介52单片机一共有6个中断源,它们的符号,名称以及各产生的条件分别如下:INT0 - 外部中断0,由P3.2端口线引入,低电平或下降沿引起INT1 - 外部中断1,由P3.3端口线引入,低电平或下降沿引起T0 - 定时器...
  • 基于ARM软件中断swi

    2017-01-11 19:28:23
    SWI指令用于产生软件中断,以便用户程序能调用操作系统系统例程。操作系统在 SWI异常处理程序中提供相应系统服务,指令中 24位立即数指定用户程序调用系统例程类型,相关参数通过通用寄存器传递,当指令中...
  • 中断和异常的区别 1、异常:  是指CPU内部出现的中断,即在CPU执行特定指令时出现的非法情况。同时异常也称为同步中断,因此... 内核必须处理的异常条件产生的(eg:缺页)  产生的目的:  Linux利用异常来达到两...
  • 1 中断机制的产生 早期计算机各个程序只能串行执行、系统资源利用低。为了解决上述问题,人们就发明了操作系统,引入了中断机制,实现了多道程序并发执行,提高了系统资源利用率。中断是多程序并发执行前提...
  • Linux设备树(四 中断)

    2019-10-05 22:50:55
    中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中一个中断,这种情况中断产生设备中断源称之为中断控制器中对应中断子中断。一般情况中断产生设备数量要多于中断控制器,多个中断产生设备中断...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 582
精华内容 232
关键字:

中断产生的条件