嵌入式学习硬件I.MX6ULL(五)按键 中断 GIC OCP原则
目录
一、按键
1.步骤
(1)原理图
编辑
(2)时钟
(3)复用功能
(4)电器属性
(5)输入输出方向
2.代码
二、中断
1.步骤
2.GIC相关
(1)相关寄存器
(2)相关指令mcr和mrc(类似cpsr那里的msr和mrs)
(3)协处理器 coprocessor
(1)cp15中的c0寄存器的MIDR
(2)cp15中的c1寄存器SCTLR
(3)cp15中的c12寄存器的VBAR
(4)cp15中的c15寄存器的CBAR
(4)异常状态返回地址偏移量
(5)GPIO相关配置
(1)设置中断触发方式编辑
(2)中断屏蔽设置
(3)中断状态寄存器
三、OCP原则降低代码耦合度
1.OCP原则
interrupt.c
interrupt.h
gpio.c
gpio.h
一、按键
1.步骤
查看原理图 打开时钟 配置复用功能 配置电器属性 配置输入输出方向
(1)原理图
(2)时钟
(3)复用功能
ps SION默认是开的
(4)电器属性
(5)输入输出方向
2.代码
#include"key.h"
#include"MCIMX6Y2.h"
#include"fsl_iomuxc.h"
#include "core_ca7.h"
#include "gpio.h"
void init_key(void)
{IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_UART1_CTS_B,0x10F0);GPIO_Pin_Config_t t = {.direction = GPIO_Direction_In};gpio_pin_config(GPIO1,18,&t);GPIO1->ICR2 |= (3 << 18);GPIO1->IMR |= (1 << 18);GIC_SetPriority(GPIO1_Combined_16_31_IRQn,1);GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);}int key_pressed(void)
{return((GPIO1->DR & (1 << 18)) == 0) ? 1 : 0;}
二、中断
1.步骤
1.中断源发出中断请求
2.CPU检查是否响应中断以及该中断是否被屏蔽
3.检查中断的优先级
4.保护现场
5.执行终端服务函数
6.恢复现场
2.GIC相关
1. SPI(Shared Peripheral Interrupt),共享中断, (注意!不是 SPI 总线那个中断),这类中断泛指所有的外设中断;
2. PPI(Private Peripheral Interrupt),私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断;
3. SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。
(1)相关寄存器
__IM uint32_t C_IAR; /*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */ GIC向内核发送中断号时先把中断号保存在此寄存器
__OM uint32_t C_EOIR; /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */
中断结束寄存器 处理完中断后把中断标志位清除
用法:把第一个寄存器的数值写入到第二个寄存器中实现中断标志位的清除
(2)相关指令mcr和mrc(类似cpsr那里的msr和mrs)
MRC<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}
<c>是条件可以省略,<Rt>是目标寄存器,读协处理器<coproc>的某个寄存器的值到<Rt>中。
eg mrc p15,0,r0,c0,c0,0 MIDR寄存器的值就会被写到r0寄存器中
MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}
把<Rt>中的数写到协处理器<coproc>中。
(3)协处理器 coprocessor
常用cp15(找出GIC寄存器的基地址),cp10,cp11(浮点型运算)
cp15有c0-c15共16个寄存器
(1)cp15中的c0寄存器的MIDR
(2)cp15中的c1寄存器SCTLR
bit13,选择异常向量表的基地址。
为0时,普通异常向量表,基地址为0x00000000。软件可以使用VBAR重新映射这个基地址。
为1时,高异常向量表,基地址为0xFFFF0000,这个基地址不能再被映射。
bit12,指令高速缓存使能位。这是一个全局的指令高速缓存使能位。
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1 << 13)
orr r0,r0,#(1 << 12)
mcr p15,0,r0,c1,c0,0
(3)cp15中的c12寄存器的VBAR
用VBAR重新映射和GIC的初始化函数,越早调用该初始化函数越好。
void system_interrupt_init(void)
{
__set_VBAR(0x87800000);
GIC_Init();
}
(4)cp15中的c15寄存器的CBAR
mrc p15,4,r1,c15,c0,0
add r1,r1,#0x2000
ldr r0,[r1,#0x0c]
(4)异常状态返回地址偏移量
_irq_handler:
subs lr,lr,#4//使程序可以回到正确的位置
stmfd sp!,{r0-r12,lr}
mrc p15,4,r1,c15,c0,0
add r1,r1,#0x2000
ldr r0,[r1,#0x0c]
stmfd sp!,{r0,r1}
cps #0x1f
stmfd sp!,{lr}
(5)GPIO相关配置
(1)设置中断触发方式
(2)中断屏蔽设置
(3)中断状态寄存器
GPIO1->GDIR &= ~(1 << 18);
GPIO1->ICR2 |= (3 << 4);
GPIO1->IMR |= (1 << 18);
GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);//使能中断
三、OCP原则降低代码耦合度
1.OCP原则
对代码的添加是开放的,对代码的修改是关闭的。
interrupt.c
#include "interrupt.h"
#include "beep.h"#include "fsl_iomuxc.h"
#include "key.h"
#include "led.h"
#include <MCIMX6Y2.h>
#include "core_ca7.h"static irq_handler_t interrupt_vector_table[160];void system_interrupt_init(void)
{__set_VBAR(0x87800000);GIC_Init();
}void system_interrupt_register(irq_handler_t handler, int num)
{interrupt_vector_table[num] = handler;
}void system_interrupt_handler(int irq)
{if (interrupt_vector_table[irq] != NULL){interrupt_vector_table[irq]();}
}
interrupt.h
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_typedef void (*irq_handler_t)(void);
extern void system_interrupt_init(void);
extern void system_interrupt_register(irq_handler_t handler, int num);
extern void system_interrupt_handler(int irq);#endif
gpio.c
#include "gpio.h"
#include "fsl_iomuxc.h"
#include "MCIMX6Y2.h"void init_gpio(GPIO_Type *gpio, int pin, gpio_configt_t *config)
{if(config->pin_direction == gpio_direction_output){gpio->GDIR |= (1 << pin);if(config->default_vaule != 0){gpio->DR |= (1 << pin);}else{gpio->DR &= ~(1 << pin);}}else{gpio->GDIR &= ~(1 << pin);}
}void write_gpio(GPIO_Type *gpio, int pin, int value)
{if(value){gpio->DR |= (1 << pin);}else{gpio->DR &= ~(1 << pin);}
}int read_gpio(GPIO_Type *gpio, int pin)
{return (gpio->DR & (1 << pin)) != 0;
}
gpio.h
#ifndef _GPIO_H_
#define _GPIO_H_typedef enum
{gpio_direction_input,gpio_direction_output
}gpio_direction_t;typedef struct
{gpio_direction_t pin_direction;int default_vaule;
}gpio_configt_t;#endif