《嵌入式硬件(十一):基于IMX6ULL的中断操作》
一、中断的基本概念
外设可以产生中断->GIC(Generic Interrupt Controller)控制器接收中断->传输给内核
GIC(Generic Interrupt Controller,通用中断控制器)是ARM架构中用于管理中断请求的硬件模块,主要作用是在多核心、多外设的场景下,对中断进行分发与管理,确保不同的中断能被正确地路由到对应的处理器核心,以实现高效的中断处理。
二、外设原理
1.ICR1
2.ICR2
3.IMR(中断屏蔽寄存器)
4.ISR(中断状态寄存器)
5.EDGE_SEL(边缘寄存器)
三、GIC原理
1.基本概念
GIC
最多八核;
中断总共有1020,分为三类,SPI(32-1019),共享外设中断,PPI(16~31),私有外设中断,SGI(0~15号),软件产生中断。
IMX6ULL
内核中断有32个,外设中断有128个
e.g. GPIO1组的中断,后俩个是引脚号结合起来的中断
GPIO1_INT4_IRQn = 93, /**< INT4 interrupt request. */GPIO1_INT3_IRQn = 94, /**< INT3 interrupt request. */GPIO1_INT2_IRQn = 95, /**< INT2 interrupt request. */GPIO1_INT1_IRQn = 96, /**< INT1 interrupt request. */GPIO1_INT0_IRQn = 97, /**< INT0 interrupt request. */GPIO1_Combined_0_15_IRQn = 98, /**< Combined interrupt indication for GPIO1 signals 0 - 15. */GPIO1_Combined_16_31_IRQn = 99, /**< Combined interrupt indication for GPIO1 signals 16 - 31. */
e.g.中断寄存器
__IOM uint32_t C_CTLR; /*!< Offset: 0x2000 (R/W) CPU Interface Control Register */__IM uint32_t C_IAR; /*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */__OM uint32_t C_EOIR; /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */
中断优先级屏蔽寄存器
中断通知寄存器:保存终端号
中断结束寄存器:清楚中断标记
2.协处理器
协处理器是一种为了协助主处理器完成特定功能(如浮点运算、加密、信号处理等)而设计的处理器,它可以分担主处理器的任务,提升系统在特定领域的处理效率。 ARM Cortex A7内核配备了16个协处理器,其中CP15(系统控制协处理器)使用的多,保存着GIC基地址。
要对异常向量表进行映射
重映射原因:异常向量表默认位于固定的低地址区域(如0x00000000附近),该区域在系统运行过程中可能会被其他代码(如引导程序、应用程序)占用或修改,导致异常处理程序无法正常执行。通过重映射,可以将异常向量表移到安全、不会被干扰的内存区域(如高地址的RAM区域),保证异常处理的可靠性。
重映射方法:通过设置ARM处理器的协处理器CP15中的相关寄存器(如Vector Base Address Register,VBAR),将异常向量表的基地址指向新的内存区域,从而实现异常向量表的重映射。
读取协处理器内容的指令
MRC <c> <coproc>, <opc 1>, <rt>, <CRn> , <CRm>{,<opc2> } [对照着协处理器表填]
写协处理器的指令
MCR <c> <coproc>, <opc 1>, <rt>, <CRn> , <CRm>{,<opc2> } [对照着协处理器表填]
设置基地址(库里面已经写了),但是可以学习怎么自己写
mrc p15, 4, r0, c15, c0, 0
初始化函数:在core_ca7.h里,GIC_Init()
tpis:内联函数,调用前需要有定义,所以把他写在头文件里(static inline xxxxx),调用时可能会展开,此时会提高效率
四、CPU原理
1.CPSR
IF位
tips:如果不是软中断,需要加一行subs lr, lr, #4(ARM规定)
异常向量返回地址偏移量
tips:cps,armv6以上支持
作用1:修改处理器的状态
CPS #<mode>
作用2:CPS<effect>{<q>} <iflags> {, #<mode>}
允许中断通过,cpsie i == bic r0, r0, #(1 << 7)
五、代码
结构与之前一样
1.bsp
1)key.c
#include "key.h"
#include "fsl_iomuxc.h"
#include "gpio.h"
#include "led.h"
#include "MCIMX6Y2.h"
#include "core_ca7.h"
#include "interrupt.h"
#include "beep.h"void key_interrupt_handler(void)
{ if((GPIO1->ISR & (1 << 18)) != 0){beep_on();led_nor();GPIO1->ISR |= (1 << 18);}
}void init_key(void)
{IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xf0b0);struct GPIO_Type_t t = {.direction = gpio_input,};init_gpio(GPIO1, 18, &t);GPIO1->ICR2 |= (3 << 4);GPIO1->IMR |= (1 << 18);system_interrupt_register(GPIO1_Combined_16_31_IRQn, key_interrupt_handler);GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);//使能中断GIC_SetPriority(GPIO1_Combined_16_31_IRQn,0);//设置优先级
}int key_pressed(void)
{if(read_gpio(GPIO1, 18) == 1)//没有按下{return 0;}else{return 1;}
}
2)key.h
#ifndef _KEY_H_
#define _KEY_H_extern void init_key(void);
extern int key_pressed(void);#endif
3)interrupt.c
#include "interrupt.h"
#include "MCIMX6Y2.h"
#include "core_ca7.h"static irq_handler_t interrupt_vector_table[160];void system_interrupt_init(void)
{GIC_Init();//初始化GIC方便使用0处理器
}void system_interrupt_register(int num, irq_handler_t handler)
{interrupt_vector_table[num] = handler;
}void system_interrupt_handler(int num)
{if(interrupt_vector_table[num] != NULL){interrupt_vector_table[num]();}
}
4)interrupt.h
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_typedef void(*irq_handler_t)(void);
extern void system_interrupt_register(int num, irq_handler_t handler);
extern void system_interrupt_init(void);#endif
以及之前的代码
2.project
1)main.c
#include "beep.h"
#include "led.h"
#include "key.h"
#include "MCIMX6Y2.h"
#include "core_ca7.h"
#include "gpio.h"
#include "interrupt.h"int main(void)
{enable_clocks();system_interrupt_init();init_led();init_beep();init_key(); while(1){delay(0x0FFFFF);}return 0;
}
2)start.S
.global _start_start:ldr pc, =_reset_handlerldr pc, =_undefine_handlerldr pc, =_svc_handlerldr pc, =_prefetch_abort_handlerldr pc, =_data_abort_handlerldr pc, =_reserved_handlerldr pc, =_irq_handlerldr pc, =_fiq_handler_undefine_handler:ldr pc, =_undefine_handler_svc_handler:ldr pc, =_svc_handler_prefetch_abort_handler:ldr pc, =_prefetch_abort_handler_data_abort_handler:ldr pc, =_data_abort_handler_reserved_handler:ldr pc, =_reserved_handler_irq_handler:subs lr, lr, #4mrc p15, 4, r1, c15, c0, 0 //GIC获取基地址add r1, r1, #0x2000ldr r0, [r1, #0x0C]stmfd sp!, {r0-r12, lr}stmfd sp!, {r0, r1}cps #0x1fstmfd sp!, {lr}bl system_interrupt_handlerldmfd sp!, {lr}ldmfd sp!, {r0, r1}str r0, [r1, #0x10]ldmfd sp!, {r0-r12, pc}^_fiq_handler:ldr pc, =_fiq_handler_reset_handler://mrs r0, cpsr//bic r0, r0, #0x1F//orr r0, r0, #0x12 //irq//bic r0, r0, #(1 << 7)//msr cpsr, r0cps #0x12ldr sp, =0x86000000 //起始地址80000000,ram大小为512mb(20000000) 80000000~A0000000-1//mrs r0, cpsr//bic r0, r0, #0x1F//orr r0, r0, #0x1F //system//msr cpsr, r0 cps #0x1fcpsie ildr sp, =0x84000000 //给irq分配的栈指针空间bl _enable_icahcebl _set_vbarbl _bss_clearb main_enable_icahce:mrc p15, 0, r0, c1, c0, 0bic r0, r0, #(1 << 13)orr r0, r0, #(1 << 12)mcr p15, 0, r0, c1, c0, 0bx lr_set_vbar:ldr r0, =0x87800000mcr p15, 0, r0, c12, c0, 0bx lr_bss_clear:ldr r0, =__bss_startldr r2, =__bss_end
loop: mov r1, #0str r1, [r0]add r0, r0, #4cmp r0, r2blt loopbx lrfinished:b finished