Pages: 1 2 3 [4]   Go Down
Author Topic: PinChangeInt library- To attach interrupts to multiple Arduino (Uno/Due) pins  (Read 17426 times)
0 Members and 2 Guests are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I assume its a memory leak as my understanding is that delete does not free memory in Arduino and the current implementation of detach seems to assume that delete works.
Yes, I ran a test and noticed that my memory got gobbled up pretty quickly. Drat!!! ...The problem is not merely in delete(), because delete just calls free().  The problem is that free() doesn't seem to work.

Anyway, regardless of that I like your idea of having detachInterrupt() simply disable the pin from interrupting, rather than using the delete() operator. I am working on it doing just that.

attachInterrupt() will return -1 on error, 0 if the pin has already been added to the list (the pin will be enabled if it is called and had previously been created already), and 1 if a new pin is created.
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 22
Posts: 1675
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Perfect, I will post a link to this topic from the two related threads so that the ops are aware of this and can follow the progress.

Thanks

Duane B
Logged


Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 197
Posts: 12744
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In both topics, the ops would like to detach pin change interrupts and later reattach them to enter and exit autonomous and RC Modes.

Is that done in the context of the interrupt handler?
Logged

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

******************************************************************************

        PinChangeInt
        ---- RELEASE NOTES ---

******************************************************************************
Version 2.13 (beta) Mon Nov 12 09:33:06 CST 2012
SIGNIFICANT BUGFIX release! Significant changes:
1. PCintPort::curr bug. Interrupts that occur rapidly will likely not get serviced properly by PCint().
2. PCint() interrupt handler optimization.
3. PCIFR port bit set bug fix.
4. Many static variables added for debugging; used only when #define PINMODE is on.
5. detachInterrupt() no longer does a delete(), since that wasn't working anyway. When you detachInterrupt(), the PORT just disables interrupts for that pin; the PCintPin object remains in memory and in the linked list of pins (possibly slowing down your interrupts a couple of micros).  You can reenable a detached interrupt- but you must do it within the PinChangeInt library (would anyone ever enable an interrupt on a pin, then disable it, then have need to reenable it but not using the library?).
6. attachInterrupt() now returns a uint8_t value:  1 on successful attach, 0 on successful attach but using an already-enabled pin, and -1 if the new() operator failed to create a PCintPin object.
Also, modified these release notes.

Details:

Uncovered a nasty bug, thanks to robtillaart on the Arduino Forums and Andre' Franken who posted to the PinChangeInt groups. This bug was introduced by me when I assigned PCintPort::curr early in the interrupt handler:
Code:
ISR(PCINT0_vect) {
    PCintPort::curr = portB.portInputReg;
    portB.PCint();
}
Later, in the interrupt handler PCint(), we loop as long as PCIFR indicates a new interrupt wants to be triggered, provided DISABLE_PCINT_MULTI_SERVICE is not defined (it is not by default):
Code:
#ifndef DISABLE_PCINT_MULTI_SERVICE
        pcifr = PCIFR & PCICRbit;
        PCIFR = pcifr;  // clear the interrupt if we will process it (no effect if bit is zero)
} while(pcifr);
#endif
...Well. Problem is, if a pin pops up and causes the PCIFR to change, we have to reread the port and look at how it is now! I wasn't doing that before, so if a new interrupt appeared while I was still servicing the old one, odd behavior would take place. For example, an interrupt would register but then the userFunc would not be called upon to service it.  The code needs to be:
Code:
        pcifr = PCIFR & PCICRbit;
        PCIFR = pcifr;  // clear the interrupt if we will process it (no effect if bit is zero)
        PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
} while(pcifr);

Also, made the interrupt handler even faster with an optimization from robtillaart to take out the checks for changed pins from the while() loop that steps through the pins:
Code:
uint8_t changedPins = (PCintPort::curr ^ lastPinView) &
                      ((portRisingPins & PCintPort::curr ) | ( portFallingPins & ~PCintPort::curr ));
...This speedup is offset by more changes in the PCint() handler, which now looks like the following; there are two bug fixes:
----------------------------
FIX 1: sbi(PCIFR, PCICRbit);
FIX 2: ...the aforementioned PCintPort::curr=portInputReg;
Here's the new code:
----------------------------
Code:
    #ifndef DISABLE_PCINT_MULTI_SERVICE
        pcifr = PCIFR & PCICRbit;
        if (pcifr) {
        //if (PCIFR & PCICRbit) { // believe it or not, this adds .6 micros
            sbi(PCIFR, PCICRbit); // This was a BUG: PCIFR = pcifr  ...And here is the fix.
            #ifdef PINMODE
            PCintPort::pcint_multi++;
            if (PCIFR & PCICRbit) PCintPort::PCIFRbug=1; // PCIFR & PCICRbit should ALWAYS be 0 here!
            #endif
            PCintPort::curr=portInputReg; // ...Fixed in 2.11beta.
            goto loop;  // A goto!!! Don't want to look at the portInputReg gratuitously, so the while() will not do.
        }
    #endif

