ARM-Linux 中断分析

发布者:innovation2最新更新时间:2016-12-03 来源: eefocus关键字:ARM  Linux  中断分析 手机看文章 扫描二维码
随时随地手机看文章

 ARM体系结构中,把复位、中断、快速中断等都看作‘异常’,当这些‘异常’发生时,CPU会到固定地址处去找指令,他们对应的地址如下:

          地址                异常类型      进入时的工作模式

          0x00000000         Reset                 Supervisor

          0x00000004         Und                  Undefined

          0x00000008         Soft interupt           Supervisor

          0x0000000c         Abort(prefetch)        Abort

          0x00000010         Abort(data)            Abort

          0x00000014         Reserved              Reserved

          0x00000018         IRQ                   IRQ

          0x0000001c         FIQ                   FIQ

     首先要明确的一点就是,无论内存地址空间是如何映射的,以上这些地址都不会变,比如当有快速中断发生时,ARM将铁定到0X0000001C这个地址处取指令。这也是BOOTLOADER把操作系统引导以后,内存必须重映射的原因!否则操作系统不能真正接管整套系统!

     LINUX启动以后要初始化这些区域,初始化代码在main.c中的start_kernel()中,具体是调用函数trap_ini()来实现的。如下面所示(具体可参照entry-armv.S):

     .LCvectors:         swi    SYS_ERROR0

                   b       __real_stubs_start + (vector_undefinstr - __stubs_start)

                   ldr     pc, __real_stubs_start + (.LCvswi - __stubs_start)

                   b       __real_stubs_start + (vector_prefetch - __stubs_start)

                   b       __real_stubs_start + (vector_data - __stubs_start)

                   b       __real_stubs_start + (vector_addrexcptn - __stubs_start)

                   b       __real_stubs_start + (vector_IRQ - __stubs_start)

                   b       __real_stubs_start + (vector_FIQ - __stubs_start)

 

     ENTRY(__trap_init)

                   stmfd         sp!, {r4 - r6, lr}

 

                   adr    r1, .LCvectors                        @ set up the vectors

                   ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}

                   stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}

 

                   add    r2, r0, #0x200

                   adr    r0, __stubs_start          @ copy stubs to 0x200

                   adr    r1, __stubs_end

1:                ldr     r3, [r0], #4

                   str     r3, [r2], #4

                   cmp  r0, r1

                   blt     1b

                   LOADREGS(fd, sp!, {r4 - r6, pc})

 

     以上可以看出这个函数初始化了中断向量,实际上把相应的跳转指令拷贝到了对应的地址。

 

当发生中断时,不管是从用户模式还是管理模式调用的,最终都要调用do_IRQ():

     __irq_usr:  sub    sp, sp, #S_FRAME_SIZE

                   stmia sp, {r0 - r12}                         @ save r0 - r12

                   ldr     r4, .LCirq

                   add    r8, sp, #S_PC

                   ldmia r4, {r5 - r7}                           @ get saved PC, SPSR

                   stmia r8, {r5 - r7}                           @ save pc, psr, old_r0

                   stmdb         r8, {sp, lr}^

                   alignment_trap r4, r7, __temp_irq

                   zero_fp

1:                get_irqnr_and_base r0, r6, r5, lr

                   movne        r1, sp

                   adrsvc        ne, lr, 1b

                   @

                   @ routine called with r0 = irq number, r1 = struct pt_regs *

                   @

                   bne    do_IRQ    @ 调用do_IRQ来实现具体的中断处理

                   mov  why, #0

                   get_current_task tsk

                   b       ret_to_user

 

     对于以上代码,在很多文章中都有过分析,这里不再赘述。

 

 

     Linux每个中断通过一个结构irqdesc来描述,各中断的信息都在这个结构中得以体现:

  struct irqdesc {

         unsigned int         nomask   : 1;            /* IRQ does not mask in IRQ   */

         unsigned int         enabled  : 1;              /* IRQ is currently enabled   */

         unsigned int         triggered: 1;                 /* IRQ has occurred           */

         unsigned int         probing  : 1;              /* IRQ in use for a probe     */

         unsigned int         probe_ok : 1;              /* IRQ can be used for probe  */

         unsigned int         valid    : 1;               /* IRQ claimable       */

         unsigned int         noautoenable : 1;        /* don't automatically enable IRQ */

         unsigned int         unused   :25;

         void (*mask_ack)(unsigned int irq);         /* Mask and acknowledge IRQ   */

         void (*mask)(unsigned int irq);                /* Mask IRQ                      */

         void (*unmask)(unsigned int irq);   /* Unmask IRQ                  */

         struct irqaction *action;

         /*

          * IRQ lock detection

          */

         unsigned int         lck_cnt;

         unsigned int         lck_pc;

         unsigned int         lck_jif;

     };

 

     在具体的ARM芯片中会有很多的中断类型,每一种类型的中断用以上结构来表示:

struct irqdesc irq_desc[NR_IRQS];   /* NR_IRQS根据不同的MCU会有所区别*/

     在通过request_irq()函数注册中断服务程序的时候,将会把中断向量和中断服务程序对应起来。

     我们来看一下request_irq的源码:

     int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),

                    unsigned long irq_flags, const char * devname, void *dev_id)

     {

         unsigned long retval;

         struct irqaction *action;

 

         if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||

             (irq_flags & SA_SHIRQ && !dev_id))

                   return -EINVAL;

 

         action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);

         if (!action)              /*  生成action结构*/

                   return -ENOMEM;

 

         action->handler = handler;

         action->flags = irq_flags;

         action->mask = 0;

         action->name = devname;

         action->next = NULL;

         action->dev_id = dev_id;

 

         retval = setup_arm_irq(irq, action);   /*把中断号irq和action 对应起来*/

 

         if (retval)

                   kfree(action);

         return retval;

     }

     其中第一个参数irq就是中断向量,第二个参数即是要注册的中断服务程序。很多同仁可能疑惑的是,我们要注册的中断向量号是怎么确定的呢?这要根据具体芯片的中断控制器,比如三星的S3C2410,需要          通过读取其中的中断状态寄存器,来获得是哪个设备发生了中断:

   

 

     if defined(CONFIG_ARCH_S3C2410)

     #include

 

                   .macro  disable_fiq

                   .endm

                   .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp

                   mov  r4, #INTBASE             @ virtual address of IRQ registers

                   ldr     \irqnr, [r4, #0x8]  @ read INTMSK   中断掩码寄存器

                   ldr     \irqstat, [r4, #0x10]   @ read INTPND  中断寄存器

                   bics    \irqstat, \irqstat, \irqnr

                   bics    \irqstat, \irqstat, \irqnr

                   beq    1002f                  

                   mov  \irqnr, #0

1001:                   tst     \irqstat, #1

                   bne    1002f                            @ found IRQ

                   add    \irqnr, \irqnr, #1

                   mov  \irqstat, \irqstat, lsr #1

                   cmp  \irqnr, #32

                   bcc    1001b

1002:

                   .endm

                   .macro  irq_prio_table

                   .endm                 

     以上代码也告诉了我们,中断号的确定,其实是和S3C2410手册中SRCPND寄存器是一致的,即:

 

     /* Interrupt Controller */

     #define IRQ_EINT0             0       /* External interrupt 0 */

     #define IRQ_EINT1             1       /* External interrupt 1 */

     #define IRQ_EINT2             2       /* External interrupt 2 */

     #define IRQ_EINT3             3       /* External interrupt 3 */

     #define IRQ_EINT4_7                  4       /* External interrupt 4 ~ 7 */

     #define IRQ_EINT8_23                5       /* External interrupt 8 ~ 23 */

     #define IRQ_RESERVED6            6       /* Reserved for future use */

     #define IRQ_BAT_FLT                 7

     #define IRQ_TICK               8       /* RTC time tick interrupt  */

     #define IRQ_WDT                        9       /* Watch-Dog timer interrupt */

     #define IRQ_TIMER0                   10     /* Timer 0 interrupt */

     #define IRQ_TIMER1                   11     /* Timer 1 interrupt */

     #define IRQ_TIMER2                   12     /* Timer 2 interrupt */

     #define IRQ_TIMER3                   13     /* Timer 3 interrupt */

     #define IRQ_TIMER4                   14     /* Timer 4 interrupt */

     #define IRQ_UART2           15     /* UART 2 interrupt  */

     #define IRQ_LCD                          16     /* reserved for future use */

     #define IRQ_DMA0            17     /* DMA channel 0 interrupt */

     #define IRQ_DMA1            18     /* DMA channel 1 interrupt */

     #define IRQ_DMA2            19     /* DMA channel 2 interrupt */

     #define IRQ_DMA3            20     /* DMA channel 3 interrupt */

     #define IRQ_SDI                           21     /* SD Interface interrupt */

     #define IRQ_SPI0                 22     /* SPI interrupt */

     #define IRQ_UART1           23     /* UART1 receive interrupt */

     #define IRQ_RESERVED24          24

     #define IRQ_USBD              25     /* USB device interrupt */

     #define IRQ_USBH              26     /* USB host interrupt */

     #define IRQ_IIC                            27     /* IIC interrupt */

     #define IRQ_UART0           28     /* UART0 transmit interrupt */

     #define IRQ_SPI1                 29     /* UART1 transmit interrupt */

     #define IRQ_RTC                          30     /* RTC alarm interrupt */

     #define IRQ_ADCTC          31     /* ADC EOC interrupt */

     #define NORMAL_IRQ_OFFSET        32

     这些宏定义在文件irqs.h中,大家可以看到它的定义取自S3C2410的文档。

  

     总结: linux在初始化的时候已经把每个中断向量的地址准备好了!就是说添加中断服务程序的框架已经给出,当某个中断发生时,将会到确定的地址处去找指令,所以我们做驱动程序时,只需要经过request_irq()来挂接自己编写的中断服务程序即可。

 

     另:对于快速中断,linux在初始化时是空的,所以要对它挂接中断处理程序,就需要单独的函数set_fiq_handler()来实现,此函数在源文件fiq.c中,有兴趣的读者可进一步研究。


关键字:ARM  Linux  中断分析 引用地址:ARM-Linux 中断分析

上一篇:移植嵌入式Linux到ARM处理器S3C2410:操作系统
下一篇:移植嵌入式Linux到ARM处理器S3C2410:BootLoader

推荐阅读最新更新时间:2024-03-16 15:23

基于AT91 M42800A的LED显示系统设计
最近,笔者在某工厂大型生产线上基于现场总线的物流呼叫系统项目中发现,由于所需要显示的信息流比较大,用现有的基于AT89C51芯片组成的LED显示屏控制系统,由于受到微处理器的处理速度、体系架构、寻址范围、外围接口资源等诸多限制,已难以在要求显示较多像素、显示内容帧频较高、动态显示效果复杂的情况下,得到良好的动态视觉效果。针对以上情况,在利用现有资源的基础上,重新设计和研制了一种全新的,由32位高性能ARM微处理器组成的LED显示屏控制系统,并通过RS485接口与现场总线中的上位机进行实时数据通信,实现整个系统的信息显示。 1 系统硬件结构 该系统的硬件组成框图如图1所示。图1中,微处理器是Atmel公司生产的AT91M
[单片机]
基于AT91 M42800A的LED显示系统设计
S5PV210体系结构与接口01:ARM体系结构概述
1. 嵌入式系统的组成 1.1 硬件组成 ① 嵌入式微处理器 目前流行的体系结构:ARM、MIPS、PowerPC、MC68000等 ② 外围设备 主要用于完成存储、通信、调试、显示等功能,常见如下: 存储设备:如RAM、SRAM、Flash等 通信设备:如RS232接口、SPI接口、以太网接口等 显示设备:如显示屏等 1.2 软件组成 两种软件组成的区别在于是否包含嵌入式操作系统 补充:嵌入式系统软硬件构成图 2. 交叉编译和交叉调试 2.1 交叉编译 交叉编译就是在一个平台上生成可以在另一个平台上执行的代码。需要注意的是,编译器本身也是程序,也要在与之对应的某一个CPU上运行。
[单片机]
S5PV210体系结构与接口01:<font color='red'>ARM</font>体系结构概述
Keil(MDK-ARM)系列教程(二)_工具栏详细说明
Ⅰ、写在前面 Toolbars工具栏其实就是在菜单下面一行一行的快捷图标按钮,这些快捷按钮之所以归为工具栏里面,在于它们使用的频率较高。比如编译按钮,这个按钮在我们编程的时候使用的频率是相当高,其他快捷按钮同样也经常使用。 本文说的Toolbars工具栏和大部分上位机软件(如:Keil、IAR、VS、STM32CubeMX等)一样,只是工具栏的多少不同,工具栏中快捷按钮的多少不同而已。 本文虽然以Keil MDK-ARM V5为例来讲述,其实Keil MDK-ARM 其它版本,以及Keil C51的各个版本也有同样工具栏,功能也一样。因此,本文也适合它们。 本文内容已经整理成PDF文件,提供给大家下载: http:
[单片机]
Keil(MDK-<font color='red'>ARM</font>)系列教程(二)_工具栏详细说明
ARM芯片的选型原则
1.1 ARM芯核 如果希望使用WinCE或Linux等操作系统以减少软件开发时间,就需要选择ARM720T以上带有MMU(memory management unit)功能的ARM芯片,ARM720T、Stron-gARM、ARM920T、ARM922T、ARM946T都带有MMU功能。而ARM7TDMI没有MMU,不支持Windows CE和大部分的Linux,但目前有uCLinux等少数几种Linux不需要MMU的支持。 1.2 系统时钟控制器 系统时钟决定了ARM芯片的处理速度。ARM7的处理速度为0.9MIPS/MHz,常见的ARM7芯片系统主时钟为20MHz-133MHz,ARM9的处理速度为1.1MIPS/MHz,
[单片机]
基于ARM和FPGA的多路电机控制方案
介绍了一种基于fpga的多轴控制器,控制器主要由arm7(LPC2214)和fpga(EP2C5T144C8)及其外围电路组成,用于同时控制多路电机的运动。利用Verilog HDL硬件描述语言在fpga中实现了电机控制逻辑,主要包括脉冲控制信号产生、加减速控制、编码器反馈信号的辨向和细分、绝对位移记录、限位信号保护逻辑等。论文中给出了fpga内部一些核心逻辑单元的实现,并利用QuartusⅡ、Modelsim SE软件对关键逻辑及时序进行了仿真。实际使用表明该控制器可以很好控制多轴电机的运动,并且能够实现高精度地位置控制。 随着电机广泛地应用于数字控制系统中,对电机控制的实时性和精度上的要求越来越高。如何灵活、有效地控制电机
[单片机]
基于<font color='red'>ARM</font>和FPGA的多路电机控制方案
关于ARM CM3的启动文件分析
下面以ARM Cortex_M3裸核的启动代码为例,做一下简单的分析。首先,在启动文件中完成了三项工作: 1、堆栈以及堆的初始化 2、定位中断向量表 3、调用Reset Handler。 在介绍之前,我们先了解一下ARM芯片启动文件中涉及到的一些汇编指令的用法。 补充一下,其中DCD相当于C语言当中的&,定义地址。 1、堆栈以及堆的初始化 1.1 堆栈的初始化 Startup_xxx.s中的堆栈初始化代码   Stack_Size EQU 0x00000400,这个语句相当于Stack_Size这个标号(标号:链接器的术语,下文中提到的所有“标号”,指的都是指的链接器中的标号)等于0x00000400相当于C语言
[单片机]
关于<font color='red'>ARM</font> CM3的启动文件<font color='red'>分析</font>
ARM电子负载网络监控系统
  随着电子产品的广泛应用,各种电源设备被使用,而电源设备运行可靠与否直接关系到系统运行的安全性和准确性,因此对这些电源设备的检验非常重要。电子负载即针对电源系统中输出电能的设备或转换装置,如发电机、AC/DC、DC/AC变换器、蓄电池、整流器及电感、电容等部件的输出特性、可靠性(老化放电)进行全面测试的设备。现在广泛应用的电子负载存在许多不足,如只能工作在单机面板操作模式下,缺乏上位机监控功能,数据显示缺乏图形界面,显示不直观,人性化;测试过程必须全程有人员进行操作,无法进行编程控制测试;没有以太网络接口,无法进行远程通讯与控制。而基于网络的电子负载系统相对于传统电子负载系统有以下突出优点:   (1)测试工作在上位机集中进行
[单片机]
<font color='red'>ARM</font>电子负载网络监控系统
AI芯片,开战
春节也没有阻挡AI跨越的脚步,2月16日凌晨,美国OpenAI公司的视频生成模型Sora再次冲击AI界,成为继ChatGPT后又一现象级应用。Sora的问世令世人惊呼:现实不存在了。 短短几日,AI又掀起新一轮浪潮,而作为其核心动力的AI芯片,也迎来巨变。 打倒英伟达 看着英伟达赚钱,市场玩家分外眼红。为了抢占市场,巨头不惜砸大钱布局市场。 先是OpenAI首席执行官山姆·奥特曼(Sam Altman)万亿美元造芯片,再是自嘲为“秃头骗子”的孙正义1000亿美元造AI芯片。 山姆·奥特曼因为万亿美元而登上头条新闻,他曾表示半导体行业需要他,而建立庞大的芯片制造网络需要通过向全球投资者寻求大量资金,他则需要
[嵌入式]
AI芯片,开战
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved