Chinaunix首页 | 论坛 | 博客
  • 博客访问: 133443
  • 博文数量: 38
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 191
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-16 11:31
个人简介

嵌入式新人

文章分类

全部博文(38)

文章存档

2016年(38)

我的朋友

分类: 嵌入式

2016-07-07 23:13:05

    中断处理是ARM和嵌入式软件中重要的内容,一定要理解透彻,熟练掌握。本文首先对ARM的7种异常处理进行介绍,然后以S5PV210的中断异常(IRQ)(最为典型的一种异常)为例,对ARM的中断处理过程进行较详细的介绍,通过这些内容,相信对ARM的中断处理有了一定深度的认知。
    

1 异常处理的过程
        在我的博客ARM的异常处理机制中对ARM的异常种类、异常优先级、异常向量地址和ARM的异常处理机制都进行了详细的介绍,为了保证本文的完整性,这里列出ARM的异常处理过程,便于与后续S5PV210的中断处理过程进行对照,加深知识的理解。
    异常发生后,硬件会自动将PC指针指向异常向量表中该向量,接着做3件事(1)保存现场;(2)调用并执行异常处理程序;(3)返回现场。
    保存现场的目的是为了异常返回后,能够继续执行被异常打断的程序,现场指的是异常发生时ARM所处工作模式的寄存器,包括R0~R12、SP、LR、PC和CPSR,保存现场也就是保存异常发生时寄存器的值。
    保存完现场后,会调用并执行真正的异常处理程。
    异常处理程序执行完成后,需返回异常发生前的工作模式,恢复寄存器R0~R12、SP、LR、PC和CPSR的值继续执行被异常打断的程序
    这里以IRQ中断(异常的一种)为例,说明中断发生后需做的3件事。
#define IRQ_STACK    0xd0037f80 //以S5PV210的IRQ STACK为例
IRQ_handle:            
//------------以下为保存现场-----------------//
ldr sp, =IRQ_STACK      // 设置IRQ模式下的栈
sub lr, lr, #4  //保存LR,ARM有3级流水线,PC指向正在执行代码地址+8的地址,发生中断后,正在执行的代码需要执行完才可响应中断,因此中断返回后PC需要指向正在执行代码地址+4的地址,也即原PC-4的地址
stmfd {r0-r12, lr}     // 压栈,保存r0-r12和lr到irq模式下的栈,同时硬件自动将CPSR复制到IRQ模式下的SPSR中,保存起来

//------------以下为执行中断处理程序-----------------//
 bl irq_handler      // 调用真正的isr来处理中断

//------------以下为恢复现场-----------------//
 ldmfd {r0-r12, pc}^     // 出栈,将之前压栈的r0-r12和pc恢复到原模式下r0-r12和pc中,同时硬件自动将IRQ模式下的SPSR复制到原模式的CPSR中,恢复现场


2 中断处理过程
    程序正常运行时,如果某个中断被触发,ARM处理器硬件会自动将PC指针指向异常向量表中IRQ向量,即程序跳转到IRQ_handle函数,(1)执行保存现场,(2)调用irq_handler函数,进一步执行真正的ISR函数(本节重点内容),(3)中断处理程序执行完后,恢复现场,执行被中断打断的程序。本节的内容就是来了解irq_handler函数需要做哪些事情,这些事情在S5PV210是如何实现的。
2.1 
irq_handler函数需要做的事
    中断发生后,irq_handler函数做的事:
1)确定是哪个编号的中断源发生了中断(需事先对所有中断源进行编号)
2)根据中断源编号,选择相应的ISR程序执行(需要事先将ISR程序和中断源绑定)。
    
2.2 S3C2440的irq_handler函数需要做的事
    S3C2440中定中断源编号和选择isr程序的分界相对清晰(这种中断处理方式也是CPU中较为典型的处理方式),具体过程是:
    
定中断源编号的方法是:当中断发生后,中断源寄存器SRCPND的相应bit位会置1(如果多个中断源同时请求中断,所有相应的bit都会置1),然后通过优先级仲裁后,只有优先级最高的中断得到响应,将寄存器INTPND中的该bit置1,(之前这些步骤都是硬件自动完成的,后续步骤是软件完成的),
通过查询INTPND中1的位置,即可得到哪个中断源请求得到响应,确定中断源编号。
    择ISR程序的方法是:确定中断源编号后,用该编号作为索引在isr数组中查询得到isr地址(isr数组是由各中断isr函数名组成的数组,在中断初始化时就静态绑定好的),然后执行isr程序。

    可见,S3C2440的irq_handler函数需要做的事就是有下划线的语句描述的内容。

    

