JZ2440定时器

裸机系列代码地址:链接:http://pan.baidu.com/s/1pLHOd0v 密码:4x5s

S3C2440时钟控制逻辑给整个芯片提供了3种时钟:

FCLK:用于CPU核
HCLK:用于AHB总线上设备,比如存储控制器,中断控制器,LCD控制器,DMA和USB主机模块。
PCLK:用于APB总线上的设备,比如WATCHDOG,IIC,PWM定时器,MMC接口,ADC,UART,GPIO,RTC,SPI
JZ2440定时器_第1张图片
开发板上的晶振为12MHZ,为了提高频率,需要时钟控制逻辑PLL提高系统时钟,S3C2440有两个PLL
MPLL:用于设置FCLK,HCLK,PCLK。
UPLL: 专用于USB设备。

MPLL的设置,一般使用三个寄存器 LOCKTIME,MPLLCON,CLKDINV寄存器来设置FCLK,HCLK,PCLK的时钟频率
(1)设置MPLL的几个寄存器后,需要等待一段时间,MPLL的输出才稳定,这个等待的时间由LOCKTIME设置
(2)MPLLCON设置FCLK的频率相对于Fin的倍数关系,Fin为板上晶振频率,所以通过MPLLCON可以得到FCLK的频率
(3)CLKDIVN用来设置FCLK:HCLK:PCLK的比例关系,已知FCLK,又得到这个比例关系,则HCLK,PCLK频率可以确定
注意:当FCLK:HCLK!=1:1时,系统总线模式应从“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"        /* 写入控制寄存器 */
    );
PWM定时器
S3C2440有5个16位的定时器,其中定时器0,1,2,3有PWM功能,有输出引脚,定时器4无输出引脚
定时器部件的时钟源为PCLK,首先通过1个8位的预分频器(TCFG0)降低频率,然后进入第二级分频器(TCFG1)分频,
这就得到定时器使用的频率。
确定定时器的工作频率后,在看看怎么控制定时器。
TCMPBn和TCNTBn用来设置定时器的PWM比例,定时器启动时,TCMPBn、TCNTBn的值被自动装入定时器内部寄存器TCMPn、TCNTn。
当定时器的TCNTn的值等于TCMPn的值时,定时器n的输出引脚的电平第一次翻转,当定时器的TCNTn的值等于0时,
JZ2440定时器_第2张图片
TCON(TIMER CONTROL)
定时器的控制寄存器,用来决定定时器的启动,停止;当计数为0时是否自动将TMPPBn和TCNPBn的值装入定时器内部寄存器;

定时器的输出引脚是否翻转;第一次启动时是否将TMPPBn和TCNPBn的值装入定时器内部寄存器。


下面是一个定时器的实例

Makefile文件

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

time.bin: $(objs)
	arm-linux-ld -Ttime.lds -o time_linux $^
	arm-linux-objcopy -O binary -S time_linux $@
	arm-linux-objdump -D -m arm time_linux > time.dis
	
%.o:%.c
	arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S
	arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:
	rm -f time.bin time_linux time.dis *.o	
链接文件time.lds

SECTIONS {
    . = 0x30000000;
    .text          :   { *(.text) }
    .rodata ALIGN(4) : {*(.rodata)} 
    .data ALIGN(4) : { *(.data) }
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
}

head.S文件

.text
.global _start
_start:
	b reset 
HandleUndef:
	b HandleUndef

HandlerSWI:
	b HandlerSWI 

HandlePrefetchAbort:
	b HandlePrefetchAbort

HandleDataAbort:
	b HandleDataAbort

HandleNotUsed:
	b HandleNotUsed

    b HandleIRQ                    /*中断向量表的位置必须固定,即 b HandleIRQ运行位置必须在0x18处*/

HandleFIQ:
	b HandleFIQ

reset:
	ldr sp,=4096
	bl disable_watch_dog
	bl init_clock                   /*初始化系统时钟,可以提高系统频率,加快执行速度*/
	bl memsetup                     /*存储控制器初始化,使得SDRAM可用,注意这里HCLK=100HZ,*/
	bl copy_steppingstone_to_sdram  /*将代码复制到SDRAM中执行,因为链接地址是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,即使得led引脚为输出引脚*/
	bl init_irq                     /*初始化中断,不屏蔽TOU0中断*/
	bl init_time0                   /*定时器初始化*/
	
	msr cpsr_c,#0x5f                /*开中断*/

	ldr lr,=halt_loop
	ldr pc,=main                    /*进入死循环的main函数,等待中断*/

halt_loop:
	b halt_loop

HandleIRQ:                          /*有IRQ中断到来就跳到此处*/
	sub lr,lr,#4                    /*计算中断返回的地址*/
	stmdb sp!,{r0-r12,lr}           /*保存中断现场*/

	ldr lr,=int_return              /*计算具体中断的返回地址*/
	ldr pc,=EINT_Handle             /*具体中断的函数*/

int_return:
	ldmia sp!,{r0-r12,pc}^          /*返回到中断前的模式中*/
各初始化函数所在文件

#include "s3c2440.h"

void disable_watch_dog(void)
{
	WTCON = 0x00000000;
}

void init_clock(void)
{
	#define MPLL_200MHZ (0x5c<<12)|(0x01<<4)|(0x02)
	CLKDIVN =0x03;/*FCLK:HCLK:PCLK = 4:2:1*/

		__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"        /* 写入控制寄存器 */
    );
	
	MPLLCON = MPLL_200MHZ;
}

void copy_steppingstone_to_sdram(void)
{
	unsigned int *pdest = (unsigned int *)0x30000000;
	unsigned int *psrc  = (unsigned int *)0x00000000;

	while(psrc<(unsigned int *)4096)  //片内存储大小为4k字节,即4096字节
	{
		*pdest=*psrc;                 //将源地址内容复制到目的地址处
		pdest++;
		psrc++;
	}
}

void init_time0(void)
{
	TCFG0 = (99);      /*一级预分频器*/
	TCFG1 = (0x03);    /*二级预分频器16分频*/
	TCNTB0 = 3125;     /*计数初始值*/
	TCON = (1<<1);     /*第一次手动加载*/
	TCON = (0x09);     /*自动加载,清除手动更新,启动定时器0*/
}

void init_irq(void)
{

	/*允许TOU0中断*/
	INTMSK &= ~(0x1<<10);
}

void init_led(void)
{
	GPFCON &= ~( (3<<8) | (3<<10) | (3<<12)); 
	GPFCON |=  ( (0b01<<8) | (0b01<<10) | (0b01<<12) );
	GPFDAT |= (0xf<<4);
}

void memsetup(void)
{
    volatile unsigned long *p = (volatile unsigned long *)0x48000000;

    /* 这个函数之所以这样赋值,而不是像前面的实验(比如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
}
irq.c文件

#include "s3c2440.h"
void EINT_Handle(void)
{
	int oft=INTOFFSET;
	if(10 == oft)
	{
		if((GPFDAT>>4)&1 )
			GPFDAT &=~(1<<4);
		else
			GPFDAT |= (1<<4);
		break;
			
	}

	/*清除中断*/
	SRCPND = 1<
main.c文件

int main(void)
{
while(1);
return 0;
}






你可能感兴趣的:(嵌入式)