ARM中的中断

在ARM中,事件发生将会触发中断,然而,中断并不会直接触发CPU,而是在由一个GIC,中断控制器来管理:

其中,中断分为?
Supports three interrupt types:
 Private Peripheral Interrupt (PPI)一个中断源对应一个CPU
Software Generated Interrupt (SGI)     CPU对应CPU
Shared Peripheral Interrupt (SPI)    一个中断源对应多个CPU

今天的例子是用SGI中断来实现的,在处理中断的时候,主要分三步:

//step 1: cpu cpsr

  CPU允许中断
 20       __asm__ __volatile__(
 21           "mrs r0, cpsr\n"
 22           "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开
 23           "msr cpsr, r0\n"
 24           ::: "r0"
 25       );
 26
 27       //step 2: GIC

  GIC
 28       ICCICR_CPU0 = 1;//CPU接口控制寄存器
 29       ICCPMR_CPU0 = 0xff;//中断优先标志寄存器
 30       ICDDCR = 1;//设置本中断的开关
 31       ICDIPR0_CPU0 = (0x00 << 0);//本中断的优先级
 32       ICDIPTR0_CPU0 = 1;//选择指定的CPU
 33       ICDISER0_CPU0 = (1 << 0);//设置本中断开启
 34   各个寄存器描述如下:详细见4412     782页

  
 35       //step 3: interrupt source

  中断源
 36       ICDSGIR = 0 | (1 << 16) | (0 << 24);//SGI控制寄存器CPUTargetList.TargetListFi    lte
 37       printf("welcome back! \n");

