提高STM32F401时钟速度的代码无效

发布于 2025-01-24 04:44:51 字数 2175 浏览 2 评论 0 原文

我试图使用PLL将STM32F401的时钟速度提高到84MHz。我尝试了日志时间。但是代码不起作用。谁能检查需要做什么?外部晶体具有功能,因为我使用HAL库检查了该晶体。

我在没有HAL的情况下尝试的原因是,我已经看到几个文件说HAL会消耗太多记忆,最好避免它。

void Enable_PLL_F401(void)
{
    //Enable The HSE
    RCC->CR |= RCC_CR_HSEON;
    //Wait Until HSE Stabilizes
    //Remove While Loop; If the HSE isn't stabilized, code will stuck
    while(!(RCC->CR & RCC_CR_HSERDY))
        ;
    /* Activate Prefetch Buffer*/
    /*        Optional         */
    
    
    //Configure the PLL registers
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
    RCC->PLLCFGR &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
    RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
    RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]
    
    RCC->CFGR &=~ RCC_CFGR_HPRE;         //System Clock Not Divided [AHB Prescalar]
    RCC->CFGR &=~ RCC_CFGR_PPRE1_DIV16;  //Clearing PPRE1 values
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    RCC->CFGR &=~ RCC_CFGR_PPRE2_DIV16;  //Clearing PPRE2 Values
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;    //AHB not divided [APB2 Prescalar]
    
    RCC->CR |= RCC_CR_PLLON;
    //Wait Until HSE Stabilizes
    //Remove While Loop; If the HSE isn't stabilized, code will stuck
    while(!(RCC->CR & RCC_CR_PLLRDY))
        ;
    
    RCC->CFGR &=~ RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    
    while(!(RCC->CFGR & RCC_CFGR_SWS_PLL))
        ;
    
    //SystemInit();
    SystemCoreClockUpdate();
}

这是cubemx中的时钟配置:

”

I was trying to increase the clock speed of STM32F401 to 84Mhz using PLL. I tried for log time. But the code is not working. Can anyone check what needs to be done? External crystals is functional , because I checked that using HAL library.

The reason I am trying without HAL is that I've seen several document saying that the HAL consumes too much memory and it is better to avoid it.

void Enable_PLL_F401(void)
{
    //Enable The HSE
    RCC->CR |= RCC_CR_HSEON;
    //Wait Until HSE Stabilizes
    //Remove While Loop; If the HSE isn't stabilized, code will stuck
    while(!(RCC->CR & RCC_CR_HSERDY))
        ;
    /* Activate Prefetch Buffer*/
    /*        Optional         */
    
    
    //Configure the PLL registers
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
    RCC->PLLCFGR &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
    RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
    RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
    RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]
    
    RCC->CFGR &=~ RCC_CFGR_HPRE;         //System Clock Not Divided [AHB Prescalar]
    RCC->CFGR &=~ RCC_CFGR_PPRE1_DIV16;  //Clearing PPRE1 values
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    RCC->CFGR &=~ RCC_CFGR_PPRE2_DIV16;  //Clearing PPRE2 Values
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;    //AHB not divided [APB2 Prescalar]
    
    RCC->CR |= RCC_CR_PLLON;
    //Wait Until HSE Stabilizes
    //Remove While Loop; If the HSE isn't stabilized, code will stuck
    while(!(RCC->CR & RCC_CR_PLLRDY))
        ;
    
    RCC->CFGR &=~ RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    
    while(!(RCC->CFGR & RCC_CFGR_SWS_PLL))
        ;
    
    //SystemInit();
    SystemCoreClockUpdate();
}

This is the clock configuration in CubeMX:

Clock configuration in CubeMX

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼眸里的那抹悲凉 2025-01-31 04:44:52

尽管问题仍然缺少一些信息,但让我尝试给您一些指示:

写给MCU寄存器

首先, ,写信给 pllcfgr 在许多小步骤中注册是通常不是要走的路。请参阅您的代码的以下部分:

//Configure the PLL registers
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
RCC->PLLCFGR &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
RCC->PLLCFGR |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]

该执行9写信给同一寄存器。在第一次写入中,您选择HSE振荡器时钟。在第二个写入中,您可以清除主PLL( pllm )的除法因子。但是,值0是无效的值。这可能已经引起问题(我认为在这种情况下没有指定行为,因此我们只能猜测会发生什么)。

通过首先计算正确的值,然后将其写入单个操作中的寄存器,可以轻松避免这种情况:

uint32_t reg = RCC->PLLCFGR;
//Configure the PLL registers
reg |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
reg &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
reg |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
reg &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
reg |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
reg &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
reg |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
reg &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
reg |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]
RCC->PLLCFGR = reg;

同样适用于代码中的其他寄存器。

动态重新配置时钟

如果您想提高MCU 动态的时钟速度(因此,当它已经运行时)或 >(因此更改初始配置)。

如果您想动态更改时钟速度,还有一些其他事情要考虑:

  • 启用PLL后,主要的PLL配置将无法更改。因此,如果您想更改时钟速度,则首先必须将其禁用。
  • 您必须始终确保至少有一个有效的系统时钟。如果您重新配置主PLL,则必须暂时切换到内部时钟(HSI)。

