1
\$\begingroup\$

I've a bare metal PLL setup for my STM32F407 which should generate a 168MHz system clock. However for some reason the 1ms SysTick interrupt is orders of magnitude off the grid.

The math works out on paper and in practice.

When I'm using the 8MHz HSE crystal as the system clock, everything is working fine and the 1ms SysTick interrupt is accurate.

And before anybody is asking, yes I know that modifying registers separately is inefficient and slow. Anyway here are my 2 clock init functions of which the 8MHz one is working.

void clock_init_hse_8mhz(void) {
    RCC->CR |= RCC_CR_HSEON;
    while ((RCC->CR & RCC_CR_HSERDY) == 0);

    RCC->CFGR &= ~RCC_CFGR_HPRE_MASK;
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

    RCC->CFGR &= ~RCC_CFGR_PPRE1_MASK;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;

    RCC->CFGR &= ~RCC_CFGR_PPRE2_MASK;
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;

    FLASH->ACR |= FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN | FLASH_LATENCY_0WS;

    RCC->CFGR &= ~RCC_CFGR_SW_MASK;
    RCC->CFGR |= RCC_CFGR_SW_HSE;
    while ((RCC->CFGR & RCC_CFGR_SWS_HSE) != RCC_CFGR_SWS_HSE);

    s_sys_clk_freq = HSE_FREQ;
    s_ahb_clk_freq = s_sys_clk_freq / 1;
    s_apb1_clk_freq = s_sys_clk_freq / 1;
    s_apb2_clk_freq = s_sys_clk_freq / 1;

    SYSTICK->LOAD = (s_sys_clk_freq / 1000) - 1;
    SYSTICK->VAL = 0;
    SYSTICK->CTRL = SYSTICK_CTRL_ENABLE | SYSTICK_CTRL_TICKINT | SYSTICK_CTRL_CLKSOURCE;
}

void clock_init_pll_168mhz(void) {
    uint32_t pllm = 8;
    uint32_t plln = 336;
    uint32_t pllp = 2;
    uint32_t pllq = 4;

    RCC->CR |= RCC_CR_HSEON;
    while ((RCC->CR & RCC_CR_HSERDY) == 0);

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    PWR->CR |= PWR_CR_VOS;

    RCC->CFGR &= ~RCC_CFGR_HPRE_MASK;
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

    RCC->CFGR &= ~RCC_CFGR_PPRE1_MASK;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;

    RCC->CFGR &= ~RCC_CFGR_PPRE2_MASK;
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;

    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_MASK;
    RCC->PLLCFGR |= (pllm << RCC_PLLCFGR_PLLM_POS);

    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_MASK;
    RCC->PLLCFGR |= (plln << RCC_PLLCFGR_PLLN_POS);

    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_MASK;
    RCC->PLLCFGR |= (pllp << RCC_PLLCFGR_PLLP_POS);

    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_MASK;
    RCC->PLLCFGR |= (pllq << RCC_PLLCFGR_PLLQ_POS);

    RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC;

    RCC->CR |= RCC_CR_PLLON;
    while ((RCC->CR & RCC_CR_PLLRDY) == 0);

    FLASH->ACR |= FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_PRFTEN | FLASH_LATENCY_5WS;

    RCC->CFGR &= ~RCC_CFGR_SW_MASK;
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while ((RCC->CFGR & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL);

    s_sys_clk_freq = (HSE_FREQ * (plln / pllm)) / pllp;
    s_ahb_clk_freq = s_sys_clk_freq / 1;
    s_apb1_clk_freq = s_sys_clk_freq / 4;
    s_apb2_clk_freq = s_sys_clk_freq / 2;

    SYSTICK->LOAD = (s_sys_clk_freq / 1000) - 1;
    SYSTICK->VAL = 0;
    SYSTICK->CTRL = SYSTICK_CTRL_ENABLE | SYSTICK_CTRL_TICKINT | SYSTICK_CTRL_CLKSOURCE;
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You are mostly read-modify-write ORing the default register values. What if they are not zeroes? \$\endgroup\$
    – Justme
    Commented Nov 15, 2023 at 15:03
  • \$\begingroup\$ You are right, I have updated the code. Now I first clear the bits with the appropriate mask and then write the new value. But it still does not work. \$\endgroup\$
    – Michael
    Commented Nov 15, 2023 at 15:30
  • \$\begingroup\$ Have you tried using the ST MX configurator and comparing with your settings? \$\endgroup\$ Commented Nov 15, 2023 at 16:03

1 Answer 1

0
\$\begingroup\$
uint32_t pllp = 2;

RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_MASK;
RCC->PLLCFGR |= (pllp << RCC_PLLCFGR_PLLP_POS);

RCC_PLLCFGR.PLLP does not contain directly the divider, see its description in RM. By setting it to 2 = 0b01, you select divide by 6, i.e. the PLL's P output frequency (thus system frequency) is 8MHz/8*336/6=56MHz, i.e. 168MHz/3 (thus your systick interrupt frequency is around 333Hz, isn't it?)

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much, this was infact the issue! Your math works out. That "2" which should be "0" instead cost me my whole day but I'm very happy that it is finally working. Now all may peripherals are starting to work as well :) Again thank you so much! \$\endgroup\$
    – Michael
    Commented Nov 15, 2023 at 19:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.