自己的总结:
1.2440 有俩个PLL ,UPLL 和MPLL 。UPLL 用于USB 时钟UCLK ,MPLL 对应FCLK .HCLK 、PCLK 。ARM 启动时直接使用外部晶振作为CPU 时钟,对应2440 为12Mhz 。只有在设置了时钟寄存器M P S 三个值,具体的寄存器PLLCON 下面已经说得很清楚了。设置分频寄存器后CPU 时钟即采用倍频后的FCLK 时钟。
2. CPU 时钟即就是FCLK 时钟,HCLK 从FCLK 分频,PCLK 从HCLK 分频。具体的分频比例需要设置寄存器CLKDIVN ,详细见手册。
3. 系统要工作需要首先设置好时钟,时钟是CPU 及外设工作的心脏,当你没有设置时钟时CPU 直接使用外部晶振,所以有些慢设没有设置时钟也能工作。时钟设置时有一个CPU 时钟模式- 快速总线模式和异步时钟模式,具体是实现找了好多资料都没有弄明白,大概有一些了解的地方是 ,快速总线模式下且HDIVN 不为0 时,CPU 使用HCLK 时钟且可以改变CPU 时钟但不改变FCLK 和PCLK 的频率。
下面是转载别人的:
S3C2410 CPU 默认的工作主频为12MHz ,使用PLL 电路可以产生更高的主频供CPU 及外围器件使用 。S3C2410 有两个PLL :MPLL 和UPLL ,UPLL 专用与USB 设备。MPLL 用于CPU 及其他外围器件。
通过MPLL 会产生三个部分的时钟频率:FCLK 、HCLK 、PLCK 。FCLK 用于CPU 核,HCLK 用于AHB 总线的设备( 比如SDRAM) ,PCLK 用于APB 总线的设备( 比如UART) 。从时钟结构图中可以查看到使用不同时钟频率的硬件。
Figure 7-1. Clock Generator Block Diagram
(注:这里要注意从图中看出,Uart 使用的是PCLK )
时钟源选择
表 7-1 描述了模式控制引脚 (OM3 和 OM2) 和选择时钟源之间的对应关系。 OM[3:2] 的状态由 OM3 和 OM2 引脚的状态在 nRESET( 当振荡器 (crystal/oscillatto) 时钟输出稳定后, nRESET 引脚变为高电平 ) 的上升沿锁存得到。
注意: 1 、尽管 MPLL 在系统复位的时候就开始产生,但是只有有效的设置好 MPLLCON 寄存器后 才能用于系统时钟。在此之前,外部时钟将直接作为系统时钟 。即使不需要改变 MPLLCON 寄存器的初值,也必须 将同样的值写入寄存器。
2 、当 OM[1:0] 为 11 时, OM[3:2] 用于决定一种测试模式。
下面介绍MPLL 的启动流程:
(注:下面内容部分直接摘录自《s3c2410 完全开发流程》,Clock 部分写了非常好)
S3c2410 datasheet 224 页“Figure 7-4. Power-On Reset Sequence” 展示了上电后MPLL 启动的过程
请跟随FCLK 的图像了解启动过程:
1 、上电几毫秒后,晶振输出稳定,FCLK= 晶振频率,nRESET 信号恢复高电平后,CPU 开始执行指令。
2 、我们可以在程序开头启动MPLL ,在设置MPLL 的几个寄存器后,需要等待一段时间(Lock Time) , MPLL 的输出才稳定。在这段时间(Lock Time) 内,FCLK 停振,CPU 停止工作。Lock Time 的长短由寄存器LOCKTIME 设定。
3 、Lock Time 之后,MPLL 输出正常,CPU 工作在新的FCLK 下。
设置S3c2410 的时钟频率就是设置MPLL 的几个寄存器:
1 、LOCKTIME :设为0x00ffffff
前面说过,MPLL 启动后需要等待一段时间(Lock Time) ,使得其输出稳定。位[23:12] 用于UPLL ,位[11:0] 用于MPLL 。使用确省值0x00ffffff 即可。
2 、CLKDIVN :用来设置FCLK:HCLK:PCLK 的比例关系,默认为1:1:1
这里值设为0x03 ,即FCLK:HCLK:PCLK=1:2:4
CLKDIVN 不同的设置及对应的时钟比例关系如下图:
3 、MPLLCON :设为(0x5c << 12)|(0x04 << 4)|(0x00) ,即0x5c0040
对于MPLLCON 寄存器,[19:12] 为MDIV ,[9:4] 为PDIV ,[1:0] 为SDIV 。有如下计算公式:
MPLL(FCLK) = (m * Fin)/(p * 2^s)
其中: m = MDIV + 8, p = PDIV + 2
Fin 即默认输入的时钟频率12MHz 。MPLLCON 设为0x5c0040 ,可以计算出FCLK=200MHz ,再由CLKDIVN 的设置可知:HCLK=100MHz ,PCLK=50MHz 。
通常我们将如上时钟初始化的过程写成clock_init 函数供其他函数调用,代码如下:
void clock_init(void)
{
/*init clock*/
rLOCKTIME = 0xFFFFFF;
/* 设置FCLK:HCLK:PCLK=1:2:4, 这样假设处理器主频为200M, 则HCLK 为50M,PCLK 为25M 。ARM920T 内核使用FCLK, 内存控制器,LCD 控制器等使用HCLK ,看门狗、串口等使用PCLK*/
rCLKDIVN = 0x3;
/* 设置时钟频率为200M*/
rMPLLCON = 0x5c0040;
}
改变2410 的PLL 频率,具体过程:
1 、第一步软件工作: 设置P M S divider control ,也就是设置MPLLCON 寄存器。
关于PMS ,可以看Figure 7-2. 寄存器MPLLCON 的设置呢,其实有一定的规则,并非你想要的每个Fclk 频率都可以得到。官方推荐了一个表PLL VALUE SELECTION TABLE ,要按照这个进行。否则的话,就需要自己按照公式推算,但是mizi 公司并不保证你的设置是合适的。所以,如果想要工作在200MHz ,还是按 照vivi 的推荐值即可。
@ step1: set P M S divider control mov r1, #CLK_CTL_BASE ldr r2, =vMPLLCON_200 str r2, [r1, #oMPLLCON] |
其中,MDIV=0x5c ,PDIV=0x04 ,SDIV=0x00. 公式Mpll (Fclk )= (m×Fin )/ (p×(2^s) )【m=MDIV+8, p=PDIV+2,s=SDIV 】
2 、第二步软件工作:设置CLKDIVN 。
这一步是设置分频系数,即Fclk 为cpu 主频,Hclk 由Fclk 分频得到,Pclk 由Hclk 分频得到。假设Hclk 是Fclk 的二分频,Pclk 是 Hclk 的二分频,那么分频系数比就是Fclk :Hclk :Pclk=1 :2 :4. 那么Hclk 为100MHz ,总线时钟周期为10ns 。Pclk 为 50MHz 。
@ step2: change clock divider mov r1, #CLK_CTL_BASE mov r2, #vCLKDIVN str r2, [r1, #oCLKDIVN] |
3 、第三步软件工作: CLKDIVN 的补充设置
void ChangeClockDivider(int hdivn,int pdivn)
{
// hdivn,pdivn FCLK:HCLK:PCLK
// 0,0 1:1:1
// 0,1 1:1:2
// 1,0 1:2:2
// 1,1 1:2:4
rCLKDIVN = (hdivn<<1) | pdivn;
if(hdivn)
MMU_SetAsyncBusMode();
else
MMU_SetFastBusMode();
}
If HDIVN = 1, CPU 总线模式必须从快速总线模式转变为同步总线模式,采用以下指令 ;void MMU_SetFastBusMode(void) ; FCLK:HCLK= 1:1 EXPORT MMU_SetFastBusMode MMU_SetFastBusMode mrc p15,0,r0,c1,c0,0 bic r0,r0,#R1_iA:OR:R1_nF mcr p15,0,r0,c1,c0,0 MOV_PC_LR If HDIVN=1 and CPU 总线模式为快速总线模式时, CPU 由HCLK 提供. 该特性可以在不改变HCLK and PCLK 的前提下把CPU 的频率减半. |
;void MMU_SetAsyncBusMode(void) ; FCLK:HCLK= 1:2 EXPORT MMU_SetAsyncBusMode MMU_SetAsyncBusMode mrc p15,0,r0,c1,c0,0 orr r0,r0,#R1_nF:OR:R1_iA mcr p15,0,r0,c1,c0,0 MOV_PC_LR |
4 、第四步软件工作:等待locktime 时间,让新的Fclk 生效
@ step4: stay locktime mov r1, #CLK_CTL_BASE ldr r2, =vLOCKTIME str r2, [r1, #oLOCKTIME] |
6 、对外设的影响
在这个实验中,主要是有两个需要改变,一个外设是UART ,一个外设是SDRAM 。
(1 )UART ,它是接在APB 总线上,所以对应的时钟信号为Pclk ,现在为50MHz 。如果想要设置波特率为115200bps ,那么根据公式 UBRDIV0=(int)(PCLK/(bps*16))-1 计算,应该为26 。如果放到程序中,那么应该注意形式。具体如下:
UBRDIV0 = ((int)(PCLK/16./UART_BAUD_RATE) -1); |
(2 )SDRAM ,主要的影响因素为刷新频率。前面在SDRAM 中没有具体分析,现在可以详细说明。使用了两片HY57V561620CT-H ,查看手册 其刷新频率为8192 refresh cycles/64ms ,所以刷新周期64ms/8192 =7.8125us 。看寄存器REFRESH 的各个位的设置情况:
·REFEN[23] :开启自动模式,设为1
·TREFMD[22] :设为Auto refresh 模式,设为0
·Trp[21:20] :看看RAS precharge Time ,查看SDRAM 手册,发现-H 系列此参数至少为20ns ,现在Hclk 对应的时钟周期为10ns ,所以至少应该为2 个clock 。可以设为00
·Tsrc : Semi Row Cycle Time ,也就是RAS Cycle Time ,至少65ms ,所以至少得6.5clock ,按照可选值,应该设置为11
·Refresh[10:0] :
公式refresh period = (2^11 - refresh_count +1)/Hclk ,由此推导出refresh_count=2^11+1-refresh period*Hclk 。带入数值,计算得出1268 =0x04f4 ,这个数值要用四舍五入,减少误差。
· 其余的保留值,均设置为0
由此得出该寄存器的值应该为0x008c04f4 。