Yesterday I've opened a thread about a system crash after the execution of an IRQ routine. After many tests I've isolated the problem and symplified the context in which it happens.
Now the problem I see is the following.
I've only an IRQ routine linked to CPU timer 0. It should be invoked every 1 ms. However after the first call the CPU switches to DATA ABORT mode.
I configure LPC2378 (rev. B) with 72 MHz clock and MAM fully enabled (the problem is present olaso with MAM partially enabled). The source code is the following
/************************************************* ** INITIALISING FUNCTION **************************************************/ void ini_base_timer(void){ PCONP |= (1 << 1); /* power up timer 0 */ T0TCR = 0; /* disable timer 0 */ PCLKSEL0 |= 0x00000004; /* timer 0 clock = PCLOCK */ T0IR = 0x11; /* reset irq flag */ T0CTCR = 0; T0PR = 8; /* prescaler */ T0MR0 = 7999; /* match register 0 */ /* configuration vectored interrupt */ VICIntEnClr |= (1 << 4); /* irq disabling */ VICIntSelect &= ~(1 << 4);/* IRQ interrupt */ VICVectPriority4 = 8; /* priority */ VICVectAddr4 = (UINT32)&irq_base_timer; /* ISR */ VICIntEnable |= (1 << 4);/* irq enabling*/ T0MCR |= 0x03; /* irq enabling and TC reset on match register 0 value */ T0TCR = 0x01; /* start timer */ } /* end ini_base_timer */ /************************************************* ** IRQ FUNCTION (ISR) ** global variables: ** long sd[32]; // global array ** unsigned char buffer_rx_fw[512]; // global array **************************************************/ void __IRQ__ irq_base_timer(void){ UINT32 cont; FIO4SET = 0x01; /* set GPOUTPUT 4.0 */ T0IR = 1; /* irq flag reset */ for(cont = 0; cont < 2; cont++){ if(sd[31] == cont){ sd[30]++; if(sd[30] == buffer_rx_fw[cont]) sd[28]++; } /* end if */ } /* end for */ FIO4CLR = 0x01; /* clear GPOUTPUT 4.0 */ VICVectAddr = 0; /* dummy write */ } /* end irq_base_timer */
In this condition the problem is deterministic in the sense that every time after the first execution of irq function, CPU switches to DATA ABORT mode (the system crashes!). If I execute code step-by-step in assembly mode I see that when micro exits from irq function the LR register contains the address of an instruction that causes DATA ABORT exception. I don't know how a simple IRQ routine can generate such terrible problem!
I'm using GCC compiler (ver. 4.0.3) with optimization level 1. If I put optimization level to 0 (zero) the system doesn't crash, however the assembly code produced is so redundant to degradate system performance too much!
Have you any suggestions?
Thank you,
Demis
Thank you very much for your links! I supposed that there was a bug in GCC but this is the definitive proof! I saw the double subtraction of LR and it sounded unusual to me...efectively that was THE problem...
Thanks again!
mama miya! a compiler bug! santa maria! santa antonyo! santa clara!
From PR16634: Wrong-code for IRQ functions (gcc.gnu.org/.../msg00230.html):
AFAICS this has always been broken, so is not a regression. IMHO writing interrupt handlers directly in C is a fairly dubious feature anyway, so unless someone thinks it's important I'm defering this patch until mainline is open again.
Emphasize is mine, it looks like the GCC compiler people know something the mere mortals don't. There are some options to override his "IMHO"; use attribute naked with your own prologue/epilogue, or go commercial compiler (their IMHOs are not public). :-)
As explained in another post, I've put the IRQ and FIQ functions into a file compiled without optimizations. The body of each function consists of a single call of a function compiled in another file with optimization enabled.
In this way I have a correct prologue/epilogue and optimized interrupt functions!
Have a good compilation! ;-)
cheers