目录

1.中断处理流程

2 start.s

3 interrupt.c

3.1中断初始化

3.2 中断处理函数


1.中断处理流程

首先我们要对中断进行初始化,中断初始化主要分为下面三块:

  • 设置中断源,让它能够发出中断信号,
  • 设置中断控制器,让它能够发出中断信号给CPU,
  • 设置CPU,CPSR有I位,它是总开关。

然后中断的处理过程和之前说的异常处理过程类似,不一样的就是处理完成之后要清中断。

2 start.s

首先我们CPSR寄存器的bit7清零,这是中断的总开关,只有这一位设置为0才能相应中断。

mrs r0, cpsr         /* 读出cpsr */
bic r0, r0, #(1<<7)  /* 清除I位, 使能中断 */
msr cpsr, r0

然后当发生中断时,程序会跳转到0x18的地方去执行程序,因此我们增加如下代码

 ldr pc, irq_addr /* vector 0x18 : irq */

然后我们增加中断处理流程的代码,整体流程也是保存现场,处理中断,恢复现场。


.text
.global _start_start:b reset          /* vector 0 : reset */ldr pc, und_addr /* vector 4 : und */ldr pc, swi_addr /* vector 8 : swi */b halt             /* vector 0x0c : prefetch aboot */b halt            /* vector 0x10 : data abort */b halt            /* vector 0x14 : reserved */ldr pc, irq_addr /* vector 0x18 : irq */b halt          /* vector 0x1c : fiq */und_addr:.word do_undswi_addr:.word do_swiirq_addr:.word do_irqdo_und:/* 执行到这里之前:* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_und保存有被中断模式的CPSR* 3. CPSR中的M4-M0被设置为11011, 进入到und模式* 4. 跳到0x4的地方执行程序 *//* sp_und未设置, 先设置它 */ldr sp, =0x34000000/* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 *//* lr是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}  /* 保存现场 *//* 处理und异常 */mrs r0, cpsrldr r1, =und_stringbl printException/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */und_string:.string "undefined instruction exception".align 4do_swi:/* 执行到这里之前:* 1. lr_svc保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_svc保存有被中断模式的CPSR* 3. CPSR中的M4-M0被设置为10011, 进入到svc模式* 4. 跳到0x08的地方执行程序 *//* sp_svc未设置, 先设置它 */ldr sp, =0x33e00000/* 保存现场 *//* 在swi异常处理函数中有可能会修改r0-r12, 所以先保存 *//* lr是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}  mov r4, lr/* 处理swi异常 */mrs r0, cpsrldr r1, =swi_stringbl printExceptionsub r0, r4, #4bl printSWIVal/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */swi_string:.string "swi exception".align 4do_irq:/* 执行到这里之前:* 1. lr_irq保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_irq保存有被中断模式的CPSR* 3. CPSR中的M4-M0被设置为10010, 进入到irq模式* 4. 跳到0x18的地方执行程序 *//* sp_irq未设置, 先设置它 */ldr sp, =0x33d00000/* 保存现场 *//* 在irq异常处理函数中有可能会修改r0-r12, 所以先保存 *//* lr-4是异常处理完后的返回地址, 也要保存 */sub lr, lr, #4    //这里减掉4是规定,芯片手册的中断向量的表格里面就是这样写的。stmdb sp!, {r0-r12, lr}  /* 处理irq异常 */bl handle_irq_c/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^会把spsr_irq的值恢复到cpsr里 */reset:/* 关闭看门狗 */ldr r0, =0x53000000ldr r1, =0str r1, [r0]/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m *//* LOCKTIME(0x4C000000) = 0xFFFFFFFF */ldr r0, =0x4C000000ldr r1, =0xFFFFFFFFstr r1, [r0]/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */ldr r0, =0x4C000014ldr r1, =0x5str r1, [r0]/* 设置CPU工作于异步模式 */mrc p15,0,r0,c1,c0,0orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iAmcr p15,0,r0,c1,c0,0/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) *  m = MDIV+8 = 92+8=100*  p = PDIV+2 = 1+2 = 3*  s = SDIV = 1*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M*/ldr r0, =0x4C000004ldr r1, =(92<<12)|(1<<4)|(1<<0)str r1, [r0]/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定* 然后CPU工作于新的频率FCLK*//* 设置内存: sp 栈 *//* 分辨是nor/nand启动* 写0到0地址, 再读出来* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动* 否则就是nor启动*/mov r1, #0ldr r0, [r1] /* 读出原来的值备份 */str r1, [r1] /* 0->[0] */ ldr r2, [r1] /* r2=[0] */cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */ldr sp, =0x40000000+4096 /* 先假设是nor启动 */moveq sp, #4096  /* nand启动 */streq r0, [r1]   /* 恢复原来的值 */bl sdram_init//bl sdram_init2  /* 用到有初始值的数组, 不是位置无关码 *//* 重定位text, rodata, data段整个程序 */bl copy2sdram/* 清除BSS段 */bl clean_bss/* 复位之后, cpu处于svc模式* 现在, 切换到usr模式*/mrs r0, cpsr         /* 读出cpsr */bic r0, r0, #0xf     /* 修改M4-M0为0b10000, 进入usr模式 */bic r0, r0, #(1<<7)  /* 清除I位, 使能中断 */msr cpsr, r0/* 设置 sp_usr */ldr sp, =0x33f00000ldr pc, =sdram
sdram:bl uart0_initbl print1/* 故意加入一条未定义指令 */
und_code:.word 0xdeadc0de  /* 未定义指令 */bl print2swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 *///bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */ldr pc, =main  /* 绝对跳转, 跳到SDRAM */halt:b halt

