首先声明,此文章是基于对国嵌视频教程中tiny6410有关视频教程的总结,为方便大家的复习。再次予以感谢,感谢国嵌各位老师为我们提供如此好的视频教程,为对于想要迈入嵌入式大门却迟迟找不到合适方法的学子们指引一条光明的方向。好了,接下来步入正题,此处将介绍tiny6410 按键驱动程序的设计。
首先,先来介绍一下S3C2440的中断,它包含60个中断源,如下图所示:
同时一些中断还包含一些子中断,如下图所示,如串口中断包含串口发送,串口接收,串口错误等中断。
s3c2440的中断处理流程如下所示:
首先,我们来简要对上图进行简要介绍,先介绍不含子中断的情况:对于不含子中断的中断(后面都用NS中断表示),当NS中断发生时,会设置SRCPND标志,然后判断此中断是否为FIQ中断,若成立,则进行FIQ中断处理子程序,反之则判断此中断是否为可屏蔽中断,若为可屏蔽中断,则结束中断。反之若为不可屏蔽中断(即中断屏蔽位无效),则进入中断优先级判断,然后设置INTPND标志,通过优先级的顺序,执行中断处理子程序。
对于包含子中断的中断而言,当中断发生时,先设置SUBSRCPND标志,然后判断子中断是否为可屏蔽中断,若为可屏蔽中断,则中断停止,若为不可屏蔽中断,则进行下一步操作,后面操作与NS中断相同。
S3C6410支持64个中断源,6410中断与2440中断最主要区别是多出了VIC矢量中断控制器,如下图所示:
使用VIC和不适用VIC的区别如下:
1 不使用VIC情况:
2 使用VIC情况:
下面通过程序来说明如何使用VIC中断处理,程序代码来自(光盘4\实验代码\3-4-1\src\main.c):
main.c
/**********************************************************
*实验要求: 按键中断方式操作蜂鸣器发声。
*功能描述: 本实验代码针对tiny6410开发板,并兼容mini6410。
* tiny6410的8个按键资源如下:
* KEYINT1 -- GPN0 -- XEINT0
* KEYINT2 -- GPN1 -- XEINT1
* KEYINT3 -- GPN2 -- XEINT2
* KEYINT4 -- GPN3 -- XEINT3
* KEYINT5 -- GPN4 -- XEINT4
* KEYINT6 -- GPN5 -- XEINT5
* KEYINT7 -- GPL11-- XEINT
* KEYINT8 -- GPL12-- XEINT5
* 以上EINT资源均是EINT Group 0的资源。
* 在程序中使用了KEYINT1、KEYINT3和KEYINT5,分别
* 设置为低电平中断、下降沿中断和双沿中断,在中断发
* 生后会由蜂鸣器发出一段固定频率的声音。
*日 期: 2011-3-10
*作 者: 国嵌
**********************************************************/
#include "gpio.h"
#include "def.h"
#include "system.h"
#include "intc.h"
//给指定地址赋整数值
#define Outp32(addr, data) (*(volatile u32 *)(addr) = (data))
//读出指定地址的值
#define Inp32(addr) (*(volatile u32 *)(addr))
//GPIO
#define GPIO_BASE (0x7F008000)
//oGPIO_REGS类型在 gpio.h 中定义
#define GPIO (( volatile oGPIO_REGS *)GPIO_BASE)
//函数声明
void __irq Isr_Eint(void);
void delay(int times);
void BuzzerPortInit(void);
void BuzzerPlay(u32 count);
void KeyIntPortInit(u32 uKey, u32 uType);
void EintClrPend(u32 uEINT_No );
void EintDisMask(u32 uEINT_No );
void KeyEIntInit(void);
/*
* 程序入口
* */
int main(void)
{
SYSTEM_EnableVIC();
SYSTEM_EnableIRQ();
INTC_Init();
BuzzerPortInit();
KeyEIntInit();
while(1);
}
/*
* 延时函数
* */
void delay(int times)
{
int i;
for(;times>0;times--)
for(i=0;i<3000;i++);
}
/*
* 初始化蜂鸣器端口
* @ 这里仅仅是把对应端口GPF14初始化为Output,没有使用
* PWM TOUT的特殊功能
* */
void BuzzerPortInit(void)
{
u32 uConValue;
uConValue = GPIO->rGPIOFCON;
uConValue &= ~(0x3<<28);
uConValue |= 0x1<<28;
GPIO->rGPIOFCON = uConValue;
}
/*
* 调节对应端口电平,使蜂鸣器发出一段声音
* */
void BuzzerPlay(u32 count)
{
while(count--)
{
GPIO->rGPIOFDAT |= 0x1<<14;
delay(10);
GPIO->rGPIOFDAT &= ~(0x1<<14);
delay(10);
}
}
/*
* 按键中断处理函数,在其中使蜂鸣器发出一段声音
* */
void __irq Isr_Eint(void)
{
//清除中断悬起位
EintClrPend(0);
EintClrPend(2);
EintClrPend(4);
BuzzerPlay(3);
//清除rVIC0ADDR,该寄存器按位记录哪个VIC0中断源曾发生了中断
Outp32(rVIC0ADDR, 0);
}
/*
* 初始化KeyInt对应的端口及EINT的类型
* @uKey -- Tiny6410上有8个按键,uKey对应按键1-6
* @uType -- 中断类型
* 注意按键(1,2)、(3,4)、(5,6)中断类型由于使用相同寄存器位
* 设置,所以它们的中断类型两两一致。
* */
void KeyIntPortInit(u32 uKey, u32 uType)
{
u32 uConValue;
if (uKey==0||uKey>6)
return;
//设置对应IO为特殊功能 -- EINT
uConValue = GPIO->rGPIONCON;
uConValue &= ~(0x3<<((uKey-1)<<1));
uConValue |= 0x2<<((uKey-1)<<1);
GPIO->rGPIONCON = uConValue;
//设置对应IO为上下拉除能
uConValue = GPIO->rGPIONPUD;
uConValue &= ~(0x3<<((uKey-1)<<1));
uConValue |= 0x0<<((uKey-1)<<1);
GPIO->rGPIONPUD = uConValue;
//设置对应EINT为@uType 类型中断
uConValue = GPIO->rEINT0CON0;
uConValue &= ~(0x7<<(((uKey-1)/2)<<2));
uConValue |= uType<<(((uKey-1)/2)<<2);
GPIO->rEINT0CON0 = uConValue;
}
/*
* 清除中断悬起位,方法是向对应位写1
* */
void EintClrPend(u32 uEINT_No )
{
GPIO->rEINT0PEND = 1<<uEINT_No;;
}
/*
* 除能Eint[27:0]中断屏蔽位
* */
void EintDisMask(u32 uEINT_No )
{
u32 uConValue;
uConValue = GPIO->rEINT0MASK;
uConValue &= ~(0x1<<uEINT_No);
GPIO->rEINT0MASK = uConValue;
}
/*
* 初始化EInt,将EINT Group 0中的EINT0,1设置为Low_Level、
* EINT2,3设置为Falling_Edge、EINT4,5设置为Both_Edge
* */
void KeyEIntInit(void)
{
u32 uConValue;
//初始化各Key对应的端口
KeyIntPortInit(1, Low_Level);
KeyIntPortInit(3, Falling_Edge);
KeyIntPortInit(5, Both_Edge);
//清除中断悬起位
EintClrPend(0);
EintClrPend(2);
EintClrPend(4);
//向rVIC0VECTADDR中写入对应中断服务程序的地址
Outp32(rVIC0VECTADDR, (unsigned)Isr_Eint);
Outp32(rVIC0VECTADDR+4, (unsigned)Isr_Eint);
//使能中断源:
// INT_EINT0: External interrupt 4 ~ 11
// INT_EINT1: External interrupt 0 ~ 3
uConValue = Inp32(rVIC0INTENABLE);
uConValue |= (1<<NUM_EINT0)|(1<<NUM_EINT1);
Outp32(rVIC0INTENABLE, uConValue);
//解除屏蔽
EintDisMask(0);
EintDisMask(2);
EintDisMask(4);
}
先来对几个宏定义进行说明:
#define Outp32(addr, data) (*(volatile u32 *)(addr) = (data)) 这个宏定义作用为:将addr地址指向的单元的内容存入data数据。
#define Inp32(addr) (*(volatile u32 *)(addr)) 这个宏的作用为:用来获得addr地址指向的单元所存放的内容。
#define GPIO_BASE (0x7F008000)
#define GPIO (( volatile oGPIO_REGS *)GPIO_BASE)
这两个宏定义在LED驱动程序一节说明过了,此处不再介绍。
接下来分析main函数,main函数主要完成以下几个步骤:(1)使能VIC(SYSTEM_EnableVIC());(2)使能IRQ中断(SYSTEM_EnableIRQ());(3)中断初始化(INTC_Init());(4)蜂鸣器初始化(BuzzerPortInit());(5)按键初始化(KeyEIntInit());
下面对几个步骤分别进行介绍:
1 SYSTEM_EnableVIC()函数是来自于(光盘4\实验代码\3-4-1\src\_common\system_.s)
system_.s
;/*************************************************************************************
;
; Project Name : S3C6410 Validation
;
; Copyright 2006 by Samsung Electronics, Inc.
; All rights reserved.
;
; Project Description :
; This software is only for validating functions of the S3C6410.
; Anybody can use this software without our permission.
;
;--------------------------------------------------------------------------------------
;
; File Name : system_.s
;
; File Description : This file implements CP15 control.
;
; Author : Haksoo,Kim
; Dept. : AP Development Team
; Created Date : 2006/11/08
; Version : 0.1
;
; History
; - Created(Haksoo,Kim 2006/11/08)
;
;*************************************************************************************/
AREA |C$$code|, CODE, READONLY
;;===============================================================================
;;
;; Exception
;;
EXPORT SYSTEM_EnableVIC
SYSTEM_EnableVIC PROC //PROC和ENDP来在汇编指令当中定义一个函数
mrc p15,0,r0,c1,c0,0 //查看arm6410手册,arm1176JZF-S.pdf 第3-14页,op1=0,CRn=c1,CRm=c0,op2=0,跳转到第3-44页查看对应寄存器
orr r0,r0,#(1<<24)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableVIC
SYSTEM_DisableVIC PROC
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1<<24)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableIRQ
SYSTEM_EnableIRQ PROC
mrs r0,cpsr
bic r0,r0,#(1<<7)
msr cpsr_cxsf,r0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableIRQ
SYSTEM_DisableIRQ PROC
mrs r0,cpsr
orr r0,r0,#(1<<7)
msr cpsr_cxsf,r0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableFIQ
SYSTEM_EnableFIQ PROC
mrs r0,cpsr
bic r0,r0,#(1<<6)
msr cpsr_cxsf,r0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableFIQ
SYSTEM_DisableFIQ PROC
mrs r0,cpsr
orr r0,r0,#(1<<6)
msr cpsr_cxsf,r0
mov pc,lr
ENDP
;;
;;===============================================================================
EXPORT Stop_WFI_Test
Stop_WFI_Test PROC
;stmfd sp!, {r0-r13}
stmfd sp!, {r0-r6}
ldr r5, =0x7E00FA1C ; Inform7
ldr r6, [r5]
mov r0, #0
ldr r1, =0x7E00F90C
mov r3, #0
mov r4, #0
LOOP_STOP
add r3, r3, #1
cmp r3, #0x2
blt Wait_BLK_PWR1
mcr p15,0,r0,c7,c10,5 ; Data Memory Barrier
mcr p15,0,r0,c7,c10,4 ; test, Data Sync. Barrier
mcr p15,0,r0,c7,c0,4
Wait_BLK_PWR1
ldr r2, [r1]
;cmp r2, #0x7F
;cmp r2, #0x51
cmp r2, r6
bne Wait_BLK_PWR1
add r4, r4, #1
cmp r4, #2
blt LOOP_STOP
ldmfd sp!, {r0-r6}
mov pc,lr
ENDP
EXPORT Stop_WFI_Test1
Stop_WFI_Test1 PROC
;stmfd sp!, {r0-r13}
stmfd sp!, {r0-r6}
ldr r5, =0x7E00FA1C ; Inform7
ldr r6, [r5]
mov r0, #0
ldr r1, =0x7E00F90C
mov r3, #0
mov r4, #0
LOOP_STOP1
add r3, r3, #1
cmp r3, #0x2
blt Wait_BLK_PWR2
ldr r1, =0x7E00F800
mov r0, #0x2
str r0, [r1]
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
;mcr p15,0,r0,c7,c10,5 ; Data Memory Barrier
;mcr p15,0,r0,c7,c10,4 ; test, Data Sync. Barrier
;mcr p15,0,r0,c7,c0,4
b .
Wait_BLK_PWR2
nop;
nop;
nop;
nop;
nop;
nop;
nop;
add r4, r4, #1
cmp r4, #2
blt LOOP_STOP1
;b .
ldmfd sp!, {r0-r6}
mov pc,lr
ENDP
EXPORT MMU_WaitForInterrupt
MMU_WaitForInterrupt PROC
mov r0, #0
; ldr r1, =0x7E00F90C
mcr p15,0,r0,c7,c10,5 ; Data Memory Barrier
mcr p15,0,r0,c7,c10,4 ; test, Data Sync. Barrier
;mcr p15,0,r0,c7,c5,4 ; Flush Prefetch Buffer
mcr p15,0,r0,c7,c0,4
;for test
;nop
;nop
;nop
;nop
;nop
;nop
;nop
;nop
;nop
;nop
;bl SYSTEM_EnableIRQ
;ldr r1, =0x71200014
;ldr r2, =0xffffffff
;str r2, [r1]
;ldr r1, =0x71200F00
;ldr r2, =0x0
;str r2, [r1]
;Wait_BLK_PWR
; ldr r2, [r1]
; cmp r2, #0x7F
; bne Wait_BLK_PWR
mov pc,lr
ENDP
;;===============================================================================
;;
;; MMU/Cache
;;
EXPORT SYSTEM_EnableBP
SYSTEM_EnableBP PROC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<11)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableICache
SYSTEM_EnableICache PROC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<12)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableICache
SYSTEM_DisableICache PROC
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1<<12)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableDCache
SYSTEM_EnableDCache PROC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<2)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableDCache
SYSTEM_DisableDCache PROC
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1<<2)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_InvalidateEntireICache
SYSTEM_InvalidateEntireICache PROC
mov r0,#0
mcr p15,0,r0,c7,c5,0
mov pc,lr
ENDP
EXPORT SYSTEM_InvalidateEntireDCache
SYSTEM_InvalidateEntireDCache PROC
mov r0,#0
mcr p15,0,r0,c7,c6,0
mov pc,lr
ENDP
EXPORT SYSTEM_InvalidateBothCache
SYSTEM_InvalidateBothCache PROC
mov r0,#0
mcr p15,0,r0,c7,c7,0
mov pc,lr
ENDP
EXPORT SYSTEM_CleanEntireDCache
SYSTEM_CleanEntireDCache PROC
mov r0,#0
mcr p15,0,r0,c7,c10,0
mov pc,lr
ENDP
EXPORT SYSTEM_CleanInvalidateEntireDCache
SYSTEM_CleanInvalidateEntireDCache PROC
mov r0,#0
mcr p15,0,r0,c7,c14,0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableMMU
SYSTEM_EnableMMU PROC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<0)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableMMU
SYSTEM_DisableMMU PROC
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1<<0)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_InvalidateTLB
SYSTEM_InvalidateTLB PROC
mov r0,#0x0
mcr p15,0,r0,c8,c7,0
mov pc,lr
ENDP
EXPORT SYSTEM_SetTTBase
SYSTEM_SetTTBase PROC ; r0=TTBase
mcr p15,0,r0,c2,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_SetDomain
SYSTEM_SetDomain PROC ; r0=Domain
mcr p15,0,r0,c3,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_SetFCSEPID
SYSTEM_SetFCSEPID PROC ; r0= FCSEPID
mcr p15,0,r0,c13,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_EnableAlignFault
SYSTEM_EnableAlignFault PROC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<1)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_DisableAlignFault
SYSTEM_DisableAlignFault PROC
mrc p15,0,r0,c1,c0,0
bic r0,r0,#(1<<1)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_ReadDFSR
SYSTEM_ReadDFSR PROC
mrc p15,0,r0,c5,c0,0
mov pc,lr
ENDP
EXPORT SYSTEM_ReadIFSR
SYSTEM_ReadIFSR PROC
mrc p15,0,r0,c5,c0,1
mov pc,lr
ENDP
EXPORT SYSTEM_ReadFAR
SYSTEM_ReadFAR PROC
mrc p15,0,r0,c6,c0,0
mov pc,lr
ENDP
EXPORT EBI_Test_Assem
EBI_Test_Assem PROC
ldr r1, =0x70200010 ; Dest Addr of NFCON
ldr r2, =0x55555555
ldr r3, =0xaaaaaaaa
ldr r4, =0xffffffff
ldr r5, =0x5a5a5a5a
ldr r8, =0x00005555 ; DATA
ldr r9, =0x70200010 ; NFCON DATA Register
ldr r6, =0x0000aaaa ; DATA
ldr r7, =0x7030192C ; CFCON Register
;---------- WW --------------
; Store to NFCON Data register
str r8,[r9] ; DATA -> NFCON Data Register
; Store to CFCON Register
str r6, [r7] ; DATA -> CFCON Data Register
nop
nop
;---------- WR --------------
; Store to NFCON Data register
str r8,[r9] ; DATA -> NFCON Data Register
; Read from CFCON Register
ldr r0, [r7] ; CFCON Data Register -> Register
nop
nop
;---------- BWW --------------
stm r1,{r2-r5} ; DATA -> NFCON Data Register
; Store to CFCON Register
str r6, [r7] ; DATA -> CFCON Data Register
nop
nop
;---------- BWR --------------
stm r1,{r2-r5} ; DATA -> NFCON Data Register
; Read from CFCON Register
ldr r0, [r7] ; CFCON Data Register -> Register
nop
nop
ENDP
EXPORT Set_Ata_Cmd_START
Set_Ata_Cmd_START PROC
ldr r8, = 0x0
ldr r9, =0x1 ; START command
ldr r10, =0x70301908 ; ATA_COMMAND register
swp r8, r9, [r10] ; swap operation
mov pc,lr
ENDP
EXPORT Set_Ata_Cmd_STOP
Set_Ata_Cmd_STOP PROC
ldr r8, = 0x0
ldr r9, =0x0 ; STOP command
ldr r10, =0x70301908 ; ATA_COMMAND register
swp r8, r9, [r10] ; swap operation
mov pc,lr
ENDP
EXPORT Set_Ata_Cmd_ABORT
Set_Ata_Cmd_ABORT PROC
ldr r8, = 0x0
ldr r9, =0x2 ; ABORT command
ldr r10, =0x70301908 ; ATA_COMMAND register
swp r8, r9, [r10] ; swap operation
mov pc,lr
ENDP
EXPORT Set_Ata_Cmd_CONTINUE
Set_Ata_Cmd_CONTINUE PROC
ldr r8, = 0x0
ldr r9, =0x3 ; CONTINUE command
ldr r10, =0x70301908 ; ATA_COMMAND register
swp r8, r9, [r10] ; swap operation
mov pc,lr
ENDP
EXPORT MEMCOPY_TEST
MEMCOPY_TEST PROC
ldr r0, =0x51000000
ldr r1, =0x52000000
ldr r2, =0x8000
ldr r3, =0
TCOPY
ldmia r0!, {r5-r12}
stmia r1!, {r5-r12}
add r3, r3, #1
cmp r3, r2
;add r0, r0, #0x20
;add r1, r1, #0x20
blt TCOPY
mov pc,lr
ENDP
EXPORT MEMCOPY_TEST0
MEMCOPY_TEST0 PROC
ldr r0, =0x41000000
ldr r1, =0x42000000
ldr r2, =0x8000
ldr r3, =0
TCOPY0
ldmia r0!, {r5-r12}
stmia r1!, {r5-r12}
add r3, r3, #1
cmp r3, r2
;add r0, r0, #0x20
;add r1, r1, #0x20
blt TCOPY0
mov pc,lr
ENDP
EXPORT MEMCOPY8
MEMCOPY8 PROC
stmfd sp!, {r0-r12}
;ldr r0, =0x51000000
;ldr r1, =0x52000000
;ldr r2, =0x8000
ldr r3, =0
TCOPY8
ldmia r0!, {r5-r12}
stmia r1!, {r5-r12}
add r3, r3, #1
cmp r3, r2
;add r0, r0, #0x20
;add r1, r1, #0x20
blt TCOPY8
ldmfd sp!, {r0-r12}
mov pc,lr
ENDP
EXPORT MEMWRITE4
MEMWRITE4 PROC
stmfd sp!, {r0-r8}
ldr r4, =0
TWRITE4
mov r5, r2
mov r6, r3
mov r7, r2
mov r8, r3
stmia r0!, {r5-r8}
add r4, r4, #1
cmp r4, r1
;add r0, r0, #0x20
;add r1, r1, #0x20
blt TWRITE4
ldmfd sp!, {r0-r8}
mov pc,lr
ENDP
EXPORT MODEM_BlockCopy
MODEM_BlockCopy PROC
;LDR r0, =src ; r0 = pointer to source block
;LDR r1, =dst ; r1 = pointer to destination block
;MOV r2, #nWord ; r2 = number of words to copy
;MOV sp, #0x400
;PUSH {r4-r11}
STMDB r13!,{r0-r2,r4-r11,lr}
mov pc,lr
ENDP
;;
;;===============================================================================
END
此处只关心下面一段代码:
EXPORT SYSTEM_EnableVIC
SYSTEM_EnableVIC PROC //PROC和ENDP用来在汇编指令当中定义一个函数
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<24)
mcr p15,0,r0,c1,c0,0
mov pc,lr
ENDP
主要是通过CP15协处理器特定的寄存器来控制VIC的使能:查看arm6410手册,arm1176JZF-S.pdf 第3-14页如下图(1)所示,因为op1=0,CRn=c1,CRm=c0,op2=0,跳转到第3-44页如图(2)所示,查看对应寄存器。
图1 S3C6410手册3-14页
图2 S3C6410手册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协处理器对应的寄存器当中。
2 SYSTEM_EnableIRQ()函数主要完成IRQ的使能操作。
EXPORT SYSTEM_EnableIRQ
SYSTEM_EnableIRQ PROC
mrs r0,cpsr //获得cpsr寄存器的值,放入r0当中
bic r0,r0,#(1<<7) //将r0的第7位清零
msr cpsr_cxsf,r0 //将清零后的值重新放回cpsr当中
mov pc,lr //lr位r14,即调用函数语句的下一条语句的地址,用于函数调用完的返回地址。
ENDP
由下图3可知,cpsr寄存器的第7位I位IRQ中断禁止位,0表示允许,1表示禁止,因为bic r0,r0,#(1<<7)是将第7位清零,所以相当于开启IRQ总中断。
图3 程序状态寄存器CPSR
3 INTC_Init()完成中断的初始化工作:
intc.c
/**************************************************************************************
*
* Project Name : S3C6410 Validation
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6410.
* Anybody can use this software without our permission.
*
*--------------------------------------------------------------------------------------
*
* File Name : intc.c
*
* File Description : This file implements the API functons for interrupt controller.
*
* Author : Haksoo,Kim
* Dept. : AP Development Team
* Created Date : 2006/11/08
* Version : 0.1
*
* History
* - Created(Haksoo,Kim 2006/11/08)
* - Added Software Interrupt API (wonjoon.jang 2007/01/17)
*
**************************************************************************************/
#include "library.h"
#include "intc.h"
//
// Function Name : INTC_Init
// Function Description : This function initializes interrupt controller
// Input : NONE
// Output : NONE
// Version :
void INTC_Init(void)
{
#if (VIC_MODE==0)
u32 i;
for(i=0;i<32;i++)
Outp32(rVIC0VECTADDR+4*i, i);
for(i=0;i<32;i++)
Outp32(rVIC1VECTADDR+4*i, i+32);
#endif
Outp32(rVIC0INTENCLEAR, 0xffffffff);
Outp32(rVIC1INTENCLEAR, 0xffffffff);
Outp32(rVIC0INTSELECT, 0x0);
Outp32(rVIC1INTSELECT, 0x0);
INTC_ClearVectAddr();
return;
}
//
// Function Name : INTC_ClearVectAddr
// Function Description : This function clears the vector address register
// Input : NONE
// Output : NONE
// Version :
void INTC_ClearVectAddr(void)
{
Outp32(rVIC0ADDR, 0);
Outp32(rVIC1ADDR, 0);
return;
}
首先看INTC_Init()函数,因为我们在汇编程序的预处理中设置VIC_MODE=1,所以INTC_Init()函数开始执行Outp32(rVIC0INTENCLEAR, 0xffffffff);先来看看几个寄存datasheet如下图所示:因为6410总共有64个中断源,所以分两组VIC0和VIC1来存放对应寄存器,Outp32(rVIC0INTENCLEAR, 0xffffffff),Outp32(rVIC1INTENCLEAR, 0xffffffff)用来将VIC*INTENCLEAR寄存器的所有位置1,由(a)(b)图红色方框部分可知,在要设置允许中断的时候,只需要设置VIC*INTENABLE相应的位为1即可完成操作。当要设置不允许中断的时候,必须要设置VIC*INTENCLEAR相应的位为1,才可以禁止中断;而要想读取目前中断的状态时,只需读取VIC*INTENABLE相应位为0表明中断禁止,为1表示中断允许。
(a) (b)
(c) (d)
Outp32(rVIC0INTSELECT, 0x0),Outp32(rVIC1INTSELECT, 0x0) 由(c)图可知,当VIC*INTSELECT相应位为0时,选择的是IRQ中断。
Outp32(rVIC0ADDR, 0),Outp32(rVIC1ADDR, 0) 由(d)图可知,向寄存器写入任何值都可以清除当前中断。只有在终端服务快要结束的时候才可以进行写入操作。此处设置VIC*ADDR为全0,表明清楚所有当前中断。
4 BuzzerPortInit()完成蜂鸣器的初始化:
由下图可以看出,tiny6410使用的是S3C6410的GPF14管教,GPFCON寄存器datasheet如下:
蜂鸣器初始化代码如下:
u32 uConValue;
uConValue = GPIO->rGPIOFCON; //得到GPF控制寄存器GPIOCON的内容
uConValue &= ~(0x3<<28); //将其28,29位清零,其它位不变
uConValue |= 0x1<<28; //将其29位置1,其它位不变
GPIO->rGPIOFCON = uConValue; //得到的GPFCON[29,28]=01,说明此管教位输出管教,用来控制蜂鸣器的响与不响。
5 KeyEIntInit()完成按键的初始化工作。
tiny6410的8个按键资源如下:
* KEYINT1 -- GPN0 -- XEINT0
* KEYINT2 -- GPN1 -- XEINT1
* KEYINT3 -- GPN2 -- XEINT2
* KEYINT4 -- GPN3 -- XEINT3
* KEYINT5 -- GPN4 -- XEINT4
* KEYINT6 -- GPN5 -- XEINT5
* KEYINT7 -- GPL11-- XEINT19
* KEYINT8 -- GPL12-- XEINT20
原理图如下:
(1)首先调用KeyIntPortInit(u32 uKey, u32 uType)
KeyIntPortInit(1, Low_Level);
KeyIntPortInit(3, Falling_Edge);
KeyIntPortInit(5, Both_Edge);
用于将按键KEYINT1、KEYINT3和KEYINT5,分别置为低电平中断、下降沿中断和双沿中断。
接下来对KeyIntPortInit(u32 uKey, u32 uType)函数进行详解,在gpio.h中定义了:
#define Low_Level 0x0
#define High_Level 0x1
#define Falling_Edge 0x2
#define Rising_Edge 0x4
#define Both_Edge 0x6
下面通过代码注释来解释KeyIntPortInit(u32 uKey, u32 uType)函数的作用,此处假设:uKey=1,uType=Low_Level 其它情况类似类似代码如下:
void KeyIntPortInit(u32 uKey, u32 uType)
{
u32 uConValue;
if (uKey==0||uKey>6)
return;
//设置对应IO为特殊功能 -- EINT
uConValue = GPIO->rGPIONCON; //因为由原理图可知,按键对应的管教为GPION,所以此处获取GPIONCON的值
uConValue &= ~(0x3<<((uKey-1)<<1)); //由于uKey号按键,相应的管教为GPN的(uKey-1)号管教,此处uKey=1时,相当于将GPNCON的[1:0]清零,其它位不变
uConValue |= 0x2<<((uKey-1)<<1); //将GPNCON的第1位置1,其它位不变,由下图(a)可知,GPNCON[1:0]=10,表示GPN0管脚为外部中断方式
GPIO->rGPIONCON = uConValue; //将得到的值赋会GPIONCON中
//设置对应IO为上下拉除能
uConValue = GPIO->rGPIONPUD; //
uConValue &= ~(0x3<<((uKey-1)<<1));
uConValue |= 0x0<<((uKey-1)<<1); //这三行代码使GPNPUD[1:0]=00,由下图(c)所示,即不要上下拉电阻,因为原理图中有上拉电阻
GPIO->rGPIONPUD = uConValue;
//设置对应EINT为@uType 类型中断
uConValue = GPIO->rEINT0CON0;
uConValue &= ~(0x7<<(((uKey-1)/2)<<2));
uConValue |= uType<<(((uKey-1)/2)<<2); //这三行代码使EINT0CON0[2:0]=uType,如图(b)所示,即选择触发方式
GPIO->rEINT0CON0 = uConValue;
}
(a) (b) EINT0CON0寄存器
(c)
(2)然后调用void EintClrPend(u32 uEINT_No ):EintClrPend(0);EintClrPend(2); EintClrPend(4); 清除中断悬起
void EintClrPend(u32 uEINT_No )
{
GPIO->rEINT0PEND = 1<<uEINT_No;; //加入对于按键1为例,其对应的外部中断时EINT0,此处是用于清除中断悬起位,使得EINT0PEND[0]=1,如下图所示,表示能够发生中断
}
在sfr6410.h中定义了:
#define VIC0_BASE (0x71200000)
#define VIC1_BASE (0x71300000)
init.h
#ifndef __INTC_H__
#define __INTC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "def.h"
#include "sfr6410.h"
void INTC_Init(void);
void INTC_ClearVectAddr(void);
#define INT_LIMIT (64)
//INT NUM - VIC0
#define NUM_EINT0 (0)
#define NUM_EINT1 (1)
#define NUM_RTC_TIC (2)
#define NUM_CAMIF_C (3)
#define NUM_CAMIF_P (4)
#define NUM_I2C1 (5)
#define NUM_I2S (6)
#define NUM_3D (8)
#define NUM_POST0 (9)
#define NUM_ROTATOR (10)
#define NUM_2D (11)
#define NUM_TVENC (12)
#define NUM_SCALER (13)
#define NUM_BATF (14)
#define NUM_JPEG (15)
#define NUM_MFC (16)
#define NUM_SDMA0 (17)
#define NUM_SDMA1 (18)
#define NUM_ARM_DMAERR (19)
#define NUM_ARM_DMA (20)
#define NUM_ARM_DMAS (21)
#define NUM_KEYPAD (22)
#define NUM_TIMER0 (23)
#define NUM_TIMER1 (24)
#define NUM_TIMER2 (25)
#define NUM_WDT (26)
#define NUM_TIMER3 (27)
#define NUM_TIMER4 (28)
#define NUM_LCD0 (29)
#define NUM_LCD1 (30)
#define NUM_LCD2 (31)
//INT NUM - VIC1
#define NUM_EINT2 (32+0)
#define NUM_EINT3 (32+1)
#define NUM_PCM0 (32+2)
#define NUM_PCM1 (32+3)
#define NUM_AC97 (32+4)
#define NUM_UART0 (32+5)
#define NUM_UART1 (32+6)
#define NUM_UART2 (32+7)
#define NUM_UART3 (32+8)
#define NUM_DMA0 (32+9)
#define NUM_DMA1 (32+10)
#define NUM_ONENAND0 (32+11)
#define NUM_ONENAND1 (32+12)
#define NUM_NFC (32+13)
#define NUM_CFC (32+14)
#define NUM_UHOST (32+15)
#define NUM_SPI0 (32+16)
#define NUM_SPI1 (32+17)
#define NUM_IIC (32+18)
#define NUM_HSItx (32+19)
#define NUM_HSIrx (32+20)
#define NUM_EINTGroup (32+21)
#define NUM_MSM (32+22)
#define NUM_HOSTIF (32+23)
#define NUM_HSMMC0 (32+24)
#define NUM_HSMMC1 (32+25)
#define NUM_OTG (32+26)
#define NUM_IRDA (32+27)
#define NUM_RTC_ALARM (32+28)
#define NUM_SEC (32+29)
#define NUM_PENDNUP (32+30)
#define NUM_ADC (32+31)
#define NUM_PMU (32+32)
// VIC0
#define rVIC0IRQSTATUS (VIC0_BASE + 0x00)
#define rVIC0FIQSTATUS (VIC0_BASE + 0x04)
#define rVIC0RAWINTR (VIC0_BASE + 0x08)
#define rVIC0INTSELECT (VIC0_BASE + 0x0c)
#define rVIC0INTENABLE (VIC0_BASE + 0x10)
#define rVIC0INTENCLEAR (VIC0_BASE + 0x14)
#define rVIC0SOFTINT (VIC0_BASE + 0x18)
#define rVIC0SOFTINTCLEAR (VIC0_BASE + 0x1c)
#define rVIC0PROTECTION (VIC0_BASE + 0x20)
#define rVIC0SWPRIORITYMASK (VIC0_BASE + 0x24)
#define rVIC0PRIORITYDAISY (VIC0_BASE + 0x28)
#define rVIC0VECTADDR (VIC0_BASE + 0x100)
#define rVIC0VECPRIORITY (VIC0_BASE + 0x200)
#define rVIC0ADDR (VIC0_BASE + 0xf00)
#define rVIC0PERID0 (VIC0_BASE + 0xfe0)
#define rVIC0PERID1 (VIC0_BASE + 0xfe4)
#define rVIC0PERID2 (VIC0_BASE + 0xfe8)
#define rVIC0PERID3 (VIC0_BASE + 0xfec)
#define rVIC0PCELLID0 (VIC0_BASE + 0xff0)
#define rVIC0PCELLID1 (VIC0_BASE + 0xff4)
#define rVIC0PCELLID2 (VIC0_BASE + 0xff8)
#define rVIC0PCELLID3 (VIC0_BASE + 0xffc)
// VIC1
#define rVIC1IRQSTATUS (VIC1_BASE + 0x00)
#define rVIC1FIQSTATUS (VIC1_BASE + 0x04)
#define rVIC1RAWINTR (VIC1_BASE + 0x08)
#define rVIC1INTSELECT (VIC1_BASE + 0x0c)
#define rVIC1INTENABLE (VIC1_BASE + 0x10)
#define rVIC1INTENCLEAR (VIC1_BASE + 0x14)
#define rVIC1SOFTINT (VIC1_BASE + 0x18)
#define rVIC1SOFTINTCLEAR (VIC1_BASE + 0x1c)
#define rVIC1PROTECTION (VIC1_BASE + 0x20)
#define rVIC1SWPRIORITYMASK (VIC1_BASE + 0x24)
#define rVIC1PRIORITYDAISY (VIC1_BASE + 0x28)
#define rVIC1VECTADDR (VIC1_BASE + 0x100)
#define rVIC1VECPRIORITY (VIC1_BASE + 0x200)
#define rVIC1ADDR (VIC1_BASE + 0xf00)
#define rVIC1PERID0 (VIC1_BASE + 0xfe0)
#define rVIC1PERID1 (VIC1_BASE + 0xfe4)
#define rVIC1PERID2 (VIC1_BASE + 0xfe8)
#define rVIC1PERID3 (VIC1_BASE + 0xfec)
#define rVIC1PCELLID0 (VIC1_BASE + 0xff0)
#define rVIC1PCELLID1 (VIC1_BASE + 0xff4)
#define rVIC1PCELLID2 (VIC1_BASE + 0xff8)
#define rVIC1PCELLID3 (VIC1_BASE + 0xffc)
#ifdef __cplusplus
}
#endif
#endif