项目场景:
项目场景:初次接触STM32单片机的使用,选择点亮一个LED的项目入手。为了更加深入的了解STM32,通过寄存器的方式去编写自己的项目。
问题描述
起初通过库函数的方式编写代码,配置好系统时钟和GPIO外设时钟后,成功点亮LED灯,对库函数的代码进行简单的解读后,再借助CSDN创作助手的AI工具对系统时钟进行配置,AI工具的配置系统时钟的代码如下。联合以前的代码,烧入后发现无法点亮LED灯。
以下是配置STM32F103CBT6使用内部高速时钟配置64MHz系统时钟的代码示例:
#include "stm32f1xx.h"
void SystemClock_Config(void);
int main(void)
{
// 配置系统时钟
SystemClock_Config();
// 你的代码
while (1)
{
// 主循环
}
}
void SystemClock_Config(void)
{
// 启用内部高速时钟(HSI)
RCC->CR |= RCC_CR_HSION;
// 等待HSI稳定
while ((RCC->CR & RCC_CR_HSIRDY) == 0);
// 选择HSI作为系统时钟
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_HSI;
// 等待HSI成为系统时钟
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
// 启用FLASH预取缓存
FLASH->ACR |= FLASH_ACR_PRFTBE;
// 设置FLASH延迟
FLASH->ACR |= FLASH_ACR_LATENCY_1;
// 配置PLL分频因子和倍频因子
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL);
RCC->CFGR |= RCC_CFGR_PLLSRC_HSI_DIV2 | RCC_CFGR_PLLMULL16;
// 启用PLL
RCC->CR |= RCC_CR_PLLON;
// 等待PLL稳定
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
// 选择PLL作为系统时钟
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
// 等待PLL成为系统时钟
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
// 配置APB1和APB2分频因子
RCC->CFGR &= ~(RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2);
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1;
}
这段代码将系统时钟配置为64MHz,使用内部高速时钟(HSI)作为时钟源,并通过PLL进行倍频得到64MHz。注意,此代码中使用的是STM32F1系列的寄存器和头文件,如果你使用的是其他型号的STM32系列,可能需要相应的修改。
启动文件中的时钟配置也已经注释关闭。
原因分析:
通过库函数配置系统时钟后是可以点亮LED灯的,所以问题可以定位在寄存器配置系统时钟的部分。
解决方案:
逐条分析代码后,如下两句存在的意义,令人产生疑惑。
// 启用FLASH预取缓存
FLASH->ACR |= FLASH_ACR_PRFTBE;
// 设置FLASH延迟
FLASH->ACR |= FLASH_ACR_LATENCY_1;
随后查阅如下手册,解读这两个寄存器的意义。
文档给出
flash预缓冲区的作用是提高cpu读取flash指令的速度,要知道cpu的时钟是很快的,但是flash的访问速度是有上限的,且cpu的时钟普遍是远高于flash的访问速度的,所以为了提高cpu对flash的访问速度,st设置了一个叫做flash预缓冲区的东西。
STM32系统架构图:
当我们看到STM32 的系统架构时,我们看到Cortex-M3 内核是通过一个专门的I-总线连接到内部FLASH的。此总线与CPU 运行在相同的频率,因此当PLL使能时核心将试图全速运行在72MHz。由于本质上Cortex CPU是一个单周期的机器,它会试图以每次1.3ns 的速度访问内部FLASH。当STM32启动时,它是从频率为8 MHz 的内部振荡器运行的,因此内部FLASH 的访问时间不是一个问题。然而,一旦PLL启用并作为时钟源,对于运行在最高性能的Cortex CPU来说,FLASH的访问时间太长了(35ns)。为了允许Cortex CPU 运行在72 MHz具有零等待状态,FLASH 存储器具有由两个64 位缓存器组成的预取缓冲器。这些缓冲器可以从FLASH 存储器中进行64 位宽读取,然后传递独立的16 位或32 位指令给Cortex CPU执行。该技术在Thumb-2 指令集的条件执行和Cortex 流水线的分支预测中效果很好。由于FLASH 缓冲区的存在,在正常操作过程中程序员不需要采取任何特别的措施。但是你必须确保在主时钟源切换到PLL前启用它。FLASH缓冲区是由FLASH 访问控制寄存器控的。启用预取缓冲器,你必须调整FLASH 预取缓冲器所需的等待周期,来从FLASH 存储器中读取8个字节。延迟设置如下:
0< SYSCLK <24MHz
24< SYSCLK <48MHz
48<SYSCLK <72MHz
这些等待状态是在预取缓冲器和FLASH存储器之间的,不会影响Cortex CPU。CPU正在执行缓冲器上半部分的指令的同时,下半部分正在加载,使得CPU可以在其最佳的速度无缝地继续执行代码。
最终将改成下面这种,因为设置的系统时钟是64MHz,所以此处应该为48<SYSCLK <72MHz,LATENCY应该设置为010。
// 启用FLASH预取缓存
FLASH->ACR |= FLASH_ACR_PRFTBE;
// 设置FLASH延迟
FLASH->ACR |= FLASH_ACR_LATENCY_2;