Currently I'm trying to establish a communication between my PC and an ARM Cortex M0 over UART. The system is simple: The custom-made UART module has a one Byte buffer. If the buffer is full the interrupt flag is set. The interrupt handler gets called and calls the interrupt service routine (ISR) in return. The ISR reads the buffer (therefore the interrupt flag of the modules gets reset) and writes the obtained Byte into a global array.
Doing so I discovered the following problem: Once I send a character (=1 Byte), the system enters the ISR but never returns. 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. 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. Here is how I do it:
Interrupt Handler Code (in 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):
// 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). The Stack should be large enough. Using only the simulator of ARM Keil everything works as it should.
Having googled to find examples I sometimes came across an explicit definition for ISR as following:
__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? 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.
UART_Handler PROC
lacking a return from interrupt instruction? Or is that taken care of with the finalPOP
? Usually aRETI
type instruction will restore the flags register too. – Weather VaneUART_ISR
is corrupting the normal flow (corrupting the stack, for instance)? The__attribute__ ((__interrupt__))
should not be needed here, since the routine is a regular function just called from the actual ISR – Eugene Sh.BL
is a returnable-from 'call' rather than a straight jump. ARM is downright weird if you're used to x86 ;) – NotlikethatBL
is a correct instruction here – Eugene Sh.volatile
– Eugene Sh.