Best practice for libraries sharing hardware resources like interrupts?

Hi,

I'm developing a little weather station. It has a GSM module attached to send weather data to the server. The GSM Shield use pin 7 and 8 for reading and writing data using the SoftwareSerial library.

The windspeed sensor gives two pulses per rotation and is attached to pin 10. I use the PinChangeInt library to define an interrupt on this pin.

I'm currently trying to get this to work on Arduino 1.0. I had it working on 023 but wanted to move to 1.0. In 023 I used NewSoftSerial which is now the SoftwareSerial in 1.0. Though SoftwareSerial defines interrupts for all Pin Change Interrupts and thus without removing some in SoftwareSerial I cannot get PinChangeInt to compile.

In a more normal C environment a couple of defines in the beginning of the code could easily make the compiler to include enough interrupts definitions needed but due to Arduinos a bit weird preprocessor it does not work to something like this in my sketch:

#define DO_NOT_USE_PORTC // disable SoftwareSerial interrupts on A0-A5
#define DO_NOT_USE_PORTB // disable SoftwareSerial interrupts on D9-D13
#define	NO_PORTD_PINCHANGES // disable PinChangeInt on D0-D8

So right now my solution is to go into the Arduino installation, change the SoftwareSerial.cpp file in the installation to only use PORTD and PinChangeInt has a PinChangeIntConfig.h file where I can define which ports it should use. But this is not manageble in the long run, when I start my next project my hardware might look completely different and I need to change the installed files and thus this project wont compile any longer....

So how do you solve these kind of issues? One Arduino installation per project? But wont Preferences start to conflict? I would like to hear how you sort this out without ending up in a mess of libraries all created for specific projects...

Thanks, and Happy Holidays everyone :slight_smile:

http://www.arduino.cc/playground/Main/PinChangeInt

For example if only port D has pin change interrupts connected:

#define NO_PORTB_PINCHANGES
#define NO_PORTC_PINCHANGES

Will either of those mask out defines that conflict with your Software Serial defines?
If they can but don't then why not code that into pinChangeInt?

To answer the question in the header:
Best practice for sharing is to do nothing unless the User asks for it. Thus, the SoftwareSerial library should not modify interrupts for ports other than what you specifically request.
Relying on defines is troublesome because the same files may be included from different sources with different defines.

GoForSmoke:
http://www.arduino.cc/playground/Main/PinChangeInt

For example if only port D has pin change interrupts connected:

#define NO_PORTB_PINCHANGES
#define NO_PORTC_PINCHANGES

Will either of those mask out defines that conflict with your Software Serial defines?
If they can but don't then why not code that into pinChangeInt?

Yes they will, this is how the PinChangeInt code looks like:

#ifndef NO_PORTB_PINCHANGES
ISR(PCINT0_vect) {
	PCintPort::pcIntPorts[0].PCint();
}
#endif

#ifndef NO_PORTC_PINCHANGES
ISR(PCINT1_vect) {
	PCintPort::pcIntPorts[1].PCint();
}
#endif

#ifndef NO_PORTD_PINCHANGES
ISR(PCINT2_vect) {
	PCintPort::pcIntPorts[2].PCint();
}
#endif

The problem with Arduino IDE is that it wont help to have those defined in the sketch. And even more problematic is that SoftwareSerial includes the following code:

#if defined(PCINT0_vect)
#ifndef DO_NOT_USE_PORTB
{
  SoftwareSerial::handle_interrupt();
}
#endif

#if defined(PCINT1_vect)
ISR(PCINT1_vect)
{
  SoftwareSerial::handle_interrupt();
}
#endif

#if defined(PCINT2_vect)
ISR(PCINT2_vect)
{
  SoftwareSerial::handle_interrupt();
}
#endif

#if defined(PCINT3_vect)
ISR(PCINT3_vect)
{
  SoftwareSerial::handle_interrupt();
}
#endif

