From 4dc46149143c22f87bb9d4a2331a1b0a2455ed1d Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 3 May 2007 00:29:56 +0000 Subject: [PATCH] Completes coding of basic interrupt handling logic git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@199 42af7a65-404d-4744-a932-0658087f49c3 --- arch/arm/include/lpc214x/irq.h | 2 + arch/arm/src/lpc214x/chip.h | 2 +- arch/arm/src/lpc214x/lpc214x_decodeirq.c | 39 +++++++---- arch/arm/src/lpc214x/lpc214x_irq.c | 82 +++++++++++++++++------- arch/arm/src/lpc214x/lpc214x_vic.h | 6 ++ 5 files changed, 95 insertions(+), 36 deletions(-) diff --git a/arch/arm/include/lpc214x/irq.h b/arch/arm/include/lpc214x/irq.h index 457a903d8b..1542ee290b 100644 --- a/arch/arm/include/lpc214x/irq.h +++ b/arch/arm/include/lpc214x/irq.h @@ -80,7 +80,9 @@ * Public Types ************************************************************/ +#ifndef __ASSEMBLY__ typedef void (*vic_vector_t)(uint32 *regs); +#endif /************************************************************ * Inline functions diff --git a/arch/arm/src/lpc214x/chip.h b/arch/arm/src/lpc214x/chip.h index 807777fd8e..84cdf4c135 100644 --- a/arch/arm/src/lpc214x/chip.h +++ b/arch/arm/src/lpc214x/chip.h @@ -68,7 +68,7 @@ #define LPC214X_PLL_BASE 0xe01fc080 /* Phase Locked Loop (PLL) Base Address */ #define LPC214X_VPBDIV 0xe01fc100 /* VPBDIV Address */ #define LPC214X_EMC_BASE 0xffe00000 /* External Memory Controller (EMC) Base Address */ -#define LPC214X_VIC_BASE 0xffff0000 /* Vectored Interrupt Controller (VIC) Base */ +#define LPC214X_VIC_BASE 0xfffff000 /* Vectored Interrupt Controller (VIC) Base */ /* UART0/1 Register Offsets */ diff --git a/arch/arm/src/lpc214x/lpc214x_decodeirq.c b/arch/arm/src/lpc214x/lpc214x_decodeirq.c index f28be26061..f90feb9c72 100644 --- a/arch/arm/src/lpc214x/lpc214x_decodeirq.c +++ b/arch/arm/src/lpc214x/lpc214x_decodeirq.c @@ -65,6 +65,10 @@ * Private Data ********************************************************************************/ +/* This type arry maps 4 bits into the bit number of the lowest bit that it set */ + +static uint8 g_nibblemap[16] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + /******************************************************************************** * Private Functions ********************************************************************************/ @@ -108,19 +112,34 @@ static void lpc214x_decodeirq( uint32 *regs) PANIC(OSERR_ERREXCEPTION); #else - /* Decode the interrupt. First, fetch the interrupt id register. */ + /* Decode the interrupt. We have to do this by search for the lowest numbered + * non-zero bit in the interrupt status register. + */ - int irq = 0; -#warning "Need to decode the interrupt here" + uint32 pending = vic_getreg(LPC214X_VIC_IRQSTATUS_OFFSET) & 0x007fffff; + unsigned int nibble; + unsigned int irq_base; + unsigned int irq = NR_IRQS; - /* Verify that the resulting IRQ number is valie */ + /* Search in groups of four bits. For 22 sources, this is at most five + * times through the loop. + */ - if ((unsigned)irq < NR_IRQS) + for (nibble = pending & 0xff, irq_base = 0; + pending && irq < NR_IRQS; + pending >>= 4, nibble = pending & 0xff, irq_base += 4) { - /* Mask and acknowledge the interrupt */ + if (nibble) + { + irq = irq_base + g_nibblemap[nibble]; + break; + } + } - up_maskack_irq(irq); + /* Verify that the resulting IRQ number is valid */ + if (irq < NR_IRQS) + { /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -134,12 +153,6 @@ static void lpc214x_decodeirq( uint32 *regs) /* Indicate that we are no long in an interrupt handler */ current_regs = NULL; - - /* Unmask the last interrupt (global interrupts are still - * disabled. - */ - - up_enable_irq(irq); } #endif } diff --git a/arch/arm/src/lpc214x/lpc214x_irq.c b/arch/arm/src/lpc214x/lpc214x_irq.c index 8105fd8978..37609a6dd4 100644 --- a/arch/arm/src/lpc214x/lpc214x_irq.c +++ b/arch/arm/src/lpc214x/lpc214x_irq.c @@ -76,12 +76,14 @@ void up_irqinitialize(void) { int reg; - /* Acknowledge and disable all interrupts */ + /* Disable all interrupts. We do this by writing zero to the IntEnable + * register. This is equivalent to writing all ones to the IntClearEnable + * register. + */ - vic_putreg(0, LPC214X_VIC_INTENCLEAR_OFFSET); vic_putreg(0, LPC214X_VIC_INTENABLE_OFFSET); - /* All IRQs, no FIQs */ + /* Select all IRQs, no FIQs */ vic_putreg(0, LPC214X_VIC_INTSELECT_OFFSET); @@ -98,8 +100,6 @@ void up_irqinitialize(void) vic_putreg(0, reg); } -#warning "Not implemented" - /* currents_regs is non-NULL only while processing an interrupt */ current_regs = NULL; @@ -121,7 +121,16 @@ void up_irqinitialize(void) void up_disable_irq(int irq) { -#warning "Not implemented" + /* Verify that the IRQ number is within range */ + + if (irq < NR_IRQS) + { + /* Disable the irq by setting the corresponding bit in the VIC + * Interrupt Enable Clear register. + */ + + vic_putreg((1 << irq), LPC214X_VIC_INTENCLEAR_OFFSET); + } } /**************************************************************************** @@ -134,34 +143,55 @@ void up_disable_irq(int irq) void up_enable_irq(int irq) { -#warning "Not implemented" -} + /* Verify that the IRQ number is within range */ -/**************************************************************************** - * Name: up_maskack_irq - * - * Description: - * Mask the IRQ and acknowledge it - * - ****************************************************************************/ + if (irq < NR_IRQS) + { + /* Disable all interrupts */ -void up_maskack_irq(int irq) -{ -#warning "Not implemented" + irqstate_t flags = irqsave(); + + /* Enable the irq by setting the corresponding bit in the VIC + * Interrupt Enable register. + */ + + uint32 val = vic_getreg(LPC214X_VIC_INTENABLE_OFFSET); + vic_putreg(val | (1 << irq), LPC214X_VIC_INTENCLEAR_OFFSET); + irqrestore(flags); + } } /**************************************************************************** * Name: up_attach_vector * * Description: - * Assign + * Attach a user-supplied handler to a vectored interrupt * ****************************************************************************/ #ifndef CONFIG_VECTORED_INTERRUPTS void up_attach_vector(int irq, int vector, vic_vector_t handler) { -#warning "Not implemented" + /* Verify that the IRQ number and vector number are within range */ + + if (irq < NR_IRQS && vector < 16 && handler) + { + int offset = vector << 2; + + /* Disable all interrupts */ + + irqstate_t flags = irqsave(); + + /* Save the vector address */ + + vic_putreg((uint32)handler, LPC214X_VIC_VECTADDR0_OFFSET + offset); + + /* Enable the vectored interrupt */ + + vic_putreg(((irq << LPC214X_VECTCNTL_IRQSHIFT) | LPC214X_VECTCNTL_ENABLE), + LPC214X_VIC_VECTCNTL0_OFFSET + offset); + irqrestore(flags); + } } #endif @@ -169,13 +199,21 @@ void up_attach_vector(int irq, int vector, vic_vector_t handler) * Name: up_detach_vector * * Description: - * Mask the IRQ and acknowledge it + * Detach a user-supplied handler from a vectored interrupt * ****************************************************************************/ #ifndef CONFIG_VECTORED_INTERRUPTS void up_detach_vector(int vector) { -#warning "Not implemented" + /* Verify that the vector number is within range */ + + if (vector < 16) + { + /* Disable the vectored interrupt */ + + int offset = vector << 2; + vic_putreg(0, LPC214X_VIC_VECTCNTL0_OFFSET + offset); + } } #endif diff --git a/arch/arm/src/lpc214x/lpc214x_vic.h b/arch/arm/src/lpc214x/lpc214x_vic.h index d9b60501f5..dcc297030f 100755 --- a/arch/arm/src/lpc214x/lpc214x_vic.h +++ b/arch/arm/src/lpc214x/lpc214x_vic.h @@ -49,6 +49,12 @@ #define vic_getreg(o) getreg32(LPC214X_VIC_BASE+(o)) #define vic_putreg(v,o) putreg32((v),LPC214X_VIC_BASE+(o)) +// Vector Control Register bit definitions + +#define LPC214X_VECTCNTL_IRQMASK (0x0000001f) +#define LPC214X_VECTCNTL_IRQSHIFT (0) +#define LPC214X_VECTCNTL_ENABLE (1 << 5) + /************************************************************************************ * Public Types ************************************************************************************/