This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nesting irq and fiq

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 }

0