JZ2440定时器

来源:互联网 发布:淘宝香水四大靠谱点 编辑:程序博客网 时间:2024/06/08 13:24

裸机系列代码地址:链接: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

开发板上的晶振为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时,

TCON(TIMER CONTROL)
定时器的控制寄存器,用来决定定时器的启动,停止;当计数为0时是否自动将TMPPBn和TCNPBn的值装入定时器内部寄存器;

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


下面是一个定时器的实例

Makefile文件

objs := head.o init.o irq.o main.otime.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:%.carm-linux-gcc -Wall -O2 -c -o $@ $<%.o:%.Sarm-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 HandleUndefHandlerSWI:b HandlerSWI HandlePrefetchAbort:b HandlePrefetchAbortHandleDataAbort:b HandleDataAbortHandleNotUsed:b HandleNotUsed    b HandleIRQ                    /*中断向量表的位置必须固定,即 b HandleIRQ运行位置必须在0x18处*/HandleFIQ:b HandleFIQreset:ldr sp,=4096bl disable_watch_dogbl 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_loopldr pc,=main                    /*进入死循环的main函数,等待中断*/halt_loop:b halt_loopHandleIRQ:                          /*有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);elseGPFDAT |= (1<<4);break;}/*清除中断*/SRCPND = 1<<oft;INTPND = 1<<oft;}
main.c文件

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