Exynos4412裸机开发——中断处理

 以KEY2控制LED3亮灭为例:

一、轮询方式

【0】检测按键k2,按键k2按下一次,灯LED2闪一次。

【1】查看原理图,连接引脚和控制逻辑
(1)按键k2 连接在GPX1_1引脚
(2)控制逻辑
       k2 按下  ---- K2闭合 ---- GPX1_1 低电压
       k2 常态  ---- K2打开 ---- GPX1_1 高电压

【2】查看相应的芯片手册

    【2-1】循环检测GPX1_1引脚输入的电平,为低电压时,按键按下

        (1)配置GPX1_1引脚功能为输入,设置内部上拉下拉禁止。
                  GPX1.CON = GPX1.CON &(~(0xf<<4)) ;

                  GPX1.PUD = GPX1.PUD & ~(0x3 << 2);
  (2)循环检测:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. while(1)  
  2. {  
  3.     if(!(GPX1.DAT & (0x1<<1)))  // 返回为真,按键按下  
  4.     {      
  5.         msdelay(10);  
  6.         if(!(GPX1.DAT & (0x1<<1))) //二次检测,去抖  
  7.         {  
  8.             GPX2.DAT |= 0x1 << 7;  //Turn on LED2  
  9.             mydelay_ms(500);  
  10.             GPX2.DAT &= ~(0x1<<7);  //Turn off LED2  
  11.             mydelay_ms(500);  
  12.         
  13.             while(!(GPX1.DAT & (0x1<<1)));  
  14.         }  
  15.     }  
  16. }  

这种轮询方式始终占着CPU,不利于操作。

 

二、中断方式

         将K2按下时,GPX1_1引脚获得的电平,作为异常事件。使能异常处理,k2每按下一次,响应一次异常处理。SPI 传递流程如下示:

注:

      Exynos4412中断控制器包括160个中断控制源,这些中断源来自软中断(SGI),私有外部中断(PPI),公共外部中断(SPI)。

      Exynos4412采用GIC中断控制器,主要是因为Contex-A9 是多核处理器,GIC(Generic Interrupt Controller)通用中断控制器用来选择使用哪个CPU接口,具体主要有两个功能:

1)分配器:设置一个开关,是否接收外部中断源;为该中断源选择CPU接口;

2)CPU接口:设置一个开发,是否接受该中断源请求;

 

具体实现如下:

1、外设一级 ---设置 GPIO控制器

1-- 将GPX1_1引脚的上拉和下拉禁止

        GPX1PUD[3:2]= 0b00;

2 -- 将GPX1_1引脚功能设置为中断功能 WAKEUP_INT1[1] --- EXT_INT41[1]

        GPX1CON[7:4] = 0xf

3 -- EXT_INT41CON  配置触发电平

       当前配置成下降沿触发:

       EXT_INT41CON[6:4] = 0x2

4 -- EXT_INT41_FLTCON0 配置中断引脚滤波

       默认就是打开的,不需要配置

5 -- EXT_INT41_MASK 中断使能寄存器

      使能INT41[1]

      EXT_INT41_MASK[1] = 0b0

6 -- EXT_INT41_PEND 中断状态寄存器
       当GPX1_1引脚接收到中断信号,中断发生,中断状态寄存器EXT_INT41_PEND 相应位会自动置1
        注意:中断处理完成的时候,需要清除相应状态位。置1清0.
        EXT_INT41_PEND[1] =0b1 

 

2、中断控制器

1-- 找到外设中断名称和GIC中断控制器对应的名称

    查看芯片手册(本例:Exynos_4412 -- 9.2表)
       WAKEUP_INT1[1] --- EXT_INT41[1] --- INT[9] --- SPI[25]/ID[57]

      其对应INT[9],中断ID为57,这是非常重要的,在后面的寄存器设置中起很大作用;

 

下面是外设与中断控制器处理具体流程:

 

2 -- GIC使能

       ICDDCR =1;

       使能分配器。

