参考韦东山嵌入式
S3C2440有三种时钟:FCLK HCLK PCLK
FCLK: CPU
HCLK :内存芯片,网卡等
PCLK :UART,定时器等
设置这三种时钟的方式:晶振通过PLL,达到一个很高的频率FCLK ,然后将FCLK 分频,以达到想要的HCLK PCLK;
下图是S3C2440CPU,系统刚上电时cpu运行的频率FCLK等于晶振OSC的频率,通过PLL设置,FCLK达到一个新的很高的频率。图中有一个锁定时间,在锁定时间内,cpu停止运行,当频率稳定后,CPU再次开始以新的频率运行。
通过上面的表述,需要对PLL进行设置:
①锁定时间:LOCKTIME 寄存器
②PLL寄存器:MPLLCON 通过这个寄存器,设置MPLL(FCLK)寄存器的值
②分频寄存器:CLKDIVN 设置HCLK PCLK寄存器的值
/** 对于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*/
如下是启动代码以及时钟初始化代码:
@******************************************************************************
@ 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 HandleFIQReset: ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLKbl memsetup @ 设置存储控制器以使用SDRAMbl 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_loopHandleIRQ:sub lr, lr, #4 @ 计算返回地址stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器@ 注意,此时的sp是中断模式的sp@ 初始值是上面设置的4096ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址 ldr pc, =Timer0_Handle @ 调用中断服务函数,在interrupt.c中
int_return:ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
其中clock_init 是c代码实现,如下:
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
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=200MHz,HCLK=100MHz,PCLK=50MHz */}else{MPLLCON = S3C2440_MPLL_200MHZ; /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */}
}
下图是芯片手册中对相关寄存器的说明:
1、锁定时间寄存器(LOCKTIME)
2、PLL控制寄存器
3、分频寄存器