Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2757798
  • 博文数量: 102
  • 博客积分: 1444
  • 博客等级: 中尉
  • 技术积分: 13891
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-29 10:58
文章分类

全部博文(102)

文章存档

2014年(29)

2013年(14)

2012年(59)

分类: LINUX

2013-05-25 12:21:14


 驱动数字电路运转的是时钟信号,时序电路都需要一个外部时钟信号来驱动,完成计时,同步,计数,时序控制等各种功能。像CPU也是时序信号驱动来完成各种运算的,而且像ARM带的模块大部分都与时序有关,因此理解时钟信号对于底层编程非常重要。


一、时钟信号的源头--晶振

    

    数字电路的时钟信号的来源哪里呢?主流的设计方案是使用时钟这种外部器件来产生稳定的电流波形。这是性价比最高的一个方案,晶振是一块水晶加一些电路的小器材,但是它只需要输入很小的电流就可以持续输出稳定时钟波形。

晶振在数字电路的作用就是提供一个基准时间,数字电路都是按照时序进行工作的,在某个时刻专门完成特定的任务,因此几乎每个电路都有会接外部时钟信号的管脚。如果某个时钟信号发生混乱,整个电路就工作不正常了。在一个整体设备里,如开发板或PC主板,所有电路通常共享一个晶振,便于各部分保持同步。有些通讯系统的基频和射频使用不同的晶振,而通过电子调整频率的方法保持同步。


二、系统主频--内部时钟频率


    一般晶振称为外部时钟频率,它需要把信号引入数字电路给CPU和其他模块使用,局限于材料的物理特性,一般的晶振的频率并不是太高。如S5PC100上的晶振频率一般是12MHZ,而对应的CPU需要时钟信号高达667MHZ,或者更高。这个时候,需要把较低外部时钟信号增加到CPU可以接收的频率。这称为倍频。S5PC100的主频最高可达到800MHZ。

    

锁相环电路

    

    倍频的功能是由一种特殊电路--锁相环电路完成的。锁相环电路(Phase-Locked Loop,缩写PLL),PLL基本上是一个闭环的反馈控制系统,它使PLL的输出可以与一个参考信号保持固定的相位关系。PLL在电路的作用之一是起到倍频的作用。即可以输出系统时钟的固定倍数频率。

因为在ARM CPU启动后,最开始必须做的事情就是配置倍频的比率。这样当输入外部时钟频率一定的情况下,按照倍频的比例,就可以得到CPU的频率。在嵌入式CPU里面,一个系统可能出于不同的母的需要不同的频率运行。低频运算速度慢但是省电,高频运算速度快但耗能大。

每个CPU都有一个最高频,如果强行配置成高于设计频率的速度运行,就是人们称的超频。有可能加速CPU老化,运行时散热增加的问题。


一般为了保险,软件开发都会配成产商给的几种标准频率。


三、设备频率

    

    在SOC上,除了CPU内核以外,在一个物理芯片上,还有一些其他模块,以S5PC100为例,它带了I2C,UART,USB等多个模块,这一些模块通过AMBA总线与CPU内核相连,这一些模块同样需要时钟信号来驱动。

但是ARM的主频信号相对于这一些模块来说,频率显得过高。这个时候像S5PC100中内核会提供两种较低频率的时钟信号。HCLK和PCLK两种时钟信号给设备使用。


divider 分频器

    

    但是对一些低频模块,PCLK的频率仍然显得过高,这时需要模块自己使用分频器(divider)来把频率进一步降低。降到多少值一般取决于软件的需求,因此各个模块的分频参数一般都是可以调整的。因此初始化模块时候,软件做的一件重要事情就是设置分频参数。


    Prescaler 预分频因子

    

    有一些模块,如果需要编程来设定分频的比率,通常是用Prescaler即预分频因子这个参数来设定分频后的值,假设输入频率Fin,分频后输出的频率是Fout,而三者有如下关系

Fout = Fin/(Prescaler + 1)

在某一些模块里,分频后的频率仍然是太高,可能需要再次分频,这时分频的参数一般 称为divider value,这样公式变成

