Author Topic: pin change interrupts Moteino Mega - pinChange [solution/library]  (Read 9000 times)

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Hi All,

Trying to get a button to work on a pin change interrupt.

Button (from lowpowerlabs shop) is connected to A6 and 3.3v

I want to wake the 1284p from sleep, and/or register the button has been pressed - nothing fancy yet.

Any ideas why this does not work?

Code: [Select]
#include <LowPower.h>
#include <avr/interrupt.h>

volatile int pinChanged;

void setup() {
 
  pinChanged = 0;

  pinMode(A6, INPUT);
  digitalWrite(A6, HIGH);
 
  PCICR |= (1<<PCIE0);       //enable group interrupts on PORTA PCINT[7:0]
  PCMSK0 |= (1<<PCINT6);
  sei();
  Serial.begin(9600);
}
void loop() {
 
  // woken up, either because the button was pressed or we
  // woke up naturally
  Serial.flush();
 
  if (pinChanged == 1) {
    Serial.println("Button pressed!!!");
  } else {
    Serial.println("We woke up naturally");
  }
 
  doStuff();

  if (pinChanged == 1) {
    Serial.println("Button pressed");
  }

  // going to kip
  Serial.println("nite!!!");
  Serial.flush();
  pinChanged = 0;
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

ISR(PCINT0_vect) {
  pinChanged = 1;
}


void doStuff() {
  // just sleep for 3 secs
  Serial.println("Doing stuff");
  delay(3000);
}

Does not work defined as;

- pressing button does not wake up from sleep - something I expected pin change interrupts to do
- pressing button does not set pinChanged INT to 1 - which would result in Serial output printing something different.

On a plus side it is sleeping nicely between loops.
« Last Edit: July 16, 2015, 08:41:52 AM by Felix »

rdww60

  • NewMember
  • *
  • Posts: 3
Re: pin change interrupts Moteino Mega
« Reply #1 on: June 29, 2015, 05:28:39 PM »
attachInterrupts();
I'm somewhat green on interrupts, but what I have working uses attachInterrupts() along with desired parameters.

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega
« Reply #2 on: June 29, 2015, 05:44:39 PM »
rdww60,

Got an any example code I can copy?

Just to be clear I am using pin A6 as an input

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega
« Reply #3 on: June 30, 2015, 01:20:08 AM »
Personally, I would first use the PinChangeInt library (http://playground.arduino.cc/Main/PinChangeIntExample) rather than messing with the low level coding and I'd use the digital pin reference of pin 30, rather than the analog pin reference A6.

Tom

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega
« Reply #4 on: July 15, 2015, 03:28:53 PM »
Tom is again right!

The EnableInterrupt (nee PinChangeInterrupt, moved from Google and since replaced/renamed) works a champ on the Moteino Mega;

https://github.com/GreyGnome/EnableInterrupt

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega
« Reply #5 on: July 16, 2015, 02:54:47 PM »
Tom is again right!

The EnableInterrupt (nee PinChangeInterrupt, moved from Google and since replaced/renamed) works a champ on the Moteino Mega;

https://github.com/GreyGnome/EnableInterrupt
Greg, thanks for the info on this new library.  However, I tried it and got compiler errors due to conflicts with the interrupt usage in the RFM69 library.  Have you tried this on Moteino with an RFM69 radio yet?   If so, what board settings did you use?

Tom

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #6 on: July 16, 2015, 03:04:16 PM »
Ah.

No.  Not tried that yet.

And here I was though I was making progress!!!

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #7 on: July 16, 2015, 03:27:40 PM »
Tom,

When I include;

Code: [Select]
#include <RFM69.h>

I get this;

Code: [Select]
core.a(WInterrupts.c.o): In function `__vector_1':
/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/WInterrupts.c:309: multiple definition of `__vector_1'
pinChangeIntSleep.cpp.o:/Users/greg/Documents/Arduino/libraries/EnableInterrupt/EnableInterrupt.h:774: first defined here
core.a(WInterrupts.c.o): In function `attachInterrupt':
/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/WInterrupts.c:39: multiple definition of `__vector_2'
pinChangeIntSleep.cpp.o:/Users/greg/pinChangeIntSleep.ino:56: first defined here
core.a(WInterrupts.c.o): In function `attachInterrupt':
/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/WInterrupts.c:39: multiple definition of `__vector_3'
pinChangeIntSleep.cpp.o:/Users/greg/pinChangeIntSleep.ino:56: first defined here
collect2: error: ld returned 1 exit status
Error compiling

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #8 on: July 16, 2015, 05:19:43 PM »
Yeah, same thing I get.  I don't think you can use attachInterrupt if you use this new library.  It might be all you have to do is add EnableInterrupt.h to the RFM69.h file.  I have to do some more testing, but that seems plausible given the code. 

Also, this new library is very myopically focused on Arduino boards only so you can't select Moteino Mega as your board without the new library barfing about an 'unknown' board!

I'll play around with it some as the interface seems somewhat easier to use.  That they deprecated the other library before thoroughly testing this one is pretty annoying!

Tom

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #9 on: July 19, 2015, 01:43:28 PM »
I discovered that the EnableInterrupt.h 'library' has problems  It does not allow interrupt handlers anywhere but in the main sketch code and is also peppered with references to Arduino boards rather than the underlying AVR processor used on those boards.  Consequently, if you're using a newer Arduino Board or using a 'non' Arduino board, Moteino to take a random example, you won't even be able to build the code.

I've attached a very simple change I made to their 'Simple' example to prove the failure.

Net: This library is unusable as-is for anything other than a very simple sketch with single interrupt.  I've reported the issue on the github.

Tom
UPDATED: removed inappropriate qualitative assessment and clarified usefulness.
« Last Edit: July 21, 2015, 01:58:22 PM by TomWS »

GreyGnome

  • NewMember
  • *
  • Posts: 1
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #10 on: July 21, 2015, 02:41:57 PM »
I discovered that the EnableInterrupt.h 'library' has problems  It does not allow interrupt handlers anywhere but in the main sketch code and is also peppered with references to Arduino boards rather than the underlying AVR processor used on those boards.  Consequently, if you're using a newer Arduino Board or using a 'non' Arduino board, Moteino to take a random example, you won't even be able to build the code.

I've attached a very simple change I made to their 'Simple' example to prove the failure.

Net: This library is unusable as-is for anything other than a very simple sketch with single interrupt.  I've reported the issue on the github.

Tom
UPDATED: removed inappropriate qualitative assessment and clarified usefulness.

Thanks for the removal  :) . I resembled your earlier remark.

As I mentioned in the Github issue, the references are mostly because, yes, the 'library' is Arduino focused. Given that I have a wife and child to support (== limited time [another word for it is 'myopia', apparently]), I have to direct my energies somewhere. Anyone is free to help- that's why it's released under the Apache license.

To say that it only works on a simple sketch with a single interrupt is incorrect. It will either fail to compile (because I can only test on Arduinos, and another library may define the same ISRs that this one does), or it will work on all interrupts on the chips it recognizes. See https://github.com/GreyGnome/EnableInterrupt/blob/master/examples/AllPins328/AllPins328.ino . I test every single pin, and I also test to make sure that it enables/disables, that it supports External as well as Pin Change interrupts, and even that you can switch between the two on supported pins (== 2 and 3 on the ATmega328). But I do not test with various other libraries- again, a time/family/sleep/myopia balancing act on my part.

BTW, if you put #define LIBCALL_ENABLEINTERRUPT ahead of your #include <EnableInterrupt.h> in your mOtherFunctions.h file, you should be able to use the library with other libraries. This allows the compiler to recognize the function declarations. You still need to #include EnableInterrupt.h in the main sketch, because the code needs to be defined (not just declared) somewhere. If you know of another technique to allow for this library to work with other Arduino libraries, I'm all ears. I got this idea from Paul Stoffregen some years ago. This is why the code is in the .h file and not in a .cpp file, to enable the library to work with and for other libraries. I do need to document the technique, which I missed.

I don't know why it would barf about an unknown board. The library knows nothing about boards- only CPUs. The fact that there are Arduino #defines is just convenience for me- indeed, the ATmega 1284 is supported based on a request, and it's not an Arduino chip. It's a cool chip, and I like it, so I support it to the best of my ability. But I can only guarantee Arduino compatibility because that's all I have. I can't spend untold dollars purchasing, programming, and supporting the entire ATmega line (not even close), guaranteeing compatibility with all of the different chips.

I spent a couple of months prior to the 0.1 release programming and, yes, testing the hell out of this library (again, see the previous link and other examples- I have probably 4 or 5 test sketches that I run with every release). Did I miss such things as the SoftwareSerial library/EnableInterrupt library conflict? Yes, because I don't use that library *. You can imagine how difficult it would be to design for every circumstance. It works for what I have- an Arduino Duemilanove and Mega2560- for everything else, I pray for help and bug reports over complaints.

* Not that it would have mattered to the release, but I needed to get the new one out the door. Probably what I missed was the fact that I should have documented the issue because I did have that functionality in the PinChangeInt library and would have included it eventually.

Again, if you like the idea and goals of the library, the best thing to do is file bug reports and (especially) help. Complaining about myopia and so on is not useful.

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #11 on: July 21, 2015, 04:43:48 PM »
@GreyGnome (AKA Mike), thanks for the update.  I'll try the LIBCALL define, both in the simple sketch I threw together and also in the case where I actually need it to coexist with the Moteino RFM69 library.  Hopefully I'll be able to try it tomorrow morning.

I was thrown off by your own ARDUINO defines within the code.  I apologize for that mistake - they looked like board references to me.
Quote
Thanks for the removal  :) . I resembled your earlier remark.
As well you should have, it was inappropriate.  I apologize for that as well.

