我正在使用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 release(,行为仍然是一样的。
对我有用的解决方法(从 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()
,则需要从startup_XXX.s
文件中删除相应的.weak
条目,否则中断将通过卡在默认的无限循环中来锁定 MCU,而不执行预期的中断处理程序并从中断返回, 允许其他代码执行恢复。
此错误仍然存在于gcc-arm-none-eabi-9-2020-q3-update
中,但仅适用于 C 处理程序。奇怪的是,用C++编写的处理程序(并使用extern "C"
链接声明(不再受到此错误的影响。
作为另一种解决方法,我发现将 IRQ 处理程序放在单独的.c
文件中并在没有 LTO 的情况下构建它们(并且仅构建那些(可以解决问题,而不是弄乱startup.s
文件。
对于那些使用CubeIDE并使用CubeMX(又名"设备配置工具"(生成IRQ/HAL处理程序的用户,所有自动生成的处理程序都在CoreSrcstm32XXXX_it.c
,您只需编辑此文件的属性并从编译选项中删除LTO。
这是次优的,但它非常适合自动生成的 IRQ/HAL 处理程序:只有第一次调用(从 IRQ 处理程序到 HAL 处理程序(未优化,但 HAL 代码本身已正确优化。