Hi,
I'm working with LCP2138 using the Keil demo board and the UVision IDE
with GNU compiler 3.3.1.
When I switched from examples to a little more complicated interrupt
handler for the UART0 I started experiencing strange problems: hangs,
reboots, function in the main program called out of order...
Giving a look to the asm listing I see that the GCC compiler insert an
extra 'sub lr, lr, #4' opcode in the isr entrypoint, and at the end of
isr uses the 'subs pc, lr, #4'
In this way the main program continues the execution not from were was
interrupted, but at an instruction before.
Here is the isr code and the partial assembler listing:
/**
* Interrupt service routine for UART0 device
*/
void Uart0_isr(void)
{
WORD rxnewend;
BYTE IrqIdent;
BYTE i, c;
IrqIdent = U0IIR & 0x0F;
switch(IrqIdent) {
case 0x02: // Transmit holding register empty.
IOSET1 = LED1;
break;
case 0x04: // RX Data available
for(i=0;i<4;i++) {
c = U0RBR;
rxnewend = rxbufend+1;
if(rxnewend >= RXBUFSIZE)
rxnewend = 0;
if(rxnewend == rxbufini) {
// Buffer full
ComStatus |= COM_FULL;
}
else {
rxbuffer[rxbufend] = c;
rxbufend = rxnewend;
}
}
ComStatus &= ~COM_EMPTY;
IOSET1 = LED2;
break;
case 0x06: // RX Line status Interrupt
IOSET1 = LED3;
i = U0LSR;
break;
case 0x0C: // Character time out
c = U0RBR;
rxnewend = rxbufend+1;
if(rxnewend >= RXBUFSIZE)
rxnewend = 0;
if(rxnewend == rxbufini) {
// Buffer full
ComStatus |= COM_FULL;
}
else {
rxbuffer[rxbufend] = c;
rxbufend = rxnewend;
}
ComStatus &= ~COM_EMPTY;
IOSET1 = LED4;
break;
default:
IOSET1 = LED8;
break;
}
}
241:**** /**
242:**** * Interrupt service routine for UART0 device
243:**** */
244:**** void Uart0_isr(void)
245:**** {
459 .loc 1 245 0
460 @ Interrupt Service Routine.
461 @ args = 0, pretend = 0, frame = 0
462 @ frame_needed = 0, uses_anonymous_args = 0
463 03e4 04E04EE2 sub lr, lr, #4
464 03e8 7F502DE9 stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, ip, lr}
465 .LCFI8:
248: ****
249: **** WORD rxnewend;
250: **** BYTE IrqIdent;
251: **** BYTE i, c;
252: ****
253: **** IrqIdent = U0IIR & 0x0F;
466 .loc 1 253 0
467 .LBB6:
468 03ec 0339A0E3 mov r3, #49152
469 03f0 8E3283E2 add r3, r3, #-536870904
470 03f4 0030D3E5 ldrb r3, [r3, #0] @ zero_extendqisi2
471 03f8 0F3003E2 and r3, r3, #15
......
......
296: **** default:
297: **** IOSET1 = LED8;
609 .loc 1 297 0
610 059c 0E32A0E3 mov r3, #-536870912
611 05a0 0A3983E2 add r3, r3, #163840
612 05a4 143083E2 add r3, r3, #20
613 05a8 0225A0E3 mov r2, #8388608
614 .L71:
615 05ac 002083E5 str r2, [r3, #0]
298: **** break;
299: **** }
300: ****
301: ****
302: **** }
616 .loc 1 302 0
617 .L50:
618 05b0 7F50BDE8 ldmfd sp!, {r0, r1, r2, r3, r4, r5, r6, ip, lr}
619 05b4 04F05EE2 subs pc, lr, #4
Note that if I slighty semplify the handler (ex. removing the for()
loop), the compiler needs to use less registers, don't save the LR
register, does not insert the sub lr,lr,#4 opcode and the code work!!
Anyone experienced similar problems and has a solution?
Thank you.Message
GCC compiler generates wrong code for interrupt handler routines
2006-01-31 by c.barbaro
Attachments
- No local attachments were found for this message.