main.c:
/*--------------------- led 灯------------------------------------------*/
#define rGPMCON (*(volatile unsigned *)(0x7F008820))
#define rGPMDAT (*(volatile unsigned *)(0x7F008824))
#define rGPMPUD (*(volatile unsigned *)(0x7F008828))
void msDelay(int time)
{
volatile unsigned int i,j;
for (i = 0; i < 2000; ++i)
{
for (j = 0; j < time; ++j);
}
}
void GPIO_Init(void)
{
rGPMCON = 0x11111;
rGPMPUD = 0x00;
rGPMDAT = 0xFFFFFFFF;
}
void LedTest(int pos)
{
if (4 <= pos) {
return;
}
rGPMDAT = 0xFFFFFFFF;
rGPMDAT = ~(1 << pos);
}
/*--------------------- interrut ------------------------------------------*/
#define rEINT0CON0 (*(volatile unsigned *)(0x7F008900))
#define rEIT0MASK (*(volatile unsigned *)(0x7F008920))
#define rEINT0PEND (*(volatile unsigned *)(0x7F008924))
#define rGPNCON (*(volatile unsigned *)(0x7F008830)) //n控制寄存器
#define rGPNDAT (*(volatile unsigned *)(0x7F008834)) //n数据寄存器
#define rGPNPUD (*(volatile unsigned *)(0x7F008838)) //n上拉/下拉寄存器
#define rVIC0VECTADDR_0 (*(volatile unsigned *)(0x71200100))
#define rVIC0VECTADDR_1 (*(volatile unsigned *)(0x71200104))
#define rVIC0INTENCLEAR (*(volatile unsigned *)(0x71200014))
#define rVIC0INTSELECT (*(volatile unsigned *)(0x7120000C))
#define rVIC0ADDRESS (*(volatile unsigned *)(0x71200F00))
#define rVIC0INTENABLE (*(volatile unsigned *)(0x71200010))
#define rVIC0IRQSTATUS (*(unsigned long volatile *)0x71200000)
extern unsigned long IrqHandle;
void key_interrut_1(void);
void key_interrut_2(void);
/*外部中断初始化 --按键*/
void key_interrut_init(void)
{
//配置为中断模式 0b10101010, rGPNCON 每两位代表一个GPIO口
rGPNCON = 0x0AAA;
rGPNPUD = 0x00;
//GPIO处于输入状态时,相应位处于管脚高低状态,输出时,设置此值控制管脚输出状态,中断状态时,读取没定义的值
rGPNDAT = 0x00;
//中断模式时,rGPN0 ~ rGPN5 使用 Ext interrut[0] ~ Ext Interrut[5]
//EINT控制寄存器,用来控制外部中断的触发方式.当前设置外部中断EINT以低电平方式触发 0x000
rEINT0CON0 &= ~((0x07 << 0) | (0x07 << 4) | (0x07 << 8));
//rEINT0CON0 = (0x07 << 0) | (0x07 << 4) | (0x07 << 8);
//中断屏蔽寄存器EIN0MASK,可读可写,写1屏蔽中断,写0使能中断.设置外部中断EINT0 ~ EINT5使能, 也就是将外部中断屏蔽寄存器置0
rEIT0MASK &= ~((0x01 << 0) | (0x01 << 1) | (0x01 << 2) | (0x01 << 3) | (0x01 << 4) | (0x01 << 5));
//清除外部中断挂载,也就是外部中断挂载寄存器置1. 此寄存器可读可写,读1表示发生中断,读0表没发生中断,写1表示清除外部中断
rEINT0PEND |= ((0x01 << 0) | (0x01 << 1) | (0x01 << 2) | (0x01 << 3) | (0x01 << 4) | (0x01 << 5));
}
/*vic init -- 系统中断初始化,并于外部中断关联起来*/
void vic_interrut_init(void)
{
//设置方式:1,关中断;2,配置中断;3,开中断
//1.确定设定中断为IRQ还是FIQ,配置前要先关中断。当前KEY只用到了系统中断INT_EINT0/INT_EINT1
rVIC0INTENCLEAR |= (0x01 << 0 | 0x01 << 1); //外部中断GROP0_0 ~ GROP0_5属于系统中断INT_EINT0/INT_EINT1
//2.设定中断类型为IRQ还是FIQ, 0-IRQ, 1-FIQ
rVIC0INTSELECT &= ~((0x01 << 0 | 0x01 << 1));
//3.清除系统中断标记,对应位写0或1,只能写32位
rVIC0ADDRESS &= ~((0x01 << 0 | 0x01 << 1));
//4.设定中断服务函数入口地址
rVIC0VECTADDR_0 = &IrqHandle;
rVIC0VECTADDR_1 = &IrqHandle;
//5.使能系统中断,对应位置1
rVIC0INTENABLE |= (0x01 << 0 | 0x01 << 1);
}
/*如果没有 __irq 关键字,那么此FUNC会变成普通的func,编译器不会作为中断函数保护现场,中断处理函数1*/
void key_interrut_1(void)
{
LedTest(0);
}
/*如果没有 __irq 关键字,那么此FUNC会变成普通的func,编译器不会作为中断函数保护现场,中断处理函数2*/
void key_interrut_2(void)
{
LedTest(1);
}
/* 中断号与中断处理服务函数映射结构 */
typedef void (* IRQFUNC)(void);
#define NULL (0)
#define true (1)
#define false (0)
typedef struct stIRQ
{
unsigned int u32Num;
IRQFUNC pFunc;
} IRQ_s;
#define IRQ_NUM_MAX (32)
IRQ_s stIrqArry0[IRQ_NUM_MAX] = { 0 };
/* 中断号与中断处理服务函数映射结构初始化 */
void InitIrqArry(void)
{
int i = 0;
for (i = 0; i < IRQ_NUM_MAX; ++i) {
stIrqArry0[i].u32Num = 1 << i;
stIrqArry0[i].pFunc = NULL;
}
stIrqArry0[0].pFunc = key_interrut_1;
stIrqArry0[1].pFunc = key_interrut_2;
}
#define EINT0OPTMATCH(__x__) \
(NULL != stIrqArry0[__x__].pFunc) && (rEINT0PEND & (1 << __x__))
//通过EINTXPEND寄存器确定由哪个外部中断触发
void EintDispatchIrq(void)
{
int i = 0;
for (i = 0; i < IRQ_NUM_MAX; ++i) {
if (EINT0OPTMATCH(i)) {
(* stIrqArry0[i].pFunc)();
//清除外部中断EINT,写1表示清除中断
rEINT0PEND = 1 << i;
}
}
}
//中断处理入口函数
void DoIrq(void)
{
EintDispatchIrq();
//清除内部(系统)中断VIC
rVIC0ADDRESS = 0;
}
//----------------------------------------------------------
int main(int argc, char *argv[])
{
GPIO_Init();
key_interrut_init();
vic_interrut_init();
InitIrqArry();
while (true) ;
return false;
}
---------------------
init.s:
.globl _start
.globl main
.globl DoIrq
.globl IrqHandle;
_start:
@-- set irq mode sp
mov r0, #0xd2
msr cpsr_cxsf,r0
ldr sp, =0x0c000F00
@-- set svc mode sp
mov r0, #0xd3
msr cpsr_cxsf, r0
ldr sp, =0x0c001000
@-- enable vic port
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<24)
mcr p15,0,r0,c1,c0,0
@-- enable irq
mrs r0,cpsr
bic r0,r0,#0x80
msr cpsr_c,r0
b main
IrqHandle:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
bl DoIrq
ldmfd sp!, {r0-r12, pc}^ @the ^ meaning mv spsr to cpsr, svc mode
@ mrs r0, spsr
@ msr cpsr, r0
@ mov pc, lr
--------------------------
Makefile:
################################################################
# FLAG
################################################################
APPEND_FLAG :=
#for warning: conflicting types for built-in function 'putchar'
APPEND_FLAG += -fno-builtin
#no use libc function
APPEND_FLAG += -nostdlib
#APPEND_FLAG += -march=armv6 -mcpu=arm1176jzf-s
APPEND_FLAG += -mfpu=vfp -mfloat-abi=hard
all:
arm-linux-gcc $(APPEND_FLAG) -o init.o -c init.s
arm-linux-gcc $(APPEND_FLAG) -o intterrut.o -c intterrut.c
arm-linux-ld -Tlink.lds -o inter.elf init.o intterrut.o
arm-linux-objcopy -O binary inter.elf inter.bin
arm-linux-objdump -D inter.elf > inter.dis
clean:
-rm -f ./*.o ./inter.*