|
文件: |
timer.rar |
大小: |
31KB |
下载: |
下载 | |
¥¥¥¥¥¥¥ head.S ¥¥¥¥¥¥¥¥¥¥
;*******************************************
; File:head.S
; 功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数
;*****************************************
IMPORT Main ;声明外部函数,后面要使用
IMPORT disable_watch_dog
IMPORT clock_init
IMPORT memsetup
IMPORT init_led
IMPORT timer0_init
IMPORT init_irq
IMPORT Timer0_Handle
AREA HEAD, CODE, READONLY
ENTRY
CODE32
START
;*****************************************
; 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
;******************************************
b Reset
; 0x04: 未定义指令中止模式的向量地址
HandleUndef
b HandleUndef
; 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI
b HandleSWI
; 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort
b HandlePrefetchAbort
; 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort
b HandleDataAbort
; 0x14: 保留
HandleNotUsed
b HandleNotUsed
; 0x18: 中断模式的向量地址
b HandleIRQ
; 0x1c: 快中断模式的向量地址
HandleFIQ
b HandleFIQ
Reset
ldr sp, =0x32000000 ; 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog ; 关闭WATCHDOG,否则CPU会不断重启
bl clock_init ; 设置MPLL,改变FCLK、HCLK、PCLK
bl memsetup ; 设置存储控制器以使用SDRAM
msr cpsr_c, #0xd2 ; 进入中断模式
ldr sp, =0x33000000 ; 设置中断模式栈指针
msr cpsr_c, #0xdf ; 进入系统模式
ldr sp, =0x34000000 ; 设置系统模式栈指针,
bl init_led ; 初始化LED的GPIO管脚
bl timer0_init ; 初始化定时器0
bl init_irq ; 调用中断初始化函数,在init.c中
msr cpsr_c, #0x5f ; 设置I-bit=0,开IRQ中断
ldr lr, =halt_loop ; 设置返回地址
ldr pc, =Main ; 调用main函数
halt_loop
b halt_loop
HandleIRQ
sub lr, lr, #4 ; 计算返回地址
stmdb sp!, { r0-r12,lr } ; 保存使用到的寄存器
; 注意,此时的sp是中断模式的sp
; 初始值是上面设置的4096
ldr lr, =int_return ; 设置调用ISR即EINT_Handle函数后的返回地址
ldr pc, =Timer0_Handle ; 调用中断服务函数,在interrupt.c中
int_return
ldmia sp!, { r0-r12,pc }^ ; 中断返回, ^表示将spsr的值复制到cpsr
END
*************** init.c ***************
/*
* init.c: 进行一些初始化
*/
#include "s3c2440.h"
void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void init_led(void);
void timer0_init(void);
void init_irq(void);
/*
* 关闭WATCHDOG,否则CPU会不断重启
*/
void disable_watch_dog(void)
{
WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
}
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
/*
* 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
* 有如下计算公式:
* S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
* 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
* 对于本开发板,Fin = 12MHz
* 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
*/
void clock_init(void)
{
// LOCKTIME = 0x00ffffff; // 使用默认值即可
CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm{
mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
}
MPLLCON = S3C2440_MPLL_200MHZ; /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值
* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到
* SDRAM之前就可以在steppingstone中运行
*/
/* 存储控制器13个寄存器的值 */
p[0] = 0x22011110; //BWSCON
p[1] = 0x00000700; //BANKCON0
p[2] = 0x00000700; //BANKCON1
p[3] = 0x00000700; //BANKCON2
p[4] = 0x00000700; //BANKCON3
p[5] = 0x00000700; //BANKCON4
p[6] = 0x00000700; //BANKCON5
p[7] = 0x00018005; //BANKCON6
p[8] = 0x00018005; //BANKCON7
/* REFRESH,
* HCLK=12MHz: 0x008C07A3,
* HCLK=100MHz: 0x008C04F4
*/
p[9] = 0x008C04F4;
p[10] = 0x000000B1; //BANKSIZE
p[11] = 0x00000030; //MRSRB6
p[12] = 0x00000030; //MRSRB7
}
/*
* LED1-4对应GPB5、GPB6、GPB7、GPB8
*/
#define GPB5_out (1<<(5*2)) // LED1
#define GPB6_out (1<<(6*2)) // LED2
#define GPB7_out (1<<(7*2)) // LED3
#define GPB8_out (1<<(8*2)) // LED4
void init_led(void)
{
GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ; //设置为输出功能
}
/*
* Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
* {prescaler value} = 0~255
* {divider value} = 2, 4, 8, 16
* 本实验的Timer0的时钟频率=100MHz/(99+1)/(16)=62500Hz
* 设置Timer0 0.5秒钟触发一次中断:
*/
void timer0_init(void)
{
TCFG0 = 99; // 预分频器0 = 99
TCFG1 = 0x03; // 选择16分频
TCNTB0 = 31250; // 0.5秒钟触发一次中断
TCMPB0 = 0;
TCON |= (1<<1); // 手动更新
TCON = 0x09; // 自动加载,清“手动更新”位,启动定时器0
}
/*
* 定时器0中断使能
*/
void init_irq(void)
{
// 定时器0中断使能
INTMSK &= (~(1<<10));
}
******** interrupt.h ***************
void EINT_Handle();
*********** interrupt.c ***********
#include "s3c2440.h"
void Timer0_Handle(void)
{
/*
* 每次中断令4个LED改变状态
*/
if(INTOFFSET == 10) //判断是否是时钟中断,时钟中断使用IRQ10
{
GPBDAT = ~(GPBDAT & (0xf << 5));
}
//清中断
SRCPND = 1 << INTOFFSET;
INTPND = INTPND;
}
^^^^^^^^^^^^^^ main.c ^^^^^^^^^^^^^
int Main(void)
{
while(1); //死循环,等待时钟中断;当中断到来时跳到中断处理函数处执行
return 0;
}
~~~~~~~~~~~~~~~ s3c2440.h ~~~~~~~~~~~~~~~
/* WOTCH DOG register */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* SDRAM regisers */
#define MEM_CTL_BASE 0x48000000
#define SDRAM_BASE 0x30000000
/* NAND Flash registers */
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCMD (*(volatile unsigned char *)0x4e000004)
#define NFADDR (*(volatile unsigned char *)0x4e000008)
#define NFDATA (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT (*(volatile unsigned char *)0x4e000010)
/*GPIO registers*/
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068)
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHDAT (*(volatile unsigned long *)0x56000074)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/*UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
/*interrupt registes*/
#define SRCPND (*(volatile unsigned long *)0x4A000000)
#define INTMOD (*(volatile unsigned long *)0x4A000004)
#define INTMSK (*(volatile unsigned long *)0x4A000008)
#define PRIORITY (*(volatile unsigned long *)0x4A00000c)
#define INTPND (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)
/*external interrupt registers*/
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
/*clock registers*/
#define LOCKTIME (*(volatile unsigned long *)0x4c000000)
#define MPLLCON (*(volatile unsigned long *)0x4c000004)
#define UPLLCON (*(volatile unsigned long *)0x4c000008)
#define CLKCON (*(volatile unsigned long *)0x4c00000c)
#define CLKSLOW (*(volatile unsigned long *)0x4c000010)
#define CLKDIVN (*(volatile unsigned long *)0x4c000014)
/*PWM & Timer registers*/
#define TCFG0 (*(volatile unsigned long *)0x51000000)
#define TCFG1 (*(volatile unsigned long *)0x51000004)
#define TCON (*(volatile unsigned long *)0x51000008)
#define TCNTB0 (*(volatile unsigned long *)0x5100000c)
#define TCMPB0 (*(volatile unsigned long *)0x51000010)
#define TCNTO0 (*(volatile unsigned long *)0x51000014)
#define GSTATUS1 (*(volatile unsigned long *)0x560000B0)