linux 下 VSCODE 使用CMake編譯STM32程式
專案在做什麼
專案地址
- 本專案是為了研究MCU在linux下開發而做的
--build 存放cmake編譯生成的檔案
--cmake 存放cmake編譯時會用到的檔案,比如工具鏈檢查、編譯選項等
--prj windows下kei工程的工程檔案
--src 原始碼
- 本專案中大量的CMakeLists.txt的寫法參考了LoRa-Node
目前專案已經初步能夠運行了
使用的元件
- VSCODE -> 程式設計師使用的文字編輯器
- cmake -> 組織編譯邏輯
- arm-none-eabi --> 編譯,生成elf,bin,hex
- JLinkGDBServer -> GDB 伺服器
- cortex-debug -> 用來除錯程式
我的環境
jk@jk:~$ sudo lsb_release -a
[sudo] jk 的密碼:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.2 LTS
Release: 18.04
Codename: bionic
至此,需要的元件就羅列清除了,下面來講下怎麼安裝
元件安裝
VSCODE
官網瞎下載安裝即可,每什麼可講的,記得安裝最新版
CMake(需要>3.6)
jk@jk:~$ cmake -version cmake version 3.10.2 CMake suite maintained and supported by Kitware (kitware.com/cmake).
安裝方法:
- Ubuntu 16.04/ Linux Mint 18: Since the official repository version is too old, one can use e.g. PPA
- Linux Arch:
pacman -S cmake
arm-none-eabi
- GNU ARM-Toolchain
- GNU/Linux:
- Ubuntu 16.04/ Linux Mint 18: Since the official repository version is too old, one can use e.g. PPA
- Ubuntu 18.04: the toolchain has been updated but there is a bug with
libnewlib
sudo apt install gcc-arm-none-eabi
- Linux Arch:
pacman -S arm-none-eabi-gcc arm-none-eabi-newlib
JLinkGDBServer
jk@jk:~$ JLinkGDBServer -version
SEGGER J-Link GDB Server V6.48b Command Line Version
JLinkARM.dll V6.48b (DLL compiled Aug 2 2019 10:20:19)
去官網下載:JLinkGDBServer
我下載的是deb格式,使用dpkg -i安裝即可
cortex-debug
VSCODE 裡面搜尋cortex-debug 安裝即可
至此,安裝就完成了
思路
首先,我們來看main函式
/**
* Main application entry point.
*/
int main( void )
{
board_init();
uart1.rx_complete_callback = uartCallback;
while(1)
{
HAL_UART_SendBytes((uint8_t*)"hello world\r\n",sizeof("hello world\r\n"));
DelayMs(5000);
}
}
這個程式就是將硬體初始化,然後5s列印一次"Hello World\r\n"
也就是說這個程式主要分為三個部分:
- main
- 驅動
- MCU HAL 庫
我們來看一下原始碼結構,也可以得出結論
jk@jk:~/programe/stm32-linux-cmake$ tree -d -L 2 src
src
├── apps
└── boards
├── driver
└── stm32
其中:
apps中存放的就是main.c檔案
boards中存放的是硬體部分
boards.driver存放的是硬體的驅動
boards.stm32中存放的就是stm32的HAL庫的程式碼
所以,我的思路是:
- app/boards.driver/boards.stm32這三部分分別生成三個target,最後由這三個target生成exe
實現
AS WE KNOWN
編譯需要指定.c檔案,編譯.c檔案時由於多函式跨檔案呼叫是通過標頭檔案進行的,所以需要找尋標頭檔案,當頭檔案找不到時就無法呼叫指定函式
將.c檔案新增到指定target的方法,我這裡用了兩種,兩種方式都可以達到一樣的效果
一個個新增
list(APPEND ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c" )
新增指定資料夾下的所有c檔案
file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.c")
將標頭檔案路徑新增倒target路徑,是通過cmake的target_include_directories()方法,其中,我們可以通過${CMAKE_CURRENT_SOURCE_DIR},直接新增目錄,但有時候,我們需要新增別的target的標頭檔案,此時可以用表示式去獲取target的標頭檔案,比如
1. $<TARGET_PROPERTY:drivers,INTERFACE_INCLUDE_DIRECTORIES>
通過這個表示式可以獲取到在drivers這個target中新增的標頭檔案
CMake的用法還有很多,太靈活了,我這寫的也只是冰山一角,後面還要繼續努力
### 幹活
編譯程式
在專案的根目錄建立CMakeLists.txt,將apps,boards.driver,boards.stm32三個subdirectory分別匯入,並在這三個資料夾中寫好分別的CMakeLists.txt
我們分別將三個target命名為
- app -->project(app)
- drivers -->project(drivers)
- stm32l051 -->project(stm32l051)
並在其中新增好各自target的.c檔案和標頭檔案,具體見原始碼
ok之後,CMake檔案就編寫完了
我們需要執行
- mkdir build
- cd build
- cmake -DCMAKE_TOOLCHAIN_FILE="cmake/toolchain-arm-none-eabi.cmake" ..
PS:
- 在根目錄生成build資料夾,這是為了方便我們管理,後續如果要刪除編譯的產物,直接刪除build資料夾即可,也可以防止編譯的產物汙染程式碼
- Makefile生成成功提示如下:
jk@jk:~/programe/stm32-linux-cmake$ ./configure -- The C compiler identification is GNU 8.3.1 -- The CXX compiler identification is GNU 8.3.1 -- Check for working C compiler: /home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gcc -- Check for working C compiler: /home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-g++ -- Check for working CXX compiler: /home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-g++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done Linker script: /home/jk/programe/stm32-linux-cmake/src/boards/stm32/cmsis/arm-gcc/stm32l051xx_flash.ld -- The ASM compiler identification is GNU -- Found assembler: /home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gcc -- Configuring done -- Generating done -- Build files have been written to: /home/jk/programe/stm32-linux-cmake/build
執行make,編譯程式
jk@jk:~/programe/stm32-linux-cmake/build$ make Scanning dependencies of target app [ 3%] Building C object src/apps/CMakeFiles/app.dir/main.c.obj [ 3%] Built target app Scanning dependencies of target stm32l051 [ 6%] Building ASM object src/boards/stm32/CMakeFiles/stm32l051.dir/cmsis/arm-gcc/startup_stm32l051xx.s.obj [ 9%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/cmsis/system_stm32l0xx.c.obj [ 12%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal.c.obj [ 16%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_adc.c.obj [ 19%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_adc_ex.c.obj [ 22%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_cortex.c.obj [ 25%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_dma.c.obj [ 29%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash.c.obj [ 32%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_flash_ex.c.obj [ 35%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_gpio.c.obj [ 38%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_i2c.c.obj [ 41%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_pwr.c.obj [ 45%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_pwr_ex.c.obj [ 48%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rcc.c.obj [ 51%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rcc_ex.c.obj [ 54%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rtc.c.obj [ 58%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_rtc_ex.c.obj [ 61%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_spi.c.obj [ 64%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_uart.c.obj [ 67%] Building C object src/boards/stm32/CMakeFiles/stm32l051.dir/mcu/stm32/STM32L0xx_HAL_Driver/Src/stm32l0xx_hal_uart_ex.c.obj [ 67%] Built target stm32l051 Scanning dependencies of target drivers [ 70%] Building C object src/boards/driver/CMakeFiles/drivers.dir/board.c.obj [ 74%] Building C object src/boards/driver/CMakeFiles/drivers.dir/delay.c.obj [ 77%] Building C object src/boards/driver/CMakeFiles/drivers.dir/gpio-board.c.obj [ 80%] Building C object src/boards/driver/CMakeFiles/drivers.dir/gpio.c.obj [ 83%] Building C object src/boards/driver/CMakeFiles/drivers.dir/key_board.c.obj [ 87%] Building C object src/boards/driver/CMakeFiles/drivers.dir/led_board.c.obj [ 90%] Building C object src/boards/driver/CMakeFiles/drivers.dir/stm32l0xx_hal_msp.c.obj [ 93%] Building C object src/boards/driver/CMakeFiles/drivers.dir/stm32l0xx_it.c.obj [ 96%] Building C object src/boards/driver/CMakeFiles/drivers.dir/uart_board.c.obj [ 96%] Built target drivers Scanning dependencies of target arm_minisys [100%] Linking C executable arm_minisys text data bss dec hex filename 14988 12 400 15400 3c28 arm_minisys [100%] Built target arm_minisys Scanning dependencies of target arm_minisys.hex [100%] Built target arm_minisys.hex Scanning dependencies of target arm_minisys.bin [100%] Built target arm_minisys.bin
至此,程式編譯完成
配置VSCODE
- 配置launch.json (應以除錯)
- 配置c_cpp_properties.json(用於編寫,閱讀程式碼)
此處我使用的是JLinkGDBServer,是因為之前使用openocd進行除錯時總是出現問題,而用JLinkGDBServer則沒發現什麼問題
launch.json
不講了,自己看配置檔案吧
c_cpp_properties.json
之前沒有仔細配置時,總是在程式碼編輯器的右邊出現紅色的錯誤提示,很是難受,配完之後,這些錯誤提示都消失了,就舒服了。
下面我講一下其中重的部分:
includePath,這個下面一定要靶所有的標頭檔案的路徑都包含進去,不然找不到標頭檔案,就會出現波浪線的錯誤提示了,可以使用**的用法,來將目錄下的所有檔案都匯入
"includePath": [ "${workspaceFolder}/src/**", "/home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/arm-none-eabi/include/**" ],
defines,需要把程式中使用的巨集新增到此處,否則編輯器對預編譯巨集做的程式碼開關也是沒法正確識別,例如:
"defines": [ "STM32L051xx", "USE_HAL_DRIVER" ],
compilerPath,這個填寫正確的gcc路徑,否則也是有奇奇怪怪的錯誤
最後的注意事項
- 當CMake config/generate失敗的時候,可以嘗試將build資料夾刪除,重新進行,可能會成功
- 因為此處我是通過傳遞工具鏈檔案的方式來傳遞工具鏈給CMake的,指令有些長,且難記,為了方便,我將指令做成了config檔案,在${ROOT}下有個config檔案,這樣,後面只要執行./config就可以生成Makefile檔案了
- 程式碼結構要清晰,要儘量接耦,否則CMakeLists.txt檔案編寫時會互相呼叫,顯得不整潔