引言
在嵌入式系统开发中,微处理器的时钟配置是确保系统性能和稳定性的关键步骤之一。本文将详细介绍如何为I.MX6U处理器配置PLL(Phase-Locked Loop)及时钟频率分配器(PFD),并设置AHB、IPG和PERCLK根时钟,以确保所有外设能够正常工作。
系统概述
I.MX6U是一款基于ARM Cortex-A7架构的多核处理器,其内部集成了多个PLL用于生成不同频率的时钟信号。每个PLL都有若干个PFD来进一步细分这些时钟信号,以满足不同外设的需求。正确配置这些时钟源对于系统的正常运行至关重要。
目标设定
- PLL2:固定为528MHz。
- PLL3:固定为480MHz。
- PLL7:固定为480MHz。
- PLL4~PLL6:针对特殊外设使用,按需设置。
- PFD:根据NXP推荐值进行配置。
- AHB_CLK_ROOT:设置为132MHz。
- IPG_CLK_ROOT 和 PERCLK_CLK_ROOT:均设置为66MHz。
PLL 和 PFD 设置
PLL2 和 PLL3 的 PFD 配置
我们将首先配置PLL2和PLL3及其各自的4路PFD。具体的频率设置如下表所示:
PFD | NXP 推荐频率 (MHz) | 计算公式 | FRAC 值 |
---|---|---|---|
PLL2_PFD0 | 352 | 528 * 18 / PFD0_FRAC | 27 |
PLL2_PFD1 | 594 | 528 * 18 / PFD1_FRAC | 16 |
PLL2_PFD2 | 400 (实际396) | 528 * 18 / PFD2_FRAC | 24 |
PLL2_PFD3 | 297 | 528 * 18 / PFD3_FRAC | 32 |
PLL3_PFD0 | 720 | 480 * 18 / PFD0_FRAC | 12 |
PLL3_PFD1 | 540 | 480 * 18 / PFD1_FRAC | 16 |
PLL3_PFD2 | 508.2 | 480 * 18 / PFD2_FRAC | 17 |
PLL3_PFD3 | 454.7 | 480 * 18 / PFD3_FRAC | 19 |
寄存器操作细节
- 使用寄存器
CCM_ANALOG_PFD_528n
设置PLL2的PFD:PFDx_FRAC
位用于设定分频数。PFDx_STABLE
只读位表示是否稳定。PFDx_CLKGATE
使能位控制输出(0=使能, 1=关闭)。
- 使用寄存器
CCM_ANALOG_PFD_480n
设置PLL3的PFD:- 结构与
CCM_ANALOG_PFD_528n
相同,只是频率计算公式不同。 - 对应的FRAC值通过PLL3的基础频率480MHz计算得出。
- 结构与
AHB、IPG 和 PERCLK 根时钟设置
寄存器说明
CCM_CBCDR
:用于设置AHB、IPG等总线时钟分频。CCM_CBCMR
:用于选择pre_periph_clk和其他时钟源。CCM_CSCMR1
:主要用于外设时钟源的选择。
配置过程
-
选择PrePeriph时钟源
- 设置
CCM_CBCMR
中的PRE_PERIPH_CLK_SEL
位选择PLL2_PFD2作为pre_periph_clk的时钟源。
- 设置
-
选择Periph时钟源
- 设置
CCM_CBCDR
中的PERIPH_CLK_SEL
位为0,即选择PLL2作为Periph时钟源。
- 设置
-
设置AHB_CLK_ROOT
- 设置
CCM_CBCDR
中的AHB_PODF
位为3(3分频),得到132MHz(396/3=132MHz)。 - 注意:修改此位会引起一次与MMDC的握手,所以修改完成后要等待握手完成。
- 设置
-
设置IPG_CLK_ROOT
- 设置
CCM_CBCDR
中的IPG_PODF
位为2(2分频),得到66MHz(132/2=66MHz)。 - 同样地,需要等待与MMDC的握手完成。
- 设置
-
设置PERCLK_CLK_ROOT
- 设置
CCM_CSCMR1
中的PERCLK_CLK_SEL
位为0,选择IPG_CLK_ROOT作为PERCLK_CLK_ROOT的源。 - 设置
PERCLK_PODF
位为1(1分频),保持66MHz不变。
- 设置
关键寄存器字段解释
-
CCM_CBCDR:
PERIPH_CLK2_PODF
: Peripheral2时钟分频,范围07对应18分频。PERIPH2_CLK_SEL
: Peripheral2主时钟选择,0选PLL2,1选periph2_clk2_clk。AHB_PODF
: AHB时钟分频,范围07对应18分频。IPG_PODF
: IPG时钟分频,范围03对应14分频。
-
CCM_CBCMR:
PRE_PERIPH_CLK_SEL
: PrePeriph时钟源选择,范围00~11对应不同的PLL或PFD选项。PERIPH_CLK2_SEL
: Peripheral_clk2时钟源选择,范围00~10对应不同的PLL或振荡器选项。
-
CCM_CSCMR1:
PERCLK_CLK_SEL
: Perclk时钟源选择,0选IPG clk,1选OSC clk。PERCLK_PODF
: Perclk时钟分频,范围07对应18分频。
注意事项
- 修改某些分频器或时钟选择器时会触发与MMDC(Memory Management Data Controller)之间的握手协议,必须等待握手完成才能继续操作。
- 在修改
arm_podf
和ahb_podf
时需要先关闭相关时钟输出,完成后重新开启,避免出现无时钟输出的问题。 - 某些配置可能会影响内存控制器的操作,因此在进行任何更改之前,请确保了解潜在的影响,并采取适当的预防措施。
实际应用中的代码片段示例
下面是一段伪代码示例,展示了如何编程实现上述配置:
// 定义PLL和PFD配置函数
void configure_pll_pfd(void) {
// 设置PLL2和PLL3的PFD
CCM_ANALOG_PFD_528n = (0 << 31) | // PFD0_CLKGATE
(27 << 0); // PFD0_FRAC for 352MHz
CCM_ANALOG_PFD_480n = (0 << 31) | // PFD0_CLKGATE
(12 << 0); // PFD0_FRAC for 720MHz
// ...其他PFD配置...
}
// 定义AHB、IPG和PERCLK配置函数
void configure_bus_clocks(void) {
// 设置PrePeriph时钟源为PLL2_PFD2
CCM_CBCMR |= (1 << PRE_PERIPH_CLK_SEL);
// 设置Periph时钟源为PLL2
CCM_CBCDR &= ~(1 << PERIPH_CLK_SEL);
// 设置AHB_PODF为3分频
CCM_CBCDR |= (3 << AHB_PODF);
// 设置IPG_PODF为2分频
CCM_CBCDR |= (2 << IPG_PODF);
// 等待与MMDC握手完成
while (CCM_CDHIPR & (1 << AHB_PODF)) {}
// 设置PERCLK_CLK_ROOT为IPG_CLK_ROOT且不分频
CCM_CSCMR1 &= ~(1 << PERCLK_CLK_SEL);
CCM_CSCMR1 |= (1 << PERCLK_PODF);
}
结论
通过上述详细的步骤,我们可以成功地将I.MX6U的主频及其他重要时钟源配置到位,确保了系统的稳定性和性能。这一过程涉及到多个关键寄存器的操作,包括但不限于CCM_CBCDR
、CCM_CBCMR
和CCM_CSCMR1
。理解并掌握这些寄存器的功能对于高效配置I.MX6U至关重要。
参考资料
希望这篇博客能帮助你更好地理解和应用I.MX6U的时钟配置。如果有任何疑问或需要进一步的帮助,请随时联系我。