本实例首先启动MPLL提高系统时钟,初始化内存控制器,使SDRAM工作在新的HCLK下,然后将定时器0设为0.5秒产生一次中断,在中断程序里改变LED的状态。
head.S
.extern main
.text
.global _start
_start:
b Reset
@ 0x04:
HandleUndef:
b HandleUndef
@ 0x08:
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, =4096 @ 设置好栈指针,调用C函数之前要设好栈
bl disable_watch_dog @ 关闭watch dog,否者CPU会不断重启
bl clock_init @
bl memsetup @
bl copy_steppingstone_to_sdram @
ldr pc, =on_sdram @
on_sdram:
msr cpsr_c, #0xd2 @
ldr sp, =4096 @
msr cpsr_c, #0xdf @
ldr sp, =0x34000000 @
bl init_led @
bl timer0_init @
bl init_irq @
msr cpsr_c, #0x5f @
ldr lr, =halt_loop @
ldr pc, =main @
halt_loop:
b halt_loop
HandleIRQ:
sub lr, lr, #4 @ 计算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此时的sp是中断模式的sp
@
ldr lr, =int_return @ 设置调用ISR函数(即EINT_Handle)后的返回地址
ldr pc, =Timer0_Handle @ 调用定时器中断处理函数
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中断返回,^表示将spsr的值复制到cpsr
init.c
#include "s3c24xx.h"
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
void disable_watch_dog(void);
void clock_init(void);
void memsetup(void);
void copy_steppingstone_to_sdram(void);
void init_led(void);
void timer0_init(void);
void init_irq(void);
void disable_watch_dog(void)
{
WTCON = 0;
}
void clock_init(void)
{
//LOCKTIME = 0x00ffffff;/*default value*/
CLKDIVN = 0x03; /*FCLK:HCLK:PCLK=1:2:4*/
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n"
"orr r1, r1, #0xc0000000\n"
"mcr p15, 0, r1, c1, c0, 0\n"
);
if((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
MPLLCON = S3C2410_MPLL_200MHZ;
else
MPLLCON = S3C2440_MPLL_200MHZ;
}
void memsetup(void)
{
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
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
}
void copy_steppingstone_to_sdram(void)
{
unsigned int *pdwSrc = (unsigned int *)0;
unsigned int *pdwDest = (unsigned int *)0x30000000;
while (pdwSrc < (unsigned int *)4096)
{
*pdwDest = *pdwSrc;
pdwDest++;
pdwSrc++;
}
}
#define GPF4_out (1<<(4*2))
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2))
void init_led(void)
{
GPFCON = GPF4_out|GPF5_out|GPF6_out; /*设置为输出*/
}
void timer0_init(void)
{
TCFG0 = 99; /*Prescaler 0 = 99*/
TCFG1 = 0x03; /*16 divide*/
/*FCLK:HCLK:PCLK = 1:2:4, FCLK = 200Mhz*/
/*timer 0 clk = 50Mhz/(99+1)/16 = 31500 hz*/
TCNTB0 = 31250; /*1s occur interrupt*/
TCON |= 1<<1; /*update TCNTB0 & TCMPB0*/
TCON = 0x09;/*auto reload , start for timer0*/
}
void init_irq(void)
{
INTMSK &= (~(1<<10));
}
interrupt.c
#include "s3c24xx.h"
void Timer0_Handle(void)
{
if(INTOFFSET == 10)
{
GPFDAT = ~(GPFDAT & (0x7 << 4));
}
SRCPND = 1 << INTOFFSET;
INTPND = INTPND;
}
main.c
int main(void)
{
while(1);
return 0;
}
s3c24xx.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)
timer.lds
SECTIONS {
. = 0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
Makefile
objs := head.o init.o interrupt.o main.o
timer.bin: $(objs)
arm-linux-ld -Ttimer.lds -o timer_linux $^
arm-linux-objcopy -O binary -S timer_linux $@
arm-linux-objdump -D -m arm timer_linux > timer.dis
%.o:%.c
arm-linux-gcc -Wall -O2 -c -o $@ $<
%.o:%.S
arm-linux-gcc -Wall -O2 -c -o $@ $<
clean:
rm -f timer.bin timer_linux timer.dis *.o