3 interrupt.c

3.1中断初始化

我们在这里面完成初始化中断控制器和初始化按键中断的工作,

我们从上面的原理图可以看到四个按键对应着外部中断0 2 11 19,我们把他们设置成中断引脚,

例如我们需要把GPF0设置为中断引脚, 然后我们看一下GPFCON寄存器,

 我们首先把按键设置成中断引脚,

/* 配置GPIO为中断引脚 */
GPFCON &= ~((3<<0) | (3<<4));
GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */GPGCON &= ~((3<<6) | (3<<11));
GPGCON |= ((2<<6) | (2<<11));   /* S4,S5被配置为中断引脚 */

然后将中断设置为双边沿触发,按下松开都会触发中断。

/* 设置中断触发方式: 双边沿触发 */
EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */
EXTINT1 |= (7<<12);             /* S4 */
EXTINT2 |= (7<<12);             /* S5 */

然后设置外部中断mask,使能外部中断,外部中断0和1不需要设置,因为寄存器中是reserved。

/* 设置EINTMASK使能eint11,19 */
EINTMASK &= ~((1<<11) | (1<<19));

接下来我们需要设置中断控制器,我们看一下interrupt controller这一章。

里面的优先级priority我们先不用管,MODE是指我们可以把某个中断设置为快中断还是IRQ,这个MODE我们也不管,里面的INTPND是等待处理我们可以读这个寄存器判断是哪一个中断产生了,然后上图中的最前面还有个分支,这里的意思是有些中断需要先设置subsrcpnd和submask然后才能到SRCPND,而有些中断可以直接到SRCPND,我们的外部中断不需要经过subsrcpnd和submask可以直接到SUBMASH,所以我们只需要设置SRCPND,MASK和INTPND这三个。

其中SRCPND用来显示哪个中断产生了,执行完之后需要清除SRCPND,

INTMSK用来屏蔽中断, 如果某一位设置为1,那么即便中断产生了也不会发给cpu。

前面产生了多个中断,然后经过Priority之后是哪个优先级最高的中断呢,通过读INTPND就可以知道当前正在处理的唯一的中断是哪一个。

从上面我们可以看到,设置中断控制器其实只需要设置INTMSK即可,另外两个寄存器是处理中断时要用的。

