c++ 为什么不能正确配置PLL时钟?

q3qa4bjr  于 2023-03-20  发布在  其他
关注(0)|答案(1)|浏览(131)

我目前正在尝试使用C++编写STM32F401微控制器的引导装载程序。我已经删除了所有使用-nostartfiles的启动文件,并自己编写了所有启动代码。我目前面临的主要问题是从25MHz的外部晶体源设置系统时钟,以使系统达到大约84MHz。我已使用STM32CubeIDE确认尝试配置的时钟设置确实是有效值。
我的主要问题是无法设置PLL就绪位以继续执行我的程序。我更改了HSE配置和PLL配置的操作顺序,但没有效果。每个外设都被构造为一个类,其中新的操作符被覆盖以返回存储器中的确切地址。RCC::EnableExternalSystemClock()函数是我在boot_main()条目中调用的第一个函数。下面是我现在拥有的当前时钟配置代码的一些片段:
RCC.cpp

/**
 * @brief Sets the system clock to the specified TARGET_SYSTEM_CLOCK through
 * the external oscillator.
 *
 */
void RCC::EnableExternalSystemClock() {
    size_t timeout = 0;

    // Enable HSE
    this->CR.bits.HSEON = 1;
    while (this->CR.bits.HSERDY != 0b1 || timeout < this->HSE_TIMEOUT) {
        timeout++;
    }

    // Enable power controller
    this->APB1ENR.bits.PWREN = 1;

    // Configure voltage regulator scaling
    PWR &power = *new PWR();
    power.SetRegulatorScale(PWR::Scale::DIV2);

    // Enable flash prefetch & caches
    FLASH &flash = *new FLASH();
    flash.EnablePrefetchCache();

    // Calculate actual system clock
    constexpr auto pll_clocks =
        RCC::CalculatePLLClocks(RCC::HSE_CRYSTAL_FREQ_HZ, RCC::TARGET_SYSTEM_CLOCK);
    constexpr auto sys_clock = RCC::CalculateSysClock(RCC::HSE_CRYSTAL_FREQ_HZ, pll_clocks.pll_m,
                                                      pll_clocks.pll_n, pll_clocks.pll_p);

    // Set APB scalers
    constexpr auto lsapb2_prescaler = RCC::CalculateLSAPB2Prescaler(sys_clock);
    this->CFGR.bits.HPRE = 0b000;
    this->CFGR.bits.PPRE1 = lsapb2_prescaler; // calculates as 0x04
    this->CFGR.bits.PPRE2 = 0b000;

    // Enable system config click
    this->APB2ENR.bits.SYSCFGEN = 1;

    // Disable PLL
    this->CR.bits.PLLON = 0;
    while (this->CR.bits.PLLRDY != 0) {
        // Do nothing
    }

    // Set PLL scalers
    this->PLLCFGR.bits.PLLM = pll_clocks.pll_m; // calculates as 13
    this->PLLCFGR.bits.PLLN = pll_clocks.pll_n; // calclulates as 87
    this->PLLCFGR.bits.PLLP = pll_clocks.pll_p; // calculates as 0x00
    this->PLLCFGR.bits.PLLQ = 4;

    // Set PLL source
    this->PLLCFGR.bits.PLLSRC = 1;

    // Enable PLL
    this->CR.bits.PLLON = 1;
    while (this->CR.bits.PLLRDY == 0) { // currently stuck here
        // Do nothing
    }

    // Set clock source
    this->CFGR.bits.SW = 0b10;
    while (this->CFGR.bits.SWS != 0b10) {
        // Do nothing
    }
}

FLASH.hpp

void FLASH::EnablePrefetchCache() {
    this->ACR.bits.DCEN = 1;
    this->ACR.bits.ICEN = 1;
    this->ACR.bits.PRFTEN = 1;

    constexpr int sys_clock = RCC::GetSystemClock(RCC::HSE_CRYSTAL_FREQ_HZ);
    constexpr uint8_t latency = FLASH::CalculateFlashLatency(TARGET_SYSTEM_VOLTAGE, sys_clock);
    this->ACR.bits.LATENCY = latency;
}

RCC.hpp文件可以在here中找到。
以下是STM32CubeIDE中预期系统时钟配置的示意图:

我错过了什么让系统时钟设置正确?

n1bvdmb6

n1bvdmb61#

您违反了PLLM和PLLN配置。参考手册RM0368. RCC部分,PLL配置寄存器(第105页):

阅读注意部分。基本上,它说PLLM时钟分频后输出必须在1 MHz-2 MHz范围内。
接下来是PLLN:

提出一个系数组合本身就是一个小数学问题。我建议的解决方案是:

  1. PLLM为25,因此VCO输入为1 MHz。
  2. PLLN为84*4 = 336。
  3. PLLP分频器为4,因此PLLP输出为336 MHz/4= 84 MHz。
    此外,如果您要将MCU推到最大,则可能需要在PWR外设中启用过驱动/过驱动开关。您只需要设置缩放比例。

相关问题