S3C2440时钟配置

参考:

http://blog.csdn.net/mr_raptor/article/details/6555734

http://blog.csdn.net/mjx91282041/article/details/8887729

系统时钟

MINI2440开发板在没有开启时钟前,整个开发板全靠一个12MHz的晶振提供频率来运行,也就是说CPU,内存,UART等需要用到时钟频率的硬件都工作12MHz下,而S3C2440A可以正常工作在400MHz下,两者速度相差可想而知,就好比牛车和动车。如果CPU工作在12MHz频率下,开发板的使用效率非常低,所有依赖系统时钟工作的硬件,其工作效率也很低,比如,我们电脑里面经常提到的超频,超频就是让CPU工作在更高的频率下,让电脑运算速度更快,虽然频率是越高越好,但是由于硬件特性决定了任何一个设备都不可能无止境的超频,电脑超频时要考虑到CPU或主板发热过大,烧坏的危险,同样开发板的主板上的外设和CPU也有一个频率限度,ARM920T内核的S3C2440的最高正常工作频率如下:

l   FCLK:400MHz

l   HCLK:100MHz

l   PCLK:50MHz

既然如此,那么怎样让CPU工作在400MHz,让牛车速度提高到动车的速度呢?

1   系统工作时钟频率

在对系统时钟进行提速之前,让我们先来了解下S3C2440上的工作时钟频率,FCLK,HCLK,PCLK,其中FCLK主要为ARM920T内核提供工作频率,如图2-44所示:

 

图2-44  ARM920T内核结构

HCLK主要为S3C2440 AHB总线(Advanced High performance Bus)上挂接硬件提供工作频率,AHB总线主要挂接有内存,NAND,LCD控制器等硬件,如图2-45所示:

 

图2-45 S3C2440 AHB总线上挂接硬件

PCLK主要为APB总线提供工作频率,由图2-46所示,APB总线主要挂接UART串口,Watchdog等硬件控制器。

 

图2-46 S3C2440 APB总线挂接硬件

也就是说,对于一些需要时钟工作的硬件,如果切断其时钟源 ,就不会再工作,从而达到降低功耗的目的,这也是便携嵌入式设备里的一个特点。

时钟源:为了减少外界环境对开发板电磁干扰,降低制作成本,通常开发板的外部晶振时钟频率都很低,MINI2440开发板由12MHz的晶振来提供时钟源,要想让CPU运行在更高的频率就要通过时钟控制逻辑单元PLL(锁相环)来提高主频。

S3C2440里有两个PLL:MPLL和UPLL,MPLL用来产生FCLK,HCLK,PCLK的高频工作时钟,UPLL用来为USB提供工作频率。

 

图2-47系统时钟初始化时序

开发板上电后,晶振OSC开始提供晶振时钟,由于系统刚刚上电,电压信号等都还不稳定,这时复位信号(nRESET)拉低,这时MPLL虽然默认启动,但是如果不向MPLLCON中写入值,那么外部晶振则直接作为系统时钟FCLK,过几毫秒后,复位信号上拉,CPU开始取指运行,这时可以通过代码设置启动MPLL,MPLL启动需要一定锁定时间(LockTime),这是因为MPLL输出频率还没有稳定,在这期间FCLK都停止输出,CPU停止工作,过了LockTime后时钟稳定输出,CPU工作在新设置的频率下,这时可以通过设置FCLK,HCLK和PCLK三者的频率比例来产生不同总线上需要的不同频率,下面详细介绍开启MPLL的过程:

l  设置LockTime变频锁定时间

l  设置FCLK与晶振输入频率(Fin)的倍数

l  设置FCLK,HCLK,PCLK三者之间的比例

LockTime变频锁定时间由LOCKTIME寄存器(见下表)来设置,由于变频后开发板所有依赖时钟工作的硬件都需要一小段调整时间,该时间计数通过设置LOCKTIME寄存器[31:16]来设置UPLL(USB时钟锁相环)调整时间,通过设置LOCKTIME寄存器 [15:0]设置MPLL调整时间,这两个调整时间数值一般用其默认值即可。

表2-8变频锁定时间寄存器(LOCKTIME)

寄存器名

地址

是否读写

描述

复位默认值

LOCKTIME

0x4C000000

R/W

变频锁定时间寄存器

0xFFFFFFFF

 

LOCKTIME

描述

初始值

U_TIME

[31:16]

UPLL对UCLK的锁定时间值

(U_TIME:300us)

0xFFFF

M_TIME

[15:0]

MPLL对于FCLK,HCLK,PCLK的锁定时间值(M_TIME:300us)

0xFFFF

FCLK与Fin的倍数通过MPLLCON寄存器设置,三者之前有以下关系:

MPLL(FCLK) = (2*m*Fin)/(p*2^s)

其中:m = MDIV + 8, p = PDIV + 2, s = SDIV

当设置完MPLL之后,就会自动进入LockTime变频锁定期间,LockTime之后,MPLL输出稳定时钟频率。

表2-9 MPLL配置寄存器(MPLLCON)

寄存器名

地址

是否读写

描述

复位默认值

MPLLCON

0x4C000004

R/W

MPLL配置寄存器

0x00096030

 

MPLLCON

描述

初始值

MDIV

[19:12]

主分频器控制位

0x96

PDIV

[9:4]

预分频器控制位

0x03

SDIV

[1:0]

后分频器控制位

0x0

通过上述算法比较难以找到合适的PLL值,下表给出了官方推荐的一些MPLL参考设置:

表2-10 官方推荐MPLL

 

FCLK,HCLK,PCLK三者之间的比例通过CLKDIVN寄存器进行设置,S3C2440时钟设置时,还要额外设置CAMDIVN寄存器,如下表,HCLK4_HALF,HCLK3_HALF分别与CAMDIVN[9:8]对应,下表列出了各种时钟比例:

表2-11 FCLK HCLK PCLK设置比例

 

如果HDIV设置为非0,CPU的总线模式要进行改变,默认情况下FCLK = HCLK,CPU工作在fast bus mode快速总线模式下,HDIV设置为非0后, FCLK与HCLK不再相等,要将CPU改为asynchronous bus mod异步总线模式,可以通过下面的嵌入汇编代码实现:

__asm{ 

mrc p15, 0, r1, c1, c0, 0         /* 读取CP15 C1寄存器 */ 

orr r1, r1, #0xc0000000         /* 设置CPU总线模式 */ 

mcr p15, 0, r1, c1, c0, 0         /* 写回CP15 C1寄存器 */

关于mrc与mcr指令,请查看MMU与内存保护的实现章节。

表2-12时钟分频器控制寄存器(CLKDIVN)

寄存器名

地址

是否读写

描述

复位默认值

CLKDIVN

0x4C000014

R/W

时钟分频器控制寄存器

0x00000000

 

CLKDIVN

描述

初始值

DIV_UPLL

[3]

UCLK选择寄存器(UCLK必须对USB提供48MHz)

0:UCLK=UPLL clock

1:UCLK=UPLL clock/2

0

HDIVN

[2:1]

00:HCLK = FCLK/1

01:HCLK = FCLK/2

10:HCLK = FCLK/4,当CAMIVN[9]=0

HCLK = FCLK/8,当CAMIVN[9]=1

11: HCLK = FCLK/3,当CAMIVN[8]=0

HCLK = FCLK/6,当CAMIVN[8]=1

0

PDIVN

[0]

0:PCLK是和HCLK/1相同时钟

1:PCLK是和HCLK/2相同时钟

0

表2-13摄像头时钟分频控制寄存器(CAMDIVN)

寄存器名

地址

是否读写

描述

复位默认值

CAMDIVN

0x4C000018

R/W

摄像头时钟分频控制寄存器

0x00000000

 

CAMDIVN

描述

初始值

HCLK4_HALF

[9]

HDIVN分频因子选择位(当CLKIVN[2:1]位为10b时有效)

0: HCLK=FCLK/4

1: HCLK=FCLK/8

0

HCLK3_HALF

[8]

HDIVN分频因子选择位(当CLKIVN[2:1]位为11b时有效)

0: HCLK=FCLK/3

1: HCLK=FCLK/6

0

2    时钟驱动实验

系统时钟驱动可以分别用ARM汇编和C语言两个版本实现。

ARM汇编版本:

; 以下为时钟相关寄存器地址

LOCKTIME                                    EQU     0x4c000000        

MPLLCON                                 EQU                   0x4c000004       

CLKDIVN                                  EQU                   0x4c000014

CAMDIVN                                          EQU                   0x4c000018

 

clock_init                                                            ; 时钟初始化代码

    ; 设置变频锁定时间

    ldr r0, =LOCKTIME

    ldr r1, =0x00ffffff

    str r1, [r0]

 

    ; 设置分频比FCLK:HCLK:PCLK=1:4:8

    ; 由于CAMDIVN[9]位初始值为0,寄存器CAMDIVN未使用,这儿不用再设置其值

    ldr r0, =CLKDIVN

    mov r1, #0x05

    str r1, [r0]

 

    ; 修改CPU总线模式

    mrc   p15, 0, r1, c1, c0, 0

    orr    r1, r1, #0xc0000000

    mcr     p15, 0, r1, c1, c0, 0

 

    ldr r0, =MPLLCON

    ldr r1, =0x5c011                                ; MPLL = 400MHz

str r1, [r0]

mov pc, lr                                           ; 函数调用返回

该汇编代码入口处先设置了变频锁定时间为0x00ffffff,然后设置FCLK:HCLK:PCLK的分频比,由于系统时钟已经改变,需要修改CPU总线模式,最后设置系统时钟工作频率。

C语言版本:

/* 通过MPLL计算公式可以算出:MDIV=92,PDIV=1,SDIV=0时,MPLL=400MHz

#define MPLL_400MHz ((92 << 12)|(1 << 4)|(1 << 0))

void clock_init(void){

           /* 设置变频锁定时间 */

           LOCKTIME = 0x00ffffff;

           /* 设置分频比FCLK:HCLK:PCLK=1:4:8,CAMDIVN初始值为0,不用再对其设置 */

           CLKDIVN  = 0x05;

           /* 修改CPU总线模式 */

           __asm{

                    mrc   p15, 0, r1, c1, c0, 0

                    orr     r1, r1, #0xc0000000

                    mcr p15, 0, r1, c1, c0, 0
              }

           MPLLCON = MPLL_400MHz;

}

C语言版本与汇编版本一样,只是由于修改CPU总线模式时要使用mrc指令,因此只能使用C语言嵌入汇编方式来实现。

 

系统时钟驱动实验:

;

; 系统时钟初始化实验

;

WTCON                        EQU          0x53000000        ; 看门狗控制寄存器

WTDAT                         EQU          0x53000004        ; 看门狗数据寄存器

LOCKTIME                  EQU     0x4c000000         ; 变频锁定时间寄存器

MPLLCON                   EQU          0x4c000004        ; MPLL寄存器

CLKDIVN                    EQU          0x4c000014        ; 分频比寄存器

GPBCON                      EQU      0x56000010        ; LED控制寄存器

GPBDAT                       EQU      0x56000014        ; LED数据寄存器

GPBUP                         EQU      0x56000018        ; 上拉电阻设置寄存器

DELAYVAL                  EQU      0x8fff                  ; 延时数值

 

         AREA    CLOCK, CODE, READONLY

         ENTRY
         start

           ldr r0, = 0x53000000                      ; 看门狗关闭代码

         mov  r1, #0

         str  r1, [r0]



         bl  clock_init                                  ; 调用时钟初始化函数

         bl  led_on                                      ; 调用点亮Led函数

 

clock_init                                                  ; 时钟初始化代码

           ; 设置锁频时间

    ldr r0, =LOCKTIME                         ; 取得LOCKTIME寄存器地址

    ldr r1, =0x00ffffff                              ; LOCKTIME寄存器设置数据

    str r1, [r0]                                          ; 将LOCKTIME设置数据写入LOCKTIME寄存器

           ; 设置分频数

    ldr r0, =CLKDIVN                           ; 取得CLKDIVN寄存器地址

    mov r1, #0x05                                   ; CLKDIVN寄存器设置数据

    str r1, [r0]                                          ; 将CLKDIVN设置数据写入CLKDIVN寄存器

 

    ; 修改CPU总线模式

    mrc    p15, 0, r1, c1, c0, 0

    orr    r1, r1, #0xc0000000

    mcr    p15, 0, r1, c1, c0, 0

 

    ldr r0, =MPLLCON

    ldr r1, =0x5c011                                ; MPLL is 400MHz

    str r1, [r0]

    mov pc, lr

 

led_on                                                        ; 亮点Led函数

           ; Led初始化开始

    ldr  r0,=GPBCON                        ; 将LED控制寄存器地址放入r0

    ldr  r1,[r0]                                        ; 将控制寄存器里的值读出放入r1

    bic  r1,r1,#0x3fc00                          ; 将r1里的值(控制寄存器里的值)

                                                              ; bit[10]~bit[17]清位,其它位不变

    orr  r1,r1,#0x15400                         ; 设置控制寄存器

    str  r1,[r0]                                        ; 将r1里的值写入控制寄存器

   

    ; 禁止GPF4-GPF7端口的上拉电阻

    ldr  r0,=GPBUP

    ldr  r1,[r0]

    orr  r1,r1,#0x1e0

    str  r1,[r0]

           ; Led初始化结束

 

 

led_loop                                                     ; 循环点亮Led

    ldr  r2,=GPBDAT                                     ; 将LED数据寄存器的地址放入r2

    ldr  r3,[r2]                                        ; 将数据寄存器(r2)里的值放入r3

    bic  r3,r3,#0x1e0                              ; 清除bit[5]~bit[8],bit[n]代表led1~led4

    orr  r3,r3,#0x1c0                              ; 清对应Led位-亮灯,设置相应位-灭灯(点亮led1)

    str  r3,[r2]                                       ; 将控制亮灯数据写入数据寄存器r2

    ldr r0,=DELAYVAL                         ; 设置延迟数

    bl   delay                                         ; 调用延迟子程序

 

    ldr  r3,[r2]                                        ; 将数据寄存器(r2)里的值放入r3

    bic  r3,r3,#0x1e0                              ; 清除bit[5]~bit[8],bit[n]代表led1~led4

    orr  r3,r3,#0x1a0                              ; 清对应Led位-亮灯,设置相应位-灭灯(点亮led2)

    str  r3,[r2]                                       ; 将控制亮灯数据写入数据寄存器r2

    ldr r0,=DELAYVAL                         ; 设置延迟数

    bl   delay                                       ; 调用延迟子程序

 

    ldr  r3,[r2]                                        ; 将数据寄存器(r2)里的值放入r3

    bic  r3,r3,#0x1e0                              ; 清除bit[5]~bit[8],bit[n]代表led1~led4

    orr  r3,r3,#0x160                             ; 清对应Led位-亮灯,设置相应位-灭灯(点亮led3)

    str  r3,[r2]                                       ; 将控制亮灯数据写入数据寄存器r2

    ldr r0,=DELAYVAL                         ; 设置延迟数

    bl   delay                                       ; 调用延迟子程序

 

    ldr  r3,[r2]                                        ; 将数据寄存器(r2)里的值放入r3

    bic  r3,r3,#0x1e0                              ; 清除bit[5]~bit[8],bit[n]代表led1~led4

    orr  r3,r3,#0xe0                               ; 清对应Led位-亮灯,设置相应位-灭灯(点亮led4)

    str  r3,[r2]                                       ; 将控制亮灯数据写入数据寄存器r2

    ldr r0,=DELAYVAL                         ; 设置延迟数

    bl   delay                                      ; 调用延迟子程序

 

    b led_loop

   

delay

         sub r0,r0,#1                             ; r0=r0-1

           cmp r0,#0x0                                   ; 将r0的值与0相比较

bne delay                                                  ; 比较的结果不为0,继续调用delay

           mov pc,lr                                        ; 返回

    END                                ; 程序结束符

该实验首先关闭了看门狗定时器,然后修改系统时钟,将默认系统工作频率12MHz提高到400MHz,由于CPU工作在较高频率下,其执行速度明显比未启动系统时钟时高的多,可以通过注释掉系统时钟初始化代码跳转指令 bl clock_init,对比LED的跑马灯效果可以证明。

-----------------------------------------------------------------------------------------------------------------------------

 在移植Nboot时,发现串口输出乱码,检查串口配置没问题后,觉得应该是时钟配置没配好,修改后果然ok,所以补习一下!
2440时钟配置详细说明,以上电为顺序讲述:

一、S3C2440A时钟概述

     1、S3C2440A的电源管理有4种模式:NORMAL,SLOW,IDLE,SLEEP。

     2、 有4种时钟:FCLK,HCLK,PCLK,UCLK具体分工如下:

FCLK is used by ARM920T.
HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, the interrupt controller, the LCD
                    controller, the DMA and USB host block.
PCLK is used for APB bus, which is used by the peripherals such as WDT, IIS, I2C, PWM timer, MMC interface,
                    ADC, UART, GPIO, RTC and SPI.

           UCLK专门为USB供电,有UPLL输出。

      3、有两个锁相环,一个MPLL负责FCLK,HCLK,PCLK,一个UPLL负责USB的48MHz,通过三个倍频因子MDIV、PDIV和SDIV来 设置倍频

二、S3C2440A时钟上电过程

       1、主时钟源可以由外部时钟(EXTCLK)或者外部晶振(XTIPll)提供,时钟源由模式控制引脚OM3和OM2选择,在复位信号

              的上升沿检测OM3和OM2引脚状态并锁定在OM[3:2]中。

      2、我们可以在程序开头启动MPLL,在设置MPLL的几个寄存器后,需要等待一段时间(Lock Time),MPLL的输出才稳定。在这段 

            (Lock Time)时间内,FCLK停振,CPU停止工作。Lock Time的长短由寄存器LOCKTIME设定。Lock Time之后,MPLL输出平    

         稳。在上电没有设置MPLL时,系统时钟为晶振时钟。

三、S3C2440A时钟配置流程和样例

      1、设置S3C2440A的时钟频率需要配置4个寄存器:LOCKTIME(0x4C000000)CLKDIVN (0x4C000014)MPLLCON

        ( 0x4C000004)UPLLCON(0x4C000008)。

      2、时钟配置顺序如上:LOCKTIME => CLKDIVN  => MPLLCON => UPLLCON。注意:UPLL的设置要先于MPLL,切超前7个时钟

            设置。

      3、时钟样例:

          (1)、LOCKTIME:位[31:16]用于UPLL,位[15:0]用于MPLL。确省值为0xFFFFFFFF

          (2)、CLKDIVN:DIVN _UPLL[3]:HDIVN [2:1]:PDIVN [0]用来设置FCLK:HCLK:PCLK的比例关系,默认为1:1:1。

                       CLKDIVN不同的设置及对应的时钟比例关系如下图:

                             图HDIVN 和PDIVN对应的比例,HCLK4_HALF和HCLK3_HALF在摄像头CAMDIVN寄存器中。  

          ( 3)MPLLCON寄存器位[19:12]-MDIV(Main divider control);[9:4]-PDIV(Pre-divider control);[1:0]-SDIV(Post divider        

                    control)。                     

 

             锁相环输出时钟MPLL(FCLK) 通过如下计算公式得出:

                              MPLL(FCLK) = (m * Fin)/(p * 2^s);其中:m = (MDIV + 8), p = (PDIV + 2), s = SDIV,Fin 输入的时钟频率。

                     如:MPLLCON设为(0x5c << 12)|(0x01 << 4)|(0x1),即0x5c010,可以计算出FCLK=200MHz,假设CLKDIVN设置 

                      HDIV=1和PDIV=1;可知比例FCLK、HCLK、PCLK比率为1:2:4,所以HCLK=100MHz,PCLK=50MHz。

                     下图 为锁相环配置推荐表。

            UPLLCON同理一样设置,计算公式如下UPLL(UCLK) = (m * Fin) / (p * 2^s),m = (MDIV + 8), p = (PDIV + 2), s =SDIV。

       Fin 输入的时钟频率。

   (4)程序:

  1. ;To reduce PLL lock time, adjust the LOCKTIME register.  
  2.   ldr r0,=LOCKTIMEldr r1,=0xffffffstr r1,[r0] ;Configure CLKDIVN  
  3.  ; Added for confirm clock divide. for 2440.; Setting value Fclk:Hclk:Pclkldr r0,=CLKDIVNldr r1,=CLKDIV_VAL; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.str r1,[r0];Configure UPLL  
  4.     ldr r0,=UPLLCON  
  5.     ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)    
  6.     str r1,[r0]  
  7.     nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.  
  8.     nop  
  9.     nop  
  10.     nop  
  11.     nop  
  12.     nop  
  13.     nop  
  14. ;Configure MPLL  
  15.     ldr r0,=MPLLCON  
  16.     ldr r1,=((96<<12)+(M_PDIV<<4)+M_SDIV)  ;Fin=16.9344MHz  68<<12+1<<4+1  
  17.     str r1,[r0]  

四、时钟修改影响单元


    在移植程序是要注意时钟修改后对应的模块频率也改变了,我的Nboot移植时,需要修改两个地方:UART 和 SDRAM。 UART,它是接在APB总线上,对应的时钟信号为PCLK,假设现在为50MHz。如果想要设置波特率为115200bps,那么根公式 UBRDIV0=(int)(PCLK/(bps*16))-1计算,应该为26。程序:UBRDIV0 = ((int)(PCLK/16./UART_BAUD_RATE) -1).

 

原文地址:https://www.cnblogs.com/pengdonglin137/p/3378662.html