/* SRCPND 用来显示哪个中断产生了, 需要清除对应位* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTMSK 用来屏蔽中断, 1-masked* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTOFFSET : 用来显示INTPND中哪一位被设置为1*//* 初始化中断控制器 */
void interrupt_init(void)
{INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
}

3.2 中断处理函数

在中断处理函数里面,首先需要分辨中断源,然后调用对应的处理函数。最后清中断。

#include "s3c2440_soc.h"/* SRCPND 用来显示哪个中断产生了, 需要清除对应位* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTMSK 用来屏蔽中断, 1-masked* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTPND 用来显示当前优先级最高的、正在发生的中断, 需要清除对应位* bit0-eint0* bit2-eint2* bit5-eint8_23*//* INTOFFSET : 用来显示INTPND中哪一位被设置为1*//* 初始化中断控制器 */
void interrupt_init(void)
{INTMSK &= ~((1<<0) | (1<<2) | (1<<5));
}/* 初始化按键, 设为中断源 */
void key_eint_init(void)
{/* 配置GPIO为中断引脚 */GPFCON &= ~((3<<0) | (3<<4));GPFCON |= ((2<<0) | (2<<4));   /* S2,S3被配置为中断引脚 */GPGCON &= ~((3<<6) | (3<<22));GPGCON |= ((2<<6) | (2<<22));   /* S4,S5被配置为中断引脚 *//* 设置中断触发方式: 双边沿触发 */EXTINT0 |= (7<<0) | (7<<8);     /* S2,S3 */EXTINT1 |= (7<<12);             /* S4 */EXTINT2 |= (7<<12);             /* S5 *//* 设置EINTMASK使能eint11,19 */EINTMASK &= ~((1<<11) | (1<<19));
}/* 读EINTPEND分辨率哪个EINT产生(eint4~23)* 清除中断时, 写EINTPEND的相应位*/void key_eint_irq(int irq)
{unsigned int val = EINTPEND;unsigned int val1 = GPFDAT;unsigned int val2 = GPGDAT;if (irq == 0) /* eint0 : s2 控制 D12 */{if (val1 & (1<<0)) /* s2 --> gpf6 */{/* 松开 */GPFDAT |= (1<<6);}else{/* 按下 */GPFDAT &= ~(1<<6);}}else if (irq == 2) /* eint2 : s3 控制 D11 */{if (val1 & (1<<2)) /* s3 --> gpf5 */{/* 松开 */GPFDAT |= (1<<5);}else{/* 按下 */GPFDAT &= ~(1<<5);}}else if (irq == 5) /* eint8_23, eint11--s4 控制 D10, eint19---s5 控制所有LED */{if (val & (1<<11)) /* eint11 */{if (val2 & (1<<3)) /* s4 --> gpf4 */{/* 松开 */GPFDAT |= (1<<4);}else{/* 按下 */GPFDAT &= ~(1<<4);}}else if (val & (1<<19)) /* eint19 */{if (val2 & (1<<11)){/* 松开 *//* 熄灭所有LED */GPFDAT |= ((1<<4) | (1<<5) | (1<<6));}else{/* 按下: 点亮所有LED */GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));}}}EINTPEND = val;
}void handle_irq_c(void)
{/* 分辨中断源 */int bit = INTOFFSET;/* 调用对应的处理函数 */if (bit == 0 || bit == 2 || bit == 5)  /* eint0,2,eint8_23 */{key_eint_irq(bit); /* 处理中断, 清中断源EINTPEND */}/* 清中断 : 从源头开始清 */SRCPND = (1<<bit);INTPND = (1<<bit);
}

