linux 下 VSCODE 使用CMake編譯STM32程式

  • 2019 年 10 月 3 日
  • 筆記

項目在做什麼

項目地址

  1. 本項目是為了研究MCU在linux下開發而做的
--build 存放cmake編譯生成的文件  --cmake 存放cmake編譯時會用到的文件,比如工具鏈檢查、編譯選項等  --prj windows下kei工程的工程文件  --src 源碼
  1. 本項目中大量的CMakeLists.txt的寫法參考了LoRa-Node

目前項目已經初步能夠運行了

使用的組件

  1. VSCODE -> 程式設計師使用的文本編輯器
  2. cmake -> 組織編譯邏輯
  3. arm-none-eabi –> 編譯,生成elf,bin,hex
  4. JLinkGDBServer -> GDB 伺服器
  5. 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 causing the linker to fail. 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 worldrn",sizeof("hello worldrn"));          DelayMs(5000);      }  }

這個程式就是將硬體初始化,然後5s列印一次"Hello Worldrn"

也就是說這個程式主要分為三個部分:

  • 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

  1. 編譯需要指定.c文件,編譯.c文件時由於多函數跨文件調用是通過頭文件進行的,所以需要找尋頭文件,當頭文件找不到時就無法調用指定函數

  2. 將.c文件添加到指定target的方法,我這裡用了兩種,兩種方式都可以達到一樣的效果

    1. 一個個添加

      list(APPEND ${PROJECT_NAME}_SOURCES      "${CMAKE_CURRENT_SOURCE_DIR}/main.c"  )
    2. 添加指定文件夾下的所有c文件

      file(GLOB ${PROJECT_NAME}_SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.c")
  3. 將頭文件路徑添加倒target路徑,是通過cmake的target_include_directories()方法,其中,我們可以通過${CMAKE_CURRENT_SOURCE_DIR},直接添加目錄,但有時候,我們需要添加別的target的頭文件,此時可以用表達式去獲取target的頭文件,比如

    1. $<TARGET_PROPERTY:drivers,INTERFACE_INCLUDE_DIRECTORIES>

    通過這個表達式可以獲取到在drivers這個target中添加的頭文件

  4. CMake的用法還有很多,太靈活了,我這寫的也只是冰山一角,後面還要繼續努力

### 幹活

編譯程式

  1. 在項目的根目錄建立CMakeLists.txt,將apps,boards.driver,boards.stm32三個subdirectory分別導入,並在這三個文件夾中寫好分別的CMakeLists.txt

  2. 我們分別將三個target命名為

    • app –>project(app)
    • drivers –>project(drivers)
    • stm32l051 –>project(stm32l051)
  3. 並在其中添加好各自target的.c文件和頭文件,具體見源碼

  4. ok之後,CMake文件就編寫完了

  5. 我們需要執行

    • 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
  6. 執行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
  7. 至此,程式編譯完成

配置VSCODE

  • 配置launch.json (應以調試)
  • 配置c_cpp_properties.json(用於編寫,閱讀程式碼)

此處我使用的是JLinkGDBServer,是因為之前使用openocd進行調試時總是出現問題,而用JLinkGDBServer則沒發現什麼問題

launch.json

不講了,自己看配置文件吧

c_cpp_properties.json

之前沒有仔細配置時,總是在程式碼編輯器的右邊出現紅色的錯誤提示,很是難受,配完之後,這些錯誤提示都消失了,就舒服了。

下面我講一下其中重的部分:

  1. includePath,這個下面一定要靶所有的頭文件的路徑都包含進去,不然找不到頭文件,就會出現波浪線的錯誤提示了,可以使用**的用法,來將目錄下的所有文件都導入

                "includePath": [                  "${workspaceFolder}/src/**",                  "/home/jk/cross-tool/gcc-arm-none-eabi-8-2019-q3-update/arm-none-eabi/include/**"              ],
  2. defines,需要把程式中使用的宏添加到此處,否則編輯器對預編譯宏做的程式碼開關也是沒法正確識別,例如:

                "defines": [                  "STM32L051xx",                  "USE_HAL_DRIVER"              ],
  3. compilerPath,這個填寫正確的gcc路徑,否則也是有奇奇怪怪的錯誤

最後的注意事項

  1. 當CMake config/generate失敗的時候,可以嘗試將build文件夾刪除,重新進行,可能會成功
  2. 因為此處我是通過傳遞工具鏈文件的方式來傳遞工具鏈給CMake的,指令有些長,且難記,為了方便,我將指令做成了config文件,在${ROOT}下有個config文件,這樣,後面只要執行./config就可以生成Makefile文件了
  3. 程式碼結構要清晰,要盡量接耦,否則CMakeLists.txt文件編寫時會互相調用,顯得不整潔

感謝大家,有問題歡迎大家指正