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