69.ARM裸机开发--中断(补充)

一. ARM中断

硬件层面:

中断也属于异常的一种,我们平时开发常用的就是定时器中断,按键外部中断等。

初始化过程就是要过五关斩六将,获得许可之后才能到达最后的cpu核。

 

二.中断过程

软件层面

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号会写入一个特定的寄存器。

中断处理程序可以读取该寄存器来决定该调用哪个具体的中断处理函数。

 

五.异常向量表

 

异常向量表默认从0地址开始,我们要对地址进行改写,4412中通过CP15协处理器进行操作

协处理器指令

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寄存器中

                  @ set Vector Base Address 为0x40008000     

                  ldr      r0,=0x40008000

 

六.实现按键中断

makefile

all:
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o start.o start.S
	arm-none-linux-gnueabi-gcc -fno-builtin -nostdinc -c -o main.o main.c
	arm-none-linux-gnueabi-ld start.o main.o -Tmap.lds -o uart.elf
	arm-none-linux-gnueabi-objcopy -O binary  uart.elf uart.bin
	arm-none-linux-gnueabi-objdump -D uart.elf > uart.dis
clean:
	rm -rf *.bak start.o main.o uart.elf uart.bin uart.dis

链接脚本:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") //指定文件格式
OUTPUT_ARCH(arm)
ENTRY(_start) //连接之后的第一个地址是_start
SECTIONS
{
	. = 0x40008000;  /*指定链接的起始地址   */
	. = ALIGN(4);
	.text      :      //代码段开始
	{
		start.o(.text) //入口start.s
		*(.text)   //系统自动指定其他函数
	}
	. = ALIGN(4);
    .data : 		//	数据段开始
	{ *(.data) }
    . = ALIGN(4);
    .bss :
     { *(.bss) }
}

s'tart.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)
#define  ULCON2     (*(volatile unsigned int *)0x13820000) 
#define  UCON2      (*(volatile unsigned int *)0x13820004) 
#define  UBRDIV2    (*(volatile unsigned int *)0x13820028) 
#define  UFRACVAL2  (*(volatile unsigned int *)0x1382002C) 
#define  UTXH2      (*(volatile unsigned int *)0x13820020) 
#define  UTRSTAT2   (*(volatile unsigned int *)0x13820010) 

//----------------led
#define  GPL2CON    (*(volatile unsigned int *)0x11000100)
#define  GPL2DAT    (*(volatile unsigned int *)0x11000104) 


//---------------interrupt
#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)


void interrupt_init(void)
{
	//-----外: 配置管脚的工作模式
	GPX1CON = (GPX1CON & ~(0xF<<4))|(0xF<<4);  //配置 GPX1_1为中断模式
	
	EXT_INT41CON = (EXT_INT41CON & ~(0x7<<4))|(0x2<<4);  //设置GPX1_1的触发方式为 下降沿触发
	EXT_INT41_MASK = EXT_INT41_MASK & (~0x02);		//GPX1_1 中断使能
	
	//-----内: 功能块设置
	ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<25);	//EINT9 (GPX1_1)  GIC中断使能
	ICDIPTR14_CPU0 = 0x01010101;   //参考例子背景,用默认设置 
	ICDDCR = ICDDCR|1; //GIC 分发总使能
	ICCICR_CPU0 = 1;  // CPU0  中断使能
	ICCPMR_CPU0 = 0XFF;   //设置CPU0的优先级门槛为最低

	//KEY3
	//外
	GPX1CON = (GPX1CON & ~(0xF<<8))|(0xF<<8);  //配置 GPX1_2为中断模式
	EXT_INT41CON = (EXT_INT41CON & ~(0x7<<8))|(0x2<<8);  //设置GPX1_2的触发方式未 下降沿触发
	EXT_INT41_MASK = EXT_INT41_MASK & (~0x04);		//GPX1_2 中断使能

	//内
	ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<26);	//EINT9 (GPX1_2)  GIC中断使能
}


void uart_init(void)
{
  //-----外: 配置管脚的工作模式
  GPA1CON = 0x22;  //配置GPA1_1 GPA10 为uart串口模式
  
  //-----内: 功能块设置
  //1.  uart 通讯协议格式的设置
  ULCON2 = 0x03;  //设置协议格式(  无校验位  1个停止位 8个数据位)
  UCON2 = 0x05;   //设置串口发送接收模式为polling模式
  
  /*2.  设置uart 的速度为115200*/
  UBRDIV2 = 53;
  UFRACVAL2 = 4;
    
}

void led_init(void)
{
	GPL2CON = (GPX1CON & ~0x01)| 0x01; 
	GPL2DAT	= (GPL2DAT & ~0x01)| 0x01;
}


void putc(char c)
{
   while(1)
   {
      if(UTRSTAT2&0x02)  //检测发送是否为空
      {
         break;
      }
   }
   
   UTXH2 = c;  //发送字符
}


void do_irq(void )
{

  int irq_num;

   irq_num = ICCIAR_CPU0&0x3ff; 中断ID号

   switch(irq_num)
   {
   case 57:			
	    GPL2DAT	= (GPL2DAT & ~0x01)| 0x01;
		delay1s();
	    GPL2DAT	= (GPL2DAT & ~0x01)| 0x00;
		delay1s();
  	   EXT_INT41_PEND = EXT_INT41_PEND|(1<<1);  //清GPX1_1中断标志	   
  	   ICDICPR1_CPU0 = ICDICPR1_CPU0|(1<<25);    //清GIC GPX1_1中断标志
   	   break;
	case 58:
   	   putc('k');
  	   EXT_INT41_PEND = EXT_INT41_PEND|(1<<2);  //清GPX1_2中断标志	   
  	   ICDICPR1_CPU0 = ICDICPR1_CPU0|(1<<26);    //清GIC GPX1_2中断标志
   	   break;
   default:
   	   putc('e');
   	   break;
   }
   	ICCEOIR_CPU0 = (ICCEOIR_CPU0&0x3FF)|irq_num;    //结束中断	将处理完成的中断ID号写入该寄存器,则表示相应的中断处理完成
}

int main(void) 
{
	led_init();
    uart_init();
    interrupt_init();

	while(1);
	
	return 0;
}

loadb 40008000   在板子上程序加载到这个地址

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值