[英]Interrupt Service Routine doesn't jump back to Interrupt Handler on an ARM Cortex M0
目前,我正在尝试通过UART在PC和ARM Cortex M0之间建立通信。 系统很简单:定制的UART模块具有一个1字节的缓冲区。 如果缓冲区已满,则设置中断标志。 调用中断处理程序并返回中断服务程序(ISR)。 ISR读取缓冲区(因此模块的中断标志将被重置),并将获得的字节写入全局数组。
这样做时发现了以下问题:发送字符(= 1字节)后,系统进入ISR,但永不返回。 我可以一次又一次中断系统,但是它永远不会返回主代码。 现在,由于我的设置是将ARM硬核集成在Xilinx Spartan 6 FPGA上,而Xilinx Spartan 6 FPGA是在开发板上构建的,因此对ARM代码进行调试非常困难。 我还没有想办法。 因此,我想到了在开始设置新的调试工具链之前,尝试消除可能的(理论上的)错误。 因此,我的帖子在这里。
我认为我以某种方式误解了如何在ARM上处理中断。 这是我的方法:
中断处理程序代码(在ASM中):
; Jump Table
__Vectors DCD __initial_sp
DCD Reset_Handler
DCD 0
...
; External Interrupts
DCD UART_Handler
...
; Interrupt Handler
UART_Handler PROC
EXPORT UART_Handler
IMPORT UART_ISR
PUSH {R0,LR} ; SAVE register state
; GPIO #1
MOVS R0, #1 ; MASK all interrupts
MSR PRIMASK, R0
BL UART_ISR ; JUMP to ISR
; GPIO #4
MOVS R0, #0 ; ENABLE all interrupts
MSR PRIMASK, R0
POP {R0,PC} ; RESTORE register state
ENDP
中断服务程序代码(C语言):
// Defined in the main routine
char buffer[129] __attribute__((aligned (4)));
// Global Variables
int uart_in_progress;
char* uart_ptr = buffer;
unsigned int uart_length;
void UART_ISR()
{
char inChar;
// GPIO #2
// Read Character out of Buffer (=reset interrupt flag)
inChar= *(unsigned int*)APB_UART_BASE;
if(uart_in_progress) {
// end transmission for EOL or Max Length
if(current_char == '\n' || uart_length == 129) {
uart_in_progress = 0;
}
// add next character to Memory Buffer
else {
*(uart_ptr + uart_length) = current_char;
uart_length++;
}
}
// GPIO #3
return;
}
在我理解之后,此代码足以处理和响应中断调用。 使用GPIO,我可以轻松地看到标志如何上升,中断处理程序作出反应(GPIO#1),ISR启动(GPIO#2),标志下降,ISR结束(GPIO#3),然后再也不会跳回到处理程序(缺少GPIO#4)。 堆栈应足够大。 仅使用ARM Keil的模拟器,一切都可以正常工作。
谷歌搜索示例后,我有时会遇到如下针对ISR的明确定义:
__attribute__ ((__interrupt__)) void UART_ISR()
这样的定义是强制性的吗? 还是需要其他命令来向ARM处理器指示已处理了该中断? 查看我编译的汇编代码,我只是看到来回跳转,并且不了解这种定义是否会为这些(正确的)跳转添加任何内容。
任何建议深表感谢。 再说一次:我很清楚需要正确的调试器-如果可以避免麻烦,那将是很好的。
我看不到您清除中断。 一些UART外设要求您清除中断,否则中断将继续循环。 但是,有些会在读取数据寄存器时自动清除中断,因此请参阅外围设备文档。 以我的经验,未清除的中断通常是永久循环中断的原因。
另外,我不认为这是您的问题,但是,您不需要
MOVS R0, #1 ; MASK all interrupts
MSR PRIMASK, R0
和
MOVS R0, #0 ; ENABLE all interrupts
MSR PRIMASK, R0
代码部分。 在中断期间,您不必屏蔽任何中断。 如果从中断上下文执行,则正确配置中断优先级将阻止其他中断的触发。
就像其他人说的那样,根据您的使用方式,您根本不需要汇编代码,只需将C函数命名为“ UART_Handler”即可。
尝试将R0-R3,LR推入堆栈,并在返回之前将所有弹出窗口弹出。 处理中断的函数调用将破坏这些寄存器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.