ok6410 按键中断点LED灯

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.*


你可能感兴趣的:(ok6410 按键中断点LED灯)