簡體   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