which wont mask out any interrupt definitions but I added #ifndef DO_NOT_USE_PORT for each to be able to mask them aout but still I have to define in SoftwareSerila.h and not in my sketch which to use/not use which makes it very unpractical in the long run.

But as jwatte suggest it would be a better practice for both PinChangeInt and SoftwareSerial to require the one using the library to do the following in his/her sketch:

// make SoftwareSerial catch interrupts on pin 7 and 8, port D
ISR(PCINT2_vect)
{
  SoftwareSerial::handle_interrupt();
}

and

// make PinChangeInt catch interrupts on pin 10, port B
ISR(PCINT0_vect) {
	PCintPort::pcIntPorts[0].PCint();
}

Correct? Or is there a better solution?

Thanks,
/Kalle

This all takes time. It might be overdesign for what is basically a tiny processor system.

In your case, why not just use D2/D3 hardware interrupts? Personally I don't particularly like pin-change interrupts, because for one thing the interrupt code is shared. Short of your vectoring idea, it isn't particularly easy to make a pin-change interrupt just for one pin for library A, and another one for library B.

What are D2/D3 hardware interrupts?? I'm not very familiar with the hardware details of Arduino, I'm much more of a software guy as you might have noticed and for me i't's natural to create something that is modular and easily re-useable. And SoftwareSerial nor PinChangeInt are my constructions, the first is part of the Arduino IDE and the second a library I downloaded. And I'm just trying to figure out a way to have them play along nicely which doesn't seem to be the case.

See attachInterrupt.

Both pins generate a dedicated interrupt on rising, falling, change or low signals. This seems an ideal place to attach your windspeed sensor. And it won't conflict with the software serial interrupts.

Aaah, you mean pin D2 and D3. Don't know how I had missed that!! Thanks!

Just note that hardware serial does use those pins.

No, on the Atmega328 hardware serial is just on pins D0/D1.

Son of a gun, I got pin 2&3 mixed up with PD2&PD3 some time back and it kinda made sense that hardware serial would use the interrupts. But I look at the pin map and sure enough INT0&INT1 are clear. Good news for me.

Mostly I dedicate IDE is whole Ardunio folder for a project. Rename the folder with my project name. play , make any changes needed. i change the necessary changes to the core files. as the need of my project. I edit core for time critical routines. like which i need to run on defined timer. like i edit timer0 for my need removing off its millis and all that stuff. set my timer as my application needs. then write another code for delay where i can do delay(), but most of my functions are just based on counter that runs in timer isr. when the counter is reached. function specific flag is made high. in this way my single counter sets as many function flags. these flags are continue-sly checked in loop() and if it finds set respective function is called. and during execution the flag is cleared too. but I always dedicate one IDE for each project. in other words I only bother to take pains where functions are critical, for rest I use spoon feed by arduino.

I_think:
Mostly I dedicate IDE is whole Ardunio folder for a project. Rename the folder with my project name. play , make any changes needed. i change the necessary changes to the core files. as the need of my project. I edit core for time critical routines. like which i need to run on defined timer. like i edit timer0 for my need removing off its millis and all that stuff [...] but I always dedicate one IDE for each project.

Just a question, maybe this is possible and I just missed how to do this.
However, I'd like to do this in a more clean way.

Maybe there exists an environment variable that you can modify so that an application-specific library directory can take precedence to the common library directories?
This would be very nice if you have to make project-specific library changes/optimizations.

Anyway, this is just one of the difficulties with the IDE why I am atm trying to get the makefile approach work, just to avoid cumbersome and error-prone kludging with the IDE.

BTW, version 1.4 of PinChangeInt now allows you to modify your #define's in your sketch. So they can be different on a sketch-by-sketch basis. See Google Code Archive - Long-term storage for Google Code Project Hosting.

As Nick said, if you have an Arduino Uno and have only 2 interrupt pins, the "External Interrupt" pins (pins 2 and 3 of the Arduino) are probably your best bet. If you need to interrupt more than 2 pins, Pin Change interrupts are the only way to go.