Hello.
I'm using Keil Realview compiler with a MCB2300 board (LPC2378). In my program I have 2 IRQ handlers (for Uart and timer 0) and 1 fiq handler (ADC).
When I run the program without nested interrupts it all works fine. But with nested interrupts the program crashes at random times and ends up in prefetch abort mode.
Below is the all the code related to the irq's and fiq. Does someone have any idea what's going wrong?
Kind regards, Sander Wiggers
/****************************************/ /* STARTUP.S */ /****************************************/ EXTERN adc_isr AREA RESET, CODE, READONLY PRESERVE8 ARM Vectors LDR PC, Reset_Addr LDR PC, Undef_Addr LDR PC, SWI_Addr LDR PC, PAbt_Addr LDR PC, DAbt_Addr NOP ; Reserved Vector ; LDR PC, IRQ_Addr LDR PC, [PC, #-0x0120] ; Vector from VicVectAddr LDR PC, FIQ_Addr Reset_Addr DCD Reset_Handler Undef_Addr DCD Undef_Handler SWI_Addr DCD SWI_Handler PAbt_Addr DCD PAbt_Handler DAbt_Addr DCD DAbt_Handler DCD 0 ; Reserved Address IRQ_Addr DCD IRQ_Handler FIQ_Addr DCD FIQ_Handler Undef_Handler B Undef_Handler SWI_Handler B SWI_Handler PAbt_Handler B PAbt_Handler DAbt_Handler B DAbt_Handler IRQ_Handler B IRQ_Handler FIQ_Handler B adc_isr /*************************** FUNCTION ************************************/ uint32 install_irq(uint32 int_number, void *handler_addr, uint32 priority ) { uint32 *vect_addr; uint32 *vect_cntl; VICIntEnClr = 1 << int_number; /* Disable Interrupt */ if(int_number >= VIC_SIZE ) { return(FALSE); } else { /* find first un-assigned VIC address for the handler */ vect_addr = (uint32 *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + int_number*4); vect_cntl = (uint32 *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + int_number*4); *vect_addr = (uint32)handler_addr; /* set interrupt vector */ *vect_cntl = priority; VICIntEnable = 1 << int_number; /* Enable Interrupt */ return(TRUE); } } /*********************************************/ void init_adc(void) /*********************************************/ { .... .... PCLKSEL0 |= (0x01 << 24); /* Set ADC clock to CPU clock */ PCONP |= (1 << 12); /* Enable CLOCK into ADC controller */ PINSEL1 |= (0x01 << 14) | (0x01 << 16) | (0x01 << 18); AD0CR = (0x07 << 0) | /* SEL = 3, select channel 0 and 1 on ADC0 */ (15 << 8) | /* CLKDIV - 1 */ (0 << 16) | /* BURST = 0, software controlled */ (0 << 17) | /* CLKS = 0, 11 clocks/10 bits */ (1 << 21) | /* PDN = 1, normal operation */ (0 << 22) | /* TEST1: 0 = 00 */ (0 << 24) | /* START = 0 A/D conversion stops */ (0 << 27) ; /* EDGE = 0 (CAP/MAT singal falling, trigger A/D conversion) */ VICIntSelect = (0x00000001 << ADC0_INT); VICIntEnable = (0x00000001 << ADC0_INT); } /*****************************************/ void adc_isr(void) __irq /*****************************************/ { static uint8 adc_sample_count = (uint8)ADC_SAMPLE_COUNT; static uint32 adc_value[3]; adc_value[0] += (*((uint16*)(ADC_DATA_REGISTER + 0))); adc_value[1] += (*((uint16*)(ADC_DATA_REGISTER + 4))); adc_value[2] += (*((uint16*)(ADC_DATA_REGISTER + 8))); FIO2SET = 0x00000040; ..... ..... ..... FIO2CLR = 0x00000040; VICVectAddr = 0; /* Acknowledge interrupt */ } /*****************************************/ void timer0_isr(void) __irq /*****************************************/ { T0IR = 0x01; /* Clear Timer0 interrupt */ IENABLE; /* handles nested interrupt */ .... .... .... IDISABLE; VICVectAddr = 0; /* Acknowledge interrupt */ } /*****************************************/ void uart_isr(void) __irq /*****************************************/ { uint8 iir_value; IENABLE; /* handles nested interrupt */ iir_value = U0IIR; if((iir_value & 0x01) == 0x00) { if((iir_value & 0x0E) == 0x02) /* Transmit buffer empty interrupt */ uart_tx_isr(); if((iir_value & 0x0E) == 0x04) /* Receive buffer full interrupt */ uart_rx_isr(); } IDISABLE; VICVectAddr = 0; /* Acknowledge interrupt */ } static uint32 sysreg; /* used as LR register */ #define IENABLE __asm { MRS sysreg, SPSR; MSR CPSR_c, #SYS32Mode } #define IDISABLE __asm { MSR CPSR_c, #(IRQ32Mode|I_Bit); MSR SPSR_cxsf, sysreg }