STM32F103CBT6使用内部高速时钟配置系统时钟时的BUG分析

项目场景:

项目场景:初次接触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;

引用:

1.STM32的Flash缓冲区_stm32数据缓冲区是flash吗-CSDN博客

2.百问网物联网设计-STM32启动_flash预取缓冲器作用-CSDN博客

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值