Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

GCC compiler generates wrong code for interrupt handler routines

2006-01-31 by c.barbaro

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.

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.