嵌入式linux——时钟(三)

时间:2023-03-08 22:32:51

  今天写第一篇,S3C2440的时钟,配置好时钟系统,各个模块才能正常有效的工作,为了了解始终系统,必须要阅读芯片手册,尽量看英文版的,这样还能捎带着增加一下阅读英语计数文档的能力。

概览  

  在2440数据手册的第7章,时钟和电源管理。硬着头皮往下读。主要阅读时钟控制部分,从手册可以知道,CPU用FCLK,AHB总线设备用HCLK,APB总线设备用PCLK。

时钟的架构和选择

  2440的主时钟源可以是外接的晶振,亦可以是外部的时钟源,有一个叫PLL锁相环的东西,他可以产生需要的高时钟源。根据实际的情况选择合适的方式,通过OM[3:2]可以选择时钟源。有个注意事项,在软件配置好MPLLCON寄存器时候,系统的时钟源才是我们想要的,并不是一上电或者复位就是按照我们设定的时钟源工作,他需要一个准备的时间,在准备好之前都是按照外接晶振或者外部的时钟源频率工作的,准备好了才能正常工作。接下来会看到这样一个图,这是2440时钟体系图,从这个图里面可以大致知道从一上电接入外部的晶振后都做了什么,我们才能得到想要的时钟频率。嵌入式linux——时钟(三)

从图中可以看出大致过程:

  1. 设置OM[3:2]两位,选择合适的时钟源。有的开发板,就是用的外接晶振做时钟源,所以干脆把OM2和OM3接接到了GND低电平(OM23是两根引脚)。这里我也一用外部晶振为例来说

  2. 上一步选择完了时钟源的来源,就得到了MPLLin,就是外接的晶振频率,然后经过一个叫MPLL的东西,是配置一个寄存器,P、M、S位。然后得到Mpll。

  3. Mpll在经过CLKCNTL就得到了FCLK,这个是CPU的频率,分了两条线一条是直接发出去,另一条是通过HDIVN和PDIVN两个步骤在发出去,一直到下边可以看到,其实到了这里就是配置好了FCLK、HCLK、PCLK三个频率,现在CPU、AHB总线设备、APB总线设备需要的频率都有了,大家都可以正常工作了。

  4. 有以下公式:

      Mpll = (2*m * Fin) / (p * 2^s)

      m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2

  说的是Mpll的数值确定公式,Fin是输入的频率,就是外接晶振的频率,然后就要设置M、P的值了,第2步,配置某个寄存器完成设置P、M、S。这个后面再说。

  接下来就是更加的细致的结构图了,这里看看就行。,然后会看到这样一个图,完整的描述了上电之后时钟部分所发生的事情。嵌入式linux——时钟(三)

这个图要会看,上电之后,晶振就起振,但是频率并不是用户自己设定的,中间还需要一个时间缓冲,给一点时间才能正常的工作。然后一定要注意,仔细阅读NOTE部分的内容,这里

1. CLKDIVN should be set carefully not to exceed the limit of HCLK and PCLK.
2. If HDIVN is not 0, the CPU bus mode has to be changed from the fast bus mode to the asynchronous
bus mode using following instructions(S3C2440 does not support synchronous bus mode).
MMU_SetAsyncBusMode
mrc p15,0,r0,c1,c0,0
orr r0,r0,#R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
If HDIVN is not 0 and the CPU bus mode is the fast bus mode, the CPU will operate by the HCLK.
This feature can be used to change the CPU frequency as a half or more without affecting the HCLK
and PCLK.

这个就很重要了,说的是HDIVN不是0的话,CPU的总线模式从快总线变为异步总线不支持同步总线,百度一下哈HDIVN不是0,而且是快总线模式,CPU会被HCLK操作,这个特点能够改变CPU频率,嗯。

  After setting PMS value, it is required to set CLKDIVN register. The value set for CLKDIVN will be valid after PLL lock time.这里说的其实就是上面提到的PMS,就是图中要经过的几个方框,配置一些寄存器。了解了这么些东西就可以区配置寄存器了。下面挨个寄存器介绍一下。

  1. LOCK TIME COUNT REGISTER (LOCKTIME) :取最大值就行了,绝对安全。

  2. PLL CONTROL REGISTER (MPLLCON & UPLLCON) :MPLL这个寄存器和输入输出频率有关,手册里有图。

  3. CLOCK CONTROL REGISTER:各种外设使能

  4. CLOCK SLOW CONTROL (CLKSLOW) REGISTER :

  5. CLOCK DIVIDER CONTROL (CLKDIVN) REGISTER:分频相关的,上面确定了输出,即FCLK披绿,这里要分频出PCLK和HCLK

  6. CAMERA CLOCK DIVIDER (CAMDIVN) REGISTER :貌似没用到这个

  

  到此整个时钟就设置完了,其中涉及到了一些计算,很简单的,对应着把这些都计算出来就可以了,然后填入寄存器中。

  刚才写了设置CPU频率的程序,为了对比,把之前写的C语言点亮led的程序,进行了扩展,增加了延时函数,让工作在外部晶振12M时,led闪烁。代码如下

void delay(void)
{
int i = 0XFFFF;
while(i--)
;
}
int main()
{
unsigned int *pGPFCON = (unsigned int *)0x56000050;
unsigned int *pGPFDAT = (unsigned int *)0x56000054; *pGPFCON = 0x100;
*pGPFDAT |= (<<); // off
while()
{
*pGPFDAT &= ~(<<); // & 0 on
delay();
*pGPFDAT |= (<<); // off
delay();
}
return ; }

然后然后再汇编程序中,写设置频率的代码,如下

.text
.global _start
_start: /* 设置时钟 */
/* 外部晶振12M,FCLK-400M,HCLK-100M,PCLK-50M */ /* 1. LOCKTIME 0x4C000000 0xFFFFFFFF */
ldr r0, = 0x4C000000
ldr r1, = 0xFFFFFFFF
str r1, [r0] /* 2. MPLLCON 0x4C000004 (1<<0)|(1<<4)|(92<<12)
* F:H:P = 400:100:50*/
ldr r0, = 0x4C000004
ldr r1, = (<<)|(<<)|(<<)
str r1, [r0] /* 3. 设置CPU工作于异步模式 */
mrc p15,,r0,c1,c0,
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,,r0,c1,c0, /* 4. CLKDIVN 0x4C000014 0x5 */
/*CAMDIVN 0x4C000018 0*/
ldr r0, =0x4C000018
ldr r1, =
str r1, [r0] ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0] ldr sp ,= bl main halt:
b halt

把这段代码烧到板子后,可以看到,小灯闪烁的更加的快了,因为频率有12M提高到了50M。但是我之前是没有加协处理器指令,让CPU工作在异步模式,led闪烁确实快了,但是我不知道为什么,手册里面说,要这么设置,我没这么设置,看着也是成功的,但是还是要按照手册里面的做,加上协处理器指令,还有一个问题,我写的代码设置各个寄存器的顺序和例程不一样(视频看了很久了,这次是自己回忆着, 并且看手册各个寄存器说明做的)不知道有没有问题。不管怎么样现在的现象是实现了,先记录一下。接下来有问题的话,再回来找