下面是代码:

 1 #include"regs.h"
  2
  3 int (*printf)(char *, ...) = 0xc3e114d8;
  4
  5 void init_ttb(unsigned long *addr);
  6 void enable_mmu(void);
  7 unsigned long data_abort_init();
  8 void memcopy(unsigned long* dest,unsigned long* source,int len);
  9 void do_irq();
 10
 11 int main()
 12 {
 13      *(unsigned long *)0x66000000 = do_irq;
 14     unsigned long source_addr=data_abort_init();
 15     printf("swi_souce addr is %x\n",source_addr);
 16     memcopy(0x60000000,source_addr,0x1000);
 17     enable_mmu();
 18
 19      //step 1: cpu cpsr
 20       __asm__ __volatile__(
 21           "mrs r0, cpsr\n"
 22           "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开
 23           "msr cpsr, r0\n"
 24           ::: "r0"
 25       );
 26
 27       //step 2: GIC
 28       ICCICR_CPU0 = 1;//CPU接口控制寄存器
 29       ICCPMR_CPU0 = 0xff;//中断优先标志寄存器
 30       ICDDCR = 1;//设置本中断的开关
 31       ICDIPR0_CPU0 = (0x00 << 0);//本中断的优先级
 32       ICDIPTR0_CPU0 = 1;//选择指定的CPU
 33       ICDISER0_CPU0 = (1 << 0);//设置本中断开启
 34
 35       //step 3: interrupt source
 36       ICDSGIR = 0 | (1 << 16) | (0 << 24);//SGI控制寄存器CPUTargetList.TargetListFi    lte
 37       printf("welcome back! \n");
 38 }
 39
 40 void do_irq()
 41     {
 42         unsigned long data = ICCIAR_CPU0;
 43         unsigned long irq_id = data & 0x3ff;
 44         unsigned long cpu_id = (data >> 10) & 0x7;
 45         ICCEOIR_CPU0 = irq_id | (cpu_id << 10);
 46         printf("irq is %d, cpu is %d\n", irq_id, cpu_id);
 47     }
 48
 49 void memcopy(unsigned long* dest, unsigned long* source,int len)
 50 {
 51     int i=0;;
 52     for(i=0;i<len;i++)
 53         dest[i]=source[i];
 54 }
 55
 56 unsigned long  data_abort_init()
 57 {
 58     unsigned long source;
 59     __asm__ __volatile__(
 60          "ldr %0, =voliate_start\n"
 61          : "=r" (source)
 62      );
 63     return source;
 64 }
 65
 66 __asm__(
 67 "voliate_start:\n"
 68     //跳转目录
 69     " b reset\n"
 70     " b undefined\n"
 71     " b swi\n"
 72     " b pre_abt\n"
 73     " b data_abt\n"
 74     " .word 0\n"//占位符号,一个位占4个字节
 75     " b irq\n"
 76     " b fiq\n"
 77 "\n"
 78     //跳转要分三部:
 79     //1:将PC保存到新模式下的lr中;
 80     //2:将CPSR保存在SPSR中
 81     //3:初始化SP
 82     //前两步由硬件完成,而第三部需要手动完成
 83 "reset:\n"
 84
 85 "undefined:\n"
 86      "mov sp, #0x66000000\n"//初始化SP
 87      "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器
 88     //打印一句话
 89      "ldr r0, =und_string\n"
 90      "ldr r2, show\n"
 91      "blx r2\n"
 92     //跳回来分两部
 93     //1:将CPSR保存在SPSR中
84
 85 "undefined:\n"
 86      "mov sp, #0x66000000\n"//初始化SP
 87      "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器
 88     //打印一句话
 89      "ldr r0, =und_string\n"
 90      "ldr r2, show\n"
 91      "blx r2\n"
 92     //跳回来分两部
 93     //1:将CPSR保存在SPSR中
 94     //2:将PC保存到新模式下的lr中;
 95      "mov sp, #0x66000000\n"//
 96      "ldmea sp, {r0-r12, pc}^\n"//
 97
 98 "swi:\n"
 99
100 "pre_abt:\n"
101 "data_abt:\n"
102      "sub lr, lr, #4\n"
103      "mov sp, #0x66000000\n"//初始化SP
104      "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器
105     //打印一句话
106      "ldr r0, =data_string\n"
107      "ldr r2, show\n"
108      "blx r2\n"
109     //跳回来分两部
110     //1:将CPSR保存在SPSR中
111     //2:将PC保存到新模式下的lr中;
112      "mov sp, #0x66000000\n"//
113      "ldmea sp, {r0-r12, pc}^\n"//
114
115 "irq:\n"
116     "sub lr, lr, #4\n"
117      "mov sp, #0x66000000\n"//初始化SP
118      "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器
119     //打印一句话
120      "mov r2, #0x66000000\n"
121      "ldr r1, [r2]\n"
122      "blx r1\n"
123
124    //  "ldr r0, =irq_string\n"
125    //  "ldr r2, show\n"
126    //  "blx r2\n"
127     //跳回来分两部
128     //1:将CPSR保存在SPSR中
129     //2:将PC保存到新模式下的lr中;
130      "mov sp, #0x66000000\n"//
131      "ldmea sp, {r0-r12, pc}^\n"//
132 "fiq:\n"
133     "show:\n"
134      ".word 0xc3e114d8\n"
135
136     "und_string:\n"
137      ".asciz \"This is  UND!\\n\" \n"
138      "data_string:\n"
139      ".asciz \"This DATA_ABORT!\\n\" \n"
140      "irq_string:\n"
141      ".asciz \"This IRQ!\\n\" \n"
142
143         );
144
145 void init_ttb(unsigned long *addr)
146 {
147     unsigned long va = 0;//定义虚拟地址
148     unsigned long pa = 0;//定义物理地址
149
150     //40000000-------80000000   ====  40000000------80000000
151     for(va=0x40000000; va<=0x80000000; va+=0x100000){
152         pa = va;
153         addr[va >> 20] = pa | 2;
154         //|2的目的是将0-2位置为10此时将是小页模式4K
155     }
156
157     //00000000-------10000000   ====  60000000------70000000
158     for(va=0x00000000; va<=0x10000000; va+=0x100000){
159         pa = va+0x60000000;
160         addr[va >> 20] = pa | 2;
161     }
162
163     //10000000-------14000000   ====  10000000------14000000
164     for(va=0x10000000; va<=0x14000000; va+=0x100000){
165         pa = va;
166         addr[va >> 20] = pa | 2;
167     }
168
169     //30000000-------40000000   ====  50000000------60000000
170     for(va=0x30000000; va<0x40000000; va+=0x100000){
171         pa = va + 0x20000000;
172         addr[va >> 20] = pa | 2;
173     }
174 }
175
176 void enable_mmu(void)
177
178 {
179     unsigned long addr = 0x70000000;
180     init_ttb(addr);
181     //step:初始化页表
182
183     unsigned long mmu = 1 | (1 << 1) | (1 << 8);
184     //将MMU的第0,1,8位置1
185     __asm__ __volatile__(
186         "mov r0, #3\n"
187         "MCR p15, 0, r0, c3, c0, 0\n"//manager
188         "MCR p15, 0, %0, c2, c0, 0\n"//addr
189         "MCR p15, 0, %1, c1, c0, 0\n"// enable mmu
190         :
191         : "r" (addr), "r" (mmu)
192         : "r0"
193     );
194     printf("MMU is enable!\n");
195 }
196 

在代码中,主函数其他的部分在前面都已经说了,已不再说。主要是在VICTOR函数中,将处理中断的部分,做成了一个函数,以后更容易修改处理的部分。

void do_irq()
 41     {
 42         unsigned long data = ICCIAR_CPU0;//取出IRQ  ID  和CPU  ID
 43         unsigned long irq_id = data & 0x3ff;
 44         unsigned long cpu_id = (data >> 10) & 0x7;
 45         ICCEOIR_CPU0 = irq_id | (cpu_id << 10);//清除CPU
 46         printf("irq is %d, cpu is %d\n", irq_id, cpu_id);
 47     }
//总的来说,在以前的基础上面,今天主要认识了GIC的配置,更重要的是,中断分为四步:

1,CPU开

2,GIC配置

3,中断源

4,处理中断,清中断

时间: 2024-08-10 21:30:39

ARM中的中断的相关文章

ARM中外部中断

在整个ARM体系结构中,为了处理外部中断,依次学习了MMU,模式跳转,异常,GIC,看门狗程序,这些都是为了处理外部中断 具体如下: 处理外部中断有五个步骤: 30      //step 1: cpu cpsr 31       __asm__ __volatile__( 32           "mrs r0, cpsr\n" 33           "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开 34          

