中断服务程序不会跳回ARM Cortex M0上的中断处理程序

时间:2015-05-27 18:26:41

标签: c debugging arm interrupt-handling cortex-m

目前,我正在尝试通过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代码,我只看到来回跳转,并且不明白这样的定义是否会为这些(正确的)跳转添加任何内容。

非常感谢任何建议。再说一次:我很清楚需要一个正确的调试器 - 如果我可以避免麻烦,那就太棒了。

2 个答案:

答案 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插入堆栈并在返回之前弹出所有内容。处理中断的函数调用将破坏这些寄存器。