Setting the CPU Frequency (STM32F411CU, HAL or libopencm3)

I have started to play with PlatformIO and have a working blinking LED in two projects, one with HAL, another with libopencm3.
Both of them use this to blink (so clock changes would be visible):

while(true) {
gpio_toggle(LEDPORT, LEDPIN); //Using API function gpio_toggle()
for (i = 0; i<1000000; i++)
asm(“nop”);
}

None of the projects sets the clock explicitly in main.c or elswhere. So I have tried to edit platform.ini:
board_build.f_cpu = 18000000L
build_flags = -D HSE_VALUE=12000000U
build_flags = -D SYS_CLOCK=12000000L
None of these settings changed the blinking frequency.

Is it possible to change the clock (PLL, divider, …) in HAL or libopencm3 projects? What am I doing wrong?
Thanks

Hi!
for libopencm3 use functions like
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_168MHZ]); or configure pll manually with code

Thanks, that worked for libopencm3.
I will have to make own ‘rcc_hse’ define to set more options, but it’s straight forward.

static RCC_ClkInitTypeDef rccClkInstance =
{
    .ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2,
    .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
    .AHBCLKDivider = RCC_SYSCLK_DIV1,
    .APB1CLKDivider = RCC_HCLK_DIV1,
    .APB2CLKDivider = RCC_HCLK_DIV1,
};

static RCC_OscInitTypeDef clock_setup = {
    .OscillatorType = RCC_OSCILLATORTYPE_HSE,
    .HSEState = RCC_CR_HSEON,
    .PLL = {       //100MHz with external 25MHz quarz
        .PLLState = RCC_PLL_ON,
        .PLLSource = RCC_PLLSOURCE_HSE,
        .PLLM = 25,
        .PLLN = 400,
        .PLLP = RCC_PLLP_DIV4,
    }
};

void main()
{
	HAL_Init();
	if(HAL_RCC_OscConfig(&clock_setup) != HAL_OK) Error_Handler();
	if(HAL_RCC_ClockConfig(&rccClkInstance, FLASH_LATENCY_2) != HAL_OK) Error_Handler();
	...
}

works as initialisation using HAL manually (without using STM32CubeMX).
I was falsely thinking that PlatformIO configures the chip on it own, because of existing .ini flags.

Utilizing and Verifying System Clock Configuration on STM32

Here’s how to set up and verify the system clock configuration for an STM32 microcontroller, such as the Blue Pill, using an external 8 MHz crystal to run the MCU at 72 MHz.

Step 1: Create ClockConfig.h and ClockConfig.cpp

ClockConfig.h:

#define CLOCKCONFIG_H

#ifdef __cplusplus
extern "C" {
#endif

void SystemClock_Config(void);
void Error_Handler(void);

#ifdef __cplusplus
}
#endif

#endif // CLOCKCONFIG_H

ClockConfig.cpp:

#include "stm32f1xx_hal.h"

void Error_Handler(void)
{
    // Infinite loop as an error indicator
    while (1) {
        // You can add additional error handling here
    }
}

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    // Configure the HSE oscillator and activate PLL with desired settings
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; // 72 MHz

    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }

    // Configure clocks for CPU, AHB, and APB buses
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK |
                                  RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // Max 36 MHz for APB1
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
        Error_Handler();
    }

    // Ensure the Flash latency is correct
    __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_2);
}

Step 2: Use in main.cpp

main.cpp:

#include "ClockConfig.h"

void setup() {
    HAL_Init();              // Initialize the HAL Library
    SystemClock_Config();    // Configure the system clock

    // Verify clock frequencies using HAL functions
    uint32_t sysClkFreq = HAL_RCC_GetSysClockFreq();
    uint32_t hClkFreq = HAL_RCC_GetHCLKFreq();
    uint32_t pClk1Freq = HAL_RCC_GetPCLK1Freq();
    uint32_t pClk2Freq = HAL_RCC_GetPCLK2Freq();

    // Variables for debugging and verification
    volatile uint32_t debugSysClkFreq = sysClkFreq;
    volatile uint32_t debugHClkFreq = hClkFreq;
    volatile uint32_t debugPClk1Freq = pClk1Freq;
    volatile uint32_t debugPClk2Freq = pClk2Freq;

    // Place breakpoints here to verify the values
}

void loop() {
    // Your main loop code
}

Step 3: Verifying Clock Speed

  1. Debugging:
  • Set breakpoints on the lines where debugSysClkFreq, debugHClkFreq, debugPClk1Freq, and debugPClk2Freq are assigned.
  • Use a debugger to inspect the values and verify that sysClkFreq equals 72 MHz, hClkFreq equals 72 MHz, pClk1Freq equals 36 MHz, and pClk2Freq equals 72 MHz.
  1. Post Verification:
  • Ensure code consistency and verify hardware connections if values do not match expected results. Check oscillator and clock settings in the configuration files.

This setup ensures your STM32 is configured to run at its maximum frequency with an external crystal and provides a reliable method to verify that…