STM32CubeMX
Last updated: 2026-04-15
On this page
1) What is STM32CubeMX?
STM32CubeMX is STMicroelectronics’ configuration tool for STM32 microcontrollers. Its main job is to stop you from doing 40 minutes of register archaeology just to turn on a UART.
It helps you:
- select and configure peripherals (GPIO, UART, SPI, I2C, CAN, timers, ADC, DMA, etc.),
- set up the clock tree (a.k.a. the “why is my baud rate cursed” page),
- generate initialization code (HAL/LL) and project files for your IDE/toolchain.
RoboTeam context: we use CubeMX primarily as a configuration source of truth for pins, clocks, and peripheral init. The generated code is then compiled as part of the firmware in our repositories. In other words: the .ioc file is the “contract”, and the generated code is the implementation we agree not to hand-edit into chaos.
2) Before you start
What you should have
- The correct board / STM32 part number (ask your lead if unsure — guessing is how you meet the smoke monster).
- The firmware repository checked out and building at least once.
- Basic Git workflow (branch, commit, PR).
Things to clarify (ask in RoboTeam channels)
- Toolchain: Are we using STM32CubeIDE, Make/CMake, or another setup for this project?
- HAL vs LL: Most projects use HAL; some performance-critical code may use LL.
- RTOS: Does this firmware use FreeRTOS?
Important: CubeMX can overwrite files. Treat code generation as a controlled action, not a button you mash until it “looks right”.
3) Install & open a project
Install
- Install STM32CubeMX (standalone) or STM32CubeIDE (includes CubeMX functionality). Use whatever the project expects — the build system does not care about your editor preferences.
- Install the correct STM32 device pack / firmware package when prompted.
Open an existing RoboTeam project
Most RoboTeam embedded repos store CubeMX configuration as an .ioc file.
- Find the
.iocfile in the repository (common names:*.ioc,board.ioc,project.ioc). - Open it in CubeMX (double click on Windows/macOS, or use File → Open Project).
- Confirm the MCU/board matches what you expect.
Tip: If you can’t find an .ioc file, the project may not be CubeMX-based or it’s stored elsewhere. Ask your team before creating a new one (creating a new one is how you get “two sources of truth” and zero joy).
4) Typical RoboTeam workflow
When you need to add/change a peripheral (for example: “add UART for debug”):
- Pull latest and create a branch:
feature/cubemx-uart-debug - Open the
.iocin CubeMX. - Make minimal changes: pin assignment, peripheral settings, clocks, DMA, NVIC.
- Generate code (carefully, see Code generation rules).
- Run the post-generation scriptst remove all generated artifacts
- Build + run formatting/tests if your repo has them.
- Commit changes (both
.iocand generated code) and open a PR.
The post generation script is neccessary for the compilation of the current project structure. For more information go to the Post-Generation Scripts
5) Pinout & peripherals
Pinout view
Use the Pinout & Configuration tab to assign functions to pins (GPIO, UART TX/RX, SPI SCK/MISO/MOSI, etc.).
- Click a pin and select the function (e.g.
USART2_TX). - Resolve conflicts (CubeMX will warn you if a pin is already used).
- Give GPIOs meaningful labels in CubeMX (helps readability and makes reviews less painful).
Peripheral configuration
For each enabled peripheral (left-side tree), configure:
- Mode/settings: baud rate, polarity, prescalers, sample times, etc.
- DMA: if you need high throughput / low CPU usage.
- NVIC: interrupts and priorities, especially if using FreeRTOS.
RoboTeam convention (recommended): keep pin naming consistent with schematics. If the schematic says IMU_CS, don’t rename it to GPIO_OUT_7 just because you can.
6) Clock configuration
The Clock Configuration tab controls system frequency and peripheral clocks. Getting this right is critical for:
- accurate UART baud rates,
- correct timer frequencies (motor control / PWM),
- USB timing, and
- stable CPU operation.
What to watch for
- Clock source: HSI vs HSE (internal vs external crystal).
- PLL settings: CubeMX will highlight invalid ranges (it is judging you, but it’s also correct).
- Peripheral clock mux: some peripherals can pick different clock sources.
Common pitfall: “It compiles but communication is broken.” Often the root cause is a clock mismatch causing wrong baud rate or timing. If you’re on Windows and things are extra weird, double-check you’re using the right compiler/toolchain for the repo (don’t invent a new one mid-debug).
7) Middleware (FreeRTOS, USB, etc.)
Middleware is configured in CubeMX under Middleware (varies by STM32 family / CubeMX version).
FreeRTOS
- Define tasks, priorities, stack sizes, and timers.
- Be consistent with interrupt priorities (especially if calling RTOS APIs from ISRs, because the scheduler is not your therapist).
8) Code generation rules (IMPORTANT)
Do not hand-edit generated sections. CubeMX regeneration can overwrite changes outside of “User Code” blocks. If you fight the generator, the generator wins.
User Code blocks
CubeMX-generated files typically contain protected regions like:
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
Only put custom code inside these regions if you must edit generated files.
Safer pattern: keep custom code outside generated files
If the project structure allows it, prefer:
- putting application logic in separate
src/files, - calling your init/setup from
main()inside a user code block, - keeping CubeMX-owned init in its generated location.
When you click “Generate Code”
- Scan the “Project Manager” settings first.
- Confirm the output location matches the repo layout.
- Generate, then immediately git diff to inspect what changed (trust nothing, verify everything).
Golden rule: Always review the diff. If CubeMX touched hundreds of unrelated lines, stop and ask before committing — that’s not “progress”, that’s a surprise refactor.
Versioning
CubeMX, HAL packages, and codegen output can change between versions. If your team uses a specific CubeMX/Cube firmware version, write it down in the repo/wiki and try to match it. Consistency beats heroics.
9) Git best practices
- Commit the
.iocfile (it’s the source config). - Commit generated code if the repository expects it (most do).
- Keep commits focused:
CubeMX: enable UART2 + DMA RX. - Do not mix unrelated refactors with CubeMX regen commits (reviewers can only suffer so much).
Recommended commit flow
- Commit 1:
.iocchanges - Commit 2: generated code changes (if separate)
- Commit 3+: application code changes
10) Troubleshooting
“CubeMX overwrote my changes”
- Check if your edits were outside
/* USER CODE BEGIN */blocks. - Restore from Git history and move custom code into separate files or user regions.
“Pins conflict / can’t enable peripheral”
- Some pins have limited alternate functions; check the datasheet.
- Try remapping (different instance: USART1 vs USART2) if the board wiring allows it.
“UART/SPI/I2C is behaving weird”
- Verify clocks and prescalers.
- Confirm pull-ups/pull-downs and GPIO speed settings.
- Check DMA/interrupt configuration and priorities.
“Build fails after regeneration”
- Compare project settings in “Project Manager”.
- Check include paths / generated file locations.
- Inspect the diff for deleted/renamed files.
If stuck: attach your .ioc, a screenshot of the pinout/clock tabs, and the relevant git diff in your help message. That turns “it doesn’t work” into something the rest of us can actually debug.