mini 2440 PWM定时器(led闪烁) 代码下载
http://www.jyguagua.com/bbs/forum.php?mod=viewthread&tid=187&fromuid=1
PWM定时器的原理:
S3C2440的定时器一共有5个,均是16位定时器.根据S3C2440手册,我们可以知道0,1,2,3四个定时器都有PWM(Pulse Width Modulation)功能, 即他们都有一个输出引脚,可以通过定时器来控制引脚周期性的高低电平变化;定时器4没有输出引脚.
定时器部件的时钟源为:PCLK,首先通过两个8位的预分频处理器降低频率:定时器0,1共用一个预分频处理器, 定时器2,3,4共用第二个预分频处理器,紧接着第二级别分频处理器可以产生:2,4,8,16的分频以及外接TCLK0/TCLK1.每个定时器可以从这5中频率中选择.
1:程序初始化,设定:TCMPBn,TCNTBn这两个寄存器,代表的是定时器n的比较值跟初始计数值;
2:随之设置TCON寄存器启动定时器,这时,TCMPBn,TCMTBn这两个寄存器的值被装入TCMPn, TCMTn的寄存器中,在定时器n的工作频率下,TCMTn开始减1,其值可以通过读取TCNTOn寄存器得知;
3:当TCNTn的值等于TCMPn的时候,定时器n的输出管脚TOUTn反转,TCNTn继续减1计数;
4:当TCNTn的值减到0时, 其输出管脚TOUTn再次反转,并触发定时器n的中断(如果中断使能的话);
5:当TCNTn的值为0时,如果再TCON寄存器中将定时器n设为自动加载,则TCMPB0和TCNTB0寄存器的值被自动装入TCMP0和TCNT0寄存器中,下一个计数接着开始.
下面是代码:
head.S
/*中断向量表*/ b Reset HandleUndef: b HandleUndef HandleSWI: b HandleSWI HandlePrefetchAbort: b HandlePrefetchAbort HandleDataAbort: b HandleDataAbort HandleNotUsed: b HandleNotUsed b HandleIRQ HandleFIQ: b HandleFIQ Reset: ldr sp, =4096 @下面都是C语言,设置栈 bl disable_watch_dog @关看门狗 bl clock_init @初始化时钟 bl memsetup @初始化Sdram bl copy_steppingstone_to_sdram @拷贝前4k代码到0x30000000处 ldr pc, =on_sdram @进入中断 on_sdram: msr cpsr_c, #0xd2 @进入中断模式 ldr sp, =4096 @设置栈,这个是中断模式的栈 msr cpsr_c, #0xdf @进入系统模式 ldr sp, =0x34000000 @系统模式栈 bl init_led @初始化led,全部关闭 bl timer0_init @初始化定时器 bl init_irq @设置irq寄存器 msr cpsr_c, #0x5f @开IRQ中断 ldr lr, =halt_loop ldr pc, =main @调用main函数 halt_loop: b halt_loop HandleIRQ: sub lr, lr, #4 stmdb sp!, {r0-r12, lr} ldr lr, =int_return ldr pc, =Timer0_Handle int_return: ldmia sp!, {r0-r12, pc}^
init.c
#include "s3c2440.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); void disable_watch_dog(void) { WTCON = 0; } void clock_init(void) { CLKDIVN = 0x05; __asm__( "mrc p15, 0, r1, c1, c0, 0\n" "orr r1, r1, #0xc0000000\n" "mcr p15, 0, r1, c1, c0, 0\n" ); if ((GSTATUS1 == 0x32410002)) { MPLLCON = mini2440PLL; } } void memsetup(void) { volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE; /* 存储控制器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++; } } void init_led(void) { GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out; } void timer0_init(void) { TCFG0 = 99; TCFG1 &= 0X02; TCNTB0 = 25000; TCON |= (1<<1); TCON = 0X9; } void init_irq(void) { INTMSK &= (~(1<<10)); INTMOD &= (~(1<<10)); }
interrupt.c
#include "s3c2440.h" void Timer0_Handle(void) { if (INTOFFSET == 10) { GPBDAT = ~(GPBDAT & (0xf << 5)); } SRCPND = 1 << INTOFFSET; INTPND = INTPND; }
interrupt.h
void EINT_Handle();
main.c
int main(void) { while(1); return 0; }
S3C2440.h
/*chip info register*/ #define GSTATUS1 (*(unsigned long *)0x560000b0) /*watch dog register*/ #define WTCON (*(unsigned long *)0x53000000) /*clock registers*/ #define CLKDIVN (*(volatile unsigned long *)0x4C000014) #define MPLLCON (*(volatile unsigned long *)0x4C000004) #define CLKCON (*(volatile unsigned long *)0x4C00000C) #define mini2440PLL ((0x7f<<12)|(0x02<<4)|(0x00)) /*sdram registers*/ #define MEM_CTL_BASE 0x48000000 #define SDRAM_BASE 0x30000000 /*gpio led registers*/ #define GPBCON (*(volatile unsigned long *)0x56000010) #define GPBDAT (*(volatile unsigned long *)0x56000014) #define GPB5_out (1<<(5*2)) #define GPB6_out (1<<(6*2)) #define GPB7_out (1<<(7*2)) #define GPB8_out (1<<(8*2)) /*key interrupt io registers*/ #define GPG0_eint (2) #define GPG3_eint (2<<(3*2)) #define GPG5_eint (2<<(5*2)) #define GPG6_eint (2<<(6*2)) /*interrupt registers*/ #define INTMSK (*(volatile unsigned long *)0X4A000008) #define INTOFFSET (*(volatile unsigned long *)0x4A000014) #define INTPND (*(volatile unsigned long *)0X4A000010) #define INTMOD (*(volatile unsigned long *)0X4A000004) #define SRCPND (*(volatile unsigned long *)0X4A000000) /*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)
timer.lds
SECTIONS { . = 0x30000000; .text : { *(.text) } .rodata ALIGN(4) : {*(.rodata)} .data ALIGN(4) : { *(.data) } .bss ALIGN(4) : { *(.bss) *(COMMON) } }
main.c
int main(void) { while(1); return 0; }
文章的脚注信息由WordPress的wp-posturl插件自动生成