Tiny4412中断介绍
通过几天裸板驱动开发,今天对ARM的中断做一些简单总结,前面我们已经了解了ARM的7种异常模式,中断是异常模式的一种,在ARM中异常事件发生将会触发中断,但是,所有的中断都不能直接访问cpu,而是都统一由GIC(中断管理器)来管理;下面是samsung提供的模式图:
其中GIC管理的中断有分为:
(1)SGI:一个cpu中断另一个cpu(cpu0 ->cpu1)
(2)PPI:一个中断只能中断一个cpu
(3)SPI:一个中断可以中断多个cpu
处理一个中断大致需要三步:
(1)cpu permit interrupt (cpu允许中断)
(2)GIC enable (启用GIC)
(3)SET Interrupt source (设置中断源)
下面是用SGI实现的一个程序:
头文件:
1 #ifndef __BUNFLY_H 2 #define __BUNFLY_H 3 4 #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000) 5 #define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004) 6 #define ICDDCR (*(volatile unsigned long *)0x10490000) 7 #define ICDIPR2_CPU0 (*(volatile unsigned long *)0x10490408) 8 #define ICDIPTR2_CPU0 (*(volatile unsigned long *)0x10490808) 9 #define ICDISER0_CPU0 (*(volatile unsigned long *)0x10490100) 10 #define ICDSGIR (*(volatile unsigned long *)0x10490f00) 11 #define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) 12 #define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000c) 13 14 #endif //__BUNFLY_H
1 #include "bunfly.h" 2 3 int (*printf)(char *, ...) = 0xc3e114d8; 4 void enable_mmu(); 5 void init_table(unsigned long *addr); 6 void memcpy(unsigned char *dest, unsigned char *src, int len); 7 extern unsigned long vector_start; 8 void do_irq(); 9 10 int main() 11 { 12 memcpy(0x70000000, vector_start, 0x1000); 13 enable_mmu(); 14 15 *(unsigned long *)0x47000000 = do_irq; 16 17 //step 1: set cpu permit interrupt 18 __asm__ __volatile__( 19 "mrs r0, cpsr\n" 20 "bic r0,r0, #0x80\n" 21 "msr cpsr, r0\n" 22 :::"r0" 23 ); 24 25 //step 2: set GIC (cgi) enable 26 ICCICR_CPU0 = 1;//cpu接口控制寄存器(总开关) 27 ICCPMR_CPU0 =0xff;//中断总优先级(门槛) 28 ICDDCR = 1;//本中断开关 29 ICDIPR2_CPU0 = (3 << 9);//本中断优先级 30 ICDIPTR2_CPU0 = (1 << 9);//目标cpu 31 ICDISER0_CPU0 = (1 << 9);//启用本中断 32 33 //step 3: set interrupt source 34 ICDSGIR = 9 | (1 << 16); 35 36 printf("welcom back\n"); 37 } 38 39 void do_irq() 40 { 41 unsigned long ack_id = 0; 42 unsigned long cpu_id = 0; 43 unsigned long data = ICCIAR_CPU0; 44 45 /*clean interrupt*/ 46 ack_id = data & 0x3ff; 47 cpu_id = data & (0x7 << 10); 48 ICCEOIR_CPU0 = ack_id | cpu_id; 49 50 printf("this is interrupt\n"); 51 printf("cup_id is %d\n", cpu_id >> 10); 52 printf("ack_id is %d\n", ack_id); 53 54 } 55 56 void memcpy(unsigned char *dest, unsigned char *src, int len) 57 { 58 int i = 0; 59 for(i = 0; i < len; i++) { 60 dest[i] = src[i]; 61 } 62 } 63 64 void enable_mmu() 65 { 66 /*构建表*/ 67 unsigned long addr = 0x50000000; 68 init_table(addr); 69 /*打开mmu*/ 70 unsigned long mmu = 0; 71 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8); 72 __asm__ __volatile__ ( 73 "mov r0, #3\n" 74 "MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员 75 "MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址 76 "MCR p15, 0, %1, c1, c0, 0\n"//开启mmu 77 : 78 : "r" (addr), "r" (mmu) 79 : 80 ); 81 82 } 83 84 __asm__( 85 86 "vector: \n" 87 " b reset\n" 88 " b und\n" 89 " b swi\n" 90 " b pre_abt\n" 91 " b data_abt\n" 92 " .word 0x0\n" 93 " b irq\n" 94 " b fiq\n" 95 "reset:\n" 96 "und:\n" 97 " mov sp, #0x47000000\n" 98 " stmdb sp!, {r0-r12, lr}\n" 99 100 " ldr r3, =0x47000004\n" 101 " ldr r2, [r3]\n" 102 " blx r2\n" 103 104 " mov sp, #0x47000000\n" 105 " ldmdb sp, {r0-r12, pc}^ \n" 106 107 "swi:\n" 108 " mov sp, #0x47000000\n" 109 " stmdb sp!, {r0-r12, lr}^\n" 110 111 " mov sp, #0x47000000\n" 112 " ldmdb sp, {r0-r12, pc}^ \n" 113 114 "pre_abt:\n" 115 116 "data_abt:\n" 117 " mov sp, #0x47000000\n" 118 " sub lr, lr, #4\n" 119 " stmdb sp!, {r0-r12, lr}\n" 120 121 " ldr r3, =0x47000008\n" 122 " ldr r2, [r3]\n" 123 " blx r2\n" 124 125 " mov sp, #0x47000000\n" 126 " ldmdb sp, {r0-r12, pc}^ \n" 127 "irq:\n" 128 129 " mov sp, #0x47000000\n" 130 " sub lr, lr, #4\n" 131 " stmdb sp!, {r0-r12, lr}\n" 132 133 " ldr r3, =0x47000000\n" 134 " ldr r2, [r3]\n" 135 " blx r2\n" 136 137 " mov sp, #0x47000000\n" 138 " ldmdb sp, {r0-r12, pc}^ \n" 139 140 "fiq:\n" 141 142 ".global vector_start\n" 143 "vector_start: \n" 144 ".word vector \n " 145 146 ); 147 148 void init_table(unsigned long *addr) 149 { 150 unsigned long va = 0; 151 unsigned long phys = 0; 152 153 //0x40000000-0x80000000 -> 0x40000000-0x80000000 154 for(va = 0x40000000; va < 0x80000000; va += 0x100000) { 155 phys = va; 156 addr[va >> 20] = phys | 2; 157 } 158 159 //0x10000000-0x14000000 -> 0x10000000-0x140000000 160 for(va = 0x10000000; va < 0x14000000; va += 0x100000) { 161 phys = va; 162 addr[va >> 20] = phys | 2; 163 } 164 //0x10000000-0x14000000 -> 0x10000000-0x140000000 165 for(va = 0x0; va < 0x10000000; va += 0x100000) { 166 phys = va + 0x70000000; 167 addr[va >> 20] = phys | 2; 168 } 169 170 }
运行结果如下: