Linux
Environment Introduction
This tutorial covers the environment setup:
- System: Fedora 42 KDE Edition Linux
- System kernel: Linux 6.15.6-200.fc42.x86_64
- Architecture: X86_64
Other Linux environments are also acceptable.
Setting up various environments
Setting up the C/C++ environment
# debian系
sudo apt-get install gcc g++ gdb cmake-gui make
# rhel系
sudo dnf install gcc g++ gdb cmake-gui make

Check whether the environment was installed successfully.
gcc -v
g++ -v
gdb -v
cmake --version




Next, test whether C/C++ can be compiled normally. Find a folder containing C++ code, then cd into it in the terminal.

Then create a .cpp file and edit it with vim.
vim hello.cpp
Copy the following code into this file.
#include <iostream>
int main(int argc,char **argv)
{
std::cout << "你好,机电创新学会!" << std::endl;
return 0;
}
Then compile
g++ -o hello hello.cpp
ls

Run
./hello

The environment is already set up.
Install CubeMX

Download link:
https://www.st.com.cn/zh/development-tools/stm32cubemx.html
It is recommended to download version 6.14.1 (do not download version 6.15.0, as this version has a bug, and it is unclear when it will be fixed).


Decompress it.

Open this software with root privileges SetupSTM32CubeMX-6.15.0.
sudo ./SetupSTM32CubeMX-6.15.0

In the newly popped-up window, just keep clicking Next until the installation finishes. When it looks like the image below, the installation is successful.

/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX Enter this folder, then open a terminal and type
./STM32CubeMX

Click Help

Select Manage embedded software packages, and check the first and latest firmware for STM32F1, F4, and H7.

Click install.

Logged into the account.

Then wait for the download and installation to finish.

Just download it.
Next, you can configure a desktop shortcut for CubeMX application for quick access. For detailed instructions, refer to the Appimage section of the Vinci Robotics Team Linux Beginner Tutorial. You can use Ctrl+F to quickly locate that section.
The desktop shortcut is as follows:
[Desktop Entry]
Name=STM32CubeMX
Exec=/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX
Icon=/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX/help/STM32CubeMX.png
Type=Application
Categories=Development;Electronics;Embedded;
Comment=STM32CubeMX configuration and code generation tool
Terminal=false
Just follow the tutorial, and you'll be able to achieve this effect.


Install VSCode
https://code.visualstudio.com/Download

If it's a Debian-based system, download the .deb; if it's an RHEL-based system, download the .rpm.
After downloading, open your browser, locate the folder containing this installation package, and open a terminal in that path.

Debian-based: Enter sudo apt install ./code then press the tab key to autocomplete the filename, then press Enter.
RHEL series: Enter sudo dnf install ./code and then press the tab key to autocomplete the filename, then press Enter.
For example, after completion:
sudo dnf install ./code-1.102.1-1752598767.el8.x86_64.rpm

Then open VSCode and enter the following command in the terminal:
code

Then install some plugins.

All of the following need to be installed.




Install the ARM GNU toolchain
Compiler Tool Comparison:
| Features | ARM GCC (GNU Toolchain) | Keil AC5 (ARM Compiler 5) | Keil AC6 (ARM Compiler 6) |
|---|---|---|---|
| Core identity | Open-source compiler based on GNU GPL | ARM's traditional proprietary compiler | A modern compiler based on LLVM/Clang |
| Licensing Model | Free, open-source | Commercial license (included in MDK) | Commercial license (included in MDK) |
| Code Generation / Optimization | Good, continuous improvement. | Excellent (especially in small code size) | Excellent, striking the best balance between performance and size. |
| Standard Compatibility | Stay up to date with the latest C/C++ standards (such as C17, C++17/20). | Primarily supports C++98, which is relatively outdated. | Supports modern C++ (C++11/14/17) with better compatibility. |
| Error/Warning Messages | Relatively clear and easy to understand. | relatively obscure | Very clear and friendly, similar to GCC/Clang. |
| Integration with Keil MDK | Requires manual configuration or through CubeIDE | Native, seamless integration | Native, seamless integration—the recommended choice by ARM. |
| Linker script | Use a custom linker script syntax (.ld file) | Using ARM's own scatter loading file syntax (.sct) | Using ARM's own scatter loading file syntax (.sct) |
| Assembly syntax | Using GNU assembly syntax (.S file) | Using ARM assembly syntax (.s) | Using ARM assembly syntax (.s), but AC6 is stricter. |
| Ecosystem and Future | Its strong ecosystem makes it the top choice for many open-source projects (such as Zephyr, ESP-IDF) and IDEs (CubeIDE, VS Code). | In maintenance mode, ARM will no longer add new features and is not recommended for new projects. | It is the future and mainstay of ARM, with continuous updates and optimizations. |
Install
It is recommended to use the official method for installation.
Method 1 (Official Method)
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

Enter the download directory and open the terminal.

In the terminal, enter the following command to copy the compiler's tar archive to the folder where you store your programs (you can choose this folder yourself; it's recommended to place it in the home partition, just make sure you don't delete it later).
The specific command is cp ./arm-gnu, then press tab to autocomplete, then a space, followed by the path to the folder you want to copy to.
For example, the following command:
cp ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz ~/UserFolder/Applications/
Then enter the copied folder:
cd ~/UserFolder/Applications/

In the terminal, type tar -xvf ./arm-gnu and press tab to autocomplete.
For example, after I filled it in:
tar -xvf ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz

Then enter this unzipped folder.
cd ./arm-gnuFill in according to tab.
cd ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/
cd ./bin
Check the folder path
pwd

Copy /home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin
Then you need to configure the environment.
vim ~/.bashrc
At the end, enter the following command, replacing ~/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin with the path you just copied. /home/用户名 can be replaced with ~.
export PATH=/home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin:$PATH

Loading environment
source ~/.bashrc
Method 2 (System Repository Method)
This method is not recommended
# Debian系
sudo apt install arm-none-eabi-gcc
# Rhel系
sudo dnf install arm-none-eabi-gcc

test
Check the version.
arm-none-eabi-gcc -v

Install the JLink driver
Install the libreadline library
We will use the JLinkExe command for flashing, which requires the libreadline library. Therefore, install the libreadline library by executing the following command:
# debian系
sudo apt-get install libreadline-dev
# rhel系
sudo dnf install readline-devel

Install the JLink driver
https://www.segger.com/downloads/jlink/

It is a Debian-based system; download the 64-bit DEB.
Download the 64-bit RPM for RHEL-based systems.
(The 64-bit here refers to amd64 and X86_64. If you are using ARM64, please download the 64-bit version under Linux ARM below.)

Open the downloaded folder, and open the terminal.

Then sudo apt install ./JLink then tab to complete.
Then sudo dnf install ./JLink then tab to complete.
sudo dnf install ./JLink_Linux_V852_x86_64.rpm

Check if the installation was successful.
JLinkExe

We click No, and then enter Commander interactive mode. In this mode, we can execute various commands provided by J-Link Commander to connect, configure the debugger, download programs or files to the target device, and more. Interested students can explore this on their own.
Execute the "q" command to exit this mode.

Download and install Ozone
https://www.segger.com/products/development-tools/ozone-j-link-debugger/


It is a Debian-based system; download the 64-bit DEB.
Download the 64-bit RPM for RHEL-based systems.
(The 64-bit here refers to amd64 and X86_64. If you are using ARM64, please download the 64-bit version under Linux ARM below.)

Then sudo apt install ./Ozone then tab to complete.
Then sudo dnf install ./Ozone then tab to complete.
sudo dnf install ./Ozone_Linux_V338g_x86_64.rpm

test
Open the terminal and enter
ozone

Download SVD
https://www.st.com.cn/content/st\_com/zh.html
Search for the chip model, such as stm32f103c8t6.

CAD resources

Download SVD; click the area inside the red box to download it.

After decompression, you can obtain the SVD files for the F1 series.

Just download and extract the F4 and H7 versions as well, one after the other. (You can extract them into the same folder.)

Then open a terminal in the folder above.
Copy all of these folders into Ozone's Config/Peripherals/ directory. (You need to confirm in advance whether Ozone's configuration uses this path before copying.)

