Tiny 6410 按键中断驱动笔记

发布时间:2024-09-13  

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

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

  Tiny6410的底板有8个按键:

  

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

 

  从上图可知:

  EINT0 接 GPN0

  EINT1 接 GPN1

  EINT2 接 GPN2

  ENIT3 接 GPN3

  EINT4 接 GPN4

  EINT5 接 GPN5

  EINT19 接 GPL11

  EINT20 接 GPL12

 

知识点:

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

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

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

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

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

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

3. 中断设置流程

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

  EINT0    GPN0--->GPN15        GPL8--->GPL14         GPM0--->GPM4

  EINT1    GPA0--->GPA7           GPB0--->GPB6

  EINT2    GPC0--->GPC7

  EINT3    GPD0--->GPD5

  EINT4    GPF0--->GPF14

  EINT5    GPG0--->GPG7

  EINT6    GPH0--->GPH9

  EINT7    GPO0--->GPO15

  EINT8    GPP0--->GPP14

  EINT9    GPQ0--->GPQ9

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

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

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

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

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

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

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

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

No

Sources

Description

Group

0

 INT_EINT0

External interrupt 0 ~ 3 

VIC0

1

 INT_EINT1 

External interrupt 4 ~ 11  

VIC0

32

 INT_EINT2  

External interrupt 12 ~ 19     

VIC1

33

 INT_EINT3 

External interrupt 20 ~ 27    

VIC1

53

 INT_EINT4

External interrupt Group 1 ~ Group 9  

VIC1

 

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

  mrc p15,0,r0,c1,c0,0

  orr r0,r0,#(1<<24)'

      mcr p15,0,r0,c1,c0,0

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

 

 

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

 

  首先,mrc  p15,0,r0,c1,c0,0将协处理器cp15中op1=0,CRn=c1,CRm=c0,

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

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

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

  这样我们的VIC就能用了。

  然后就是开启总中断:

  mrs r0,cpsr

     bic r0,r0,#0x80

     msr cpsr_c,r0

 

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

  VICXINTSELECT:选择中断方式FIQ or IRQ。

  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:


    stmfd sp!, {r0-r3,r12,lr}


    ldr lr,=int_return


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


 


int_return:


    ldmfd sp!, {r0-r3,r12,lr}


    subs pc,lr,#4


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>