In this tutorial, you’ll learn how to do STM32CubeIDE/CubeMX code generation without losing your source code. We’ll discuss how to place your manual application code within the auto-generated code inside an STM32CubeIDE project. Therefore, each time you change something in STM32CubeMX (.ioc) configurations and re-run the code generation, your manual application code will be preserved and won’t get deleted by mistake.
It’s so frustrating to make a tiny change in STM32CubeMX (.ioc) configurations like a pin change or something, then you’re surprised that the newly generated code has wiped out (deleted) your manual source code. If you’re using Git, you could reverse the damage, but you’ll still have to properly place your code within the comment tags provided by the STM32CubeIDE. And this is what we’re going to learn here in this tutorial.
Table of Contents
- STM32CubeIDE Code Generation
- STM32CubeIDE Manual Source Code Placement (Sections)
- Example Code Placement in STM32CubeIDE
- Wrap Up
STM32CubeIDE Code Generation
After completing your STM32 project’s configurations in CubeMX or in STM32CubeIDE, you can click on the generate code button or save your settings, and it’ll also prompt you to generate the source code that applies your desired configurations.
Below is an example main.c file after being generated in the STM32CubeIDE project. You can easily spot the “guard” comments that define where the user’s (your) code should be.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } |
STM32CubeIDE Manual Source Code Placement (Sections)
The STM32CubeIDE code generation tool doesn’t preserve all the manual code you write anywhere inside the generated source files. It only preserves the code that you place between the USER CODE BEGIN and USER CODE END comment tags.
For example, this is a valid place to add your own header files.
|
1 2 3 4 |
/* USER CODE BEGIN Includes */ #include <stdio.h> #include <string.h> /* USER CODE END Includes */ |
And this is another valid place to add your own private variables.
|
1 2 3 |
/* USER CODE BEGIN PV */ uint32_t LastTick = 0; /* USER CODE END PV */ |
Any code placed between those two guard comments will be kept by STM32CubeIDE when you re-generate the project code. On the other hand, any manual code written outside these user code sections can be overwritten or deleted by the code generation tool.
Here is a quick overview of the most commonly used user code sections inside the main.c file.
| User Code Section | What To Place There |
|---|---|
USER CODE BEGIN Includes | Extra header files |
USER CODE BEGIN PTD | Private typedefs, structs, enums |
USER CODE BEGIN PD | Private definitions and constants |
USER CODE BEGIN PM | Private macros |
USER CODE BEGIN PV | Private global/static variables |
USER CODE BEGIN PFP | Private function prototypes |
USER CODE BEGIN 0 | Private functions or callback functions |
USER CODE BEGIN 1 | Code at the beginning of main() before HAL initialization |
USER CODE BEGIN Init | Extra initialization after HAL_Init() |
USER CODE BEGIN SysInit | System-level initialization after clock configuration |
USER CODE BEGIN 2 | Application initialization after peripheral initialization |
USER CODE BEGIN 3 | Application code inside the infinite while loop |
The most important sections you’ll use most of the time are Includes, PD, PV, PFP, 0, 2, and 3.
For example, if you want to add a variable, place it in the PV section. If you want to add a function prototype, place it in the PFP section. If you want to add your main application logic that runs continuously, place it inside the USER CODE BEGIN 3 section.
Note: You should also be careful not to rename, delete, or move the user code guard comments themselves. STM32CubeIDE depends on these exact comment tags to know which parts of the file should be preserved.
Example Code Placement in STM32CubeIDE
Let’s say we’ve configured one GPIO pin as an output pin for an LED, and another GPIO pin as an external interrupt input for a push button. We want to toggle the LED each time the button is pressed.
First, in STM32CubeMX, you can label the pins as LED_Pin and BTN_Pin. This will make the generated code more readable in main.h.
Now, the manual application code can be placed in the USER CODE BEGIN 0 section.
|
1 2 3 4 5 6 7 8 9 |
/* USER CODE BEGIN 0 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == BTN_Pin) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } } /* USER CODE END 0 */ |
That’s it for this example. The while(1) loop can stay empty.
|
1 2 3 4 5 6 7 8 9 10 |
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ /* USER CODE END 3 */ } |
Now, whenever the button interrupt fires, the HAL library will call HAL_GPIO_EXTI_Callback(), and our manual code will toggle the LED output pin.
Since the callback function is written between the USER CODE BEGIN 0 and USER CODE END 0 tags, STM32CubeIDE will preserve it even if you change the .ioc file and regenerate the code later.
Wrap Up
In conclusion, STM32CubeIDE gives us dedicated user code sections to safely place our manual application code within the auto-generated project files. As long as your code is placed between the USER CODE BEGIN and USER CODE END comment tags, it’ll be preserved after each code generation.
This is extremely important when working with STM32CubeMX or STM32CubeIDE because project configurations usually change many times during development. So, always make sure to place your includes, variables, functions, initialization code, and main loop logic in the proper user code sections.
This will save you a lot of frustration and help keep your STM32 projects’ manual code clean, organized, and compatible with the STM32CubeIDE auto code generation process.
Also Read
