Mehdi
Mehdi

Reputation: 62

STM32 timer clock frequency doesn't change and stay at 1.6MHz

It's been days which I'm reading the reference manual and changing the code to configure the STM32F401RE timers clock. It seems that SYSCLK is set at 84MHZ, PCLK1 is 42MHZ, and PCLK2 is 84MHZ. but every time I want to use TIM2, the clock is set at 1.6MHZ. I used my phone and lap the time from led on and led off states and with the PSC and ARR I assumed that clock frequency is something around 1.6MHZ

here is clock configuration

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR &= ~PWR_CR_VOS_Msk;
    PWR->CR |= PWR_CR_VOS_1; // scale mode 2
    
    
    // flash
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
    
    // HSI CONFIGURATION
    RCC->CR |= RCC_CR_HSION;
    while( !(RCC->CR & RCC_CR_HSIRDY) ){}
    
    
    // PLL CONFIGURATION
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLSRC; // PLL SRC= HSI
    
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
    RCC->PLLCFGR |= 16 << RCC_PLLCFGR_PLLM_Pos;
    
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_Msk;
    RCC->PLLCFGR |= 336 << RCC_PLLCFGR_PLLN_Pos;
    
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_Msk;
    RCC->PLLCFGR |= RCC_PLLCFGR_PLLP_0; // div4
    
    RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_Msk;
    RCC->PLLCFGR |= 4 << RCC_PLLCFGR_PLLQ_Pos;
    
    RCC->CR |= RCC_CR_PLLON;
    while( !(RCC->CR & RCC_CR_PLLRDY) ){}
    
    // CPU, AHB, APB buses clocks
    RCC->CFGR &= ~RCC_CFGR_SW_Msk;// PLL CLK SRC
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    while( !(RCC->CFGR & RCC_CFGR_SWS_PLL) ){}
        
        
    // flash
    FLASH->ACR &= ~FLASH_ACR_LATENCY;
    FLASH->ACR |= FLASH_ACR_LATENCY_2WS;
    
    RCC->CFGR &= ~RCC_CFGR_HPRE; // AHB DIV 1
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    
    RCC->CFGR &= ~RCC_CFGR_PPRE1_Msk; // APB1 DIV 2
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    
    RCC->CFGR &= ~RCC_CFGR_PPRE2_Msk; // APB2 DIV 1
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    

    SystemCoreClockUpdate();

and here is the timer2 configuration


    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    TIM2->CR1 |= TIM_CR1_CKD_1;
    TIM2->PSC = 1093-1;
    TIM2->ARR = 1024 - 1;
    TIM2->CNT = 0;
    
    
    TIM2->DIER |= TIM_DIER_UIE;
    NVIC_EnableIRQ(TIM2_IRQn);
    
    TIM2->CR1 |= TIM_CR1_CEN;

Clock Setting

Is there anything I missed or misunderstood in the configuration?

Upvotes: 1

Views: 1876

Answers (1)

Tagli
Tagli

Reputation: 2592

Your code seems mostly correct. There are 2 problems I can detect, but I'm not sure if they are the real causes.

  • PLL-Q divider should be 7. But this may be irrelevant as you probably don't use USB peripheral. Still, it's best to be in clock limits.
  • You set peripheral divider (APB1) after you switch clock source. It means that before you set it, APB1 is clocked with 84 MHz, which is out of specs.

I'm not sure if there are other errors, but I have tested the code below on a F4 Discovery board. It has a STM32F407, but this uC is quite similar to yours.

FLASH->ACR |= FLASH_ACR_LATENCY_2WS; // 2 wait state for 84 MHz
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ;
RCC->PLLCFGR |= (7 << RCC_PLLCFGR_PLLQ_Pos); // PLL-Q: /7
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC_HSI; // PLL source is HSI
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP;
RCC->PLLCFGR |= (0b01 << RCC_PLLCFGR_PLLP_Pos); // PLL-P: /4
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN;
RCC->PLLCFGR |= (336 << RCC_PLLCFGR_PLLN_Pos); // PLL-N: x336
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM;
RCC->PLLCFGR |= (16 << RCC_PLLCFGR_PLLM_Pos); // PLL-M: /16
RCC->CR |= RCC_CR_PLLON; // Activate the PLL (Output: 84 MHz)
while ((RCC->CR & RCC_CR_PLLRDY) == 0); // Wait until PLL is ready
RCC->CFGR |= RCC_CFGR_HPRE_DIV1 // AHB divider: /1 (84 MHz)
        | RCC_CFGR_PPRE1_DIV2 // APB1 divider: /2 (42 MHz)
        | RCC_CFGR_PPRE2_DIV1; // APB2 divider: /1 (84 MHz)
RCC->CFGR |= RCC_CFGR_SW_PLL; // Switching to PLL clock source
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait until switching is complete

And this is how I configured TIM2 to trigger interrupts with 1 Hz frequency

TIM2->PSC = 42000 - 1;
TIM2->ARR = 2000 - 1; // 1 sec. overflow time @ 84 MHz
TIM2->EGR |= TIM_EGR_UG; // Event generation to update prescaler
TIM2->DIER |= TIM_DIER_UIE; // Enable update interrupt in peripheral
TIM2->CR1 |= TIM_CR1_CEN; // Start timer
NVIC_EnableIRQ(TIM2_IRQn); // Enable interrupt in NVIC

Upvotes: 2

Related Questions