转载自外网,原文链接:https://www.nrbtech.io/blog/2020/1/4/using-cmake-for-nordic-nrf52-projects
CMake 是一款流行的 C/C++ 构建系统(根据其官网描述,它是一个“开源的、跨平台的工具家族,旨在构建、测试和打包软件”),我们在 NRB Tech 将其用于固件项目和跨平台库。CMake 也可与优秀的 C/C++ 集成开发环境(IDE)CLion 配合使用。Nordic 官方推荐并支持 Segger Embedded Studio 作为其首选 IDE,然而 CMake 能使依赖管理和单元测试变得更为简便。
例如,NRB Tech 常用的一种开发架构是:在固件、实用工具和应用程序之间共享一个或多个 C 语言库,以减少代码重复和错误,并确保关键代码得到充分的单元测试。使用 CMake 可以轻松管理此类库,根据需要生成 Makefile 或 Xcode 项目,并将其作为依赖项集成到其他 CMake 项目中。
Nordic 在其 SDK 中并未直接提供对 CMake 的支持,但它们的 Mesh SDK 使用了 CMake,这就让基于 Nordic SDK 的非 Mesh 项目使用CMake成为可能。
nRF5 CMake 脚本
Nordic的Mesh SDK并非为构建外部的、自定义的非Mesh项目而设计,但通过一些外部支持,它可以用于此目的——这正是我们的 nRF5-cmake-scripts 项目所实现的:尽可能复用Mesh SDK的脚本,同时为其他所有功能定义自己的函数,包括添加Nordic Mesh SDK不具备的特性(例如添加引导加载程序目标和创建DFU软件包)。该项目还定义了可轻松集成Nordic SDK中众多库的函数。现在让我们尝试从头开始创建一个新项目。
环境搭建
- 下载并安装 J-Link Software and Documentation Pack
- 下载并安装 Nordic command line tools
- 下载并安装 ARM GNU Toolchain
如果你使用的是Mac系统,你可以使用homebrew:
brew tap ArmMbed/homebrew-formulaebrew install arm-none-eabi-gcc创建基于CMake的Nordic固件项目
最终的项目可在 此处查看。
首先,在终端/命令窗口中克隆 基础项目 以设置项目结构:
git clone --recurse-submodules https://github.com/NRB-Tech/nRF5-cmake-scripts-example-base.git .运行一个脚本来清理项目,以便您自己使用(在Windows上,通过右键单击目录 > “Git Bash here”来在Git Bash中运行):
# 确保文件有可执行权限chmod +x ./cleanup.sh./cleanup.sh执行下面命令,它会拷贝示例项目中的CMakeLists.txt到当前目录:
cmake -E copy nRF5-cmake-scripts/example/CMakeLists.txt .请注意:您可能还需要根据您的平台编辑此文件中的某些变量,假如 NRFJPROG、MERGEHEX、NRFUTIL 和 PATCH_EXECUTABLE 这些工具未配置在系统的 PATH 环境变量中,则需要手动指定它们的完整路径。
然后我们可以用脚本来下载依赖:
cmake -B cmake-build-download -G "Unix Makefiles" .# Windows上使用:# cmake -B cmake-build-download -G "MinGW Makefiles" .cmake --build cmake-build-download/ --target download从 SDK 示例项目中复制一些文件(对于 nRF52840 DK 开发板,请将 pca10040/s132 替换为 pca10056/s140):
cmake -E copy toolchains/nRF5/nRF5_SDK_16.0.0_98a08e2/examples/ble_peripheral/ble_app_template/pca10040/s132/armgcc/ble_app_template_gcc_nrf52.ld src/gcc_nrf52.ldcmake -E copy toolchains/nRF5/nRF5_SDK_16.0.0_98a08e2/examples/ble_peripheral/ble_app_template/pca10040/s132/config/sdk_config.h src/此时,您可以在 CLion 或您选择的任意编辑器中打开项目并进行文件编辑、添加文件并编写源代码。
这里我们在 src/main.c 中添加一段简单的日志输出代码:
#include "nrf_log_default_backends.h"#include "nrf_log.h"#include "nrf_log_ctrl.h"
int main(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
NRF_LOG_INFO("Hello world"); while(true) { // do nothing }}创建一个 src/app_config.h 文件,用于覆盖 sdk_config.h 中的部分默认配置:
#define NRF_LOG_BACKEND_RTT_ENABLED 1 // 开启RTT#define NRF_LOG_BACKEND_UART_ENABLED 0 // 关闭UART#define NRF_LOG_DEFERRED 0 // 立即刷新日志#define NRF_LOG_ALLOW_OVERFLOW 0 // 不打印溢出日志#define SEGGER_RTT_CONFIG_DEFAULT_MODE 2 // 阻塞直到处理完成我们还需要集成 DFU 引导加载程序,因此需要生成密钥。请在终端/命令提示符中执行以下操作:
nrfutil keys generate keys/dfu_private.keynrfutil keys display --key pk --format code keys/dfu_private.key --out_file keys/dfu_public_key.c现在我们需要创建 src/CMakeLists.txt 文件来构建我们的目标项目。
set(NRF5_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/gcc_${NRF_FAMILY})
# DFU 配置# 列出之前使用过的softdevice版本,若没有,则使用“FALSE”set(PREVIOUS_SOFTDEVICES FALSE)# 设置DFU密钥位置set(PRIVATE_KEY ${CMAKE_CURRENT_SOURCE_DIR}/../keys/dfu_private.key)set(PUBLIC_KEY ${CMAKE_CURRENT_SOURCE_DIR}/../keys/dfu_public_key.c)# 设置应用验证类型 [NO_VALIDATION|VALIDATE_GENERATED_CRC|VALIDATE_GENERATED_SHA256|VALIDATE_ECDSA_P256_SHA256]set(APP_VALIDATION_TYPE NO_VALIDATION)# 设置SoftDevice验证类型. [NO_VALIDATION|VALIDATE_GENERATED_CRC|VALIDATE_GENERATED_SHA256|VALIDATE_ECDSA_P256_SHA256]set(SD_VALIDATION_TYPE NO_VALIDATION)# 引导加载程序版本(用户定义)set(BOOTLOADER_VERSION 1)# DFU 版本 (固件版本) 字符串set(DFU_VERSION_STRING "${VERSION_STRING}")
# 设置Target名称set(target example)
# 添加此示例所需的库nRF5_addLog()nRF5_addSeggerRTT()nRF5_addAppError()
# include fileslist(APPEND SOURCE_FILES main.c )list(APPEND INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" )
nRF5_addExecutable(${target} "${SOURCE_FILES}" "${INCLUDE_DIRS}" "${NRF5_LINKER_SCRIPT}")
# sdk_config.h 导入 app_config.htarget_compile_definitions(${target} PRIVATE USE_APP_CONFIG)
# 处理BootLoader中的用户预定义变量set(bootloader_vars "")
# add the secure bootloader build targetnRF5_addSecureBootloader(${target} "${PUBLIC_KEY}" "${bootloader_vars}")# add the bootloader merge targetnRF5_addBootloaderMergeTarget(${target} ${DFU_VERSION_STRING} ${PRIVATE_KEY} ${PREVIOUS_SOFTDEVICES} ${APP_VALIDATION_TYPE} ${SD_VALIDATION_TYPE} ${BOOTLOADER_VERSION})# add the bootloader merged flash targetnRF5_addFlashTarget(bl_merge_${target} "${CMAKE_CURRENT_BINARY_DIR}/${target}_bl_merged.hex")# Add the Bootloader + SoftDevice + App package targetnRF5_addDFU_BL_SD_APP_PkgTarget(${target} ${DFU_VERSION_STRING} ${PRIVATE_KEY} ${PREVIOUS_SOFTDEVICES} ${APP_VALIDATION_TYPE} ${SD_VALIDATION_TYPE} ${BOOTLOADER_VERSION})# Add the App package targetnRF5_addDFU_APP_PkgTarget(${target} ${DFU_VERSION_STRING} ${PRIVATE_KEY} ${PREVIOUS_SOFTDEVICES} ${APP_VALIDATION_TYPE})
# print the size of consumed RAM and flash - does not yet work on Windowsif(NOT ${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") nRF5_print_size(${target} ${NRF5_LINKER_SCRIPT} TRUE)endif()至此,我们已经准备好构建并运行示例项目。首先,请运行 JLink 工具以获取 RTT 输出:
cmake -Bcmake-build-debug -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug .# Windows,使用:# cmake -B cmake-build-debug -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE=Debug .# 如果报编译器未找到的错误,请确保环境变量配置正确 (运行 `arm-none-eabi-gcc` 来检查是否已配置正确)cmake --build cmake-build-debug/ --target START_JLINK_RTT接下来,构建并烧录目标固件:
cmake --build cmake-build-debug/ --target flash_bl_merge_example您现在应该能在 RTT 控制台中看到 “Hello world” 日志输出了!至此,您可以通过 nRF5-cmake-scripts/includes/libraries.cmake 文件中提供的宏来添加源代码并集成 SDK 库。
NRB Tech 运用 CMake 构建经过充分测试的产品,并充分利用跨平台代码的优势。如果您正在规划新产品开发,或希望参与多样化的跨平台产品研发,欢迎 与我们联系。
一些关联的项目
你可以将以下代码另存为nrf5-sdk-to-clion.sh,然后放在nRF5 SDK根目录执行。
它会为所有SDK中的实例项目创建好CMakeList.txt文件:
#!/usr/bin/env bash
#Copyright 2017 Jumper Labs Ltd.
#Licensed under the Apache License, Version 2.0 (the "License");#you may not use this file except in compliance with the License.#You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0##Unless required by applicable law or agreed to in writing, software#distributed under the License is distributed on an "AS IS" BASIS,#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.#See the License for the specific language governing permissions and#limitations under the License.
set -e
tmp_makefile="/tmp/CMakeLists-generator.mk"
\cat << 'EOF' > ${tmp_makefile}include Makefile
generate: $(foreach var, PROJECT_NAME SDK_ROOT PROJ_DIR SRC_FILES INC_FOLDERS CFLAGS CXXFLAGS, \ echo "set($(var) $($(var)))" ; \ echo ; \ )
@echo 'cmake_minimum_required(VERSION 2.4.0)' @echo 'project($$$ {PROJECT_NAME})'
@echo 'list(APPEND CFLAGS "-undef" "-D__GNUC__")' @echo 'list(FILTER CFLAGS EXCLUDE REGEX mcpu)' @echo 'string(REPLACE ";" " " CFLAGS "$$$ {CFLAGS}")' @echo 'set(CMAKE_C_FLAGS $$$ {CFLAGS})'
@echo 'include_directories($$$ {INC_FOLDERS})' @echo 'add_executable($$$ {PROJECT_NAME} $$$ {SRC_FILES})'EOF
\echo "cmake_minimum_required(VERSION 2.8.9)" > CMakeLists.txt
for makefile in `\find ./examples -name Makefile` ; do dir=`\dirname ${makefile}` \echo "Creating CMakeLists.txt for ${makefile}" \pushd ${dir} > /dev/null \make -s -f ${tmp_makefile} generate > CMakeLists.txt \popd > /dev/null \echo "#add_subdirectory(${dir})" >> CMakeLists.txtdone\rm ${tmp_makefile}
echo '************************************'echo 'Enjoy using CLION with the NRF5-SDK!'echo '************************************'