跳到正文

Wiki

Linux

約 37 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

1.環境介紹

本教程環境介紹:

  1. 系統:Fedora 42 KDE Edition Linux

  2. 系統核心:Linux 6.15.6-200.fc42.x86_64

  3. 架構:X86_64

其他Linux環境也可以。

2.安裝各種環境

2.1.安裝C/C++環境


# debian系
sudo apt-get install gcc g++ gdb cmake-gui make

# rhel系
sudo dnf install gcc g++ gdb cmake-gui make

檢視是否環境安裝成功

gcc -v
g++ -v
gdb -v
cmake --version

接下來測試是否能夠對C/C++正常編譯,請找一個存放C++程式碼的資料夾,然後在終端中cd進去。

然後建立一個.cpp檔案並用vim編輯

vim hello.cpp

複製以下程式碼到該檔案裡

#include <iostream> 
int main(int argc,char **argv) 
{ 
    std::cout << "你好,机电创新学会!" << std::endl; 
    return 0; 
}

然後編譯

g++ -o hello hello.cpp
ls

執行

./hello

說明環境已經配置好了

2.2.安裝CubeMX

下載地址:

https://www.st.com.cn/zh/development-tools/stm32cubemx.html

推薦下載6.14.1版本(不要下載6.15.0,這個版本有bug,不知道後續何時會修復)

解壓出來

用root許可權開啟這個軟體SetupSTM32CubeMX-6.15.0

sudo ./SetupSTM32CubeMX-6.15.0

在新彈出的介面一直點下一步就行,安裝結束後出現如下圖就成功了。

/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX進入這個資料夾,然後開啟終端輸入

./STM32CubeMX

點選Help

Manage embedded software packages,把STM32F1,F4,H7的第一個最新的韌體勾上。

點install

登陸上賬號

然後等下載和安裝完

下載好就行了。

接下來可以把CubeMX應用配置一個桌面快捷方式等可以快速開啟,教程詳見Vinci機器人隊Linux入門教程的Appimage章節,可以用ctrl+F快速定位該章節。

桌面快捷方式如下:

