ARM中断机制-作业

1. 实现K3 按下后能触发中断输出字符 实现按k2 ,led灯闪烁(请上传视频及源码)

1.1 .c代码

/* 	
	实现K3 按下后能触发中断输出字符 
	实现按k2 ,led灯闪烁 
	2020-11-9 by lsy
*/

//uart
#define GPA1CON 	0x11400020
#define ULCON2 		0x13820000
#define UCON2 		0x13820004
#define UBRDIV2 	0x13820028
#define UFRACVAL2  	0x1382002c
#define UTXH2 		0x13820020
#define UTRSTAT2 	0x13820010

#define rGPA1CON 	(*(volatile unsigned int*)GPA1CON)
#define rULCON2 	(*(volatile unsigned int*)ULCON2)
#define rUCON2 		(*(volatile unsigned int*)UCON2)
#define rUBRDIV2 	(*(volatile unsigned int*)UBRDIV2)
#define rUFBRACVAL2 (*(volatile unsigned int*)UFRACVAL2)
#define rUTXH2 		(*(volatile unsigned int*)UTXH2)
#define rUTRSTAT2 	(*(volatile unsigned int*)UTRSTAT2)


//interrupt
#define GPX1CON 		0x11000c20
#define EXT_INT41CON 	0x11000E04
#define EXT_INT41_MASK 	0x11000F04
#define ICDISER1_CPU0 	0x10490104
#define ICDDCR 			0x10490000
#define ICCPMR_CPU0 	0x10480004
#define ICCICR_CPU0 	0x10480000
#define ICCIAR_CPU0 	0x1048000C
#define EXT_INT41_PEND 	0X11000F44
#define ICDICPR1_CPU0 	0x10490284
#define ICCEOIR_CPU0 	0x10480010
#define ICDIPTR14_CPU0 	0x10490838

#define rGPX1CON 		(*(volatile unsigned int*)GPX1CON)
#define rEXT_INT41CON 	(*(volatile unsigned int*)EXT_INT41CON)
#define rEXT_INT41_MASK (*(volatile unsigned int*)EXT_INT41_MASK)
#define rICDISER1_CPU0 	(*(volatile unsigned int*)ICDISER1_CPU0)
#define rICDDCR 		(*(volatile unsigned int*)ICDDCR)
#define rICCPMR_CPU0 	(*(volatile unsigned int*)ICCPMR_CPU0)
#define rICCICR_CPU0 	(*(volatile unsigned int*)ICCICR_CPU0)
#define rICCIAR_CPU0 	(*(volatile unsigned int*)ICCIAR_CPU0)
#define rEXT_INT41_PEND (*(volatile unsigned int*)EXT_INT41_PEND)
#define rICDICPR1_CPU0 	(*(volatile unsigned int*)ICDICPR1_CPU0)
#define rICCEOIR_CPU0 	(*(volatile unsigned int*)ICCEOIR_CPU0)
#define rICDIPTR14_CPU0 (*(volatile unsigned int*)ICDIPTR14_CPU0)

//LED
#define GPX2CON 	0x11000C40
#define GPX2DAT 	0x11000C44

#define rGPX2CON 	(*(volatile unsigned int*)GPX2CON)
#define rGPX2DAT 	(*(volatile unsigned int*)GPX2DAT)

void uart_putc(char c);
void do_irq(void);
void do_led(void);