3 -- 使能相应中断到分配器

      ICDISER.ICDISER1 |= (0x1 << 25);    //57/32 =1...25 取整数(那个寄存器) 和余数(哪位)

      ICDISER用于使能相应中断到分配器,一个bit控制一个中断源,一个ICDISER可以控制32个中断源,这里INT[9] 对应的中断ID为57,所以在ICDSER1中进行设置,57/32 =1余25,所以这里在ICDISER1第25位置一。

 

4 -- 选择CPU接口

      设置SPI[25]/ID[57]由那个cpu处理,当前设置为cpu0的irq中断

      ICDIPTR.ICDIPTR14 |= 0x01<<8; //SPI25  interrupts are sent to processor 0   //57/4 = 14..1 14号寄存器的[15:8]

      ICDIPTR寄存器每8个bit 控制一个中断源

 

5 -- 全局使能cpu0中断处理

       CPU0.ICCICR |= 0x1;

       使能中断到CPU。

 

6 -- 优先级屏蔽寄存器,设置cpu0能处理所有的中断。

      CPU0.ICCPMR = 0xFF;

                          

3、ARM内核(cpu0)

       前面两步设置好,就可以等待中断的发生了,当中断发生时,ARM内核的处理过程如下:

 

 1-- 四大步三小步 --- 硬件

    

      (1)拷贝 CPSR 到 SPSR_<mode>
  (2)设置适当的 CPSR 位:                                
    (2-1)--改变处理器状态进入 ARM 态
       (2-2)--改变处理器模式进入相应的异常模式
       (2-3)--设置中断禁止位禁止相应中断 (如果需要)
  (3)保存返回地址到 LR_<mode>
  (4)设置 PC 为相应的异常向量
          

2 -- 中断服务程序 --- start.S 汇编

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. .text  
  2. .global _start  
  3. _start:  
  4.         b       reset  
  5.         ldr     pc,_undefined_instruction  
  6.         ldr     pc,_software_interrupt  
  7.         ldr     pc,_prefetch_abort  
  8.         ldr     pc,_data_abort  
  9.         ldr     pc,_not_used  
  10.         ldr     pc,_irq  
  11.         ldr     pc,_fiq  
  12.   
  13. _undefined_instruction: .word  _undefined_instruction  
  14. _software_interrupt:    .word  _software_interrupt  
  15. _prefetch_abort:        .word  _prefetch_abort  
  16. _data_abort:            .word  _data_abort  
  17. _not_used:              .word  _not_used  
  18. _irq:                   .word  irq_handler  
  19. _fiq:                   .word  _fiq  
  20.   
  21.   
  22. reset:  
  23.   
  24.     ldr r0,=0x40008000  
  25.     mcr p15,0,r0,c12,c0,0       @ Vector Base Address Register  
  26.   
  27.   
  28. init_stack:  
  29.         ldr     r0,stacktop         /*get stack top pointer*/  
  30.   
  31.     /********svc mode stack********/  
  32.         mov     sp,r0  
  33.         sub     r0,#128*4          /*512 byte  for irq mode of stack*/  
  34.     /****irq mode stack**/  
  35.         msr     cpsr,#0xd2  
  36.         mov     sp,r0  
  37.         sub     r0,#128*4          /*512 byte  for irq mode of stack*/  
  38.     /***fiq mode stack***/  
  39.         msr     cpsr,#0xd1  
  40.         mov     sp,r0  
  41.         sub     r0,#0  
  42.     /***abort mode stack***/  
  43.         msr     cpsr,#0xd7  
  44.         mov     sp,r0  
  45.         sub     r0,#0  
  46.     /***undefine mode stack***/  
  47.         msr     cpsr,#0xdb  
  48.         mov     sp,r0  
  49.         sub     r0,#0  
  50.    /*** sys mode and usr mode stack ***/  
  51.         msr     cpsr,#0x10  
  52.         mov     sp,r0             /*1024 byte  for user mode of stack*/  
  53.   
  54.         b       main  
  55.   
  56.     .align  4  
  57.   
  58.     /****  swi_interrupt handler  ****/  
  59.   
  60.   
  61.     /****  irq_handler  ****/  
  62. irq_handler:  
  63.   
  64.     sub  lr,lr,#4  
  65.     stmfd sp!,{r0-r12,lr}  
  66.     .weak do_irq  
  67.     bl  do_irq  
  68.     ldmfd sp!,{r0-r12,pc}^  
  69.   
  70. stacktop:    .word      stack+4*512  
  71. .data  
  72.   
  73. stack:   .space  4*512  

 