ARM中的异常和中断

ARM中有5种异常模式,有7种中断源.这7种中断源中有些中断是我们希望发生的,但有些中断是我们不希望发生的. 我们希望发生的中断: 软中断:属于svc模式,通过SWI指令便可以产生软中断,进入到svc模式. irq中断:属于irq模式,当产生普通的外部中断时,处理器便进入到IRQ模式. fiq中断:属于fiq模式,当产生高优先级外部中断时,处理器便进入到FIQ模式. 我们不希望发生的中断: 复位:属于svc模式,当系统上电时便会产生复位中断,系统进入到svc模式.复位中断不需要中断返回. 取指中

ARM中13个必知知识点详解

ARM处理器的优点相信不用多说,大家都了解,其非常适合在嵌入式学习初期使用,在开始使用ARM进行实际操作之前,还是希望大家能够了解一些其使用过程中一些注意事项.接下来我们就一起来看看ARM中有哪些需要注意的事项吧. MAM使用注意事项 当改变MAM定时值时,必须先通过向MAMCR写入0来关闭MAM,然后将新值写入MAMTIM.最后,将需要的操作模式的对应值写入MAMCR,再次打开MAM.对于低于20MHz的系统时钟,MAMTIM设定为001.对于20MHz到40MHz之间的系统时钟,建议将Fla

ARM中的看门狗程序

在ARM中,有一个硬件部分叫WATCH DOG.这个硬件,一直在做一件事情:就是,从某一数值,一直数,各一段时间减一,隔一段时间减一,直到减到0的时候将会触发重启或者中断.而有时候,为了预防死机,我们在操作系统跑起来的时候会有一个特定的程序来做一件事情:减到特定是值的时候数值将会重新置到100.这样,看门狗将会循环往复做一件事情:一直数数,而不会死机. 这个程序叫做守护程序:又叫做喂狗程序. 看门狗的逻辑运算图如下: 今天,有看门狗来写了一个程序:隔一段时间来触发一个中断,每次中断来的时候,将会

如何将已部署在ASM的资源迁移到ARM中

使用过Azure的读者都知道,Azure向客户提供了两个管理portal,一个是ASM,一个是ARM,虽然Azure官方没有宣布说淘汰ASM,两个portal可能会在很长的一段时间共存,但是考虑到ARM提供了更多的功能,只有很少部分工作才会用到powershell完成,所以笔者建议以后大家尽量使用ARM,但是对于哪些已经使用ASM作为生产环境的用户想迁移到ARM中,应该怎么办,今天笔者就像大家介绍一下如何将云资源从ASM迁移到ARM中!!! 首先介绍一下现在迁移可以使用的一些服务与工具 1.平台

ARM 中必须明白的几个概念

文章具体介绍了关于ARM的22个常用概念. 1.ARM中一些常见英文缩写解释 MSB:最高有效位: LSB:最低有效位: AHB:先进的高性能总线: VPB:连接片内外设功能的VLSI外设总线: EMC:外部存储器控制器: MAM:存储器加速模块: VIC:向量中断控制器: SPI:全双工串行接口: CAN:控制器局域网,一种串行通讯协议: PWM:脉宽调制器: ETM:嵌入式跟踪宏: CPSR:当前程序状态寄存器: SPSR:程序保护状态寄存器: 2.MAM 使用注意事项: 答:当改变 MAM

S5PV210-arm裸机-异常中的中断实现过程

210中的异常中的中断实现过程: 首先异常分为很多种,异常中包含了中断异常,有一个东西叫做异常向量表,在异常向量表中有很多相应异常的的地址.异常向量表中的所有异常中断的地址是不会变化的.地址都是固定的,但这些地址都是一个基于基地址的一个地址.不同的CPU中,基地址是不同的. 在210中,CPU内部给了一个发生异常时的异常向量的基地址,查阅官方资料知道,这个基地址为0XD0037400,所以我们需要自己把异常向量表中的地址加在210给的发生异常时的异常向量的基地址上.比如:reset(复位异常)在

ARM中的寻址方式

ARM处理器支持9中不同的寻址方式. 1.移位寄存器寻址: 有5种移位方式: LSL:逻辑左移.最低位用0补充,且移出的最后一位存放在cpsr中的C位中. LSR:逻辑右移.最高位用0补充,且移出的最后一位存放在cpsr中的C位中. ASR:算术右移.最高位用符号位补充,且移出的最后一位存放在cpsr中的C位中. ROR:循环右移(不涉及到CPSR中的C位的循环右移).且移出的最后一位存放在cpsr中的C位. RRX:扩展循环右移(带有C位的右移).只循环右移一位,且最高位用cpsr中的C位补充

Linux内核中的中断栈与内核栈的补充说明【转】

转自:http://blog.chinaunix.net/uid-12461657-id-3487463.html 原文地址:Linux内核中的中断栈与内核栈的补充说明 作者:MagicBoy2010 中断栈与内核栈的话题更多地属于内核的范畴,所以在<深入Linux设备驱动程序内核机制>第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题. 本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系