Tom




gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #12 on: July 27, 2015, 05:56:04 AM »
Hi All,

For others who might want to use Pin Change Interrupts, Sleep AND the Moteino Mega;

I now have a demo sketch (very basic) that works with;
Moteino Mega
RFM69 Lib
SPI lib
LowPower Lib

It just sleeps 8 secs, and wakes up if the button is pressed using A6, and pinchange interrupts.

Code: [Select]
#include <LowPower.h>
#include <avr/interrupt.h>
#include <RFM69.h>
#include <SPI.h>

// Help from
// http://www.geertlangereis.nl/Electronics/Pin_Change_Interrupts/PinChange_en.html

volatile int pinChanged;

void setup() {
 
  pinChanged = 0;
  // put your setup code here, to run once:
  pinMode(A6, INPUT);
  digitalWrite(A6, HIGH);
 
  PCMSK0 |= (1<<PCINT6);
  PCICR |= (1<<PCIE0);
  sei();
 
  Serial.begin(9600);
}
void loop() {
 
  // woken up, either because the button was pressed or we
  // woke up naturally
  Serial.flush();
  Serial.println("");
  Serial.println("Woke up");
 
  if (pinChanged == 1) {
    Serial.println("Button pressed!!!");
    // reset
    pinChanged = 0;
  } else {
    Serial.println("We woke up naturally");
  }
 
  doStuff();
 
  checkButton();

  kip();
  // going to kip
  //Serial.println("Going to sleep for 8 secs ... nite!!!");
  //Serial.flush();
  //LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

void kip() {
  // going to kip
  Serial.println("");
  Serial.println("Going to sleep for 8 secs ... nite!!!");
  Serial.flush();
  LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}

ISR(PCINT0_vect) {
  pinChanged = 1;
}

void checkButton() {
  if (pinChanged == 1) {
    Serial.println("Button pressed");
    // reset
    pinChanged = 0;
  }
}

void doStuff() {
  // just sleep for 3 secs
  Serial.println("Doing stuff for 3 secs");
  for (int i = 0; i < 3; i++) {
    checkButton();
    Serial.print(".");
    delay(1000);
  }
  Serial.println("");
  Serial.println("Stuff done");
}

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #13 on: July 27, 2015, 08:55:41 AM »
Greg, thanks for your suggestion, but I think others are better served using the pinChangeInt library.  Despite the claim that it is 'deprecated', I personally don't accept that - the library works well for what it's intended for and easily handles multiple pin interrupt sources without the problem of managing this in your own code and, as of yet, there is no completely effective replacement.

I am working to see if EnableInterrupt library can be used, but, so far, have not resolved problems using it with Moteinos.

Tom

gregcope

  • Full Member
  • ***
  • Posts: 174
  • Country: gb
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #14 on: July 27, 2015, 08:58:13 AM »
Tom,

I agree with using a Library in the first instance, but I need something that works, so just posted this here if anyone needed it as I found few examples working on the 1284p aka Moteino Mega.

If anyone does use this code with a different pin they will need to check which port it is on, and make the relevant changes.

Vendigroth

  • NewMember
  • *
  • Posts: 1
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #15 on: August 05, 2015, 10:25:56 PM »
Hi,

So does anyone have any of the libraries working with Mega?
I've tried PinChangeInt since Tom says it works, but I can't even get a single pin to interrupt.
I'm using PinChangeInt from https://github.com/GreyGnome/PinChangeInt with this:

Code: [Select]
#include <PinChangeInt.h>
#define PIN 20

volatile uint16_t interruptCount=0;

void interruptFunction() {
  interruptCount++;
}
void setup() {
  Serial.begin(9600);
  Serial.print("PinChangeInt");
  pinMode(PIN, INPUT);
  digitalWrite(PIN, HIGH);
  PCintPort::attachInterrupt(PIN, interruptFunction, CHANGE);
  // (RISING, FALLING, CHANGE)
  }
 
void loop() {
  delay(1000);                            // Every second,
  Serial.print("Pin was interrupted: ");
  Serial.print(interruptCount, DEC);      // print the interrupt count.
  Serial.println(" times.");
  Serial.print("Currently: ");
  int buttonState = digitalRead(PIN);
  Serial.println(buttonState);
}

In the end I'm planning to have 3 pins interrupted, and I was hoping to avoid doing it manually and figuring out which is which or having them on different ports. 

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: pin change interrupts Moteino Mega - pinChange [solution/library]
« Reply #16 on: August 06, 2015, 09:23:38 AM »
@Vendigroth, if you want to use RFM69 library AND use ATmega1284P AND use pinChange Interrupts, then, unfortunately, the code that gregcope mentioned in his post is your best bet.   To use pin 20, there are a couple of changes:

Change:
Code: [Select]
  PCMSK0 |= (1<<PCINT6);
  PCICR |= (1<<PCIE0);
to:
Code: [Select]
  PCMSK2 |= (1<<PCINT20); // You can use this snippet for interrupts on pins 16-23.
  PCICR |= (1<<PCIE2);


Change:
Code: [Select]
ISR(PCINT0_vect) {
  pinChanged = 1;
}
to:
Code: [Select]
ISR(PCINT2_vect) {
  pinChanged = 1; // If you want to know WHICH pin changed, then you need to read PORTC and differentiate it with its previous value.
}

Tom