10.IMX6ULL外部中断

一、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 <opc1> <rt> <crn> <crm> <opc2>

​ MRC与MCR寄存器,对应于将内核数据移到寄存器中&&将寄存器数据移到内核数据。

​ 其中 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.复位中断函数

​ 向量表中有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
	dsb
	isb
	mcr p15 ,0 ,r0 ,c12 ,c0 ,0
	dsb
	isb
*/
    /*清除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_T
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值