目前,我正在尝试通过UART在PC和ARM Cortex M0之间建立通信。系统很简单:定制的UART模块有一个字节缓冲区。如果缓冲区已满,则设置中断标志。中断处理程序被调用并作为回应调用中断服务例程(ISR)。 ISR读取缓冲区(因此模块的中断标志被重置)并将获得的Byte写入全局数组。
这样做我发现了以下问题:一旦我发送了一个字符(= 1 Byte),系统就会进入ISR,但永远不会返回。我可以一次又一次地中断系统,但它永远不会返回主代码。 现在由于我在一个Xilinx Spartan 6 FPGA上集成的ARM硬核的设置,它是在开发板上构建的,因此难以调试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处理器指示中断被处理的附加命令?看看我编写的asm代码,我只看到来回跳转,并且不明白这样的定义是否会为这些(正确的)跳转添加任何内容。
非常感谢任何建议。再说一次:我很清楚需要一个正确的调试器 - 如果我可以避免麻烦,那就太棒了。
答案 0 :(得分:2)
我没有看到你清除中断。某些UART外设要求您清除中断或中断将继续循环。但是,有些会在读取数据寄存器时自动清除中断,因此请参阅外设文档。根据我的经验,未清除的中断通常是永久循环中断的原因。
另外,我不相信这是你的问题但是,你不应该
MOVS R0, #1 ; MASK all interrupts
MSR PRIMASK, R0
和
MOVS R0, #0 ; ENABLE all interrupts
MSR PRIMASK, R0
代码部分。在中断期间,您不必屏蔽任何中断。如果您正在从中断上下文执行,则正确配置的中断优先级将阻止其他中断触发。
像其他人一样,根据您的使用方式,您根本不需要汇编代码,只需命名您的C函数" UART_Handler"。
答案 1 :(得分:0)
尝试将R0-R3,LR插入堆栈并在返回之前弹出所有内容。处理中断的函数调用将破坏这些寄存器。