Fout = Fin / (Prescaler + 1) / divider

以PWM的定时器的参数为例,它的设置就有如下几个值



以供电系统为例来给这种系统时钟打一个比方

晶振就是发电站,它通过PLL倍频后变成高压电,给CPU传输使用,而模块又使用分频器把高压电降下来给自己使用。


四、S5PC100时钟分析

    

    S5PC100的ARM核心是cortex-A8,核心主频为667MHZ,最高可达800MHZ。

S5PC100的时钟信号可以由外部晶振(XXTI)和外部晶振(XusbXTI),两种方式输入时钟信号。它是由跳线OM[0]决定的,这一位为0 时,由XXTI提供,为1时由XusbXTI提供。


由于外部晶振提供的时钟频率只有12MHZ, 需要通过PLL来倍频。S5PC100提供了4个PLL,分别为:APLL,MPLL,HPLL,EPLL。

APLL给ARM CORE用的,可以产生50MHZ ~ 2GHZ

MPLL主要给系统总线使用,可以产生 12MHZ ~ 600MHZ

EPLL 主要给一些需要特殊频率设备使用(audio),12MHZ ~ 600MHZ

HPLL 主要给HDMI使用,可以产生27MHZ ~ 600MHZ

S5PC100 的时钟系统比较复杂,给一个模块提供的时钟,可以由多条路径提供,我们在实际操作的时候,只需要选择其中的一条路径即可。


这里以配置S5PC100的核ARMCLK为例,讲解S5PC100时钟配置的套路。


下图是从S5PC100的DATASHEET中截取的部分时钟框图。


由上图中红色线标识所示:

图中MUX为多路复用器,如MUXAPLL,将其值设为0,选择 FINAPLL输入(没有倍频),将其值设为1选择FOUTAPLL(APLL倍频)输入。DIV为分频器。

 ARMCLK的时钟可以配置由XXTI输入->APLL倍频->DIVAPLL分频->DIVARM分频->ARMCLK。

以此类推,如果想得到HCLK1的时钟,可以由哪几种选择呢?读者可以自己思考。

下面我们以一个实例来配置ARM核的时钟和总线的时钟,配置的具体时钟频率由下图所示。


  S5PC100的时钟系统分为三个域:D0,D1,D2。不同的域给不同的模块提供时钟。在这里我们只关心D0域和D1域。

如上图所示,现在想把ARMCLK配置成667MHZ,HCLK0配置成166MHZ,PCLK0配置成83MHZ,HCKL1配置成133MHZ,PCLK1配置成66MHZ。


第一步:选择路径

XXTI>APLL->DIVAPLL->DIVARM->ARMCLK

XXTI->APLL->DIVAPLL->DIVARM->DIVD0_BUS->HCLK0

XXTI->APLL->DIVAPLL->DIVARM->DIVD0_BUS->DIVPCLK0->PCLK0

关于HCLK1和PCLK1的时钟路径在选择的时候就都有两条:

其中一条是APLL倍频之后,然后由DIVAM分频后提供的。在这里我们不选择这一条路径。为什么呢?在S5PC100的datasheet中明确说明,DIVAM最高能承受的时钟信号是667MHZ,图中也有标明。由于我们给ARMCLK的时钟是667MHZ,在达到之前还需要通过分频器分频,所以APLL倍频后的时钟频率在这里是要大于667MHZ的。

XXTI->MPLL->DIVD1_BUS->HCLK1

XXTI->MPLL->DIVD1_BUS->DIVPCLK->PCLK1

第二步:配置相关的寄存器(倍频器(PLLCON),分频器(DIV),时钟源选择器(MUX))

在这里我说一下ARMCLK,HCLK0,PCLK0的配置方法,大家可以自己按照datasheet配置一下HCLK1,PCLK1。

XXTI>APLL->DIVAPLL->DIVARM->ARMCLK

XXT1的输入时钟是12MHZ,首先要配置APLL。查看datasheet:


