嵌入式linux-ARM体系结构及接口技术,ARM中断机制,外部中断的配置,协处理器指令修改异常向量表起始地址,清中断标志
程序员文章站
2022-03-04 15:25:40
文章目录1,中断硬件机制2,外部中断的配置2.1,查看原理图2.2,配置I/O口为中断模式2.3,配置中断为下降沿触发2.4,使能外部中断1,中断硬件机制2,外部中断的配置2.1,查看原理图2.2,配置I/O口为中断模式2.3,配置中断为下降沿触发2.4,使能外部中断......
文章目录
1,ARM中断机制
1.1,中断硬件机制
1.2,中断过程
1.3,中断源
Exynos4412中断控制器包含160个中断控制源,分三类分别是: | |
用于CPU之间通信的SGI (Software Generated Interrupt) |
|
专用于特定CPU核的PPI (Private Peripheral Interrupt) |
|
被多个CPU核共享的SPI (Shared Peripheral Interrupt) |
1.4,中断控制器
中断源分发给不同的CPU.
每个中断都有一个唯一对应的ID号,当中断发生时,该ID号会写入一个特定的寄存器。
中断处理程序可以读取该寄存器来决定该调用哪个具体的中断处理函数。
2,外部中断的配置
2.1,查看原理图
可以看到按键k2,挂载在GPX1_1引脚上,对应XEINT9
2.2,外部,配置芯片管脚工作模式
2.2.1,配置I/O口为中断模式
GPX1CON = (GPX1CON & ~(0x0f << 4) | (0x0f << 4)); // 设置管脚为中断模式
2.2.2,配置中断为下降沿触发
EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 4)) | (0X02 << 4); //设置中断触发方式为下降沿
2.2.3,使能外部中断
EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1); //管脚中断使能(一关)
2.3,内部,设置功能模块(中断控制模块 GIC)
2.3.1,查GIC中断表,找出对应的中断端口号和ID号
XEINT9对应的中断端口号是25,ID号是57
2.3.2,设置GIC中断使能
ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 25); //使能对应中断(二关)
2.3.3,分发配置
根据样例选用默认设置
//#define ICDIPTR17_CPU0 (*(volatile unsigned int *)0x10490844) //分发配置,根据样例选用默认设置 #define ICDIPTR14_CPU0 (*(volatile unsigned int *)0x10490838) //分发配置,根据样例选用默认设置
//ICDIPTR17_CPU0 = 0x01010101; ICDIPTR14_CPU0 = 0x01010101;
ICDIPTR17_CPU0 = 0x01010101; //分发器中断使能 (三关),根据样例选用默认设置
2.3.4,分发总使能
ICDDCR = ICDDCR | 0X01; //分发器中断使能 (三关)
2.3.5,CPU外部中断借口使能
ICCICR_CPU0 = ICCICR_CPU0 | 0x01; //CPU接口中断使能(四关)
2.3.6,设置CPU的中断优先级门限值
ICCPMR_CPU0 = 0xff; //设置CPU的中断优先级门限值,当前为最低,所有的中断都可以处理
3,中断处理
3.1,协处理器指令修改异常向量表起始地址
- CPU规定的异常向量表的地址是从0x00开始的,其中中断异常的地址是0x18
- 但是想开发版中下载程序的时候我们会制定一个起始地址,这样异常向量表的起始地址就不是0x00了
- 所以,需要重新制定模拟的异常向量表的起始地址
MRC Pn,op1,Rd,CRn,CRm,op2 //mrc p15,0,r0,c1,c0,0 读入cp15的c1寄存器的内容到r0中
MCR Pn,op1,Rd,CRn,CRm,op2 //mcr p15,0,r0,c1,c0,0 写r0内容到cp15的c1寄存器中
通过协处理器设置异常向量表的起始地址为0x40008000
@ set Vector Base Address 为0x40008000 ldr r0,=0x40008000 mcr p15,0,r0,c12,c0,0
3.2,异常向量表
_start: b start_code
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
irq_handler:
sub lr,lr,#4
stmfd sp!,{r0-r12,lr} @保护现场
bl do_irq
irq_handler_end:
ldmfd sp!,{r0-r12,pc}^ @恢复现场
软中断SWI中,lr既是返回地址,中断IRQ中lr-4才是返回地址
3.3,中断处理函数
3.3.1,获取中断ID号
int irq_num; irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号
3.3.2,清GPIO的中断标志
EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志
3.3.3,清GCI中断标志
ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1的中断标志
3.3.4,结束中断
ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断
3.3.5,中断处理函数
void do_irq() { /* 获取中断ID号,并根据不同的中断号做相应的处理 */ int irq_num; irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号 switch(irq_num) { case 57: uart2_putc('k'); uart2_putc('2'); EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志 ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1的中断标志 break; default: uart2_putc('d'); } /*结束中断 将处理完成的中断ID号写入该寄存器,则表示相应的中断处理完成*/ ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断 }
4,例
4.1,start.S
.global 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_handler
_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
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 /* 跳转到c程序的main函数 */
irq_handler:
sub lr,lr,#4 @软中断SWI中,lr既是返回地址,中断IRQ中lr-4才是返回地址
stmfd sp!,{r0-r12,lr} @入栈保护现场
bl do_irq @调用C函数
irq_handler_end:
ldmfd sp!,{r0-r12,pc}^ @出栈恢复现场
delay1s:
ldr r4,=0x1ffffff
delay1s_loop:
sub r4,r4,#1
cmp r4,#0
bne delay1s_loop
mov pc,lr
.align 4
/**** swi_interrupt handler ****/
stacktop: .word stack+4*512
.data
stack:
.space 4*512
.end
4.2,main.c
#define GPA1CON (*(volatile unsigned int *)0x11400020) //volatile 确保本条指令不会因编译器的优化而省略 #define ULCON2 (*(volatile unsigned int *)0x13820000) //串口2线控:数据位,停止位,奇偶校验位 #define UCON2 (*(volatile unsigned int *)0x13820004) //串口2读取控制:串口读的方式(如:轮询/中断等),写的方式 #define UBRDIV2 (*(volatile unsigned int *)0x13820028) //串口2波特率设置 #define UFRACVAL2 (*(volatile unsigned int *)0x1382002c) //串口2波特率设置 #define UTXH2 (*(volatile unsigned int *)0x13820020) //串口2发送缓存器 #define URXH2 (*(volatile unsigned int *)0x13820024) //串口2接受缓存器 #define UTRSTAT2 (*(volatile unsigned int *)0x13820010) //串口2状态寄存器 #define GPA0CON (*(volatile unsigned int *)0x11400000) //volatile 确保本条指令不会因编译器的优化而省略 #define ULCON0 (*(volatile unsigned int *)0x13800000) //串口0线控:数据位,停止位,奇偶校验位 #define UCON0 (*(volatile unsigned int *)0x13800004) //串口0读取控制:串口读的方式(如:轮询/中断等),写的方式 #define UBRDIV0 (*(volatile unsigned int *)0x13800028) //串口0波特率设置 #define UFRACVAL0 (*(volatile unsigned int *)0x1380002c) //串口0波特率设置 #define UTXH0 (*(volatile unsigned int *)0x13800020) //串口0发送缓存器 #define URXH0 (*(volatile unsigned int *)0x13800024) //串口0接受缓存器 #define UTRSTAT0 (*(volatile unsigned int *)0x13800010) //串口0状态寄存器 #define GPX1CON (*(volatile unsigned int *)0x11000C20) // #define EXT_INT41_CON (*(volatile unsigned int *)0x11000E04) //外部中断1触发方式 #define EXT_INT41_MASK (*(volatile unsigned int *)0x11000f04) //使能外部中断 #define ICDISER1_CPU0 (*(volatile unsigned int *)0x10490104) //GIC中断使能 //#define ICDIPTR17_CPU0 (*(volatile unsigned int *)0x10490844) //分发配置,根据样例选用默认设置 #define ICDIPTR14_CPU0 (*(volatile unsigned int *)0x10490838) //分发配置,根据样例选用默认设置 #define ICDDCR (*(volatile unsigned int *)0x10490000) //全局外部中断使能 #define ICCICR_CPU0 (*(volatile unsigned int *)0x10480000) //CPU外部中断接口使能 #define ICCPMR_CPU0 (*(volatile unsigned int *)0x10480004) //优先级设定 #define ICCIAR_CPU0 (*(volatile unsigned int *)0x1048000c) //获取中断ID号 #define EXT_INT41_PEND (*(volatile unsigned int *)0x11000f44) //清GPIO的中断标志 #define ICDICPR1_CPU0 (*(volatile unsigned int *)0x10490284) //清GIC[31:0]的中断标志 #define ICCEOIR_CPU0 (*(volatile unsigned int *)0x10480010) //结束中断 #define GPX2CON (*(volatile unsigned int *)0x11000C40) // #define GPF3CON (*(volatile unsigned int *)0x11000C20) // #define GPX1DATA (*(volatile unsigned int *)0x11000C24) // #define GPX2DATA (*(volatile unsigned int *)0x11000C44) // #define GPF3DATA (*(volatile unsigned int *)0x114001E4) // #define GPX2_7_U (GPX2DATA |= (0X01 << 7)) //LED2 #define GPX2_7_D (GPX2DATA &= ~(0X01 << 7)) #define GPX1_0_U (GPX1DATA |= (0X01 << 0)) //LED3 #define GPX1_0_D (GPX1DATA &= ~(0X01 << 0)) #define GPF3_4_U (GPF3DATA |= (0X01 << 4)) //LED4 #define GPF3_4_D (GPF3DATA &= ~(0X01 << 4)) #define GPF3_5_U (GPF3DATA |= (0X01 << 5)) //LED5 #define GPF3_5_D (GPF3DATA &= ~(0X01 << 5)) void uart_init(void) { //4.设置波特率为115200 //For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz,UBRDIVn and UFRACVALn are: //DIV_VAL = (SCLK_UART/(bps * 16)) - 1 //DIV_VAL = (100000000/(115200 * 16)) – 1 //= 54.253 – 1 //= 53.253 //UBRDIVn = 53 (integer part of DIV_VAL) //UFRACVALn/16 = 0.253 //Therefore, UFRACVALn = 4 //1.配置GPA1CON寄存器中的UART2 GPA1_0 UART_2_RXD // GPA1_1 UART_2_TXD GPA1CON &= 0xffffff00; GPA1CON |= 0x00000022; //2.配置ULCON2寄存器 串口2 8位数据位,1位停止位,无奇偶校验 ULCON2 &= 0Xffffffc0; ULCON2 |= 0x00000003; //3.配置UCON2寄存器 通过轮询(polling)的模式读取串口数据 通过轮询(polling)的模式往串口写入数据数据 UCON2 &= 0xfffffff0; UCON2 |= 0x00000005; UBRDIV2 = 53; UFRACVAL2 = 4; //1.配置GPA0CON寄存器中的UART0 GPA0_0 UART_0_RXD // GPA0_1 UART_0_TXD GPA0CON &= 0xffffff00; GPA0CON |= 0x00000022; //2.配置ULCON0寄存器 串口0 8位数据位,1位停止位,无奇偶校验 ULCON0 &= 0Xffffffc0; ULCON0 |= 0x00000003; //3.配置UCON0寄存器 通过轮询(polling)的模式读取串口数据 通过轮询(polling)的模式往串口写入数据数据 UCON0 &= 0xfffffff0; UCON0 |= 0x00000005; //4.设置波特率为115200 UBRDIV0 = 53; UFRACVAL0 = 4; } void interrupt_init() { //* key2 GPX1_1 EINT9 SPIPORT:25 INTID:57 * //*******外 配置芯片管脚工作模式************************************** //1.配置GPX1CON寄存器中的WAKEUP_INT1_1 GPX1_1 GPX1CON = (GPX1CON & ~(0x0f << 4)) | (0x0f << 4); //2.通过EXT_INT41_CON1 配置外部中断1为下降沿触发 EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 4)) | (0X02 << 4); //3.使能外部中断 EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 1)) | (0X00 << 1); //*******内 功能块设置************************************** //4.设置GIC中断使能 ICDISER1_CPU0 GPX1_1的中断,即XEINT9 中断端口号为25 ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 25); //5.根据样例选用默认设置 //ICDIPTR17_CPU0 = 0x01010101; ICDIPTR14_CPU0 = 0x01010101; //6.分发总使能 ICDDCR = ICDDCR | 0X01; //7.CPU外部中断借口使能 ICCICR_CPU0 = ICCICR_CPU0 | 0x01; //8.设置CPU0的优先级门槛为最低 ICCPMR_CPU0 = 0xff; //* key3 GPX1_2 EINT10 SPIPORT:26 INTID:58 //*******外 配置芯片管脚工作模式************************************** //1.配置GPX1CON寄存器中的WAKEUP_INT1_2 GPX1_2 GPX1CON = (GPX1CON & ~(0x0f << 8)) | (0x0f << 8); //2.通过EXT_INT41_CON2 配置外部中断1为下降沿触发 EXT_INT41_CON = (EXT_INT41_CON & ~(0X07 << 8)) | (0X02 << 8); //3.使能外部中断 EXT_INT41_MASK = (EXT_INT41_MASK & ~(0X01 << 2)) | (0X00 << 2); //*******内 功能块设置************************************** //4.设置GIC中断使能 ICDISER1_CPU0 GPX1_2的中断,即XEINT10 中断端口号为26 ICDISER1_CPU0 = ICDISER1_CPU0 | (0x01 << 26); //5.根据样例选用默认设置 //ICDIPTR17_CPU0 = 0x01010101; ICDIPTR14_CPU0 = 0x01010101; //6.分发总使能 ICDDCR = ICDDCR | 0X01; //7.CPU外部中断借口使能 ICCICR_CPU0 = ICCICR_CPU0 | 0x01; //8.设置CPU0的优先级门槛为最低 ICCPMR_CPU0 = 0xff; } void led_init() { GPX2CON = (GPX2CON & ~(0X0F << 28)) | (0X01 << 28); //设置LED2灯的配置寄存器 GPX2CON7为输出状态 GPX1CON = (GPX1CON & ~(0X0F << 0)) | (0X01 << 0); //设置LED3灯的配置寄存器 GPX1CON0为输出状态 GPF3CON = (GPF3CON & ~(0X0F << 16)) | (0X01 << 16); //设置LED4灯的配置寄存器 GPF3CON4为输出状态 GPF3CON = (GPF3CON & ~(0X0F << 20)) | (0X01 << 20); //设置LED5灯的配置寄存器 GPF3CON5为输出状态 } void uart0_putc(char c) { while(1) { if(UTRSTAT0 && 0X02) break; } UTXH0 = c; } char uart0_getc(char *c) { while(1) { if(UTRSTAT0 && 0X01) break; } *c = URXH0; uart0_putc(*c); return *c; } void uart2_putc(char c) { while(1) { if(UTRSTAT2 && 0X02) break; } UTXH2 = c; } void do_irq() { int irq_num; irq_num = ICCIAR_CPU0 & 0X3ff; //获取中断ID号 switch(irq_num) { case 57: //LED2闪烁 GPX2_7_U; delay1s(); GPX2_7_D; EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 1); //清GPX1_1中断标志 ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 25); //清GCI中GPX1_1的中断标志 break; case 58: uart2_putc('3'); EXT_INT41_PEND = EXT_INT41_PEND | (0X01 << 2); //清GPX1_2中断标志 ICDICPR1_CPU0 = ICDICPR1_CPU0 | (0x01 << 26); //清GCI中GPX1_2的中断标志 break; default: uart2_putc('d'); } ICCEOIR_CPU0 = (ICCEOIR_CPU0 & ~0x3ff) | irq_num; //结束对应的中断 } int main(void) { uart_init(); led_init(); interrupt_init(); char c; while(1) { uart0_getc(&c); uart2_putc('b'); delay1s(); delay1s(); } return 0; }
本文地址:https://blog.csdn.net/m0_37542524/article/details/85808651