EINTx on LPC2148 problem

Hi all,

I am trying to use EINT3 on LPC2148 in Logomatic2.

When EINT3 is triggered, it runs the ISR but it doesn’t come back to main in the end.

I have defined a Nonvectored interrupt, and it is performed, after this interrupt is done, it goes back to main, to where it came from. But If I don’t define nonvectored interrupt, It resets the Microcontroller.

void __attribute__ ((interrupt("IRQ"))) NonVectored(void) 
{
    rprintf("NonVectored\n\r");
}

void __attribute__ ((interrupt("IRQ")))  EINT3_routine(void) 
{
    rprintf("Vectored\n\r");
    EXTINT 	= 0x08;		// clear interrupt 
    VICVectAddr = 0;		// Acknowledge Interrupt 
}

void VICInit(void)
{
    enableIRQ();
    PINSEL0 |= 0x000C0000;   //make P0.9 EINT3
    EXTMODE = 0x08;             //Edge Trigger
    EXTPOLAR = 0x00;            //falling Edge
    VICIntSelect = 0x00;         //normal IRQ
    VICIntEnable = 0x00020000;      //Enable EINT3
    VICVectCntl0 = 0x31;         //set for EINT3
    VICVectAddr0 = (unsigned long) EINT3_routine;
    VICDefVectAddr = (unsigned long) NonVectored;
}

main() { ...VICInit() ...}

I would be thankful if you help me.

Regards

Hi

When using vectored interrupts your handler needs to read the interrupt from the VICVectAddr (0xffffff030) and then call the interrupt routine.

How this is done depends on the general interrupt handler code and possibly compiler - the last time I tried using GCC it didn’t work due to a bug and so an interrupt dispatcher was needed (a general interrupt handler which loads the address and jumps there - the interrupt routine itself is then not declared as interrupt but as normal sub-routine since the dispatcher performs the IRQ part.

If using a compiler that can do this it does something like this:

; Reset entry point
		MODULE	?RESET
		COMMON	INTVEC:CODE:NOROOT(2)
		PUBLIC  __program_start
		EXTERN	?cstartup
                CODE32	; Always ARM mode after reset
		ORG	0x00            ; reset starts at address 0
__program_start
		ldr	pc,[pc,#24]	; Branch to program start
		org	0x04
		ldr	pc,[pc,#24]	; Branch to undef_handler
		org	0x08
		ldr	pc,[pc,#24]	; Branch to swi_handler
		org	0x0c
		ldr	pc,[pc,#24]	; Branch to prefetch_handler
		org	0x10
		ldr	pc,[pc,#24]	; Branch to data_handler
        org	0x18
        LDR     PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
		org	0x1c
		ldr	pc,[pc,#24]	; Branch to fiq_handler

In this case the line

LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr

does a direct branch to the interrupt routine (which is also a real interrupt routine and so much be declared correctly).

As mentioned before - I am not sure that this works with GCC since it doesn’t correctly handle the method.

Regards

Mark

[www.uTasker.com](http://www.uTasker.com)

I use the mode where you store the address of the ISR in the interrupt number and let the hardware do the vectoring.

stevech:
I use the mode where you store the address of the ISR in the interrupt number and let the hardware do the vectoring.

Hi thanks for the answer, but may I ask How exactly you do it?

durin this time I tried to use Keil, but I cannot, because I need to use SDMemory and also the Sparkfun bootlaoder so Keil doesnät build FW.SFE and nither has a good examples like bubblelogger and logomatic example that I can easyly chang for my own application. But for now I definitely need to use external interrupts there.

Also dear mjbcswitzerland, I really donät think I can change the Startup.S is seems to be so complicated.

Best regards

I find it easier to have a common vector and dispatch, but use the VIC to store a pointer to device context for the device. (Including func ptr/vtable entry to the device interrupt handler.) This means you load up the VIC with addresses of device structures but set the vector itself not to read from the VIC but jump to a fixed handler. I also do this because I like to save thread state and update the VIC enable bits to implement IPLs. The common handler in my case also saves thread state. Kinda repetitive to make every device interrupt handler have to do that, although it would probably save 5 instructions or so. (But running out of internal NOR flash that’s negligible. And there’s always FIQ for even better latency.)

In my soft-IPL model each device context structure (class Device) contains two 32-bit values that are loaded into two VIC registers by the common handler, and the device interrupt handler then reenables interrupts if it wants to. A Device::SetIPL() method computes the values to use for each device - basically a mask with only the devices enabled that have higher IPLs. When the device interrupt handler is invoked the CPU is at that soft IPL. I try to do as much as possible out of interrupt using elevated priority threads, especially things like ethernet drivers and protocol processing. All the ethernet drive does for instance is to signal a condition on the Device that wakes a thread that then performs mac/ip processing. So it’s pretty cheap, reasonable latency, and fully preemptible; when the ethernet interrupt handler the protocol thread is the one reloaded on return, if nothing of higher priority is already running. Schedulers IMO are better than IPLs and VIC masking, and it’s more SMP friendly. (Although using a shared controller.) I like to resort to interrupt masking and priorities only when either a scheduler can’t really do something, or as low-level glue (cross the t’s and dot the i’s kinda thing).