- Forums
- Resources
- About
- Groups
Close
大家好,这是这周的时钟系统说明的补充。主要说明时钟初始化的代码,希望这周能结束时钟部分,下周开始启动配置。(其实不准备现在写,隔壁姑娘打电话把我吵醒了。。。很尴尬。)
在配置之前,我们首先要选择晶振频率,并且设定时钟倍频的目标时钟。这些都被事先定义为宏:
很明显是一簇条件编译的指令,所以我们需要准备一个头文件,定义好晶振时钟和时钟倍频的目标。如下定义是在if_cfg.h头文件里定义的:20MHz-200MHz。
正如我们上一个帖子所描述的,时钟配置可以在启动阶段的SSW里面配置,也可以在启动后立即进行配置。ILLD当中,时钟是在启动文件的后半段进行配置的,调用了时钟初始化函数:
IfxScuCcu_init(&IfxScuCcu_defaultClockConfig);
函数的定义为:boolean IfxScuCcu_init(const IfxScuCcu_Config *cfg);
该函数的工作就是配置时钟源、PLL配置、时钟分频三个部分。在进行函数分析之前,我们先讲讲该函数调用的参数:结构体指针类型:cfg。ILLD给出的IfxScuCcu_defaultClockConfig是 该函数的实参,是事先定义好的宏,该数据里面包括所有时钟配置需要的参数。以下是该数据结构体的定义:
(找不到插入代码的选项,只能这么看了。。。)我们看到该结构体定义了5个成员。如果我们以20MHz的晶振为例,目标是倍频到200MHz。因为如上一贴所说,时钟频率不能瞬间变化。我们的想法是先给定一个时钟基准,假如是100MHz,然后一步一步倍频到目标时钟。第一个参数就是指达到目标时钟倍频的次数,illd推荐的从100MHz到200MHz倍频三次,从120MHz、150 MHz到200MHz,当然也可以进行个性化设置。而以下代码就是时钟倍频设置的宏,总共有三次倍频,也就是第一个参数等于3。
而第二个成员,是指向每次时钟倍频的配置数组的首地址,该数组就是通过上述宏定义的。数组的三个元素就是三次时钟倍频的配置结构体,而对应的配置值为K2,分别是5、4、3。
然后我们看第三个成员:初始化时钟分频因子,其实就是我们刚刚所说的配置一个基准时钟100MHz,当然这个值也可以因人而异。以下就是20MHz倍频到200MHz的基准时钟100MHz宏定义:
我们得到了P=2;N=60;K2=6;而f_OSC=20MHz,带入正常模式PLL时钟计算公式:
f_PLL=N/(P*K2) f_OSC=100MHz;
第四个成员,终于到了为每个模块分频的配置。我们知道时钟分频是CCU单元负责的,它共有八个CCU控制寄存器。这里就是对着八个寄存器进行配置。
寄存器的定义有个小窍门(我也是刚学会)。
通过这个结构体,先定义寄存器相应位域的值value;然后定义寄存器相应位域的位数mask。最后将两个值相与,结果就很严格了,不会相互干扰。以下就是寄存器的宏定义:
当然这种方法适用于你懒得严格定义每一位的情况,尤其是像我现在的初始化配置,参数给定如果定义的太复杂,那么我们的数据结构就更庞大了。而严格的寄存器定义是采用联合结构体,如下:
如上所示,每一个位域的定义都很严格了。这种定义很实用,既可以实现寄存器的整体读写,也可以实现位域和位的操作。(老司机必会)
表一:寄存器CCUCON0宏定义
31 | 30 | [29:28] | [27:26] | [25:24] | [23:22] | [21:20] | [19:16 | [15:12] | [11:8] | [7:4] | [3:0] |
LCK | UP | CLKSEL | ADCCLKSEL | FSIDIV | 0 | FSI2DIV | SPBDIV | LPDIV | SRIDIV | BAUD2DIV | BAUD1DIV |
2 | 1 | 2 | 0 | 1 | 1 | 2 | |||||
100MHz | 200MHz | 100MHz | 200MHz | 200MHz | 100MHz |
表二:寄存器CCUCON1配置
31 | 30 | [29:28] | [27:24] | [23:20] | [19:16 | [15:12] | [11:8] | [7:4] | [3:0] |
LCK | UP | INSEL | ASCLINSDIV | ASCLINFDIV | ETHDIV | GTMIV | STMIV | ERAYDIV | CANDIV |
2 | 1 | 4 | 2 | 2 | 3 | 2 | |||
100MHz | 200MHz | 5MHz | 100MHz | 100MHz | 80/3MHz | 100MHz |
接下来我们以CCUCON0为例来讲解,该寄存器定义了12个参数。以下是宏定义里面给出的值:
BAUD1DIV = 1*2;
BAUD1DIV = 1;
SRIDIV = 1;
SPBDIV = 1*2;
FSI2DIV = 1;
FSIDIV = 1*2;
大家可以翻看上几贴的时钟树,查看每一个分频因子的含义。
f_BAUD1 = f_source/2 =f_pll/2 =100MHz;//I2C总线基础时钟
f_BAUD2 = f_source=200 MHz;// QSPI总线和PSI5的基础时钟
f_SRI = f_source=200 MHz;// SRI总线的基础时钟
f_SPB = f_source/2 =f_pll/2 =100MHz;//SPB总线基础时钟
f_FSI2 = f_SRI =200 MHz;//flash接口2时钟
f_FSI = f_SRI/2=100 MHz;//flash接口时钟
最后一个参数是指,在时钟改变的过程中,FLASH要保持等待,是对该状态的配置。主要通过配置FCON寄存器实现,具体的配置等到我们进行到FLASH的时候再分析(不知将会是何年月。。。)
到这里我们就将时钟初始化输入参数分析完了。总结一下,这个输入参数作为一个比较复杂的数组,它包含时钟倍频的参数和时钟分频的参数(而且这些参数随晶振时钟和目标时钟的定义而改变)。
本以为这帖子可以把时钟初始化讲完,但是估计有点困难了,没想到光是输入参数就这么多内容。不过不着急,我们下次帖子在再见吧。
大家可以根据本帖子的内容分析,以得到各个子系统的时钟,在这里我直接给出,ILLD的默认时钟配置表:
PLL | ERAY_PLL | SPB | ADC | CAN | FSI2 | FSI | CPU2 | CPU1 | CPU0 | SRI | GTM |
200MHz | 80MHz | 100MHz | 关闭 | 100MHz | 200MHz | 100MHz | 200MHz | 200MHz | 200MHz | 200MHz | 100MHz |
STM | OSC0 | BAUD1 | BAUD2 | ERAY | ASCLINF | ASCLINS | BBB | REFCLK1/2 |
100MHz | 20MHz | 100MHz | 200MHz | 80/3MHz | 200MHz | 100MHz | 100MHz | 25/3MHz |
只有注册用户才能在此添加评论。 如果您已经注册,请登录。 如果您还没有注册,请注册并登录。