简体   繁体   English

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

[英]Interrupt Service Routine doesn't jump back to Interrupt Handler on an ARM Cortex M0

Currently I'm trying to establish a communication between my PC and an ARM Cortex M0 over UART. 目前,我正在尝试通过UART在PC和ARM Cortex M0之间建立通信。 The system is simple: The custom-made UART module has a one Byte buffer. 系统很简单:定制的UART模块具有一个1字节的缓冲区。 If the buffer is full the interrupt flag is set. 如果缓冲区已满,则设置中断标志。 The interrupt handler gets called and calls the interrupt service routine (ISR) in return. 调用中断处理程序并返回中断服务程序(ISR)。 The ISR reads the buffer (therefore the interrupt flag of the modules gets reset) and writes the obtained Byte into a global array. ISR读取缓冲区(因此模块的中断标志将被重置),并将获得的字节写入全局数组。

Doing so I discovered the following problem: Once I send a character (=1 Byte), the system enters the ISR but never returns. 这样做时发现了以下问题:发送字符(= 1字节)后,系统进入ISR,但永不返回。 I can interrupt the system again and again but it never returns to the main code. 我可以一次又一次中断系统,但是它永远不会返回主代码。 Now due to my setup with the ARM hardcore integrated on an Xilinx Spartan 6 FPGA which is build on a dev board debugging of the ARM code is difficult. 现在,由于我的设置是将ARM硬核集成在Xilinx Spartan 6 FPGA上,而Xilinx Spartan 6 FPGA是在开发板上构建的,因此对ARM代码进行调试非常困难。 I haven't yet figured out a way how to do. 我还没有想办法。 So I thought of trying to eliminate possible (theoretical) errors before starting the pain of setting up a new debugging toolchain. 因此,我想到了在开始设置新的调试工具链之前,尝试消除可能的(理论上的)错误。 Therefore my post here. 因此,我的帖子在这里。

I think that I misunderstood somehow the way how to treat interrupts on an ARM. 我认为我以某种方式误解了如何在ARM上处理中断。 Here is how I do it: 这是我的方法:

Interrupt Handler Code (in ASM): 中断处理程序代码(在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

Interrupt Service Routine Code (in C): 中断服务程序代码(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;
}

After my understanding this code is sufficient to treat and respond the interrupt call. 在我理解之后,此代码足以处理和响应中断调用。 Using GPIOs I can easily see how the flag rises, the interrupt handler reacts (GPIO #1), the ISR starts (GPIO #2), the flag falls, the ISR ends (GPIO #3) and then never jumps back to the handler (missing GPIO #4). 使用GPIO,我可以轻松地看到标志如何上升,中断处理程序作出反应(GPIO#1),ISR启动(GPIO#2),标志下降,ISR结束(GPIO#3),然后再也不会跳回到处理程序(缺少GPIO#4)。 The Stack should be large enough. 堆栈应足够大。 Using only the simulator of ARM Keil everything works as it should. 仅使用ARM Keil的模拟器,一切都可以正常工作。

Having googled to find examples I sometimes came across an explicit definition for ISR as following: 谷歌搜索示例后,我有时会遇到如下针对ISR的明确定义:

__attribute__ ((__interrupt__)) void UART_ISR()

Is such a definition mandatory? 这样的定义是强制性的吗? Or are additional commands necessary to indicate to the ARM processor that the interrupt was treated? 还是需要其他命令来向ARM处理器指示已处理了该中断? Looking at my complied asm code I just see jumps back and forth and do not understand if such a definition would add anything to these (correct) jumps. 查看我编译的汇编代码,我只是看到来回跳转,并且不了解这种定义是否会为这些(正确的)跳转添加任何内容。

Any advice is much appreciated. 任何建议深表感谢。 And again: I am well aware of the need of a correct debugger - would just be great if I can avoid the hassle. 再说一次:我很清楚需要正确的调试器-如果可以避免麻烦,那将是很好的。

I don't see you clearing the interrupt. 我看不到您清除中断。 Some UART peripherals require you to clear the interrupt or the interrupt will continue to cycle. 一些UART外设要求您清除中断,否则中断将继续循环。 Some will clear the interrupt automatically when the data register is read, though, so refer to the peripheral documentation. 但是,有些会在读取数据寄存器时自动清除中断,因此请参阅外围设备文档。 In my experience an uncleared interrupt is often the cause of a perpetually cycling interrupt. 以我的经验,未清除的中断通常是永久循环中断的原因。

Also, I'm unconvinced it's your problem but, you shouldn't need the 另外,我不认为这是您的问题,但是,您不需要

MOVS    R0, #1      ; MASK all interrupts
MSR     PRIMASK, R0

and

MOVS    R0, #0      ; ENABLE all interrupts
MSR     PRIMASK, R0

sections of code. 代码部分。 You shouldn't have to mask any interrupts while in an interrupt. 在中断期间,您不必屏蔽任何中断。 If you're executing from an interrupt context, having properly configured interrupt priorities will stop other interrupts from triggering. 如果从中断上下文执行,则正确配置中断优先级将阻止其他中断的触发。

Like others say, based on how you're using it, you shouldn't need the assembly code at all, just name your C function "UART_Handler". 就像其他人说的那样,根据您的使用方式,您根本不需要汇编代码,只需将C函数命名为“ UART_Handler”即可。

Try pushing R0-R3, LR into stack and popping all of that out before return. 尝试将R0-R3,LR推入堆栈,并在返回之前将所有弹出窗口弹出。 The function call to handle your interrupt will corrupt those registers. 处理中断的函数调用将破坏这些寄存器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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