我是靠谱客的博主 无限含羞草,最近开发中收集的这篇文章主要介绍ARM体系结构及接口技术-04ARM中断机制ARM中断机制外部(按键)中断示例中断处理工程示例参考博客,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
文章目录
- ARM中断机制
- 中断硬件机制
- 中断 过程
- 中断源
- 中断控制器
- 外部(按键)中断示例
- Step0:原理图查看
- 外: 配置管脚的工作模式
- Step1.配置I/O口为中断模式(外部中断)
- Step2.配置中断为下降沿触发触发
- Step3:使能外部中断
- 内: 功能块设置
- Step4.1: 查GIC中断表,找出对应的中断端口号和ID号
- Step4.2: 设置GIC中断使能
- Step5:分发配置
- Step6:分发总使能
- Step7:CPU外部中断借口使能
- Step8:设置CPU的中断优先级门限值
- 中断处理
- 协处理器指令修改异常向量表起始地址
- 异常向量表
- 中断处理函数
- Step1:获取中断ID号
- Step2:清GPIO的中断标志
- Step3:清GCI中断标志
- Step4: 结束中断
- 中断处理函数
- 工程示例
- start.S
- main.c
- 参考博客
ARM中断机制
中断硬件机制
- ARM 有两级外部中断 FIQ,IRQ.
- 可是大多数的基于ARM 的系统有 >2个的中断源!
因此需要一个中断控制器(通常是地址映射的)来控制中断是怎样传递给ARM的。
在许多系统中,一些中断的优先级比其它中断的优先级高,他们要抢先任何正在处理的低优先级中断。
Note: 通常中断处理程序总是应该包含清除中断源的代码。
首先,外部中断信号需经过GPIO管脚进入CPU内部,然后再内部经使能–>分发–>分发使能–>cpu接口–>接口使能和优先级–>ARM内核 过五关 斩六将 终于到达ARM内核,然后产生中断标志位,再执行之前讲到的中断实现(程序实现)。
中断 过程
- 中断初始化
a. 管脚初始化
b. 中断控制器初始化 - 中断向量表
a.中断发生后,硬件自动跳转
b. 现场保护
c. 调用中断处理 - 中断处理
a. 根据中断号做相应处理
b. 清中断
c. 现场恢复
中断源
Exynos4412中断控制器包含160个中断控制源,
分三类分别是:
- 用于CPU之间通信的SGI
(Software Generated Interrupt), - 专用于特定CPU核的PPI
(Private Peripheral Interrupt) - 被多个CPU核共享的SPI
(Shared Peripheral Interrupt)
中断控制器
中断源分发给不同的CPU.
每个中断都有一个唯一对应的ID号,当中断发生时,该ID号会写入一个特定的寄存器。
中断处理程序可以读取该寄存器来决定该调用哪个具体的中断处理函数。
外部(按键)中断示例
Step0:原理图查看
按键K2,挂载在GPX1_1引脚上,对应XEINT9
按键K2,挂载在GPX1_2引脚上,对应XEINT10
外: 配置管脚的工作模式
Step1.配置I/O口为中断模式(外部中断)
GPX1CON = (GPX1CON & ~(0x0F<<4)) | (0x0F<<4);
Step2.配置中断为下降沿触发触发
EXT_INT41CON = (EXT_INT41CON & ~(0x7<<4)) | (0x2<<4);
Step3:使能外部中断
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);
内: 功能块设置
Step4.1: 查GIC中断表,找出对应的中断端口号和ID号
- XEINT9对应的中断端口号是25,ID号是57
Step4.2: 设置GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<25);
Step5:分发配置
-
根据样例选用默认设置
#define ICDIPTR14_CPU0 (*(volatile int *)0x10490838) ICDIPTR14_CPU0 = 0x01010101;
Step6:分发总使能
ICDDCR = ICDDCR|1;
Step7:CPU外部中断借口使能
ICCICR_CPU0 = 1;
Step8:设置CPU的中断优先级门限值
ICCPMR_CPU0 = 0XFF;
中断处理
协处理器指令修改异常向量表起始地址
-
CPU规定的异常向量表的地址是从0x00开始的,其中中断异常的地址是0x18
-
但是想开发版中下载程序的时候我们会制定一个起始地址,这样异常向量表的起始地址就不是0x00了
-
所以,需要重新制定模拟的异常向量表的起始地址
-
协处理器指令
MRC Pn,op1,Rd,CRn,CRm,op2 //mrc p15,0,r0,c1,c0,0 读入cp15的c1寄存器的内容到r0中 MCR Pn,op1,Rd,CRn,CRm,op2 //mcr p15,0,r0,c1,c0,0 写r0内容到cp15的c1寄存器中 通过协处理器设置异常向量表的起始地址为0x40008000 @ set Vector Base Address 为0x40008000 ldr r0,=0x40008000 mcr p15,0,r0,c12,c0,0
异常向量表
_start: b start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word irq_handler
_fiq: .word _fiq
irq_handler:
sub lr,lr,#4
stmfd sp!,{r0-r12,lr} @保护现场
bl do_irq
irq_handler_end:
ldmfd sp!,{r0-r12,pc}^ @恢复现场
- 软中断SWI中,lr既是返回地址,中断IRQ中lr-4才是返回地址
中断处理函数
Step1:获取中断ID号
int irq_num;
irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号
Step2:清GPIO的中断标志
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
Step3:清GCI中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1的中断标志
Step4: 结束中断
ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断
中断处理函数
void do_irq(void )
{
int irq_num;
irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号
switch(irq_num)
{
//KEY2
case 57:
putc(DEVICE_UART_COM0,'K');
putc(DEVICE_UART_COM0,'2');
GPX2_7_H;
GPX1_0_H;
delay1s();
GPX2_7_L;
GPX1_0_L;
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1ç„中断标志
break;
//KEY3
case 58:
putc(DEVICE_UART_COM0,'K');
putc(DEVICE_UART_COM0,'3');
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); //清GPX1_2中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26); //清GCI中GPX1_2中断标志
break;
default:
break;
}
ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断
}
工程示例
start.S
.global delay1s
.text
.global _start
_start:
b reset @0x00
ldr pc,_undefined_instruction @0x04
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq @0x18
ldr pc,_fiq
_undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
_not_used: .word _not_used
_irq: .word irq_handler
_fiq: .word _fiq
irq_handler:
sub lr,lr,#4
stmfd sp!,{r0-r12,lr} @进栈保存现场
bl do_irq
irq_handler_end:
ldmfd sp!,{r0-r12,pc}^ @出栈恢复现场
reset:
ldr r0,=0x40008000 @设置异常向量表的启始地址为 0x40008000
mcr p15,0,r0,c12,c0,0 @ Vector Base Address Register
init_stack:
ldr r0,stacktop /*get stack top pointer*/
/********svc mode stack********/
mov sp,r0
sub r0,#128*4 /*512 byte for irq mode of stack*/
/****irq mode stack**/
msr cpsr,#0xd2
mov sp,r0
sub r0,#128*4 /*512 byte for irq mode of stack*/
/***fiq mode stack***/
msr cpsr,#0xd1
mov sp,r0
sub r0,#0
/***abort mode stack***/
msr cpsr,#0xd7
mov sp,r0
sub r0,#0
/***undefine mode stack***/
msr cpsr,#0xdb
mov sp,r0
sub r0,#0
/*** sys mode and usr mode stack ***/
msr cpsr,#0x10
mov sp,r0 /*1024 byte for user mode of stack*/
b main
delay1s:
ldr r4,=0xfffffff
delay1s_loop:
sub r4,r4,#1
cmp r4,#0
bne delay1s_loop
mov pc,lr
.align 4
/**** swi_interrupt handler ****/
stacktop: .word stack+4*512
.data
stack:
.space 4*512
.end
main.c
/*
功能:实现K3 按下后能触发中断输出字符
实现按k2 ,led灯闪烁
*/
//----------------uart
#define GPA1CON (*(volatile unsigned int *)0x11400020) //volatile 确保本条指令不会因编译器的优化而省略
#define ULCON2 (*(volatile unsigned int *)0x13820000) //串口2线控:数据位,停止位,奇偶校验位
#define UCON2 (*(volatile unsigned int *)0x13820004) //串口2读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV2 (*(volatile unsigned int *)0x13820028) //串口2波特率设置
#define UFRACVAL2 (*(volatile unsigned int *)0x1382002c) //串口2波特率设置
#define UTXH2 (*(volatile unsigned int *)0x13820020) //串口2发送缓存器
#define URXH2 (*(volatile unsigned int *)0x13820024) //串口2接受缓存器
#define UTRSTAT2 (*(volatile unsigned int *)0x13820010) //串口2状态寄存器
#define GPA0CON (*(volatile unsigned int *)0x11400000) //volatile 确保本条指令不会因编译器的优化而省略
#define ULCON0 (*(volatile unsigned int *)0x13800000) //串口0线控:数据位,停止位,奇偶校验位
#define UCON0 (*(volatile unsigned int *)0x13800004) //串口0读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV0 (*(volatile unsigned int *)0x13800028) //串口0波特率设置
#define UFRACVAL0 (*(volatile unsigned int *)0x1380002c) //串口0波特率设置
#define UTXH0 (*(volatile unsigned int *)0x13800020) //串口0发送缓存器
#define URXH0 (*(volatile unsigned int *)0x13800024) //串口0接受缓存器
#define UTRSTAT0 (*(volatile unsigned int *)0x13800010) //串口0状态寄存器
#define ULCON3 (*(volatile unsigned int *)0x13830000) //串口3线控:数据位,停止位,奇偶校验位
#define UCON3 (*(volatile unsigned int *)0x13830004) //串口3读取控制:串口读的方式(如:轮询/中断等),写的方式
#define UBRDIV3 (*(volatile unsigned int *)0x13830028) //串口3波特率设置
#define UFRACVAL3 (*(volatile unsigned int *)0x1383002c) //串口3波特率设置
#define UTXH3 (*(volatile unsigned int *)0x13830020) //串口3发送缓存器
#define URXH3 (*(volatile unsigned int *)0x13830024) //串口3接受缓存器
#define UTRSTAT3 (*(volatile unsigned int *)0x13830010) //串口3状态寄存器
//---------------interrupt_init
#define GPX1CON (*(volatile unsigned int *)0x11000c20)
#define EXT_INT41CON (*(volatile int *)0x11000E04)
#define EXT_INT41_MASK (*(volatile int *)0x11000F04)
#define ICDISER1_CPU0 (*(volatile int *)0x10490104)
#define ICDIPTR14_CPU0 (*(volatile int *)0x10490838)
#define ICDDCR (*(volatile int *)0x10490000)
#define ICCICR_CPU0 (*(volatile int *)0x10480000)
#define ICCPMR_CPU0 (*(volatile int *)0x10480004)
#define EXT_INT41_PEND (*(volatile int *)0x11000f44)
#define ICCIAR_CPU0 (*(volatile int *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile int *)0x10480010)
#define ICDICPR1_CPU0 (*(volatile int *)0x10490284)
//-----------------led
#define GPX2CON (*(volatile unsigned int *)0x11000C40) //
#define GPF3CON (*(volatile unsigned int *)0x11000C20) //
#define GPX1DATA (*(volatile unsigned int *)0x11000C24) //
#define GPX2DATA (*(volatile unsigned int *)0x11000C44) //
#define GPF3DATA (*(volatile unsigned int *)0x114001E4) //
#define GPX2_7_H (GPX2DATA |= (0X01 << 7)) //LED2
#define GPX2_7_L (GPX2DATA &= ~(0X01 << 7))
#define GPX1_0_H (GPX1DATA |= (0X01 << 0)) //LED3
#define GPX1_0_L (GPX1DATA &= ~(0X01 << 0))
#define GPF3_4_H (GPF3DATA |= (0X01 << 4)) //LED4
#define GPF3_4_L (GPF3DATA &= ~(0X01 << 4)
#define GPF3_5_H (GPF3DATA |= (0X01 << 5)) //LED5
#define GPF3_5_L (GPF3DATA &= ~(0X01 << 5))
typedef enum
{
DEVICE_UART_COM0 = 0,
DEVICE_UART_COM1 = 1,
DEVICE_UART_COM2 = 2,
DEVICE_UART_COM3 = 3,
DEVICE_BUTTON_KEY2,
DEVICE_BUTTON_KEY3,
MAX_DEVICE
}DEVICE_LIST_E;
/*
设置波特率为115200
//For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz,UBRDIVn and UFRACVALn are:
//DIV_VAL = (SCLK_UART/(bps * 16)) - 1
//DIV_VAL = (100000000/(115200 * 16)) – 1
//= 54.253 – 1
//= 53.253
//UBRDIVn = 53 (integer part of DIV_VAL)
//UFRACVALn/16 = 0.253
//Therefore, UFRACVALn = 4
*/
void USART_Init(DEVICE_LIST_E Device_type)
{
if(Device_type == DEVICE_UART_COM0)
{
//1.配置GPA0CON寄存器中的UART0
//GPA0_0 UART_0_RXD
//GPA0_1 UART_0_TXD
GPA0CON &= 0xffffff00;
GPA0CON |= 0x00000022;
//2.配置ULCON0寄存器
//串口0 8位数据位,1位停止位,无奇偶校验
ULCON0 &= 0Xffffffc0;
ULCON0 |= 0x00000003;
//3.配置UCON0寄存器
//通过轮询(polling)的模式读取串口数据 通过轮询(polling)的模式往串口写入数据数据
UCON0 &= 0xfffffff0;
UCON0 |= 0x00000005;
//4.设置波特率为115200
UBRDIV0 = 53;
UFRACVAL0 = 4;
}
if(Device_type == DEVICE_UART_COM2)
{
GPA1CON &= 0xffffff00;
GPA1CON |= 0x00000022;
ULCON2 &= 0Xffffffc0;
ULCON2 |= 0x00000003;
UCON2 &= 0xfffffff0;
UCON2 |= 0x00000005;
UBRDIV2 = 53;
UFRACVAL2 = 4;
}
if(Device_type == DEVICE_UART_COM3)
{
GPA1CON &= 0xff00ffff;
GPA1CON |= 0x00220000;
ULCON3 &= 0Xffffffc0;
ULCON3 |= 0x00000003;
UCON3 &= 0xfffffff0;
UCON3 |= 0x00000005;
UBRDIV3 = 53;
UFRACVAL3 = 4;
}
}
void putc(DEVICE_LIST_E Device_type, char c)
{
switch(Device_type)
{
case DEVICE_UART_COM0:
while(1)
{
if(UTRSTAT0 && 0X02)
break;
}
UTXH0 = c;
break;
case DEVICE_UART_COM1:
break;
case DEVICE_UART_COM2:
while(1)
{
if(UTRSTAT2 && 0X02)
break;
}
UTXH2 = c;
break;
case DEVICE_UART_COM3:
while(1)
{
if(UTRSTAT3 && 0X02)
break;
}
break;
default:
break;
}
}
char getc(void)
{
while(1)
{
if(UTRSTAT0 && 0X01) break;
}
return URXH0;
}
void interrupt_init(DEVICE_LIST_E Device_type)
{
//KEY2的初始化设置
if(Device_type == DEVICE_BUTTON_KEY2)
{
//----- key2 GPX1_1 EINT9 SPIPORT:25 INTID:57
//-----外: 配置管脚的工作模式
//1-配置 GPX1_1为中断模式
GPX1CON = (GPX1CON & ~(0x0F<<4)) | (0x0F<<4);
//2-设置GPX1_1的触发方式为 下降沿触发
EXT_INT41CON = (EXT_INT41CON & ~(0x7<<4)) | (0x2<<4);
//3-GPX1_1 中断使能
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1);
//-----内: 功能块设置
//4-EINT9 (GPX1_1) GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<25);
//5-参考例子背景,用默认设置
ICDIPTR14_CPU0 = 0x01010101;
//6-GIC 分发总使能
ICDDCR = ICDDCR|1;
//7-CPU0 中断使能
ICCICR_CPU0 = 1;
//8-设置CPU0的优先级门槛为最低
ICCPMR_CPU0 = 0XFF;
}
//KEY3的初始化设置
if(Device_type == DEVICE_BUTTON_KEY3)
{
//---- key3 GPX1_2 EINT10 SPIPORT:26 INTID:58
-----外: 配置管脚的工作模式
//1-配置 GPX1_2为中断模式
GPX1CON = (GPX1CON & ~(0x0F<<8)) | (0x0F<<8);
//2-设置GPX1_2的触发方式为 下降沿触发
EXT_INT41CON = (EXT_INT41CON & ~(0x7<<8)) | (0x2<<8);
//3-GPX1_2 中断使能
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 2)) | (0X00 << 2);
//-----内: 功能块设置
//4-EINT10 (GPX1_2) GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<26);
//5-参考例子背景,用默认设置
ICDIPTR14_CPU0 = 0x01010101;
//6-GIC 分发总使能
ICDDCR = ICDDCR|1;
//7-CPU0 中断使能
ICCICR_CPU0 = 1;
//8-设置CPU0的优先级门槛为最低
ICCPMR_CPU0 = 0XFF;
}
}
void do_irq(void )
{
int irq_num;
irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号
switch(irq_num)
{
//KEY2
case 57:
putc(DEVICE_UART_COM0,'K');
putc(DEVICE_UART_COM0,'2');
GPX2_7_H;
GPX1_0_H;
delay1s();
GPX2_7_L;
GPX1_0_L;
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1ç„中断标志
break;
//KEY3
case 58:
putc(DEVICE_UART_COM0,'K');
putc(DEVICE_UART_COM0,'3');
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); //清GPX1_2中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26); //清GCI中GPX1_2中断标志
break;
default:
break;
}
ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断
}
void led_init(void)
{
GPX2CON = (GPX2CON & ~(0X0F << 28)) | (0X01 << 28); //设置LED2灯的配置寄存器 GPX2CON7为输出状态
GPX1CON = (GPX1CON & ~(0X0F << 0)) | (0X01 << 0); //设置LED3灯的配置寄存器 GPX1CON0为输出状态
GPF3CON = (GPF3CON & ~(0X0F << 16)) | (0X01 << 16); //设置LED4灯的配置寄存器 GPF3CON4为输出状态
GPF3CON = (GPF3CON & ~(0X0F << 20)) | (0X01 << 20); //设置LED5灯的配置寄存器 GPF3CON5为输出状态
}
int main(void)
{
USART_Init(DEVICE_UART_COM0);
led_init();
interrupt_init(DEVICE_BUTTON_KEY2);
interrupt_init(DEVICE_BUTTON_KEY3);
char c;
while(1)
{
#if 0
c = getc();
delay1s();
putc(vDevice,c);
delay1s();
#endif
}
return 0;
}
参考博客
https://blog.csdn.net/m0_37542524/article/details/85808651#21_53
最后
以上就是无限含羞草为你收集整理的ARM体系结构及接口技术-04ARM中断机制ARM中断机制外部(按键)中断示例中断处理工程示例参考博客的全部内容,希望文章能够帮你解决ARM体系结构及接口技术-04ARM中断机制ARM中断机制外部(按键)中断示例中断处理工程示例参考博客所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复