2021-11-26 03:35 AM
Hello,
I need to perform some task without using HAL libraries. I am using CMSIS.
To start, I have set up a blinking led with timer.
I programmed the clock as per attached picture. The source clock of TIM6 should be 60 MHz but the led behaves as it were 30 MHz. It blinks at half the speed.
When I expect 500ms delay, the led stays on (or off) 1s. I don't' understand where this factor 2 comes from.
What am I doing wrong?
Here is the code
#include <stdint.h>
#include "stm32f2xx.h"
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
static void SystemClock_Config();
void TIM6Config (void);
void Delay_us (uint16_t us);
void Delay_ms (uint16_t ms);
int main(void)
{
// uint32_t i;
SystemClock_Config();
//NVIC_SetPriority
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER |= 0x01 << GPIO_MODER_MODER14_Pos;
GPIOB->OSPEEDR |= 0x01 << 29;
//uart (not yet implemented, to be completed)
//ENABLE PORT D AND USART 3
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
GPIOD->AFR[1] |= (7<<0); //ALTERNATE PD8
GPIOD->AFR[1] |= (7<<4); //ALTERNATE PD9
GPIOD->OSPEEDR |= (3<<16) | (3<<18); //HIGH SPEED FOR PD8 AND PD9
TIM6Config ();
/* Loop forever */
while(1) {
GPIOB->ODR ^= GPIO_ODR_ODR_14;
Delay_ms (500);
}
}
static void SystemClock_Config()
{
#define PLL_M_SETTING 8
#define PLL_N_SETTING 240
#define PLL_P_SETTING 0 //PLLP = 2
// Start HSE in Bypass Mode
RCC->CR |= RCC_CR_HSEBYP;
RCC->CR |= RCC_CR_HSEON;
while(!(RCC->CR & RCC_CR_HSERDY));
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
RCC->PLLCFGR |= (PLL_M_SETTING << 0) | (PLL_N_SETTING << 6) | (PLL_P_SETTING << 16) | (RCC_PLLCFGR_PLLSRC_HSE);
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
SystemCoreClockUpdate();
}
void TIM6Config (void)
{
// 1. Enable Timer clock
RCC->APB1ENR |= (1<<4); // Enable the timer6 clock
// 2. Set the prescalar and the ARR
TIM6->PSC = 60-1; // 1 MHz ~~ 1 uS delay
TIM6->ARR = 0xffff; // MAX ARR value
// 3. Enable the Timer, and wait for the update Flag to set
TIM6->CR1 |= (1<<0); // Enable the Counter
while (!(TIM6->SR & (1<<0)));
}
void Delay_us (uint16_t us)
{
TIM6->CNT = 0;
while (TIM6->CNT < us);
}
void Delay_ms (uint16_t ms)
{
for (uint16_t i=0; i<ms; i++)
{
Delay_us (1000); // delay of 1 ms
}
}
Solved! Go to Solution.
2021-11-26 04:56 AM
If in doubts, read out related registers' content and observe.
> RCC->PLLCFGR |= (PLL_M_SETTING << 0) | (PLL_N_SETTING << 6) | (PLL_P_SETTING << 16) | (RCC_PLLCFGR_PLLSRC_HSE);
The default value of RCC->PLLCFGR is not zero, so after this OR it contains something else than you assume.
Also make sure you change FLASH latency before you switch the system clock source.
JW
2021-11-26 04:56 AM
If in doubts, read out related registers' content and observe.
> RCC->PLLCFGR |= (PLL_M_SETTING << 0) | (PLL_N_SETTING << 6) | (PLL_P_SETTING << 16) | (RCC_PLLCFGR_PLLSRC_HSE);
The default value of RCC->PLLCFGR is not zero, so after this OR it contains something else than you assume.
Also make sure you change FLASH latency before you switch the system clock source.
JW
2021-11-26 05:42 AM
In line 56 you have set
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
...which sets the APB1 prescaler to /4 and generates an APB1 timer clock of 30MHz. You should set it to:
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
...to generate an APB1 timer clock of 60MHz.
Regards
/Peter
2021-11-26 06:13 AM
@Peter BENSCH
Thank you for your answer.
Did you have a look at the screenshot I attached?
If it is like you say, why the "APB1 timer clocks" is set to 60MHz, with APB1 prescaler set to 4 and not 2? The APB1 peripheral clock is 30, but the timer clocks is 60 Mhz. Why?
2021-11-26 06:19 AM
Ah, sorry, I read too quickly and assumed an HCLK = 60MHz. Then I keep looking to see if I can find something...
2021-11-26 06:40 AM
@Community member
well spotted! Thank you!
It works, now, after I added the lines
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_Msk;
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLP_Msk;