項目在做什么
- 本項目是為了研究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
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 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文件編寫時會互相調用,顯得不整潔