zoukankan      html  css  js  c++  java
  • linux 下 VSCODE 使用CMake编译STM32程序

    项目在做什么

    项目地址

    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 world
    ",sizeof("hello world
    "));
            DelayMs(5000);
        }
    }
    

    这个程序就是将硬件初始化,然后5s打印一次"Hello World "

    也就是说这个程序主要分为三个部分:

    • 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文件编写时会互相调用,显得不整洁

    感谢大家,有问题欢迎大家指正

  • 相关阅读:
    第七次作业
    rfid工作原理
    实验九——基本数据类型存储及应用总结
    实验八——函数定义及调用总结
    实验七——函数定义及调用总结
    作业
    作业
    作业
    开始
    实验12——指针的基础应用2
  • 原文地址:https://www.cnblogs.com/answerinthewind/p/11401756.html
Copyright © 2011-2022 走看看