[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

根據教程做,就可以實現這種效果啦。

2.3.安裝VScode

https://code.visualstudio.com/Download

如果是debian系下載deb,如果是rhel系下載rpm.

下載完之後,點選瀏覽器,找到這個安裝包的資料夾,並在該路徑開啟終端。

Debian系:輸入sudo apt install ./code然後按tab按鍵補齊檔名,回車。

RHEL系:輸入sudo dnf install ./code然後按tab按鍵補齊檔名,回車。

例如補齊後的:

sudo dnf install ./code-1.102.1-1752598767.el8.x86_64.rpm

然後開啟VScode,在終端輸入下面的命令

code

然後安裝一些外掛

下面這些都要裝

2.4.安裝ARM GNU工具鏈

編譯工具比較:

特性 ARM GCC (GNU 工具鏈) Keil AC5 (ARM Compiler 5) Keil AC6 (ARM Compiler 6)
核心身份 基於GNU GPL的開源編譯器 ARM自家的傳統編譯器 基於LLVM/Clang的現代編譯器
許可模式 免費、開源 商業收費(包含在MDK中) 商業收費(包含在MDK中)
程式碼生成/最佳化 良好,持續改進 優秀(尤其在小程式碼尺寸上) 極佳,在效能與尺寸間有最佳平衡
標準相容性 緊跟最新C/C++標準(如C17,C++17/20) 主要支援C++98,較陳舊 支援現代C++(C++11/14/17),相容性更好
錯誤/警告資訊 比較清晰易懂 相對晦澀 非常清晰和友好,類似GCC/Clang
與Keil MDK整合 需要手動配置或通過CubeIDE 原生、無縫整合 原生、無縫整合,是ARM推薦選擇
連結指令碼 使用自有的連結指令碼語法(.ld檔案) 使用ARM自家的分散載入檔案語法(.sct) 使用ARM自家的分散載入檔案語法(.sct)
彙編語法 使用GNU彙編語法(.S檔案) 使用ARM彙編語法(.s) 使用ARM彙編語法(.s),但AC6更嚴格
生態與未來 生態強大,是很多開源專案(如Zephyr,ESP-IDF)和IDE(CubeIDE,VS Code)的首選 處於維護模式,ARM不再增加新功能,不推薦新專案使用 是ARM的未來和主力,持續更新和最佳化

2.4.1.安裝

建議都用官方法進行安裝。

2.4.1.1.方法一(官網法)

https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

進入下載目錄並開啟終端

在終端裡輸入下列命令,將編譯器檔案tar壓縮包複製到你存放程式的資料夾(這個資料夾你自己定,建議在home分割槽,別以後刪了就行)。

具體命令為cp ./arm-gnu然後按tab補齊,然後空格,再跟上你要複製到的資料夾的路徑。

比如下面的命令:

cp ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz ~/UserFolder/Applications/

然後進入複製到的資料夾:

cd ~/UserFolder/Applications/

在終端裡輸入tar -xvf ./arm-gnu並按tab補齊。

例如我補齊後的:

 tar -xvf ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz

再進入這個解壓後的資料夾

cd ./arm-gnutab補齊。

cd ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/
cd ./bin

檢視資料夾路徑

pwd

複製一下/home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin

然後需要配置環境

vim ~/.bashrc

在末尾輸入下面的命令,把下面~/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin替換成你剛才複製的路徑,/home/用户名可以用~來代替。

export PATH=/home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin:$PATH

載入環境

source ~/.bashrc
2.4.1.2.方法二(系統倉庫法)

不建議本法


# Debian系
sudo apt install arm-none-eabi-gcc

# Rhel系
sudo dnf install arm-none-eabi-gcc

2.4.2.測試

檢查版本

arm-none-eabi-gcc -v

2.5.安裝JLink驅動

2.5.1.安裝libreadline庫

我們燒錄會用到JLinkExe的命令,而JLinkExe會用到libreadline庫,所以要安裝libreadline庫,執行如下命令安裝:


# debian系
sudo apt-get install libreadline-dev

# rhel系
sudo dnf install readline-devel

2.5.2.安裝JLink驅動

https://www.segger.com/downloads/jlink/

是Debian系下載64位DEB

是RHEL系下載64位RPM

(這裡的64位指的是amd64和X86_64,如果你是ARM64請下載下方那個Linux ARM裡的64位)

開啟下載到的資料夾,並開啟終端

然後sudo apt install ./JLink然後tab補齊。

然後sudo dnf install ./JLink然後tab補齊。

sudo dnf install ./JLink_Linux_V852_x86_64.rpm

檢查是否安裝成功

JLinkExe

我們點選No,然後會進入Commander互動模式,在這種模式下,我們可以執行各種 J-Link Commander 提供的命令來連線、配置偵錯程式,下載程式或檔案到目標裝置等操作,感興趣的同學可自行學習。

執行“q”指令退出該模式。

2.5.3.下載並安裝Ozone

https://www.segger.com/products/development-tools/ozone-j-link-debugger/

是Debian系下載64位DEB

是RHEL系下載64位RPM

(這裡的64位指的是amd64和X86_64,如果你是ARM64請下載下方那個Linux ARM裡的64位)

然後sudo apt install ./Ozone然後tab補齊。

然後sudo dnf install ./Ozone然後tab補齊。

sudo dnf install ./Ozone_Linux_V338g_x86_64.rpm

2.5.4.測試

開啟終端輸入

ozone

2.6.下載SVD

https://www.st.com.cn/content/st_com/zh.html

在搜尋裡搜尋晶片型號,如stm32f103c8t6

點CAD資源

下載SVD,滑鼠點紅色框的區域就可以下載了

解壓後就可以獲得F1系列的SVD檔案了

依次把F4和H7的也下載解壓了就可以了。(可以解壓到一個資料夾裡)

然後在上面的資料夾開啟終端

將這些資料夾全部複製到Ozone的Config/Peripherals/目錄下。(你需要提前確定一下ozone的配置是否是這個路徑再複製)

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

3.工程建立與測試

3.1.使用CubeMX建立工程

點選進入微控制器挑選的按鈕

搜尋對應晶片,並雙擊對應晶片選項。

進行一些配置,以下都是很基礎的東西,你在看這個影片前肯定都會了

隨便開一個IO用來測試,比如LED的GPIO

FreeRTOS也要配置一下。

這些資料夾也要配置好,最後Toolchain選擇CMake,編譯器選擇GCC(6.14.1及之前沒有選擇編譯器這個選項很正常)

(但是CubeMX6.15.0有bug,這個選擇GCC編譯器並沒有用,還需要後續自己手動選擇編譯器,以後可能會修復這個bug.)

3.2.對工程進行配置與編譯

在工程資料夾開啟終端

然後開啟vscode

code .

進入vscode後,點選目錄下的CMakeLists.txt

檢查第25行左右是否有下面這行,如果沒有,你需要手動給他加上這兩行。(6.14.1版本沒有這個bug)

tips1:這就是上面說的CubeMX6.15.0版本的bug,因為這個版本增加了對clang編譯器的支援,在CubeMX裡也支援了選擇編譯器的操作,但是這個選項估計是工程師沒寫好,選擇編譯器不管選哪個,他都不會選擇咱們選擇的編譯器,所以咱們需要手動選擇。

tips2:這CubeMX6.15.0有第二個bug,這個工作區根CMakeLists.txt他說了只會生成一次,後續不會再重新覆蓋生成,但是發現每次在CubeMX修改配置後,然後重新生成程式碼,其他命令都被保留了,就這個命令不會被保留。不知道後續會不會被修復,或者直接修復上面tips1的bug.所以每次重新配置CubeMX後,需要再把這句加上。


# Include toolchain file
include("cmake/gcc-arm-none-eabi.cmake")

按ctrl+~開啟內建終端。

使用下方命令建立並進入build資料夾

mkdir build
cd build

接下來使用cmake命令生成makefile檔案

cmake ..

檢查一下是否ARM的C/C++以及彙編編譯器都被找到了(如果沒有,請檢查上面的教程是否有做錯的地方)

然後使用make命令進行編譯,命令為make或者make -jxx,這裡的xx是你想使用CPU的幾個執行緒來進行編譯,比如我電腦是8核16執行緒,我就可以讓xx是比16低的數字。而make是預設用一個執行緒。如果你並不知道你CPU有幾個執行緒,那你就老老實實用make命令,別用make -jxx命令了。

make -j16

這樣就是編譯成功了。

3.3.對程式碼提示進行配置

在VScode中按Ctrl+Shift+P,搜尋clangd,並選擇下載語言服務

在右下角選擇安裝即可,安裝完就會出現下圖提示。

接著停用C/C++外掛的程式碼提示功能(如果沒這個介面,請往下看)

如果沒有上圖的彈窗,可以進行手動關閉,依然是ctrl shift P,輸入settings然後找到如下圖的選項

找到下圖這個選項,改成disabled即可。

"C_Cpp.intelliSenseEngine": "disabled"

在VScode中再按Ctrl+Shift+P,搜尋clangd,並選擇重啟clangd語言服務(重啟clangd語言服務之前必須編譯過一遍程式碼了)

此時,可以看程式碼裡標頭檔案都正常識別了,程式碼提示也正常了。

⚠️注意:Clangd 預設找的是 本機系統的 libc/include 路徑(比如 x86_64 的 /usr/include ,而我們工程裡面實際使用的是 ARM 工具鏈的標頭檔案路徑 ,這就有機率導致包含C/C++庫函式的標頭檔案報錯

例如:

這裡的 #include <math.h>顯示找不到標頭檔案,但是我們進行編譯的時候卻沒有報錯,說明是clangd的配置有問題 。以下介紹一種解決方法:

  1. 執行以下命令,獲取 ARM GCC 使用的標準 include 路徑:
arm-none-eabi-gcc -x c -E -v - </dev/null

  1. 在工程根目錄下面建立 .clangd 檔案 將自己的標頭檔案路徑包含進去(引號裡面替換成你自己的arm gcc標頭檔案路徑)
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"
  ]

儲存,此時重新整理一下clangd,標頭檔案提示正常

3.4.移植Vinci機器人隊標準C/C++工程模板

用git clone命令克隆倉庫:https://github.com/tungchiahui/CubeMX_MDK5to6_Template

git clone https://github.com/tungchiahui/CubeMX_MDK5to6_Template.git

把倉庫裡的“工程檔案移植”資料夾裡的 所有內容 複製到我們CMake工程的目錄裡。

然後開啟applications資料夾,在Src和Inc資料夾分別建立led_task.cpp和led_task.h,內容分別如下:

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

然後開啟cmake/user資料夾下的CMakeLists.txt,把剛才新建的led_task.cpp新增上去。

詳細介紹(可以不看):這裡的cmake/stm32cubemx下的CMakeLists.txt是被CubeMX管理的,你重新用CubeMX生成新程式碼後,這個檔案裡的東西會被覆蓋。而工作區根目錄下的CMakeLists.txt是不會被重新覆蓋的,而且給我們留了一些區域加原始檔和標頭檔案,但是這樣會讓這個檔案太過於嘈雜。所以我們選擇新建一個user資料夾,然後在這裡面弄一個CMakeLists.txt,再用頂層CMakeLists.txt去載入這個子CMakeLists.txt,這個子CMakeLists.txt方便咱們修改,檔案結構也更加明顯。(這些都不需要咱們自己建立,我已經給建立到 工程檔案移植 裡了,你在上面複製的時候已經複製過來了)

然後要去最頂層的CMakeLists.txt里加上這句話來引用我們自己的CMakeLists.txt。


# Add USER generated sources
add_subdirectory(cmake/user)

大功告成,編譯一次試試。可以看到下圖,那些新加的檔案都編譯上了。

cmake ..
make

然後去main.c中引用cpp_interface.h標頭檔案,並將cpp_main()函式在main函式的這個地方呼叫。(我這裡是開RTOS了,所以需要在啟動RTOS之前呼叫cpp_main函式,如果你是沒有用RTOS的裸機程式,則在while (1)的上方呼叫cpp_main即可)

然後在cpp_interface.h裡修改isRTOS這個宏來讓程式知道你是否開啟了RTOS,如果開啟了,宏就為1,裸機就填0。

其他更加詳細的關於STM32的C/C++工程介紹請看Vinci機器人隊微控制器教程

此時在build資料夾下進行編譯程式,發現成功!

cmake ..
make

3.5.下載程式到板子

3.5.1.配置CMake生成.bin和.hex檔案

在下載程式到板子之前,我們需要去看看咱們之前編譯的到底生成了啥檔案。

通過下圖可知,他只生成了.elf檔案,並沒有咱們常見的.bin和.hex檔案。

咱們需要再更改一下工作區下的CMakeLists.txt從而來讓編譯的時候生成.hex和.bin(沒辦法,就得這麼麻煩,我也不知道為啥CubeMX不給全乾好)


# 生成 .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"
)