由于我不知道您的启动时钟配置,因此我不能详细介绍更多详细信息,但我希望这将提供足够的信息。

flash等待状态

如old_timer和tagli所述,您可能还需要调整闪存等待状态。
这在第3.4.1节中描述了” DM00096844-STM32F401XB-C-C-C-and-STM32F401XD-E-ADVANCEND-32-BIT-BIT-MCUS-MCUS-STMICRECRECTROCT.PDF“ rel =“ nofollow noreferrer”>“ nofollow noreferrer”> stm32f401参考人(RM0368) Revision 5)。所需的值取决于您的电源电压和CPU时钟频率。

功率调节器电压

要在STM32F4上实现84 MHz,必须将调节器电压缩放输出设置为2(pwr_cr寄存器中的VOS = 2)。这是重置后的默认值,但是如果您的初始配置不同,则可能必须再次设置它。


NB:关于您的陈述:“ 我在没有HAL的情况下尝试的原因是,我已经看到几个文件说HAL会消耗太多记忆,最好避免它。该语句中的有效点,但这不是您应该遵循的一般规则。对于诸如时钟配置之类的低级内容,HAL代码非常基本,并且不会花费太多的内存。考虑到它的复杂性,除非我确实需要保存每一个字节,否则我不会费心重写。高级HAL功能(例如,用于UART或I2C)非常大,因为它们试图覆盖许多用例,并且您可能仅通过编写所需的代码来节省很多内存。尽管如此,我还是从HAL功能开始,只能在需要时进行优化。

Although the question is still missing some information, let me try to give you some pointers:

Writing to MCU registers

First of all, writing to the PLLCFGR register in many small steps is generally not the way to go. See the following piece of your code:

//Configure the PLL registers
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
RCC->PLLCFGR &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
RCC->PLLCFGR &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
RCC->PLLCFGR |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]

This performs 9 writes to the same register. In the first write, you select the HSE oscillator clock. In the second write, you clear the division factor for the main PLL (PLLM). However, the value 0 is an invalid value. This might already cause issues (I don't think the behavior in this case is specified, so we can only guess what will happen).

This can be easily avoid by first calculating the correct value and then writing it to the register in a single operation like this:

uint32_t reg = RCC->PLLCFGR;
//Configure the PLL registers
reg |= RCC_PLLCFGR_PLLSRC;  //PLL Source HSE
reg &=~ (RCC_PLLCFGR_PLLM); //Clearing PLLM values
reg |= (RCC_PLLCFGR_PLLM_0 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLM_4);  //Divided by 25
reg &=~ RCC_PLLCFGR_PLLN;   //Clearing PLLM values
reg |= (RCC_PLLCFGR_PLLN_4|RCC_PLLCFGR_PLLN_6|RCC_PLLCFGR_PLLN_8);      //Multiplied by 336
reg &=~ RCC_PLLCFGR_PLLP;   //Clearing PLLP values
reg |= RCC_PLLCFGR_PLLP_0;  //Divided by 4
reg &=~ RCC_PLLCFGR_PLLQ;   //Clearing PLLP values
reg |= RCC_PLLCFGR_PLLQ_2;  //Divided by 4 [USB-OTG Clock]
RCC->PLLCFGR = reg;

The same applies as well to other registers in your code.

Dynamically reconfiguring clocks

It's not entirely clear to me if you want to increase the clock speed of the MCU dynamically (so when it's already running) or statically (so changing the initial configuration).

In case you want to change the clock speed dynamically, there a few additional things to consider:

  • The Main PLL configuration cannot be changed once the PLL is enabled. So if you want to change the clock speed, you will first have to disable it.
  • You have to make sure that there is at least one valid system clock at all times. If you're reconfiguring the Main PLL, you will have to temporarily switch to the internal clock (HSI).

Since I don't know your startup clock configuration, I can't go into more details, but I hope this will provide enough information.

Flash wait states

As mentioned by old_timer and Tagli, you might also need to adjust the flash wait states.
This is described in section 3.4.1 "Relation between CPU clock frequency and Flash memory read time" of the STM32F401 Reference Manual (RM0368) (revision 5). The required value depends on your supply voltage and CPU clock frequency.

Power Regulator Voltage

To be able to achieve 84 MHz on the STM32F4, the regulator voltage scaling output must be set to Scale 2 (VOS = 2 in the PWR_CR register). This is the default after reset, but if your initial configuration was different, you may have to set it again.


NB: Regarding your statement "The reason I am trying without HAL is that I've seen several document saying that the HAL consumes too much memory and it is better to avoid it."... There's a valid point in that statement, but it's not a general rule that you should follow. For low-level stuff like clock configuration, the HAL code is pretty basic and won't cost that much memory. And given the complexity of it, I wouldn't bother rewriting this, unless I really needed to save every byte of memory. The high-level HAL functions, e.g. for UART or I2C, are pretty big, since they try to cover many use cases, and you might save quite some memory by writing only the code you need. Still, I'd start with the HAL functions and only optimize when needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文