STM32裸机编程指南-11

系列目录

配置时钟

启动后,Nucleo-F429ZI CPU以16MHz运行,最大频率为180MHz。请注意,系统时钟频率并不是我们需要关心的唯一因素。外设连接到不同的总线,APB1 和 APB2 时钟不同。 它们的时钟速度由频率预分频器配置值,在 RCC 中设置。主 CPU 时钟源也可以不同 - 我们可以使用外部晶体振荡器 (HSE) 或内部振荡器(HSI)。在我们的例子中,我们将使用 HSI。

当CPU从闪存执行指令时,闪存读取速度(大约25MHz)在CPU时钟变高时成为瓶颈。有几个技巧会有所帮助,指令预取就是其中之一。此外,我们可以给闪存控制器提供一些线索,告诉它系统时钟有多快:该值称为闪存延迟。对于 180MHz 系统时钟,FLASH_LATENCY值为 5。闪存控制器中的位 8 和 9 控制启用指令和数据缓存:

1
FLASH->ACR |= FLASH_LATENCY | BIT(8) | BIT(9);      // Flash latency, caches

时钟源(HSI 或 HSE)通过一个称为锁相环(PLL)的硬件,将源频率乘以特定值。然后,一组分频器用于设置系统时钟和APB1、APB2时钟。为了获得180MHz的最大系统时钟,可能需要多个值的PLL分频器和APB预分频器。第 6.3.3 节数据表告诉我们APB1时钟的最大值:<= 45MHz,和 APB2 时钟:<= 90MHz。这缩小了可能的列表组合。在这里,我们手动选择值。请注意,像CubeMX这样的工具可以自动化该过程,并使其变得简单和可视化。

1
2
3
4
enum { APB1_PRE = 5 /* AHB clock / 4 */, APB2_PRE = 4 /* AHB clock / 2 */ };
enum { PLL_HSI = 16, PLL_M = 8, PLL_N = 180, PLL_P = 2 }; // Run at 180 Mhz
#define PLL_FREQ (PLL_HSI * PLL_N / PLL_M / PLL_P)
#define FREQ (PLL_FREQ * 1000000)

现在,我们已经准备好使用简单的算法来设置CPU和外设总线的时钟。可能看起来像这样:

  • 可选,使能FPU
  • 设置flash延迟
  • 确定时钟源,PLL、APB1和APB2分频
  • 配置RCC
1
2
3
4
5
6
7
8
9
10
11
12
static inline void clock_init(void) {                 // Set clock frequency
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
FLASH->ACR |= FLASH_LATENCY | BIT(8) | BIT(9); // Flash latency, caches
RCC->PLLCFGR &= ~((BIT(17) - 1)); // Clear PLL multipliers
RCC->PLLCFGR |= (((PLL_P - 2) / 2) & 3) << 16; // Set PLL_P
RCC->PLLCFGR |= PLL_M | (PLL_N << 6); // Set PLL_M and PLL_N
RCC->CR |= BIT(24); // Enable PLL
while ((RCC->CR & BIT(25)) == 0) spin(1); // Wait until done
RCC->CFGR = (APB1_PRE << 10) | (APB2_PRE << 13); // Set prescalers
RCC->CFGR |= 2; // Set clock source to PLL
while ((RCC->CFGR & 12) == 0) spin(1); // Wait until done
}

剩下的就是从主函数调用 clock_init,然后重新编译和烧写,这样我们的板子就以它的最大速度180MHz运行了!

完整工程源码可以在 step-6-clock 文件夹找到。