我是靠谱客的博主 无限含羞草,最近开发中收集的这篇文章主要介绍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内核,然后产生中断标志位,再执行之前讲到的中断实现(程序实现)。

中断 过程

  1. 中断初始化
    a. 管脚初始化
    b. 中断控制器初始化
  2. 中断向量表
    a.中断发生后,硬件自动跳转
    b. 现场保护
    c. 调用中断处理
  3. 中断处理
    a. 根据中断号做相应处理
    b. 清中断
    c. 现场恢复
    在这里插入图片描述

中断源

Exynos4412中断控制器包含160个中断控制源,
分三类分别是:

  1. 用于CPU之间通信的SGI
    (Software Generated Interrupt),
  2. 专用于特定CPU核的PPI
    (Private Peripheral Interrupt)
  3. 被多个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中断机制外部(按键)中断示例中断处理工程示例参考博客所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部