Also I added a lot of variables for debugging when PINMODE is defined, for routing out nasty bugs. I may need them in the future... :-(

Finally, I am not putting newlines in this commentary so I can make it easier to paste online.
Logged

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BTW, I am still testing this release but I wanted it to get out there because I uncovered some nasty bugs. They made my interrupts unreliable! So it's important if you use this code, to realize that the new version should work better.

I realized that about 5-10% of my interrupts were missed due to my switch bounce; some of the bounces happen only 50 microseconds apart or so. And my code was not processing them properly. With this code, I notice that my switches are more reliable.

I also notice that I am not getting the speed bump that I hoped to get, and some of my bugfixes actually introduce a few extra microseconds of processing. This is disappointing and I hope to find them if I can.
Logged

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I already thought of a bug in v. 2.13beta.  If you detach an interrupt and attach it again, and give it a new user function, it will not attach the new user function- it will use the first user function that you attached.

However you are able to change the mode at this point (RISING, FALLING, or CHANGE).
Logged

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Version 2.15beta is out now, and I allow for attaching a new user function. I don't know if anyone would really do that, but there should be no nasty surprises in the code, and attachInterrupt() will thus do exactly what you tell it to do in the argument list.

URL: http://code.google.com/p/arduino-pinchangeint/
« Last Edit: November 18, 2012, 09:40:34 pm by GreyGnome » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

1) goto loop: ? why not use break?

addpcint
Code:
if (firstPin != NULL) {
tmp=firstPin;
if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
while (tmp->next != NULL) {
tmp=tmp->next;
if (tmp->arduinoPin == arduinoPin)  { enable(tmp, userFunc, mode); return(0); }
};
}

shorter == smaller footprint? faster?
Code:
if (firstPin != NULL) {
tmp=firstPin;
                do {
        if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0);
                        tmp=tmp->next;
                } while (tmp != NULL);
}

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the input. This saved 12 bytes; I haven't measured the speed:
Code:
    if (firstPin != NULL) {
        tmp=firstPin;
        do {
            if (tmp->arduinoPin == arduinoPin) { enable(tmp, userFunc, mode); return(0); }
            if (tmp->next == NULL) break;
            tmp=tmp->next;
        } while (true);
    }

I have also converted the goto to a do/while/break situation. No change to interrupt speed, but I guess it looks better :-).
Logged

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
                } while (tmp != NULL);
This won't work because tmp will become null, which will exit us from the loop.

I need tmp->next later in the code, therefore I need the last non-null value of tmp.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

oops,
 I figured that out too and you replied while I removed my previous post,
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Jr. Member
**
Karma: 4
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Version 2.19beta has been released. The library now includes Sanguino support. There have been a number of recent bugfixes, so be sure to look at the Release Notes. If you have any library prior to version 2.17beta, it is highly recommended that you upgrade to 2.17beta or later.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 27
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hey,

I like to use the PINCHANGE Library with the Arduino DUE.
But I still get this failure:
Code:
In file included from FirstTask.ino:24:
.....\Arduino\libraries\PinChangeInt/PinChangeInt.h:103: fatal error: new.h: No such file or directory
compilation terminated.
Maybe some know this failure?

I need to use the pinchange lib because I need to know of many pins, which pin has changed without using for every pin a own function like this:
Code:
     attachInterrupt(1, action1, HIGH);
attachInterrupt(2, action2, HIGH); 

Maybe someone knows also an alternative solution :-)
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13479
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(very little Due experience)
you could try to uncomment it , and see if it is needed for the DUE
The DUe is an ARM processor while the lib was originally written for the AVR.

just a thought!
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Belgium
Offline Offline
Edison Member
*
Karma: 68
Posts: 1897
Arduino rocks; but with my plugin it can fly rocking the world ;-)
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

hey,

I like to use the PINCHANGE Library with the Arduino DUE.
But I still get this failure:
Code:
In file included from FirstTask.ino:24:
.....\Arduino\libraries\PinChangeInt/PinChangeInt.h:103: fatal error: new.h: No such file or directory
compilation terminated.
Maybe some know this failure?

I need to use the pinchange lib because I need to know of many pins, which pin has changed without using for every pin a own function like this:
Code:
     attachInterrupt(1, action1, HIGH);
attachInterrupt(2, action2, HIGH); 

Maybe someone knows also an alternative solution :-)

Not sure why you would need that.
The attach interrupt doc at http://arduino.cc/en/Reference/AttachInterrupt clearly states:
Quote
The Arduino Due board has powerful interrupt capabilities that allows you to attach an interrupt function on all available pins. You can directly specify the pin number in attachInterrupt().
The overhead of creating a function for each pin is probably nothing compared to linking and porting the pinchangeint lib.
Not that I would care about the size of the program or data when writing code for the due.
Best regards
Jantje
Logged

Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

Pages: 1 2 3 [4]   Go Up
Jump to: