精华内容
下载资源
问答
  • 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层。内核版本基于3.3。虽然内核的版本不断地提升,不过自从上一...

    这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层。内核版本基于3.3。虽然内核的版本不断地提升,不过自从上一次变更到当前的通用中断子系统后,大的框架性的东西并没有太大的改变。

     

    /*****************************************************************************************************/
    声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
    /*****************************************************************************************************/

    1.  设备、中断控制器和CPU

    一个完整的设备中,与中断相关的硬件可以划分为3类,它们分别是:设备、中断控制器和CPU本身,下图展示了一个smp系统中的中断硬件的组成结构:


                                                                           图 1.1  中断系统的硬件组成

            设备  设备是发起中断的源,当设备需要请求某种服务的时候,它会发起一个硬件中断信号,通常,该信号会连接至中断控制器,由中断控制器做进一步的处理。在现代的移动设备中,发起中断的设备可以位于soc(system-on-chip)芯片的外部,也可以位于soc的内部,因为目前大多数soc都集成了大量的硬件IP,例如I2C、SPI、Display Controller等等。

            中断控制器  中断控制器负责收集所有中断源发起的中断,现有的中断控制器几乎都是可编程的,通过对中断控制器的编程,我们可以控制每个中断源的优先级、中断的电器类型,还可以打开和关闭某一个中断源,在smp系统中,甚至可以控制某个中断源发往哪一个CPU进行处理。对于ARM架构的soc,使用较多的中断控制器是VIC(Vector Interrupt Controller),进入多核时代以后,GIC(General Interrupt Controller)的应用也开始逐渐变多。

            CPU  cpu是最终响应中断的部件,它通过对可编程中断控制器的编程操作,控制和管理者系统中的每个中断,当中断控制器最终判定一个中断可以被处理时,他会根据事先的设定,通知其中一个或者是某几个cpu对该中断进行处理,虽然中断控制器可以同时通知数个cpu对某一个中断进行处理,实际上,最后只会有一个cpu相应这个中断请求,但具体是哪个cpu进行响应是可能是随机的,中断控制器在硬件上对这一特性进行了保证,不过这也依赖于操作系统对中断系统的软件实现。在smp系统中,cpu之间也通过IPI(inter processor interrupt)中断进行通信。

    2.  IRQ编号

    系统中每一个注册的中断源,都会分配一个唯一的编号用于识别该中断,我们称之为IRQ编号。IRQ编号贯穿在整个Linux的通用中断子系统中。在移动设备中,每个中断源的IRQ编号都会在arch相关的一些头文件中,例如arch/xxx/mach-xxx/include/irqs.h。驱动程序在请求中断服务时,它会使用IRQ编号注册该中断,中断发生时,cpu通常会从中断控制器中获取相关信息,然后计算出相应的IRQ编号,然后把该IRQ编号传递到相应的驱动程序中。

    3.  在驱动程序中申请中断

    Linux中断子系统向驱动程序提供了一系列的API,其中的一个用于向系统申请中断:


    1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,  
    2.              irq_handler_t thread_fn, unsigned long irqflags,  
    3.              const char *devname, void *dev_id)  

    其中,

    • irq是要申请的IRQ编号,
    • handler是中断处理服务函数,该函数工作在中断上下文中,如果不需要,可以传入NULL,但是不可以和thread_fn同时为NULL;
    • thread_fn是中断线程的回调函数,工作在内核进程上下文中,如果不需要,可以传入NULL,但是不可以和handler同时为NULL;
    • irqflags是该中断的一些标志,可以指定该中断的电气类型,是否共享等信息;
    • devname指定该中断的名称;
    • dev_id用于共享中断时的cookie data,通常用于区分共享中断具体由哪个设备发起;

    关于该API的详细工作机理我们后面再讨论。

    4.  通用中断子系统(Generic irq)的软件抽象

    在通用中断子系统(generic irq)出现之前,内核使用__do_IRQ处理所有的中断,这意味着__do_IRQ中要处理各种类型的中断,这会导致软件的复杂性增加,层次不分明,而且代码的可重用性也不好。事实上,到了内核版本2.6.38,__do_IRQ这种方式已经彻底在内核的代码中消失了。通用中断子系统的原型最初出现于ARM体系中,一开始内核的开发者们把3种中断类型区分出来,他们是:

    • 电平触发中断(level type)
    • 边缘触发中断(edge type)
    • 简易的中断(simple type)
    后来又针对某些需要回应eoi(end of interrupt)的中断控制器,加入了fast eoi type,针对smp加入了per cpu type。把这些不同的中断类型抽象出来后,成为了中断子系统的流控层。要使所有的体系架构都可以重用这部分的代码,中断控制器也被进一步地封装起来,形成了中断子系统中的硬件封装层。我们可以用下面的图示表示通用中断子系统的层次结构:


                                                     图 4.1  通用中断子系统的层次结构

            硬件封装层  它包含了体系架构相关的所有代码,包括中断控制器的抽象封装,arch相关的中断初始化,以及各个IRQ的相关数据结构的初始化工作,cpu的中断入口也会在arch相关的代码中实现。中断通用逻辑层通过标准的封装接口(实际上就是struct irq_chip定义的接口)访问并控制中断控制器的行为,体系相关的中断入口函数在获取IRQ编号后,通过中断通用逻辑层提供的标准函数,把中断调用传递到中断流控层中。我们看看irq_chip的部分定义:

    1. struct irq_chip {  
    2.     const char  *name;  
    3.     unsigned int    (*irq_startup)(struct irq_data *data);  
    4.     void        (*irq_shutdown)(struct irq_data *data);  
    5.     void        (*irq_enable)(struct irq_data *data);  
    6.     void        (*irq_disable)(struct irq_data *data);  
    7.   
    8.     void        (*irq_ack)(struct irq_data *data);  
    9.     void        (*irq_mask)(struct irq_data *data);  
    10.     void        (*irq_mask_ack)(struct irq_data *data);  
    11.     void        (*irq_unmask)(struct irq_data *data);  
    12.     void        (*irq_eoi)(struct irq_data *data);  
    13.   
    14.     int     (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);  
    15.     int     (*irq_retrigger)(struct irq_data *data);  
    16.     int     (*irq_set_type)(struct irq_data *data, unsigned int flow_type);  
    17.     int     (*irq_set_wake)(struct irq_data *data, unsigned int on);  
    18.         ......  
    19. };  
    看到上面的结构定义,很明显,它实际上就是对中断控制器的接口抽象,我们只要对每个中断控制器实现以上接口(不必全部),并把它和相应的irq关联起来,上层的实现即可通过这些接口访问中断控制器。而且,同一个中断控制器的代码可以方便地被不同的平台所重用。

            中断流控层  所谓中断流控是指合理并正确地处理连续发生的中断,比如一个中断在处理中,同一个中断再次到达时如何处理,何时应该屏蔽中断,何时打开中断,何时回应中断控制器等一系列的操作。该层实现了与体系和硬件无关的中断流控处理操作,它针对不同的中断电气类型(level,edge......),实现了对应的标准中断流控处理函数,在这些处理函数中,最终会把中断控制权传递到驱动程序注册中断时传入的处理函数或者是中断线程中。目前内核提供了以下几个主要的中断流控函数的实现(只列出部分):

    • handle_simple_irq();  
    • handle_level_irq();  电平中断流控处理程序
    • handle_edge_irq();  边沿触发中断流控处理程序
    • handle_fasteoi_irq();  需要eoi的中断处理器使用的中断流控处理程序
    • handle_percpu_irq();  该irq只有单个cpu响应时使用的流控处理程序

            中断通用逻辑层  该层实现了对中断系统几个重要数据的管理,并提供了一系列的辅助管理函数。同时,该层还实现了中断线程的实现和管理,共享中断和嵌套中断的实现和管理,另外它还提供了一些接口函数,它们将作为硬件封装层和中断流控层以及驱动程序API层之间的桥梁,例如以下API:

    • generic_handle_irq();
    • irq_to_desc();
    • irq_set_chip();
    • irq_set_chained_handler();

            驱动程序API  该部分向驱动程序提供了一系列的API,用于向系统申请/释放中断,打开/关闭中断,设置中断类型和中断唤醒系统的特性等操作。驱动程序的开发者通常只会使用到这一层提供的这些API即可完成驱动程序的开发工作,其他的细节都由另外几个软件层较好地“隐藏”起来了,驱动程序开发者无需再关注底层的实现,这看起来确实是一件美妙的事情,不过我认为,要想写出好的中断代码,还是花点时间了解一下其他几层的实现吧。其中的一些API如下:

    • enable_irq();
    • disable_irq();
    • disable_irq_nosync();
    • request_threaded_irq();
    • irq_set_affinity();

    这里不再对每一层做详细的介绍,我将会在本系列的其他几篇文章中做深入的探讨。

    5.  irq描述结构:struct irq_desc

    整个通用中断子系统几乎都是围绕着irq_desc结构进行,系统中每一个irq都对应着一个irq_desc结构,所有的irq_desc结构的组织方式有两种:

            基于数组方式  平台相关板级代码事先根据系统中的IRQ数量,定义常量:NR_IRQS,在kernel/irq/irqdesc.c中使用该常量定义irq_desc结构数组:

    1. struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {  
    2.     [0 ... NR_IRQS-1] = {  
    3.         .handle_irq = handle_bad_irq,  
    4.         .depth      = 1,  
    5.         .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),  
    6.     }  
    7. };  

            基于基数树方式  当内核的配置项CONFIG_SPARSE_IRQ被选中时,内核使用基数树(radix tree)来管理irq_desc结构,这一方式可以动态地分配irq_desc结构,对于那些具备大量IRQ数量或者IRQ编号不连续的系统,使用该方式管理irq_desc对内存的节省有好处,而且对那些自带中断控制器管理设备自身多个中断源的外部设备,它们可以在驱动程序中动态地申请这些中断源所对应的irq_desc结构,而不必在系统的编译阶段保留irq_desc结构所需的内存。

    下面我们看一看irq_desc的部分定义:

    1. struct irq_data {  
    2.     unsigned int        irq;  
    3.     unsigned long       hwirq;  
    4.     unsigned int        node;  
    5.     unsigned int        state_use_accessors;  
    6.     struct irq_chip     *chip;  
    7.     struct irq_domain   *domain;  
    8.     void            *handler_data;  
    9.     void            *chip_data;  
    10.     struct msi_desc     *msi_desc;  
    11. #ifdef CONFIG_SMP  
    12.     cpumask_var_t       affinity;  
    13. #endif  
    14. };  

     

    1. struct irq_desc {  
    2.     struct irq_data     irq_data;  
    3.     unsigned int __percpu   *kstat_irqs;  
    4.     irq_flow_handler_t  handle_irq;  
    5. #ifdef CONFIG_IRQ_PREFLOW_FASTEOI  
    6.     irq_preflow_handler_t   preflow_handler;  
    7. #endif  
    8.     struct irqaction    *action;    /* IRQ action list */  
    9.     unsigned int        status_use_accessors;  
    10.     unsigned int        depth;      /* nested irq disables */  
    11.     unsigned int        wake_depth; /* nested wake enables */  
    12.     unsigned int        irq_count;  /* For detecting broken IRQs */  
    13.   
    14.     raw_spinlock_t      lock;  
    15.     struct cpumask      *percpu_enabled;  
    16. #ifdef CONFIG_SMP  
    17.     const struct cpumask    *affinity_hint;  
    18.     struct irq_affinity_notify *affinity_notify;  
    19. #ifdef CONFIG_GENERIC_PENDING_IRQ  
    20.     cpumask_var_t       pending_mask;  
    21. #endif  
    22. #endif  
    23.     wait_queue_head_t       wait_for_threads;  
    24.   
    25.     const char      *name;  
    26. } ____cacheline_internodealigned_in_smp;  
    对于irq_desc中的主要字段做一个解释:     

            irq_data  这个内嵌结构在2.6.37版本引入,之前的内核版本的做法是直接把这个结构中的字段直接放置在irq_desc结构体中,然后在调用硬件封装层的chip->xxx()回调中传入IRQ编号作为参数,但是底层的函数经常需要访问->handler_data,->chip_data,->msi_desc等字段,这需要利用irq_to_desc(irq)来获得irq_desc结构的指针,然后才能访问上述字段,者带来了性能的降低,尤其在配置为sparse irq的系统中更是如此,因为这意味着基数树的搜索操作。为了解决这一问题,内核开发者把几个低层函数需要使用的字段单独封装为一个结构,调用时的参数则改为传入该结构的指针。实现同样的目的,那为什么不直接传入irq_desc结构指针?因为这会破坏层次的封装性,我们不希望低层代码可以看到不应该看到的部分,仅此而已。

            kstat_irqs  用于irq的一些统计信息,这些统计信息可以从proc文件系统中查询。

            action  中断响应链表,当一个irq被触发时,内核会遍历该链表,调用action结构中的回调handler或者激活其中的中断线程,之所以实现为一个链表,是为了实现中断的共享,多个设备共享同一个irq,这在外围设备中是普遍存在的。

            status_use_accessors  记录该irq的状态信息,内核提供了一系列irq_settings_xxx的辅助函数访问该字段,详细请查看kernel/irq/settings.h

            depth  用于管理enable_irq()/disable_irq()这两个API的嵌套深度管理,每次enable_irq时该值减去1,每次disable_irq时该值加1,只有depth==0时才真正向硬件封装层发出关闭irq的调用,只有depth==1时才会向硬件封装层发出打开irq的调用。disable的嵌套次数可以比enable的次数多,此时depth的值大于1,随着enable的不断调用,当depth的值为1时,在向硬件封装层发出打开irq的调用后,depth减去1后,此时depth为0,此时处于一个平衡状态,我们只能调用disable_irq,如果此时enable_irq被调用,内核会报告一个irq失衡的警告,提醒驱动程序的开发人员检查自己的代码。

            lock  用于保护irq_desc结构本身的自旋锁。

            affinity_hit  用于提示用户空间,作为优化irq和cpu之间的亲缘关系的依据。

            pending_mask  用于调整irq在各个cpu之间的平衡。

            wait_for_threads  用于synchronize_irq(),等待该irq所有线程完成。

    irq_data结构中的各字段:

            irq  该结构所对应的IRQ编号。

            hwirq  硬件irq编号,它不同于上面的irq;

            node  通常用于hwirq和irq之间的映射操作;

            state_use_accessors  硬件封装层需要使用的状态信息,不要直接访问该字段,内核定义了一组函数用于访问该字段:irqd_xxxx(),参见include/linux/irq.h。

            chip  指向该irq所属的中断控制器的irq_chip结构指针

            handler_data  每个irq的私有数据指针,该字段由硬件封转层使用,例如用作底层硬件的多路复用中断。

            chip_data  中断控制器的私有数据,该字段由硬件封转层使用。

            msi_desc  用于PCIe总线的MSI或MSI-X中断机制。

            affinity  记录该irq与cpu之间的亲缘关系,它其实是一个bit-mask,每一个bit代表一个cpu,置位后代表该cpu可能处理该irq。


    这是通用中断子系统系列文章的第一篇,这里不会详细介绍各个软件层次的实现原理,但是有必要对整个架构做简要的介绍:

    • 系统启动阶段,取决于内核的配置,内核会通过数组或基数树分配好足够多的irq_desc结构;
    • 根据不同的体系结构,初始化中断相关的硬件,尤其是中断控制器;
    • 为每个必要irq的irq_desc结构填充默认的字段,例如irq编号,irq_chip指针,根据不同的中断类型配置流控handler;
    • 设备驱动程序在初始化阶段,利用request_threaded_irq() api申请中断服务,两个重要的参数是handler和thread_fn;
    • 当设备触发一个中断后,cpu会进入事先设定好的中断入口,它属于底层体系相关的代码,它通过中断控制器获得irq编号,在对irq_data结构中的某些字段进行处理后,会将控制权传递到中断流控层(通过irq_desc->handle_irq);
    • 中断流控处理代码在作出必要的流控处理后,通过irq_desc->action链表,取出驱动程序申请中断时注册的handler和thread_fn,根据它们的赋值情况,或者只是调用handler回调,或者启动一个线程执行thread_fn,又或者两者都执行;
    • 至此,中断最终由驱动程序进行了响应和处理。

    6.  中断子系统的proc文件接口

    在/proc目录下面,有两个与中断子系统相关的文件和子目录,它们是:

    • /proc/interrupts:文件
    • /proc/irq:子目录
    读取interrupts会依次显示irq编号,每个cpu对该irq的处理次数,中断控制器的名字,irq的名字,以及驱动程序注册该irq时使用的名字,以下是一个例子:


    /proc/irq目录下面会为每个注册的irq创建一个以irq编号为名字的子目录,每个子目录下分别有以下条目:

    • smp_affinity            irq和cpu之间的亲缘绑定关系;
    • smp_affinity_hint   只读条目,用于用户空间做irq平衡只用;
    • spurious                  可以获得该irq被处理和未被处理的次数的统计信息;
    • handler_name       驱动程序注册该irq时传入的处理程序的名字;
    根据irq的不同,以上条目不一定会全部都出现,以下是某个设备的例子:

    # cd /proc/irq
    # ls
    ls
    332
    248
    ......
    ......
    12
    11
    default_smp_affinity


    # ls 332
    bcmsdh_sdmmc
    spurious
    node
    affinity_hint
    smp_affinity


    # cat 332/smp_affinity
    3

    可见,以上设备是一个使用双核cpu的设备,因为smp_affinity的值是3,系统默认每个中断可以由两个cpu进行处理。


    本章内容结束。接下来的计划:

    Linux中断(interrupt)子系统之二:arch相关的硬件封装层

    Linux中断(interrupt)子系统之三:中断流控处理层

    Linux中断(interrupt)子系统之四:驱动程序接口层

    Linux中断(interrupt)子系统之五:软件中断(softirq)


    展开全文
  • Linux 中断系统,软中断实现原理解析,softirq: 首先是二级中断向量,接着是 一级中断的内容: /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high frequency threaded job ...
    
    

    Linux 中断子系统,软中断实现原理解析,softirq:

    首先是二级中断向量,接着是

    一级中断的内容:

    /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
    frequency threaded job scheduling. For almost all the purposes
    tasklets are more than enough. F.e. all serial device BHs et
    al. should be converted to tasklets, not to softirqs.
    */
    enum
    {
    HI_SOFTIRQ=0,      //
    高优先级软中断,高优先级的tasklet            tasklet_hi_action
    NET_TX_SOFTIRQ,  //
    网络数据包发送
    NET_RX_SOFTIRQ,  //网络数据包接受
    TASKLET_SOFTIRQ  //一般行的软中断,一般性的tasklet                       bh_action
    };

    底层触发方式:

    static inline void raise_softirq(int nr)   //内联函数为最高封装,属于原子操作。
    {
    unsigned long flags;

    local_irq_save(flags);    //
    现场的保存
    __cpu_raise_softirq(smp_processor_id(), nr);
    local_irq_restore(flags);                //
    位置①
    }

     

    static inline void __cpu_raise_softirq(int cpu, int nr)
    {
    softirq_active(cpu) |= (1<<nr);
    }

    也就是对某个个位置1,就可以实现产生一个中断,并且回到位置①处,显然单片机的定时器很容易实现该功能,比如对某个寄存器进行点评的修改,长生一个中断给中断控制器,进而执行相应的中断处理函数,然后返回。例子:红外接收。

    高层中断触发方式:

    static inline void tasklet_hi_schedule(struct tasklet_struct *t)
    {
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
    int cpu = smp_processor_id();
    unsigned long flags;

    local_irq_save(flags);    //
    现场保存寄存器,内存,代码等
    t->next = tasklet_hi_vec[cpu].list;
    tasklet_hi_vec[cpu].list = t;
    __cpu_raise_softirq(cpu, HI_SOFTIRQ);
    local_irq_restore(flags);        //
    现场的恢复。
    }
    }

    以下同理:

    static inline void tasklet_schedule(struct tasklet_struct *t)
    {
    if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
    int cpu = smp_processor_id();
    unsigned long flags;

    local_irq_save(flags);
    t->next = tasklet_vec[cpu].list;
    tasklet_vec[cpu].list = t;
    __cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
    local_irq_restore(flags);
    }
    }

    二级中断系统:

    中断类型:

    num {
    TIMER_BH = 0,       //
    定时器或者是时钟中断
    TQUEUE_BH,
    DIGI_BH,
    SERIAL_BH,
    RISCOM8_BH,
    SPECIALIX_BH,
    AURORA_BH,
    ESP_BH,
    SCSI_BH,
    IMMEDIATE_BH,
    CYCLADES_BH,
    CM206_BH,
    JS_BH,
    MACSERIAL_BH,
    ISICOM_BH
    };

    软中断初始化:

    void __init softirq_init()
    {
    int i;

    for (i=0; i<32; i++)
    tasklet_init(bh_task_vec+i, bh_action, i);

    open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
    绑定一级中断的两个中断服务程序
    open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);        绑定一级中断的两个中断服务程序

    }

     

    中断服务程序:

    static void tasklet_action(struct softirq_action *a)

    {

    int cpu = smp_processor_id();

    struct tasklet_struct *list;

     

    local_irq_disable();

    list = tasklet_vec[cpu].list;

    tasklet_vec[cpu].list = NULL;

    local_irq_enable();

     

    while (list != NULL) {

    struct tasklet_struct *t = list;

     

    list = list->next;

     

    if (tasklet_trylock(t)) {

    if (atomic_read(&t->count) == 0) {

    clear_bit(TASKLET_STATE_SCHED, &t->state);

     

    t->func(t->data);            //执行tasklet_struct里面的函数,以及tasklet_struct里面保存的参数具体见绿色的初始化。

    /*

    * talklet_trylock() uses test_and_set_bit that imply

    * an mb when it returns zero, thus we need the explicit

    * mb only here: while closing the critical section.

    */

    #ifdef CONFIG_SMP

    smp_mb__before_clear_bit();

    #endif

    tasklet_unlock(t);

    continue;

    }

    tasklet_unlock(t);

    }

    local_irq_disable();

    t->next = tasklet_vec[cpu].list;

    tasklet_vec[cpu].list = t;

    __cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);

    local_irq_enable();

    }

    }

    绿色:

    void __init softirq_init()
    {
    ……
    for (i=0; i<32; i++)
    tasklet_init(bh_task_vec+i, bh_action, i);
    ……
    }

     

    void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)
    {
    t->func = func;
    t->data = data;
    t->state = 0;
    atomic_set(&t->count, 0);
    }

    一起使用bh_action函数,但使用不同的i参数,所以:

    static void bh_action(unsigned long nr)
    {
    int cpu = smp_processor_id();

    if (!spin_trylock(&global_bh_lock))
    goto resched;

    if (!hardirq_trylock(cpu))
    goto resched_unlock;

    if (bh_base[nr])
    bh_base[nr]();       
    //
    根据不同的参数,调用bh_base数组的不同的函数。而bh_base数组是32个对应于二级中断的32中类型。(中断底半部)

    hardirq_endlock(cpu);
    spin_unlock(&global_bh_lock);
    return;

    resched_unlock:
    spin_unlock(&global_bh_lock);
    resched:
    mark_bh(nr);
    }

     

    Tasklet的状态:

    1state成员所表示的运行状态;(2count成员决定的使能/禁止状态。 Enable disabled

    num
    {
    TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */    
    已经准备好了,只要被选择就可以执行。
    TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ 对于SMP系统表示已经在其它cpu上运行了。
    };

     

    参考自:http://blog.chinaunix.net/uid-145571-id-2798845.html

    展开全文
  • 嵌入式系统原理中断

    千次阅读 2018-09-17 15:24:37
    中断是一种硬件机制,用于通知CPU有个异步事件发生了。 当微处理器检测到某个中断请求引脚上有信号时,微处理器就会停止当前正在执行的应用程序,CPU保存部分(或全部)现场即部分或全部寄存器的值,跳转到中断服务...

    中断是一种硬件机制,用于通知CPU有个异步事件发生了。

    当微处理器检测到某个中断请求引脚上有信号时,微处理器就会停止当前正在执行的应用程序,CPU保存部分(或全部)现场即部分或全部寄存器的值,跳转到中断服务程序ISR。

     

    先占个坑,有空再写。。。

    展开全文
  • 玖:中断系统原理与应用

    千次阅读 2018-09-30 21:40:27
    顾名思义,中断就是中断当前工作去处理一些临时发生的时间,处理完后,则继续原工作过程。例如:你在看书,电话响了,你在书上做好记号后去接电话,接完之后再原记号处继续往下看书。 2、51单片机也需要“中断”?...

    基本概念

    1、什么是“中断”?
    顾名思义,中断就是中断当前工作去处理一些临时发生的时间,处理完后,则继续原工作过程。例如:你在看书,电话响了,你在书上做好记号后去接电话,接完之后再原记号处继续往下看书。
    2、51单片机也需要“中断”?
    通常单片机中只有一个CPU,但却要应对诸如:运行程序、数据输入、数据输出、以及特殊情况处理等多项任务,为此单片机必须具备中断处理的功能,以应对特殊情况的紧急处理。
    3、“中断过程”是怎样的?
    中断的目的是为了暂停主程序的运行,先去执行中断服务程序,其功能是为了提高CPU工作效率。在中断源提出中断请求后,处理器执行完当前指令便进行中断响应,一旦中断服务程序执行完毕后,仍须返回到主程序被中断处(断点处)继续执行原先程序,其过程如图所示

    这里写图片描述

    4、谁能“中断”51单片机?
    中断源:能引发中断的来源称为中断源。
    51单片机一共支持5个中断源(2个外部中断源,3个内部中断源),这些中断源分别是:
    (1)外部中断请求0,由INT0(P3.2引脚)输入。
    (2)外部中断请求1,由INT1(P3.3引脚)输入。
    (3)片内定时/计数器0溢出中断(T0)请求。
    (4)片内定时/计数器0溢出中断(T1)请求。
    (5)片内串行口发送/接收中断请求。

    5、“中断源”同时来临,怎么办?
    中断优先级:处理中断源的优先顺序称为中断优先级

    51单片机将优先级整个划分为2个大等级:高优先级和低优先级。高优先级的中断先响应,等高优先级的中断响应完之后才响应低优先级的中断,高低优先级的分配可通过IP寄存器来设置。
    当多个中断都分配为同一个优先等级,并且发生中断时,由查询电路来确定最终优先级。
    对于同一优先级,单片机对其中断次序安排如下:外部中断0>定时/计数器T0>外部中断1>定时/计数器T1>串行口。
    6、“中断源”的信号可否屏蔽?
    51单片机是可以屏蔽中断信号的。有总开关和分开关。
    这里写图片描述

    7、中断响应可否嵌套?
    高优先级中断是可以打断低优先级的中断处理过程。
    这里写图片描述

    8、每个“中断”响应程序放在哪里呢?

    51单片机给每个中断安排了一个唯一的中断入口地址。

    中断源的入口地址表

    中断源
    入口地址
    外部中断0(INT0)
    0003H
    定时/计数器0
    000BH
    外部中断1(INT1)
    0013H
    定时/计数器1
    001BH
    串行口中断
    0023H

    51中断的使用

    ★★★中断允许寄存器(IE)

    D7
    D6
    D5
    D4
    D3
    D2
    D1
    D0
    EA
    ES
    ET1
    EX1
    ET0
    EX0
    ![这里写图片描述](https://img-blog.csdn.net/20180705231013334?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE3MDE3NTQ1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) EA:中断总开关位。EA = 1,开中断;EA = 0,禁止所有中断。(分开关类似)

    ★★★中断优先级寄存器(IP)

    D7
    D6
    D5
    D4
    D3
    D2
    D1
    D0
    PS
    PT1
    PX1
    PT0
    PX0
    对应中断源
    对应中断源
    对应中断源
    串行口
    定时器1
    外部中断1
    定时器0
    外部中断0
    以上表格中,若某位=1,则该对应的中断源设置为高优先级;若该位=0,则该对应的中断源设置为低优先级。 **★★★各中断源的标志位** **TCON**
    D7
    D6
    D5
    D4
    D3
    D2
    D1
    D0
    TF1
    TF0
    IE1
    IT1
    IE0
    IT0
    T1计数溢出
    T0计数溢出
    外部中断1
    外部中断0

    SCON

    D7
    D6
    D5
    D4
    D3
    D2
    D1
    D0
    TI
    RI
    发送完毕
    接收完毕

    IT0、IT1:外部中断0、1触发方式选择位,由软件设置。1:下降沿触发方式;0:低电平触发方式
    IE0、IE1:外部中断0、1请求标志位。当外部中断0、1依据触发方式满足产生中断请求是,由硬件置位。
    RI :串行口接收中断请求标志位。当串行口接收完一帧数据后请求中断时,由硬件置位(RI=1)。RI必须由软件清0。
    TI:串行口发送中断请求标志位。当串行口发送完一帧数据后请求中断时,由硬件置位(TI=1)。TI必须由软件清0。

    (1)中断初始化
    中断系统的初始化:在为某个中断源编写中断服务程序前,首先应在主程序中对中断系统进行初始化,初始化步骤应包括:
    1)软件清除相应中断源的中断标志位,以消除以前中断标志对现在的影响。
    2)默认或设置中断优先级。
    3)其他设置:若为外部中断,应设置是电平触发方式还是下降沿触发方式;若为定时/计数器中断,应将定时/计数初值送入寄存器THx、TLx中。
    4)打开相应中断源的分开关和总开关EA。
    (2)中断服务程序的预先安排
    汇编语言要哟昂到ORG伪指令和JMP跳转指令,C语言要用到关键字interrupt。
    中断服务程序入口地址设置

    中断源
    服务程序名称(假设)
    入口地址
    汇编程序
    C程序
    外部中断0
    INT0_i
    0003H
    ORG 0003H JMP INT0_i
    INT0_i() interrupt 0
    定时/计数器0
    T0_i
    000BH
    ORG 000BH JMP T0_i
    T0_i() interrupt 1
    外部中断1
    INT1_i
    0013H
    ORG 0013H JMP INT1_i
    INT1_i() interrupt 2
    定时/计数器1
    T1_i
    001BH
    ORG 001BH JMP T1_i
    T1_i() interrupt 3
    串行口
    COM_i
    0023H
    ORG 0023H JMP COM_i
    COM_i() interrupt 4

    (3)中断服务程序的预先安排

    	ORG		OOOOH
    	JMP 	Start	;跳转到主程序
    	ORG		00BH
    	JMP		T0_i	;跳转到T0中断服务程序处
    	ORG		0030H
    Start:			;主程序
    	……
    T0_i:			;T0的中断服务程序
    	……
    	RETI        ;中断返回
    	END		
    

    (4)中断返回
    一旦某个中断请求得到响应,单片机必须把它的相应对应中断标志位清0,否则,单片机会因中断标志未能得到及时清除而重新相应同一中断请求,这是绝对不允许的。
    1、外部中断标志的清除
    当外部中断工作在电平触发方式下,外部中断标志IE0或IE1是依靠单片机检测其引脚INT0或INT1上为低电平而置位的。尽管RETI指令能使中断标志IE0或IE1自动清除成“0”状态,但无法改变引脚INT0或INT1上电平始终为低电平的事实,所以单机在运行过程中会再次检测到INT0或INT1引脚上的低电平而置位IE0或IE1。
    2、串行口中断标志的清除
    串行口有两个中断标志位TI和RI,硬件无法判别是哪个中断标志引发的中断请求,所以中断响应后,RETI指令无法自动清除中断标志,只能由软件清除。编程时应在中断服务程序的适当位置采用指令清除TI或RI。
    #实验

    汇编代码

    ******************************************************************/ 
    *   【课程10】 ****中断系统的应用***********
    *   【说  明】 ****使用T0定时1秒让LED灯闪烁一次	
    *   【描  述】 ****使用T0定时1秒让LED灯闪烁一次,并通过按键来控制定时器的开启和关闭。
    ******************************************************************/ 
    	    ORG 0000H
    		JMP MAIN        ;跳到主程序
    		ORG 000BH       
    		JMP Timer0      ;跳到Timer0的中断服务程序
    
    		ORG 0030H
    Timer0:	MOV TH0,#3CH  ;定时器T0赋初值
    		MOV TL0,#0B0H
    		INC R3            ;R3保存N值
    		MOV A,R3
    		CJNE A,#19,L1	  ;A不等于19,则跳转到L1处
    		CLR P2.7          ;P2.7=0,点亮D1灯
    L1:		CJNE A,#20,L2     
    		SETB P2.7         ;P2.7=1,熄灭D1灯
    		MOV R3,#00H       ;N=0
    L2:		RETI
    
    
    MAIN:	MOV TMOD,#01H    ;定时器T0工作在方式1下
    		MOV TH0,#3CH         ;T0赋初值
    		MOV TL0,#0B0H
    		SETB ET0             ;ET0=1,定时器t0中断允许
    		SETB EA              ;开中断总开关
    		SETB TR0             ;启动T0,开始定时
    		MOV R3,#00H          ;R3保存N值,N=0
    
    		CLR  20H            ;位地址20H处,保存标志量
    LOOP:	JB   P3.2,$	     ;如果P3.2=1,则跳到自身处继续运行
    		CALL DELAY
    		JB   P3.2,LOOP
    		JNB  P3.2,$
    		JB   20H,L3
    		SETB 20H
    		CLR  TR0             ;关闭T0
    		JMP  LOOP
    L3:		CLR  20H
    		SETB TR0             ;开启T0
    		JMP  LOOP
    
    DELAY:   MOV    R7,#0FFH
    W1:      MOV    R6,#03FH
    W2:      DJNZ   R6,W2
             DJNZ   R7,W1
    RET
    END
    

    C代码

    ******************************************************************/	
    *   【课程10】 ****中断系统的应用***********
    *   【说  明】 ****使用T0定时1秒让LED灯闪烁一次		
    *   【描  述】 ****使用T0定时1秒让LED灯闪烁一次,并通过按键来控制定时器的开启和关闭。
    ******************************************************************/
    
    #include<reg51.h>		//51头文件,
    #include <intrins.h>
    
    //---------常用的两个宏定义-------------- 
    #define uint8	unsigned char
    #define uint16  unsigned int
    
    
    sbit Key=P3^2;
    sbit Led=P2^7;
    uint8 num;			  //一秒的计数变量
    uint8 flag;
    
    /************************************
    函数名:Timer0_I()
    功能:中断服务程序
    ************************************/
    void Timer0_I() interrupt 1
    {
    	TH0=0x3c;  		//重装初值
    	TL0=0xb0;
    	num++;   		//计时变量+1
    	if(num==20)	{Led=~Led;  num=0;}
    }
    /************************************
    函数名:main()
    功能:主程序
    ************************************/
    void main()
    {
    	TMOD=0x01;		//选择定时器0工作在定时方式1
    	TH0=0x3c;		//定时50ms,装初值
    	TL0=0xb0;
    	ET0=1;  		//开启定时中断
    	EA=1;			//开总中断
    	TR0=1;			//开启定时器T0
    
    	num=0;
    	flag=0;
    	while(1)
    	{
    		if(Key==0)   	//有键按下
    		{
    			if(flag==0)
    			{flag=1;  TR0=0;}	//关闭定时器T0
    			else
    			{flag=0;  TR0=1;}	//开启定时器T0
    		}	
    	}
    }	
    
    展开全文
  • 这篇文章是整个《漫谈计算机组成原理》系列文章的最后一篇——中断系统。实际上,在《I/O系统》那一篇文章中,我们已经介绍过了中断系统,我想你大概也知道了中断的流程及中断的两种方式,如果你还不知道,就去翻翻...
  • 上一篇文章我们模拟操作系统的加载器程序,使用汇编语言实现了一个程序加载器:点击链接查看上一篇文章:程序加载器的实现原理 本篇文章,是实模式学习的结尾。在经过了那么多坎坷,终于学完了8086的实模式!!!最...
  • 51单片机中断系统原理和运用

    千次阅读 2020-05-02 23:31:00
    51的中断系统有5个中断源,2个优先级,可实现二级中断嵌套 中断优先级控制寄存器IP(B8H)可位寻址 位 0 1 2 3 4 5 6 7 符号 - - - PS PT1 PX1 PT0 PX0 PX0/PX1 INT0/1优先级控制位 =0属低优先级 =1属高优先级 PT0/...
  • 微机原理-07-中断系统

    2020-04-09 09:14:12
    中断系统 ###定义 中断”,是指CPU暂时停止正在执行的程序,转去执行请求CPU为之服务的内、外部事件的服务程序,待该服务程序执行完后,又返回到被暂停的程序继续运行的过程。 中断的作用 (1)可以提高CPU的...
  • linux中断处理原理分析

    千次阅读 2015-09-04 17:58:01
    首先需要了解一下中断的概念:一个“中断”仅仅是一个信号,当硬件需要获得处理器对它的关注时,就可以发送这个信号。内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。 模块在使用中断前要先...
  • 理解ARM中断原理以及中断嵌套

    千次阅读 2017-10-14 11:50:16
    usr(用户模式)、fiq(快速中断模式)、irq(中断模式)、svc(管理模式)、abt(数据访问终止模式)、sys(系统模式)、und(未定义指令中止模式) ① 我们假设ARM核心有两根中断引脚(实际上是看不见的),一根叫irq pin,一根叫...
  • 计算机系统原理之CPU中断技术

    千次阅读 2013-09-22 10:28:28
    一、什么是CPU中断? 二、CPU中断的作用 三、CPU中断的类型 四、CPU中断的过程 五、多核CPU对中断的处理   一、什么是CPU中断?  使用计算机的过程中,经常会遇到这么一种情景:  1. 你正在看电影  2. 你的朋友...
  • ...
  • 联系信箱:feixiaoxing @163.com】 在嵌入式操作系统中,最难模仿的是系统中断的问题。在windows下面,这是没有办法的事情。但是在linux下面,却有一个非常便利的条件,那就是linux的信号处理。因为用户程序处理的...
  • 中断 / 软中断原理和实现

    万次阅读 2015-12-06 20:46:10
    本文主要内容:硬中断 / 软中断原理和实现 内核版本:2.6.37 Author:zhangskd @ csdn blog   概述   从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给...
  • 中断系统原理 何为中断,何为中断系统 举个例子: 生活中常见的例子,一个正在写寒假作业的孩子突然听到一阵敲门声,原来是父母下班回来了,孩子说:“等会,我来了”。于是,他记住当下页码放下作业去开门,然后...
  • 51单片机的中断响应原理

    千次阅读 2019-11-12 11:26:35
    1.中断概念 CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生); CPU暂时中断当前的工作...2.中断系统结构 3.中断允许控制 4.中断请求标志 5.中断响应条件 6.实验程序: #i...
  • I/O中断原理

    千次阅读 2019-12-14 13:00:27
    文章目录@[toc]I/O中断原理前言什么是中断中断类型硬件中断软件中断I/O中断流程无中断中断中断处理相关文献 I/O中断原理 前言 在Windows内核原理-同步IO与异步IO和《高性能网络通讯原理》两篇文章中,都出现了中断...
  • 计算机组成原理10----中断系统

    千次阅读 2019-07-04 17:25:01
    1.中断概念 计算机在执行程序过程中,出现异常情况或者特殊请求时,计算机暂停现行程序,转而执行对于这些异常情况和特殊请求的处理,处理结束后再返回现行程序间断处,继续执行。 当程序执行到K处时,执行中断...
  • 系列索引:《嵌入式系统原理与应用》 | 嵌入式系统 重点知识梳理 目录 什么是中断 中断的处理过程、中断向量表 中断的利弊 STM32 中NVIC的中断优先级处理 STM32中段服务函数的作用及其特点 中断相关...
  • 中断原理及定时器

    千次阅读 2016-09-09 14:51:47
    一、中断系统 1.1.中断的概念 1.2.中断流程示意图 1.3.中断的优先级 二、定时器 定时器的使用及程序 一、中断系统 1.1.中断的概念 什么是中断:CPU在处理某一事件A时,发生的另外某一事件B请求CPU去处理(产生了...
  • 从某种意义上来说,没有中断就没有嵌入式操作系统。一旦你明白了中断的真正含义,你对操作系统的了解就算真正入门了。什么是中断呢?我们可以看看单片机下面是怎么做的。 #include sbit LED = P1 ^ 6; unsigne
  • linux中断--中断原理分析

    千次阅读 2014-04-14 18:48:28
    中断原理篇 前言: 中断是计算机发展中一个重要的技术,它的出现很大程度上解放了CPU,提高了CPU的执行效率。 在中断出现之前,CPU对IO采用的是轮询的方式进行服务,这使的CPU纠结在某一个IO上,一直在等待它的...
  • 51 中断系统 外部中断0 外部中断1

    万次阅读 多人点赞 2019-06-14 22:26:11
    51单片机的中断系统结构 中断允许控制 CPU对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE控制的。 EX0(IE.0),外部中断0允许位; ET0(IE.1),定时/计数器T0中断允许位; EX1(IE.2),...
  • STM32 中断优先级原理

    千次阅读 2015-07-22 17:13:23
    CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256级的可编程中断设置。但 STM32 并没有使用 CM3 内核的全部东西,而是只用了它的一部分。STM32 有 84 个中断,...
  • LINUX系统调用原理-既应用层如何调用内核层函数之软件中断   SWI:software interrupt 软件中断   ARM Linux系统利用SWI指令来从用户空间进入内核空间,还是先让我们了解下这个SWI指令吧。SWI指令用于产生...
  • 中断原理

    千次阅读 2012-05-21 19:12:06
    中断是计算机发展中一个重要的技术,它的出现很大程度上解放了CPU,提高了CPU的执行效率。 在中断出现之前,CPU对IO采用的是轮询的方式进行服务,这使的CPU纠结在某一个IO上,一直在等待它的响应,如果它不响应,...
  • 单片机中断原理及定时器详解

    万次阅读 多人点赞 2018-04-22 17:20:21
    一、中断系统1.1.中断的概念什么是中断:CPU在处理某一事件A时,发生的另外某一事件B请求CPU去处理(产生了中断),随后CPU暂时中断当前正在执行的任务,去对事件B进行处理,CPU处理完事件B后再返回之前中断的位置...
  • 单片机(AT89C51)中断系统详解和中断系统应用实验

    千次阅读 多人点赞 2020-04-07 20:06:02
    单片机中断系统 什么叫做单片机的中断? CPU暂时中止其正在执行的程序,转去执行请求中断的那个外设或事件的服务程序,等处理完毕后再返回执行原来中止的程序, 叫做中断。 为什么要设置中断? ⑴ 提高CPU...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 161,258
精华内容 64,503
关键字:

中断系统的原理