這些需要在工作區主CMakeLists.txt裡新增的命令我全都寫在這個記事本里了,每次生成新工程直接複製即可。

然後再次編譯

cmake ..
make

此時再看build目錄:咱們需要的.hex或者.bin就出來了

3.5.2.將裝置連線到JLink並燒錄程式
3.5.2.1.圖形介面燒錄
#打开终端输入
JFlashLite

選擇對應的晶片型號和速度

新增hex檔案

點選燒錄並完成:

成功點亮led:

3.5.2.2.終端燒錄

算鳥算鳥,太麻煩了。

3.6.配置VScode任務

咱們在上面編譯,一直需要輸入以下命令

cd build
cmake ..
make

這樣每次編譯過於麻煩了,所以我們使用強大的VScode來一鍵編譯。

首先建立.vscode資料夾和tasks.json檔案

以下是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": []    //不需要问题匹配器
        }

    ]
}

方法一:

在VScode標題欄上,找到终端,然後再選擇运行构建任务,快捷鍵是Ctrl+Shift+B

可見任務已經被運行了。

方法二:

在VScode標題欄上,找到终端,然後再選擇运行任务

下面有4個stm32的任務,第一個是stm32-Build任務,執行後的效果和剛才方法一是一樣的,方法一的那個运行构建任务的按鈕,就是執行的這個stm32-Build任務。

