繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM