Home » 朱老师嵌入式 » Soc时钟体系框图

Soc时钟体系框图

编 辑:Y ┊ 时 间:2022年04月11日 ┊ 访问: 19 次

时钟体系框图

时钟体系框图的位置:数据手册P361&P362,Figure3-3

24397-4bek2fxea3m.png

76979-31uglr7jcjc.png

第一页完成了主要时钟分配,第二页就是分频了。

由晶振+时钟发生器开始

第二张是总线设备时钟从何而来,由第一个时钟再由第二个分频器分

第二张是第一张图的深入。

(2)两张图之间是渐进的关系。第一张图从左到右依次完成了原始时钟生成->PLL倍频得到高频时钟->初次分频得到各总线时钟;第二张图是从各中间时钟(第一张图中某个步骤生成的时钟)到各外设自己使用的时钟(实际就是个别外设自己再额外分频的设置)。可见,第一张图是理解整个时钟体系的关键,第二种图是进一步分析各外设时钟来源的关键。

65811-kks1j2oyyr.png

梯形的开关是多选一开关,MUX
68817-w5asg6q32a9.png

方形的是DIV分频器
38096-0hw6wkrzkm4.png

(3)要看懂时钟体系框图,2个符号很重要:一个是MUX开关,另一个是DIV分频器。
(3.1)MUX开关就是个或门,实际对应某个寄存器的某几个bit位的设置,设置值决定了哪条通道通的,分析这个可以知道右边的时钟是从左边哪条路过来的,从而知道右边时钟是多少。
(3.2)DIV分频器,是一个硬件设备,可以对左边的频率进行n分频,分频后的低频时钟输出到右边。分频器在编程时实际对应某个寄存器中的某几个bit位,我们可以通过设置这个寄存器的这些对应bit位来设置分频器的分频系数(譬如左边进来的时钟是80MHz,分频系统设置为8,则分频器右边输出的时钟频率为10MHz)。

时钟相关寄存器

58644-1x4gvmmbraj.png
一共有七个寄存器都在进行选择

(3.3)寄存器中的clock source x就是在设置MUX开关;clock divider control寄存器就是在设置分频器分频系数。

33291-enerkfi95jn.png

时钟设置的关键性寄存器

60131-hzq3wrl97sn.png

xPLL_LOCK

xPLL_LOCK寄存器主要控制PLL锁定周期的。

xPLL_CON/xPLL_CON0/xPLL_CON1

PLL_CON寄存器主要用来打开/关闭PLL电路,设置PLL的倍频参数,查看PLL锁定状态等

CLK_SRCn(n:0~6)

CLK_SRC寄存器是用来设置时钟来源的,对应时钟框图中的MUX开关。

CLK_SRC_MASKn

CLK_SRC_MASK决定MUX开关n选1后是否能继续通过。默认的时钟都是打开的,好处是不会因为某个模块的时钟关闭而导致莫名其妙的问题,坏处是功耗控制不精细、功耗高。

CLK_DIVn

各模块的分频器参数配置

CLK_GATE_x

类似于CLK_SRC_MASK,对时钟进行开关控制

46107-r1itwcubws.png

CLK_DIV_STATn / CLK_MUX_STATn

这两类状态位寄存器,用来查看DIV和MUX的状态是否已经完成还是在进行中
总结:其中最重要的寄存器有3类:CON、SRC、DIV。其中CON决定PLL倍频到多少,SRC决定走哪一路,DIV决定分频多少。

代码部分

加入了一个clock.S

在start.S中我们增加了一句

bl clock_init

在makefile中也要修改一下加个 clock.o

重点在clock.S中

初始化时钟

设置各种时钟之前,暂时不使用PLL

汇编实现时钟设置代码详解1

时钟设置的步骤分析:

第1步:先选择不使用PLL。让外部24MHz原始时钟直接过去,绕过APLL那条路

// 1 设置各种时钟开关,暂时不使用PLL
ldr    r1, =0x0
// 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
str    r1, [r0, #CLK_SRC0_OFFSET]    

第2步:设置锁定时间。默认值为0x0FFF,保险起见我们设置为0xFFFF

// 2 设置锁定时间,使用默认值即可
// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
ldr    r1,    =0x0000FFFF                    
str    r1,    [r0, #APLL_LOCK_OFFSET]                
str r1, [r0, #MPLL_LOCK_OFFSET]    

第3步:设置分频系统,决定由PLL出来的最高时钟如何分频得到各个分时钟

// 3 设置分频

// 清bit[0~31]
ldr r1, [r0, #CLK_DIV0_OFFSET]  
ldr r2, =CLK_DIV0_MASK  
bic r1, r1, r2
ldr r2, =0x14131440  
orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]

第4步:设置PLL,主要是设置PLL的倍频系统,决定由输入端24MHz的原始频率可以得到多大的输出频率。我们按照默认设置值设置输出为ARMCLK为1GHz

// 4 设置PLL
// FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
ldr    r1, =APLL_VAL                        
str    r1, [r0, #APLL_CON0_OFFSET]
// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
ldr    r1, =MPLL_VAL                        
str    r1, [r0, #MPLL_CON_OFFSET]

第5步:打开PLL。前面4步已经设置好了所有的开关和分频系数,本步骤打开PLL后PLL开始
工作,锁定频率后输出,然后经过分频得到各个频率。

// 5 设置各种时钟开关,使用PLL
ldr    r1, [r0, #CLK_SRC0_OFFSET]
ldr    r2, =0x10001111
orr    r1, r1, r2
str    r1, [r0, #CLK_SRC0_OFFSET]

总结:以上5步,其实真正涉及到的寄存器只有5个而已。

33291-enerkfi95jn.png

71185-vjr79kavwms.png

CLK_SRC寄存器的设置分析

CLK_SRC寄存器其实是用来设置MUX开关的。在这里先将该寄存器设置为全0,主要是bit0和bit4设置为0,表示APLL和MPLL暂时都不启用。

CLK_LOCK寄存器的设置分析

设置PLL锁定延时的。官方推荐值为0xFFF,我们设置为0xFFFF。

CLK_DIV寄存器的设置分析

20310-uqpz7maqu7c.png

0x14131440这个值的含义分析:
PCLK_PSYS = HCLK_PSYS / 2
HCLK_PSYS = MOUT_PSYS / 5
PCLK_DSYS = HCLK_DSYS / 2
HCLK_DSYS = MOUT_DSYS / 4
·······
HCLK_MSYS = ARMCLK / 5
ARMCLK = MOUT_MSYS / 1

汇编实现时钟设置代码详解2

PLL倍频的相关计算

46327-7k2c5wzlvzn.png

38065-pz0jqofrwz.png

29540-y7agtzetif.png

(1)、我们设置了APLL和MPLL两个,其他两个没有管。
FOUT = MDIVFIN/(PDIV2^(SDIV-1))=0x7d24/(0x32^(1-1))=1000 MHz

十进制的125转16就是7D

#define set_pll(mdiv, pdiv, sdiv)    (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL            set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL            set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)
ldr    r1, =APLL_VAL                        
str    r1, [r0, #APLL_CON0_OFFSET]

(2)、APLL和MPLL设置的关键都是M、P、S三个值,这三个值都来自于官方数据手册的推荐值
(3)、M、P、S的设置依赖《4.2.C语言位运算》中讲过的位运算技术。
42381-zpz7n9ubkkr.png

09817-40pd6jfx0sa.png
// FOUT = MDIVFIN/(PDIV2^SDIV)=0x29b24/(0xc2^1)= 667 MHz

ldr r1, =MPLL_VAL  
str r1, [r0, #MPLL_CON_OFFSET]

FOUT = MDIVFIN/(PDIV2^(SDIV-1))=0x7d24/(0x32^(1-1))=1000 MHz

打开PLL

96026-yt3j3obzvi.png

// 5 设置各种时钟开关,使用PLL
ldr    r1, [r0, #CLK_SRC0_OFFSET]
ldr    r2, =0x10001111
orr    r1, r1, r2
str    r1, [r0, #CLK_SRC0_OFFSET]

85366-8j6k3vokzij.png

结合寄存器、时钟框图、代码三者综合分析S5PV210的时钟系统

分析时记得在图上做标记(把MUX开关选哪个和DIV分频多少都标出来)然后清楚了。

代码:

// 时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE        0xE0100000    

// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#define APLL_LOCK_OFFSET        0x00        
#define MPLL_LOCK_OFFSET        0x08

#define APLL_CON0_OFFSET        0x100
#define APLL_CON1_OFFSET        0x104
#define MPLL_CON_OFFSET            0x108

#define CLK_SRC0_OFFSET            0x200
#define CLK_SRC1_OFFSET            0x204
#define CLK_SRC2_OFFSET            0x208
#define CLK_SRC3_OFFSET            0x20c
#define CLK_SRC4_OFFSET            0x210
#define CLK_SRC5_OFFSET            0x214
#define CLK_SRC6_OFFSET            0x218
#define CLK_SRC_MASK0_OFFSET    0x280
#define CLK_SRC_MASK1_OFFSET    0x284

#define CLK_DIV0_OFFSET            0x300
#define CLK_DIV1_OFFSET            0x304
#define CLK_DIV2_OFFSET            0x308
#define CLK_DIV3_OFFSET            0x30c
#define CLK_DIV4_OFFSET            0x310
#define CLK_DIV5_OFFSET            0x314
#define CLK_DIV6_OFFSET            0x318
#define CLK_DIV7_OFFSET            0x31c

#define CLK_DIV0_MASK            0x7fffffff

// 这些M、P、S的配置值都是查数据手册中典型时钟配置值的推荐配置得来的。
// 这些配置值是三星推荐的,因此工作最稳定。如果是自己随便瞎拼凑出来的那就要
// 经过严格测试,才能保证一定对。
#define APLL_MDIV                   0x7d        // 125
#define APLL_PDIV               0x3
#define APLL_SDIV               0x1

#define MPLL_MDIV                0x29b        // 667
#define MPLL_PDIV                0xc
#define MPLL_SDIV                0x1

#define set_pll(mdiv, pdiv, sdiv)    (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL            set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL            set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)


.global clock_init
clock_init:
    ldr    r0, =ELFIN_CLOCK_POWER_BASE
    
    // 1 设置各种时钟开关,暂时不使用PLL
    ldr    r1, =0x0
    // 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
    str    r1, [r0, #CLK_SRC0_OFFSET]                

    // 2 设置锁定时间,使用默认值即可
    // 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
    ldr    r1,    =0x0000FFFF                    
    str    r1,    [r0, #APLL_LOCK_OFFSET]                
    str r1, [r0, #MPLL_LOCK_OFFSET]                     

    // 3 设置分频
    // 清bit[0~31]
    ldr r1, [r0, #CLK_DIV0_OFFSET]                    
    ldr    r2, =CLK_DIV0_MASK                    
    bic    r1, r1, r2
    ldr    r2, =0x14131440                        
    orr    r1, r1, r2
    str    r1, [r0, #CLK_DIV0_OFFSET]

    // 4 设置PLL
    // FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
    ldr    r1, =APLL_VAL                        
    str    r1, [r0, #APLL_CON0_OFFSET]
    // FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
    ldr    r1, =MPLL_VAL                        
    str    r1, [r0, #MPLL_CON_OFFSET]

    // 5 设置各种时钟开关,使用PLL
    ldr    r1, [r0, #CLK_SRC0_OFFSET]
    ldr    r2, =0x10001111
    orr    r1, r1, r2
    str    r1, [r0, #CLK_SRC0_OFFSET]

    mov    pc, lr



Copyright © 2026 Y 版权所有.网站运行:13年238天21小时25分