這個stm32-Build任務包含stm32-cmake和stm32-make任務。

然後stm32-clean任務就是清除build資料夾下的所有檔案。

可以試一下stm32-clean任務。

可以發現都刪完了。

你不用擔心每次新建工程都需要配置那麼多東西。

以上大多數配置檔案全部都已經包含在https://github.com/tungchiahui/CubeMX_MDK5to6_Template仓库下的***`工程文件移植(建立新模板請看這裡)`***資料夾了,到時候新建一個工程後,直接把這個資料夾下的所有檔案全部複製過來即可。

3.7.使用ozone進行Flash燒錄和Debug除錯

3.7.1.基礎配置

開啟終端輸入ozone開啟軟體或者直接找到應用圖示開啟ozone

先選擇device,比如我是STM32F407VET6

選擇Peripherals:

點選下一步

你用的SWD就填SWD,是JTAG就填JTAG

選擇ELF

elf,hex,bin都可以選,一般選elf就行。

這一步保持預設即可。

如果你開啟了RTOS可能會遇到這個問題。

warning (138): The target application seems to be using FreeRTOS, but FreeRTOS-awareness is not enabled.

意思是你的目標應用似乎使用了 FreeRTOS,但當前沒有啟用對 FreeRTOS 的除錯支援(RTOS-awareness)。

直接按照他底下的提示應用修復即可。

點繼續就行。

3.7.2.燒錄與除錯

可以看下面這個影片,講的挺好的。(從30:10開始看)

https://www.bilibili.com/video/BV1yrLHzZEoE

點選File讓他按檔名排序。

找到led_task.cpp點選就可以開啟這個原始檔啦。