我正在使用 SystemWorkbench 4 stm32 对 STM32F413 微控制器进行编程。中断向量在程序集启动文件中定义为弱别名,如下所示:
.weak TIM1_UP_TIM10_IRQHandler
.thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
并在如下对象中引用:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.....
.word TIM1_UP_TIM10_IRQHandler
.....
因此
g_pfnVectors
是 IRQ 处理函数的地址列表。它们被声明为弱别名,因此如果用户未定义它们,则使用默认处理程序。
我已经这样定义了处理程序:
extern "C" {
void TIM1_UP_TIM10_IRQHandler() {
if (SU_TIM->SR & TIM_SR_UIF) {
SU_TIM->SR &= ~TIM_SR_UIF;
...
}
}
}
这与正常的编译器优化标志配合得很好,但是我想尝试一下是否可以使用
-flto
获得更小且可能更快的代码(主要是为了尝试它,并不真正需要它)。但是当使用 -flto
进行编译时,g++ 会忽略我对处理程序的实现并仅使用默认处理程序,我的处理程序根本不在代码中。
所以我尝试通过在函数定义中添加
__attribute__((used))
来强制 g++ 包含该函数,但仍然没有编译。但是,如果我给它另一个名称,那么它就会包含在二进制文件中。另外,如果我删除弱别名并仅在启动文件中引用处理程序,它也可以工作。
因此,弱别名无法与 g++ 链接时间优化一起使用。也许有人可以告诉我错误是什么以及我在这里做错了什么。
编辑:
我查看了在生成的 .elf 文件上使用 nm 创建了哪些符号,并且
TIM1_UP_TIM10_IRQHandler
被导出为带有 DefaultHandler 地址的弱符号。但是,当仅查看包含 TIM1_UP_TIM10_IRQHandler
函数的编译单元中的 .o 文件时,它将作为文本部分 (T) 中的符号导出。因此,出于某种原因,链接器选择保留弱符号,即使存在同名的强符号。
我认为你应该通知编译器它是中断
__attribute__ ((interrupt ("IRQ")))
,通常不需要,因为F4默认情况下硬件将堆栈对齐到8。
如果没有帮助,解决方法是为处理程序分配一个函数指针,这将防止它被丢弃(如果指针本身不会被丢弃 - 请与调试器检查)。
最后的手段 - 使用向量表定义更改 .s 文件
对于那些寻找此问题的人来说,GCC 7 中显然存在一个与链接时优化相关的已确认错误 (
-flto
):
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966
我刚刚再次遇到这个问题,在 GCC 8(gcc-arm-none-eabi-8-2019-q3-update 版本)中,行为仍然相同。
对我也有效的解决方法(来自https://github.com/ObKo/stm32-cmake/issues/78)是删除或注释
startup_XXX.s
文件末尾的弱定义,因此更改,例如
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
到
/*
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
*/
并将它们替换为源文件中您自己的实现:
void NMI_Handler(void)
{
//...
}
所有正在调用的弱处理程序都需要删除,因此,例如,如果您在 HAL/LL 驱动程序中定义了
UART1_Handler()
,则需要从 .weak
文件中删除相应的 startup_XXX.s
条目,否则中断将通过陷入默认的无限循环来锁定 MCU,而不执行预期的中断处理程序并从中断返回,从而允许其他代码执行恢复。
此错误仍然存在于
gcc-arm-none-eabi-9-2020-q3-update
中,但仅适用于 C 处理程序。奇怪的是,用 C++ 编写的处理程序(并使用 extern "C"
链接声明)不再受此错误影响。
作为另一种解决方法,我发现将 IRQ 处理程序放在单独的
startup.s
文件中并在没有 LTO 的情况下构建这些(并且仅那些)即可解决问题,而不是弄乱 .c
文件。
对于使用 CubeIDE 并使用 CubeMX(又名“设备配置工具”)生成 IRQ/HAL 处理程序的用户,所有自动生成的处理程序都在
Core\Src\stm32XXXX_it.c
中,您只需编辑此文件的属性并从编译中删除 LTO选项。
这不是最优的,但它非常适合自动生成的 IRQ/HAL 处理程序:只有第一个调用(从 IRQ 处理程序到 HAL 处理程序)未优化,但 HAL 代码本身已正确优化。
到 2023 年它仍然存在,使用 11.2.1-1.2。
因此,如果不破解核心源代码,就不可能使用中断处理程序。
古力克