HSE Clock Setup

Cannot Over Use The Clock of STM32F103C8 over 52Mhz.
Also while using HSE Clock i get garbage value at serial.

What’s your project’s platformio.ini and the code you’re running?

[env:genericSTM32F103C8]
platform = ststm32
board = genericSTM32F103C8
framework = cmsis
upload_protocol = serial
board_build.core = stm32

And the code you’re running?

void setSystemFreq()
{
    // Turn HSE ON
    RCC->CR |= RCC_CR_HSEON;
    // Wait Until HSE Is Ready
    while (!(RCC->CR & RCC_CR_HSERDY));
    // // Set HSE Prescaler On PLL Entry
    RCC->CFGR &= ~RCC_CFGR_PLLXTPRE;
    // //Set PLL Source
    RCC->CFGR &= ~RCC_CFGR_PLLSRC;
    // Set PLL Multiplier
    RCC->CFGR |= 0b1100 << 18;
    // Turn On PLL Clock
    RCC->CR |= RCC_CR_PLLON;
    // Wait Until PLL Is Ready
    while (!(RCC->CR & RCC_CR_PLLRDY));
    // Set System To PLL CLock
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    // Clear All Interrupts
    RCC->CIR = 0x009F0000;
}

You got to give a little more info than that in order for us to help you…

What means “cannot use”? Any error? What symtompts?

Where do you set up the UART in this code? Can you give your complete code? (Github or dropbox / google drive preffered)

1 Like

My blue pill just completely stops functioning and freezes whenever i set my PLL multiplier to run over 52MHz. I will upload the code to github. Sorry for inconvenience.

The UART clock is referenced to the device clock. So if you alter the clock the baud rate will go wrong.

e.g. an ESP8266 expects a 40MHz crystal but the actual xtal is usually 26MHz so 115kbaud becomes 74880baud.

e.g an 8MHZ 3V3 328 will probably run at 16MHz if you swap the xtal but the baud rate will double - you set 9600 but 19200 comes out

here you can check my environment

i know that.
i have been using
SystemCoreClockUpdate()
and
SystemCoreClock
to solve the issue

But I am having different problem

The code you provided runs fine on my bluepill for 9600 baud and produces

Hello 5833 56000000

however your ms_delay(1000); doesn’t give 1000 ms delay because it’s a NOP loop with a constant 500 NOPs per millisecond so that won’t work on all frequences. Systick timer is better here.

Anyways I corrected your PLL code by just doing equal things as this does. You set the wrong PLL multiplier and also forget to modify the flash wait states, so code can’t be able tun run after this.

Corrected method:

void setSystemFreq()
{
	RCC->CIR = 0x009F0000;

    // Turn HSE ON
    RCC->CR |= RCC_CR_HSEON;

    // Wait Until HSE Is Ready
    while (!(RCC->CR & RCC_CR_HSERDY))
        ;
    serialPrint("HSE ON\n");

    //set HSE as system clock
    RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_HSE;

    //AHB prescaler
    RCC->CFGR &= ~(RCC_CFGR_HPRE); //remove old prescaler
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //set AHB prescaler = 1.
    //set ADC prescaler = 8
    RCC->CFGR &= ~(RCC_CFGR_ADCPRE);
    RCC->CFGR |= RCC_CFGR_ADCPRE_DIV8;
    //set APB1 prescaler
    RCC->CFGR &= ~(RCC_CFGR_PPRE1);
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
    //set APB2 prescaler
    RCC->CFGR &= ~(RCC_CFGR_PPRE2);
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;

    //set flash wait states to 2 wait states
    FLASH->ACR &= ~(FLASH_ACR_LATENCY);
    FLASH->ACR |= FLASH_ACR_LATENCY_2;

    //Set PLL Multiplier
    //RCC->CFGR |= 0b1100 << 18;
    //at HSE=8MHz, 8*9 = 72MHz.
    RCC->CFGR &= ~(RCC_CFGR_PLLMULL);
    RCC->CFGR |= RCC_CFGR_PLLMULL9;

    // //Set HSE as PLL Source. bit set -> HSE, bit unser -> HSI
    RCC->CFGR |= RCC_CFGR_PLLSRC;

    // Set HSE Prescaler On PLL Entry
    RCC->CFGR &= ~RCC_CFGR_PLLXTPRE;
    RCC->CFGR |= RCC_CFGR_PLLXTPRE_HSE; //no HSE prescaler before PLL entry


    // Turn On PLL Clock
    RCC->CR |= RCC_CR_PLLON;
    serialPrint("wait for PLL ON\n");
    //ms_delay(1000);

    // Wait Until PLL Is Ready
    while (!(RCC->CR & RCC_CR_PLLRDY))
        ;
    serialPrint("PLL rdy\n");

    //serialPrint("Clock ON\n");
    //ms_delay(1000);
    // Set System To PLL CLock
    RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_PLL;
    serialPrint("switched to PLL clock\n");


    // Clear All Interrupts
    RCC->CIR = 0x009F0000;
}

outputs (with extra prints in clock source enabled)

Hello 7500 72000000
Clock Source : 1
AHB_Prec : 0
Pll_Multiplier : 9
PLL_Source : 1
HSE_Prec : 0
PLL_Freq : 72000000
SystemCoreClock : 72000000

So you have your 72MHz now and the UART still works at 9600 baud.

Here’s the libopencm3 code for configuring 72 MHz operations. It covers many additional aspects:

  • If first enable the internal HSI before switching to HSE
  • It configures prescalers for the different internal buses (AHB, ADC etc.)
  • It sets 2 wait states for flash access (this might be your immediate problem)

You also have a bug in your delay using Sysclock function. Since you decided to use C++ code in this C framework, you must name interrupt functions according to their C-linkage names

so

must be

extern "C" void SysTick_Handler()

then delayInit(); and delayMs also works.

1 Like

Is it necessary to set AHB, APB bus speed?
Also what is the flash register for?
I just wrote ms_delay for debugging I am planning to change it in future.

Peripherals like timers and UART are connected to the AHB and APB buses. If you change the system clock, they can be affected as well. If they are incorrectly configured for the higher system clok, timers and UART no longer work.

I propose you install STM32CubeMX. It has an interactive clock configuration tool that will help you better understand the clock configuration.

Changes the flash wait states. The CPU needs to insert wait states when it has a faster clock speed than the speed at which the flash and prefetch buffer can serve instructions to the CPU. So it has to stall for a few cycles. This is explained in the reference manual page 60 and related…

Yes see that ahb bus is set to presacler 1. If it remains unchanged i get the same speed in apb2 bus which is exactly what i need

H�bbz␂fddd␄�#�␘0a�␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0A�␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄��H�bbz␂fddd␄�#�␘0��␄␄�

I have updated my code.
This what I am getting whenever I use HSE as clock either directly or through PLL

That looks like an incorrect baud rate.

The statemet “The UART clock is referenced to the device clock” (in a post above) isn’t correct. If I’m not mistaken, USART1 is clocked off the APB2 clock, and USART2 off ABP1 (check the reference manual). So after configuring the MCU for a 72 MHz system clock, you will need to update the USART baud rate calculation.

I have a function to auto update baud rate.
If i use HSI clock for any PLL presecaler it doesn’t give me any trouble