第5課:ARM的中斷
而硬件中斷有內(nèi)部中斷,即中斷控制器中所列出的那些中斷。而外部中斷在中斷控制器里列的是EINT。
本文引用地址:http://m.butianyuan.cn/article/201611/316802.htm總共有60個(gè)中斷源,而在中斷控制器中列出32個(gè),還有一些子中斷在子中斷控制器里列出。這些控制器我們都是通過(guò)寄存器的某一位來(lái)控制。
中斷發(fā)生之后的流程:
1把下一條指令的地址放入LR,不過(guò)PC是5級(jí)流水線,所以LR的值要減去4才是正真的下一條指令的地址。
2把cpsr復(fù)制到中斷模式的spsr
3pc設(shè)置到0x18的位置,這個(gè)位置是中斷向量表,他指引程序跳轉(zhuǎn)到中斷處理程序。而中斷處理程序的作用是1:保存上下文2:繼續(xù)跳轉(zhuǎn)到中斷服務(wù)程序。
4退出的時(shí)候要恢復(fù)上下文,最重要的是把中斷的spsr復(fù)制到cpsr
以下介紹下用到的寄存器:
1 SRCPND 它只要發(fā)送一次中斷,該相應(yīng)位就變成1。即使那個(gè)中斷源被屏蔽了,這個(gè)位還是置1.
2 SUBSRCPND 子中斷源未決寄存器。
3 INTMSK 中斷源屏蔽
4 INTSUBMSK 子中斷源屏蔽
5 INTOFFSET 讀這個(gè)寄存器 方便讀出是哪個(gè)中斷,用10進(jìn)制表示。
以下來(lái)做個(gè)例子:
在主程序中小燈一直閃,然后串口接受到數(shù)據(jù),產(chǎn)生中斷,然后回顯數(shù)據(jù)。
這個(gè)crt0.s 是文件的入口,該程序放在0x0的位置,所以一開(kāi)始進(jìn)入的是中斷向量表
.extern main
.extern EINT_Handle
.externinit_irq
.text
.global _start
_start:
bReset
HandleUndef:
bHandleUndef
HandleSWI:
bHandleSWI
HandlePrefetchAbort:
bHandlePrefetchAbort
HandleDataAbort:
bHandleDataAbort
HandleNotUsed:
bHandleNotUsed
bHandleIRQ@0x18
HandleFIQ:
bHandleFIQ
Reset:
ldr r0, =0x53000000 @ WATCHDOG close
mov r1, #0x0
str r1, [r0]
msr cpsr_c, #0xd2 @進(jìn)入中斷模式
ldr sp, =3072 @設(shè)置中斷模式的sp
msr cpsr_c, #0xd3 @進(jìn)入svc模式
ldr sp, =4096
bl init_irq
msr cpsr_c, #0x53 @把svc的i位置0
ldr lr, =halt_loop @設(shè)置返回地址
ldr pc, =main @ 進(jìn)入主程序
HandleIRQ:@中斷處理程序
sub lr, lr, #4
stmdb sp!, { r0-r12,lr } @ 保存環(huán)境
ldr lr, =int_return
ldr pc, =ISR_Handle @進(jìn)入中斷服務(wù)程序
int_return:
ldmia sp!, { r0-r12,pc }^ @恢復(fù)環(huán)境
halt_loop:
bhalt_loop
這個(gè)是程序的主框架。
以下是中斷服務(wù)程序int.c
#include "addr.h"
void init_irq()
{
INTMSK = ~(1<<28);
INTMOD = 0;
INTSUBMSK = 0xfffffffe;
}
void EINT_Handle()
{
unsigned long oft = INTOFFSET;
if(oft == 28){
if(SUBSRCPND & 1){
UTXH0 = URXH0;//這里RX里面的數(shù)據(jù)一定要讀走,不然中斷有問(wèn)題。不然會(huì)根據(jù)RX interpute type 選擇模式的不同有不同的效果。
SUBSRCPND |= 1;//這里清中斷,要置1,清中斷有一定順序。從src子到src再到int
SRCPND |= 1<
}
}
以下是main主程序:主要初始化燈和串口,執(zhí)行小燈閃
#include"addr.h"
#define UART_CLK 50000000
#define UART_BAUD_RATE 115200
#define UART_BRD (int)(UART_CLK/(UART_BAUD_RATE *16))-1
void wait(int time)
{
do{
time--;
}
while(time>0);
}
void init_uart()
{
GPHCON |=0xa0;
GPHUP = 0x0c;
ULCON0 = 0x3;
UCON0 = 0x5+ (1<<8);
UFCON0 = 0;
UMCON0 = 0;
UBRDIV0 = UART_BRD;
}
void init_led()
{
GPECON = GPE12_out|GPE13_out;
}
void uart_write(char *data)
{
while (*data !=