int main(int argc, const char *argv[])
{
	//KEY3
	/* 设置GPA1控制器为UART模式 */
	rGPA1CON &= ~(0xff<<0);   	//把寄存器的bit0~7全部清零
	rGPA1CON |= 0X22<<0; 			//Rx,Tx
	/* 设置串口协议 */
	rULCON2 = 0x03; 			//0校验位 ,8数据位,1停止位
	rUCON2 = 0x05; 				//轮询模式
	/*
	 * 设置波特率:
	 *UART时钟信号源的值为:
	 *100Mhz= 100 000khz = 100 000 000hz
	 *本实验波特率值位115200,DIV_VAL = 100000000/(115200*16) -1 = 54.25 -1 = 53.25
	 *UBRDIVn = 53
	 *UFRACVALn/16 = 0.25 ----> UFRACVALn = 4
	 */
	rUBRDIV2 = 53; 				
	rUFBRACVAL2 = 4;

	//INT K2
	/* 外设层次上,配置管脚工作模式 */
	rGPX1CON &= ~(0xf<<4); 	//设置GPX1_1为中断模式
	rGPX1CON |= (0xF<<4);
	rEXT_INT41CON &= ~(0X7<<4);		//设置GPX1_1设置为下降沿触发
	rEXT_INT41CON |= (0X02<<4); 	
	rEXT_INT41_MASK &= ~(1<<1); 	//设置GPX1_1外设引脚使能中断,可以让中断发生
	/* GIC(通用中断控制器)层次上 */
	rICDISER1_CPU0 = rICDISER1_CPU0 | (1<<25); 	//使能GPX1_1对应的中断
	rICDDCR |= (1<<0); 			//全局使能GIC 让所有中断可以通过GIC到达CPU
	rICCPMR_CPU0 |= (0xFF<<0); 	//设置中断优先级掩码级别为255
	/* CPU内核层次上 */
	rICCICR_CPU0 |= (1<<0); 		//CPU0的全局使能中断,所有中断都可以通过CPU接口到达内核
	
	rICDIPTR14_CPU0 = 0x01010101; //照抄,意义不明

	//INT K3 GPX1_2
	/* 外设层次上,配置管脚工作模式 */
	rGPX1CON &= ~(0xf<<8); 			//设置GPX1_2为中断模式
	rGPX1CON |= (0xF<<8);
	rEXT_INT41CON &= ~(0X7<<8);		//设置GPX1_2为下降沿触发
	rEXT_INT41CON |= (0X02<<8); 	
	rEXT_INT41_MASK &= ~(1<<2); 	//设置GPX1_2外设引脚使能中断,可以让中断发生
	/* GIC(通用中断控制器)层次上 */
	rICDISER1_CPU0 = rICDISER1_CPU0 | (1<<26); 	//使能GPX1_2对应的中断


	/* 发送状态判断 */	
	while(1)
	{
		uart_putc('c');
		delay1s();
	}

	return 0;
}


void uart_putc(char c)
{	
	while(!(rUTRSTAT2&0X02));
	rUTXH2 = c;
	return;
}

void do_irq(void) //参数中的void表示该函数不允许接受参数,理论上不写也可以,为了方便编译器通过,处于严谨考虑,还是要写上
{	
	int irq_num;
	int i;
	irq_num = rICCIAR_CPU0&0x3FF; 	//获取中断号
	switch(irq_num) 
	{
	case 57:
		do_led();
		rEXT_INT41_PEND |= 1<<1; 	//清GPX1_1中断位
		rICDICPR1_CPU0 |= 1<<25; 	//清GIC GPX1_1中断位
		break;
	case 58:
		uart_putc('k');
		uart_putc('3');
		rEXT_INT41_PEND |= 1<<2; 	//清GPX1_2中断位
		rICDICPR1_CPU0 |= 1<<26; 	//清GIC GPX1_2中断位
		break;
	default:
		uart_putc('x');
		break;
	}
	
	rICCEOIR_CPU0 &= (~0x3FF);
	rICCEOIR_CPU0 |= irq_num; 	//结束中断 将处理完成的中断ID号写入该寄存器 表示相应的中断处理完成
}

void do_led(void)
{
	rGPX2CON &= ~(0xF<<28);	//设置OUTPUT模式
	rGPX2CON |= (1<<28);
	rGPX2DAT |= (1<<7); 		//输出高电平
	delay1s();
	rGPX2DAT &= ~(1<<7);		//输出低电平
	delay1s();
}



1.2 .s代码

    .global  delay1s  @.C文件要调用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
		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_handle 
_fiq:					.word  _fiq


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          /* 初始化阶段要禁止IRQ,FIQ中断,I位=1,r位=1,mode位=10010 集合到一起就是d2 */
		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

irq_handle:
	sub lr,lr,#4
	stmfd sp!,{r0-r12,lr}
	bl do_irq
irq_handle_end:
	ldmfd sp!,{r0-r12,pc}^
	


delay1s:                            /* 延时1s函数 */
     ldr      r4,=0x1ffffff   
delay1s_loop:
     sub    r4,r4,#1
     cmp    r4,#0         
     bne    delay1s_loop
     mov   pc,lr	




	.align	4                   /* 4字节对齐 */

	/****  swi_interrupt handler  ****/


stacktop:    .word 		stack+4*512

.data

stack:	 
  .space  4*512
.end

1.3 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

1.4 map.lds代码

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x40008000;  /*ָ 内存起始地址  */
	. = ALIGN(4);
	.text      :
	{
		start.o(.text)
		*(.text)
	
	. = ALIGN(4);
    .data : 
	{ *(.data) }
    . = ALIGN(4);
    .bss :
     { *(.bss) }
}

1.5 开发板效果展示:

1.6 代码效果展示: