初始化向量表的代码位于STM32cubeIDE的启动代码中:
.global g_pfnVectors
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.
.
.
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
.
.
.
我想了解它,然后我有一些问题,如果有人可以帮助:
g_pfnVectors
已经声明了两次,一次是.global
,另一次是.word
。它首先声明为全局,然后声明其在硬件中的大小?
1.第2,3,4行有逗号分隔的东西,它们是什么?
1.有什么参考资料可以理解他们吗?
注意:我知道第6行是g_pfnVectord
的数组定义。
1.看起来启动必须持有IRQhandlers函数指针,因为我们已经在 *_it.c中定义了它们,这些将链接到它们,对吗?
1.在arm interupt vector relocation usage and description中,他们在表重新分配后重新分配了SysTick_Handler
。如果我们使用链接器将此函数移动到RAM,那么我们不需要重新分配此函数,对吗?(由于此函数在cubeIDE应用程序上默认每1mS执行一次,并且速度很快)
1条答案
按热度按时间9o685dep1#
不能很好地涵盖汇编语法,但我认为一些关于向量表和中断入口的解释会很有帮助。事实上,在启动时没有汇编代码是非常容易的,你完全可以在C中将向量表作为一个数组,放在它自己的节中。另外,我自己也不是汇编方面的超级逆。无论如何,关于向量表,它是什么,它是如何工作的,你可以用它做什么。
在Flash的开始,在任何可执行代码之前,你有一个向量表。它只是一个指向void(void)函数的指针列表。(向量表的第一个字在开机时被加载到主堆栈指针中,其他的都是指针)。由于Flash并不打算在运行时动态改变,我们可以放心地假设在实践中这些指针是固定的。
当中断发生时,CPU从向量表中读取相应的中断处理程序地址,然后跳转到它读取的任何地址。因此,如果你移动向量表,你还需要确保所有中断的处理程序地址在新的向量表中的正确位置。基本上,你想把旧的向量表复制到新的位置。
少量添加:在Cortex M中,向量表条目的最低有效位始终设置为1(与所有函数指针一样)。体系结构要求(指示Thumb指令集,而不是32位ARM指令集)。否则使用错误异常。(因此,对于0x 20040000处的中断处理程序,向量表条目为0x 20040001)。
让我们考虑一个基本的例子。
向量表位于Flash中,并且是固定的(不可更改)。假设您的中断号为20。假设您有用于该中断的void IRQ20_Handler(void)处理程序,该处理程序也位于Flash中,通常是可执行代码所在的位置。让我们假设处理程序的地址为0x 08004000(Flash中不与向量表重叠的任何地址,仅举一例)。
在闪存中,存储器的32位字编号36将包含0x 08004001. 36,因为MSP+异常(hardfault、memmanage故障、busfault、systick等)占用前16个字,IRQ仅在此之后开始。矢量表在STM MCU的参考手册中。
现在,向量表位于0x 08000000位置(Flash开头),其中第36个字有一个指向IRQ20_Handler的指针,该指针也位于Flash中的某个位置。因此,如果发生IRQ 20中断,MCU将从Flash读取第36个字(0x 08004001),并跳转到0x 08004000,然后跳转到处理程序。
假设您希望SRAM中有一个函数,作为位于0x 20040000的中断处理程序。您必须重写闪存,以便向量表字36具有新的处理程序地址-不建议仅为一件事重写闪存-因此,您将向量表移至RAM,然后可以在运行时根据需要动态更改向量。
因此,首先将IRQ处理程序移动到RAM(比如,0x 20040000),然后将向量表移动到RAM,并确保所有处理程序地址都被复制到那里,以便所有中断像以前一样工作,然后在新的向量表中覆盖IRQ20_Handler(向量表的字36)与SRAM功能的地址(+1)。在这种情况下,与0x 20040001。
遗憾的是,不能提供更多关于汇编的细节,因为我只使用了一点,主要是作为上下文切换的内联汇编块或C本身不支持的特殊指令。它看起来像是声明了一个section(并使其全局可见),并为其提供了一对属性。