S3C2440裸机------异常与中断__按键中断程序示例相关推荐

  1. stm32l4 外部中断按键会卡死_【stm32f407】外部中断实现按键中断方式

    一.外部中断 STM32F4的每个IO都可以作为外部中断的中断输入口,这点也是STM32F4的强大之处.STM32F407的中断控制器支持22个外部中断/事件请求.每个中断设有状态位,每个中断/事件都 ...

  2. S3C2440裸机------异常与中断__swi异常模式程序示例

    目录 1.start.S 2.uart.c  5 种异常模式对应着 7 种异常源:   异常工作模式      异常源 FIR               FIR IRQ              I ...

  3. 龙芯OpenHarmony课程 【4】 按键中断

    1 按键中断线程 按键中断相关代码位于device\loongson\ls1c300b_hrst\test\sample_key_irq.c文件中. 首先create_key_irq_task 创建一 ...

  4. linux驱动开发5 按键中断实验(定时器和中断)

    led:IO的输出 :key:IO的输入 法一:直接读写IO 使用while(1)无限读取,但CPU占用达到了99.6%,所以不行 #include <linux/types.h>#inc ...

  5. 从ARM裸机看驱动之按键中断方式控制LED(一)

    硬件环境:Samsung Cortex-A9 Exynos4412 BSP + JTAG ARM 仿真器 软件环境:Eclipse ================================== ...

  6. Keil5 平台 S3C2440裸机程序开发-----中断系统/UART

    目录 前言 一.启动文件 二.代码 main.c uart.c uart.h led.c led.h S3C2440.h 三.编译,烧录,打开串口助手,接收到数据. 前言 本博文介绍mini2440开 ...

  7. S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)

    在调试CAN总线的时候,遇到了操作系统的中断,为了彻底的弄清楚中断是怎么回事?我先从底层的中断开始研究,在这里我们只讨论外部中断,下面就结合S3C2440TEST测试程序来分析一下中断是怎么执行的:我 ...

  8. 从ARM裸机看驱动之按键中断方式控制LED(二)

    硬件环境:Samsung Cortex-A9 Exynos4412 BSP 软件环境:Linux3.14 =============================================== ...

  9. S3C2440之按键中断

    文章目录 前言 一.中断过程 二.关键代码 前言 本文基于S3C2440开发板所写的按键中断 一.中断过程 1.初始化.①设置中断,让它能够发出中断信号 ②设置中断控制器,让它能发出中断给CPU ③设 ...

  10. S5P4418裸机开发(十二):IRQ (按键中断) 串口中断

    S5P4418 64个中断源,按键的GPIO口是GPIOB28-30,中断号为54: Interrupt Controller相关寄存器 寄存器 功能 VICIRQSTATUS R,相关位为1表示该I ...

最新文章

  1. 数据库“新解”,看这里,get!
  2. IPython和Jupyter关系及区别
  3. Atitit qzone qq空间博客自动点赞与评论工具的设计与实现
  4. “社区之星”成长故事征集
  5. C# Note34: 异常机制相关小点
  6. 没有PARAMETER ID,想 call TRANSACTION
  7. tkinter menu
  8. Visual C++ 的代码折叠
  9. tyvj 1391 走廊泼水节【最小生成树】By cellur925
  10. Debian Linux下如何以root账号登录桌面
  11. 淘宝开源的代码质量检测工具,太强大了!!
  12. 多媒体前端技术入门指南
  13. 静态代理和动态代理区别(是否有实现类)
  14. word中的英文字体选择
  15. html勾选标签,html怎么勾选框
  16. POP3,全名为“Post Office Protocol - Version 3”,即“邮局协议版本3”
  17. Echarts柱状图上加图标
  18. 体验ANT DESIGN PRO V5--项目创建并安装umi气泡工作台
  19. Linux中超级用户root的密码破解与防止破解方法
  20. Prim算法伪+代码讲解

热门文章

  1. 如何实现阿里云短信接口使用短信业务
  2. Kvaser、C++、Qt编写监控界面(一)
  3. linux基础ppt下载,《Linux基础》PPT课件.ppt
  4. 如何在Google地图上找到经度和纬度
  5. python svm参数_python SVM 案例,sklearn.svm.SVC 参数说明
  6. android制作镜像,android镜像制作方法
  7. linux xps文件,Master PDF:PDF和XPS文件编辑神器
  8. xps15u盘装linux,戴尔XPS 15 9575笔记本安装win10系统的操作教程
  9. 计算机网络笔记 韩立刚(物理层+数据链路层+网络层+传输层已完成)
  10. Maven环境变量配置