使用CMake构建STM32固件时的中断处理
Interrupt handling while using CMake to build STM32 firmware
我调试用CMake创建的STM32工程。它使用 HAL 库,一开始我配置了 HAL 和 SysTick。
root/
├─ core/
│ ├─ core.c
│ ├─ core.h
│ ├─ stm32g4xx_it.c
│ ├─ stm32g4xx_it.h
│ ├─ CMakeLists
├─ main.c
├─ startup.s
├─ CMakeLists.txt
startup.s
文件包含弱SysTick_Handler,如下:
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
stm32g4xx_it.c
还包含覆盖弱声明的 SysTick_Handler
。
问题是在编译 link 并像上面那样加载应用程序时,SysTick 中断在 Default_Handler
结束。如果我从 startup.s
文件中删除弱声明,那么它会正常工作并执行正确的处理函数。我认为这是 cmake 工作方式的结果。在根目录中有一个主要的 CMakeLists.txt 文件,它编译 startup.s
和 main.c
文件,然后是 links 核心库。正确的 SysTick handler
放在核心库中,因此 startup.s
文件的编译“看不到”此处理函数的其他实现。
解决它的正确而优雅的方法是什么?
我想到的另一个问题是我应该如何为其他中断处理程序编写代码以及如何在 CMake 构建系统中 link 它们?假设我有一个 UART 模块,该模块有自己的中断处理程序。我是否应该创建一个基于 startup.s
文件和 link 所有其他具有中断处理程序的模块的单独库?我认为 CMake 应该使构建更加透明、可读和容易,但那样看起来更像意大利面条。可能我遗漏了什么...
编辑 2021 年 4 月 14 日
我发现问题只与启动 asm 文件有关。例如,我可以在main.c中创建一个弱函数符号,例如:
__attribute__((weak)) void SystemInit(void)
在核心库中,在core.c中我创建函数:
void SystemInit(void)
然后在编译和 linking 之后使用 core.c 中的正确函数。所以看起来这里有一些与 asm 文件严格相关的东西。
这种 linker 行为的原因是它以不同的方式对待库。当它在源文件中找到弱符号时,它会停止在库中寻找相同的符号。这样做的原因是库提供了一些功能,开发人员应该能够覆盖这些功能以使其与自己的项目保持一致。
无需在微控制器的嵌入式项目中使用库。我发现它会导致更多的疼痛。一些开发人员不在他们的 CMakeLists.txt
中使用库 add_library()
。在使用 CMake 时,我觉得它不太合理。它用于更好地组织项目文件和管理模块之间的依赖关系。
这里的问题可以通过使用 OBJECT
库来简单解决。那种类型的link已经在3.12版本的target_link_libraries
中加入了。我认为它是专门为微控制器项目添加的,而且效果非常好。
我调试用CMake创建的STM32工程。它使用 HAL 库,一开始我配置了 HAL 和 SysTick。
root/
├─ core/
│ ├─ core.c
│ ├─ core.h
│ ├─ stm32g4xx_it.c
│ ├─ stm32g4xx_it.h
│ ├─ CMakeLists
├─ main.c
├─ startup.s
├─ CMakeLists.txt
startup.s
文件包含弱SysTick_Handler,如下:
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
stm32g4xx_it.c
还包含覆盖弱声明的 SysTick_Handler
。
问题是在编译 link 并像上面那样加载应用程序时,SysTick 中断在 Default_Handler
结束。如果我从 startup.s
文件中删除弱声明,那么它会正常工作并执行正确的处理函数。我认为这是 cmake 工作方式的结果。在根目录中有一个主要的 CMakeLists.txt 文件,它编译 startup.s
和 main.c
文件,然后是 links 核心库。正确的 SysTick handler
放在核心库中,因此 startup.s
文件的编译“看不到”此处理函数的其他实现。
解决它的正确而优雅的方法是什么?
我想到的另一个问题是我应该如何为其他中断处理程序编写代码以及如何在 CMake 构建系统中 link 它们?假设我有一个 UART 模块,该模块有自己的中断处理程序。我是否应该创建一个基于 startup.s
文件和 link 所有其他具有中断处理程序的模块的单独库?我认为 CMake 应该使构建更加透明、可读和容易,但那样看起来更像意大利面条。可能我遗漏了什么...
编辑 2021 年 4 月 14 日
我发现问题只与启动 asm 文件有关。例如,我可以在main.c中创建一个弱函数符号,例如:
__attribute__((weak)) void SystemInit(void)
在核心库中,在core.c中我创建函数:
void SystemInit(void)
然后在编译和 linking 之后使用 core.c 中的正确函数。所以看起来这里有一些与 asm 文件严格相关的东西。
这种 linker 行为的原因是它以不同的方式对待库。当它在源文件中找到弱符号时,它会停止在库中寻找相同的符号。这样做的原因是库提供了一些功能,开发人员应该能够覆盖这些功能以使其与自己的项目保持一致。
无需在微控制器的嵌入式项目中使用库。我发现它会导致更多的疼痛。一些开发人员不在他们的 CMakeLists.txt
中使用库 add_library()
。在使用 CMake 时,我觉得它不太合理。它用于更好地组织项目文件和管理模块之间的依赖关系。
这里的问题可以通过使用 OBJECT
库来简单解决。那种类型的link已经在3.12版本的target_link_libraries
中加入了。我认为它是专门为微控制器项目添加的,而且效果非常好。