按键程序开发(tiny6410版)

首先声明,此文章是基于对国嵌视频教程中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,说明此管教位输出管教,用来控制蜂鸣器的响与不响

 

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 


 

 

       

   

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值