3--中断处理程序 --- do_irq函数 C语言(函数原型void name(void))

(1) 读取正在处理的中断ID寄存器(ICCIAR)

          irq_num = (CPU0.ICCIAR & 0x1FF);

(2)根据irq_num,分支处理中断  

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. switch(irq_num)  
  2. {  
  3.     .  
  4.     case 57:  
  5.         break;  
  6.     ....  
  7.   
  8. }  


 (3)清除中断状态位

        (3-1)i.外设级,EXT_INT41_PEND |= 0x1 << 1;
        (3-2)ii.GIC级,ICDICPR.ICDICPR1 |= 0x1 << 25;
        (3-3)iii.CPU0级 CPU0.ICCEOIR = (CPU0.ICCEOIR & ~(0x1FF)) | irq_num;

 

下面是C 程序:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. #include "exynos_4412.h"  
  2. #include "led.h"  
  3.   
  4. void  delay_ms(unsigned int num)  
  5. {  
  6.     int i,j;  
  7.     for(i=num; i>0;i--)  
  8.     for(j=1000;j>0;j--)  
  9.         ;  
  10. }  
  11. void do_irq(void)  
  12. {  
  13.     static int a = 1;  
  14.     int irq_num;  
  15.     irq_num = CPU0.ICCIAR&0x3ff;  //获取中断号  
  16.     switch(irq_num)  
  17.     {  
  18.     case 57:  
  19.         printf("in the irq_handler\n");  
  20.             if(a)  
  21.                 led_on(1);  
  22.             else  
  23.                 led_off(1);  
  24.             a = !a;  
  25.             EXT_INT41_PEND = EXT_INT41_PEND |((0x1 << 1)); //清GPIO中断标志位  
  26.             ICDICPR.ICDICPR1 = ICDICPR.ICDICPR1 | (0x1 << 25); //清GIC中断标志位  
  27.         break;  
  28.     }  
  29.     CPU0.ICCEOIR = CPU0.ICCEOIR&(~(0x3ff))|irq_num; //清cpu中断标志位  
  30. }  
  31. /* 
  32.  *  裸机代码,不同于LINUX 应用层, 一定加循环控制 
  33.  */  
  34. int main (void)  
  35. {  
  36.     GPX1.CON =GPX1.CON & (~(0xf << 4)) |(0xf << 4); //配置引脚功能为外部中断  
  37.     GPX1.PUD = GPX1.PUD & (~(0x3 << 2));  //关闭上下拉电阻  
  38.     EXT_INT41_CON = EXT_INT41_CON &(~(0xf << 4))|(0x2 << 4); //外部中断触发方式  
  39.     EXT_INT41_MASK = EXT_INT41_MASK & (~(0x1 << 1));  //使能中断  
  40.     ICDDCR = 1;  //使能分配器  
  41.     ICDISER.ICDISER1 = ICDISER.ICDISER1 | (0x1 << 25); //使能相应中断到分配器  
  42.     ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xff << 8))|(0x1 << 8); //选择CPU接口  
  43.     CPU0.ICCPMR = 255; //中断屏蔽优先级  
  44.     CPU0.ICCICR = 1;   //使能中断到CPU  
  45.     led_init();  
  46.     while(1)  
  47.     {  
  48.   
  49.     }  
  50.    return 0;  
  51. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

