(特定于Arduino Uno ...)
当AVR微控制器上发生中断并调用函数时,堆栈会发生什么?编译器是否内联代码?它是否将堆栈缓存在某个地方,然后重置堆栈指针?它是否仅具有用于中断的辅助堆栈?
据我了解,中断的向量是汇编中的直接GOTO命令。另外,我不认为微控制器会自动弄乱堆栈,因此它可能一个人呆着。但是,这仍然不能解释功能在ISR期间如何工作。
(特定于Arduino Uno ...)
当AVR微控制器上发生中断并调用函数时,堆栈会发生什么?编译器是否内联代码?它是否将堆栈缓存在某个地方,然后重置堆栈指针?它是否仅具有用于中断的辅助堆栈?
据我了解,中断的向量是汇编中的直接GOTO命令。另外,我不认为微控制器会自动弄乱堆栈,因此它可能一个人呆着。但是,这仍然不能解释功能在ISR期间如何工作。
Answers:
AVR是RISC架构,因此具有相当基本的中断硬件处理能力。大多数处理器在中断期间都会使堆栈混乱,尽管有两种使用不同方法的处理器,最著名的是ARM和PowerPC。
无论如何,这是AVR对中断的作用:
发生中断时,处理器硬件将执行以下步骤,而不仅仅是简单的GOTO:
现在,硬件已经完成了所有要做的工作。该软件必须正确编写以免损坏。通常,接下来的步骤将遵循这些原则。
将状态寄存器压入堆栈。(必须先进行更改,然后再进行更改)。
将将(或可能被更改)的所有CPU寄存器压入堆栈。编程模型定义了需要以这种方式保存的寄存器。编程模型由编译器定义。
现在可以运行工作中断代码。为了回答调用函数的问题,它只是做它总是做的事情,将返回值压入堆栈,然后在完成后将其弹出。到目前为止,这不会影响我们保存在堆栈中的所有先前值。
现在我们完成了,想从中断中返回。首先,我们必须进行软件清理。
执行RTI指令。硬件为此指令执行以下步骤:
一个。启用全局中断标志。(请注意,在接受下一个中断之前,必须至少运行一条指令。这可以防止大量中断完全阻塞后台工作。)
b。将保存的返回地址弹出到PC中。
现在我们回到普通代码。
注意,有些地方我们必须非常小心,特别是在状态寄存器和可能更改的保存寄存器周围。幸运的是,如果您使用的是C编译器,那么所有这些操作都是在后台进行的。
另外,您还必须注意堆栈深度。在启用中断的任何时候,ISR都可以使用比查看本地代码明显更多的堆栈。当然,除非您将内存推到极限,否则确实不会有太大的变化。
如果需要参考,这里是描述此过程的链接。
ISR_NAKED
)禁用状态和其他寄存器的自动保存。在您确实需要这些循环的情况下,这可以让您跳过第5、6、8、9步。缺点是您必须绝对确定自己将保留任何相关的寄存器,或者可以无害地覆盖它们。