External interrupts

According to the new product page for the Due it states "interrupts 0 and 1 (pins 2 and 3 respectively)". This is the only mention of interrupts on the page. Are there not more than just two?

The chip is capable of generating an interrupt from all of the IO pins, however it looks like only those on pins 2 and 3 have been implemented.

I may be wrong as I just started looking at the code 20 minutes ago but so far that's how it looks to me.

EDIT: I delved a bit deeper, it looks like there is allowance for 8 external interrupts. The docs are probably cut and pasted from another board, maybe they are wrong.

Actually I can't see any mention of interrupts at all on the product page.


Rob

Actually interrupt*() functions are not implemented yet.

Sorry for that guys, but we didn't had the time to implement it on time for launch, this is one of our high priority for the next 1.5.1, that will be released ASAP.

Graynomad's description of interrupt capabilities is very accurate, but the current Arduino API (that we are going to implement) cannot be used to exploit all of them. An API update should be taken into account, but this is food for discussion on the developer's list on the coming weeks, for now we must stick to the current 1.0 API.

C

Just pushed attach and detach interrupt functions

i've tested the basic functionality and it seems working fine.
The actual interrupt/pin mapping is:

0 => pin 2
1 => pin 3
2 => pin 4
3 => pin 5
4 => pin 6
5 => pin 7
6 => pin 8

Note: this pin mapping is for testing purpose only. The final pin mapping will be different.

the available modes are
CHANGING, RISING, FALLING, HIGH, LOW

this pin mapping is for testing purpose only. The final pin mapping will be different.

By the time I get a Due it will be cast in stone :frowning:


Rob

Indeed I think he will have it all done before the Due actually gets out to the customers.

Thanks for keeping us in the loop over the progress. Looking forward to playing around with it.

Denbo:
Thanks for keeping us in the loop over the progress.

Yes, thanks @cmaglie and @Massimo for keeping us informed on the various things -- I've noticed you guys have been monitoring the Due forum with good frequency since the release.

@giantsfan3

Thank you :slight_smile:

@graynomad: in the end there will be no mapping at all..

With the Due board you must use the attachInterrupt directly with the pin number:

attachInterrupt(pin, callback, mode)

for example:
attachInterrupt(9, myfunction, RISING); // RISING edge on pin 9 => calls myfunction

There is no limit on the number of interrupt that can be defined. (Yes, you can setup a different interrupt function for each pin)

attachInterrupt() will be available again with Arduino IDE 1.5.1 (released on Nov, 5)

C

Thanks, good that you're using all the interrupts.

I'll be interested to look at the code and see how it compares with my LPC version.


Rob

@Graynomad here the source code:

There is an inner loop inside the interrupt handler, I've not optimized it yet really, but the response time should be <2uS.

If you have any suggestion on how to improve it you're welcome!

C

Looks like we've essentially done the same thing, I guess there's only so many ways to skin this particular cat

/////////////////////////////////////////////////////////////////////
//
// Function name:		PIOINTx_IRQHandler
//
// Description:			Replacement for the default PORT0 interrupt handler.
//
// Parameters:			none
//
// Returned value:		none
//
// Errors raised:		none
//
// Notes:				The code has to determine the pin that caused the interrupt.
//						This is done by scanning the value in the MIS register
//						looking for a 1 bit. When found the corresponding user handler
//						is called if it exists.
//
//						Whether or not the user handler exists the interrupt is cleared.
//
//						Only a single interrupt at a time is called so an active pin
//						cannot hog the system. This is implemented by maintaining a
//						counter across invocations so for example if pin 4 is handled
//						this time the scan starts from pin 5 next time.
//
//						This method however has a side effect of increasing the latency
//						considerably in systems that only have 1 or 2 external interrupts,
//						for example after handling a pin 4 interrupt the next invocation
//						has to scan 31 bits before arriving back at pin 4.
//
//						This is largely reduced by writing 0 to the __force_interrupt_scan
//						variable. In this case the next scan starts from the pin the
//						last scan ended on.
//
// TODO:				Implement a scan range to further reduce latency.
//
// Example:
//
void PIOINT0_IRQHandler() {

	static uint8 pin = 0;

	ATOMIC_START;

		uint8 x = PINS_ON_PORT0;
		uint32 misVal = LPC_GPIO0->MIS;	// get the masked interrupt flags for this port

		do {
			if (misVal & 1) {
				////////////////////////////////////////////////
				// Check for a user-defined handler, if one exists
				// then call it, clear the interrupt, increment the
				// pin counter and exit
				if (eventFunctions[EVENT_PININT_0 + pin] != NULL) {
					(eventFunctions[EVENT_PININT_0 + pin]) ();
					pinClearInterrupt(pin);
					pin = (pin > PINS_ON_PORT0 ? 0 : pin + __force_interrupt_scan);
					ATOMIC_END;
					return;
				}
				/////////////////////////////////////////////////
				// Clear the interrupt, if no user handler was called
				// the interrupt is lost.
				pinClearInterrupt(pin);
			}
			pin = (pin > PINS_ON_PORT0 ? 0 : pin +1);
			misVal >>= 1;
		} while (--x);

	ATOMIC_END;
}

One difference is that I only allow the servicing of one interrupt per invocation, I'm not convinced that a good idea or not yet :slight_smile:

There's a big difference in our attachInterrupt() functions though

void attachInterrupt (uint8_t pin, void (*func)(void), int mode) {

	switch (mode) {

		case LOW:
			pinSetInterruptMode(pin, PININT_LOW_LEVEL);
			break;

		case CHANGE:
			pinSetInterruptMode(pin, PININT_BOTH_EDGES);
			break;

		case FALLING:
			pinSetInterruptMode(pin, PININT_FALLING_EDGE);
			break;

		case RISING:
			pinSetInterruptMode(pin, PININT_RISING_EDGE);
			break;

	}

	attachEventHandler(EVENT_PININT_0 + pin, func);
	pinEnableInterrupt(pin);

}

Although I suspect that if I inserted the code from the function calls they would be similar. Note that this is a function that's part of my Arduino port, it maps the Arduino call to my LPC equivalent, that's really why there's no real work done here.

I work with a flat model of the pins, at this level I don't care what port they are on or anything. Also I'm implementing a system of "events" whereby everything that happens on the system is an event that can have a user function supplied if required. Pin interrupts are simply another 55 events.


Rob