实验(8)、MPLL和定时器操作

一、编写使用按键中断程序

1、程序功能:启动MPLL,提高系统时钟,初始化存储控制器使SDRAM工作在新的HCLK下,然后将定时器0设置为0.5s产生一次中断,在中断服务程序中改变LED的状态。

2、写程序如下:head.S、init.c、interrupt.c、main.c、s3c24xx.h、makefile

(1)head.S程序如下:

@******************************************************************************

@ File:head.S

@功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数

@******************************************************************************

.extern main

.text

.global _start

_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, =4096 @设置栈指针,以下都是C函数,调用前需要设好栈

bl disable_watch_dog @关闭WATCHDOG,否则CPU会不断重启

bl clock_init @设置MPLL,改变FCLK、HCLK、PCLK

bl memsetup @设置存储控制器以使用SDRAM

bl copy_steppingstone_to_sdram @复制代码到SDRAM中

ldr pc, =on_sdram @跳到SDRAM中继续执行

on_sdram:

msr cpsr_c, #0xd2 @进入中断模式

ldr sp, =4096 @设置中断模式栈指针

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

(2)init.c程序如下:

/*

* init.c:进行一些初始化

*/

#include "s3c24xx.h"

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);

/*

*关闭WATCHDOG,否则CPU会不断重启

*/

void disable_watch_dog(void)

{

WTCON = 0; //关闭WATCHDOG很简单,往这个寄存器写0即可

}

#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))

/*

*对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV

*有如下计算公式:

* S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)

* S3C2410: 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\n" /*读出控制寄存器*/

"orr r1, r1, #0xc0000000\n" /*设置为“asynchronous bus mode”*/

"mcr p15, 0, r1, c1, c0, 0\n" /*写入控制寄存器*/

);

/*判断是S3C2410还是S3C2440 */

if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

{

MPLLCON = S3C2410_MPLL_200MHZ; /*现在,FCLK=200M,HCLK=100M,PCLK=50M*/

}

else

{

MPLLCON = S3C2440_MPLL_200MHZ; /*现在,FCLK=200M,HCLK=100M,PCLK=50M*/

}

}

/*

*设置存储控制器以使用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

}

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++;

}

}

/*

* 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

/*

* K1-K4对应GPF1/EINT1、GPF4/EINT4、GPF2/EINT2、GPF0/EINT0;

*/

#define GPF1_eint (2<<(1*2)) // K1,EINT1

#define GPF4_eint (2<<(4*2)) // K2,EINT4

#define GPF2_eint (2<<(2*2)) // K3,EINT2

#define GPF0_eint (2<<(0*2)) // K4,EINT0

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的时钟频率=50MHz/(99+1)/(16)=31250Hz

*设置Timer0 0.5秒钟触发一次中断:

*/

void timer0_init(void)

{

TCFG0 = 99; //预分频器0 = 99

TCFG1 = 0x03; //选择16分频

TCNTB0 = 15625; // 0.5秒钟触发一次中断

TCON |= (1<<1); //手动更新

TCON = 0x09; //自动加载,清“手动更新”位,启动定时器0

}

/*

*定时器0中断使能

*/

void init_irq(void)

{

//定时器0中断使能

INTMSK&= (~(1<<10));

}

(3)interrupt.c程序如下:

#include "s3c24xx.h"

void Timer0_Handle(void)

{

/*

*每次中断令4个LED改变状态

*/

if(INTOFFSET == 10)

{

GPBDAT ^= (0xf << 5);

}

//清中断

SRCPND = 1 << INTOFFSET;

INTPND = INTPND;

}

(4)main.c程序如下:

int main()

{

while(1);

return 0;

}

(5)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)

(6)Makefile程序如下:

objs := head.o init.o interrupt.o main.o

timer.bin: $(objs)

arm-linux-ld -Ttimer.lds -o timer_elf $^

arm-linux-objcopy -O binary -S timer_elf $@

arm-linux-objdump -D -m arm timer_elf > timer.dis

%.o:%.c

arm-linux-gcc -nostdlib –Wall -c -o $@ $<

%.o:%.S

arm-linux-gcc -nostdlib -Wall -c -o $@ $<

clean:

rm -f timer.bin timer_elf timer.dis *.o

Q&A:

(1)请查阅教材和网络,说明本实验makefile中$^指什么文件?$@指什么文件,$<指什么文件?再对比实验四的makefile

(2)根据第一个问题,将makefile重新编写后编译

results matching ""

    No results matching ""

    results matching ""

      No results matching ""