2.3 S5PV210的irq_handler函数需要做的事

        S5PV210中定中断源编号和选择isr程序的分界不明显,因为S5PV210硬件会自动识别中断编号,从中断发生到调用isr函数的过程是:
    S5PV210将中断源分成4组(VIC0-VIC3),每组32个中断源,共128个中断源(实际是96个),当中断发生后,硬件会自动识别中断编号,自动将状态寄存器VICnIRQstatus[0:31](n=0-3,合计为128bit,硬件上对应128个中断源)中相应bit位置1(如果多个中断源同时请求中断,经过优先级仲裁后,只有优先级最高的中断源对应的bit位置1,(之前这些步骤都是硬件自动完成的,后续步骤是软件完成的),通过查询哪个VICnIRQstatus不为0n=0-3,查询的是4个寄存器整体,而不是bit位,得知是VIC0-VIC3哪组发生了中断。

     同时硬件会
自动将VICnVECTADDR0---VICnVECTADDR31寄存器(n=0-3,合计为128个寄存器,硬件上对应128个中断源)中存放的isr函数地址(中断初始化时就静态绑定好的)复制到VICnADDR中,(之前这些步骤都是硬件自动完成的,后续步骤是软件完成的),根据获得发生中断的组号(VIC0-VIC3,去相应的VICnADDR(n=0-3,对应中断源组VIC0-VIC3)中取出isr函数地址,然后执行isr函数。
       
可见,S3C2440的irq_handler函数需要做的事就是有下划线的语句描述的内容,其他事情则需要其他程序提前初始化好,如isr函数地址绑定到VICnVECTADDR0---VICnVECTADDR31中,异常向量表中IRQ向量的跳转等。

3 S5PV210的中断处理实例
3.1 中断处理实例的任务
    中断处理实例的任务是在开发板S5PV210上,当按下按键时,从串口打印出相应的信息,例如按下SW5(LEFT)键,串口打印出“isr_eint2_LEFT.”信息。按键部分的原理图见下图,可见SW5(LEFT)对应中断EINT2,SW6(LEFT)对应中断EINT3,SW7-SW10对应中断EINT16-EINT19。

3.2 程序设计思想和实现
    说明 ,本程序来源于朱有鹏老师的例程,在此表示感谢。请仔细阅读源代码,理解S5PV21整个中断处理过程
    完整程序文件:
    keyint.rar

  • Start.S中用IRQ_handle实现中断触发后的现场保护、irq_handler的调用(进一步调用和执行isr函数)和返回现场。
  • 在main.c中实现(1)key管脚初始化为中断工作方式,(2)UART初始化,(3)异常向量表的初始化(绑定IRQ_handle到异常向量表中的IRQ向量),(4)将isr函数绑定到中断控制器相应的VICnVECTADDR中,(5)使能与按键相关的中断。
  • main.c在正常运行中如果发生中断,硬件会自动将VICnVECTADDR的内容复制到VICnADDR中,然后PC跳转到异常向量表中的IRQ向量-->再跳转执行IRQ_handle-->进一步调用irq_handler,在irq_handler通过查询VIC0IRQSTATUS确定去哪个VICnADDR中取isr函数地址-->执行isr函数-->返回现场,继续执行main.c中的被中断打断的程序。
(1) start.s

点击(此处)折叠或打开

  1. #define WTCON        0xE2700000
  2. #define SVC_STACK    0xd0037d80
  3. #define IRQ_STACK    0xd0037f80

  4. .global _start    
  5. .global IRQ_handle    

  6. _start:
  7.     
  8.     ldr r0, =WTCON // 第1步:关看门狗(向WTCON的bit5写入0即可)
  9.     ldr r1, =0x0
  10.     str r1, [r0]
  11.         
  12.     bl clock_init // 第2步:初始化时钟
  13.     
  14.     ldr sp, =SVC_STACK // 第3步:设置SVC栈
  15.     
  16.     mrc p15,0,r0,c1,c0,0;    // 第4步:开/关icache        // 读出cp15的c1到r0中
  17.     //bic r0, r0, #(1<<12)            // bit12 置0 关icache
  18.     orr r0, r0, #(1<<12)            // bit12 置1 开icache
  19.     mcr p15,0,r0,c1,c0,0;

  20.     bl main
  21.     b . // 汇编最后的这个死循环不能丢
  22.     

  23. IRQ_handle:

  24. //------------以下为保存现场-----------------//
  25.     ldr sp, =IRQ_STACK // 设置IRQ模式下的栈
  26.     sub lr, lr, #4 //保存LR,ARM有3级流水线,PC指向正在执行代码地址+8的地址,发生中断后,正在执行的代码需要执行完才可响应中断,因此中断返回后PC需要指向正在执行代码地址+4的地址,也即原PC-4的地址
  27.     stmfd {r0-r12, lr} // 压栈,保存r0-r12和lr到irq模式下的栈,同时硬件自动将CPSR复制到IRQ模式下的SPSR中,保存起来

  28. //------------以下为执行中断处理程序-----------------//
  29.     bl irq_handler // 调用真正的isr来处理中断
  30.  
  31. //------------以下为恢复现场-----------------//
  32.     ldmfd {r0-r12, pc}^ // 出栈,将之前压栈的r0-r12和pc恢复到原模式下r0-r12和pc中,同时硬件自动将IRQ模式下的SPSR复制到原模式的CPSR中,恢复现场
(2) main.c


点击(此处)折叠或打开

  1. #include "stdio.h"
  2. #include "int.h"
  3. #include "main.h"

  4. #define KEY_EINT2        NUM_EINT2        // LEFT key
  5. #define KEY_EINT3        NUM_EINT3        // DOWN key
  6. #define KEY_EINT16_19    NUM_EINT16_31    // Other 4 keys

  7. void delay(int i)
  8. {
  9.     volatile int j = 10000;
  10.     while (i--)
  11.         while(j--);
  12. }


  13. int main(void)
  14. {
  15.     key_init_interrupt(); //用中断方式来处理按键的初始化函数
  16.     uart_init(); //串口初始化
  17.     system_init_exception(); //异常处理初始化
  18.     
  19.     printf("-------------key interrypt test--------------");
  20.     
  21.     
  22.     intc_setvectaddr(KEY_EINT2, isr_eint2); // 将中断源编号KEY_EINT2的ISR函数isr_eint2绑定到中断控制器相应的VICnVECTADDR中
  23.     intc_setvectaddr(KEY_EINT3, isr_eint3);
  24.     intc_setvectaddr(KEY_EINT16_19, isr_eint16171819);
  25.     

  26.     intc_enable(KEY_EINT2);     // 使能编号KEY_EINT2的中断
  27.     intc_enable(KEY_EINT3);
  28.     intc_enable(KEY_EINT16_19);
  29.     
  30.     
  31.     while (1) // 心跳
  32.     {
  33.         printf("A ");
  34.         delay(10000);
  35.     }

  36.     return 0;
  37. }
(3)key.c

点击(此处)折叠或打开
  1. #include "stdio.h"
  2. #include "main.h"

  3. // 定义操作寄存器的宏
  4. #define GPH0CON        0xE0200C00
  5. #define GPH0DAT        0xE0200C04
  6. #define GPH2CON        0xE0200C40
  7. #define GPH2DAT        0xE0200C44

  8. #define rGPH0CON    (*(volatile unsigned int *)GPH0CON)
  9. #define rGPH0DAT    (*(volatile unsigned int *)GPH0DAT)
  10. #define rGPH2CON    (*(volatile unsigned int *)GPH2CON)
  11. #define rGPH2DAT    (*(volatile unsigned int *)GPH2DAT)

  12. #define EXT_INT_0_CON    0xE0200E00
  13. #define EXT_INT_2_CON    0xE0200E08
  14. #define EXT_INT_0_PEND    0xE0200F40
  15. #define EXT_INT_2_PEND    0xE0200F48
  16. #define EXT_INT_0_MASK    0xE0200F00
  17. #define EXT_INT_2_MASK    0xE0200F08

  18. #define rEXT_INT_0_CON    (*(volatile unsigned int *)EXT_INT_0_CON)
  19. #define rEXT_INT_2_CON    (*(volatile unsigned int *)EXT_INT_2_CON)
  20. #define rEXT_INT_0_PEND    (*(volatile unsigned int *)EXT_INT_0_PEND)
  21. #define rEXT_INT_2_PEND    (*(volatile unsigned int *)EXT_INT_2_PEND)
  22. #define rEXT_INT_0_MASK    (*(volatile unsigned int *)EXT_INT_0_MASK)
  23. #define rEXT_INT_2_MASK    (*(volatile unsigned int *)EXT_INT_2_MASK)


  24. //-----------------------中断方式处理按键-----------------------------------
  25. // 以中断方式来处理按键的初始化
  26. void key_init_interrupt(void)
  27. {
  28.     // 1. 外部中断对应的GPIO模式设置
  29.     rGPH0CON |= 0xFF<<8;        // GPH0_2 GPH0_3设置为外部中断模式
  30.     rGPH2CON |= 0xFFFF<<0;        // GPH2_0123共4个引脚设置为外部中断模式
  31.     
  32.     // 2. 中断触发模式设置
  33.     rEXT_INT_0_CON &= ~(0xFF<<8);     // bit8~bit15全部清零
  34.     rEXT_INT_0_CON |= ((2<<8)|(2<<12));     // EXT_INT2和EXT_INT3设置为下降沿触发
  35.     rEXT_INT_2_CON &= ~(0xFFFF<<0);
  36.     rEXT_INT_2_CON |= ((2<<0)|(2<<4)|(2<<8)|(2<<12));    
  37.     
  38.     // 3. 中断允许
  39.     rEXT_INT_0_MASK &= ~(3<<2);            // 外部中断允许
  40.     rEXT_INT_2_MASK &= ~(0x0f<<0);
  41.     
  42.     // 4. 清挂起,清除是写1,不是写0
  43.     rEXT_INT_0_PEND |= (3<<2);
  44.     rEXT_INT_2_PEND |= (0x0F<<0);
  45. }

  46. // EINT2通道对应的按键,就是GPH0_2引脚对应的按键,就是开发板上标了LEFT的那个按键
  47. void isr_eint2(void)
  48. {
  49.     // 真正的isr应该做2件事情。
  50.     // 第一,中断处理代码,就是真正干活的代码
  51.     printf("isr_eint2_LEFT.\n");
  52.     // 第二,清除中断挂起
  53.     rEXT_INT_0_PEND |= (1<<2);
  54.     intc_clearvectaddr();
  55. }

  56. void isr_eint3(void)
  57. {
  58.     // 真正的isr应该做2件事情。
  59.     // 第一,中断处理代码,就是真正干活的代码
  60.     printf("isr_eint3_DOWN.\n");
  61.     // 第二,清除中断挂起
  62.     rEXT_INT_0_PEND |= (1<<3);
  63.     intc_clearvectaddr();
  64. }

  65. void isr_eint16171819(void)
  66. {
  67.     // 真正的isr应该做2件事情。
  68.     // 第一,中断处理代码,就是真正干活的代码
  69.     // 因为EINT16~31是共享中断,所以要在这里再次去区分具体是哪个子中断
  70.     if (rEXT_INT_2_PEND & (1<<0))
  71.     {
  72.         printf("eint16\n");
  73.     }
  74.     if (rEXT_INT_2_PEND & (1<<1))
  75.     {
  76.         printf("eint17\n");
  77.     }
  78.     if (rEXT_INT_2_PEND & (1<<2))
  79.     {
  80.         printf("eint18\n");
  81.     }
  82.     if (rEXT_INT_2_PEND & (1<<3))
  83.     {
  84.         printf("eint19\n");
  85.     }

  86.     // 第二,清除中断挂起
  87.     rEXT_INT_2_PEND |= (0x0f<<0);
  88.     intc_clearvectaddr();
  89. }
(4) int.c

点击(此处)折叠或打开

  1. #include "int.h"
  2. #include "stdio.h"

  3. void system_init_exception(void);
  4. void irq_handler(void);
  5. unsigned long intc_getvicirqstatus(unsigned long ucontroller);

  6. void intc_init(void);
  7. void intc_enable(unsigned long intnum);
  8. void intc_disable(unsigned long intnum);
  9. void intc_setvectaddr(unsigned long intnum, void (*handler)(void));
  10. void intc_clearvectaddr(void);


  11. void IRQ_handle(void);



  12. void reset_exception(void)
  13. {
  14.     printf("reset_exception.\n");
  15. }

  16. void undef_exception(void)
  17. {
  18.     printf("undef_exception.\n");
  19. }

  20. void soft_int_exception(void)
  21. {
  22.     printf("soft_int_exception.\n");
  23. }

  24. void prefetch_exception(void)
  25. {
  26.     printf("prefetch_exception.\n");
  27. }

  28. void data_exception(void)
  29. {
  30.     printf("data_exception.\n");
  31. }

  32. /*
  33. 1.system_init_exception的工作有两项,1--初始化中断控制器,2--将IRQ_handle函数绑定到异常向量表中的IRQ向量。目的是发生IRQ异常后,硬件自动将PC指向到异常向量表的IRQ向量,再跳转到IRQ_handle函数地址,执行IRQ_handle函数。
  34. 2.IRQ_handle的工作是保存现场,调用irq_handler函数(进一步调用真正的isr函数),返回现场。
  35. 3.调用真正的isr函数的步骤

  36. */
  37. // 主要功能:绑定第一阶段异常向量表;禁止所有中断;选择所有中断类型为IRQ;
  38. // 清除VICnADDR为0
  39. void system_init_exception(void)
  40. {
  41.     // 第一阶段处理,绑定异常向量表
  42.     r_exception_reset = (unsigned int)reset_exception;
  43.     r_exception_undef = (unsigned int)undef_exception;
  44.     r_exception_sotf_int = (unsigned int)soft_int_exception;
  45.     r_exception_prefetch = (unsigned int)prefetch_exception;
  46.     r_exception_data = (unsigned int)data_exception;
  47.     r_exception_irq = (unsigned int)IRQ_handle;
  48.     r_exception_fiq = (unsigned int)IRQ_handle;
  49.     
  50.     // 初始化中断控制器的基本寄存器
  51.     intc_init();
  52. }

  53. // 初始化中断控制器
  54. void intc_init(void)
  55. {
  56.     // 禁止所有中断
  57.     // 这样做的目的是:中断一旦打开,因为外部或者硬件自己的原因产生中断后一定就会寻找isr,
  58.     // 而我们可能认为自己用不到这个中断就没有提供isr,这时它自动拿到的就是乱码,程序很可能跑飞,所以不用的中断一定要关掉。
  59.     // 通常做法是先禁止所有中断,再逐一打开需要的中断。一旦打开,就必须提供相应的isr并绑定好。
  60.     VIC0INTENCLEAR = 0xffffffff;
  61.     VIC1INTENCLEAR = 0xffffffff;
  62.     VIC2INTENCLEAR = 0xffffffff;
  63.     VIC3INTENCLEAR = 0xffffffff;

  64.     // 选择中断类型为IRQ
  65.     VIC0INTSELECT = 0x0;
  66.     VIC1INTSELECT = 0x0;
  67.     VIC2INTSELECT = 0x0;
  68.     VIC3INTSELECT = 0x0;

  69.     // 清VICxADDR
  70.     intc_clearvectaddr();
  71. }


  72. // 清除需要处理的中断的中断处理函数的地址
  73. void intc_clearvectaddr(void)
  74. {
  75.     // VICxADDR:当前正在处理的中断的中断处理函数的地址
  76.     VIC0ADDR = 0;
  77.     VIC1ADDR = 0;
  78.     VIC2ADDR = 0;
  79.     VIC3ADDR = 0;
  80. }


  81. // 绑定我们写的isr到VICnVECTADDR寄存器
  82. // 绑定过之后我们就把isr地址交给硬件了,剩下的我们不用管了,硬件自己会处理
  83. // 等发生相应中断的时候,我们直接到相应的VICnADDR中去取isr地址即可。
  84. // 参数:intnum是int.h定义的物理中断号,handler是函数指针,就是我们写的isr

  85. // VIC0VECTADDR定义为VIC0VECTADDR0寄存器的地址,就相当于是VIC0VECTADDR0~31这个
  86. // 数组(这个数组就是一个函数指针数组)的首地址,然后具体计算每一个中断的时候
  87. // 只需要首地址+偏移量即可。
  88. void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
  89. {
  90.     //VIC0
  91.     if(intnum<32)
  92.     {
  93.         *( (volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)) ) = (unsigned)handler;
  94.     }
  95.     //VIC1
  96.     else if(intnum<64)
  97.     {
  98.         *( (volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)) ) = (unsigned)handler;
  99.     }
  100.     //VIC2
  101.     else if(intnum<96)
  102.     {
  103.         *( (volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)) ) = (unsigned)handler;
  104.     }
  105.     //VIC3
  106.     else
  107.     {
  108.         *( (volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)) ) = (unsigned)handler;
  109.     }
  110.     return;
  111. }


  112. // 使能中断
  113. // 通过传参的intnum来使能某个具体的中断源,中断号在int.h中定义,是物理中断号
  114. void intc_enable(unsigned long intnum)
  115. {
  116.     unsigned long temp;
  117.     // 确定intnum在哪个寄存器的哪一位
  118.     // <32就是0~31,必然在VIC0
  119.     if(intnum<32)
  120.     {
  121.         temp = VIC0INTENABLE;
  122.         temp |= (1<<intnum);        // 如果是第一种设计则必须位操作,第二种设计可以
  123.                                     // 直接写。
  124.         VIC0INTENABLE = temp;
  125.     }
  126.     else if(intnum<64)
  127.     {
  128.         temp = VIC1INTENABLE;
  129.         temp |= (1<<(intnum-32));
  130.         VIC1INTENABLE = temp;
  131.     }
  132.     else if(intnum<96)
  133.     {
  134.         temp = VIC2INTENABLE;
  135.         temp |= (1<<(intnum-64));
  136.         VIC2INTENABLE = temp;
  137.     }
  138.     else if(intnum<NUM_ALL)
  139.     {
  140.         temp = VIC3INTENABLE;
  141.         temp |= (1<<(intnum-96));
  142.         VIC3INTENABLE = temp;
  143.     }
  144.     // NUM_ALL : enable all interrupt
  145.     else
  146.     {
  147.         VIC0INTENABLE = 0xFFFFFFFF;
  148.         VIC1INTENABLE = 0xFFFFFFFF;
  149.         VIC2INTENABLE = 0xFFFFFFFF;
  150.         VIC3INTENABLE = 0xFFFFFFFF;
  151.     }

  152. }

  153. // 禁止中断
  154. // 通过传参的intnum来禁止某个具体的中断源,中断号在int.h中定义,是物理中断号
  155. void intc_disable(unsigned long intnum)
  156. {
  157.     unsigned long temp;

  158.     if(intnum<32)
  159.     {
  160.         temp = VIC0INTENCLEAR;
  161.         temp |= (1<<intnum);
  162.         VIC0INTENCLEAR = temp;
  163.     }
  164.     else if(intnum<64)
  165.     {
  166.         temp = VIC1INTENCLEAR;
  167.         temp |= (1<<(intnum-32));
  168.         VIC1INTENCLEAR = temp;
  169.     }
  170.     else if(intnum<96)
  171.     {
  172.         temp = VIC2INTENCLEAR;
  173.         temp |= (1<<(intnum-64));
  174.         VIC2INTENCLEAR = temp;
  175.     }
  176.     else if(intnum<NUM_ALL)
  177.     {
  178.         temp = VIC3INTENCLEAR;
  179.         temp |= (1<<(intnum-96));
  180.         VIC3INTENCLEAR = temp;
  181.     }
  182.     // NUM_ALL : disable all interrupt
  183.     else
  184.     {
  185.         VIC0INTENCLEAR = 0xFFFFFFFF;
  186.         VIC1INTENCLEAR = 0xFFFFFFFF;
  187.         VIC2INTENCLEAR = 0xFFFFFFFF;
  188.         VIC3INTENCLEAR = 0xFFFFFFFF;
  189.     }

  190.     return;
  191. }




  192. // 真正的中断处理程序。意思就是说这里只考虑中断处理,不考虑保护/恢复现场
  193. void irq_handler(void)
  194. {    
  195.     // 虽然硬件已经自动帮我们把isr放入了VICnADDR中,但是因为有4个,所以我们必须
  196.     // 先去软件的检查出来到底哪个VIC中断了,也就是说isr到底在哪个VICADDR寄存器中
  197.     unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
  198.     int i=0;
  199.     void (*isr)(void) = NULL;

  200.     for(i=0; i<4; i++)
  201.     {
  202.         // 发生一个中断时,4个VIC中有3个是全0,1个的其中一位不是0
  203.         if(intc_getvicirqstatus(i) != 0)
  204.         {
  205.             isr = (void (*)(void)) vicaddr[i];
  206.             break;
  207.         }
  208.     }
  209.     (*isr)();        // 通过函数指针来调用函数
  210. }


  211. // 读取VICnIRQSTATUS寄存器,判断其中哪个有一位为1,来得知哪个VIC发生中断了
  212. unsigned long intc_getvicirqstatus(unsigned long ucontroller)
  213. {
  214.     if(ucontroller == 0)
  215.         return    VIC0IRQSTATUS;
  216.     else if(ucontroller == 1)
  217.         return     VIC1IRQSTATUS;
  218.     else if(ucontroller == 2)
  219.         return     VIC2IRQSTATUS;
  220.     else if(ucontroller == 3)
  221.         return     VIC3IRQSTATUS;
  222.     else
  223.     {}
  224.     return 0;
  225. }
(5)int.h

点击(此处)折叠或打开

  1. #ifndef __INT_H__
  2. #define __INT_H__


  3. void intc_init(void);
  4. void intc_enable(unsigned long intnum);
  5. void intc_disable(unsigned long intnum);
  6. void intc_setvectaddr(unsigned long intnum, void (*handler)(void));
  7. void intc_clearvectaddr(void);
  8. unsigned long intc_getvicirqstatus(unsigned long ucontroller);
  9. void irq_handler(void);
  10. void IRQ_handle(void);
  11. void system_init_exception(void);



  12. //// Interrupt
  13. #define VIC0_BASE                    (0xF2000000)
  14. #define VIC1_BASE                    (0xF2100000)
  15. #define VIC2_BASE                    (0xF2200000)
  16. #define VIC3_BASE                    (0xF2300000)

  17. // VIC0
  18. #define        VIC0IRQSTATUS            ( *((volatile unsigned long *)(VIC0_BASE + 0x00)) )
  19. #define        VIC0FIQSTATUS            ( *((volatile unsigned long *)(VIC0_BASE + 0x04)) )
  20. #define        VIC0INTSELECT            ( *((volatile unsigned long *)(VIC0_BASE + 0x0c)) )
  21. #define        VIC0INTENABLE            ( *((volatile unsigned long *)(VIC0_BASE + 0x10)) )
  22. #define        VIC0INTENCLEAR            ( *((volatile unsigned long *)(VIC0_BASE + 0x14)) )
  23. #define     VIC0VECTADDR            (VIC0_BASE + 0x100)
  24. #define     VIC0ADDR                ( *((volatile unsigned long *)(VIC0_BASE + 0xf00)) )

  25. // VIC1
  26. #define        VIC1IRQSTATUS            ( *((volatile unsigned long *)(VIC1_BASE + 0x00)) )
  27. #define        VIC1FIQSTATUS            ( *((volatile unsigned long *)(VIC1_BASE + 0x04)) )
  28. #define        VIC1INTSELECT            ( *((volatile unsigned long *)(VIC1_BASE + 0x0c)) )
  29. #define        VIC1INTENABLE            ( *((volatile unsigned long *)(VIC1_BASE + 0x10)) )
  30. #define        VIC1INTENCLEAR            ( *((volatile unsigned long *)(VIC1_BASE + 0x14)) )
  31. #define     VIC1VECTADDR            (VIC1_BASE + 0x100)
  32. #define     VIC1ADDR                ( *((volatile unsigned long *)(VIC1_BASE + 0xf00)) )

  33. // VIC2
  34. #define        VIC2IRQSTATUS            ( *((volatile unsigned long *)(VIC2_BASE + 0x00)) )
  35. #define        VIC2FIQSTATUS            ( *((volatile unsigned long *)(VIC2_BASE + 0x04)) )
  36. #define        VIC2INTSELECT            ( *((volatile unsigned long *)(VIC2_BASE + 0x0c)) )
  37. #define        VIC2INTENABLE            ( *((volatile unsigned long *)(VIC2_BASE + 0x10)) )
  38. #define        VIC2INTENCLEAR            ( *((volatile unsigned long *)(VIC2_BASE + 0x14)) )
  39. #define         VIC2VECTADDR            (VIC2_BASE + 0x100)
  40. #define         VIC2ADDR                ( *((volatile unsigned long *)(VIC2_BASE + 0xf00)) )

  41. // VIC3
  42. #define        VIC3IRQSTATUS            ( *((volatile unsigned long *)(VIC3_BASE + 0x00)) )
  43. #define         VIC3FIQSTATUS            ( *((volatile unsigned long *)(VIC3_BASE + 0x04)) )
  44. #define         VIC3INTSELECT            ( *((volatile unsigned long *)(VIC3_BASE + 0x0c)) )
  45. #define         VIC3INTENABLE            ( *((volatile unsigned long *)(VIC3_BASE + 0x10)) )
  46. #define         VIC3INTENCLEAR            ( *((volatile unsigned long *)(VIC3_BASE + 0x14)) )
  47. #define         VIC3VECTADDR            (VIC3_BASE + 0x100)
  48. #define         VIC3ADDR                ( *((volatile unsigned long *)(VIC3_BASE + 0xf00)) )


  49. #define exception_vector_table_base        0xD0037400
  50. #define exception_reset                    (exception_vector_table_base + 0x00)
  51. #define exception_undef                    (exception_vector_table_base + 0x04)
  52. #define exception_soft_int                (exception_vector_table_base + 0x08)
  53. #define exception_prefetch                (exception_vector_table_base + 0x0C)
  54. #define exception_data                    (exception_vector_table_base + 0x10)
  55. #define exception_irq                    (exception_vector_table_base + 0x18)
  56. #define exception_fiq                    (exception_vector_table_base + 0x1C)

  57. #define r_exception_reset        (*(volatile unsigned int *)exception_reset)
  58. #define r_exception_undef        (*(volatile unsigned int *)exception_undef)
  59. #define r_exception_sotf_int    (*(volatile unsigned int *)exception_soft_int)
  60. #define r_exception_prefetch    (*(volatile unsigned int *)exception_prefetch)
  61. #define r_exception_data        (*(volatile unsigned int *)exception_data)
  62. #define r_exception_irq            (*(volatile unsigned int *)exception_irq)
  63. #define r_exception_fiq            (*(volatile unsigned int *)exception_fiq)




  64. // 中断源编号
  65. #define INT_LIMIT                (96)

  66. //INT NUM - VIC0
  67. #define NUM_EINT0                (0)
  68. #define NUM_EINT1                (1)
  69. #define NUM_EINT2                (2)
  70. #define NUM_EINT3                (3)
  71. #define NUM_EINT4                (4)
  72. #define NUM_EINT5                (5)
  73. #define NUM_EINT6                (6)
  74. #define NUM_EINT7                (7)
  75. #define NUM_EINT8                (8)
  76. #define NUM_EINT9                (9)
  77. #define NUM_EINT10                (10)
  78. #define NUM_EINT11                (11)
  79. #define NUM_EINT12                (12)
  80. #define NUM_EINT13                (13)
  81. #define NUM_EINT14                (14)
  82. #define NUM_EINT15                (15)
  83. #define NUM_EINT16_31            (16)
  84. #define NUM_Reserved17            (17)
  85. #define NUM_MDMA                (18)
  86. #define NUM_PDMA0                (19)
  87. #define NUM_PDMA1                (20)
  88. #define NUM_TIMER0                (21)
  89. #define NUM_TIMER1                (22)
  90. #define NUM_TIMER2                (23)
  91. #define NUM_TIMER3                (24)
  92. #define NUM_TIMER4                (25)
  93. #define NUM_SYSTIMER            (26)
  94. #define NUM_WDT                    (27)
  95. #define NUM_RTC_ALARM            (28)
  96. #define NUM_RTC_TICK            (29)
  97. #define NUM_GPIOINT                (30)
  98. #define NUM_FIMC3                (31)

  99. //INT NUM - VIC1
  100. #define NUM_CORTEX0                (32+0)
  101. #define NUM_CORTEX1                (32+1)
  102. #define NUM_CORTEX2                (32+2)
  103. #define NUM_CORTEX3                (32+3)
  104. #define NUM_CORTEX4                (32+4)
  105. #define NUM_IEM_APC                (32+5)
  106. #define NUM_IEM_IEC                (32+6)
  107. #define NUM_Reserved39            (32+7)
  108. #define NUM_NFC                    (32+8)
  109. #define NUM_CFC                    (32+9)
  110. #define NUM_UART0                (32+10)
  111. #define NUM_UART1                (32+11)
  112. #define NUM_UART2                (32+12)
  113. #define NUM_UART3                (32+13)
  114. #define NUM_I2C                    (32+14)
  115. #define NUM_SPI0                (32+15)
  116. #define NUM_SPI1                (32+16)
  117. #define NUM_SPI2                (32+17)
  118. #define NUM_AUDIO                (32+18)
  119. #define NUM_I2C_PMIC            (32+19)
  120. #define NUM_I2C_HDMI            (32+20)
  121. #define NUM_HSIRX                (32+21)
  122. #define NUM_HSITX                (32+22)
  123. #define NUM_UHOST                (32+23)
  124. #define NUM_OTG                    (32+24)
  125. #define NUM_MSM                    (32+25)
  126. #define NUM_HSMMC0                (32+26)
  127. #define NUM_HSMMC1                (32+27)
  128. #define NUM_HSMMC2                (32+28)
  129. #define NUM_MIPI_CSI            (32+29)
  130. #define NUM_MIPI_DSI            (32+30)
  131. #define NUM_ONENAND_AUDI        (32+31)

  132. //INT NUM - VIC2
  133. #define NUM_LCD0                (64+0)
  134. #define NUM_LCD1                (64+1)
  135. #define NUM_LCD2                (64+2)
  136. #define NUM_LCD3                (64+3)
  137. #define NUM_ROTATOR                (64+4)
  138. #define NUM_FIMC_A                (64+5)
  139. #define NUM_FIMC_B                (64+6)
  140. #define NUM_FIMC_C                (64+7)
  141. #define NUM_JPEG                (64+8)
  142. #define NUM_2D                    (64+9)
  143. #define NUM_3D                    (64+10)
  144. #define NUM_MIXER                (64+11)
  145. #define NUM_HDMI                (64+12)
  146. #define NUM_HDMI_I2C            (64+13)
  147. #define NUM_MFC                    (64+14)
  148. #define NUM_TVENC                (64+15)
  149. #define NUM_I2S0                (64+16)
  150. #define NUM_I2S1                (64+17)
  151. #define NUM_I2S2                (64+18)
  152. #define NUM_AC97                (64+19)
  153. #define NUM_PCM0                (64+20)
  154. #define NUM_PCM1                (64+21)
  155. #define NUM_SPDIF                (64+22)
  156. #define NUM_ADC                 (64+23)
  157. #define NUM_PENDN                (64+24)
  158. #define NUM_KEYPAD                (64+25)
  159. #define NUM_Reserved90            (64+26)
  160. #define NUM_HASH                (64+27)
  161. #define NUM_FEEDCTRL            (64+28)
  162. #define NUM_PCM2                (64+29)
  163. #define NUM_SDM_IRQ                (64+30)
  164. #define NUM_SMD_FIQ                (64+31)

  165. //INT NUM - VIC3
  166. #define NUM_IPC                    (96+0)
  167. #define NUM_HOSTIF                (96+1)
  168. #define NUM_HSMMC3                (96+2)
  169. #define NUM_CEC                    (96+3)
  170. #define NUM_TSI                    (96+4)
  171. #define NUM_MDNIE0                (96+5)
  172. #define NUM_MDNIE1                (96+6)
  173. #define NUM_MDNIE2                (96+7)
  174. #define NUM_MDNIE3                (96+8)
  175. #define NUM_ADC1                (96+9)
  176. #define NUM_PENDN1                (96+10)
  177. #define NUM_ALL                    (200)

  178. #endif

阅读(1726) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~