远程WEB控制MP3播放器设计(基于mini2440)

网上有很多 基于mini2440的MP3播放器设计的资料&#xff0c;多是按键控制&#xff0c;这里博主做了些轻微改动&#xff0c;利用远程WEB来控制MP3播放&#xff0c;具体怎么实现&#xff0c;下面会给出&#xff0c;大家先看看效果&#xff1a; WEB界面&#xff1a; 后台运行&…

嵌入式数据库 SQLite 浅析

SQLite是一个非常轻量级自包含(lightweight and self-contained)的DBMS&#xff0c;它可移植性好&#xff0c;很容易使用&#xff0c;很小&#xff0c;高效而且可靠。SQLite嵌入到使用它的应用程序中&#xff0c;它们共用相同的进程空间&#xff0c;而不是单独的一个进程。从外…

socket 请求Web服务器过程

HTTP协议只是一个应用层协议&#xff0c;它底层是通过TCP进行传输数据的。因此&#xff0c;浏览器访问Web服务器的过程必须先有“连接建立”的发生。 而有人或许会问&#xff1a;众所周知&#xff0c;HTTP协议有两大特性&#xff0c;一个是“无连接”性&#xff0c;一个是“无状…

有些事情现在不做一辈子就都不会做了

这句话最近一直印在我的脑海里。这句话最早是在Casperkid的百度空间里面看见的&#xff0c;那时他生日。作为师傅的刺&#xff08;道哥&#xff09;送了他自己写的一本《白帽子讲WEB安全》给他&#xff0c;并在扉页上写着这句话。那时一看到这句话&#xff0c;仿佛有种触电的感…

HTTP 数据包头解析

一、连接至Web服务器 一个客户端应用&#xff08;如Web浏览器&#xff09;打开到Web服务器的HTTP端口的一个套接字&#xff08;缺省为80&#xff09;。 例如&#xff1a;http://www.myweb.com:8080/index.html 在Java中&#xff0c;这将等同于代码&#xff1a; [java] view pla…

Shell 脚本中如何使用make命令

最近开发的项目中需要编写Shell脚本对整个工程进行自动化编译&#xff0c;即在Shell脚本中使用make命令来进行编译&#xff0c;下面回顾一下Shell脚本中如何使用make命令&#xff09; 在开发一个系统时&#xff0c;一般是将一个系统分成几个模块&#xff0c;这样做提高了系统的…

Shell 脚本知识回顾 (六) —— Shell 函数

一、Shell函数&#xff1a;Shell函数返回值、删除函数、在终端调用函数 函数可以让我们将一个复杂功能划分成若干模块&#xff0c;让程序结构更加清晰&#xff0c;代码重复利用率更高。像其他编程语言一样&#xff0c;Shell 也支持函数。Shell 函数必须先定义后使用。 Shell 函…

Shell 脚本知识回顾 (五) —— Shell 循环

一、Shell for循环 与其他编程语言类似&#xff0c;Shell支持for循环。 for循环一般格式为&#xff1a;for 变量 in 列表 docommand1command2...commandN done 列表是一组值&#xff08;数字、字符串等&#xff09;组成的序列&#xff0c;每个值通过空格分隔。每循环一次&…

Shell 脚本知识回顾 (四) —— Shell 命令及Shell 相关语句

一、Shell echo命令 echo是Shell的一个内部指令&#xff0c;用于在屏幕上打印出指定的字符串。命令格式&#xff1a;echo arg您可以使用echo实现更复杂的输出格式控制。 显示转义字符 echo "\"It is a test\""结果将是&#xff1a;"It is a test"…

Shell 脚本知识回顾 (三) —— 替换、运算符、字符串、数组

一、Shell替换&#xff1a;Shell变量替换&#xff0c;命令替换&#xff0c;转义字符 如果表达式中包含特殊字符&#xff0c;Shell 将会进行替换。例如&#xff0c;在双引号中使用变量就是一种替换&#xff0c;转义字符也是一种替换。 举个例子&#xff1a; [cpp] view plaincop…

Shell 脚本知识回顾 (二) —— Shell变量

一、Shell变量&#xff1a;Shell变量的定义、删除变量、只读变量、变量类型 Shell支持自定义变量。定义变量 定义变量时&#xff0c;变量名不加美元符号&#xff08;$&#xff09;&#xff0c;如&#xff1a; [cpp] view plaincopy variableName"value" 注意&…

Shell 脚本知识回顾 (一) —— 基础篇

一、Shell简介&#xff1a;什么是Shell&#xff0c;Shell命令的两种执行方式 Shell本身是一个用C语言编写的程序&#xff0c;它是用户使用Unix/Linux的桥梁&#xff0c;用户的大部分工作都是通过Shell完成的。Shell既是一种命令语言&#xff0c;又是一种程序设计语言。作为命令…

红帽集群RHCS

1、简介&#xff1a;RHCS是RedHatClusterSuite的缩写&#xff0c;也就是红帽子集群套件&#xff0c;RHCS是一个能够提供高可用性、高可靠性、负载均衡、存储共享且经济廉价的集群工具集合&#xff0c;它将集群系统中三大集群架构融合一体&#xff0c;可以给web应用、数据库应用…

Java 基础——数组解析

数组对于每一门编辑应语言来说都是重要的数据结构之一&#xff0c;当然不同语言对数组的实现及处理也不尽相同。 Java语言中提供的数组是用来存储固定大小的同类型元素。 可以声明一个数组变量&#xff0c;如numbers[100]来代替直接声明100个独立变量number0&#xff0c;number…

《在你身边,为你设计》-哪位知道下载、在线阅读地址啊?

《在你身边&#xff0c;为你设计》-前端UI必读出自腾讯CDChttp://cdc.tencent.com/?p6761今天听同事说这本书写的非常好&#xff0c;改变了他关于前端UI的许多看法&#xff0c;可谓&#xff1a;醍醐灌顶。可惜我网上找了下都需要Money买&#xff0c;哪位有在线阅读、PDF下载地…

一、OpenStack架构

DashBoardHorizon提供WEB界面ComputerNova计算也就是虚拟机NetworkingNeutron提供给nova网络支持Object StorageSwift提供对象存储Block StorageCinder提供云硬盘给nova&#xff0c;同时备份到SwiftIdentity SserviceKeystone提供所有组件的认证Image ServiceGlance提供给nova镜…

Java 三大特性 —— 多态

Java中多态性的实现 一、什么是多态 1.面向对象的三大特性&#xff1a;封装、继承、多态。从一定角度来看&#xff0c;封装和继承几乎都是为多态而准备的。这是我们最后一个概念&#xff0c;也是最重要的知识点。 2.多态的定义&#xff1a;指允许不同类的对象对同一消息做出响应…

linux /proc/cpuinfo文件分析

为什么80%的码农都做不了架构师&#xff1f;>>> 基于不同指令集&#xff08;ISA&#xff09;的CPU产生的/proc/cpuinfo文件不一样&#xff0c;基于X86指令集CPU的/proc/cpuinfo文件包含如下内容&#xff1a; processor  &#xff1a; 0vendor_id  &#xff1a;…

Java 高级类(下) —— 内部类和匿名类

Java内部类&#xff08;Inner Class&#xff09;&#xff0c;类似的概念在C里也有&#xff0c;那就是嵌套类&#xff08;Nested Class&#xff09;&#xff0c;乍看上去内部类似乎有些多余&#xff0c;它的用处对于初学者来说可能并不是那么显著&#xff0c;但是随着对它的深入…

Java 高级类(上) —— 抽象类和接口

在面向对象的概念中&#xff0c;我们知道所有的对象都是通过类来描绘的&#xff0c;但是并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 抽象类往往用来表征我们在对问题领域进行分析、 设…