1. 前期准备与环境搭建
1.1 工具链版本矩阵
在开始移植之前,需要确保开发环境中的工具版本与LAT1730文档一致,以避免因版本差异引发的兼容性问题。文档中明确列出的工具及版本如下:
| 工具名称 | 版本 | 用途 | 获取方式 |
| STM32CubeIDE for Visual Studio Code | V3.9.0 | VSCode环境下的STM32开发扩展,提供工程配置、编译、调试能力 | VSCode扩展市场搜索安装 |
| STM32CubeProgrammer | V2.22.0 | 提供STM32_Programmer_CLI命令行工具,用于编译后FLASH CRC注入 | ST官网下载安装 |
| STM32CubeMX | 随扩展包配套 | 图形化配置工具,用于创建STM32C5初始工程并生成CMake | ST官网下载安装 |
| X-CUBE-CLASSB-C5 | 扩展包 | 功能安全自检扩展包,包含STL_Lib.a静态库和示例代码 | ST官网或STM32CubeMX包管理器获取 |
特别需要注意的是STM32CubeProgrammer的安装路径。CMake脚本中默认搜索路径为C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin,如果安装时选择了其他路径,后续在修改CMakeLists.txt时需要对应更新STM32_PROGRAMMER_CLI_HINTS变量,或者将bin目录加入系统PATH环境变量。
1.2 硬件平台确认
LAT1730文档中的所有示例和例程均基于STM32C562RE Nucleo开发板。在开始移植前需要确认:
- 开发板型号为STM32C562RE Nucleo,板载芯片为STM32C562RE;
- 开发板通过USB连接到开发主机,ST-LINK调试接口正常识别;
- PA5引脚在该开发板上连接了用户LED,可用于运行状态指示。
如果使用的是其他STM32C5子型号或自定义硬件平台,移植流程基本一致,但需要调整FLASH地址范围参数,并确认LED指示引脚的实际映射。
资料获取:实战经验 | LAT1730 基于VSCode从零开始移植STM32C5的X-CUBE-CLASSB
2. 基础工程创建
2.1 STM32CubeMX工程配置
步骤1:新建STM32C5工程
打开STM32CubeMX,在MCU/MPU选择器中搜索并选择STM32C562RE(或实际使用的STM32C5型号),创建一个新的工程。工程类型选择基础的闪灯(GPIO Toggle)模板,或者从空白工程开始配置。
2.2 PA5 LED引脚与CRC外设激活
步骤2:配置PA5为GPIO输出
在Pinout视图中找到PA5引脚,将其配置为GPIO_Output模式。这个引脚用于驱动板载LED,在程序运行时通过LED闪烁来指示代码执行状态。在后续的自检测试中,LED也可以作为故障指示的输出通道。
步骤3:激活CRC硬件外设
在外设配置中找到CRC(Cyclic Redundancy Check)模块,将其激活。参数保持默认值即可,不需要修改多项式、初始值等配置。CRC硬件外设在运行时FLASH自检阶段会被自检库调用,用于计算Flash内容的CRC校验值。
这里需要强调:CRC外设的激活是必须的。如果跳过这一步,编译可能仍然通过,但运行时FLASH自检将因缺少硬件CRC计算能力而失败。
2.3 CMake工程生成与VSCode打开
步骤4:生成CMake工程
在STM32CubeMX的Project Manager中,设置工程名称和保存路径,Toolchain/IDE选择CMake(或STM32CubeIDE for VSCode对应的生成选项),点击GENERATE CODE生成工程文件。
步骤5:在VSCode中打开工程
启动VSCode,通过File > Open Folder打开生成的工程根目录。确保STM32CubeIDE for Visual Studio Code扩展(V3.9.0)已安装并启用。VSCode会自动识别CMake工程并配置构建环境。
2.4 闪灯验证与硬件连通性确认
步骤6:编译并下载闪灯程序
在添加自检库之前,先编译基础工程。正常情况下,此时的工程应该可以直接编译通过。在main函数中添加PA5引脚翻转的闪灯代码(如果CubeMX生成的模板中尚未包含),编译后下载到开发板。
步骤7:确认LED闪烁
程序运行后,观察开发板上的LED是否正常闪烁。LED闪烁确认了以下事项均正常:硬件连接无误、时钟配置正确、GPIO驱动工作正常、调试下载链路通畅。这一步是后续所有工作的基线——如果连闪灯都跑不起来,说明基础环境存在问题,不应该继续添加自检库。
3. 自检库文件部署
3.1 Middlewares文件夹复制
步骤8:复制Middleware文件夹
从X-CUBE-CLASSB-C5扩展包中找到Middleware文件夹,将其完整复制到目标工程的根目录下。复制完成后,工程根目录下应该出现Middlewares/ST/STM32_Safety_STL/路径,该目录下包含Lib/、Src/、Inc/等子目录。
3.2 工程目录结构规范
复制完成后,自检库相关的关键文件路径如下:
| 文件/目录 | 相对路径 | 说明 |
| 静态库 | Middlewares/ST/STM32_Safety_STL/Lib/STL_Lib.a | 预编译的功能安全自检核心库 |
| 工具函数源文件 | Middlewares/ST/STM32_Safety_STL/Src/stl_util.c | 自检库运行时辅助函数 |
| 用户参数模板 | Middlewares/ST/STM32_Safety_STL/Src/stl_user_param_template.c | 需根据硬件修改的配置参数 |
| 头文件目录 | Middlewares/ST/STM32_Safety_STL/Inc/ | 自检库API声明头文件 |
保持这个目录结构不变很重要,因为后续CMakeLists.txt中的路径变量STM32_SAFETY_STL_DIR就是基于${CMAKE_SOURCE_DIR}/Middlewares/ST/STM32_Safety_STL定义的。如果目录结构发生变化,需要同步修改CMake中的路径变量。
4. CMakeLists.txt完整改造
工程根目录下的CMakeLists.txt是构建系统的核心配置文件。需要在其中添加三段内容,分别对应链接脚本依赖、自检库集成和CRC后处理。以下按照文档给出的顺序逐段说明。
4.1 链接脚本依赖段
步骤9:添加链接脚本自动检测与依赖
在CMakeLists.txt中添加以下代码段。这段代码的作用是自动搜索CMSIS设备目录下的*_flash.ld链接脚本,并将其注册为目标的链接依赖,确保.ld文件修改后自动重新链接。
# Ensure linker script changes trigger re-link
set(CMSIS_DEVICE_DIR "${CMSIS_RTE_FOLDER}/Device/${CMSIS_Dname}")
file(GLOB DEVICE_LD_SCRIPTS "${CMSIS_DEVICE_DIR}/*_flash.ld")
list(LENGTH DEVICE_LD_SCRIPTS DEVICE_LD_COUNT)
if(DEVICE_LD_COUNT EQUAL 1)
list(GET DEVICE_LD_SCRIPTS 0 LINKER_SCRIPT)
set_property(TARGET ${CMAKE_PROJECT_NAME} APPEND PROPERTY
LINK_DEPENDS "${LINKER_SCRIPT}")
elseif(DEVICE_LD_COUNT GREATER 1)
message(WARNING "Multiple linker scripts found in
${CMSIS_DEVICE_DIR}; select one explicitly.")
else()
message(WARNING "No linker script found in ${CMSIS_DEVICE_DIR};
relying on DFP fallback/template.")
endif()
4.2 库路径与源文件段
步骤10:定义自检库目标并挂载源文件
添加以下代码段,定义自检库的目录变量、创建IMPORTED静态库目标、挂载两个辅助源文件、添加头文件路径,并将库链接到主目标。
set(STM32_SAFETY_STL_DIR
${CMAKE_SOURCE_DIR}/Middlewares/ST/STM32_Safety_STL)
set(STM32_SAFETY_STL_LIB
${STM32_SAFETY_STL_DIR}/Lib/STL_Lib.a)
add_library(STM32_Safety_STL STATIC IMPORTED GLOBAL)
set_target_properties(STM32_Safety_STL PROPERTIES
IMPORTED_LOCATION ${STM32_SAFETY_STL_LIB})
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
${STM32_SAFETY_STL_DIR}/Src/stl_util.c
${STM32_SAFETY_STL_DIR}/Src/stl_user_param_template.c
)
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
${STM32_SAFETY_STL_DIR}/Inc
)
target_link_libraries(${CMAKE_PROJECT_NAME} STM32_Safety_STL)
4.3 CRC后处理段
步骤11:添加FLASH CRC注入后处理
添加以下代码段,定义FLASH地址参数、查找STM32_Programmer_CLI工具、注册POST_BUILD事件在链接后自动注入CRC。需要注意根据实际安装路径修改STM32_PROGRAMMER_CLI_HINTS,根据实际芯片Flash范围修改CLASSB_FLASH_END。
# X-CUBE-CLASSB: compute and inject flash CRC into output ELF
set(CLASSB_FLASH_START "0x08000000" CACHE STRING
"CLASSB flash CRC start address")
set(CLASSB_FLASH_END "0x08080000" CACHE STRING
"CLASSB flash CRC end address (exclusive)")
set(CLASSB_FLASH_SECTION_SIZE "0x400" CACHE STRING
"CLASSB flash section size in bytes")
set(STM32_PROGRAMMER_CLI_HINTS
"C:/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin"
)
find_program(STM32_PROGRAMMER_CLI_EXECUTABLE
NAMES STM32_Programmer_CLI.exe STM32_Programmer_CLI
HINTS ${STM32_PROGRAMMER_CLI_HINTS}
)
if(STM32_PROGRAMMER_CLI_EXECUTABLE)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND "${STM32_PROGRAMMER_CLI_EXECUTABLE}" -sl
"$<TARGET_FILE:${CMAKE_PROJECT_NAME}>"
${CLASSB_FLASH_START} ${CLASSB_FLASH_END}
${CLASSB_FLASH_SECTION_SIZE}
COMMENT "X-CUBE-CLASSB: injecting flash CRC into ELF
via STM32_Programmer_CLI"
VERBATIM
)
else()
message(WARNING "STM32_Programmer_CLI not found.
CLASSB CRC post-build step is disabled.
Install STM32CubeProgrammer or set PATH accordingly.")
endif()
添加完成后保存CMakeLists.txt。此时可以先尝试一次编译,确认CMake配置阶段没有报错(尤其是STM32_Programmer_CLI是否找到、库文件路径是否正确)。如果CMake输出了“STM32_Programmer_CLI not found”的警告,需要先解决工具路径问题再继续。
5. 链接脚本修改
链接脚本(通常名为STM32C562RETx_FLASH.ld或类似命名,位于CMSIS设备目录下)需要修改内存段布局。文档中用颜色区分了修改内容:黄色为原有代码仅调整位置,红色为新增代码。以下按照最终的段顺序给出完整修改方案。
5.1 stack段调整
步骤12:将stack段移到.data段之前
找到原链接脚本中的.stack段定义,将其整体移动到.data段之前。段内内容保持不变:
.stack (NOLOAD) :
{
. = ALIGN(8);
__StackLimit = .;
. += STACK_SIZE;
. = ALIGN(8);
__StackTop = .;
_estack = .;
__stack = .;
} > RAM
这一调整的原因是X-CUBE-CLASSB-C5用户手册UM3667中关于PSPLIM的注意事项。将stack放在.data section之前是手册建议的简便实现方式。
5.2 backup_buffer_section新增
步骤13:在stack之后、.data之前添加backup_buffer_section
在.stack段之后、.data段之前插入以下新段定义:
.backup_buffer_section (NOLOAD) :
{
. = ALIGN(8);
__backup_buffer_start__ = .;
*(backup_buffer_section)
*(.backup_buffer_section*)
. = ALIGN(8);
__backup_buffer_end__ = .;
} > RAM
5.3 .data段位置确认
步骤14:确认.data段紧随其后
.data段保持原有定义不变,位置在backup_buffer_section之后。确认其定义中包含_edata_load符号的计算:
.data :
{
. = ALIGN(8);
_sidata = LOADADDR(.data);
__data_start__ = .;
_sdata = .;
*(.data);
*(.data*);
. = ALIGN(8);
_edata = .;
_edata_load = LOADADDR(.data) + SIZEOF(.data) - 4;
} > RAM AT> ROM
修改完成后,链接脚本中的RAM段顺序应为:.stack → .backup_buffer_section → .data → .bss(及其他原有段)。保存链接脚本文件。
6. 测试代码集成
6.1 StlSingleTest()移植
步骤15:复制测试示例代码
从X-CUBE-CLASSB-C5扩展包的示例工程中,找到StlSingleTest()函数的实现代码以及相关的宏定义、变量声明,将它们复制到用户工程中。可以新建一个源文件(如classb_test.c)来存放这些代码,或者直接添加到main.c中。
StlSingleTest()函数是自检库的统一测试入口,内部会依次调用CPU自检、FLASH自检、RAM自检等各个功能安全模块的测试函数,并返回各模块的测试状态。
6.2 main函数调用时机
步骤16:在系统初始化之后调用StlSingleTest()
在main函数中,完成所有系统初始化(时钟、GPIO、外设等)之后,添加对StlSingleTest()的调用。示例结构如下:
int main(void)
{
/* 系统初始化 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_CRC_Init();
/* ... 其他外设初始化 ... */
/* 功能安全自检 */
StlSingleTest();
/* 主循环 */
while (1)
{
/* 应用代码 */
}
}
调用时机必须在系统初始化之后,因为自检库依赖已经配置好的系统时钟、CRC外设等硬件资源。如果在初始化之前调用,外设尚未就绪,自检将无法正常执行。
7. 编译与仿真验证
7.1 编译通过判据
步骤17:全量编译
在VSCode中执行全量编译(Clean Build),观察编译输出。预期结果:
- CMake配置阶段无错误,可能输出STM32_Programmer_CLI相关的信息或警告;
- 所有源文件(包括stl_util.c、stl_user_param_template.c和用户工程文件)编译通过;
- 链接阶段无错误,STL_Lib.a成功链接;
- POST_BUILD阶段执行STM32_Programmer_CLI -sl命令,FLASH CRC成功注入ELF文件;
- 最终生成可执行文件(.elf/.hex/.bin)。
LAT1730文档中给出了集成完所有文件之后工程编译成功的结果截图,作为编译通过的参考。如果编译失败,优先检查:库文件路径是否正确、链接脚本段顺序是否正确、STM32_Programmer_CLI是否可执行、头文件包含路径是否配置。
7.2 功能安全模块全通过测试
步骤18:进入仿真调试
在VSCode中启动调试会话,将程序下载到开发板并运行。程序执行到StlSingleTest()时,可以通过调试器单步执行或在测试完成后设置断点,查看各功能安全模块的测试结果。
步骤19:确认所有模块测试通过
LAT1730文档中给出的VSCode仿真测试结果显示:所有功能安全模块测试均通过。这包括CPU自检、FLASH CRC校验、RAM自检等模块。如果某个模块测试失败,需要根据失败模块的类型排查:
- CPU测试失败:检查时钟配置是否稳定,是否存在干扰;
- FLASH测试失败:检查CRC外设是否激活、FLASH地址范围是否正确、CRC后处理步骤是否成功执行;
- RAM测试失败:检查链接脚本中backup_buffer_section是否正确添加、stack位置是否符合要求。
所有模块测试通过后,移植工作即告完成。此时工程具备了在VSCode环境下运行X-CUBE-CLASSB-C5功能安全自检的能力。
8. 移植检查清单
以下清单汇总了移植过程中的关键检查点,可用于移植完成后的自查或团队内部的代码评审。
| 序号 | 检查项 | 预期状态 | 对应步骤 |
| 1 | PA5配置为GPIO_Output | 已配置 | 步骤2 |
| 2 | CRC外设已激活 | 已激活,参数默认 | 步骤3 |
| 3 | 基础工程编译通过 | 无错误 | 步骤6 |
| 4 | LED闪烁正常 | 可观察到闪烁 | 步骤7 |
| 5 | Middlewares文件夹已复制 | 目录结构完整 | 步骤8 |
| 6 | CMakeLists添加链接脚本依赖 | 代码已添加 | 步骤9 |
| 7 | CMakeLists添加自检库目标 | IMPORTED库已定义 | 步骤10 |
| 8 | CMakeLists添加CRC后处理 | POST_BUILD已注册 | 步骤11 |
| 9 | STM32_Programmer_CLI可找到 | 无"not found"警告 | 步骤11 |
| 10 | FLASH地址参数匹配芯片 | 0x08000000~0x08080000(C562RE) | 步骤11 |
| 11 | 链接脚本stack移至.data前 | 段顺序正确 | 步骤12 |
| 12 | 链接脚本添加backup_buffer_section | 新段已插入 | 步骤13 |
| 13 | StlSingleTest()已复制 | 函数实现完整 | 步骤15 |
| 14 | main中系统初始化后调用测试 | 调用位置正确 | 步骤16 |
| 15 | 全量编译通过 | 无错误,CRC注入成功 | 步骤17 |
| 16 | 仿真测试所有模块通过 | 全部PASS | 步骤18-19 |
LAT1730文档还附带了一个名为STM32C5_ClassB_cmake.7z的压缩包,其中包含了完整的CMake工程示例。在移植过程中遇到问题时,可以将自己的工程与附件中的参考工程进行对比,快速定位差异。
182