(1)PLL需要屏蔽一段时间,以达到输出稳定的倍频时钟。这个和你开车一样,并不是一下就可以提到你想要的车速,需要一段时间的国度,才可以达到你想要的车速。


需要屏蔽的时间从手册上可以知道,如果输入的是12MHZ,需要屏蔽300us,也就是将PLL_MASKTIME设置成0xE10。


(2)设置倍频值

PLL的倍频值由MDIV,PDIV,SDIV这三个倍频因子决定,即给他们不同的值我们得到不同的频率。他们之间有个换算规则,APLL的换算规则如下:





在这里我们将APLL配置成输出1332MHZ的时钟频率,需要将SDIV的值设为0,PDIV的值设为3,MDIV的值设为333。

主意最后还要将APLL使能哦,即将第31位设为1。

  为了简化开发,一般会有如下固定值给开发人员来设定:



(3)设置分频值

    ARMCLK需要通过DIVAPLL和DIVARM两个分频器分频后得到,手册上说明这两个分频器必须有一个的分频值要大于1。

从手册找到设置分频器的寄存器,如下图所示:



DIVAPLL的值设为1,DIVARM的值设为0,DIVD0_BUS的值设为3,DIVPCLK0的值设为1 即可得到:

ARMCLK = 1332 / 2 = 666MHZ

HCLK0  = 666 / 4  = 166MHZ

PCLK0  = 166 / 2  = 83MHZ

最后给出配置的实验代码:

system_clock_init:

    ldr r0,=S5PC100_CLOCK_BASE

    /*set clock divider*/

    ldr r1,=(1 << 0) + (0 << 4) + (3 << 8) + ( 1 << 12) + ( 1 << 16);

    str r1,[r0,#0x0300]

    ldr r1,=(1 << 12) + (1 << 16);

    str r1,[r0,#0x0304]

    /*set lock time*/

    ldr r1,=S5PC100_PLL_MASKTIME

    str r1,[r0,#0x0000]

    str r1,[r0,#0x0004]

    str r1,[r0,#0x0008]

    str r1,[r0,#0x000c]

    @APLL_CON ~1334MHZ

    @SDIV 0, PDIV 3, MDIV 333   1332MHZ

    @ldr r1,=(APLL_MDIV << 16) + (APLL_PDIV << 8) + (APLL_SDIV << 0)

    ldr r1,=(1 << 31) + (333 << 16) + (3 << 8) + ( 0 << 0)

    str r1,[r0,#0x0100]

    @MPLL_CON ~600MHZ

    @SDIV 1, PDIV 3,MDIV 133   266MHZ

    @ldr r1,=(MPLL_MDIV << 16) + (MPLL_PDIV << 8) + (MPLL_SDIV << 0)

    ldr r1,=(1 << 31) + (133 << 16) + (3 << 8) + (1 << 0)

    str r1,[r0,#0x0104]

    /*Set Source Clock*/

    ldr r1,=0x11        @APLL_SEL 1,MPLL_SEL 1

    str r1,[r0,#0x0200] @CLK_SRC0

    /*wait at least 200us to stablize all clock*/

    ldr r2,=0x10000

1:  subs r2,r2,#1

    bne 1b

    mov pc,lr

stop:

b stop

最后顺便提一下,有些人总是在思考一个问题我的模块具体属于哪一个时钟域呢。这个问题手册上是有说明的,可以通过 CLK_GATE寄存器知道,例如S5PC100的PWM模块,它的时钟是由谁提供的呢?


从上图可以知道,它是由D1时钟域的PCLK提供的。

如何知道自己的时钟是否配置正确了,可以通过示波器去检测,也可以通过流水灯实验观察流水灯的速度。这里我们将ARMCLK的时钟设为了667MHZ,此时观看一下流水灯的速度,将ARMCLK时钟域调低一点(怎么调呀,设对应分频器的值就可以了哦),观看流水灯的速度,可以看到明显变慢。


最后附上整个实验代码:

clock.rar


阅读(6815) | 评论(1) | 转发(10) |
给主人留下些什么吧!~~

zky262014-02-18 13:23:39

草根老师,这篇文章写的很详细~~学习了~~~