mini 2440 PWM定时器(led闪烁)

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: mini 2440 PWM定时器(led闪烁)

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

 

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: mini 2440 PWM定时器(led闪烁)

文章的脚注信息由WordPress的wp-posturl插件自动生成



|2|left
打赏

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: