Stm32 different result of the program in CubeIDE and platformio (stm32f103)

There were a few difficult days when my work project stopped working. For the experiment, I created a new project in CUBEMX and generated it for CubeIDE and for OtherToolchain, all settings are identical, as you can see in the screenshot.
Then I added the following code to both projects (vscode + platformio and CubeIDE)

/ * USER CODE BEGIN PV * /
uint32_t timme = 0;
char str [64] = {0,};
/ * USER CODE END PV * /

  / * USER CODE BEGIN WHILE * /
  while (1)
  {
    if ((HAL_GetTick () - timme)> 5000) // 10sec interval
      {
        snprintf (str, 64, "SEK:% d \ r \ n", 5);
        HAL_UART_Transmit (& huart1, (uint8_t *) str, strlen (str), 1000);

        snprintf (str, 64, "Core =% d,% d MHz \ r \ n", SystemCoreClock, SystemCoreClock / 1000000);
        HAL_UART_Transmit (& huart1, (uint8_t *) str, strlen (str), 1000);
        snprintf (str, 64, "HCLK =% d \ r \ n", HAL_RCC_GetHCLKFreq ());
        HAL_UART_Transmit (& huart1, (uint8_t *) str, strlen (str), 1000);
        snprintf (str, 64, "APB1 =% d \ r \ n", HAL_RCC_GetPCLK1Freq ());
        HAL_UART_Transmit (& huart1, (uint8_t *) str, strlen (str), 1000);
        snprintf (str, 64, "APB2 =% d \ r \ n", HAL_RCC_GetPCLK2Freq ());
        HAL_UART_Transmit (& huart1, (uint8_t *) str, strlen (str), 1000);

        timme = HAL_GetTick ();
      }
    / * USER CODE END WHILE * /

platformio.ini

[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = stm32cube
upload_protocol = stlink
build_flags = -Wl,-u_printf_float

I got different data in the port monitor.
What are your assumptions, what could this be related to?



P.S. I really don’t want to switch to CubeIDE😬

@maxgerhardt, I really hope for your exceptional qualified help! Even a simple comparison of files shows their complete identity.

Well but if you can still read the USART output at the same baud rate, that means the inner clock setup is the same and you’re probably not calling SystemCoreClockUpdate() which updates the internal state (reads out the state of the HSI and HSE and the PLL and calculates back the frequency). Otherwise the UART output would be at a different baud rate (double the baudrate if double the clock)

Just like in the official example, I’m taking care of the clock init and update myself.

Using the platformio.ini

[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = stm32cube
upload_protocol = stlink
build_flags = -Wl,-u_printf_float -D HSE_VALUE=8000000
board_build.f_cpu = 72000000L
; if using HSI, comment out above and use
;board_build.f_cpu = 64000000L

and only a src\main.c

#include "stm32f1xx_hal.h"
#include <string.h>
#include <stdio.h>

#define LED_PIN GPIO_PIN_13
#define LED_GPIO_PORT GPIOC
#define LED_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()

/* for reference: HSI setup */
void SystemClock_Config_HSI(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    return;
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  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;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

/* boots to 72MHz with HSE(8MHz) + PLL */
void SystemClock_Config_HSE(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    return;
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  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;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

int main(void)
{
  __HAL_RCC_AFIO_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();

  HAL_Init();
  //SystemClock_Config_HSI();
  SystemClock_Config_HSE();
  SystemCoreClockUpdate();  

  /* LED setup PC13 */ 
  LED_GPIO_CLK_ENABLE();
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.Pin = LED_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);

  /* UART init. USART1, 115200 baud, 8N1. PA9 = TX, PA10 = RX */
  /* start clocks, config GPIOs, config USART peripheral */
  __USART1_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();

  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  UART_HandleTypeDef huart;
  huart.Instance = USART1;
  huart.Init.BaudRate = 115200;
  huart.Init.WordLength = UART_WORDLENGTH_8B;
  huart.Init.Parity = UART_PARITY_NONE;
  huart.Init.StopBits = UART_STOPBITS_1;
  huart.Init.Mode = UART_MODE_TX_RX;
  huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart);

  char str[64] = {0};
  uint32_t timme = 0;
  while (1)
  {
    if ((HAL_GetTick() - timme) > 1000) // 10sec interval
    {
      HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_PIN);
      snprintf(str, 64, "SEK: %d \r\n", 5);
      HAL_UART_Transmit(&huart, (uint8_t *)str, strlen(str), 1000);

      snprintf(str, 64, "Core = %d, %d MHz \r\n", SystemCoreClock, SystemCoreClock / 1000000);
      HAL_UART_Transmit(&huart, (uint8_t *)str, strlen(str), 1000);
      snprintf(str, 64, "HCLK = %d \r\n", HAL_RCC_GetHCLKFreq());
      HAL_UART_Transmit(&huart, (uint8_t *)str, strlen(str), 1000);
      snprintf(str, 64, "APB1 = %d \r\n", HAL_RCC_GetPCLK1Freq());
      HAL_UART_Transmit(&huart, (uint8_t *)str, strlen(str), 1000);
      snprintf(str, 64, "APB2 = %d \r\n", HAL_RCC_GetPCLK2Freq());
      HAL_UART_Transmit(&huart, (uint8_t *)str, strlen(str), 1000);
      
      timme = HAL_GetTick();
    }
  }
}

void SysTick_Handler(void)
{
  HAL_IncTick();
}

void NMI_Handler(void)
{
}

void HardFault_Handler(void)
{
  while (1)
  {
  }
}

void MemManage_Handler(void)
{
  while (1)
  {
  }
}

void BusFault_Handler(void)
{
  while (1)
  {
  }
}

void UsageFault_Handler(void)
{
  while (1)
  {
  }
}

void SVC_Handler(void)
{
}

void DebugMon_Handler(void)
{
}

void PendSV_Handler(void)
{
}

I get the output

SEK: 5
Core = 72000000, 72 MHz
HCLK = 72000000
APB1 = 36000000
APB2 = 72000000

which is correct since I’m running explicitly from HSE (8MHz) and PLL to 72MHz.

If I don’t call SystemClock_Config_HSE() (while still calling SystemCoreClockUpdate) I get

SEK: 5 
Core = 8000000, 8 MHz
HCLK = 8000000
APB1 = 8000000
APB2 = 8000000

so that’s probably the default HSI.

And if I call SystemClock_Config_HSI() I get

SEK: 5 
Core = 64000000, 64 MHz
HCLK = 64000000
APB1 = 32000000
APB2 = 64000000

which is correct for the HSI+PLL setup.

So I’d recommend to explicitly do the clock setup and call SystemCoreClockUpdate() after that

@maxgerhardt , sorry for the incomplete data, it was obvious to me because of the long struggle with this problem. Unfortunately, the USART speed also varies, although the code is initialized to 115200.

Then there really is a factor 2 error somewhere, either in the default clock setup if you’re not doing it yourself or in your code. I’d recommend you to try my example which explicitly sets up HSE+PLL to 72MHz. I’ve tested in on my bluepill :slight_smile:

I update the system clock this way

void SystemCoreClockUpdate (void)
{
  uint32_t tmp = 0U, pllmull = 0U, pllsource = 0U;

#if defined (STM32F105xC) || defined (STM32F107xC)
  uint32_t prediv1source = 0U, prediv1factor = 0U, prediv2factor = 0U, pll2mull = 0U;
#endif / * STM32F105xC * /

#if defined (STM32F100xB) || defined (STM32F100xE)
  uint32_t prediv1factor = 0U;
#endif / * STM32F100xB or STM32F100xE * /
    
  / * Get SYSCLK source --------------------------------------------- ---------- * /
  tmp = RCC-> CFGR & RCC_CFGR_SWS;
  
  switch (tmp)
  {
    case 0x00U: / * HSI used as system clock * /
      SystemCoreClock = HSI_VALUE;
      break;
    case 0x04U: / * HSE used as system clock * /
      SystemCoreClock = HSE_VALUE;
      break;
    case 0x08U: / * PLL used as system clock * /

      / * Get PLL clock source and multiplication factor ---------------------- * /
      pllmull = RCC-> CFGR & RCC_CFGR_PLLMULL;
      pllsource = RCC-> CFGR & RCC_CFGR_PLLSRC;
      
#if! defined (STM32F105xC) &&! defined (STM32F107xC)
      pllmull = (pllmull >> 18U) + 2U;
      
      if (pllsource == 0x00U)
      {
        / * HSI oscillator clock divided by 2 selected as PLL clock entry * /
        SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
      }
      else
      {
 #if defined (STM32F100xB) || defined (STM32F100xE)
       prediv1factor = (RCC-> CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
       / * HSE oscillator clock selected as PREDIV1 clock entry * /
       SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
 #else
        / * HSE selected as PLL clock entry * /
        if ((RCC-> CFGR & RCC_CFGR_PLLXTPRE)! = (uint32_t) RESET)
        {/ * HSE oscillator clock divided by 2 * /
          SystemCoreClock = (HSE_VALUE >> 1U) * pllmull;
        }
        else
        {
          SystemCoreClock = HSE_VALUE * pllmull;
        }
 #endif
      }
#else
      pllmull = pllmull >> 18U;
      
      if (pllmull! = 0x0DU)
      {
         pllmull + = 2U;
      }
      else
      {/ * PLL multiplication factor = PLL input clock * 6.5 * /
        pllmull = 13U / 2U;
      }
            
      if (pllsource == 0x00U)
      {
        / * HSI oscillator clock divided by 2 selected as PLL clock entry * /
        SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
      }
      else
      {/ * PREDIV1 selected as PLL clock entry * /
        
        / * Get PREDIV1 clock source and division factor * /
        prediv1source = RCC-> CFGR2 & RCC_CFGR2_PREDIV1SRC;
        prediv1factor = (RCC-> CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
        
        if (prediv1source == 0U)
        {
          / * HSE oscillator clock selected as PREDIV1 clock entry * /
          SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
        }
        else
        {/ * PLL2 clock selected as PREDIV1 clock entry * /
          
          / * Get PREDIV2 division factor and PLL2 multiplication factor * /
          prediv2factor = ((RCC-> CFGR2 & RCC_CFGR2_PREDIV2) >> 4U) + 1U;
          pll2mull = ((RCC-> CFGR2 & RCC_CFGR2_PLL2MUL) >> 8U) + 2U;
          SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;
        }
      }
#endif / * STM32F105xC * /
      break;

    default:
      SystemCoreClock = HSI_VALUE;
      break;
  }

But now I will definitely check your decision!

And here’s another …
For the purity of the experiment, I created empty projects and deliberately did not touch the clock setting, leaving everything as generated by CubeMX, I just added the output to the port for control frequency.

@maxgerhardt To be honest, I don’t understand why this was not required before, but an explicit indication:
HSE_VALUE = 8000000
board_build.f_cpu = 72000000L
just corrected the situation and now the CPU frequency and USART speed correspond to the real ones.
Apparently, until the 5th update, it was not required to explicitly indicate, so everything worked, but when I tried to make some changes to the project, and I had already updated the platform to the 5th version, I just did not know that I needed to explicitly indicate the frequency of the processor and oscillator …
Max, thanks again!

Hm it’s probably not that the PlatformIO core was updated to 5.x, but the STM32 platform (if you’ve updated that too) had major changes in the STM32Cube builder script and integration in version 10.0.0 (here, here), so it uses the very latest STM32Cube(F1) packages (before that they were outdated by several years).

Yes, using the latest version of STM32 platform gives the desired result! And no explicit indication of frequencies was required.
[env:bluepill_f103c8]
;platform = ststm32
platform = GitHub - platformio/platform-ststm32: ST STM32: development platform for PlatformIO
board = bluepill_f103c8
framework = stm32cube
upload_protocol = stlink
build_flags = -Wl,-u_printf_float -D
;HSE_VALUE=8000000
;board_build.f_cpu = 72000000L

Tell me, how can I update STM32 globally and is it right to do it, maybe it’s better to constantly get the current version from the github by leaving a request in the ini file?

Careful that -D there should be deleted too.

You should be able to use the normal

if you update globally. Either via the PlatformIO Home β†’ Platforms β†’ Updates GUI or in a CLI with pio platform update ststm32.

1 Like

also … i keep getting this error in all my projects, but projects compile and run on MCU

Warning! Cannot find a linker script for the required board! An auto-generated script will be used to link firmware!

I once read on this forum that you shouldn’t pay attention to it, is this statement correct?

That depends. Are they custom board definitions? With which exact platformio.ini are they reproducable with?

Sorry, but the boards are a bit later.
My adventures have continued!
All the previous was a prelude to the main task, I received my PCB from jlcpcb.
Everything there is identical to the bluepill except for MCU 103t8u6 and quartz 16MHz.
I updated the libraries at the global level, with 8MHz frequencies for the bluepill everything works, but when loading the sewing onto a new board, I get discrepancies in the USART speed and the MCU frequency.
I downloaded a test case in which only the external oscillator and USART are installed, I downloaded the same example from STMCubeIDE and everything works fine, but not when loaded from platformio.
Tell me, what can I check in the platformio?
I’m confused by the presence of two installed platforms for STM32

pio platform list

I put things in order in the platforms, deleted all the old ones, left only the latest versions, the situation has not changed :frowning:

This is normal, since in PlatformIo you can arbitrarily switch between platform versions (e.g. platform = ststm32@8.0.0) etc. PlatformIO keeps these installed in case you want to use them again. Look closely at the version field.

You can ofc also uninstall it by removing the other ststm32@xyz folders in C:\Users\<user>\.platformio\platforms (or again the PIO Home β†’ Platform). The only ststm32 that should stay shuld have version 11.0.0 in the package.json :slight_smile:

What exact platformio.ini are you using? Something like

[env:genericSTM32F103T8]
platform = ststm32
board = genericSTM32F103T8
framework = stm32cube
board_build.f_cpu = 72000000L
build_flags = -D HSE_VALUE=16000000

and an adapted SystemClock_Config_HSE that was generated with STM32Cube for max-speed with the right crystal settigns there? Should look like

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

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV2;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  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;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

Certainly! Everything is identical without the small details.

platformio.ini

[env:genericSTM32F103T8]
platform = ststm32
board = genericSTM32F103T8
framework = stm32cube
upload_protocol = stlink

board_build.mcu = stm32f103t8U6
HSE_VALUE = 16000000
board_build.f_cpu = 72000000L

build_flags = 
    ; -D
    -Wl,-u_printf_float 

main.c

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

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV2;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  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;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

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

You can’t write this directly as a line in the platformio.ini, this needs to be inside the build flags. Try build_flags = -D HSE_VALUE=16000000 -Wl,-u_printf_float?

Also are you sure that the function is called durgin the main() function?

From a code point of view, there are not many places where you can go wrong, especially after the cube generates everything, you just have to check. I suppose the problem is with platformio, but I don’t know where to look.

Can you upload the complete PlatformIO project that you’re testing, and what UART output at which baud rate you’re getting?

Oh!Miracle!
It works!!!
Max, I really appreciate your help!
Yes, I need to be more careful with the flag!
Core=72000000, 72 MHz
HCLK=72000000
APB1=36000000
APB2=72000000

2 Likes