一、STM32的中断系统
代码从0x00000000运行。32设置连接首地址0x8000000的地方存放了中断向量表,因此要从0x8000000的地方开始运行。需要告诉soc内核,要设置中断向量偏移。设置SCB的VTOC寄存器为新的中断向量表起始地址,内部指向各种中断的函数名。
但是Cotex-A的中断向量表只有几个,我们主要使用的是IRQ。
二、6ULL中断系统
1.GIC控制器
GIC提供了开关中断,设置中断优先级等等。6ULL有1020个中断号,用于向CPU interface发送信号,从而通知IRQ中断。其中32-1019号ID用于SPI(共享外设中断)。其他暂时不管它。
GIC由Distributor与CPU interface构成。Distributor将中断事件发送给CPU interface。
Distributor
其中Distributor所做的事情是:SPI中断使能,设置优先级,设置到中断目标处理器列表中,设置外部中断的触发模式,设置中断属于组0还是组1。
CPU interface
作为内核与Distributor的桥梁,主要工作是:向CPU发送请求信号,应答,状态等,设置优先级掩码(从而设置哪些中断无需上报给CPU),定义抢占策略:当多个中断来时进行分配给CPU。
2.CP15协处理器
协处理器中有16个32bit寄存器。对于指令填写依照下图。
格式: MRC{cond} sp15
其中 RT 作为数据的中间人。
r0寄存器
我们要关闭ID Cache和MMU,找到手册中的SCTLR寄存,bit0关闭MMU,bit1控制对齐,控制为打开关闭MMU,bit2控制 D Cache的打开和关闭,bit11用于控制分支预测,bit12用于控制 I Cache。
c12寄存器
用于中断向量偏移设置,将新的向量表首地址写入到CP15协处理器中的VBAR。
c15寄存器
我们需要读取CBAR寄存器,保存了GIC控制器的寄存器首地址。GIC寄存器组偏移0x1000-0x1fff为GIC的Distributor。0x2000-0x3fff为CPU Interface。意味我们可以访问GIC控制器了。
MRC sp15 0 r0 c12 c0 0
MCR sp15 0 r0 c12 c0 0
1
2
三、编写外部中断
1.复位中断函数
向量表中有8个中断,需要用户自己定义。
修改汇编程序,添加中断向量表。编写复位中断函数与IRQ中断服务函数。
1.关闭L.D Cache 和MMU。
2.设置sp指针,使用外部中断必须设置IRQ模式。
3.清除bss段
4.调到C语言中
5.中断处理结束以后,必须要向GICC_EOIR寄存器写入中断号,表示完成
start.S
.global _start
_start:
ldr pc ,=Reset_Handler
ldr pc ,=Undefined_Handler
ldr pc ,=SVC_Handler
ldr pc ,=PrefAbort_Handler
ldr pc ,=DataAbort_Handler
ldr pc ,=NotUsed_Handler
ldr pc ,=IRQ_Handler
ldr pc ,=FIQ_Handler
Reset_Handler:
cpsid i /*close up IRQ */
/*关闭ID Cache
修改SCTLR寄存器,才用读改写的方式
*/
mrc p15,0,r0,c1,c0,0 /*读取SCTLR寄存器的数据到r0中*/
bic r0 ,r0 , #(1<<12) /*关闭I Cache*/
bic r0 ,r0 , #(1<<11) /*关闭分支预测*/
bic r0 ,r0 , #(1<<2) /*关闭D Cache*/
bic r0 ,r0 , #(1<<1) /*关闭对齐*/
bic r0 ,r0 , #(1<<0) /*关闭MMU*/
mcr p15,0,r0,c1,c0,0 /*写到SCTLR寄存器中*/
.global _bss_start
_bss_start:
.word __bss_start
.global _bss_end
_bss_end:
.word __bss_end
/*设置中断向量偏移*/
/* ldr r0 ,=0x87800000
d***
i***
mcr p15 ,0 ,r0 ,c12 ,c0 ,0
d***
i***
*/
/*清除BSS段*/
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0
bss_loop:
stmia r0!, {r2}
cmp r0, r1 /* 比较R0和R1里面的值 */
ble bss_loop /*如果r0地址小于等于r1,继续清除bss段*/
/*进入SYS*/
mrs r0 , cpsr
bic r0 ,r0 ,#0x1f
orr r0 ,r0 ,#0x1f
msr cpsr ,r0
ldr sp , =0x80600000 /*4M大小的地方*/
/*进入IRQ*/
mrs r0 , cpsr
bic r0 ,r0 ,#0x1f
orr r0 ,r0 ,#0x12
msr cpsr ,r0
ldr sp , =0x80400000 /*4M大小的地方*/
/*设置处理器进入SVC模式下的sp*/
mrs r0, cpsr /* 读取cpsr到r0*/
bic r0, r0, #0x1f /* 清除cpsr的bit4-0*/
orr r0, r0, #0x13 /* 使用SVC模式*/
msr cpsr, r0 /* 将r0写入到cpsr*/
/* 设置SP指针 */
ldr sp, =0x80200000
cpsie i /*open IRQ */
b main /* 跳转到C语言main函数*/
Undefined_Handler:
ldr r0 ,=Undefined_Handler
bx r0
SVC_Handler:
ldr r0 ,=SVC_Handler
bx r0
PrefAbort_Handler:
ldr r0 ,=PrefAbort_Handler
bx r0
DataAbort_Handler:
ldr r0 ,=DataAbort_Handler
bx r0
NotUsed_Handler:
ldr r0 ,=NotUsed_Handler
bx r0
IRQ_Handler:
FIQ_Handler:
ldr r0 ,=FIQ_Handler
bx r0
2.IRQ中断函数
1.首先lr,r0-r3 r12入栈。保存spsr的值。
2.将CPU Interface的GICC_IAR寄存器的中断号ID读到r0中。
3.入栈r0,r1,进入SVC模式,从而运行C语言系统中断函数。
4.出栈SVC , 进入IRQ模式,将ID好写入到EOIR位。
5.出栈r0 --ID, 恢复spsr寄存器,再回到中断之前的SYS模式。
IRQ_Handler:
IRQ_Handler:
读取spsr寄存器*/
push {r0} /*保存spsr寄存器*/
mrc p15 ,4 ,r1 ,c15 ,c0 ,0/*从CP15的C0寄存器内的值读到寄存器中*/
add r1 , r1 ,#0x2000 /*r1保存了GIC控制器CPU接口的基地址0x2000*/
ldr r0 ,[r1 , #0xC] /*偏移0x0C为GICC_IAR寄存器保存到r0寄存器 ,可以从GICC_IAR的bit9-0读取中断ID,读取中断ID的目的就是为了得到对应的中断处理函数*/
push {r0 ,r1} /*保存r0 ,r1*/
cps #0x13 /*进入SVC模式,允许其他中断再次进入*/
push {lr} /*保存SVC的lr寄存器*/
ldr r2 , =system_irqhandler/*加载C语言中断处理函数到r2寄存器内 ,压栈的r0会成为它的参数*/
blx r2 /*运行C语言中断处理函数,带有一个参数,保存到*/
pop {lr} /*执行完中断后,lr出栈*/
cps #0x12 /*进入IRQ模式*/
pop {r0, r1}
str r0 , [r1 , #0x10]/*中断执行完,r0的中断ID写到EOIR*/
pop {r0}
msr spsr_cxsf , r0 /*recover spsr*/
pop {r0-r3 ,r12}
pop {lr}
subs pc , lr ,#4 /*将两lr-4能给pc*/
四、编写中断函数
1.初始化GIC ,由于GIC控制器提供了中断的各种开关,优先级之类的。
2.初始化中断向量表
bsp_int.c
#include "stdio.h"
#include "bsp_int.h"
static uint8_t irqNesting; //中断嵌套值
/*中断表定义*/
static sys_irq_handler_t irqTable[NUMBER_OF_INT_VECTORS];
/*中断向量表初始化*/
void System_IrqTable_Init(void){
uint8_t i = 0 ;
irqNesting = 0;
for(i = 0 ; i < NUMBER_OF_INT_VECTORS ; i++){
System_Register_IrqHandler((IRQn_Type)i, handler, NULL);
}
}
void System_Register_IrqHandler(IRQn_Type irq,
system_irq_handler_t handler,
void *userParam)
{
irqTable[irq].irqHandler = handler;
irqTable[irq].userParam = userParam;
}
/*中断初始化函数*/
void int_init(void)
{
GIC_Init();
Sytem_IrqTable_Init();
/*中断向量偏移设置*/
__set_VBAR(0x87800000);
}
/*汇编IRQ模式进入的函数
*将传入的参数是是r0寄存,就是获取GICC_IAR寄存器的中断ID号
*/
void system_irqhandler(unsigned int gicciar){
uint32_t intNum = gicciar;
if(gicciar >= 160)return ;
irqNesting++;
irqTable[intNum].irqHandler(intNum , irqTable[intNum].userParam);
}
void Default_IrqHandler(uint8_t gicciar ,void *param){
while(1){}
}
bsp_int.h
#ifndef __BSP_INT_H__
#define __BSP_INT_H__
#include "imx6ull.h"
/*定义中断函数*/
typedef void (*system_irq_handler_t)(unsigned int gicciar , void *param);
/*中断函数结构体*/
typedef struct sys_irq_handler{
system_irq_handler_t irqHandler;
void *userParam;
}sys_irq_handler_t;
void int_init(void);
void system_irqhandler(unsigned int gicciar);
#endif
五、GPIO按键中断
1.GPIO中断设置
1.设置GPIO5_IO01为低电平触发为高电平触发
2.设置使能GPIO中断掩码寄存器,GPIO_IMR寄存器,用于使能中断。
3.GPIO_ICR中断设置寄存器,可以设置不同的触发信号。
3.设置EDGE位被设置以后,ICR位就没有用了。置位可以任意电平信号进行触发。
3.使能ISR中断状态寄存器,处理完以后,需要清除中断标志位。清除ISR寄存器的位。写1清0。
bsp_gpio.c
#include "bsp_gpio.h"
void gpio_init(GPIO_Type *base , int pin , gpio_pin_cfg_t *config)
{
if(config->Direction == KGPIO_DigitalInput){
base->GDIR &= ~(1<
}
else{
base->GDIR |= (1<
}
Gpio_IntConfig(base ,pin ,config->interruptMode);
}
/*Clear Interrupt FLag bit*/
void Gpio_ClearInterFlags(GPIO_Type *base , unsigned int pin){
base->ISR |= (1<
}
/*GPIO INterrupt Iiit*/
void Gpio_IntConfig(GPIO_Type *base ,unsigned int pin ,gpio_interrupt_mode_t pin_int_mode)
{
volatile uint32_t *icr;
uint32_t icrShift;
icrShift = pin;
base->EDGE_SEL &= ~(1<
if(pin<<16){
icr = &(base->ICR1);
}
else{
icr = &(base->ICR2);
icrShift -= 16;
}
switch(pin_int_mode)
{
case KGPIO_IntLowLevel:
*icr &= ~(3 << (2*icrShift));
break;
case KGPIO_IntHighLevel:
*icr &= ~(3 << (2*icrShift));
*icr |= (1 << (2*icrShift));
break;
case KGPIO_IntRisingEdge:
*icr &= ~(3 << (2*icrShift));
*icr |= (2 << (2*icrShift));
break;
case KGPIO_IntFallingEdge:
*icr &= ~(3 << (2*icrShift));
*icr |= (3 << (2*icrShift));
break;
case KGPIO_IntRisingOrFallingEdge:
base->EDGE_SEL |= (1 << pin);
break;
default:
break;
}
}
bsp_gpio.h
#ifndef __BSP_GPIO_H__
#define __BSP_GPIO_H__
#include "imx6ull.h"
/*Interrupt edge type*/
typedef enum _gpio_interrupt_mode
{
KGPIO_Nointmode = 0U,
KGPIO_IntLowLevel = 1U,
KGPIO_IntHighLevel = 2U,
KGPIO_IntRisingEdge = 3U,
KGPIO_IntFallingEdge = 4U,
KGPIO_IntRisingOrFallingEdge = 5U
}gpio_interrupt_mode_t;
/* GPIO struct*/
typedef enum Gpio_Pin{
KGPIO_DigitalInput = 0U,
KGPIO_DigitalOutput = 1U,
}gpio_pin_dir_t;
typedef struct Gpio_Pin_Config{
gpio_pin_dir_t Direction;
uint8_t OutputLogic;
gpio_interrupt_mode_t interruptMode;
}gpio_pin_cfg_t;
int gpio_pinread(GPIO_Type *base , int pin);
void gpio_pinwrite(GPIO_Type *base , int pin , int value);
void gpio_init(GPIO_Type *base , int pin , gpio_pin_cfg_t *config);
void Gpio_EnableInt(GPIO_Type *base , unsigned int pin);
void Gpio_DisableInt(GPIO_Type *base , unsigned int pin);
void Gpio_ClearInterFlags(GPIO_Type *base , unsigned int pin);
void Gpio_IntConfig(GPIO_Type *base ,unsigned int pin ,gpio_interrupt_mode_t ping_int_mode);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
六、外部中断设置
1.初始化gpio
2.使能GIC控制器
3.注册中断函数
4.使能中断
GIC配置
1.使能相应的中断IO对应的ID位位106
GPIO5_Combined_0_15_IRQn = 106,
1
2.设置中断优先级
3.注册GPIO的中断处理函数
4.GPIO_IMR寄存器进行使能
#include "bsp_exti.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_led.h"
void exti_init(void)
{
gpio_pin_cfg_t key_config;
IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0);
IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0xf080);
/* GPIO初始化 */
key_config.Direction = KGPIO_DigitalInput;
key_config.interruptMode = KGPIO_IntHighLevel;
gpio_init(GPIO5 , 1 , &key_config);
GIC_EnableIRQ(GPIO5_Combined_0_15_IRQn);
system_register_irqhandler(GPIO5_Combined_0_15_IRQn , (system_irq_handler_t)GPIO5_IO01_irqhandler , NULL);
Gpio_EnableInt(GPIO5 , 1); //IMR
}
/*Interrupt handler*/
void GPIO5_IO01_irqhandler(unsigned int gicciar,void *param){
delay(10);
if(gpio_pinread(GPIO5 , 1) == 0){
led_switch(LED_RED , LED_ON);
beep_switch(BEEP_ON);
delay(1000);
led_switch(LED_RED , LED_OFF);
beep_switch(BEEP_OFF);
delay(1000);
}
/*clear flags*/
Gpio_ClearInterFlags(GPIO5 , 1);
}
一、STM32的中断系统
代码从0x00000000运行。32设置连接首地址0x8000000的地方存放了中断向量表,因此要从0x8000000的地方开始运行。需要告诉soc内核,要设置中断向量偏移。设置SCB的VTOC寄存器为新的中断向量表起始地址,内部指向各种中断的函数名。
但是Cotex-A的中断向量表只有几个,我们主要使用的是IRQ。
二、6ULL中断系统
1.GIC控制器
GIC提供了开关中断,设置中断优先级等等。6ULL有1020个中断号,用于向CPU interface发送信号,从而通知IRQ中断。其中32-1019号ID用于SPI(共享外设中断)。其他暂时不管它。
GIC由Distributor与CPU interface构成。Distributor将中断事件发送给CPU interface。
Distributor
其中Distributor所做的事情是:SPI中断使能,设置优先级,设置到中断目标处理器列表中,设置外部中断的触发模式,设置中断属于组0还是组1。
CPU interface
作为内核与Distributor的桥梁,主要工作是:向CPU发送请求信号,应答,状态等,设置优先级掩码(从而设置哪些中断无需上报给CPU),定义抢占策略:当多个中断来时进行分配给CPU。
2.CP15协处理器
协处理器中有16个32bit寄存器。对于指令填写依照下图。
格式: MRC{cond} sp15
其中 RT 作为数据的中间人。
r0寄存器
我们要关闭ID Cache和MMU,找到手册中的SCTLR寄存,bit0关闭MMU,bit1控制对齐,控制为打开关闭MMU,bit2控制 D Cache的打开和关闭,bit11用于控制分支预测,bit12用于控制 I Cache。
c12寄存器
用于中断向量偏移设置,将新的向量表首地址写入到CP15协处理器中的VBAR。
c15寄存器
我们需要读取CBAR寄存器,保存了GIC控制器的寄存器首地址。GIC寄存器组偏移0x1000-0x1fff为GIC的Distributor。0x2000-0x3fff为CPU Interface。意味我们可以访问GIC控制器了。
MRC sp15 0 r0 c12 c0 0
MCR sp15 0 r0 c12 c0 0
1
2
三、编写外部中断
1.复位中断函数
向量表中有8个中断,需要用户自己定义。
修改汇编程序,添加中断向量表。编写复位中断函数与IRQ中断服务函数。
1.关闭L.D Cache 和MMU。
2.设置sp指针,使用外部中断必须设置IRQ模式。
3.清除bss段
4.调到C语言中
5.中断处理结束以后,必须要向GICC_EOIR寄存器写入中断号,表示完成
start.S
.global _start
_start:
ldr pc ,=Reset_Handler
ldr pc ,=Undefined_Handler
ldr pc ,=SVC_Handler
ldr pc ,=PrefAbort_Handler
ldr pc ,=DataAbort_Handler
ldr pc ,=NotUsed_Handler
ldr pc ,=IRQ_Handler
ldr pc ,=FIQ_Handler
Reset_Handler:
cpsid i /*close up IRQ */
/*关闭ID Cache
修改SCTLR寄存器,才用读改写的方式
*/
mrc p15,0,r0,c1,c0,0 /*读取SCTLR寄存器的数据到r0中*/
bic r0 ,r0 , #(1<<12) /*关闭I Cache*/
bic r0 ,r0 , #(1<<11) /*关闭分支预测*/
bic r0 ,r0 , #(1<<2) /*关闭D Cache*/
bic r0 ,r0 , #(1<<1) /*关闭对齐*/
bic r0 ,r0 , #(1<<0) /*关闭MMU*/
mcr p15,0,r0,c1,c0,0 /*写到SCTLR寄存器中*/
.global _bss_start
_bss_start:
.word __bss_start
.global _bss_end
_bss_end:
.word __bss_end
/*设置中断向量偏移*/
/* ldr r0 ,=0x87800000
d***
i***
mcr p15 ,0 ,r0 ,c12 ,c0 ,0
d***
i***
*/
/*清除BSS段*/
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0
bss_loop:
stmia r0!, {r2}
cmp r0, r1 /* 比较R0和R1里面的值 */
ble bss_loop /*如果r0地址小于等于r1,继续清除bss段*/
/*进入SYS*/
mrs r0 , cpsr
bic r0 ,r0 ,#0x1f
orr r0 ,r0 ,#0x1f
msr cpsr ,r0
ldr sp , =0x80600000 /*4M大小的地方*/
/*进入IRQ*/
mrs r0 , cpsr
bic r0 ,r0 ,#0x1f
orr r0 ,r0 ,#0x12
msr cpsr ,r0
ldr sp , =0x80400000 /*4M大小的地方*/
/*设置处理器进入SVC模式下的sp*/
mrs r0, cpsr /* 读取cpsr到r0*/
bic r0, r0, #0x1f /* 清除cpsr的bit4-0*/
orr r0, r0, #0x13 /* 使用SVC模式*/
msr cpsr, r0 /* 将r0写入到cpsr*/
/* 设置SP指针 */
ldr sp, =0x80200000
cpsie i /*open IRQ */
b main /* 跳转到C语言main函数*/
Undefined_Handler:
ldr r0 ,=Undefined_Handler
bx r0
SVC_Handler:
ldr r0 ,=SVC_Handler
bx r0
PrefAbort_Handler:
ldr r0 ,=PrefAbort_Handler
bx r0
DataAbort_Handler:
ldr r0 ,=DataAbort_Handler
bx r0
NotUsed_Handler:
ldr r0 ,=NotUsed_Handler
bx r0
IRQ_Handler:
FIQ_Handler:
ldr r0 ,=FIQ_Handler
bx r0
2.IRQ中断函数
1.首先lr,r0-r3 r12入栈。保存spsr的值。
2.将CPU Interface的GICC_IAR寄存器的中断号ID读到r0中。
3.入栈r0,r1,进入SVC模式,从而运行C语言系统中断函数。
4.出栈SVC , 进入IRQ模式,将ID好写入到EOIR位。
5.出栈r0 --ID, 恢复spsr寄存器,再回到中断之前的SYS模式。
IRQ_Handler:
IRQ_Handler:
读取spsr寄存器*/
push {r0} /*保存spsr寄存器*/
mrc p15 ,4 ,r1 ,c15 ,c0 ,0/*从CP15的C0寄存器内的值读到寄存器中*/
add r1 , r1 ,#0x2000 /*r1保存了GIC控制器CPU接口的基地址0x2000*/
ldr r0 ,[r1 , #0xC] /*偏移0x0C为GICC_IAR寄存器保存到r0寄存器 ,可以从GICC_IAR的bit9-0读取中断ID,读取中断ID的目的就是为了得到对应的中断处理函数*/
push {r0 ,r1} /*保存r0 ,r1*/
cps #0x13 /*进入SVC模式,允许其他中断再次进入*/
push {lr} /*保存SVC的lr寄存器*/
ldr r2 , =system_irqhandler/*加载C语言中断处理函数到r2寄存器内 ,压栈的r0会成为它的参数*/
blx r2 /*运行C语言中断处理函数,带有一个参数,保存到*/
pop {lr} /*执行完中断后,lr出栈*/
cps #0x12 /*进入IRQ模式*/
pop {r0, r1}
str r0 , [r1 , #0x10]/*中断执行完,r0的中断ID写到EOIR*/
pop {r0}
msr spsr_cxsf , r0 /*recover spsr*/
pop {r0-r3 ,r12}
pop {lr}
subs pc , lr ,#4 /*将两lr-4能给pc*/
四、编写中断函数
1.初始化GIC ,由于GIC控制器提供了中断的各种开关,优先级之类的。
2.初始化中断向量表
bsp_int.c
#include "stdio.h"
#include "bsp_int.h"
static uint8_t irqNesting; //中断嵌套值
/*中断表定义*/
static sys_irq_handler_t irqTable[NUMBER_OF_INT_VECTORS];
/*中断向量表初始化*/
void System_IrqTable_Init(void){
uint8_t i = 0 ;
irqNesting = 0;
for(i = 0 ; i < NUMBER_OF_INT_VECTORS ; i++){
System_Register_IrqHandler((IRQn_Type)i, handler, NULL);
}
}
void System_Register_IrqHandler(IRQn_Type irq,
system_irq_handler_t handler,
void *userParam)
{
irqTable[irq].irqHandler = handler;
irqTable[irq].userParam = userParam;
}
/*中断初始化函数*/
void int_init(void)
{
GIC_Init();
Sytem_IrqTable_Init();
/*中断向量偏移设置*/
__set_VBAR(0x87800000);
}
/*汇编IRQ模式进入的函数
*将传入的参数是是r0寄存,就是获取GICC_IAR寄存器的中断ID号
*/
void system_irqhandler(unsigned int gicciar){
uint32_t intNum = gicciar;
if(gicciar >= 160)return ;
irqNesting++;
irqTable[intNum].irqHandler(intNum , irqTable[intNum].userParam);
}
void Default_IrqHandler(uint8_t gicciar ,void *param){
while(1){}
}
bsp_int.h
#ifndef __BSP_INT_H__
#define __BSP_INT_H__
#include "imx6ull.h"
/*定义中断函数*/
typedef void (*system_irq_handler_t)(unsigned int gicciar , void *param);
/*中断函数结构体*/
typedef struct sys_irq_handler{
system_irq_handler_t irqHandler;
void *userParam;
}sys_irq_handler_t;
void int_init(void);
void system_irqhandler(unsigned int gicciar);
#endif
五、GPIO按键中断
1.GPIO中断设置
1.设置GPIO5_IO01为低电平触发为高电平触发
2.设置使能GPIO中断掩码寄存器,GPIO_IMR寄存器,用于使能中断。
3.GPIO_ICR中断设置寄存器,可以设置不同的触发信号。
3.设置EDGE位被设置以后,ICR位就没有用了。置位可以任意电平信号进行触发。
3.使能ISR中断状态寄存器,处理完以后,需要清除中断标志位。清除ISR寄存器的位。写1清0。
bsp_gpio.c
#include "bsp_gpio.h"
void gpio_init(GPIO_Type *base , int pin , gpio_pin_cfg_t *config)
{
if(config->Direction == KGPIO_DigitalInput){
base->GDIR &= ~(1<
}
else{
base->GDIR |= (1<
}
Gpio_IntConfig(base ,pin ,config->interruptMode);
}
/*Clear Interrupt FLag bit*/
void Gpio_ClearInterFlags(GPIO_Type *base , unsigned int pin){
base->ISR |= (1<
}
/*GPIO INterrupt Iiit*/
void Gpio_IntConfig(GPIO_Type *base ,unsigned int pin ,gpio_interrupt_mode_t pin_int_mode)
{
volatile uint32_t *icr;
uint32_t icrShift;
icrShift = pin;
base->EDGE_SEL &= ~(1<
if(pin<<16){
icr = &(base->ICR1);
}
else{
icr = &(base->ICR2);
icrShift -= 16;
}
switch(pin_int_mode)
{
case KGPIO_IntLowLevel:
*icr &= ~(3 << (2*icrShift));
break;
case KGPIO_IntHighLevel:
*icr &= ~(3 << (2*icrShift));
*icr |= (1 << (2*icrShift));
break;
case KGPIO_IntRisingEdge:
*icr &= ~(3 << (2*icrShift));
*icr |= (2 << (2*icrShift));
break;
case KGPIO_IntFallingEdge:
*icr &= ~(3 << (2*icrShift));
*icr |= (3 << (2*icrShift));
break;
case KGPIO_IntRisingOrFallingEdge:
base->EDGE_SEL |= (1 << pin);
break;
default:
break;
}
}
bsp_gpio.h
#ifndef __BSP_GPIO_H__
#define __BSP_GPIO_H__
#include "imx6ull.h"
/*Interrupt edge type*/
typedef enum _gpio_interrupt_mode
{
KGPIO_Nointmode = 0U,
KGPIO_IntLowLevel = 1U,
KGPIO_IntHighLevel = 2U,
KGPIO_IntRisingEdge = 3U,
KGPIO_IntFallingEdge = 4U,
KGPIO_IntRisingOrFallingEdge = 5U
}gpio_interrupt_mode_t;
/* GPIO struct*/
typedef enum Gpio_Pin{
KGPIO_DigitalInput = 0U,
KGPIO_DigitalOutput = 1U,
}gpio_pin_dir_t;
typedef struct Gpio_Pin_Config{
gpio_pin_dir_t Direction;
uint8_t OutputLogic;
gpio_interrupt_mode_t interruptMode;
}gpio_pin_cfg_t;
int gpio_pinread(GPIO_Type *base , int pin);
void gpio_pinwrite(GPIO_Type *base , int pin , int value);
void gpio_init(GPIO_Type *base , int pin , gpio_pin_cfg_t *config);
void Gpio_EnableInt(GPIO_Type *base , unsigned int pin);
void Gpio_DisableInt(GPIO_Type *base , unsigned int pin);
void Gpio_ClearInterFlags(GPIO_Type *base , unsigned int pin);
void Gpio_IntConfig(GPIO_Type *base ,unsigned int pin ,gpio_interrupt_mode_t ping_int_mode);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
六、外部中断设置
1.初始化gpio
2.使能GIC控制器
3.注册中断函数
4.使能中断
GIC配置
1.使能相应的中断IO对应的ID位位106
GPIO5_Combined_0_15_IRQn = 106,
1
2.设置中断优先级
3.注册GPIO的中断处理函数
4.GPIO_IMR寄存器进行使能
#include "bsp_exti.h"
#include "bsp_gpio.h"
#include "bsp_int.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_led.h"
void exti_init(void)
{
gpio_pin_cfg_t key_config;
IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0);
IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0xf080);
/* GPIO初始化 */
key_config.Direction = KGPIO_DigitalInput;
key_config.interruptMode = KGPIO_IntHighLevel;
gpio_init(GPIO5 , 1 , &key_config);
GIC_EnableIRQ(GPIO5_Combined_0_15_IRQn);
system_register_irqhandler(GPIO5_Combined_0_15_IRQn , (system_irq_handler_t)GPIO5_IO01_irqhandler , NULL);
Gpio_EnableInt(GPIO5 , 1); //IMR
}
/*Interrupt handler*/
void GPIO5_IO01_irqhandler(unsigned int gicciar,void *param){
delay(10);
if(gpio_pinread(GPIO5 , 1) == 0){
led_switch(LED_RED , LED_ON);
beep_switch(BEEP_ON);
delay(1000);
led_switch(LED_RED , LED_OFF);
beep_switch(BEEP_OFF);
delay(1000);
}
/*clear flags*/
Gpio_ClearInterFlags(GPIO5 , 1);
}
举报