sudo cp ./*.svd /opt/SEGGER/Ozone_V338g/Config/Peripherals/


Project Creation and Testing
Create a project using CubeMX
Click the button to select a microcontroller.

Search for the corresponding chip, and double-click the chip option.

Perform some configuration. The following are all very basic things that you definitely already know before watching this video.


Open any IO for testing, such as the LED's GPIO.


FreeRTOS also needs to be configured.


These folders also need to be configured properly. Finally, select CMake for Toolchain and choose GCC for the compiler (it's normal not to have the compiler selection option in version 6.14.1 and earlier).
(However, CubeMX 6.15.0 has a bug — selecting the GCC compiler here doesn't actually work, and you'll need to manually select the compiler later. This bug may be fixed in a future release.)


Configure and compile the project.
Open a terminal in the project folder.

Then open vscode
code .

After entering VSCode, click on the CMakeLists.txt file in the directory.

Check around line 25 for the following line. If it's not there, you need to manually add these two lines. (Version 6.14.1 does not have this bug.)
tips1: This is the bug in CubeMX version 6.15.0 mentioned above. Because this version added support for the Clang compiler and also allows selecting the compiler in CubeMX, but this option was likely not implemented correctly by the engineers. No matter which compiler you select, it won't actually choose the one you picked, so you need to select it manually.
tips2: CubeMX 6.15.0 has a second bug. It states that the workspace root CMakeLists.txt will only be generated once and will not be overwritten in subsequent generations. However, it turns out that after modifying the configuration in CubeMX and regenerating the code, all other commands are preserved except for this one. It's unclear whether this will be fixed in a future version, or if the bug from tips1 will be addressed directly. So, after each reconfiguration of CubeMX, you need to add this line back in.

# Include toolchain file
include("cmake/gcc-arm-none-eabi.cmake")
Press Ctrl+` to open the built-in terminal.

Use the command below to create and enter the build folder.
mkdir build
cd build

Next, use the cmake command to generate the makefile.
cmake ..
Check whether ARM's C/C++ and assembly compilers have all been found (if not, please check if there are any mistakes in the tutorial above).

Then use the make command to compile, with the command being make or make -jxx. Here, xx is the number of CPU threads you want to use for compilation. For example, if my computer has 8 cores and 16 threads, I can set xx to a number lower than 16. Meanwhile, make uses one thread by default. If you don't know how many threads your CPU has, just stick with the make command and don't use the make -jxx command.
make -j16
That means the compilation was successful.

Configure code hints.
In VSCode, press Ctrl+Shift+P, search for clangd, and select to download the language server.

Select Install in the bottom right corner, and once the installation is complete, a prompt like the one shown below will appear.

Next, disable the code suggestion feature of the C/C++ plugin (if you don't see this interface, scroll down).

If the pop-up shown above does not appear, you can manually close it. Again, press Ctrl+Shift+P, type "settings", and then find the option shown in the image below.

Find the option shown in the image below and change it to disabled.
"C_Cpp.intelliSenseEngine": "disabled"

In VSCode, press Ctrl+Shift+P again, search for clangd, and select Restart clangd language server (you must have compiled the code at least once before restarting the clangd language server).

At this point, you can see that the header files in the code are recognized correctly, and the code suggestions are working properly.



⚠️ Note: Clangd by default looks for the host system's libc/include path (e.g., x86_64's /usr/include) , but our project actually uses the ARM toolchain's header file path , which can cause errors when including C/C++ standard library headers.
For example:

The #include <math.h> here shows that the header file cannot be found, but when we compile it, there is no error, which means the clangd configuration is incorrect. The following describes a solution:
- Run the following command to get the standard include paths used by ARM GCC:
arm-none-eabi-gcc -x c -E -v - </dev/null

- Create a
.clangdfile in the project root directory and include your header file path (replace the content inside the quotes with your own ARM GCC header file path).
CompileFlags:
Add: [
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/lib/gcc/arm-none-eabi/14.3.1/include",
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/lib/gcc/arm-none-eabi/14.3.1/include-fixed",
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/arm-none-eabi/include"
]
Save, then refresh clangd. The header file prompt now works normally.

Porting the Vinci Robot Team's standard C/C++ project template
Use the git clone command to clone the repository: https://github.com/tungchiahui/CubeMX_MDK5to6_Template
git clone https://github.com/tungchiahui/CubeMX_MDK5to6_Template.git
Copy all contents from the "工程文件移植" folder in the repository into our CMake project directory.

Then open the applications folder, and create led_task.cpp and led_task.h in the Src and Inc folders respectively, with the following contents:

led_task.cpp:
#include "led_task.h"
#include "cmsis_os.h"
#include "stm32f1xx_hal.h"
GPIO_PinState pinstate = GPIO_PIN_RESET;
extern "C"
void StartDefaultTask(void *argument)
{
for(;;)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,pinstate);
pinstate = (pinstate == GPIO_PIN_RESET) ? GPIO_PIN_SET : GPIO_PIN_RESET;
osDelay(500);
}
}
led_task.h:
#ifndef __LED_TASK_H_
#define __LED_TASK_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "cpp_interface.h"
#ifdef __cplusplus
}
#endif
#endif
Then open CMakeLists.txt in the cmake/user folder and add the newly created led_task.cpp file.
Detailed introduction (optional reading): The cmake/stm32cubemx under CMakeLists.txt here is managed by CubeMX. Once you regenerate the code with CubeMX, the contents of this file will be overwritten. However, the CMakeLists.txt at the workspace root will not be overwritten, and it provides some areas for us to add source and header files. But this can make the file too cluttered. So we chose to create a new user folder, set up a CMakeLists.txt inside it, and then use the top-level CMakeLists.txt to load this sub-CMakeLists.txt. This sub-CMakeLists.txt makes it easier for us to modify, and the file structure is clearer. (We don't need to create these ourselves—I've already created them in the Project File Migration section, and you've already copied them over when you copied the files above.)

Then, go to the top-level CMakeLists.txt and add this line to reference our own CMakeLists.txt.

# Add USER generated sources
add_subdirectory(cmake/user)
Great success, let's try compiling once. As shown in the image below, all the newly added files have been compiled.
cmake ..
make

Then go to main.c, include the cpp_interface.h header file, and call the cpp_main() function at this location within the main function. (I have RTOS enabled here, so the cpp_main function needs to be called before starting RTOS. If you are using a bare-metal program without RTOS, just call cpp_main above the while (1) loop.)


Then modify the isRTOS macro in cpp_interface.h to let the program know whether you have enabled RTOS. If enabled, set the macro to 1; if running on bare metal, set it to 0.


For more detailed information about STM32 C/C++ project engineering, please refer to the Vinci Robotics Team Microcontroller Tutorial.
Now compile the program in the build folder and find success!
cmake ..
make

Download the program to the board
Configure CMake to generate .bin and .hex files
Before downloading the program to the board, we need to check what files were actually generated from our previous compilation.
From the image below, it can be seen that it only generated a .elf file, not the common .bin and .hex files we typically see.

We need to modify the CMakeLists.txt in the workspace again so that .hex and .bin files are generated during compilation (unfortunately, it has to be this tedious — I don't know why CubeMX doesn't handle it all).

# 生成 .bin 和 .hex 文件
find_program(OBJCOPY arm-none-eabi-objcopy REQUIRED)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${OBJCOPY} -O binary ${CMAKE_PROJECT_NAME}.elf ${CMAKE_PROJECT_NAME}.bin
COMMAND ${OBJCOPY} -O ihex ${CMAKE_PROJECT_NAME}.elf ${CMAKE_PROJECT_NAME}.hex
COMMENT "Generating ${CMAKE_PROJECT_NAME}.bin and ${CMAKE_PROJECT_NAME}.hex from ${CMAKE_PROJECT_NAME}.elf"
)
I've written all the commands that need to be added to the workspace's main CMakeLists.txt in this notepad. Just copy them directly each time you generate a new project.


Then compile again.
cmake ..
make

Now look at the build directory: the .hex or .bin files we need are ready.

Connect the device to the JLink and flash the program.
Graphical interface flashing
#打开终端输入
JFlashLite
Select the corresponding chip model and speed.

Add hex file


Click to burn and complete:

Successfully lit the LED.

Terminal Flashing
Forget it, forget it, it's too much trouble.
Configure VSCode tasks
When we compile above, we always need to enter the following command
cd build
cmake ..
make
This makes compiling too cumbersome each time, so we use the powerful VSCode for one-click compilation.
First, create the .vscode folder and the tasks.json file.

Here is the content of tasks.json:
{
"version": "2.0.0",
"options": {
"cwd": "${workspaceFolder}/build" //需要进入到我们执行tasks任务的文件夹中
},
"tasks": [ //tasks包含4个任务
{
"type": "shell",
"label": "stm32-cmake", //第一个任务的名字叫cmake
"command": "bash",
"args": [
"-c",
"mkdir -p ../log && echo \"===== CMake started at: $(date) =====\" | tee -a ../log/cmake.log && cmake .. 2>&1 | tee -a ../log/cmake.log"
],
"problemMatcher": [] //这里需要添加一个空的问题匹配器,否则会报错
},
{
"label": "stm32-make", //第二个任务的名字叫make
"command": "bash",
"args": [
"-c",
"mkdir -p ../log && echo \"===== Make started at: $(date) =====\" | tee -a ../log/make.log && make -j$(grep -c ^processor /proc/cpuinfo) 2>&1 | tee -a ../log/make.log"
],
"problemMatcher": [] //这里也需要添加一个空的问题匹配器,否则会报错
},
{
"label": "stm32-Build", //第3个任务的名字叫Build
"group": { //默认是build任务
"kind": "build",
"isDefault": true
},
"dependsOrder": "sequence", //顺序执行依赖项
"dependsOn":[ //依赖的2个项为cmake、make
"stm32-cmake", //即第一个任务的label
"stm32-make" //即第二个任务的label
]
},
{
"type": "shell",
"label": "stm32-clean", //第四个任务:清理 build 文件夹
"command": "bash",
"args": [
"-c",
"echo \"===== Clean started at: $(date) =====\" && rm -rf * && echo \"Build folder cleaned.\""
],
"options": {
"cwd": "${workspaceFolder}/build" //只清理build目录下的文件
},
"problemMatcher": [] //不需要问题匹配器
}
]
}
Method 1:
On the VScode title bar, find 终端, then select 运行构建任务. The shortcut key is Ctrl+Shift+B.

It can be seen that the task has already been executed.

Method 2:
On the VScode title bar, find 终端, then select 运行任务.

Below are 4 STM32 tasks. The first one is the stm32-Build task. After running it, the effect is the same as Method 1 just now. The 运行构建任务 button in Method 1 actually runs this stm32-Build task.
This stm32-Build task includes the stm32-cmake and stm32-make tasks.
Then the stm32-clean task is to clear all files in the build folder.

You can try the stm32-clean task.

You can see that everything has been deleted.

You don't need to worry about configuring so many things every time you create a new project.
Most of the configuration files above are already included in https://github.com/tungchiahui/CubeMX\_MDK5to6\_Template仓库下的***`工程文件移植(创建新模板请看这里)`***文件夹了,到时候新建一个工程后,直接把这个文件夹下的所有文件全部复制过来即可。.
Using ozone for Flash programming and Debug debugging
Basic Configuration
Open the terminal, type ozone to launch the software, or directly find the application icon to open Ozone.


First, select a device, such as the STM32F407VET6 for my case.


Select Peripherals:

Click Next.

Fill in SWD if you are using SWD, or JTAG if you are using JTAG.

Choose ELF

You can choose elf, hex, or bin — generally, just pick elf.

Just keep the default setting for this step.

If you have enabled RTOS, you may encounter this issue.
warning (138): The target application seems to be using FreeRTOS, but FreeRTOS-awareness is not enabled.
It means your target application appears to use FreeRTOS, but FreeRTOS debugging support (RTOS-awareness) is currently not enabled.

Just apply the fix directly as instructed below.

Just click continue.


Flashing and Debugging
You can check out the video below, it's pretty good. (Start watching from 30:10)
https://www.bilibili.com/video/BV1yrLHzZEoE

Click File to sort by file name.

Find led_task.cpp and click to open this source file.
