目录
需求
了解Cortex A9 按键中断(SPI)流程,实例:KEY2中断控制点亮LED2
实现检测按键k2,按键按下一次,实现LED灯闪一下。
实现流程
查看原理图:连接引脚和控制逻辑
- 连接引脚
按键k2连接在GPX1_1 引脚 - 控制逻辑
k2按下 —- k2闭合 —- GPX1_1 低电压
K2常态 —- k2打开 —- GPX1_1 高电压
查看相应芯片手册
循环检测
- 配置GPX1_1引脚功能
设置:引脚功能为输入,内部上下拉禁止 - 循环检测代码实现:
while(1)
{
if(!(GPX1.DAT & (0x1<<1))) // 返回为真,按键按下
{
msdelay(10);
if(!(GPX1.DAT & (0x1<<1))) //二次检测,去抖
{
GPX2.DAT |= 0x1 << 7; //Turn on LED2
mydelay_ms(500);
GPX2.DAT &= ~(0x1<<7); //Turn off LED2
mydelay_ms(500);
while(!(GPX1.DAT & (0x1<<1)));
}
}
中断方法实现按键检测
将K2按下时,GPX1_1引脚获得的电平,作为异常事件。使能异常处理,k2每按下一次,响应一次异常处理。SPI 传递流程如下示:
外设一级:GPIO控制器
- 将GPX1_1引脚的上拉和下拉禁止
GPX1PUD[3:2]=0B00; - 将GPX1_1引脚功能设置为中断功能
WAKEUP_INT1[1] — EXT_INT41[1]
GPX1CON[7:4]=0xf - EXT_INT41CON 配置触发电平
当前配置成下降沿触发:
EXT_INT41CON[6:4]=0X2 - EXT_INIT41_FLTCON0 配置中断引脚滤波
默认就是打开,不需要配置 - EXT_INT41_MASK 中断使能寄存器
使能INT41[1]:
EXT_INT41_MASK[1]=0B0 - EXT_INT41_PEND 中断状态寄存器
当GP1_1引脚收到中断信号,中断发生,中断状态寄存器 EXT_INT41_PEND 相应位会自动置1。
注:中断处理完成的时候,需手动清除相应状态为,置1清零
EXT_INT41_PEND[1]=0b1
- 将GPX1_1引脚的上拉和下拉禁止
中断控制器
- 找到外设中断名称与GIC中断控制器对应的名称
查看芯片手册(本例:Exynos_4412 – 9.2表)
WAKEUP_INT[1] — EXT_INT41[1] — INT[9] — SPI[25]/ID[57] - 使能cpu0的spi25/id57
ICDISER.ICDISER1 |= (0x1 << 25); //57/32 =1…25 取整数(那个寄存器) 和余数(哪位) - 全局使能cpu0中断处理
CPU0.ICCICR |= 0x1; - 优先级屏蔽寄存器,设置cpu0能处理所有的中断
CPU0.ICCPMR = 0xFF; - GIC使能
ICDDCR =1; - 设置SPI[25]/ID[57]由那个cpu处理,当前设置为cpu0的irq中断
ICDIPTR.ICDIPTR14 |= 0x01<<8; //SPI25 interrupts are sent to processor 0 //57/4 = 14..1 14号寄存器的
- 找到外设中断名称与GIC中断控制器对应的名称
ARM内核(cpu0)
- 四大步三小步
- 拷贝 CPSR 到 SPSR_
- 设置适当的 CPSR 位:
– 改变处理器状态进入 ARM 态
– 改变处理器模式进入相应的异常模式
– 设置中断禁止位禁止相应中断 (如果需要) - 保存返回地址到 LR_
- 设置 PC 为相应的异常向量
- 中断服务程序代码:start.S
见附录附录代码 - 中断处理程序代码:do_irq函数c语言
- 读取正在处理的中断ID寄存器(ICCIAR)
irq_num = (CPU0.ICCIAR & 0x1FF); - 根据irq_num,分支处理中断
- 清除中断状态位
i.外设级,EXT_INT41_PEND |= 0x1 << 1;
ii.GIC级,ICDICPR.ICDICPR1 |= 0x1 << 25;
iii.CPU0级 CPU0.ICCEOIR = (CPU0.ICCEOIR & ~(0x1FF)) | irq_num; - c代码如下示:
#include "exynos_4412.h" void mydelay_ms(int ms) { int i, j; while(ms--) { for (i = 0; i < 5; i++) for (j = 0; j < 514; j++); } } void do_irq(void ) { int irq_num; irq_num = (CPU0.ICCIAR & 0x1FF); switch (irq_num) { case 57: // //Clear Pend EXT_INT41_PEND |= 0x1 << 1; ICDICPR.ICDICPR1 |= 0x1 << 25; //Turn on LED2 GPX2.DAT |= 0x1 << 7; mydelay_ms(500); //Turn off LED2 GPX2.DAT &= ~(0x1 << 7); mydelay_ms(500); break; } // End of interrupt CPU0.ICCEOIR = (CPU0.ICCEOIR & ~(0x1FF)) | irq_num; } int main(void) { GPX2.CON = (GPX2.CON & ~(0xf << 28)) | 1 << 28; //GPX2_7:output, LED2 //Key_2 Interrupt GPX1_1 GPX1.PUD = GPX1.PUD & ~(0x3 << 2); // Disables Pull-up/Pull-down GPX1.CON = (GPX1.CON & ~(0xF << 4)) | (0xF << 4); //GPX1_1: WAKEUP_INT1[1](EXT_INT41[1]) EXT_INT41_CON = (EXT_INT41_CON & ~(0x7 << 4)) | 0x2 << 4; EXT_INT41_MASK = (EXT_INT41_MASK & ~(0x1 << 1)); // Bit: 0 = Enables interrupt //* GIC interrupt controller: // Enables the corresponding interrupt SPI25-- Key_2 ICDISER.ICDISER1 |= (0x1 << 25); CPU0.ICCICR |= 0x1; //Global enable for signaling of interrupts CPU0.ICCPMR = 0xFF; //The priority mask level.Priority filter. threshold ICDDCR = 1; //Bit0: GIC global enable ICDIPTR.ICDIPTR14 |= 0x01<<8; //SPI25 interrupts are sent to processor 0 while (1); return 0; }
- 读取正在处理的中断ID寄存器(ICCIAR)
- 四大步三小步
附录代码
中断服务代码:start.S
.text
.global _start
_start:
b reset
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
reset:
ldr r0,=0x40008000
mcr p15,0,r0,c12,c0,0 @ Vector Base Address Register
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 @ Enable svc mode of cpu
mov r0, #0xfffffff
mcr p15, 0, r0, c1, c0, 2 @ Defines access permissions for each coprocessor
@ Privileged a
nd User mode access
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
@Set the FPEXC EN bit to enable the FPU:
MOV r3, #0x40000000
fmxr FPEXC, r3
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00001000 @ set bit 12 (---I) Icache
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/* LED Test Code */
ldr r0, =0x114001E0
ldr r1, [r0]
bic r1, r1, #0xf0000
orr r1, r1, #0x10000
str r1, [r0]
ldr r0, =0x114001E8
ldr r1, [r0]
bic r1, r1, #0x300
str r1, [r0]
ldr r0, =0x114001E4
ldr r1, [r0]
orr r1, r1, #0x10
str r1, [r0]
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
.align 4
/**** swi_interrupt handler ****/
/**** irq_handler ****/
irq_handler:
sub lr,lr,#4
stmfd sp!,{r0-r12,lr}
.weak do_irq
bl do_irq
ldmfd sp!,{r0-r12,pc}^
stacktop: .word stack+4*512
.data
stack: .space 4*512