首先,外设需要通过时钟信号来驱动其工作。通过多路选择器和对应的寄存器配置,我们可以初始化最适合外设的频率。这样做不仅可以提高外设的工作效率,还能在一定程度上提升整个系统的响应速度。
### 初始化AHB_CLK_ROOT
AHB_CLK_ROOT是许多外设常用的时钟根,其初始化需要先对AHB_CLK_ROOT的上游时钟根进行配置。在CBCDR寄存器的PERIPH_CLK_SEL位,有一个多路选择器,用于决定时钟源。根据系统需求,我们可以选择不同的时钟源。
AHB_CLK_ROOT最大支持的频率是132MHz。如果在PERIPH_CLK_SEL处选择上位时钟源,其最大频率为PLL3_480MHz,但经过分频后最大只能达到120MHz。为了达到132MHz的最佳频率,我们需要选择下位时钟源,并在CBCMR寄存器中选择PLL2的PFD2时钟源,频率为396MHz。最终,通过CBCDR寄存器的AHB_PODF分频器,我们可以将频率调整到132MHz。
### 初始化IPG_CLK_ROOT
IPG_CLK_ROOT的最大频率为66MHz,其时钟源来自AHB_CLK_ROOT。由于AHB_CLK_ROOT的频率为132MHz,因此我们只需将CBCDR寄存器中的IPG_PODF分频器的值设置为2,即可得到66MHz的频率。
### 初始化PERCLK_CLK_ROOT
PERCLK_CLK_ROOT的最大频率同样为66MHz。在经过IPG_PODF分频器的作用后,其频率已经是66MHz。因此,我们只需将CSCMR1寄存器中的PERCLK_CLK_SEL多路选择器设置到IPG_CLK_ROOT,并将PERCLK_PODF分频器的值设置为1,即可完成初始化。
完成以上初始化后,IPG_CLK_ROOT和PERCLK_CLK_ROOT两个时钟根的频率均工作在66MHz,这不仅最大限度地发挥了SoC的性能,也成为大部分外设的时钟源。
### 特别说明
需要注意的是,修改AHB_PODF位的值时,需要先禁止AHB_CLK_ROOT的输出。然而,在实际操作中,我们可能找不到用于关闭AHB_CLK_ROOT输出的寄存器,因此无法直接设置AHB_PODF。此外,内部boot rom已经将AHB_PODF设置为3分频,即使我们不手动设置,AHB_ROOT_CLK的频率也默认为132MHz。
通过合理配置时钟根,我们可以使外设以更高效的频率运行,从而提升整个嵌入式系统的性能和响应速度。在实际应用中,开发者需要根据具体需求选择合适的时钟源和分频值,以实现最佳的系统性能。
外设需要工作也需要时钟驱动,通过多路选择器以及对应的寄存器配置初始化最适合的外设频率可以让外设更高频的工作。
从上面截图以及红框中可以看到,外设时钟根PERCLK_CLK_ROOT
与IPG_CLK_ROOT
为大多数常用的外设提供时钟,初始化这两个时钟根需要先对AHB_CLK_ROOT
进行初始化
初始化AHB_CLK_ROOT
AHB_CLK_ROOT
的时钟来源在CBCDR[PERIPH_CLK_SEL]
处有一个多路选择器
从上面这个图可以看出AHB_CLK_ROOT
最大支持的频率是132MHz,如果在CBCDR[PERIPH_CLK_SEL]
这个多路选择器这里选择了上路,那它的时钟来源最大的频率是PLL3_480
,通过CBCDR[PERIPH_CLK2_RODF]
分频后最大只能到120(此时分频器的值是4,如果是3的话160则超过了最大值),因为AHB_CLK_ROOT
限制最大是132。因此CBCDR[PERIPH_CLK_SEL]
这个多路选择器,选择下路, 同时在CBCMR[PRE_PERIPH_CLK_SEL]
时选择PLL2
的PFD2
时钟源,它的时钟频率是396MHz,最终达到AHB_CLK_ROOT
时经过CBCDR[AHB_PODF]
分频器处理刚好得到132MHz的频率。
/// 配置外接设备的时钟频率
/// CBCMR[PRE_PERIPH_CLK_SEL]选择PLL2->PFD2
/// 先将19-18两个bit位清0
/// 再将19-18两个bit位的数据写成1,选择PFD2
CCM->CBCMR &= ~(3 << 18);
CCM->CBCMR |= (1 << 18);
/// CBCDR[PERIPH_CLK_SEL]多路选择器选择下路
CCM->CBCDR &= ~(1 << 25);
/// 读取第5个bit位(PERIPH_CLK_ SEL_BUSY),如果是1指示正忙于握手,如果是0表示握手完成
while ((CCM->CDHIPR >> 5) & 0x1);
/* 修改 AHB_PODF 位的时候需要先禁止 AHB_CLK_ROOT 的输出,但是 * 我没有找到关闭 AHB_CLK_ROOT 输出的的寄存器,所以就没法设置。 * 下面设置 AHB_PODF 的代码仅供学习参考不能直接拿来使用!! * 内部 boot rom 将 AHB_PODF 设置为了 3 分频,即使我们不设置 AHB_PODF, * AHB_ROOT_CLK 也依旧等于 396/3=132Mhz。 */
#if 0
/// 将CBCDR[AHB_PODF]的12-10三个bit位清0
CCM->CBCDR &= ~(7 << 10);
/// 将CBCDR[AHB_PODF]的值设置成3,即3分频
CCM->CBCDR | (2 << 10);
/// 等待忙位检测通过
while ((CCM->CDHIPR >> 1) & 0x1);
#endif
初始化IPG_CLK_ROOT
IPG_CLK_ROOT
的频率最大值是66MHz,从AHB_CLK_ROOT
过来的频率是132MHz,所以这里只需要将CBCDR[IPG_PODF]
分频器的值设置成除2即可。
/// 将9-8两个bit位的数据清0
CCM->CBCDR &= ~(3 << 8);
/// 设置成2分频
CCM->CBCDR |= (1 << 8);
初始化PERCLK_CLK_ROOT
PERCLK_CLK_ROOT
的频率最大值是66MHz,在CBCDR[IPG_PODF]
分频器的作用下它的频率已经是66MHz了,所以此时只需要将CSCMR1[PERCLK_CLK_SEL]
多路选择器选择到IPG_CLK_ROOT
,将PERCLK_PODF
分频器的值设置成1分频即可。
/// CSCMR1[PERCLK_CLK_SEL]选择ipg clk root
CCM->CSCMR1 &= ~(1 << 6); /// 将5-0 6个bit位清0,设置成1分频,此时已经是1分频了
CCM->CSCMR1 &= ~(0x3F << 0);
以上都初始化完成后IPG_CLK_ROOT
与PERCLK_CLK_ROOT
两个时钟根的频率就工作在子66MHz,最大的发挥了SOC的性能,这两个时钟根也是大部分外设的时钟源。
特别说明
修改 AHB_PODF 位的时候需要先禁止 AHB_CLK_ROOT 的输出,但是
- 我没有找到关闭 AHB_CLK_ROOT 输出的的寄存器,所以就没法设置。
- 下面设置 AHB_PODF 的代码仅供学习参考不能直接拿来使用!!
- 内部 boot rom 将 AHB_PODF 设置为了 3 分频,即使我们不设置 AHB_PODF, * AHB_ROOT_CLK 也依旧等于 396/3=132Mhz。# 外设时钟根配置