Tiny 6410 按键中断驱动笔记


1.先查看《Tiny6410SDK-1103底板原理图》,找到按键部分:

  从上图可知,当按键按下时,相当于接地,即低电平,从而产生一个由高电平到低电平的跳变。

  Tiny6410的底板有8个按键:

2.查看《Tiny6410-1170CPU核心板原理图》,找到EINT0的连接图:

  从上图可知:

  EINT0GPN0

  EINT1GPN1

  EINT2GPN2

  ENIT3GPN3

  EINT4GPN4

  EINT5GPN5

  EINT19GPL11

  EINT20GPL12

知识点:

s3c6410外部触发的中断就是外部中断,由s3c6410内部触发的是内部中断,像watchdog就是内部中断,像key,wm9717触发的就是外部中断

  外部中断从外设到cpu的具体流程:

  外设------>GPIO------>VIC------>ARM1176

  我们编写关于中断的程序也是这个过程:

  配置外设------>配置GPIO------>配置VIC------>配置ARM协处理器等

  其实就是要打造一个通路能够让中断的电平变化能顺顺利利的传送到ARM里!

3.中断设置流程

  外设都是连到GPIO的。s3c6410具有187个多功能I/O端口,其实有127个用于外部中断。这127个引脚可以分为10个分组:

  EINT0GPN0--->GPN15GPL8--->GPL14GPM0--->GPM4

  EINT1GPA0--->GPA7GPB0--->GPB6

  EINT2GPC0--->GPC7

  EINT3GPD0--->GPD5

  EINT4GPF0--->GPF14

  EINT5GPG0--->GPG7

  EINT6GPH0--->GPH9

  EINT7GPO0--->GPO15

  EINT8GPP0--->GPP14

  EINT9GPQ0--->GPQ9

  每个引脚可以对应一个外部中断。那么当外部中断电平变化传GPIO里,除了对应端口的哪几个寄存器(CONPUDetcGPIO里又有哪些寄存器会

  对这个中断信号造成影响呢?看下面:

  EINTXCON:配置触发方式,低电平,高电平,上升沿,下降沿。

  EINTXPEND:这个现在用不到,一会儿中断处理程序会用到,这个是pendingregister.

  EINTXMASK:这里可以屏蔽某个外部中断,要通过需要clear一下对应的中断位。默认是全屏蔽的。

  EINTXFLTCON:这里设置滤波方式,可以去毛刺。

  我们这里要设置的是EINTXCONEINTXMASKEINTXFLTCON。这样我们的中断信号就可以顺利通过GPIO,然后就是VIC向量中断控制器了。

  上面说的这些外部中断在GPIO里分成了九组,具体反应到VIC里他们占用中断号如下:

No

Sources

Description

Group

0

INT_EINT0

Externalinterrupt0~3

VIC0

1

INT_EINT1

Externalinterrupt4~11

VIC0

32

INT_EINT2

Externalinterrupt12~19

VIC1

33

INT_EINT3

Externalinterrupt20~27

VIC1

53

INT_EINT4

ExternalinterruptGroup1~Group9

VIC1

  这里我们使用VIC,当然要先开启VIC,这个是在协处理器里设置的VE

  mrcp15,0,r0,c1,c0,0

  orrr0,r0,#(1<<24)"

mcrp15,0,r0,c1,c0,0

  主要是通过CP15协处理器特定的寄存器来控制VIC的使能:查看arm6410手册,arm1176JZF-S.pdf3-14页如下图所示,

  因为op1=0,CRn=c1,CRm=c0,op2=0,跳转到3-44页图所示,查看对应寄存器。

  首先,mrcp15,0,r0,c1,c0,0将协处理器cp15op1=0,CRn=c1,CRm=c0,

  op2=0所对应的寄存器的值传给r0寄存器。

  其次,orrr0,r0,#(1<<24)将上面得到的r0寄存器的值与1左移24位得到的值进行按位或运算,将得到的结果放入r0中。

  最后,mcrp15,0,r0,c1,c0,0将运算后的r0的值重新放回cp15协处理器对应的寄存器当中。

  这样我们的VIC就能用了。

  然后就是开启总中断:

  mrsr0,cpsr

bicr0,r0,#0x80

msrcpsr_c,r0

  然后是VIC的设置,几个重要的寄存器:

  VICXINTSELECT:选择中断方式FIQorIRQ

  VICXVECTADDR:设置中断处理程序的地址。

  VICXINTENABLE:使能GPIO传过来的中断信号。

  其实设置到这里外部中断就能正确运行了,但是还有许多别的寄存器,比如设置什么优先级的。

  ARM得知来了个中断,就和VIC进行一系列的握手,得到VICADDRESS,就开始执行我们的中断处理程序了。最后要清除一下EINTXPEND和VICXADDRESS

4.程序实现:

inter.s:

.text
.code 32
.global _start
.global asm_handle_k1_irq
.extern interrupt_test
.extern handle_k1_irq

_start:

    @disable watch dog 
    ldr r0, =0x7E004000
    mov r1, #0
    str r1, [r0]    
 
    @enable vic 
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#(1<<24)
    mcr p15,0,r0,c1,c0,0

    @enable interrupt
    mrs r0,cpsr
    bic r0,r0,#0x80
    msr cpsr_c,r0

    ldr sp, = 0x0C001000

    @sp_irq mode 
    msr cpsr_cxsf,#0xd2
    ldr sp, = 0x0C001000
    @return back to svc mode
    msr cpsr_cxsf, #0x13

    bl interrupt_test

loop:
    b loop

asm_handle_k1_irq:
    stmfd sp!, {r0-r3,r12,lr}
    ldr lr,=int_return
    bl handle_k1_irq

int_return:
    ldmfd sp!, {r0-r3,r12,lr}
    subs pc,lr,#4

inter_func.c:

#define GPKCON0 *((volatile unsigned int*)0x7F008800)

#define GPKDAT *((volatile unsigned int*)0x7F008808)

#define GPKPUD *((volatile unsigned int*)0x7F00880C)

#define GPNCON *((volatile unsigned int*)0x7F008830)

#define GPNPUD *((volatile unsigned int*)0x7F008838)

#define EINT0CON0 *((volatile unsigned int*)0x7F008900)

#define EINT0MASK *((volatile unsigned int*)0x7F008920)

#define EINT0PEND *((volatile unsigned int*)0x7F008924)

#define EINT0FLTCON0 *((volatile unsigned int*)0x7F00891C)

#define VIC0INTSELECT *((volatile unsigned int*)0x7120000C)

#define VIC0VECTADDR  *((volatile unsigned int*)0x71200100)  

#define VIC0INTENABLE *((volatile unsigned int*)0x71200010)  

#define VIC0INTENCLEAR *((volatile unsigned int*)0x71200014)  

#define VIC0ADDRESS *((volatile unsigned int*)0x71200F00)  

#define VIC1ADDRESS *((volatile unsigned int*)0x71300F00) 

typedef void (isr) (void);

extern void asm_handle_k1_irq();

void led_init()
{

    //init gpkcon

    GPKCON0 &= 0x0000ffff;

    GPKCON0 |= 0x11110000;

    //set output

    //light led1

    GPKDAT = 0xffef;

    //set pull-up register

    //GPKPUD = 0x000aa00;

}

void handle_k1_irq()
{

    //reverse led1
    GPKDAT ^= 0x0010;

    // clear K1 irq  

    EINT0PEND = 1;
 
    //clear irq

    VIC0ADDRESS = 0;

    VIC1ADDRESS = 0;
}

void key_io_init()
{

    //configure k1 as Ext.Interrupt

    GPNCON &= (~0x03);

    GPNCON |= 0x02;

    GPNPUD &= ~(0x3);


    //configure k1 as falling edge trigged

    EINT0CON0 &= (~0x03);

    EINT0CON0 |= 0x3;

    //EINT0FLTCON0 |= 0x40;

    //Enable EINT0 irq

    EINT0MASK &= (~0x1);

    // Select INT_EINT0 mode as irq  

    VIC0INTSELECT = 0;

    // init the isr addr  

    isr** isr_array = (isr**)(0x71200100);

    isr_array[0] = (isr*)asm_handle_k1_irq;


    //EINT0PEND = 0xffffffff;  

    //VIC0INTENCLEAR = 0xffffffff;


    //enable 

    VIC0INTENABLE |= 0x01;

}


void interrupt_test()
{

    led_init();

    key_io_init();

}

makefile:

CC=arm-linux-gcc

LD=arm-linux-ld

OBJCOPY=arm-linux-objcopy      

CFLAG=-c

LDFLAG=-e _start -Ttext 0x0c000000

inter.bin: inter

    $(OBJCOPY) -O binary $< $@

inter: inter.o inter_func.o

    $(LD) $(LDFLAG) $? -o $@

inter.o:inter.s                

    $(CC) $(CFLAG) $< -o $@    

inter_func.o:inter_func.c          

    $(CC) $(CFLAG) $< -o $@

clean:

    rm *.o

    rm inter

rm inter.bin

5.问题记录

(1)设置GPNCON时,网上的文章写成GPNCON&=(~0x2),实际上应该是GPNCON&=(~0x03),导致中断无反应。

(2)直接设置VIC向量的地址为中断逻辑,忘记要在中断模式下进行堆栈的保存与恢复,导致程序只能触发一次中断。

asm_handle_k1_irq:

stmfdsp!,{r0-r3,r12,lr}

ldrlr,=int_return

blhandle_k1_irq@一开始直接作为VIC向量的地址

int_return:

ldmfdsp!,{r0-r3,r12,lr}

subspc,lr,#4

优质内容筛选与推荐>>
1、为什么要从PHP转向Go,及满足于使用MySQL
2、Nature:人工智能研究的盲点
3、MySQL优化案例一则
4、pandas几个小函数
5、如何不出国门走进NLP学术前沿


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn