下面我们以一个实例来配置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模块,它的时钟是由谁提供的呢?
如何知道自己的时钟是否配置正确了,可以通过示波器去检测,也可以通过流水灯实验观察流水灯的速度。这里我们将ARMCLK的时钟设为了667MHZ,此时观看一下流水灯的速度,将ARMCLK时钟域调低一点(怎么调呀,设对应分频器的值就可以了哦),观看流水灯的速度,可以看到明显变慢。 |